@tea-agent/loop-agent 0.12.0 → 0.13.0-beta.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 (284) hide show
  1. package/AGENTS.md +155 -153
  2. package/CHANGELOG.md +338 -265
  3. package/README.md +345 -298
  4. package/bin/agent-worker.js +22 -22
  5. package/bin/loop-agent.js +21 -21
  6. package/dist/application/dag/generate-task-dag.js +28 -28
  7. package/dist/application/evaluation/candidate-hash.js +75 -0
  8. package/dist/application/evaluation/candidate.js +52 -0
  9. package/dist/application/evaluation/replay.js +289 -0
  10. package/dist/application/evaluation/types.js +130 -0
  11. package/dist/cli/command-definitions.js +27 -7
  12. package/dist/cli/program.js +8 -4
  13. package/dist/commands/cursor-prompt.js +6 -6
  14. package/dist/commands/eval.js +235 -0
  15. package/dist/commands/init.js +544 -506
  16. package/dist/commands/knowledge.js +129 -31
  17. package/dist/commands/loop-benchmark.js +11 -11
  18. package/dist/commands/pi-reuse-benchmark.js +16 -16
  19. package/dist/executors/pi-sdk-executor.js +38 -24
  20. package/dist/executors/shell-executor.js +34 -2
  21. package/dist/executors/shell-presets.js +20 -0
  22. package/dist/executors/shell-verification.js +7 -0
  23. package/dist/governance/manifest-types.js +4 -0
  24. package/dist/infrastructure/evaluation/candidate-store.js +435 -0
  25. package/dist/infrastructure/evaluation/store.js +40 -0
  26. package/dist/sidecars/cursor-prompt/executor.js +1 -1
  27. package/dist/task/config-types.js +28 -1
  28. package/dist/task/runtime.js +27 -27
  29. package/dist/worker/cli.js +96 -1
  30. package/dist/worker/delivery/package.js +3 -3
  31. package/dist/worker/feature/decision-loader.js +37 -6
  32. package/dist/worker/feature/next-action.js +10 -2
  33. package/dist/worker/feature/ready-plan-projection.js +81 -0
  34. package/dist/worker/feature/reducer.js +2 -1
  35. package/dist/worker/feature/review.js +19 -2
  36. package/dist/worker/feature/run.js +27 -2
  37. package/dist/worker/follow-up/approve.js +5 -2
  38. package/dist/worker/follow-up/factory.js +1 -1
  39. package/dist/worker/observability/read-model.js +246 -41
  40. package/dist/worker/observe/routes.js +173 -15
  41. package/dist/worker/observe/spec-evidence.js +281 -0
  42. package/dist/worker/observe/static/api.js +46 -27
  43. package/dist/worker/observe/static/app.js +150 -150
  44. package/dist/worker/observe/static/constants.js +148 -148
  45. package/dist/worker/observe/static/copy.js +67 -67
  46. package/dist/worker/observe/static/dag-helpers.js +172 -172
  47. package/dist/worker/observe/static/dag-layout.d.ts +31 -31
  48. package/dist/worker/observe/static/dag-layout.js +83 -83
  49. package/dist/worker/observe/static/dag-model.js +72 -72
  50. package/dist/worker/observe/static/dom.js +61 -61
  51. package/dist/worker/observe/static/format-pool.js +67 -67
  52. package/dist/worker/observe/static/format.js +292 -292
  53. package/dist/worker/observe/static/index.html +308 -308
  54. package/dist/worker/observe/static/kpi.js +94 -94
  55. package/dist/worker/observe/static/relations.js +133 -128
  56. package/dist/worker/observe/static/router.js +93 -85
  57. package/dist/worker/observe/static/run-processing.js +148 -148
  58. package/dist/worker/observe/static/shell-chrome.js +68 -68
  59. package/dist/worker/observe/static/state.js +253 -253
  60. package/dist/worker/observe/static/styles.css +1902 -1890
  61. package/dist/worker/observe/static/views/batch.js +227 -226
  62. package/dist/worker/observe/static/views/dag-graph.js +172 -172
  63. package/dist/worker/observe/static/views/dag-inspector.js +607 -477
  64. package/dist/worker/observe/static/views/dag.js +362 -362
  65. package/dist/worker/observe/static/views/dashboard.js +445 -442
  66. package/dist/worker/observe/static/views/failures.js +143 -143
  67. package/dist/worker/observe/static/views/feature.js +492 -453
  68. package/dist/worker/observe/static/views/pool.js +350 -347
  69. package/dist/worker/observe/static/views/run.js +453 -453
  70. package/dist/worker/observe/static/views/session-timeline.js +205 -205
  71. package/dist/worker/observe/static/views/shell.js +7 -7
  72. package/dist/worker/observe/static/views/task.js +314 -260
  73. package/dist/worker/observe/static/views/timeline.js +163 -163
  74. package/dist/worker/pool/doctor.js +165 -0
  75. package/dist/worker/pool/migrate-state.js +303 -0
  76. package/dist/worker/pool/run-store.js +205 -17
  77. package/dist/worker/pool/types.js +17 -1
  78. package/dist/worker/pool/validation.js +100 -15
  79. package/dist/worker/report/morning-report.js +12 -2
  80. package/dist/worker/runner/run-ready.js +41 -26
  81. package/dist/worker/task-graph/ready-planner.js +136 -0
  82. package/dist/workflows/dag/backend-test-analysis-contract.js +120 -0
  83. package/dist/workflows/dag/canvas-observer.js +275 -275
  84. package/dist/workflows/dag/convergence/controller.js +16 -8
  85. package/dist/workflows/dag/dynamic-runtime/map.js +90 -2
  86. package/dist/workflows/dag/failure-routing.js +12 -1
  87. package/dist/workflows/dag/init-hybrid.js +2404 -360
  88. package/dist/workflows/dag/node-execution.js +9 -0
  89. package/dist/workflows/dag/prompt.js +9 -0
  90. package/dist/workflows/dag/report.js +35 -1
  91. package/dist/workflows/dag/runner.js +28 -2
  92. package/dist/workflows/dag/task-demand-routing.js +383 -0
  93. package/dist/workflows/dag/types.js +51 -13
  94. package/dist/workflows/dag/upstream-artifacts.js +1 -0
  95. package/dist/workflows/dag/validate.js +59 -1
  96. package/docs/README.md +106 -104
  97. package/docs/agent-dag-recovery-playbook.md +195 -184
  98. package/docs/agent-dag-runner.md +67 -67
  99. package/docs/architecture/README.md +26 -26
  100. package/docs/architecture/dag-execution.md +140 -140
  101. package/docs/architecture/evolution.md +54 -53
  102. package/docs/architecture/facts-and-state.md +71 -58
  103. package/docs/architecture/runtime-boundaries.md +191 -191
  104. package/docs/architecture/system-overview.md +93 -93
  105. package/docs/architecture/worker-and-feature.md +85 -81
  106. package/docs/cursor-prompt-sidecar.md +36 -36
  107. package/docs/decisions/README.md +18 -15
  108. package/docs/design/README.md +167 -77
  109. package/docs/development-principles.md +73 -73
  110. package/docs/exec-plans/README.md +6 -6
  111. package/docs/exec-plans/active/README.md +15 -9
  112. package/docs/exec-plans/completed/README.md +85 -73
  113. package/docs/feature-workflow.md +389 -261
  114. package/docs/harness-methodology-debugging.md +153 -153
  115. package/docs/harness-methodology-tdd.md +130 -130
  116. package/docs/harness-methodology-verification.md +27 -27
  117. package/docs/init-surface.manifest.json +289 -280
  118. package/docs/loop-agent-harness.md +142 -130
  119. package/docs/production-readiness.md +96 -96
  120. package/docs/progress/README.md +64 -54
  121. package/docs/reports/README.md +117 -94
  122. package/docs/skills/README.md +7 -7
  123. package/docs/skills/vetted-skill-registry.md +29 -27
  124. package/docs/templates/adr.md +60 -60
  125. package/docs/templates/agent-dag-authority-surface-audit.prompt.md +94 -94
  126. package/docs/templates/agent-dag-decision-envelope.schema.json +213 -213
  127. package/docs/templates/agent-dag-decision-gate-dogfood-report.md +117 -117
  128. package/docs/templates/agent-dag-decision-gate.prompt.md +246 -246
  129. package/docs/templates/agent-dag-process-supervisor.prompt.md +98 -98
  130. package/docs/templates/agent-dag-report.schema.json +473 -473
  131. package/docs/templates/agent-dag-review-verdict.prompt.md +68 -68
  132. package/docs/templates/agent-dag.base.json +190 -190
  133. package/docs/templates/agent-dag.final-verification.json +185 -185
  134. package/docs/templates/agent-dag.schema.json +411 -383
  135. package/docs/templates/agent-dag.supervised-implementation.json +501 -501
  136. package/docs/templates/backend-test-analysis.schema.json +44 -0
  137. package/docs/templates/backend-test-dag.generate-pytest.prompt.md +202 -139
  138. package/docs/templates/backend-test-dag.json +311 -276
  139. package/docs/templates/backend-test-dag.retrospect.prompt.md +125 -125
  140. package/docs/templates/backend-test-dag.review-cases.prompt.md +81 -81
  141. package/docs/templates/exec-plan.md +64 -64
  142. package/docs/templates/feature-spec.md +53 -53
  143. package/docs/templates/frontend-design-contract.md +42 -33
  144. package/docs/templates/frontend-task-constraints.md +35 -25
  145. package/docs/templates/frontend-task-requirement.md +70 -61
  146. package/docs/templates/frontend-test-dag.generate-cases.prompt.md +5 -0
  147. package/docs/templates/frontend-test-dag.json +23 -0
  148. package/docs/templates/frontend-test-dag.retrieve-context.prompt.md +3 -0
  149. package/docs/templates/frontend-test-dag.retrospect.prompt.md +3 -0
  150. package/docs/templates/frontend-test-dag.review-cases.prompt.md +3 -0
  151. package/docs/templates/frontend-test-dag.review-execution.prompt.md +3 -0
  152. package/docs/templates/harness.schema.json +221 -221
  153. package/docs/templates/hybrid-dag.json +188 -188
  154. package/docs/templates/init-evolution-review.md +35 -35
  155. package/docs/templates/interactive-ui-round2-experiment.md +66 -66
  156. package/docs/templates/knowledge-graph-bootstrap-dag.json +118 -0
  157. package/docs/templates/knowledge-sync-dag.json +178 -0
  158. package/docs/templates/knowledge-sync-draft.schema.json +71 -0
  159. package/docs/templates/product-line/AGENTS.md +8 -8
  160. package/docs/templates/product-line/README.md +9 -9
  161. package/docs/templates/product-line/acceptance.yaml +14 -14
  162. package/docs/templates/product-line/closeout.yaml +9 -9
  163. package/docs/templates/product-line/design.md +13 -13
  164. package/docs/templates/product-line/links.md +10 -10
  165. package/docs/templates/product-line/requirement.md +17 -17
  166. package/docs/templates/product-line/task-graph.yaml +15 -15
  167. package/docs/templates/product-line/task.yaml +64 -64
  168. package/docs/templates/product-line/test-plan.md +7 -7
  169. package/docs/templates/production-readiness-checklist.md +57 -57
  170. package/docs/templates/progress-log.md +17 -17
  171. package/docs/templates/project-start-checklist.md +9 -9
  172. package/docs/templates/qa-report.md +48 -48
  173. package/docs/templates/sprint-contract.md +29 -29
  174. package/docs/templates/worker-dogfood-evidence.md +80 -80
  175. package/docs/templates/worker-dogfood-setup.md +68 -68
  176. package/docs/verification-matrix.md +70 -66
  177. package/examples/decision-gate-agent-dag.json +177 -177
  178. package/examples/example-dag.json +46 -46
  179. package/examples/hybrid-loop-agent-dag.json +189 -189
  180. package/harness.json +66 -66
  181. package/package.json +88 -46
  182. package/scripts/check-product-line-docs.sh +29 -29
  183. package/scripts/check-task-pool-root.sh +32 -32
  184. package/scripts/kb-bootstrap-init-skeleton.sh +240 -0
  185. package/scripts/kb-graph-incremental-prepare.mjs +386 -0
  186. package/scripts/kb-graph-incremental-prepare.sh +5 -0
  187. package/scripts/kb-graph-materialize.mjs +105 -0
  188. package/scripts/kb-graph-materialize.sh +4 -0
  189. package/scripts/kb-graph-promote.mjs +164 -0
  190. package/scripts/kb-graph-promote.sh +4 -0
  191. package/scripts/kb-query.mjs +554 -0
  192. package/scripts/kb-query.sh +5 -0
  193. package/skills/agent-worker/SKILL.md +39 -37
  194. package/skills/agent-worker/references/agent-worker-operator.md +60 -43
  195. package/skills/ai-engineering-context/SKILL.md +48 -48
  196. package/skills/analyze-product-dependencies/SKILL.md +67 -0
  197. package/skills/analyze-product-dependencies/agents/openai.yaml +4 -0
  198. package/skills/analyze-product-dependencies/references/api-documentation-schema.md +30 -0
  199. package/skills/analyze-product-dependencies/references/dependency-analysis-schema.md +28 -0
  200. package/skills/analyze-product-dependencies/references/example.md +76 -0
  201. package/skills/analyze-product-dependencies/references/forward-test-cases.md +35 -0
  202. package/skills/analyze-product-dependencies/references/input-contract.md +11 -0
  203. package/skills/analyze-product-dependencies/references/scouting-rules.md +61 -0
  204. package/skills/analyze-product-dependencies/scripts/test-validators.mjs +267 -0
  205. package/skills/analyze-product-dependencies/scripts/validate-api-documentation.mjs +101 -0
  206. package/skills/analyze-product-dependencies/scripts/validate-dependency-analysis.mjs +142 -0
  207. package/skills/analyze-product-dependencies/scripts/validate-product-requirement-input.mjs +76 -0
  208. package/skills/analyze-product-dependencies/scripts/validation-helpers.mjs +146 -0
  209. package/skills/analyze-product-requirements/SKILL.md +90 -0
  210. package/skills/analyze-product-requirements/agents/openai.yaml +4 -0
  211. package/skills/analyze-product-requirements/references/acceptance-criteria.md +91 -0
  212. package/skills/analyze-product-requirements/references/clarification-and-knowledge.md +56 -0
  213. package/skills/analyze-product-requirements/references/example.md +86 -0
  214. package/skills/analyze-product-requirements/references/forward-test-cases.md +66 -0
  215. package/skills/analyze-product-requirements/references/product-analysis-schema.md +32 -0
  216. package/skills/analyze-product-requirements/references/product-requirement-schema.md +33 -0
  217. package/skills/analyze-product-requirements/references/requirement-clarification-schema.md +35 -0
  218. package/skills/analyze-product-requirements/scripts/test-validators.mjs +193 -0
  219. package/skills/analyze-product-requirements/scripts/validate-product-analysis.mjs +69 -0
  220. package/skills/analyze-product-requirements/scripts/validate-product-requirement.mjs +97 -0
  221. package/skills/analyze-product-requirements/scripts/validate-requirement-clarification.mjs +98 -0
  222. package/skills/analyze-product-requirements/scripts/validation-helpers.mjs +156 -0
  223. package/skills/code-review-core/SKILL.md +20 -20
  224. package/skills/codebase-scout/SKILL.md +19 -19
  225. package/skills/frontend-design-review/SKILL.md +66 -59
  226. package/skills/frontend-design-review/references/review-checklist.md +58 -37
  227. package/skills/frontend-implementation/SKILL.md +47 -51
  228. package/skills/frontend-implementation/references/code-standards.md +32 -34
  229. package/skills/frontend-implementation/references/design-spec.md +46 -46
  230. package/skills/frontend-implementation/references/node-contracts.md +76 -32
  231. package/skills/frontend-review/SKILL.md +59 -53
  232. package/skills/frontend-review/references/review-findings.md +47 -42
  233. package/skills/frontend-verification/SKILL.md +53 -40
  234. package/skills/frontend-verification/references/verification-checklist.md +68 -56
  235. package/skills/grill-me/SKILL.md +10 -10
  236. package/skills/grill-with-docs/SKILL.md +88 -88
  237. package/skills/grill-with-docs/adr-format.md +47 -47
  238. package/skills/grill-with-docs/context-format.md +60 -60
  239. package/skills/init-capability-evolution/SKILL.md +70 -70
  240. package/skills/loop-agent/SKILL.md +151 -151
  241. package/skills/loop-agent/references/README.md +67 -67
  242. package/skills/loop-agent/references/command-reference.md +505 -452
  243. package/skills/loop-agent/references/docs-converge.md +126 -126
  244. package/skills/loop-agent/references/harness-policy.md +263 -263
  245. package/skills/loop-agent/references/hybrid-dag.md +238 -233
  246. package/skills/loop-agent/references/learned/README.md +21 -21
  247. package/skills/loop-agent/references/long-running-loop.md +57 -57
  248. package/skills/loop-agent/references/model-routing.md +36 -36
  249. package/skills/loop-agent/references/multi-worktree.md +54 -54
  250. package/skills/loop-agent/references/one-shot-runs.md +85 -85
  251. package/skills/loop-agent/references/orchestrator-and-interventions.md +169 -169
  252. package/skills/loop-agent/references/pi-prompt.md +23 -23
  253. package/skills/loop-agent/references/pi-subagent-assisted-mode.md +84 -84
  254. package/skills/loop-agent/references/post-implementation-and-patterns.md +44 -44
  255. package/skills/loop-agent/references/task-workflow.md +89 -89
  256. package/skills/loop-agent/references/verification-and-failure-handling.md +139 -139
  257. package/skills/playwright-cli/SKILL.md +420 -0
  258. package/skills/playwright-cli/references/element-attributes.md +23 -0
  259. package/skills/playwright-cli/references/playwright-tests.md +39 -0
  260. package/skills/playwright-cli/references/request-mocking.md +87 -0
  261. package/skills/playwright-cli/references/running-code.md +241 -0
  262. package/skills/playwright-cli/references/session-management.md +225 -0
  263. package/skills/playwright-cli/references/storage-state.md +275 -0
  264. package/skills/playwright-cli/references/test-generation.md +433 -0
  265. package/skills/playwright-cli/references/tracing.md +139 -0
  266. package/skills/playwright-cli/references/video-recording.md +143 -0
  267. package/skills/playwright-cli-case-generator/SKILL.md +74 -0
  268. package/skills/requesting-code-review/SKILL.md +101 -101
  269. package/skills/requesting-code-review/code-reviewer.md +168 -168
  270. package/skills/systematic-debugging/CREATION-LOG.md +119 -119
  271. package/skills/systematic-debugging/SKILL.md +296 -296
  272. package/skills/systematic-debugging/condition-based-waiting-example.ts +158 -158
  273. package/skills/systematic-debugging/condition-based-waiting.md +115 -115
  274. package/skills/systematic-debugging/defense-in-depth.md +122 -122
  275. package/skills/systematic-debugging/find-polluter.sh +63 -63
  276. package/skills/systematic-debugging/root-cause-tracing.md +169 -169
  277. package/skills/systematic-debugging/test-academic.md +14 -14
  278. package/skills/systematic-debugging/test-pressure-1.md +58 -58
  279. package/skills/systematic-debugging/test-pressure-2.md +68 -68
  280. package/skills/systematic-debugging/test-pressure-3.md +69 -69
  281. package/skills/test-driven-development/SKILL.md +20 -20
  282. package/skills/using-git-worktrees/SKILL.md +215 -215
  283. package/skills/verification-before-completion/SKILL.md +154 -154
  284. package/skills/webapp-testing/SKILL.md +19 -19
@@ -94,523 +94,523 @@ const COMPAT_PROMPTS = {
94
94
  ].join("\n"),
95
95
  };
96
96
  const GOVERNANCE_ROOT_TOKEN = "__LOOP_AGENT_GOVERNANCE_ROOT__";
97
- const INIT_CHECK_ENGINEERING_STRUCTURE_SH = `#!/usr/bin/env bash
98
- set -euo pipefail
99
-
100
- ROOT_DIR="$(cd "$(dirname "\${BASH_SOURCE[0]}")/.." && pwd)"
101
- cd "\${ROOT_DIR}"
102
-
103
- required_paths=(
104
- "README.md"
105
- "harness.json"
106
- "AGENTS.md"
107
- "${GOVERNANCE_ROOT_TOKEN}/README.md"
108
- "${GOVERNANCE_ROOT_TOKEN}/development-principles.md"
109
- "${GOVERNANCE_ROOT_TOKEN}/feature-workflow.md"
110
- "${GOVERNANCE_ROOT_TOKEN}/verification-matrix.md"
111
- "${GOVERNANCE_ROOT_TOKEN}/architecture/runtime-boundaries.md"
112
- "${GOVERNANCE_ROOT_TOKEN}/templates"
113
- ".agents/skills/loop-agent/SKILL.md"
114
- ".harness/prompts/analyze.md"
115
- ".harness/prompts/plan.md"
116
- ".harness/tasks"
117
- ".harness/dag-runs/active"
118
- ".harness/dag-runs/completed"
119
- ".harness/dag-runs/paused"
120
- ".harness/runs/active"
121
- ".harness/runs/completed"
122
- ".harness/runs/failed"
123
- "scripts/check-engineering-structure.sh"
124
- "scripts/check-doc-index.sh"
125
- "scripts/check-doc-links.sh"
126
- "scripts/check-active-plan-status.sh"
127
- "scripts/check-exec-plan-index-sync.sh"
128
- "scripts/check-harness-runtime-clean.sh"
129
- "scripts/check-architecture-boundaries.sh"
130
- "scripts/check-skill-entry.sh"
131
- "scripts/check-repo.sh"
132
- "scripts/ci-governance.sh"
133
- "scripts/ci-tests.sh"
134
- "scripts/ci.sh"
135
- )
136
-
137
- missing=()
138
- for item in "\${required_paths[@]}"; do
139
- if [[ ! -e "\${item}" ]]; then
140
- missing+=("\${item}")
141
- fi
142
- done
143
-
144
- if (( \${#missing[@]} > 0 )); then
145
- echo "loop-agent 初始化检查失败,缺少必要路径:"
146
- for item in "\${missing[@]}"; do
147
- echo " - \${item}"
148
- done
149
- exit 1
150
- fi
151
-
152
- echo "loop-agent 工程结构检查通过"
97
+ const INIT_CHECK_ENGINEERING_STRUCTURE_SH = `#!/usr/bin/env bash
98
+ set -euo pipefail
99
+
100
+ ROOT_DIR="$(cd "$(dirname "\${BASH_SOURCE[0]}")/.." && pwd)"
101
+ cd "\${ROOT_DIR}"
102
+
103
+ required_paths=(
104
+ "README.md"
105
+ "harness.json"
106
+ "AGENTS.md"
107
+ "${GOVERNANCE_ROOT_TOKEN}/README.md"
108
+ "${GOVERNANCE_ROOT_TOKEN}/development-principles.md"
109
+ "${GOVERNANCE_ROOT_TOKEN}/feature-workflow.md"
110
+ "${GOVERNANCE_ROOT_TOKEN}/verification-matrix.md"
111
+ "${GOVERNANCE_ROOT_TOKEN}/architecture/runtime-boundaries.md"
112
+ "${GOVERNANCE_ROOT_TOKEN}/templates"
113
+ ".agents/skills/loop-agent/SKILL.md"
114
+ ".harness/prompts/analyze.md"
115
+ ".harness/prompts/plan.md"
116
+ ".harness/tasks"
117
+ ".harness/dag-runs/active"
118
+ ".harness/dag-runs/completed"
119
+ ".harness/dag-runs/paused"
120
+ ".harness/runs/active"
121
+ ".harness/runs/completed"
122
+ ".harness/runs/failed"
123
+ "scripts/check-engineering-structure.sh"
124
+ "scripts/check-doc-index.sh"
125
+ "scripts/check-doc-links.sh"
126
+ "scripts/check-active-plan-status.sh"
127
+ "scripts/check-exec-plan-index-sync.sh"
128
+ "scripts/check-harness-runtime-clean.sh"
129
+ "scripts/check-architecture-boundaries.sh"
130
+ "scripts/check-skill-entry.sh"
131
+ "scripts/check-repo.sh"
132
+ "scripts/ci-governance.sh"
133
+ "scripts/ci-tests.sh"
134
+ "scripts/ci.sh"
135
+ )
136
+
137
+ missing=()
138
+ for item in "\${required_paths[@]}"; do
139
+ if [[ ! -e "\${item}" ]]; then
140
+ missing+=("\${item}")
141
+ fi
142
+ done
143
+
144
+ if (( \${#missing[@]} > 0 )); then
145
+ echo "loop-agent 初始化检查失败,缺少必要路径:"
146
+ for item in "\${missing[@]}"; do
147
+ echo " - \${item}"
148
+ done
149
+ exit 1
150
+ fi
151
+
152
+ echo "loop-agent 工程结构检查通过"
153
153
  `;
154
- const INIT_CHECK_DOC_INDEX_SH = `#!/usr/bin/env bash
155
- set -euo pipefail
156
-
157
- ROOT_DIR="$(cd "$(dirname "\${BASH_SOURCE[0]}")/.." && pwd)"
158
- cd "\${ROOT_DIR}"
159
-
160
- required_docs=(
161
- "${GOVERNANCE_ROOT_TOKEN}/README.md"
162
- "${GOVERNANCE_ROOT_TOKEN}/development-principles.md"
163
- "${GOVERNANCE_ROOT_TOKEN}/feature-workflow.md"
164
- "${GOVERNANCE_ROOT_TOKEN}/verification-matrix.md"
165
- "${GOVERNANCE_ROOT_TOKEN}/architecture/runtime-boundaries.md"
166
- "${GOVERNANCE_ROOT_TOKEN}/loop-agent-harness.md"
167
- "${GOVERNANCE_ROOT_TOKEN}/harness-methodology-tdd.md"
168
- "${GOVERNANCE_ROOT_TOKEN}/harness-methodology-verification.md"
169
- "${GOVERNANCE_ROOT_TOKEN}/harness-methodology-debugging.md"
170
- "${GOVERNANCE_ROOT_TOKEN}/templates"
171
- "${GOVERNANCE_ROOT_TOKEN}/exec-plans/active/README.md"
172
- "${GOVERNANCE_ROOT_TOKEN}/exec-plans/completed/README.md"
173
- "${GOVERNANCE_ROOT_TOKEN}/progress/README.md"
174
- "${GOVERNANCE_ROOT_TOKEN}/reports/README.md"
175
- "${GOVERNANCE_ROOT_TOKEN}/decisions/README.md"
176
- )
177
-
178
- missing=()
179
- for item in "\${required_docs[@]}"; do
180
- if [[ ! -e "\${item}" ]]; then
181
- missing+=("\${item}")
182
- fi
183
- done
184
-
185
- if (( \${#missing[@]} > 0 )); then
186
- echo "docs 索引检查失败,缺少必要文档或目录:" >&2
187
- for item in "\${missing[@]}"; do
188
- echo " - \${item}" >&2
189
- done
190
- exit 1
191
- fi
192
-
193
- echo "docs 索引检查通过"
154
+ const INIT_CHECK_DOC_INDEX_SH = `#!/usr/bin/env bash
155
+ set -euo pipefail
156
+
157
+ ROOT_DIR="$(cd "$(dirname "\${BASH_SOURCE[0]}")/.." && pwd)"
158
+ cd "\${ROOT_DIR}"
159
+
160
+ required_docs=(
161
+ "${GOVERNANCE_ROOT_TOKEN}/README.md"
162
+ "${GOVERNANCE_ROOT_TOKEN}/development-principles.md"
163
+ "${GOVERNANCE_ROOT_TOKEN}/feature-workflow.md"
164
+ "${GOVERNANCE_ROOT_TOKEN}/verification-matrix.md"
165
+ "${GOVERNANCE_ROOT_TOKEN}/architecture/runtime-boundaries.md"
166
+ "${GOVERNANCE_ROOT_TOKEN}/loop-agent-harness.md"
167
+ "${GOVERNANCE_ROOT_TOKEN}/harness-methodology-tdd.md"
168
+ "${GOVERNANCE_ROOT_TOKEN}/harness-methodology-verification.md"
169
+ "${GOVERNANCE_ROOT_TOKEN}/harness-methodology-debugging.md"
170
+ "${GOVERNANCE_ROOT_TOKEN}/templates"
171
+ "${GOVERNANCE_ROOT_TOKEN}/exec-plans/active/README.md"
172
+ "${GOVERNANCE_ROOT_TOKEN}/exec-plans/completed/README.md"
173
+ "${GOVERNANCE_ROOT_TOKEN}/progress/README.md"
174
+ "${GOVERNANCE_ROOT_TOKEN}/reports/README.md"
175
+ "${GOVERNANCE_ROOT_TOKEN}/decisions/README.md"
176
+ )
177
+
178
+ missing=()
179
+ for item in "\${required_docs[@]}"; do
180
+ if [[ ! -e "\${item}" ]]; then
181
+ missing+=("\${item}")
182
+ fi
183
+ done
184
+
185
+ if (( \${#missing[@]} > 0 )); then
186
+ echo "docs 索引检查失败,缺少必要文档或目录:" >&2
187
+ for item in "\${missing[@]}"; do
188
+ echo " - \${item}" >&2
189
+ done
190
+ exit 1
191
+ fi
192
+
193
+ echo "docs 索引检查通过"
194
194
  `;
195
- const INIT_CHECK_DOC_LINKS_SH = `#!/usr/bin/env bash
196
- set -euo pipefail
197
-
198
- ROOT_DIR="$(cd "$(dirname "\${BASH_SOURCE[0]}")/.." && pwd)"
199
- cd "\${ROOT_DIR}"
200
-
201
- if [[ ! -d "${GOVERNANCE_ROOT_TOKEN}" ]]; then
202
- echo "docs 链接检查失败:缺少 ${GOVERNANCE_ROOT_TOKEN}/" >&2
203
- exit 1
204
- fi
205
-
206
- missing=()
207
- while IFS= read -r -d '' file; do
208
- while IFS= read -r link; do
209
- [[ -z "\${link}" ]] && continue
210
- [[ "\${link}" == http://* || "\${link}" == https://* || "\${link}" == mailto:* || "\${link}" == "#"* ]] && continue
211
- [[ "\${link}" == *"://"* ]] && continue
212
- target="\${link%%#*}"
213
- [[ -z "\${target}" ]] && continue
214
- [[ "\${target}" == /* ]] && continue
215
- base="$(dirname "\${file}")"
216
- if [[ ! -e "\${base}/\${target}" ]]; then
217
- missing+=("\${file}: \${link}")
218
- fi
219
- done < <(grep -Eo '\\[[^]]+\\]\\([^)]+\\)' "\${file}" | sed -E 's/^.*\\(([^)]+)\\)$/\\1/' || true)
220
- done < <(find "${GOVERNANCE_ROOT_TOKEN}" -type f -name '*.md' -print0)
221
-
222
- if (( \${#missing[@]} > 0 )); then
223
- echo "docs 链接检查失败:" >&2
224
- for item in "\${missing[@]}"; do
225
- echo " - \${item}" >&2
226
- done
227
- exit 1
228
- fi
229
-
230
- echo "docs 链接检查通过"
195
+ const INIT_CHECK_DOC_LINKS_SH = `#!/usr/bin/env bash
196
+ set -euo pipefail
197
+
198
+ ROOT_DIR="$(cd "$(dirname "\${BASH_SOURCE[0]}")/.." && pwd)"
199
+ cd "\${ROOT_DIR}"
200
+
201
+ if [[ ! -d "${GOVERNANCE_ROOT_TOKEN}" ]]; then
202
+ echo "docs 链接检查失败:缺少 ${GOVERNANCE_ROOT_TOKEN}/" >&2
203
+ exit 1
204
+ fi
205
+
206
+ missing=()
207
+ while IFS= read -r -d '' file; do
208
+ while IFS= read -r link; do
209
+ [[ -z "\${link}" ]] && continue
210
+ [[ "\${link}" == http://* || "\${link}" == https://* || "\${link}" == mailto:* || "\${link}" == "#"* ]] && continue
211
+ [[ "\${link}" == *"://"* ]] && continue
212
+ target="\${link%%#*}"
213
+ [[ -z "\${target}" ]] && continue
214
+ [[ "\${target}" == /* ]] && continue
215
+ base="$(dirname "\${file}")"
216
+ if [[ ! -e "\${base}/\${target}" ]]; then
217
+ missing+=("\${file}: \${link}")
218
+ fi
219
+ done < <(grep -Eo '\\[[^]]+\\]\\([^)]+\\)' "\${file}" | sed -E 's/^.*\\(([^)]+)\\)$/\\1/' || true)
220
+ done < <(find "${GOVERNANCE_ROOT_TOKEN}" -type f -name '*.md' -print0)
221
+
222
+ if (( \${#missing[@]} > 0 )); then
223
+ echo "docs 链接检查失败:" >&2
224
+ for item in "\${missing[@]}"; do
225
+ echo " - \${item}" >&2
226
+ done
227
+ exit 1
228
+ fi
229
+
230
+ echo "docs 链接检查通过"
231
231
  `;
232
- const INIT_CHECK_ACTIVE_PLAN_STATUS_SH = `#!/usr/bin/env bash
233
- set -euo pipefail
234
-
235
- ROOT_DIR="$(cd "$(dirname "\${BASH_SOURCE[0]}")/.." && pwd)"
236
- cd "\${ROOT_DIR}"
237
-
238
- active_dir="${GOVERNANCE_ROOT_TOKEN}/exec-plans/active"
239
- [[ -d "\${active_dir}" ]] || { echo "active plan 检查失败:缺少 \${active_dir}" >&2; exit 1; }
240
-
241
- bad=()
242
- while IFS= read -r -d '' file; do
243
- name="$(basename "\${file}")"
244
- [[ "\${name}" == "README.md" ]] && continue
245
- if grep -Eiq 'status:[[:space:]]*(completed|done|closed)|状态[::][[:space:]]*(已完成|完成|关闭)' "\${file}"; then
246
- bad+=("\${file}")
247
- fi
248
- done < <(find "\${active_dir}" -maxdepth 1 -type f -name '*.md' -print0)
249
-
250
- if (( \${#bad[@]} > 0 )); then
251
- echo "active plan 状态检查失败:已完成计划不应留在 active 目录:" >&2
252
- for item in "\${bad[@]}"; do
253
- echo " - \${item}" >&2
254
- done
255
- exit 1
256
- fi
257
-
258
- echo "active plan 状态检查通过"
232
+ const INIT_CHECK_ACTIVE_PLAN_STATUS_SH = `#!/usr/bin/env bash
233
+ set -euo pipefail
234
+
235
+ ROOT_DIR="$(cd "$(dirname "\${BASH_SOURCE[0]}")/.." && pwd)"
236
+ cd "\${ROOT_DIR}"
237
+
238
+ active_dir="${GOVERNANCE_ROOT_TOKEN}/exec-plans/active"
239
+ [[ -d "\${active_dir}" ]] || { echo "active plan 检查失败:缺少 \${active_dir}" >&2; exit 1; }
240
+
241
+ bad=()
242
+ while IFS= read -r -d '' file; do
243
+ name="$(basename "\${file}")"
244
+ [[ "\${name}" == "README.md" ]] && continue
245
+ if grep -Eiq 'status:[[:space:]]*(completed|done|closed)|状态[::][[:space:]]*(已完成|完成|关闭)' "\${file}"; then
246
+ bad+=("\${file}")
247
+ fi
248
+ done < <(find "\${active_dir}" -maxdepth 1 -type f -name '*.md' -print0)
249
+
250
+ if (( \${#bad[@]} > 0 )); then
251
+ echo "active plan 状态检查失败:已完成计划不应留在 active 目录:" >&2
252
+ for item in "\${bad[@]}"; do
253
+ echo " - \${item}" >&2
254
+ done
255
+ exit 1
256
+ fi
257
+
258
+ echo "active plan 状态检查通过"
259
259
  `;
260
- const INIT_CHECK_EXEC_PLAN_INDEX_SYNC_SH = `#!/usr/bin/env bash
261
- set -euo pipefail
262
-
263
- ROOT_DIR="$(cd "$(dirname "\${BASH_SOURCE[0]}")/.." && pwd)"
264
- cd "\${ROOT_DIR}"
265
-
266
- required=(
267
- "${GOVERNANCE_ROOT_TOKEN}/exec-plans/README.md"
268
- "${GOVERNANCE_ROOT_TOKEN}/exec-plans/active/README.md"
269
- "${GOVERNANCE_ROOT_TOKEN}/exec-plans/completed/README.md"
270
- )
271
-
272
- for item in "\${required[@]}"; do
273
- if [[ ! -f "\${item}" ]]; then
274
- echo "exec-plan 索引同步检查失败:缺少 \${item}" >&2
275
- exit 1
276
- fi
277
- done
278
-
279
- echo "exec-plan 索引同步检查通过"
260
+ const INIT_CHECK_EXEC_PLAN_INDEX_SYNC_SH = `#!/usr/bin/env bash
261
+ set -euo pipefail
262
+
263
+ ROOT_DIR="$(cd "$(dirname "\${BASH_SOURCE[0]}")/.." && pwd)"
264
+ cd "\${ROOT_DIR}"
265
+
266
+ required=(
267
+ "${GOVERNANCE_ROOT_TOKEN}/exec-plans/README.md"
268
+ "${GOVERNANCE_ROOT_TOKEN}/exec-plans/active/README.md"
269
+ "${GOVERNANCE_ROOT_TOKEN}/exec-plans/completed/README.md"
270
+ )
271
+
272
+ for item in "\${required[@]}"; do
273
+ if [[ ! -f "\${item}" ]]; then
274
+ echo "exec-plan 索引同步检查失败:缺少 \${item}" >&2
275
+ exit 1
276
+ fi
277
+ done
278
+
279
+ echo "exec-plan 索引同步检查通过"
280
280
  `;
281
- const INIT_CHECK_HARNESS_RUNTIME_CLEAN_SH = `#!/usr/bin/env bash
282
- set -euo pipefail
283
-
284
- ROOT_DIR="$(cd "$(dirname "\${BASH_SOURCE[0]}")/.." && pwd)"
285
- cd "\${ROOT_DIR}"
286
-
287
- failures=()
288
-
289
- count_entries() {
290
- local dir="$1"
291
- if [[ ! -d "\${dir}" ]]; then
292
- echo 0
293
- return
294
- fi
295
- find "\${dir}" -mindepth 1 -maxdepth 1 ! -name .gitkeep | wc -l | tr -d ' '
296
- }
297
-
298
- if [[ "\${HARNESS_ALLOW_ACTIVE_DAG_RUNS:-}" != "1" ]]; then
299
- active_dag_count="$(count_entries ".harness/dag-runs/active")"
300
- [[ "\${active_dag_count}" == "0" ]] || failures+=(".harness/dag-runs/active contains \${active_dag_count} entries")
301
- fi
302
-
303
- if [[ "\${HARNESS_ALLOW_ACTIVE_TOOL_RUNS:-\${HARNESS_ALLOW_ACTIVE_ONE_SHOT_RUNS:-}}" != "1" ]]; then
304
- active_run_count="$(count_entries ".harness/runs/active")"
305
- [[ "\${active_run_count}" == "0" ]] || failures+=(".harness/runs/active contains \${active_run_count} entries")
306
- fi
307
-
308
- if [[ -d artifacts ]]; then
309
- artifact_count="$(find artifacts -mindepth 1 -maxdepth 1 ! -name .gitkeep | wc -l | tr -d ' ')"
310
- [[ "\${artifact_count}" == "0" ]] || failures+=("root artifacts/ contains \${artifact_count} entries; use ${GOVERNANCE_ROOT_TOKEN}/reports or .harness run artifacts")
311
- fi
312
-
313
- if (( \${#failures[@]} > 0 )); then
314
- echo "[HARNESS RUNTIME DIRTY]" >&2
315
- for item in "\${failures[@]}"; do
316
- echo " - \${item}" >&2
317
- done
318
- exit 1
319
- fi
320
-
321
- echo "harness runtime clean check passed"
281
+ const INIT_CHECK_HARNESS_RUNTIME_CLEAN_SH = `#!/usr/bin/env bash
282
+ set -euo pipefail
283
+
284
+ ROOT_DIR="$(cd "$(dirname "\${BASH_SOURCE[0]}")/.." && pwd)"
285
+ cd "\${ROOT_DIR}"
286
+
287
+ failures=()
288
+
289
+ count_entries() {
290
+ local dir="$1"
291
+ if [[ ! -d "\${dir}" ]]; then
292
+ echo 0
293
+ return
294
+ fi
295
+ find "\${dir}" -mindepth 1 -maxdepth 1 ! -name .gitkeep | wc -l | tr -d ' '
296
+ }
297
+
298
+ if [[ "\${HARNESS_ALLOW_ACTIVE_DAG_RUNS:-}" != "1" ]]; then
299
+ active_dag_count="$(count_entries ".harness/dag-runs/active")"
300
+ [[ "\${active_dag_count}" == "0" ]] || failures+=(".harness/dag-runs/active contains \${active_dag_count} entries")
301
+ fi
302
+
303
+ if [[ "\${HARNESS_ALLOW_ACTIVE_TOOL_RUNS:-\${HARNESS_ALLOW_ACTIVE_ONE_SHOT_RUNS:-}}" != "1" ]]; then
304
+ active_run_count="$(count_entries ".harness/runs/active")"
305
+ [[ "\${active_run_count}" == "0" ]] || failures+=(".harness/runs/active contains \${active_run_count} entries")
306
+ fi
307
+
308
+ if [[ -d artifacts ]]; then
309
+ artifact_count="$(find artifacts -mindepth 1 -maxdepth 1 ! -name .gitkeep | wc -l | tr -d ' ')"
310
+ [[ "\${artifact_count}" == "0" ]] || failures+=("root artifacts/ contains \${artifact_count} entries; use ${GOVERNANCE_ROOT_TOKEN}/reports or .harness run artifacts")
311
+ fi
312
+
313
+ if (( \${#failures[@]} > 0 )); then
314
+ echo "[HARNESS RUNTIME DIRTY]" >&2
315
+ for item in "\${failures[@]}"; do
316
+ echo " - \${item}" >&2
317
+ done
318
+ exit 1
319
+ fi
320
+
321
+ echo "harness runtime clean check passed"
322
322
  `;
323
- const INIT_CHECK_ARCHITECTURE_BOUNDARIES_SH = `#!/usr/bin/env bash
324
- set -euo pipefail
325
-
326
- ROOT_DIR="$(cd "$(dirname "\${BASH_SOURCE[0]}")/.." && pwd)"
327
- cd "\${ROOT_DIR}"
328
-
329
- boundary_doc="${GOVERNANCE_ROOT_TOKEN}/architecture/runtime-boundaries.md"
330
- if [[ ! -f "\${boundary_doc}" ]]; then
331
- echo "architecture boundary 检查失败:缺少 \${boundary_doc}" >&2
332
- exit 1
333
- fi
334
-
335
- violations=()
336
-
337
- check_ts_import_boundary() {
338
- local from_dir="$1"
339
- local forbidden_dir="$2"
340
- local label="$3"
341
- [[ -d "\${from_dir}" && -d "\${forbidden_dir}" ]] || return 0
342
- while IFS= read -r -d '' file; do
343
- if grep -Eq "from ['\\\"][^'\\\"]*\${forbidden_dir}/|import\\(['\\\"][^'\\\"]*\${forbidden_dir}/|require\\(['\\\"][^'\\\"]*\${forbidden_dir}/" "\${file}"; then
344
- violations+=("\${label}: \${file} imports \${forbidden_dir}")
345
- fi
346
- done < <(find "\${from_dir}" -type f \\( -name '*.ts' -o -name '*.tsx' -o -name '*.js' -o -name '*.jsx' -o -name '*.mjs' -o -name '*.cjs' \\) -print0)
347
- }
348
-
349
- # These checks are intentionally optional and stack-agnostic. They activate only
350
- # when a target repository has recognizable source directories.
351
- check_ts_import_boundary "src/workflows" "src/commands" "workflow-runtime"
352
- check_ts_import_boundary "src/executors" "src/commands" "executors"
353
- check_ts_import_boundary "src/domain" "src/infrastructure" "domain"
354
-
355
- if (( \${#violations[@]} > 0 )); then
356
- echo "architecture boundary 检查失败:" >&2
357
- for item in "\${violations[@]}"; do
358
- echo " - \${item}" >&2
359
- done
360
- echo "请更新 \${boundary_doc} 中的层边界,或修正反向依赖。" >&2
361
- exit 1
362
- fi
363
-
364
- echo "architecture boundary 检查通过"
323
+ const INIT_CHECK_ARCHITECTURE_BOUNDARIES_SH = `#!/usr/bin/env bash
324
+ set -euo pipefail
325
+
326
+ ROOT_DIR="$(cd "$(dirname "\${BASH_SOURCE[0]}")/.." && pwd)"
327
+ cd "\${ROOT_DIR}"
328
+
329
+ boundary_doc="${GOVERNANCE_ROOT_TOKEN}/architecture/runtime-boundaries.md"
330
+ if [[ ! -f "\${boundary_doc}" ]]; then
331
+ echo "architecture boundary 检查失败:缺少 \${boundary_doc}" >&2
332
+ exit 1
333
+ fi
334
+
335
+ violations=()
336
+
337
+ check_ts_import_boundary() {
338
+ local from_dir="$1"
339
+ local forbidden_dir="$2"
340
+ local label="$3"
341
+ [[ -d "\${from_dir}" && -d "\${forbidden_dir}" ]] || return 0
342
+ while IFS= read -r -d '' file; do
343
+ if grep -Eq "from ['\\\"][^'\\\"]*\${forbidden_dir}/|import\\(['\\\"][^'\\\"]*\${forbidden_dir}/|require\\(['\\\"][^'\\\"]*\${forbidden_dir}/" "\${file}"; then
344
+ violations+=("\${label}: \${file} imports \${forbidden_dir}")
345
+ fi
346
+ done < <(find "\${from_dir}" -type f \\( -name '*.ts' -o -name '*.tsx' -o -name '*.js' -o -name '*.jsx' -o -name '*.mjs' -o -name '*.cjs' \\) -print0)
347
+ }
348
+
349
+ # These checks are intentionally optional and stack-agnostic. They activate only
350
+ # when a target repository has recognizable source directories.
351
+ check_ts_import_boundary "src/workflows" "src/commands" "workflow-runtime"
352
+ check_ts_import_boundary "src/executors" "src/commands" "executors"
353
+ check_ts_import_boundary "src/domain" "src/infrastructure" "domain"
354
+
355
+ if (( \${#violations[@]} > 0 )); then
356
+ echo "architecture boundary 检查失败:" >&2
357
+ for item in "\${violations[@]}"; do
358
+ echo " - \${item}" >&2
359
+ done
360
+ echo "请更新 \${boundary_doc} 中的层边界,或修正反向依赖。" >&2
361
+ exit 1
362
+ fi
363
+
364
+ echo "architecture boundary 检查通过"
365
365
  `;
366
- const INIT_CHECK_SKILL_ENTRY_SH = `#!/usr/bin/env bash
367
- set -euo pipefail
368
-
369
- ROOT_DIR="$(cd "$(dirname "\${BASH_SOURCE[0]}")/.." && pwd)"
370
- cd "\${ROOT_DIR}"
371
-
372
- check_skill() {
373
- local skill_name="$1"
374
- shift
375
- local skill_dir=".agents/skills/\${skill_name}"
376
- local skill_md="\${skill_dir}/SKILL.md"
377
- local missing=()
378
-
379
- if [[ ! -f "\${skill_md}" ]]; then
380
- echo "skill entry 检查失败:缺少 \${skill_md}" >&2
381
- exit 1
382
- fi
383
- grep -Eq "^name:[[:space:]]*\${skill_name}[[:space:]]*$" "\${skill_md}" || missing+=("frontmatter name")
384
- grep -Eq '^description:[[:space:]]*[^[:space:]]' "\${skill_md}" || missing+=("frontmatter description")
385
-
386
- local ref
387
- for ref in "$@"; do
388
- [[ -f "\${skill_dir}/\${ref}" ]] || missing+=("\${ref}")
389
- grep -Fq "\${ref}" "\${skill_md}" || missing+=("SKILL.md -> \${ref}")
390
- done
391
- if (( \${#missing[@]} > 0 )); then
392
- echo "skill entry 检查失败(\${skill_name}):" >&2
393
- printf ' - %s\\n' "\${missing[@]}" >&2
394
- exit 1
395
- fi
396
-
397
- local line_count
398
- line_count="$(wc -l < "\${skill_md}" | tr -d ' ')"
399
- if [[ "\${line_count}" =~ ^[0-9]+$ && "\${line_count}" -gt 180 ]]; then
400
- echo "skill entry 检查失败:\${skill_md} 行数为 \${line_count},入口应保持精简" >&2
401
- exit 1
402
- fi
403
- echo "skill entry 检查通过:\${skill_name} references ok, lines=\${line_count}"
404
- }
405
-
406
- check_skill "loop-agent" \\
407
- "references/harness-policy.md" \\
408
- "references/hybrid-dag.md" \\
409
- "references/verification-and-failure-handling.md" \\
410
- "references/command-reference.md"
411
- check_skill "agent-worker" "references/agent-worker-operator.md"
412
-
413
- description_line="$(grep -E '^description:' .agents/skills/agent-worker/SKILL.md | head -n 1 | tr '[:upper:]' '[:lower:]')"
414
- for term in "agent-worker" "feature packet" "taskspec" "task pool" "self-host" "candidate" "loop-agent"; do
415
- if [[ "\${description_line}" != *"\${term}"* ]]; then
416
- echo "skill entry 检查失败(agent-worker):description 缺少触发/路由词 \${term}" >&2
417
- exit 1
418
- fi
419
- done
366
+ const INIT_CHECK_SKILL_ENTRY_SH = `#!/usr/bin/env bash
367
+ set -euo pipefail
368
+
369
+ ROOT_DIR="$(cd "$(dirname "\${BASH_SOURCE[0]}")/.." && pwd)"
370
+ cd "\${ROOT_DIR}"
371
+
372
+ check_skill() {
373
+ local skill_name="$1"
374
+ shift
375
+ local skill_dir=".agents/skills/\${skill_name}"
376
+ local skill_md="\${skill_dir}/SKILL.md"
377
+ local missing=()
378
+
379
+ if [[ ! -f "\${skill_md}" ]]; then
380
+ echo "skill entry 检查失败:缺少 \${skill_md}" >&2
381
+ exit 1
382
+ fi
383
+ grep -Eq "^name:[[:space:]]*\${skill_name}[[:space:]]*$" "\${skill_md}" || missing+=("frontmatter name")
384
+ grep -Eq '^description:[[:space:]]*[^[:space:]]' "\${skill_md}" || missing+=("frontmatter description")
385
+
386
+ local ref
387
+ for ref in "$@"; do
388
+ [[ -f "\${skill_dir}/\${ref}" ]] || missing+=("\${ref}")
389
+ grep -Fq "\${ref}" "\${skill_md}" || missing+=("SKILL.md -> \${ref}")
390
+ done
391
+ if (( \${#missing[@]} > 0 )); then
392
+ echo "skill entry 检查失败(\${skill_name}):" >&2
393
+ printf ' - %s\\n' "\${missing[@]}" >&2
394
+ exit 1
395
+ fi
396
+
397
+ local line_count
398
+ line_count="$(wc -l < "\${skill_md}" | tr -d ' ')"
399
+ if [[ "\${line_count}" =~ ^[0-9]+$ && "\${line_count}" -gt 180 ]]; then
400
+ echo "skill entry 检查失败:\${skill_md} 行数为 \${line_count},入口应保持精简" >&2
401
+ exit 1
402
+ fi
403
+ echo "skill entry 检查通过:\${skill_name} references ok, lines=\${line_count}"
404
+ }
405
+
406
+ check_skill "loop-agent" \\
407
+ "references/harness-policy.md" \\
408
+ "references/hybrid-dag.md" \\
409
+ "references/verification-and-failure-handling.md" \\
410
+ "references/command-reference.md"
411
+ check_skill "agent-worker" "references/agent-worker-operator.md"
412
+
413
+ description_line="$(grep -E '^description:' .agents/skills/agent-worker/SKILL.md | head -n 1 | tr '[:upper:]' '[:lower:]')"
414
+ for term in "agent-worker" "feature packet" "taskspec" "task pool" "self-host" "candidate" "loop-agent"; do
415
+ if [[ "\${description_line}" != *"\${term}"* ]]; then
416
+ echo "skill entry 检查失败(agent-worker):description 缺少触发/路由词 \${term}" >&2
417
+ exit 1
418
+ fi
419
+ done
420
420
  `;
421
- const INIT_CHECK_REPO_SH = `#!/usr/bin/env bash
422
- set -euo pipefail
423
-
424
- ROOT_DIR="$(cd "$(dirname "\${BASH_SOURCE[0]}")/.." && pwd)"
425
- cd "\${ROOT_DIR}"
426
-
427
- checks=(
428
- "scripts/check-engineering-structure.sh"
429
- "scripts/check-doc-index.sh"
430
- "scripts/check-doc-links.sh"
431
- "scripts/check-active-plan-status.sh"
432
- "scripts/check-exec-plan-index-sync.sh"
433
- "scripts/check-harness-runtime-clean.sh"
434
- "scripts/check-architecture-boundaries.sh"
435
- "scripts/check-skill-entry.sh"
436
- "scripts/check-product-line-docs.sh"
437
- )
438
-
439
- for check in "\${checks[@]}"; do
440
- echo "==> bash \${check}"
441
- bash "\${check}"
442
- echo
443
- done
444
-
445
- echo "仓库治理检查全部通过"
421
+ const INIT_CHECK_REPO_SH = `#!/usr/bin/env bash
422
+ set -euo pipefail
423
+
424
+ ROOT_DIR="$(cd "$(dirname "\${BASH_SOURCE[0]}")/.." && pwd)"
425
+ cd "\${ROOT_DIR}"
426
+
427
+ checks=(
428
+ "scripts/check-engineering-structure.sh"
429
+ "scripts/check-doc-index.sh"
430
+ "scripts/check-doc-links.sh"
431
+ "scripts/check-active-plan-status.sh"
432
+ "scripts/check-exec-plan-index-sync.sh"
433
+ "scripts/check-harness-runtime-clean.sh"
434
+ "scripts/check-architecture-boundaries.sh"
435
+ "scripts/check-skill-entry.sh"
436
+ "scripts/check-product-line-docs.sh"
437
+ )
438
+
439
+ for check in "\${checks[@]}"; do
440
+ echo "==> bash \${check}"
441
+ bash "\${check}"
442
+ echo
443
+ done
444
+
445
+ echo "仓库治理检查全部通过"
446
446
  `;
447
- const INIT_CHECK_PRODUCT_LINE_DOCS_SH = `#!/usr/bin/env bash
448
- set -euo pipefail
449
-
450
- ROOT_DIR="$(cd "$(dirname "\${BASH_SOURCE[0]}")/.." && pwd)"
451
- cd "\${ROOT_DIR}"
452
-
453
- if ! command -v agent-worker >/dev/null 2>&1; then
454
- echo "product-line docs check skipped: agent-worker is not installed"
455
- exit 0
456
- fi
457
-
458
- feature_dirs=()
459
- for root in features product/features dogfood/features; do
460
- [[ -d "\${root}" ]] || continue
461
- while IFS= read -r feature_dir; do
462
- if [[ ! -f "\${feature_dir}/acceptance.yaml" ]]; then
463
- echo "product-line docs check failed: incomplete feature packet missing acceptance.yaml: \${feature_dir}" >&2
464
- exit 1
465
- fi
466
- feature_dirs+=("\${feature_dir}")
467
- done < <(find "\${root}" -mindepth 1 -maxdepth 1 -type d | sort)
468
- done
469
-
470
- if [[ \${#feature_dirs[@]} -eq 0 ]]; then
471
- echo "product-line docs check skipped: no feature packets found"
472
- exit 0
473
- fi
474
-
475
- for feature_dir in "\${feature_dirs[@]}"; do
476
- echo "==> validate product-line feature: \${feature_dir}"
477
- agent-worker task validate-feature "\${feature_dir}"
478
- done
479
-
480
- echo "product-line docs checks passed: \${#feature_dirs[@]} feature packet(s)"
447
+ const INIT_CHECK_PRODUCT_LINE_DOCS_SH = `#!/usr/bin/env bash
448
+ set -euo pipefail
449
+
450
+ ROOT_DIR="$(cd "$(dirname "\${BASH_SOURCE[0]}")/.." && pwd)"
451
+ cd "\${ROOT_DIR}"
452
+
453
+ if ! command -v agent-worker >/dev/null 2>&1; then
454
+ echo "product-line docs check skipped: agent-worker is not installed"
455
+ exit 0
456
+ fi
457
+
458
+ feature_dirs=()
459
+ for root in features product/features dogfood/features; do
460
+ [[ -d "\${root}" ]] || continue
461
+ while IFS= read -r feature_dir; do
462
+ if [[ ! -f "\${feature_dir}/acceptance.yaml" ]]; then
463
+ echo "product-line docs check failed: incomplete feature packet missing acceptance.yaml: \${feature_dir}" >&2
464
+ exit 1
465
+ fi
466
+ feature_dirs+=("\${feature_dir}")
467
+ done < <(find "\${root}" -mindepth 1 -maxdepth 1 -type d | sort)
468
+ done
469
+
470
+ if [[ \${#feature_dirs[@]} -eq 0 ]]; then
471
+ echo "product-line docs check skipped: no feature packets found"
472
+ exit 0
473
+ fi
474
+
475
+ for feature_dir in "\${feature_dirs[@]}"; do
476
+ echo "==> validate product-line feature: \${feature_dir}"
477
+ agent-worker task validate-feature "\${feature_dir}"
478
+ done
479
+
480
+ echo "product-line docs checks passed: \${#feature_dirs[@]} feature packet(s)"
481
481
  `;
482
- const INIT_CI_GOVERNANCE_SH = `#!/usr/bin/env bash
483
- set -euo pipefail
484
-
485
- ROOT_DIR="$(cd "$(dirname "\${BASH_SOURCE[0]}")/.." && pwd)"
486
- cd "\${ROOT_DIR}"
487
-
488
- bash scripts/check-repo.sh
482
+ const INIT_CI_GOVERNANCE_SH = `#!/usr/bin/env bash
483
+ set -euo pipefail
484
+
485
+ ROOT_DIR="$(cd "$(dirname "\${BASH_SOURCE[0]}")/.." && pwd)"
486
+ cd "\${ROOT_DIR}"
487
+
488
+ bash scripts/check-repo.sh
489
489
  `;
490
- const INIT_CI_TESTS_SH = `#!/usr/bin/env bash
491
- set -euo pipefail
492
-
493
- ROOT_DIR="$(cd "$(dirname "\${BASH_SOURCE[0]}")/.." && pwd)"
494
- cd "\${ROOT_DIR}"
495
-
496
- ran=0
497
- notes=()
498
-
499
- run_cmd() {
500
- echo "==> $*"
501
- "$@"
502
- ran=1
503
- }
504
-
505
- run_bash() {
506
- echo "==> $*"
507
- bash -lc "$*"
508
- ran=1
509
- }
510
-
511
- has_make_target() {
512
- local target="$1"
513
- [[ -f Makefile || -f makefile ]] || return 1
514
- grep -Eq "^[[:alnum:]_.-]*\${target}[[:alnum:]_.-]*:" Makefile makefile 2>/dev/null
515
- }
516
-
517
- has_npm_script() {
518
- local script="$1"
519
- [[ -f package.json ]] || return 1
520
- command -v node >/dev/null 2>&1 || return 1
521
- node -e "const fs=require('fs'); const p=JSON.parse(fs.readFileSync('package.json','utf8')); process.exit(p.scripts && p.scripts[process.argv[1]] ? 0 : 1)" "\${script}" >/dev/null 2>&1
522
- }
523
-
524
- if [[ -f package.json ]]; then
525
- if command -v npm >/dev/null 2>&1; then
526
- for script in lint typecheck test build; do
527
- if has_npm_script "\${script}"; then
528
- run_cmd npm run "\${script}"
529
- fi
530
- done
531
- else
532
- notes+=("package.json exists but npm is not available")
533
- fi
534
- fi
535
-
536
- if has_make_target verify; then
537
- run_cmd make verify
538
- elif has_make_target test; then
539
- run_cmd make test
540
- fi
541
-
542
- if [[ -f go.mod ]]; then
543
- if command -v go >/dev/null 2>&1; then
544
- run_cmd go test ./...
545
- else
546
- notes+=("go.mod exists but go is not available")
547
- fi
548
- fi
549
-
550
- if [[ -f Cargo.toml ]]; then
551
- if command -v cargo >/dev/null 2>&1; then
552
- run_cmd cargo test
553
- else
554
- notes+=("Cargo.toml exists but cargo is not available")
555
- fi
556
- fi
557
-
558
- if [[ -f pyproject.toml || -f pytest.ini || -f tox.ini ]]; then
559
- if command -v pytest >/dev/null 2>&1; then
560
- run_cmd pytest
561
- elif command -v tox >/dev/null 2>&1 && [[ -f tox.ini ]]; then
562
- run_cmd tox
563
- else
564
- notes+=("Python project metadata found but pytest/tox is not available")
565
- fi
566
- fi
567
-
568
- if [[ -f pom.xml ]]; then
569
- if command -v mvn >/dev/null 2>&1; then
570
- run_cmd mvn test
571
- else
572
- notes+=("pom.xml exists but mvn is not available")
573
- fi
574
- fi
575
-
576
- if [[ -f build.gradle || -f build.gradle.kts || -f settings.gradle || -f settings.gradle.kts ]]; then
577
- if [[ -x ./gradlew ]]; then
578
- run_cmd ./gradlew test
579
- elif command -v gradle >/dev/null 2>&1; then
580
- run_cmd gradle test
581
- else
582
- notes+=("Gradle project metadata found but gradle/gradlew is not available")
583
- fi
584
- fi
585
-
586
- if compgen -G "*.sln" >/dev/null || compgen -G "*.csproj" >/dev/null; then
587
- if command -v dotnet >/dev/null 2>&1; then
588
- run_cmd dotnet test
589
- else
590
- notes+=(".NET project metadata found but dotnet is not available")
591
- fi
592
- fi
593
-
594
- if (( ran == 0 )); then
595
- echo "未检测到可安全自动运行的项目测试入口。"
596
- echo "loop-agent 治理检查仍可运行;请让初始化模型根据目标项目技术栈补充 scripts/ci-tests.sh 与 ${GOVERNANCE_ROOT_TOKEN}/verification-matrix.md。"
597
- fi
598
-
599
- if (( \${#notes[@]} > 0 )); then
600
- echo "项目验证探测备注:"
601
- for note in "\${notes[@]}"; do
602
- echo " - \${note}"
603
- done
604
- fi
490
+ const INIT_CI_TESTS_SH = `#!/usr/bin/env bash
491
+ set -euo pipefail
492
+
493
+ ROOT_DIR="$(cd "$(dirname "\${BASH_SOURCE[0]}")/.." && pwd)"
494
+ cd "\${ROOT_DIR}"
495
+
496
+ ran=0
497
+ notes=()
498
+
499
+ run_cmd() {
500
+ echo "==> $*"
501
+ "$@"
502
+ ran=1
503
+ }
504
+
505
+ run_bash() {
506
+ echo "==> $*"
507
+ bash -lc "$*"
508
+ ran=1
509
+ }
510
+
511
+ has_make_target() {
512
+ local target="$1"
513
+ [[ -f Makefile || -f makefile ]] || return 1
514
+ grep -Eq "^[[:alnum:]_.-]*\${target}[[:alnum:]_.-]*:" Makefile makefile 2>/dev/null
515
+ }
516
+
517
+ has_npm_script() {
518
+ local script="$1"
519
+ [[ -f package.json ]] || return 1
520
+ command -v node >/dev/null 2>&1 || return 1
521
+ node -e "const fs=require('fs'); const p=JSON.parse(fs.readFileSync('package.json','utf8')); process.exit(p.scripts && p.scripts[process.argv[1]] ? 0 : 1)" "\${script}" >/dev/null 2>&1
522
+ }
523
+
524
+ if [[ -f package.json ]]; then
525
+ if command -v npm >/dev/null 2>&1; then
526
+ for script in lint typecheck test build; do
527
+ if has_npm_script "\${script}"; then
528
+ run_cmd npm run "\${script}"
529
+ fi
530
+ done
531
+ else
532
+ notes+=("package.json exists but npm is not available")
533
+ fi
534
+ fi
535
+
536
+ if has_make_target verify; then
537
+ run_cmd make verify
538
+ elif has_make_target test; then
539
+ run_cmd make test
540
+ fi
541
+
542
+ if [[ -f go.mod ]]; then
543
+ if command -v go >/dev/null 2>&1; then
544
+ run_cmd go test ./...
545
+ else
546
+ notes+=("go.mod exists but go is not available")
547
+ fi
548
+ fi
549
+
550
+ if [[ -f Cargo.toml ]]; then
551
+ if command -v cargo >/dev/null 2>&1; then
552
+ run_cmd cargo test
553
+ else
554
+ notes+=("Cargo.toml exists but cargo is not available")
555
+ fi
556
+ fi
557
+
558
+ if [[ -f pyproject.toml || -f pytest.ini || -f tox.ini ]]; then
559
+ if command -v pytest >/dev/null 2>&1; then
560
+ run_cmd pytest
561
+ elif command -v tox >/dev/null 2>&1 && [[ -f tox.ini ]]; then
562
+ run_cmd tox
563
+ else
564
+ notes+=("Python project metadata found but pytest/tox is not available")
565
+ fi
566
+ fi
567
+
568
+ if [[ -f pom.xml ]]; then
569
+ if command -v mvn >/dev/null 2>&1; then
570
+ run_cmd mvn test
571
+ else
572
+ notes+=("pom.xml exists but mvn is not available")
573
+ fi
574
+ fi
575
+
576
+ if [[ -f build.gradle || -f build.gradle.kts || -f settings.gradle || -f settings.gradle.kts ]]; then
577
+ if [[ -x ./gradlew ]]; then
578
+ run_cmd ./gradlew test
579
+ elif command -v gradle >/dev/null 2>&1; then
580
+ run_cmd gradle test
581
+ else
582
+ notes+=("Gradle project metadata found but gradle/gradlew is not available")
583
+ fi
584
+ fi
585
+
586
+ if compgen -G "*.sln" >/dev/null || compgen -G "*.csproj" >/dev/null; then
587
+ if command -v dotnet >/dev/null 2>&1; then
588
+ run_cmd dotnet test
589
+ else
590
+ notes+=(".NET project metadata found but dotnet is not available")
591
+ fi
592
+ fi
593
+
594
+ if (( ran == 0 )); then
595
+ echo "未检测到可安全自动运行的项目测试入口。"
596
+ echo "loop-agent 治理检查仍可运行;请让初始化模型根据目标项目技术栈补充 scripts/ci-tests.sh 与 ${GOVERNANCE_ROOT_TOKEN}/verification-matrix.md。"
597
+ fi
598
+
599
+ if (( \${#notes[@]} > 0 )); then
600
+ echo "项目验证探测备注:"
601
+ for note in "\${notes[@]}"; do
602
+ echo " - \${note}"
603
+ done
604
+ fi
605
605
  `;
606
- const INIT_CI_SH = `#!/usr/bin/env bash
607
- set -euo pipefail
608
-
609
- ROOT_DIR="$(cd "$(dirname "\${BASH_SOURCE[0]}")/.." && pwd)"
610
- cd "\${ROOT_DIR}"
611
-
612
- bash scripts/ci-governance.sh
613
- bash scripts/ci-tests.sh
606
+ const INIT_CI_SH = `#!/usr/bin/env bash
607
+ set -euo pipefail
608
+
609
+ ROOT_DIR="$(cd "$(dirname "\${BASH_SOURCE[0]}")/.." && pwd)"
610
+ cd "\${ROOT_DIR}"
611
+
612
+ bash scripts/ci-governance.sh
613
+ bash scripts/ci-tests.sh
614
614
  `;
615
615
  const INIT_SCRIPT_FILES = {
616
616
  "scripts/check-engineering-structure.sh": INIT_CHECK_ENGINEERING_STRUCTURE_SH,
@@ -805,6 +805,12 @@ export function buildManagedGitignoreBlock() {
805
805
  "# one-shot executor runs",
806
806
  ".harness/runs/*",
807
807
  "!.harness/runs/.gitkeep",
808
+ "!.harness/runs/active/",
809
+ "!.harness/runs/active/.gitkeep",
810
+ "!.harness/runs/completed/",
811
+ "!.harness/runs/completed/.gitkeep",
812
+ "!.harness/runs/failed/",
813
+ "!.harness/runs/failed/.gitkeep",
808
814
  "",
809
815
  "# session / cache / logs / recomputable surface state",
810
816
  ".harness/live/",
@@ -980,6 +986,26 @@ async function ensureHarnessDirs(repoRoot, written) {
980
986
  await mkdir(path.join(repoRoot, dir), { recursive: true });
981
987
  written.push(dir);
982
988
  }
989
+ const placeholders = [
990
+ ".harness/tasks/.gitkeep",
991
+ ".harness/dag-runs/active/.gitkeep",
992
+ ".harness/dag-runs/completed/.gitkeep",
993
+ ".harness/dag-runs/paused/.gitkeep",
994
+ ".harness/runs/.gitkeep",
995
+ ".harness/runs/active/.gitkeep",
996
+ ".harness/runs/completed/.gitkeep",
997
+ ".harness/runs/failed/.gitkeep",
998
+ ];
999
+ for (const relativePath of placeholders) {
1000
+ const target = path.join(repoRoot, relativePath);
1001
+ try {
1002
+ await access(target);
1003
+ }
1004
+ catch {
1005
+ await writeFile(target, "", "utf8");
1006
+ written.push(relativePath);
1007
+ }
1008
+ }
983
1009
  }
984
1010
  async function writeCompatPrompts(input) {
985
1011
  for (const [name, content] of Object.entries(COMPAT_PROMPTS)) {
@@ -1824,12 +1850,24 @@ function buildTargetFeatureWorkflow(input) {
1824
1850
  DAG_HARD_GATE_TRIGGER,
1825
1851
  "",
1826
1852
  "Before executing a DAG, review profile routing, governance profile, writer writeSet, allowed paths, forbidden paths, shell verification, and decision gate mode.",
1853
+ "Generated DAGs bind authoritative task-source paths, SHA-256 hashes, and explicit REQ/BR/AC identifiers. Frontend plans with explicit identifiers pass a deterministic coverage gate before final design review and implementation.",
1854
+ "After an interrupted run, repair the task source and regenerate the complete DAG. Do not construct an impl-only recovery DAG from an upstream summary; strict governance rejects a v3 orphan writer without sourceBinding or a read-only planner ancestor.",
1827
1855
  "",
1828
1856
  "## Specialized Task Kinds",
1829
1857
  "",
1830
- "Set `taskKind` in `.harness/tasks/<task-id>/task.json` to route a task to a dedicated DAG profile instead of the default auto profile:",
1858
+ "- standard tasks are classified conservatively from the task title, `source/需求.md`, and structured `allowedPaths`.",
1859
+ "- Only high-confidence frontend implementation demands select the frontend DAG automatically; backend, mixed, negated, and unknown demands keep the template selected by the normal governance profile.",
1860
+ "- `frontend-mock-assess-pi` reads Mock/API/schema evidence and selects `native|browser-intercept|request-adapter|not-needed|blocked` before frontend planning; its deterministic gate rejects blocked or malformed output, while the existing frontend implementer remains the only writer.",
1861
+ "- Mock-backed verification never proves real API integration. When the backend was not exercised, closeout must retain the gap and name `<task-id>-real-api-integration-verify`; that follow-up is explicitly created/run after backend readiness, never automatic.",
1862
+ "- Automatic frontend classification never replaces a supervised template selected by an explicit profile, workflowPolicy, or the supervised quality gate.",
1863
+ "- A backend implementation does not select the backend test DAG. `backend-test` remains an explicit test-engineering workflow.",
1864
+ "- Explicit specialized `taskKind` values remain compatible and take precedence over task-source classification.",
1865
+ "",
1866
+ "Set an explicit specialized `taskKind` in `.harness/tasks/<task-id>/task.json` only when the dedicated workflow itself is part of the task contract:",
1831
1867
  "",
1868
+ "- `taskKind: \"frontend-implementation\"` explicitly selects the frontend DAG for compatibility or intentional override. Optional `frontendMock` config sets `policy: auto|required|disabled`, an existing `serviceRoot`, and generation-time-frozen `verifyCommands`; an unsafe or incomplete explicit required contract produces an assessment-only DAG with no writer, while a complete required contract adds Mock-specific verification only when trusted commands exist. Auto API tasks without a native service may use an existing browser interception harness or reversible request adapter, then continue through static and behavior verification.",
1832
1869
  "- `taskKind: \"backend-test\"` selects the dedicated backend test DAG. Its Pi nodes analyze requirements, generate and review backend cases, generate pytest, and retrospect on results; shell gate/execution nodes enforce the review verdict and run the target project's pytest. The backend test templates (`backend-test-dag.json` and the `backend-test-dag.*.prompt.md` files) ship inside the loop-agent package as static references and are projected to target projects under the governance `templates/` directory.",
1870
+ "- `taskKind: \"frontend-test\"` selects the FE-test RAG DAG. It writes a traceable frontend RAG package and Markdown case manifest, then executes manifest cases serially with `playwright-cli` in isolated test environments and retains per-case evidence. It never generates pytest or Playwright source code. `frontendTest.maxCasesPerBatch` defaults to 20 (maximum 50); optional `maxTokensPerCase` and `maxTotalTokens` stop only later cases after a completed case's token usage is recorded, marking them `blocked: token-budget-exhausted`. Generated browser startup uses `playwright-cli open --browser=chrome --headed <base-url>`; the generic playwright-cli skill is unchanged.",
1833
1871
  "- Only eligible read-only Pi nodes (planner, scout, reviewer, verifier, closeout with no write-capable tool profile) receive the conservative automatic retry policy. Supervisor, implementer, writer, docs-only, dynamic, shell, static, and decision-gate nodes are not retried automatically. Eligible nodes cannot write repository files; the controller only records immutable attempt evidence under `.harness/dag-runs/<state>/<run-id>/<node-id>/attempt-<n>.json`.",
1834
1872
  "",
1835
1873
  "## Verification",