@tea-agent/loop-agent 0.26.0 → 0.26.2

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (197) hide show
  1. package/CHANGELOG.md +1056 -1020
  2. package/README.md +8 -3
  3. package/bin/loop-agent.js +21 -21
  4. package/dist/application/dag/generate-task-dag.js +33 -0
  5. package/dist/cli/command-definitions.js +25 -10
  6. package/dist/cli/help.js +4 -3
  7. package/dist/cli/program.js +43 -17
  8. package/dist/commands/cursor-prompt.js +6 -6
  9. package/dist/commands/import-prd.js +7 -2
  10. package/dist/commands/init.js +7 -5
  11. package/dist/commands/loop-benchmark.js +11 -11
  12. package/dist/commands/pi-reuse-benchmark.js +16 -16
  13. package/dist/commands/task-source-prepare.js +474 -0
  14. package/dist/executors/dag-pi-executor.js +40 -5
  15. package/dist/executors/shell-executor.js +111 -0
  16. package/dist/executors/shell-presets.js +12 -4
  17. package/dist/executors/shell-write-guard.js +161 -25
  18. package/dist/sidecars/cursor-prompt/executor.js +1 -1
  19. package/dist/task/config-types.js +6 -0
  20. package/dist/task/contract/constants.js +1 -0
  21. package/dist/task/contract/project.js +8 -0
  22. package/dist/task/contract/schema.js +1 -0
  23. package/dist/task/frontend-preflight.js +131 -0
  24. package/dist/task/runtime.js +2 -4
  25. package/dist/task/source-prepare/build-draft.js +224 -0
  26. package/dist/task/source-prepare/completeness.js +195 -0
  27. package/dist/task/source-prepare/index.js +7 -0
  28. package/dist/task/source-prepare/parse-intent.js +373 -0
  29. package/dist/task/source-prepare/path-policy.js +197 -0
  30. package/dist/task/source-prepare/prepare.js +506 -0
  31. package/dist/task/source-prepare/reference-integrity.js +274 -0
  32. package/dist/task/source-prepare/types.js +7 -0
  33. package/dist/worker/observability/read-model.js +134 -0
  34. package/dist/worker/observe/static/copy.js +67 -67
  35. package/dist/worker/observe/static/dag-layout.d.ts +31 -31
  36. package/dist/worker/observe/static/dag-layout.js +83 -83
  37. package/dist/worker/observe/static/dom.js +220 -220
  38. package/dist/worker/observe/static/relations.js +133 -133
  39. package/dist/worker/observe/static/router.js +93 -93
  40. package/dist/worker/observe/static/run-processing.js +148 -148
  41. package/dist/worker/observe/static/state.js +61 -0
  42. package/dist/worker/observe/static/styles.css +8 -0
  43. package/dist/worker/observe/static/views/batch.js +227 -227
  44. package/dist/worker/observe/static/views/dag-graph.js +248 -172
  45. package/dist/worker/observe/static/views/dag-inspector.js +374 -157
  46. package/dist/worker/observe/static/views/dag.js +4 -11
  47. package/dist/worker/observe/static/views/failures.js +143 -143
  48. package/dist/worker/observe/static/views/feature.js +492 -492
  49. package/dist/worker/observe/static/views/run.js +453 -453
  50. package/dist/worker/observe/static/views/shell.js +7 -7
  51. package/dist/worker/observe/static/views/timeline.js +163 -163
  52. package/dist/workflows/dag/backend-test-pytest-collection.js +277 -0
  53. package/dist/workflows/dag/canvas-observer.js +275 -275
  54. package/dist/workflows/dag/convergence/controller.js +110 -21
  55. package/dist/workflows/dag/frontend-implementation-contract.js +218 -17
  56. package/dist/workflows/dag/frontend-review-context.js +7 -1
  57. package/dist/workflows/dag/frontend-verification-trace.js +14 -3
  58. package/dist/workflows/dag/frontend-worktree-diff.js +14 -3
  59. package/dist/workflows/dag/init-hybrid.js +96 -34
  60. package/dist/workflows/dag/output-protocol.js +180 -7
  61. package/dist/workflows/dag/runner.js +141 -52
  62. package/dist/workflows/dag/types.js +4 -0
  63. package/dist/workflows/dag/validate.js +3 -2
  64. package/docs/skills/README.md +7 -7
  65. package/docs/templates/adr.md +60 -60
  66. package/docs/templates/agent-dag-authority-surface-audit.prompt.md +94 -94
  67. package/docs/templates/agent-dag-decision-envelope.schema.json +213 -213
  68. package/docs/templates/agent-dag-decision-gate.prompt.md +246 -246
  69. package/docs/templates/agent-dag-process-supervisor.prompt.md +98 -98
  70. package/docs/templates/agent-dag-report.schema.json +473 -473
  71. package/docs/templates/agent-dag-review-verdict.prompt.md +68 -68
  72. package/docs/templates/backend-test-dag.json +100 -8
  73. package/docs/templates/backend-test-result.schema.json +99 -99
  74. package/docs/templates/feature-spec.md +53 -53
  75. package/docs/templates/frontend-design-contract.md +42 -42
  76. package/docs/templates/frontend-eval/fixtures/failures/01-type-build-error.md +17 -17
  77. package/docs/templates/frontend-eval/fixtures/failures/02-unit-component-test-fail.md +16 -16
  78. package/docs/templates/frontend-eval/fixtures/failures/03-fixture-schema-drift.md +16 -16
  79. package/docs/templates/frontend-eval/fixtures/failures/04-missing-loading-empty-error-state.md +16 -16
  80. package/docs/templates/frontend-eval/fixtures/failures/05-forbidden-write-writeset-expansion.md +16 -16
  81. package/docs/templates/frontend-eval/fixtures/failures/06-unapproved-dependency-add.md +16 -16
  82. package/docs/templates/frontend-eval/fixtures/failures/07-mock-production-on.md +21 -21
  83. package/docs/templates/frontend-eval/fixtures/functional/01-simple-component-style.md +29 -29
  84. package/docs/templates/frontend-eval/fixtures/functional/02-form-validation.md +28 -28
  85. package/docs/templates/frontend-eval/fixtures/functional/03-list-detail-page.md +28 -28
  86. package/docs/templates/frontend-eval/fixtures/functional/04-api-mock.md +29 -29
  87. package/docs/templates/frontend-eval/fixtures/functional/05-permission-auth-gated-ui.md +27 -27
  88. package/docs/templates/frontend-eval/fixtures/functional/06-ssr-server-client-boundary.md +28 -28
  89. package/docs/templates/frontend-eval/fixtures/functional/07-shared-public-component-api.md +28 -28
  90. package/docs/templates/frontend-eval/fixtures/functional/08-pure-local-no-remote.md +27 -27
  91. package/docs/templates/frontend-eval/metrics.md +138 -138
  92. package/docs/templates/frontend-eval/smoke-targets.md +53 -53
  93. package/docs/templates/frontend-task-constraints.md +35 -35
  94. package/docs/templates/frontend-task-requirement.md +70 -70
  95. package/docs/templates/init-evolution-review.md +35 -35
  96. package/docs/templates/init-managed-agents.md +10 -5
  97. package/docs/templates/interactive-ui-round2-experiment.md +66 -66
  98. package/docs/templates/knowledge-graph-bootstrap-dag.json +118 -118
  99. package/docs/templates/knowledge-sync-dag.json +178 -178
  100. package/docs/templates/knowledge-sync-draft.schema.json +71 -71
  101. package/docs/templates/product-line/closeout.yaml +9 -9
  102. package/docs/templates/product-line/design.md +13 -13
  103. package/docs/templates/product-line/links.md +10 -10
  104. package/docs/templates/product-line/requirement.md +17 -17
  105. package/docs/templates/product-line/test-plan.md +7 -7
  106. package/docs/templates/production-readiness-checklist.md +57 -57
  107. package/docs/templates/project-start-checklist.md +9 -9
  108. package/docs/templates/qa-report.md +48 -48
  109. package/docs/templates/sprint-contract.md +29 -29
  110. package/docs/templates/worker-dogfood-evidence.md +80 -80
  111. package/docs/templates/worker-dogfood-setup.md +68 -68
  112. package/package.json +1 -1
  113. package/scripts/kb-bootstrap-init-skeleton.sh +0 -0
  114. package/scripts/kb-graph-incremental-prepare.mjs +386 -386
  115. package/scripts/kb-graph-materialize.mjs +105 -105
  116. package/scripts/kb-graph-promote.mjs +164 -164
  117. package/scripts/kb-query.mjs +554 -554
  118. package/skills/ai-engineering-context/SKILL.md +48 -48
  119. package/skills/analyze-product-dependencies/SKILL.md +67 -67
  120. package/skills/analyze-product-dependencies/agents/openai.yaml +4 -4
  121. package/skills/analyze-product-dependencies/references/api-documentation-schema.md +30 -30
  122. package/skills/analyze-product-dependencies/references/dependency-analysis-schema.md +28 -28
  123. package/skills/analyze-product-dependencies/references/example.md +76 -76
  124. package/skills/analyze-product-dependencies/references/forward-test-cases.md +35 -35
  125. package/skills/analyze-product-dependencies/references/input-contract.md +11 -11
  126. package/skills/analyze-product-dependencies/references/scouting-rules.md +61 -61
  127. package/skills/analyze-product-dependencies/scripts/test-validators.mjs +267 -267
  128. package/skills/analyze-product-dependencies/scripts/validate-api-documentation.mjs +101 -101
  129. package/skills/analyze-product-dependencies/scripts/validate-dependency-analysis.mjs +142 -142
  130. package/skills/analyze-product-dependencies/scripts/validate-product-requirement-input.mjs +76 -76
  131. package/skills/analyze-product-dependencies/scripts/validation-helpers.mjs +146 -146
  132. package/skills/analyze-product-requirements/SKILL.md +90 -90
  133. package/skills/analyze-product-requirements/agents/openai.yaml +4 -4
  134. package/skills/analyze-product-requirements/references/acceptance-criteria.md +91 -91
  135. package/skills/analyze-product-requirements/references/clarification-and-knowledge.md +56 -56
  136. package/skills/analyze-product-requirements/references/example.md +86 -86
  137. package/skills/analyze-product-requirements/references/forward-test-cases.md +66 -66
  138. package/skills/analyze-product-requirements/references/product-analysis-schema.md +32 -32
  139. package/skills/analyze-product-requirements/references/product-requirement-schema.md +33 -33
  140. package/skills/analyze-product-requirements/references/requirement-clarification-schema.md +35 -35
  141. package/skills/analyze-product-requirements/scripts/test-validators.mjs +193 -193
  142. package/skills/analyze-product-requirements/scripts/validate-product-analysis.mjs +69 -69
  143. package/skills/analyze-product-requirements/scripts/validate-product-requirement.mjs +97 -97
  144. package/skills/analyze-product-requirements/scripts/validate-requirement-clarification.mjs +98 -98
  145. package/skills/analyze-product-requirements/scripts/validation-helpers.mjs +156 -156
  146. package/skills/browser-tools/browser-content.js +103 -103
  147. package/skills/browser-tools/browser-cookies.js +35 -35
  148. package/skills/browser-tools/browser-eval.js +53 -53
  149. package/skills/browser-tools/browser-hn-scraper.js +108 -108
  150. package/skills/browser-tools/browser-nav.js +44 -44
  151. package/skills/browser-tools/browser-pick.js +162 -162
  152. package/skills/browser-tools/browser-screenshot.js +34 -34
  153. package/skills/browser-tools/browser-start.js +86 -86
  154. package/skills/browser-tools/package-lock.json +2556 -2556
  155. package/skills/browser-tools/package.json +19 -19
  156. package/skills/code-review-core/SKILL.md +20 -20
  157. package/skills/codebase-scout/SKILL.md +19 -19
  158. package/skills/grill-me/SKILL.md +10 -10
  159. package/skills/loop-agent/SKILL.md +5 -2
  160. package/skills/loop-agent/references/README.md +67 -67
  161. package/skills/loop-agent/references/command-reference.md +17 -15
  162. package/skills/loop-agent/references/docs-converge.md +126 -126
  163. package/skills/loop-agent/references/harness-policy.md +3 -4
  164. package/skills/loop-agent/references/hybrid-dag.md +1 -1
  165. package/skills/loop-agent/references/learned/README.md +21 -21
  166. package/skills/loop-agent/references/long-running-loop.md +57 -57
  167. package/skills/loop-agent/references/one-shot-runs.md +85 -85
  168. package/skills/loop-agent/references/pi-prompt.md +23 -23
  169. package/skills/loop-agent/references/pi-subagent-assisted-mode.md +84 -84
  170. package/skills/loop-agent/references/post-implementation-and-patterns.md +1 -1
  171. package/skills/loop-agent/references/source-and-plan-practice.md +3 -2
  172. package/skills/loop-agent/references/task-workflow.md +7 -5
  173. package/skills/playwright-cli/SKILL.md +420 -420
  174. package/skills/playwright-cli/references/element-attributes.md +23 -23
  175. package/skills/playwright-cli/references/playwright-tests.md +39 -39
  176. package/skills/playwright-cli/references/request-mocking.md +87 -87
  177. package/skills/playwright-cli/references/running-code.md +241 -241
  178. package/skills/playwright-cli/references/session-management.md +225 -225
  179. package/skills/playwright-cli/references/storage-state.md +275 -275
  180. package/skills/playwright-cli/references/test-generation.md +433 -433
  181. package/skills/playwright-cli/references/tracing.md +139 -139
  182. package/skills/playwright-cli/references/video-recording.md +143 -143
  183. package/skills/requesting-code-review/SKILL.md +101 -101
  184. package/skills/requesting-code-review/code-reviewer.md +168 -168
  185. package/skills/systematic-debugging/CREATION-LOG.md +119 -119
  186. package/skills/systematic-debugging/condition-based-waiting-example.ts +158 -158
  187. package/skills/systematic-debugging/condition-based-waiting.md +115 -115
  188. package/skills/systematic-debugging/defense-in-depth.md +122 -122
  189. package/skills/systematic-debugging/find-polluter.sh +63 -63
  190. package/skills/systematic-debugging/root-cause-tracing.md +169 -169
  191. package/skills/systematic-debugging/test-academic.md +14 -14
  192. package/skills/systematic-debugging/test-pressure-1.md +58 -58
  193. package/skills/systematic-debugging/test-pressure-2.md +68 -68
  194. package/skills/systematic-debugging/test-pressure-3.md +69 -69
  195. package/skills/using-git-worktrees/SKILL.md +215 -215
  196. package/skills/verification-before-completion/SKILL.md +154 -154
  197. package/skills/webapp-testing/SKILL.md +19 -19
package/README.md CHANGED
@@ -56,11 +56,16 @@ loop-agent init reconcile --repo-root .
56
56
 
57
57
  ```bash
58
58
  loop-agent new-task example-task "实现一个有明确验收标准的小功能"
59
- ```
60
59
 
61
- 完善 `.harness/tasks/example-task/source/需求.md` `task.json` 中的结构化写入边界,然后执行:
60
+ # 推荐:先有详细 PRD,再归档并确定性派生执行契约(无需手写两个 source 文件)
61
+ # loop-agent import-prd example-task --file path/to/prd.md --json
62
+ loop-agent task source prepare example-task \
63
+ --use-imported-prd \
64
+ --allowed-path "src/**" \
65
+ --forbidden-path ".harness/**" \
66
+ --verify "typecheck:npm run typecheck" \
67
+ --apply --json
62
68
 
63
- ```bash
64
69
  loop-agent dag run-task example-task \
65
70
  --profile auto \
66
71
  --strict-models \
package/bin/loop-agent.js CHANGED
@@ -1,21 +1,21 @@
1
- #!/usr/bin/env node
2
- import { existsSync } from "node:fs";
3
- import { dirname, join } from "node:path";
4
- import { fileURLToPath, pathToFileURL } from "node:url";
5
-
6
- const packageRoot = dirname(dirname(fileURLToPath(import.meta.url)));
7
- const cliEntry = join(packageRoot, "dist", "cli.js");
8
-
9
- if (!existsSync(cliEntry)) {
10
- console.error(
11
- `loop-agent: cannot find built CLI at ${cliEntry}. Run \`npm run build\` before using the package bin.`,
12
- );
13
- process.exit(1);
14
- }
15
-
16
- try {
17
- await import(pathToFileURL(cliEntry).href);
18
- } catch (error) {
19
- console.error(error instanceof Error ? error.message : String(error));
20
- process.exit(1);
21
- }
1
+ #!/usr/bin/env node
2
+ import { existsSync } from "node:fs";
3
+ import { dirname, join } from "node:path";
4
+ import { fileURLToPath, pathToFileURL } from "node:url";
5
+
6
+ const packageRoot = dirname(dirname(fileURLToPath(import.meta.url)));
7
+ const cliEntry = join(packageRoot, "dist", "cli.js");
8
+
9
+ if (!existsSync(cliEntry)) {
10
+ console.error(
11
+ `loop-agent: cannot find built CLI at ${cliEntry}. Run \`npm run build\` before using the package bin.`,
12
+ );
13
+ process.exit(1);
14
+ }
15
+
16
+ try {
17
+ await import(pathToFileURL(cliEntry).href);
18
+ } catch (error) {
19
+ console.error(error instanceof Error ? error.message : String(error));
20
+ process.exit(1);
21
+ }
@@ -12,6 +12,9 @@ import { validateDagUseCase } from "./validate-dag.js";
12
12
  import { runDagUseCase } from "./run-dag.js";
13
13
  import { getTaskPaths, loadTaskConfig } from "../../task/runtime.js";
14
14
  import { writeTaskConfig } from "../../infrastructure/harness/task-store.js";
15
+ import { runFrontendPreflight } from "../../task/frontend-preflight.js";
16
+ import { observeTaskContract } from "../../task/contract/observe.js";
17
+ import { adoptTaskContract } from "../../task/contract/adopt.js";
15
18
  const PLACEHOLDER_WRITESET_MARKER = "REPLACE/WITH";
16
19
  function buildValidateInput(repoRoot, dagPath, parsed) {
17
20
  return {
@@ -243,6 +246,36 @@ export async function generateTaskDagUseCase(input) {
243
246
  // before any expensive DAG generation or execution. Empty/consistent
244
247
  // repos stay compatible so the default DAG flow is unblocked.
245
248
  await assertExecPlanIndexConsistent(repoRoot);
249
+ const preflightTaskConfig = await loadTaskConfig(repoRoot, parsed.taskId);
250
+ const frontendScope = await runFrontendPreflight({
251
+ repoRoot,
252
+ taskId: parsed.taskId,
253
+ taskConfig: preflightTaskConfig,
254
+ });
255
+ if (frontendScope) {
256
+ await writeTaskConfig(repoRoot, parsed.taskId, {
257
+ ...preflightTaskConfig,
258
+ allowedPaths: [
259
+ ...new Set([
260
+ frontendScope.entrypoint,
261
+ ...frontendScope.implementationPaths,
262
+ ...frontendScope.testPaths,
263
+ ]),
264
+ ],
265
+ });
266
+ const state = await observeTaskContract({ repoRoot, taskId: parsed.taskId });
267
+ if (!state.ref || !state.observedCanonicalHash) {
268
+ throw new Error("frontend preflight could not reconcile the managed Task Contract");
269
+ }
270
+ await adoptTaskContract({
271
+ repoRoot,
272
+ taskId: parsed.taskId,
273
+ expectedRevision: state.ref.revision,
274
+ expectedObservedHash: state.observedCanonicalHash,
275
+ requestId: `frontend-preflight-${parsed.taskId}-${randomUUID()}`,
276
+ requestPayloadSha256: randomUUID().replaceAll("-", "").padEnd(64, "0"),
277
+ });
278
+ }
246
279
  const candidateResult = await initHybridDagFromTask(repoRoot, parsed.taskId, {
247
280
  outputPath: parsed.outputPath,
248
281
  template: "standard-dag",
@@ -12,6 +12,7 @@ import { runInstructions } from "../commands/instructions.js";
12
12
  import { runNewTask } from "../commands/new-task.js";
13
13
  import { runImportPrd } from "../commands/import-prd.js";
14
14
  import { runTaskContract } from "../commands/task-contract.js";
15
+ import { runTaskSourcePrepare } from "../commands/task-source-prepare.js";
15
16
  import { runOperator } from "../commands/operator.js";
16
17
  import { runPlanList } from "../commands/plan-list.js";
17
18
  import { runPlanCheck, runPlanComplete, runPlanCreate, } from "../commands/plan.js";
@@ -139,7 +140,7 @@ const DAG_SUBCOMMANDS = [
139
140
  "final-verification",
140
141
  "decision",
141
142
  ];
142
- const TASK_SUBCOMMANDS = ["contract"];
143
+ const TASK_SUBCOMMANDS = ["contract", "source"];
143
144
  const TASK_CONTRACT_SUBCOMMANDS = [
144
145
  "show",
145
146
  "validate",
@@ -149,6 +150,7 @@ const TASK_CONTRACT_SUBCOMMANDS = [
149
150
  "doctor",
150
151
  "recover",
151
152
  ];
153
+ const TASK_SOURCE_SUBCOMMANDS = ["prepare"];
152
154
  const OPERATOR_SUBCOMMANDS = ["capabilities"];
153
155
  const WORKFLOW_SUBCOMMANDS = [
154
156
  "list",
@@ -271,19 +273,32 @@ export const COMMAND_DEFINITIONS = [
271
273
  name: "task",
272
274
  adapter: "required",
273
275
  tier: "primary",
274
- intent: "Task Contract application boundary: show/validate/diff/apply/adopt/doctor/recover managed contract facts.",
275
- usage: "task contract <show|validate|diff|apply|adopt|doctor|recover> ...",
276
+ intent: "Task Contract and source intake: contract show/validate/diff/apply/adopt/doctor/recover; source prepare (PRD-first Draft projection).",
277
+ usage: "task <contract|source> ... (contract <show|validate|diff|apply|adopt|doctor|recover>; source prepare ...)",
276
278
  subcommands: [...TASK_SUBCOMMANDS],
277
279
  handler: async ({ repoRoot, subcommand, rest }) => {
278
- if (subcommand !== "contract") {
279
- throw new Error(formatSubcommandUsageError("task", TASK_SUBCOMMANDS));
280
+ if (subcommand === "contract") {
281
+ const [contractSub, ...contractRest] = rest;
282
+ if (!contractSub ||
283
+ !TASK_CONTRACT_SUBCOMMANDS.includes(contractSub)) {
284
+ throw new Error(`usage: task contract <${TASK_CONTRACT_SUBCOMMANDS.join("|")}> ...`);
285
+ }
286
+ await runTaskContract(repoRoot, [contractSub, ...contractRest]);
287
+ return;
280
288
  }
281
- const [contractSub, ...contractRest] = rest;
282
- if (!contractSub ||
283
- !TASK_CONTRACT_SUBCOMMANDS.includes(contractSub)) {
284
- throw new Error(`usage: task contract <${TASK_CONTRACT_SUBCOMMANDS.join("|")}> ...`);
289
+ if (subcommand === "source") {
290
+ const [sourceSub, ...sourceRest] = rest;
291
+ if (!sourceSub ||
292
+ !TASK_SOURCE_SUBCOMMANDS.includes(sourceSub)) {
293
+ throw new Error(`usage: task source <${TASK_SOURCE_SUBCOMMANDS.join("|")}> ...`);
294
+ }
295
+ if (sourceSub === "prepare") {
296
+ await runTaskSourcePrepare(repoRoot, sourceRest);
297
+ return;
298
+ }
299
+ throw new Error(`usage: task source <${TASK_SOURCE_SUBCOMMANDS.join("|")}> ...`);
285
300
  }
286
- await runTaskContract(repoRoot, [contractSub, ...contractRest]);
301
+ throw new Error(formatSubcommandUsageError("task", TASK_SUBCOMMANDS));
287
302
  },
288
303
  },
289
304
  {
package/dist/cli/help.js CHANGED
@@ -24,9 +24,10 @@ export function formatCommandTierSummary(manifest = CODE_AGENT_COMMAND_MANIFEST)
24
24
  return [
25
25
  "Recommended DAG path:",
26
26
  " 1. new-task <task-id> [title]",
27
- " 2. import-prd <task-id> --file <original-prd> # optional but recommended",
28
- " 3. dag run-task <task-id> --profile auto --strict-models",
29
- " 4. run-dag --dag <path> --cwd <repo-root>",
27
+ " 2. import-prd <task-id> --file <detailed-prd> # PRD-first recommended",
28
+ " 3. task source prepare <task-id> --use-imported-prd --allowed-path <glob> --apply",
29
+ " 4. dag run-task <task-id> --profile auto --strict-models",
30
+ " 5. run-dag --dag <path> --cwd <repo-root>",
30
31
  "Operator recovery/closeout: dag status/report/doctor/closeout-draft",
31
32
  `Primary commands: ${primary}`,
32
33
  `Operator commands: ${operator}`,
@@ -41,6 +41,7 @@ import { runLoopBenchmark } from "../commands/loop-benchmark.js";
41
41
  import { runNewTask } from "../commands/new-task.js";
42
42
  import { runImportPrd } from "../commands/import-prd.js";
43
43
  import { runTaskContract } from "../commands/task-contract.js";
44
+ import { runTaskSourcePrepare } from "../commands/task-source-prepare.js";
44
45
  import { runOperator } from "../commands/operator.js";
45
46
  import { runPiReuseBenchmark } from "../commands/pi-reuse-benchmark.js";
46
47
  import { parsePiPromptArgs, printPiPromptUsage, runPiPrompt, } from "../commands/pi-prompt.js";
@@ -137,25 +138,33 @@ async function runCommanderAction(ctx, command, subcommand, rest) {
137
138
  await runImportPrd(ctx.repoRoot, compactArgs([subcommand, ...rest]));
138
139
  return;
139
140
  case "task": {
140
- if (subcommand !== "contract") {
141
- throw new Error("usage: task <contract> ...");
141
+ if (subcommand === "contract") {
142
+ const [contractSub, ...contractRest] = rest;
143
+ const allowed = [
144
+ "show",
145
+ "validate",
146
+ "diff",
147
+ "apply",
148
+ "adopt",
149
+ "doctor",
150
+ "recover",
151
+ ];
152
+ if (!contractSub ||
153
+ !allowed.includes(contractSub)) {
154
+ throw new Error(`usage: task contract <${allowed.join("|")}> ...`);
155
+ }
156
+ await runTaskContract(ctx.repoRoot, [contractSub, ...contractRest]);
157
+ return;
142
158
  }
143
- const [contractSub, ...contractRest] = rest;
144
- const allowed = [
145
- "show",
146
- "validate",
147
- "diff",
148
- "apply",
149
- "adopt",
150
- "doctor",
151
- "recover",
152
- ];
153
- if (!contractSub ||
154
- !allowed.includes(contractSub)) {
155
- throw new Error(`usage: task contract <${allowed.join("|")}> ...`);
159
+ if (subcommand === "source") {
160
+ const [sourceSub, ...sourceRest] = rest;
161
+ if (sourceSub !== "prepare") {
162
+ throw new Error("usage: task source <prepare> ...");
163
+ }
164
+ await runTaskSourcePrepare(ctx.repoRoot, sourceRest);
165
+ return;
156
166
  }
157
- await runTaskContract(ctx.repoRoot, [contractSub, ...contractRest]);
158
- return;
167
+ throw new Error("usage: task <contract|source> ...");
159
168
  }
160
169
  case "operator":
161
170
  await runOperator(ctx.repoRoot, compactArgs([subcommand, ...rest]));
@@ -437,6 +446,14 @@ function addStandaloneSubcommands(parent, subcommands, handler) {
437
446
  });
438
447
  }
439
448
  }
449
+ function configureTaskSourcePrepare(command) {
450
+ command
451
+ .description("Prepare deterministic task source files from a PRD or draft")
452
+ .usage("<task-id> [options]")
453
+ .option("--from-draft <path>", "TaskContractDraftV1 JSON path")
454
+ .option("--use-imported-prd", "use the task's imported PRD reference")
455
+ .option("--force-overwrite-source", "replace existing managed source files");
456
+ }
440
457
  function configureDagValidate(command) {
441
458
  command
442
459
  .description("Validate an Agent DAG spec")
@@ -662,6 +679,15 @@ export function buildLoopAgentProgram(options) {
662
679
  }
663
680
  if (entry.subcommands)
664
681
  addRawSubcommands(command, entry.subcommands, options.defaultRepoRoot);
682
+ if (entry.name === "task") {
683
+ const source = command.commands.find((child) => child.name() === "source");
684
+ if (source) {
685
+ const prepare = createRawArgsCommand("prepare", "Prepare deterministic task source files", options.defaultRepoRoot);
686
+ configureTaskSourcePrepare(prepare);
687
+ replaceActionWithOptionAwareDispatch(prepare, options.defaultRepoRoot);
688
+ source.addCommand(prepare);
689
+ }
690
+ }
665
691
  program.addCommand(command);
666
692
  }
667
693
  return program;
@@ -141,7 +141,7 @@ async function runCursorPromptBatch(task, cwd, model, timeoutMs) {
141
141
  }
142
142
  async function runCursorPromptStreaming(task, cwd, model, timeoutMs) {
143
143
  const startedAt = Date.now();
144
- process.stderr.write(`[cursor-prompt] streaming (model=${model}, cwd=${cwd})
144
+ process.stderr.write(`[cursor-prompt] streaming (model=${model}, cwd=${cwd})
145
145
  `);
146
146
  const runDir = (await computeRunDir(cwd, task)) ?? undefined;
147
147
  const result = await executeCursorPromptStream({
@@ -164,15 +164,15 @@ async function runCursorPromptStreaming(task, cwd, model, timeoutMs) {
164
164
  });
165
165
  const elapsed = ((Date.now() - startedAt) / 1000).toFixed(1);
166
166
  if (result.ok) {
167
- process.stderr.write(`
168
- [cursor-prompt] done in ${elapsed}s, status=${result.status}
167
+ process.stderr.write(`
168
+ [cursor-prompt] done in ${elapsed}s, status=${result.status}
169
169
  `);
170
170
  }
171
171
  else {
172
172
  const stderr = result.stderr || "(no output)";
173
- process.stderr.write(`
174
- [cursor-prompt] FAILED in ${elapsed}s (${result.failureCategory}):
175
- ${stderr}
173
+ process.stderr.write(`
174
+ [cursor-prompt] FAILED in ${elapsed}s (${result.failureCategory}):
175
+ ${stderr}
176
176
  `);
177
177
  process.exit(1);
178
178
  }
@@ -61,7 +61,11 @@ export async function runImportPrd(repoRoot, args) {
61
61
  .split(path.sep)
62
62
  .join("/"),
63
63
  referenceDocs: result.referenceDocs,
64
- message: "Imported PRD as an immutable source reference. Derive source/需求.md from it; do not rewrite the reference copy.",
64
+ message: "Imported PRD as an immutable source reference. Next: task source prepare --use-imported-prd (plus engineering --allowed-path/--verify) then --apply. Do not rewrite source/references/*.",
65
+ next: [
66
+ `loop-agent task source prepare ${result.taskId} --use-imported-prd --allowed-path <glob> --verify "typecheck:npm run typecheck" --json`,
67
+ `loop-agent task source prepare ${result.taskId} --use-imported-prd --allowed-path <glob> --apply --json`,
68
+ ],
65
69
  }, null, 2));
66
70
  return;
67
71
  }
@@ -71,6 +75,7 @@ export async function runImportPrd(repoRoot, args) {
71
75
  ` materialized: ${result.materializedRelativePath}`,
72
76
  ` sha256: ${result.sha256}`,
73
77
  ` manifest: ${path.relative(repoRoot, result.manifestPath).split(path.sep).join("/")}`,
74
- "Next: write source/需求.md as a derived execution contract with REQ/AC ids that map back to the original PRD. Do not edit source/references/*.",
78
+ "Next: loop-agent task source prepare <task-id> --use-imported-prd --allowed-path <glob> [--verify label:cmd] --apply --json",
79
+ "Do not hand-write source/需求.md or source/执行约束.md on the default path; do not edit source/references/*.",
75
80
  ].join("\n"));
76
81
  }
@@ -1811,14 +1811,15 @@ function buildManagedReadmeBlock(input) {
1811
1811
  "",
1812
1812
  "```bash",
1813
1813
  'loop-agent new-task <task-id> "任务标题"',
1814
- "# write .harness/tasks/<task-id>/source/需求.md",
1815
- "# write .harness/tasks/<task-id>/source/执行约束.md",
1814
+ "# 推荐:详细 PRD → import-prd → task source prepare --apply(无需手写两 source)",
1815
+ "# loop-agent import-prd <task-id> --file <prd.md>",
1816
+ 'loop-agent task source prepare <task-id> --use-imported-prd --allowed-path "<glob>" --apply --json',
1816
1817
  "loop-agent dag run-task <task-id> --profile auto --strict-models",
1817
1818
  "loop-agent dag validate --dag .harness/tasks/<task-id>/dag.json --strict-models --strict-governance",
1818
1819
  "loop-agent run-dag --dag .harness/tasks/<task-id>/dag.json --cwd .",
1819
1820
  "```",
1820
1821
  "",
1821
- `详细工作流见 \`${input.governanceRoot}/feature-workflow.md\`;验证矩阵见 \`${input.governanceRoot}/verification-matrix.md\`。任务 source 是必需项:\`source/需求.md\` 写目标、范围、非目标、验收标准和相关链接,\`source/执行约束.md\` 写允许路径、禁止路径、受保护变更、不变量、预期验证和失败条件。`,
1822
+ `详细工作流见 \`${input.governanceRoot}/feature-workflow.md\`;验证矩阵见 \`${input.governanceRoot}/verification-matrix.md\`。任务 source 仍必需(\`source/需求.md\` / \`source/执行约束.md\`),默认由 \`task source prepare --apply\` 从详细 PRD 确定性派生,而不是主会话手写或 LLM 写 md。`,
1822
1823
  "",
1823
1824
  "执行后使用 `loop-agent dag report --run-id <run-id> --markdown` 和 `loop-agent dag doctor --run-id <run-id> --markdown` 读取事实与诊断失败。失败 run 不做成功式 closeout;使用 `loop-agent dag closeout-draft --run-id <run-id>` 生成 failure handoff。",
1824
1825
  "",
@@ -2043,8 +2044,9 @@ function buildTargetFeatureWorkflow(input) {
2043
2044
  "",
2044
2045
  "```bash",
2045
2046
  'loop-agent new-task <task-id> "Task title"',
2046
- "# write .harness/tasks/<task-id>/source/需求.md",
2047
- "# write .harness/tasks/<task-id>/source/执行约束.md",
2047
+ "# Preferred: detailed PRD → import-prd → task source prepare --apply",
2048
+ "# loop-agent import-prd <task-id> --file <prd.md>",
2049
+ 'loop-agent task source prepare <task-id> --use-imported-prd --allowed-path "<glob>" --apply --json',
2048
2050
  "loop-agent dag run-task <task-id> --profile auto --strict-models",
2049
2051
  "loop-agent dag validate --dag .harness/tasks/<task-id>/dag.json --strict-models --strict-governance",
2050
2052
  "loop-agent run-dag --dag .harness/tasks/<task-id>/dag.json --cwd .",
@@ -37,17 +37,17 @@ export function parseLoopBenchmarkArgs(args) {
37
37
  return { json, markdown, outputPath };
38
38
  }
39
39
  export function printLoopBenchmarkUsage() {
40
- console.log(`usage: loop-benchmark [options]
41
-
42
- Deterministic loop-agent loop benchmark baseline (no live Pi/Cursor calls).
43
-
44
- Options:
45
- --json Emit JSON (default when no format flag is set)
46
- --markdown Emit Markdown report
47
- --output <path> Write Markdown report to a repo-relative or absolute path
48
- -h, --help Show this help
49
-
50
- Control groups: single-repair, 3-pass-convergence, 3-pass-convergence+quota.
40
+ console.log(`usage: loop-benchmark [options]
41
+
42
+ Deterministic loop-agent loop benchmark baseline (no live Pi/Cursor calls).
43
+
44
+ Options:
45
+ --json Emit JSON (default when no format flag is set)
46
+ --markdown Emit Markdown report
47
+ --output <path> Write Markdown report to a repo-relative or absolute path
48
+ -h, --help Show this help
49
+
50
+ Control groups: single-repair, 3-pass-convergence, 3-pass-convergence+quota.
51
51
  Recommendation never changes convergence.enabled default.`);
52
52
  }
53
53
  export async function runLoopBenchmark(repoRoot, rawArgs) {
@@ -106,22 +106,22 @@ export function parsePiReuseBenchmarkArgs(args) {
106
106
  };
107
107
  }
108
108
  export function printPiReuseBenchmarkUsage() {
109
- console.log(`usage: pi-reuse-benchmark [options]
110
-
111
- Deterministic Pi runtime reuse benchmark/decision summary (no live Pi calls).
112
-
113
- Options:
114
- --report <path> Benchmark report markdown (approval status)
115
- --approval <path> Explicit approval JSON artifact
116
- --off-executor <path> Baseline executor.jsonl (reuse off)
117
- --on-executor <path> Treatment executor.jsonl (reuse on)
118
- --off-task <task-id> Resolve baseline from .harness/tasks/<id>/logs/executor.jsonl
119
- --on-task <task-id> Resolve treatment from .harness/tasks/<id>/logs/executor.jsonl
120
- --json Emit JSON (default when no format flag is set)
121
- --markdown Emit Markdown summary
122
- -h, --help Show this help
123
-
124
- Recommendations: defer | maintain-opt-in | eligible-for-human-review
109
+ console.log(`usage: pi-reuse-benchmark [options]
110
+
111
+ Deterministic Pi runtime reuse benchmark/decision summary (no live Pi calls).
112
+
113
+ Options:
114
+ --report <path> Benchmark report markdown (approval status)
115
+ --approval <path> Explicit approval JSON artifact
116
+ --off-executor <path> Baseline executor.jsonl (reuse off)
117
+ --on-executor <path> Treatment executor.jsonl (reuse on)
118
+ --off-task <task-id> Resolve baseline from .harness/tasks/<id>/logs/executor.jsonl
119
+ --on-task <task-id> Resolve treatment from .harness/tasks/<id>/logs/executor.jsonl
120
+ --json Emit JSON (default when no format flag is set)
121
+ --markdown Emit Markdown summary
122
+ -h, --help Show this help
123
+
124
+ Recommendations: defer | maintain-opt-in | eligible-for-human-review
125
125
  Never changes CODE_AGENT_PI_REUSE_RUNTIME default (off).`);
126
126
  }
127
127
  function resolveRepoRelative(repoRoot, filePath) {