import assert from "node:assert/strict"; import fs from "node:fs"; import path from "node:path"; import { buildTaskContext, contextSizeReport, CONTEXT_LIMITS, root, verifyTaskIndex } from "./task-context-lib.mjs"; import { validateContextBundle } from "./context-governance.mjs"; const taskArg = process.argv.indexOf("--task"); const task = taskArg >= 0 ? process.argv[taskArg + 1] : undefined; const write = process.argv.includes("--write"); verifyTaskIndex(); const bundle = buildTaskContext(task); const report = contextSizeReport(bundle); const { context } = bundle; const governance = validateContextBundle(bundle); assert.equal(report.withinBudget, true, `task context exceeds budget: ${JSON.stringify(report)}`); assert.deepEqual(governance.violations, [], `task context governance failed: ${JSON.stringify(governance.violations)}`); if (task) assert.equal(context.task, task); assert.ok(context.parentTask); assert.ok(context.commands.length > 0, "task must expose at least one focused command"); assert.ok(context.sourceDocuments.parentManifest.endsWith("manifest.json")); assert.ok(!context.sourceDocuments.taskCard.includes("CURRENT_EXECUTION_PLAN")); if (bundle.sources.taskSource && context.task === bundle.sources.queue.currentTask) { for (const heading of ["## 目标", "## 输入与范围", "## 验收", "## 交付与回滚"]) { assert.ok(bundle.sources.taskSource.includes(heading), `current task card must include ${heading}`); } assert.match(bundle.sources.taskSource, /malformed|unsupported|取消|超限|负例|失败/iu, "current task card must name one failure boundary"); } if (context.task === bundle.sources.queue.currentTask) { assert.ok(bundle.sources.taskSource, "current task must have a compact task card; do not fall back to the full plan"); assert.ok(bundle.sources.taskSource.length <= CONTEXT_LIMITS.taskBytes, "current task card exceeds the 8 KiB context budget"); } const outputDir = path.join(root, "tests/golden", context.task); const outputPath = path.join(outputDir, "task-context.json"); if (write) { fs.mkdirSync(outputDir, { recursive: true }); fs.writeFileSync(outputPath, `${JSON.stringify({ ...context, size: report }, null, 2)}\n`); } process.stdout.write(`task-context-ok task=${context.task} parent=${context.parentTask} totalTokens=${report.totalTokens} taskBytes=${context.budgets.taskBytes} next=${context.nextTask ?? "NONE"}${write ? ` output=${path.relative(root, outputPath)}` : ""}\n`);