feat: add codex steer cli
This commit is contained in:
@@ -0,0 +1,104 @@
|
||||
import { spawnSync } from "node:child_process";
|
||||
import { writeFileSync, unlinkSync } from "node:fs";
|
||||
import { join } from "node:path";
|
||||
import { tmpdir } from "node:os";
|
||||
|
||||
type JsonRecord = Record<string, unknown>;
|
||||
|
||||
function assertCondition(condition: unknown, message: string, detail: JsonRecord = {}): void {
|
||||
if (!condition) throw new Error(`${message}: ${JSON.stringify(detail)}`);
|
||||
}
|
||||
|
||||
function runCli(args: string[], stdin?: string): { status: number | null; stdout: string; stderr: string; json: JsonRecord | null } {
|
||||
const result = spawnSync("bun", ["scripts/cli.ts", ...args], {
|
||||
cwd: process.cwd(),
|
||||
input: stdin,
|
||||
encoding: "utf8",
|
||||
});
|
||||
const stdout = String(result.stdout || "");
|
||||
let json: JsonRecord | null = null;
|
||||
try {
|
||||
json = JSON.parse(stdout) as JsonRecord;
|
||||
} catch {
|
||||
json = null;
|
||||
}
|
||||
return {
|
||||
status: result.status,
|
||||
stdout,
|
||||
stderr: String(result.stderr || ""),
|
||||
json,
|
||||
};
|
||||
}
|
||||
|
||||
function nestedRecord(value: unknown, path: string[]): JsonRecord {
|
||||
let current: unknown = value;
|
||||
for (const key of path) {
|
||||
assertCondition(current !== null && typeof current === "object" && !Array.isArray(current), "expected object while traversing JSON", { path, key, current });
|
||||
current = (current as JsonRecord)[key];
|
||||
}
|
||||
assertCondition(current !== null && typeof current === "object" && !Array.isArray(current), "expected nested object", { path, current });
|
||||
return current as JsonRecord;
|
||||
}
|
||||
|
||||
function stringArray(value: unknown): string[] {
|
||||
return Array.isArray(value) ? value.map((item) => String(item)) : [];
|
||||
}
|
||||
|
||||
function assertDryRunPrompt(response: JsonRecord, expectedText: string): void {
|
||||
assertCondition(response.ok === true, "CLI dry-run should succeed", response);
|
||||
const data = nestedRecord(response.data, []);
|
||||
assertCondition(data.dryRun === true, "dry-run response should expose dryRun=true", data);
|
||||
const prompt = nestedRecord(response.data, ["request", "body", "prompt"]);
|
||||
assertCondition(prompt.text === expectedText, "dry-run prompt text mismatch", prompt);
|
||||
assertCondition(prompt.chars === expectedText.length, "dry-run prompt char count mismatch", prompt);
|
||||
assertCondition(prompt.truncated === false, "dry-run prompt must not truncate", prompt);
|
||||
}
|
||||
|
||||
export function runCodeQueueCliSteerContract(): JsonRecord {
|
||||
const positional = runCli(["codex", "steer", "codex_test_task", "correct the running task", "--dry-run"]);
|
||||
assertDryRunPrompt(positional.json ?? {}, "correct the running task");
|
||||
|
||||
const stdin = runCli(["codex", "steer", "codex_test_task", "--prompt-stdin", "--dry-run"], "stdin steer prompt\n");
|
||||
assertDryRunPrompt(stdin.json ?? {}, "stdin steer prompt\n");
|
||||
|
||||
const promptFile = join(tmpdir(), `unidesk-code-queue-steer-${process.pid}.txt`);
|
||||
writeFileSync(promptFile, "file steer prompt", "utf8");
|
||||
try {
|
||||
const fromFile = runCli(["codex", "steer", "codex_test_task", "--prompt-file", promptFile, "--dry-run"]);
|
||||
assertDryRunPrompt(fromFile.json ?? {}, "file steer prompt");
|
||||
} finally {
|
||||
unlinkSync(promptFile);
|
||||
}
|
||||
|
||||
const duplicateSource = runCli(["codex", "steer", "codex_test_task", "positional", "--prompt-stdin", "--dry-run"], "stdin\n");
|
||||
assertCondition(duplicateSource.status !== 0, "duplicate prompt source should fail", duplicateSource.json ?? { stdout: duplicateSource.stdout });
|
||||
const duplicateMessage = String(nestedRecord(duplicateSource.json, ["error"]).message || "");
|
||||
assertCondition(duplicateMessage.includes("exactly one prompt source"), "duplicate prompt source error should be explicit", { duplicateMessage });
|
||||
|
||||
const unknownOption = runCli(["codex", "steer", "codex_test_task", "--queue", "default", "prompt", "--dry-run"]);
|
||||
assertCondition(unknownOption.status !== 0, "unknown steer option should fail", unknownOption.json ?? { stdout: unknownOption.stdout });
|
||||
const unknownMessage = String(nestedRecord(unknownOption.json, ["error"]).message || "");
|
||||
assertCondition(unknownMessage.includes("unsupported codex steer option: --queue"), "unknown option error should name option", { unknownMessage });
|
||||
|
||||
const help = runCli(["codex", "help"]);
|
||||
assertCondition(help.status === 0 && help.json?.ok === true, "codex help should succeed", help.json ?? { stdout: help.stdout });
|
||||
const usage = stringArray(nestedRecord(help.json?.data, []).usage);
|
||||
assertCondition(usage.some((line) => line.includes("codex steer <taskId>")), "codex help should list steer", { usage });
|
||||
|
||||
return {
|
||||
ok: true,
|
||||
checks: [
|
||||
"steer positional dry-run",
|
||||
"steer stdin dry-run",
|
||||
"steer prompt-file dry-run",
|
||||
"duplicate prompt source failure",
|
||||
"unsupported option failure",
|
||||
"codex help lists steer",
|
||||
],
|
||||
};
|
||||
}
|
||||
|
||||
if (import.meta.main) {
|
||||
const result = runCodeQueueCliSteerContract();
|
||||
process.stdout.write(`${JSON.stringify(result, null, 2)}\n`);
|
||||
}
|
||||
Reference in New Issue
Block a user