@tea-agent/loop-agent 0.13.0-beta.0 → 0.13.0

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 (282) hide show
  1. package/AGENTS.md +157 -155
  2. package/CHANGELOG.md +301 -322
  3. package/README.md +335 -345
  4. package/bin/agent-worker.js +22 -22
  5. package/bin/loop-agent.js +21 -21
  6. package/dist/commands/cursor-prompt.js +6 -6
  7. package/dist/commands/init.js +597 -528
  8. package/dist/commands/loop-benchmark.js +11 -11
  9. package/dist/commands/pi-reuse-benchmark.js +16 -16
  10. package/dist/executors/shell-executor.js +200 -21
  11. package/dist/infrastructure/evaluation/candidate-store.js +5 -1
  12. package/dist/sidecars/cursor-prompt/executor.js +1 -1
  13. package/dist/task/runtime.js +27 -27
  14. package/dist/worker/observe/static/api.js +46 -46
  15. package/dist/worker/observe/static/app.js +150 -150
  16. package/dist/worker/observe/static/constants.js +148 -148
  17. package/dist/worker/observe/static/copy.js +67 -67
  18. package/dist/worker/observe/static/dag-helpers.js +172 -172
  19. package/dist/worker/observe/static/dag-layout.d.ts +31 -31
  20. package/dist/worker/observe/static/dag-layout.js +83 -83
  21. package/dist/worker/observe/static/dag-model.js +72 -72
  22. package/dist/worker/observe/static/dom.js +212 -53
  23. package/dist/worker/observe/static/format-pool.js +67 -67
  24. package/dist/worker/observe/static/format.js +292 -292
  25. package/dist/worker/observe/static/index.html +308 -308
  26. package/dist/worker/observe/static/kpi.js +94 -94
  27. package/dist/worker/observe/static/relations.js +133 -133
  28. package/dist/worker/observe/static/router.js +93 -93
  29. package/dist/worker/observe/static/run-processing.js +148 -148
  30. package/dist/worker/observe/static/shell-chrome.js +68 -68
  31. package/dist/worker/observe/static/state.js +267 -253
  32. package/dist/worker/observe/static/styles.css +1902 -1902
  33. package/dist/worker/observe/static/views/batch.js +227 -227
  34. package/dist/worker/observe/static/views/dag-graph.js +172 -172
  35. package/dist/worker/observe/static/views/dag-inspector.js +627 -607
  36. package/dist/worker/observe/static/views/dag.js +371 -362
  37. package/dist/worker/observe/static/views/dashboard.js +509 -252
  38. package/dist/worker/observe/static/views/failures.js +143 -143
  39. package/dist/worker/observe/static/views/feature.js +492 -492
  40. package/dist/worker/observe/static/views/pool.js +350 -350
  41. package/dist/worker/observe/static/views/run.js +453 -453
  42. package/dist/worker/observe/static/views/session-timeline.js +219 -205
  43. package/dist/worker/observe/static/views/shell.js +7 -7
  44. package/dist/worker/observe/static/views/task.js +314 -314
  45. package/dist/worker/observe/static/views/timeline.js +163 -163
  46. package/dist/workflows/dag/backend-test-case-manifest.js +503 -0
  47. package/dist/workflows/dag/backend-test-execution-contract.js +353 -0
  48. package/dist/workflows/dag/backend-test-result-contract.js +568 -0
  49. package/dist/workflows/dag/canvas-observer.js +275 -275
  50. package/dist/workflows/dag/decision-envelope.js +57 -2
  51. package/dist/workflows/dag/frontend-implementation-contract.js +240 -0
  52. package/dist/workflows/dag/frontend-project-capability.js +309 -0
  53. package/dist/workflows/dag/frontend-repair.js +341 -0
  54. package/dist/workflows/dag/frontend-risk.js +161 -0
  55. package/dist/workflows/dag/frontend-verification-trace.js +190 -0
  56. package/dist/workflows/dag/init-hybrid.js +1020 -125
  57. package/dist/workflows/dag/repair-artifact.js +43 -3
  58. package/dist/workflows/dag/skill-instructions.js +4 -2
  59. package/dist/workflows/dag/types.js +29 -8
  60. package/docs/README.md +105 -104
  61. package/docs/agent-dag-recovery-playbook.md +195 -195
  62. package/docs/agent-dag-runner.md +67 -67
  63. package/docs/architecture/README.md +26 -26
  64. package/docs/architecture/dag-execution.md +140 -140
  65. package/docs/architecture/evolution.md +54 -54
  66. package/docs/architecture/facts-and-state.md +71 -71
  67. package/docs/architecture/runtime-boundaries.md +191 -191
  68. package/docs/architecture/system-overview.md +93 -93
  69. package/docs/architecture/worker-and-feature.md +85 -85
  70. package/docs/cursor-prompt-sidecar.md +36 -36
  71. package/docs/decisions/README.md +18 -18
  72. package/docs/design/README.md +167 -167
  73. package/docs/development-principles.md +73 -73
  74. package/docs/exec-plans/README.md +6 -6
  75. package/docs/exec-plans/active/README.md +1 -4
  76. package/docs/exec-plans/completed/README.md +106 -84
  77. package/docs/feature-workflow.md +414 -389
  78. package/docs/harness-methodology-debugging.md +153 -153
  79. package/docs/harness-methodology-tdd.md +130 -130
  80. package/docs/harness-methodology-verification.md +27 -27
  81. package/docs/init-surface.manifest.json +307 -289
  82. package/docs/loop-agent-harness.md +142 -142
  83. package/docs/production-readiness.md +96 -96
  84. package/docs/progress/README.md +76 -60
  85. package/docs/reports/README.md +150 -108
  86. package/docs/skills/README.md +7 -7
  87. package/docs/skills/vetted-skill-registry.md +29 -29
  88. package/docs/templates/adr.md +60 -60
  89. package/docs/templates/agent-dag-authority-surface-audit.prompt.md +94 -94
  90. package/docs/templates/agent-dag-decision-envelope.schema.json +213 -213
  91. package/docs/templates/agent-dag-decision-gate-dogfood-report.md +117 -117
  92. package/docs/templates/agent-dag-decision-gate.prompt.md +246 -246
  93. package/docs/templates/agent-dag-process-supervisor.prompt.md +98 -98
  94. package/docs/templates/agent-dag-report.schema.json +473 -473
  95. package/docs/templates/agent-dag-review-verdict.prompt.md +68 -68
  96. package/docs/templates/agent-dag.base.json +190 -190
  97. package/docs/templates/agent-dag.final-verification.json +185 -185
  98. package/docs/templates/agent-dag.schema.json +411 -411
  99. package/docs/templates/agent-dag.supervised-implementation.json +620 -501
  100. package/docs/templates/backend-test-analysis.schema.json +44 -44
  101. package/docs/templates/backend-test-case-manifest.schema.json +190 -0
  102. package/docs/templates/backend-test-dag.classify.prompt.md +75 -0
  103. package/docs/templates/backend-test-dag.generate-pytest.prompt.md +204 -202
  104. package/docs/templates/backend-test-dag.json +559 -311
  105. package/docs/templates/backend-test-dag.retrospect.prompt.md +139 -125
  106. package/docs/templates/backend-test-dag.review-cases.prompt.md +83 -81
  107. package/docs/templates/backend-test-execution.schema.json +133 -0
  108. package/docs/templates/backend-test-result.schema.json +99 -0
  109. package/docs/templates/branch-merge-report.md +93 -0
  110. package/docs/templates/exec-plan.md +64 -64
  111. package/docs/templates/feature-spec.md +53 -53
  112. package/docs/templates/frontend-design-contract.md +42 -42
  113. package/docs/templates/frontend-eval/fixtures/failures/01-type-build-error.md +17 -0
  114. package/docs/templates/frontend-eval/fixtures/failures/02-unit-component-test-fail.md +16 -0
  115. package/docs/templates/frontend-eval/fixtures/failures/03-fixture-schema-drift.md +16 -0
  116. package/docs/templates/frontend-eval/fixtures/failures/04-missing-loading-empty-error-state.md +16 -0
  117. package/docs/templates/frontend-eval/fixtures/failures/05-forbidden-write-writeset-expansion.md +16 -0
  118. package/docs/templates/frontend-eval/fixtures/failures/06-unapproved-dependency-add.md +16 -0
  119. package/docs/templates/frontend-eval/fixtures/failures/07-mock-production-on.md +21 -0
  120. package/docs/templates/frontend-eval/fixtures/functional/01-simple-component-style.md +29 -0
  121. package/docs/templates/frontend-eval/fixtures/functional/02-form-validation.md +28 -0
  122. package/docs/templates/frontend-eval/fixtures/functional/03-list-detail-page.md +28 -0
  123. package/docs/templates/frontend-eval/fixtures/functional/04-api-mock.md +29 -0
  124. package/docs/templates/frontend-eval/fixtures/functional/05-permission-auth-gated-ui.md +27 -0
  125. package/docs/templates/frontend-eval/fixtures/functional/06-ssr-server-client-boundary.md +28 -0
  126. package/docs/templates/frontend-eval/fixtures/functional/07-shared-public-component-api.md +28 -0
  127. package/docs/templates/frontend-eval/fixtures/functional/08-pure-local-no-remote.md +27 -0
  128. package/docs/templates/frontend-eval/metrics.md +138 -0
  129. package/docs/templates/frontend-eval/smoke-targets.md +53 -0
  130. package/docs/templates/frontend-implementation-contract.schema.json +27 -0
  131. package/docs/templates/frontend-task-constraints.md +35 -35
  132. package/docs/templates/frontend-task-requirement.md +70 -70
  133. package/docs/templates/frontend-test-dag.generate-cases.prompt.md +5 -5
  134. package/docs/templates/frontend-test-dag.json +23 -23
  135. package/docs/templates/frontend-test-dag.retrieve-context.prompt.md +3 -3
  136. package/docs/templates/frontend-test-dag.retrospect.prompt.md +3 -3
  137. package/docs/templates/frontend-test-dag.review-cases.prompt.md +3 -3
  138. package/docs/templates/frontend-test-dag.review-execution.prompt.md +3 -3
  139. package/docs/templates/harness.schema.json +221 -221
  140. package/docs/templates/hybrid-dag.json +188 -188
  141. package/docs/templates/init-evolution-review.md +35 -35
  142. package/docs/templates/interactive-ui-round2-experiment.md +66 -66
  143. package/docs/templates/knowledge-graph-bootstrap-dag.json +118 -118
  144. package/docs/templates/knowledge-sync-dag.json +178 -178
  145. package/docs/templates/knowledge-sync-draft.schema.json +71 -71
  146. package/docs/templates/product-line/AGENTS.md +8 -8
  147. package/docs/templates/product-line/README.md +9 -9
  148. package/docs/templates/product-line/acceptance.yaml +14 -14
  149. package/docs/templates/product-line/closeout.yaml +9 -9
  150. package/docs/templates/product-line/design.md +13 -13
  151. package/docs/templates/product-line/links.md +10 -10
  152. package/docs/templates/product-line/requirement.md +17 -17
  153. package/docs/templates/product-line/task-graph.yaml +15 -15
  154. package/docs/templates/product-line/task.yaml +64 -64
  155. package/docs/templates/product-line/test-plan.md +7 -7
  156. package/docs/templates/production-readiness-checklist.md +57 -57
  157. package/docs/templates/progress-log.md +17 -17
  158. package/docs/templates/project-start-checklist.md +9 -9
  159. package/docs/templates/qa-report.md +48 -48
  160. package/docs/templates/sprint-contract.md +29 -29
  161. package/docs/templates/worker-dogfood-evidence.md +80 -80
  162. package/docs/templates/worker-dogfood-setup.md +68 -68
  163. package/docs/verification-matrix.md +70 -70
  164. package/examples/decision-gate-agent-dag.json +177 -177
  165. package/examples/example-dag.json +46 -46
  166. package/examples/hybrid-loop-agent-dag.json +189 -189
  167. package/harness.json +66 -66
  168. package/package.json +52 -88
  169. package/scripts/check-product-line-docs.sh +29 -29
  170. package/scripts/check-task-pool-root.sh +32 -32
  171. package/scripts/kb-bootstrap-init-skeleton.sh +240 -240
  172. package/scripts/kb-graph-incremental-prepare.mjs +386 -386
  173. package/scripts/kb-graph-incremental-prepare.sh +5 -5
  174. package/scripts/kb-graph-materialize.mjs +105 -105
  175. package/scripts/kb-graph-materialize.sh +4 -4
  176. package/scripts/kb-graph-promote.mjs +164 -164
  177. package/scripts/kb-graph-promote.sh +4 -4
  178. package/scripts/kb-query.mjs +554 -554
  179. package/scripts/kb-query.sh +5 -5
  180. package/skills/agent-worker/SKILL.md +39 -39
  181. package/skills/agent-worker/references/agent-worker-operator.md +60 -60
  182. package/skills/ai-engineering-context/SKILL.md +48 -48
  183. package/skills/analyze-product-dependencies/SKILL.md +67 -67
  184. package/skills/analyze-product-dependencies/agents/openai.yaml +4 -4
  185. package/skills/analyze-product-dependencies/references/api-documentation-schema.md +30 -30
  186. package/skills/analyze-product-dependencies/references/dependency-analysis-schema.md +28 -28
  187. package/skills/analyze-product-dependencies/references/example.md +76 -76
  188. package/skills/analyze-product-dependencies/references/forward-test-cases.md +35 -35
  189. package/skills/analyze-product-dependencies/references/input-contract.md +11 -11
  190. package/skills/analyze-product-dependencies/references/scouting-rules.md +61 -61
  191. package/skills/analyze-product-dependencies/scripts/test-validators.mjs +267 -267
  192. package/skills/analyze-product-dependencies/scripts/validate-api-documentation.mjs +101 -101
  193. package/skills/analyze-product-dependencies/scripts/validate-dependency-analysis.mjs +142 -142
  194. package/skills/analyze-product-dependencies/scripts/validate-product-requirement-input.mjs +76 -76
  195. package/skills/analyze-product-dependencies/scripts/validation-helpers.mjs +146 -146
  196. package/skills/analyze-product-requirements/SKILL.md +90 -90
  197. package/skills/analyze-product-requirements/agents/openai.yaml +4 -4
  198. package/skills/analyze-product-requirements/references/acceptance-criteria.md +91 -91
  199. package/skills/analyze-product-requirements/references/clarification-and-knowledge.md +56 -56
  200. package/skills/analyze-product-requirements/references/example.md +86 -86
  201. package/skills/analyze-product-requirements/references/forward-test-cases.md +66 -66
  202. package/skills/analyze-product-requirements/references/product-analysis-schema.md +32 -32
  203. package/skills/analyze-product-requirements/references/product-requirement-schema.md +33 -33
  204. package/skills/analyze-product-requirements/references/requirement-clarification-schema.md +35 -35
  205. package/skills/analyze-product-requirements/scripts/test-validators.mjs +193 -193
  206. package/skills/analyze-product-requirements/scripts/validate-product-analysis.mjs +69 -69
  207. package/skills/analyze-product-requirements/scripts/validate-product-requirement.mjs +97 -97
  208. package/skills/analyze-product-requirements/scripts/validate-requirement-clarification.mjs +98 -98
  209. package/skills/analyze-product-requirements/scripts/validation-helpers.mjs +156 -156
  210. package/skills/browser-tools/SKILL.md +196 -0
  211. package/skills/browser-tools/browser-content.js +103 -0
  212. package/skills/browser-tools/browser-cookies.js +35 -0
  213. package/skills/browser-tools/browser-eval.js +53 -0
  214. package/skills/browser-tools/browser-hn-scraper.js +108 -0
  215. package/skills/browser-tools/browser-nav.js +44 -0
  216. package/skills/browser-tools/browser-pick.js +162 -0
  217. package/skills/browser-tools/browser-screenshot.js +34 -0
  218. package/skills/browser-tools/browser-start.js +86 -0
  219. package/skills/browser-tools/package-lock.json +2556 -0
  220. package/skills/browser-tools/package.json +19 -0
  221. package/skills/code-review-core/SKILL.md +20 -20
  222. package/skills/codebase-scout/SKILL.md +19 -19
  223. package/skills/frontend-design-review/SKILL.md +66 -66
  224. package/skills/frontend-design-review/references/review-checklist.md +58 -58
  225. package/skills/frontend-implementation/SKILL.md +49 -47
  226. package/skills/frontend-implementation/references/code-standards.md +32 -32
  227. package/skills/frontend-implementation/references/design-spec.md +46 -46
  228. package/skills/frontend-implementation/references/node-contracts.md +27 -76
  229. package/skills/frontend-review/SKILL.md +59 -59
  230. package/skills/frontend-review/references/review-findings.md +47 -47
  231. package/skills/frontend-verification/SKILL.md +53 -53
  232. package/skills/frontend-verification/references/verification-checklist.md +68 -68
  233. package/skills/grill-me/SKILL.md +10 -10
  234. package/skills/grill-with-docs/SKILL.md +88 -88
  235. package/skills/grill-with-docs/adr-format.md +47 -47
  236. package/skills/grill-with-docs/context-format.md +60 -60
  237. package/skills/init-capability-evolution/SKILL.md +70 -70
  238. package/skills/loop-agent/SKILL.md +151 -151
  239. package/skills/loop-agent/references/README.md +67 -67
  240. package/skills/loop-agent/references/command-reference.md +527 -505
  241. package/skills/loop-agent/references/docs-converge.md +126 -126
  242. package/skills/loop-agent/references/harness-policy.md +263 -263
  243. package/skills/loop-agent/references/hybrid-dag.md +243 -238
  244. package/skills/loop-agent/references/learned/README.md +21 -21
  245. package/skills/loop-agent/references/long-running-loop.md +57 -57
  246. package/skills/loop-agent/references/model-routing.md +36 -36
  247. package/skills/loop-agent/references/multi-worktree.md +54 -54
  248. package/skills/loop-agent/references/one-shot-runs.md +85 -85
  249. package/skills/loop-agent/references/orchestrator-and-interventions.md +169 -169
  250. package/skills/loop-agent/references/pi-prompt.md +23 -23
  251. package/skills/loop-agent/references/pi-subagent-assisted-mode.md +84 -84
  252. package/skills/loop-agent/references/post-implementation-and-patterns.md +44 -44
  253. package/skills/loop-agent/references/task-workflow.md +89 -89
  254. package/skills/loop-agent/references/verification-and-failure-handling.md +141 -139
  255. package/skills/playwright-cli/SKILL.md +420 -420
  256. package/skills/playwright-cli/references/element-attributes.md +23 -23
  257. package/skills/playwright-cli/references/playwright-tests.md +39 -39
  258. package/skills/playwright-cli/references/request-mocking.md +87 -87
  259. package/skills/playwright-cli/references/running-code.md +241 -241
  260. package/skills/playwright-cli/references/session-management.md +225 -225
  261. package/skills/playwright-cli/references/storage-state.md +275 -275
  262. package/skills/playwright-cli/references/test-generation.md +433 -433
  263. package/skills/playwright-cli/references/tracing.md +139 -139
  264. package/skills/playwright-cli/references/video-recording.md +143 -143
  265. package/skills/playwright-cli-case-generator/SKILL.md +74 -74
  266. package/skills/requesting-code-review/SKILL.md +101 -101
  267. package/skills/requesting-code-review/code-reviewer.md +168 -168
  268. package/skills/systematic-debugging/CREATION-LOG.md +119 -119
  269. package/skills/systematic-debugging/SKILL.md +296 -296
  270. package/skills/systematic-debugging/condition-based-waiting-example.ts +158 -158
  271. package/skills/systematic-debugging/condition-based-waiting.md +115 -115
  272. package/skills/systematic-debugging/defense-in-depth.md +122 -122
  273. package/skills/systematic-debugging/find-polluter.sh +63 -63
  274. package/skills/systematic-debugging/root-cause-tracing.md +169 -169
  275. package/skills/systematic-debugging/test-academic.md +14 -14
  276. package/skills/systematic-debugging/test-pressure-1.md +58 -58
  277. package/skills/systematic-debugging/test-pressure-2.md +68 -68
  278. package/skills/systematic-debugging/test-pressure-3.md +69 -69
  279. package/skills/test-driven-development/SKILL.md +20 -20
  280. package/skills/using-git-worktrees/SKILL.md +215 -215
  281. package/skills/verification-before-completion/SKILL.md +154 -154
  282. package/skills/webapp-testing/SKILL.md +19 -19
@@ -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) {
@@ -3,8 +3,14 @@ import { appendFileSync, existsSync, mkdirSync, writeFileSync } from "node:fs";
3
3
  import path from "node:path";
4
4
  import { writeDagNodeTextArtifact } from "../infrastructure/harness/artifact-store.js";
5
5
  import { truncateOutput } from "../shared/output-truncation.js";
6
- import { buildRequirementCoverageGateShellCommand, expandShellPreset, buildVerdictGateShellCommand } from "./shell-presets.js";
6
+ import { buildRequirementCoverageGateShellCommand, expandShellPreset, buildVerdictGateShellCommand, } from "./shell-presets.js";
7
7
  import { materializeBackendTestAnalysisContract } from "../workflows/dag/backend-test-analysis-contract.js";
8
+ import { materializeFrontendImplementationContract } from "../workflows/dag/frontend-implementation-contract.js";
9
+ import { formatFrontendVerificationTraceStdout, runFrontendVerificationTraceGate, } from "../workflows/dag/frontend-verification-trace.js";
10
+ import { formatFrontendFailureAssessStdout, formatFrontendRepairContractStdout, runFrontendFailureAssessGate, runFrontendRepairContractGate, } from "../workflows/dag/frontend-repair.js";
11
+ import { formatTraceabilityGateStdout, materializeBackendTestCaseManifest, runBackendTestTraceabilityGate, } from "../workflows/dag/backend-test-case-manifest.js";
12
+ import { materializeBackendTestExecutionContract } from "../workflows/dag/backend-test-execution-contract.js";
13
+ import { materializeBackendTestResultFromRunDir } from "../workflows/dag/backend-test-result-contract.js";
8
14
  import { pathsChangedDuringRun, snapshotGitStatusPorcelain, validateShellWriteGuard, } from "./shell-write-guard.js";
9
15
  import { buildShellProcessEnv } from "./shell-verification.js";
10
16
  const DEFAULT_SHELL_TIMEOUT_MS = 300_000;
@@ -24,7 +30,9 @@ function resolveBashExecutable() {
24
30
  path.join(process.env["ProgramFiles(x86)"] ?? "C:\\Program Files (x86)", "Git", "bin", "bash.exe"),
25
31
  path.join(process.env.LocalAppData ?? "", "Programs", "Git", "bin", "bash.exe"),
26
32
  ].filter(Boolean);
27
- return candidates.find((candidate) => existsSync(candidate)) ?? envCandidate ?? "bash";
33
+ return (candidates.find((candidate) => existsSync(candidate)) ??
34
+ envCandidate ??
35
+ "bash");
28
36
  }
29
37
  function isWithinRoot(root, candidate) {
30
38
  const relative = path.relative(root, candidate);
@@ -48,7 +56,12 @@ export function resolveShellCommands(shell) {
48
56
  const fromRequirementCoverageGate = shell.requirementCoverageGate
49
57
  ? [buildRequirementCoverageGateShellCommand(shell.requirementCoverageGate)]
50
58
  : [];
51
- return [...fromPreset, ...explicit, ...fromVerdictGate, ...fromRequirementCoverageGate];
59
+ return [
60
+ ...fromPreset,
61
+ ...explicit,
62
+ ...fromVerdictGate,
63
+ ...fromRequirementCoverageGate,
64
+ ];
52
65
  }
53
66
  async function readGitStatusPorcelain(cwd) {
54
67
  return new Promise((resolve, reject) => {
@@ -145,13 +158,16 @@ export async function executeShellCommand(input) {
145
158
  });
146
159
  });
147
160
  child.on("close", (code) => {
161
+ let failureCategory = "nonzero-exit";
162
+ if (timedOut) {
163
+ failureCategory = "timeout";
164
+ }
165
+ else if (code === 0) {
166
+ failureCategory = "success";
167
+ }
148
168
  finish({
149
169
  exitCode: code,
150
- failureCategory: timedOut
151
- ? "timeout"
152
- : code === 0
153
- ? "success"
154
- : "nonzero-exit",
170
+ failureCategory,
155
171
  ok: code === 0 && !timedOut,
156
172
  });
157
173
  });
@@ -286,16 +302,164 @@ export async function executeDagShellNode(input, meta) {
286
302
  if (shell?.jsonArtifactGate) {
287
303
  const started = Date.now();
288
304
  try {
289
- const artifact = await materializeBackendTestAnalysisContract({
305
+ const gate = shell.jsonArtifactGate;
306
+ let artifact;
307
+ switch (gate.schemaId) {
308
+ case "backend-test-analysis-v1":
309
+ artifact = await materializeBackendTestAnalysisContract({
310
+ runDir: meta.runDir,
311
+ fromNodeId: gate.fromNodeId,
312
+ artifactName: gate.artifactName,
313
+ outputDir: gate.outputDir,
314
+ sourceBinding: meta.spec.sourceBinding,
315
+ });
316
+ break;
317
+ case "backend-test-execution-v1":
318
+ artifact = await materializeBackendTestExecutionContract({
319
+ runDir: meta.runDir,
320
+ fromNodeId: gate.fromNodeId,
321
+ artifactName: gate.artifactName,
322
+ outputDir: gate.outputDir,
323
+ });
324
+ break;
325
+ case "backend-test-result-v1":
326
+ artifact = await materializeBackendTestResultFromRunDir({
327
+ runDir: meta.runDir,
328
+ fromNodeId: gate.fromNodeId,
329
+ artifactName: gate.artifactName,
330
+ outputDir: gate.outputDir,
331
+ });
332
+ break;
333
+ case "backend-test-case-manifest-v1":
334
+ artifact = await materializeBackendTestCaseManifest({
335
+ runDir: meta.runDir,
336
+ fromNodeId: gate.fromNodeId,
337
+ artifactName: gate.artifactName,
338
+ outputDir: gate.outputDir,
339
+ sourceBinding: meta.spec.sourceBinding,
340
+ });
341
+ break;
342
+ case "frontend-implementation-contract-v1":
343
+ artifact = await materializeFrontendImplementationContract({
344
+ runDir: meta.runDir,
345
+ fromNodeId: gate.fromNodeId,
346
+ artifactName: gate.artifactName,
347
+ outputDir: gate.outputDir,
348
+ sourceBinding: meta.spec.sourceBinding,
349
+ });
350
+ break;
351
+ default:
352
+ throw new Error(`unsupported jsonArtifactGate.schemaId: ${String(gate.schemaId)}`);
353
+ }
354
+ return {
355
+ ok: true,
356
+ stdout: `Structured artifact: ${artifact.path}\nSchema: ${artifact.schemaId}\nSHA-256: ${artifact.sha256}`,
357
+ stderr: "",
358
+ failureCategory: "success",
359
+ durationMs: Date.now() - started,
360
+ };
361
+ }
362
+ catch (error) {
363
+ return {
364
+ ok: false,
365
+ stdout: "",
366
+ stderr: error instanceof Error ? error.message : String(error),
367
+ failureCategory: "invalid-output",
368
+ durationMs: Date.now() - started,
369
+ };
370
+ }
371
+ }
372
+ if (shell?.commands?.length === 1 &&
373
+ shell.commands[0] === "backend-test-traceability-gate") {
374
+ const started = Date.now();
375
+ try {
376
+ const result = await runBackendTestTraceabilityGate({
290
377
  runDir: meta.runDir,
291
- fromNodeId: shell.jsonArtifactGate.fromNodeId,
292
- artifactName: shell.jsonArtifactGate.artifactName,
293
- outputDir: shell.jsonArtifactGate.outputDir,
294
- sourceBinding: meta.spec.sourceBinding,
378
+ workspaceRoot: input.cwd,
295
379
  });
296
380
  return {
297
381
  ok: true,
298
- stdout: `Structured artifact: ${artifact.path}\nSchema: ${artifact.schemaId}\nSHA-256: ${artifact.sha256}`,
382
+ stdout: formatTraceabilityGateStdout(result),
383
+ stderr: "",
384
+ failureCategory: "success",
385
+ durationMs: Date.now() - started,
386
+ };
387
+ }
388
+ catch (error) {
389
+ return {
390
+ ok: false,
391
+ stdout: "",
392
+ stderr: error instanceof Error ? error.message : String(error),
393
+ failureCategory: "invalid-output",
394
+ durationMs: Date.now() - started,
395
+ };
396
+ }
397
+ }
398
+ if (shell?.commands?.length === 1 &&
399
+ shell.commands[0] === "frontend-verification-trace-gate") {
400
+ const started = Date.now();
401
+ try {
402
+ const result = await runFrontendVerificationTraceGate({
403
+ runDir: meta.runDir,
404
+ workspaceRoot: input.cwd,
405
+ });
406
+ return {
407
+ ok: true,
408
+ stdout: formatFrontendVerificationTraceStdout(result),
409
+ stderr: "",
410
+ failureCategory: "success",
411
+ durationMs: Date.now() - started,
412
+ };
413
+ }
414
+ catch (error) {
415
+ const stderr = error instanceof Error ? error.message : String(error);
416
+ const recordNonZero = shell.nonZeroExitPolicy === "record";
417
+ return {
418
+ ok: recordNonZero,
419
+ stdout: recordNonZero
420
+ ? "nonZeroExitPolicy=record failureCategory=invalid-output\n"
421
+ : "",
422
+ stderr,
423
+ failureCategory: "invalid-output",
424
+ durationMs: Date.now() - started,
425
+ };
426
+ }
427
+ }
428
+ if (shell?.commands?.length === 1 &&
429
+ shell.commands[0] === "frontend-failure-assess-gate") {
430
+ const started = Date.now();
431
+ try {
432
+ const result = await runFrontendFailureAssessGate({
433
+ runDir: meta.runDir,
434
+ });
435
+ return {
436
+ ok: true,
437
+ stdout: formatFrontendFailureAssessStdout(result),
438
+ stderr: "",
439
+ failureCategory: "success",
440
+ durationMs: Date.now() - started,
441
+ };
442
+ }
443
+ catch (error) {
444
+ return {
445
+ ok: false,
446
+ stdout: "",
447
+ stderr: error instanceof Error ? error.message : String(error),
448
+ failureCategory: "invalid-output",
449
+ durationMs: Date.now() - started,
450
+ };
451
+ }
452
+ }
453
+ if (shell?.commands?.length === 1 &&
454
+ shell.commands[0] === "frontend-repair-contract-gate") {
455
+ const started = Date.now();
456
+ try {
457
+ const result = await runFrontendRepairContractGate({
458
+ runDir: meta.runDir,
459
+ });
460
+ return {
461
+ ok: true,
462
+ stdout: formatFrontendRepairContractStdout(result.assessment),
299
463
  stderr: "",
300
464
  failureCategory: "success",
301
465
  durationMs: Date.now() - started,
@@ -362,7 +526,8 @@ export async function executeDagShellNode(input, meta) {
362
526
  }
363
527
  }
364
528
  const commandsOk = results.every((result) => result.ok);
365
- const ok = commandsOk && writeGuardOk;
529
+ const recordNonZero = shell.nonZeroExitPolicy === "record";
530
+ const ok = (commandsOk || recordNonZero) && writeGuardOk;
366
531
  const firstFailure = results.find((result) => !result.ok);
367
532
  await writeDagNodeTextArtifact(meta.runDir, input.task.id, "result.summary.md", buildShellResultSummaryMarkdown({
368
533
  nodeId: input.task.id,
@@ -376,15 +541,29 @@ export async function executeDagShellNode(input, meta) {
376
541
  if (!writeGuardOk) {
377
542
  stderrParts.push(`write guard failed: ${writeGuardViolations.join(", ")}`);
378
543
  }
544
+ let failureCategory = "success";
545
+ if (!commandsOk) {
546
+ failureCategory = firstFailure?.failureCategory ?? "nonzero-exit";
547
+ }
548
+ else if (!writeGuardOk) {
549
+ failureCategory = "write-guard";
550
+ }
551
+ const commandResults = results.map((result) => ({
552
+ ok: result.ok,
553
+ exitCode: result.exitCode,
554
+ failureCategory: result.failureCategory,
555
+ command: result.command,
556
+ }));
557
+ const recordPrefix = recordNonZero && !commandsOk
558
+ ? `nonZeroExitPolicy=record exitCode=${firstFailure?.exitCode ?? "null"}\n`
559
+ : "";
379
560
  return {
380
561
  ok,
381
- stdout: aggregate.stdout,
562
+ stdout: `${recordPrefix}${aggregate.stdout}`,
382
563
  stderr: stderrParts.filter(Boolean).join("\n\n"),
383
- failureCategory: !commandsOk
384
- ? (firstFailure?.failureCategory ?? "nonzero-exit")
385
- : !writeGuardOk
386
- ? "write-guard"
387
- : "success",
564
+ failureCategory,
388
565
  durationMs: Date.now() - started,
566
+ // extra field consumed by node-execution if supported; also embedded in stdout marker
567
+ ...{ commandResults },
389
568
  };
390
569
  }
@@ -272,7 +272,11 @@ export async function registerCandidateManifest(input) {
272
272
  }
273
273
  catch (error) {
274
274
  const code = error.code;
275
- if (code !== "EEXIST" && code !== "ENOTEMPTY")
275
+ const isCreateRace = code === "EEXIST" ||
276
+ code === "ENOTEMPTY" ||
277
+ (code === "EPERM" &&
278
+ (await pathExists(candidateDir(repoRoot, manifest.candidateId))));
279
+ if (!isCreateRace)
276
280
  throw error;
277
281
  await rm(stagingDir, { recursive: true, force: true });
278
282
  return readExistingRegistration(repoRoot, manifest, manifestPath, lifecyclePath);
@@ -29,7 +29,7 @@ export function resolveArtifactWriteDir(options) {
29
29
  }
30
30
  export function buildArtifactPathPrompt(writeDir) {
31
31
  if (!writeDir)
32
- return `After changes, write artifacts/修改记录.md and artifacts/验证结果.md with verification evidence.
32
+ return `After changes, write artifacts/修改记录.md and artifacts/验证结果.md with verification evidence.
33
33
  ${ARTIFACT_INSTRUCTIONS}`;
34
34
  return [
35
35
  `After changes, write the following files:`,
@@ -236,35 +236,35 @@ export function shouldInjectSubagentGuidance(step, mode) {
236
236
  return false;
237
237
  }
238
238
  /** Advisory guidance for `analyze-plan` mode. */
239
- export const SUBAGENT_GUIDANCE_STANDARD = `<subagent_guidance>
240
- You have access to the \`subagent\` tool for lightweight delegation within this step.
241
- Use it only for read-only tasks:
242
- - Parallel scout: dispatch multiple subagents to search/read different areas simultaneously
243
- - Chain: scout -> planner (one subagent scouts, another plans based on findings)
244
- - Reviewer: have a subagent review your analysis/plan before finalizing
245
- Do NOT use subagent for writing, editing, or executing commands.
246
- Subagent output is advisory only; always verify and incorporate findings into your own output.
247
- Do NOT treat subagent results as authoritative state or artifact sources.
239
+ export const SUBAGENT_GUIDANCE_STANDARD = `<subagent_guidance>
240
+ You have access to the \`subagent\` tool for lightweight delegation within this step.
241
+ Use it only for read-only tasks:
242
+ - Parallel scout: dispatch multiple subagents to search/read different areas simultaneously
243
+ - Chain: scout -> planner (one subagent scouts, another plans based on findings)
244
+ - Reviewer: have a subagent review your analysis/plan before finalizing
245
+ Do NOT use subagent for writing, editing, or executing commands.
246
+ Subagent output is advisory only; always verify and incorporate findings into your own output.
247
+ Do NOT treat subagent results as authoritative state or artifact sources.
248
248
  </subagent_guidance>`;
249
249
  /** Strong guidance for `full` mode — prescriptive when to delegate. */
250
- export const SUBAGENT_GUIDANCE_STRONG = `<subagent_guidance>
251
- You have access to the \`subagent\` tool for lightweight delegation within this step.
252
-
253
- You SHOULD delegate to subagent scouts when:
254
- - The task requires scanning 3+ directories or comparing implementations across modules
255
- - You would otherwise need 5+ sequential read/grep calls to gather context
256
- - A reviewer subagent can independently catch scope drift before you finalize your output
257
-
258
- Delegation saves context tokens and produces better results.
259
-
260
- Allowed patterns:
261
- - Parallel scout: dispatch 2-3 subagents simultaneously to cover different file trees
262
- - Chain: scout -> planner (one subagent scouts, another plans based on findings)
263
- - Reviewer: have a subagent review your analysis/plan before finalizing
264
-
265
- Do NOT use subagent for writing, editing, or executing commands.
266
- Subagent output is advisory only; always verify and incorporate findings into your own output.
267
- Do NOT treat subagent results as authoritative state or artifact sources.
250
+ export const SUBAGENT_GUIDANCE_STRONG = `<subagent_guidance>
251
+ You have access to the \`subagent\` tool for lightweight delegation within this step.
252
+
253
+ You SHOULD delegate to subagent scouts when:
254
+ - The task requires scanning 3+ directories or comparing implementations across modules
255
+ - You would otherwise need 5+ sequential read/grep calls to gather context
256
+ - A reviewer subagent can independently catch scope drift before you finalize your output
257
+
258
+ Delegation saves context tokens and produces better results.
259
+
260
+ Allowed patterns:
261
+ - Parallel scout: dispatch 2-3 subagents simultaneously to cover different file trees
262
+ - Chain: scout -> planner (one subagent scouts, another plans based on findings)
263
+ - Reviewer: have a subagent review your analysis/plan before finalizing
264
+
265
+ Do NOT use subagent for writing, editing, or executing commands.
266
+ Subagent output is advisory only; always verify and incorporate findings into your own output.
267
+ Do NOT treat subagent results as authoritative state or artifact sources.
268
268
  </subagent_guidance>`;
269
269
  /** Preserved for backward compatibility (alias of STANDARD). */
270
270
  export const SUBAGENT_GUIDANCE = SUBAGENT_GUIDANCE_STANDARD;
@@ -1,46 +1,46 @@
1
- /** Fetch and artifact helpers (Observe UI R5). */
2
-
3
- export async function fetchJson(url) {
4
- try {
5
- const res = await fetch(url);
6
- if (!res.ok) return null;
7
- return await res.json();
8
- } catch {
9
- return null;
10
- }
11
- }
12
-
13
- /**
14
- * Read-only JSON fetch that preserves HTTP status so callers can distinguish
15
- * 404 (missing) from 409 (ambiguous task identity). Body is parsed best-effort.
16
- */
17
- export async function fetchJsonResult(url) {
18
- try {
19
- const res = await fetch(url);
20
- let body = null;
21
- try {
22
- body = await res.json();
23
- } catch {
24
- body = null;
25
- }
26
- return { ok: res.ok, status: res.status, body };
27
- } catch {
28
- return { ok: false, status: 0, body: null };
29
- }
30
- }
31
-
32
- export function artifactUrl(artifactPath) {
33
- return `/api/artifacts?path=${encodeURIComponent(artifactPath)}&tail=200`;
34
- }
35
-
36
- export function parseArtifactPreviewResponse(text) {
37
- const parsed = JSON.parse(text);
38
- if (!parsed || typeof parsed.content !== "string") {
39
- throw new Error("Artifact preview response is invalid");
40
- }
41
- return {
42
- content: parsed.content,
43
- truncated: parsed.truncated === true,
44
- };
45
- }
46
-
1
+ /** Fetch and artifact helpers (Observe UI R5). */
2
+
3
+ export async function fetchJson(url) {
4
+ try {
5
+ const res = await fetch(url);
6
+ if (!res.ok) return null;
7
+ return await res.json();
8
+ } catch {
9
+ return null;
10
+ }
11
+ }
12
+
13
+ /**
14
+ * Read-only JSON fetch that preserves HTTP status so callers can distinguish
15
+ * 404 (missing) from 409 (ambiguous task identity). Body is parsed best-effort.
16
+ */
17
+ export async function fetchJsonResult(url) {
18
+ try {
19
+ const res = await fetch(url);
20
+ let body = null;
21
+ try {
22
+ body = await res.json();
23
+ } catch {
24
+ body = null;
25
+ }
26
+ return { ok: res.ok, status: res.status, body };
27
+ } catch {
28
+ return { ok: false, status: 0, body: null };
29
+ }
30
+ }
31
+
32
+ export function artifactUrl(artifactPath) {
33
+ return `/api/artifacts?path=${encodeURIComponent(artifactPath)}&tail=200`;
34
+ }
35
+
36
+ export function parseArtifactPreviewResponse(text) {
37
+ const parsed = JSON.parse(text);
38
+ if (!parsed || typeof parsed.content !== "string") {
39
+ throw new Error("Artifact preview response is invalid");
40
+ }
41
+ return {
42
+ content: parsed.content,
43
+ truncated: parsed.truncated === true,
44
+ };
45
+ }
46
+