mirror of
https://github.com/merlinhu1/codex-game-studio.git
synced 2026-08-25 07:54:34 +02:00
* feat: add flexible studio depth foundations - add context manifests, engine references, and studio policy gates - refresh Truthmark 2.2.1 generated surfaces and lane docs - update OpenSpec tasks and validation coverage * docs: add Open Game Studio product truth - add product-capability truth doc for the Codex-native CLI - cross-link product and engineering truth in route YAML - update product truth index * chore: remove stale planning artifacts --------- Co-authored-by: MerlinH <merlinh221@gmail.com>
66 lines
2.4 KiB
TypeScript
66 lines
2.4 KiB
TypeScript
import { spawn, spawnSync } from "node:child_process";
|
|
import type { CodexSandboxMode } from "./codex-session.js";
|
|
|
|
export type CodexRuntimeOptions = {
|
|
projectRoot: string;
|
|
sandbox?: CodexSandboxMode;
|
|
codexBin?: string;
|
|
};
|
|
|
|
export type CodexAvailability = {
|
|
ok: boolean;
|
|
command: string;
|
|
reason?: string;
|
|
stdout: string;
|
|
stderr: string;
|
|
};
|
|
|
|
export type CodexExecutionResult = {
|
|
status: number | null;
|
|
signal: NodeJS.Signals | null;
|
|
stdout: string;
|
|
stderr: string;
|
|
error?: Error;
|
|
};
|
|
|
|
export function resolveCodexCommand(env: NodeJS.ProcessEnv | Record<string, string | undefined> = process.env): string {
|
|
return env.CODEX_BIN?.trim() || "codex";
|
|
}
|
|
|
|
export function buildCodexExecArgs(options: CodexRuntimeOptions): string[] {
|
|
return ["exec", "--cd", options.projectRoot, "--sandbox", options.sandbox ?? "danger-full-access", "-"];
|
|
}
|
|
|
|
export async function checkCodexAvailability(options: { codexBin?: string } = {}): Promise<CodexAvailability> {
|
|
const command = options.codexBin ?? resolveCodexCommand();
|
|
const result = spawnSync(command, ["--version"], { encoding: "utf8", shell: false });
|
|
if (result.error) {
|
|
return { ok: false, command, reason: `Codex CLI unavailable or not found: ${result.error.message}`, stdout: result.stdout ?? "", stderr: result.stderr ?? "" };
|
|
}
|
|
if (result.status !== 0) {
|
|
return { ok: false, command, reason: `Codex CLI exited with status ${result.status}`, stdout: result.stdout ?? "", stderr: result.stderr ?? "" };
|
|
}
|
|
return { ok: true, command, stdout: result.stdout ?? "", stderr: result.stderr ?? "" };
|
|
}
|
|
|
|
export async function executeCodexPrompt(prompt: string, options: CodexRuntimeOptions): Promise<CodexExecutionResult> {
|
|
const command = options.codexBin ?? resolveCodexCommand();
|
|
const args = buildCodexExecArgs(options);
|
|
return await new Promise((resolve) => {
|
|
const child = spawn(command, args, { cwd: options.projectRoot, shell: false, stdio: ["pipe", "pipe", "pipe"] });
|
|
let stdout = "";
|
|
let stderr = "";
|
|
child.stdout.setEncoding("utf8");
|
|
child.stderr.setEncoding("utf8");
|
|
child.stdout.on("data", (chunk: string) => {
|
|
stdout += chunk;
|
|
});
|
|
child.stderr.on("data", (chunk: string) => {
|
|
stderr += chunk;
|
|
});
|
|
child.on("error", (error) => resolve({ status: null, signal: null, stdout, stderr, error }));
|
|
child.on("close", (status, signal) => resolve({ status, signal, stdout, stderr }));
|
|
child.stdin.end(prompt);
|
|
});
|
|
}
|