156 lines
6.7 KiB
TypeScript
156 lines
6.7 KiB
TypeScript
import { codexOutputQuery, codexTaskQuery } from "./src/code-queue";
|
|
|
|
type JsonRecord = Record<string, unknown>;
|
|
|
|
function assertCondition(condition: unknown, message: string, detail: unknown = {}): void {
|
|
if (!condition) throw new Error(`${message}: ${JSON.stringify(detail)}`);
|
|
}
|
|
|
|
function asRecord(value: unknown): JsonRecord {
|
|
assertCondition(value !== null && typeof value === "object" && !Array.isArray(value), "expected object", { value });
|
|
return value as JsonRecord;
|
|
}
|
|
|
|
function asArray(value: unknown): unknown[] {
|
|
assertCondition(Array.isArray(value), "expected array", { value });
|
|
return value as unknown[];
|
|
}
|
|
|
|
function longText(marker: string, repeat = 220): string {
|
|
return Array.from({ length: repeat }, (_, index) => `${marker}-${String(index + 1).padStart(3, "0")} ${"abcdefghijklmnopqrstuvwxyz0123456789".repeat(3)}`).join("\n");
|
|
}
|
|
|
|
function detailFixture(path: string): JsonRecord {
|
|
assertCondition(path.includes("/summary"), "detail fixture should only fetch summary", { path });
|
|
return {
|
|
ok: true,
|
|
status: 200,
|
|
body: {
|
|
ok: true,
|
|
summary: {
|
|
id: "codex_disclosure_fixture",
|
|
queueId: "noise",
|
|
status: "failed",
|
|
providerId: "D601",
|
|
model: "gpt-5.5",
|
|
cwd: "/workspace",
|
|
prompt: longText("prompt-tail-marker"),
|
|
basePrompt: longText("base-tail-marker"),
|
|
transcriptCount: 300,
|
|
outputCount: 180,
|
|
eventCount: 40,
|
|
lastAssistantMessage: {
|
|
at: "2026-05-23T00:00:00.000Z",
|
|
seq: 300,
|
|
source: "assistant",
|
|
text: longText("assistant-tail-marker"),
|
|
},
|
|
toolSummary: {
|
|
count: 12,
|
|
returned: 8,
|
|
limit: 8,
|
|
truncated: true,
|
|
items: Array.from({ length: 8 }, (_, index) => ({
|
|
seq: index + 1,
|
|
at: "2026-05-23T00:00:00.000Z",
|
|
kind: "ran",
|
|
title: `tool-${index + 1}`,
|
|
status: "ok",
|
|
commandPreview: longText(`command-tail-marker-${index + 1}`, 20),
|
|
outputPreview: longText(`tool-output-tail-marker-${index + 1}`, 20),
|
|
rawSeqs: [index + 1],
|
|
})),
|
|
},
|
|
attempts: Array.from({ length: 8 }, (_, index) => ({
|
|
index: index + 1,
|
|
mode: index === 0 ? "initial" : "retry",
|
|
terminalStatus: "failed",
|
|
stderrTail: longText(`stderr-tail-marker-${index + 1}`, 20),
|
|
finalResponse: longText(`attempt-response-tail-marker-${index + 1}`, 30),
|
|
feedbackPromptPreview: longText(`feedback-tail-marker-${index + 1}`, 20),
|
|
runnerErrorClassification: { scope: "runner-local", globalBlocker: false },
|
|
})),
|
|
},
|
|
},
|
|
};
|
|
}
|
|
|
|
function outputFixture(path: string): JsonRecord {
|
|
assertCondition(path.includes("/output"), "output fixture should fetch output", { path });
|
|
assertCondition(path.includes("limit=20"), "default output should cap large requested limit to 20", { path });
|
|
assertCondition(path.includes("maxTextChars=500"), "default output should cap text preview chars", { path });
|
|
const output = Array.from({ length: 20 }, (_, index) => ({
|
|
seq: index + 101,
|
|
at: "2026-05-23T00:00:00.000Z",
|
|
channel: index % 2 === 0 ? "command" : "assistant",
|
|
method: "fixture",
|
|
text: longText(`raw-output-tail-marker-${index + 1}`, 40),
|
|
}));
|
|
return {
|
|
ok: true,
|
|
status: 200,
|
|
body: {
|
|
ok: true,
|
|
taskId: "codex_disclosure_fixture",
|
|
queueId: "noise",
|
|
status: "running",
|
|
updatedAt: "2026-05-23T00:00:00.000Z",
|
|
mode: "tail",
|
|
limit: 20,
|
|
total: 240,
|
|
maxSeq: 1200,
|
|
afterSeq: 0,
|
|
nextAfterSeq: 120,
|
|
previousBeforeSeq: 101,
|
|
hasMore: true,
|
|
hasBefore: true,
|
|
output,
|
|
},
|
|
};
|
|
}
|
|
|
|
export function runCodeQueueCliDisclosureContract(): JsonRecord {
|
|
const detail = codexTaskQuery("codex_disclosure_fixture", ["--detail"], detailFixture) as JsonRecord;
|
|
const detailJson = JSON.stringify(detail);
|
|
const summary = asRecord(detail.summary);
|
|
const attempts = asRecord(summary.attempts);
|
|
const attemptRecords = asArray(attempts.attemptRecords);
|
|
const toolSummary = asRecord(summary.toolSummary);
|
|
const toolItems = asArray(toolSummary.items);
|
|
|
|
assertCondition(attemptRecords.length === 3, "detail should cap attempt records by default", attempts);
|
|
assertCondition(attempts.attemptRecordCount === 8 && attempts.attemptRecordsTruncated === true, "detail should expose omitted attempt metadata", attempts);
|
|
assertCondition(detailJson.includes("detailOutputPolicy"), "detail should disclose progressive detail policy", summary);
|
|
assertCondition(!detailJson.includes("prompt-tail-marker-220"), "detail should not include full prompt tail by default", summary);
|
|
assertCondition(!detailJson.includes("assistant-tail-marker-220"), "detail should not include full assistant tail by default", summary);
|
|
assertCondition(!detailJson.includes("attempt-response-tail-marker-1-030"), "detail should not include full attempt response by default", attempts);
|
|
assertCondition(toolItems.length === 3 && toolSummary.truncated === true, "detail should cap tool summary rows by default", toolSummary);
|
|
assertCondition(!detailJson.includes("tool-output-tail-marker-1-020"), "detail should compact tool output previews", toolSummary);
|
|
|
|
const output = codexOutputQuery("codex_disclosure_fixture", ["--tail", "--limit", "120"], outputFixture) as JsonRecord;
|
|
const page = asRecord(output.outputPage);
|
|
const outputRows = asArray(page.output).map(asRecord);
|
|
const outputJson = JSON.stringify(output);
|
|
const disclosure = asRecord(page.disclosure);
|
|
assertCondition(page.requestedLimit === 120 && page.limit === 20 && page.returned === 20, "output should cap large requested limit by default", page);
|
|
assertCondition(disclosure.limitCapped === true && disclosure.fullText === false, "output should disclose capped default policy", disclosure);
|
|
assertCondition(outputRows.every((row) => row.textTruncated === true && Number(row.textChars) > String(row.text).length), "output rows should expose bounded text previews", page);
|
|
assertCondition(!outputJson.includes("raw-output-tail-marker-1-040"), "output should not include full raw text tail by default", page);
|
|
assertCondition(String(asRecord(page.commands).fullText).includes("--full-text"), "output should provide explicit full-text command", page);
|
|
|
|
return {
|
|
ok: true,
|
|
checks: [
|
|
"codex task --detail caps attempts and long text by default",
|
|
"codex output caps large requested limits by default",
|
|
"codex output preserves progressive full-text command",
|
|
],
|
|
detailChars: detailJson.length,
|
|
outputChars: outputJson.length,
|
|
};
|
|
}
|
|
|
|
if (import.meta.main) {
|
|
process.stdout.write(`${JSON.stringify(runCodeQueueCliDisclosureContract(), null, 2)}\n`);
|
|
}
|