@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
@@ -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,
@@ -679,9 +679,34 @@ function buildManagedAgentsBlock(input) {
679
679
  "- 保留无关的用户改动,不要回退自己没有做的修改。",
680
680
  "- 委托模型写入前,必须把写入边界写成结构化 `task.json.allowedPaths` / `task.json.forbiddenPaths`,再审查生成 DAG 的 writer `writeSet`;不要只依赖 `source/执行约束.md` 的自然语言约束。",
681
681
  "",
682
+ "### 自然语言入口路由",
683
+ "",
684
+ "用户用中文表达意图时,按以下三类入口路由;只读与写入必须严格区分。",
685
+ "",
686
+ "| 用户表达 | 入口 | 执行动作 |",
687
+ "|---|---|---|",
688
+ "| loop-agent 初始化 / loop agent 初始化 / loop agent初始化 / 初始化 loop-agent | 初始化 | 完成确定性初始化闭环 |",
689
+ "| 初始化更新校验 / 检查初始化更新 / loop-agent 初始化更新校验 / loop agent初始化更新校验 | 更新校验 | 只读报告,不写入 |",
690
+ "| 初始化安全更新 / 应用初始化更新 / loop-agent 初始化安全更新 / loop agent初始化安全更新 | 安全更新 | check-update 后只执行确定性安全动作 |",
691
+ "",
692
+ "**更新校验(只读)**:用户说“初始化更新校验”“检查初始化更新”时,只读执行下面命令,汇报 deterministic actions、model merge、human decisions 和 next steps。**这一步不得自动执行 `apply-safe` 或模型合并。**",
693
+ "",
694
+ "```bash",
695
+ "loop-agent init check-update --repo-root . --markdown",
696
+ "```",
697
+ "",
698
+ "**安全更新(写入型)**:用户明确说“初始化安全更新”“应用初始化更新”时,先 check-update,再执行确定性安全动作;surface 缺失时先 bootstrap,存在 human decisions 时停下等用户决策。model merge 任务必须带 allowed/forbidden paths,且不得自动决策。安全更新完成后必须复查 `loop-agent init doctor --repo-root .`、`loop-agent inspect --repo-root .`、`loop-agent docs audit --repo-root .` 与目标项目治理检查(如 `bash scripts/check-repo.sh`)。",
699
+ "",
700
+ "```bash",
701
+ "loop-agent init check-update --repo-root . --markdown",
702
+ "loop-agent init update --repo-root . --apply-safe",
703
+ "```",
704
+ "",
705
+ "仅当 check-update 报告 surface 缺失时才执行 `loop-agent init update --repo-root . --bootstrap-surface`。",
706
+ "",
682
707
  "### 初始化闭环",
683
708
  "",
684
- `当用户要求在本仓库初始化 loop-agent,或发现 \`README.md\` / \`${input.governanceRoot}/verification-matrix.md\` 仍停留在通用初始化状态时,模型应在同一轮工作中完成初始化闭环,不要把补全文档和验证矩阵留给用户交互。`,
709
+ `当用户要求初始化 loop-agent(“初始化 loop-agent”“loop agent 初始化”“loop agent初始化”“loop-agent 初始化”),或发现 \`README.md\` / \`${input.governanceRoot}/verification-matrix.md\` 仍停留在通用初始化状态时,模型应在同一轮工作中完成初始化闭环,不要把补全文档和验证矩阵留给用户交互。`,
685
710
  "",
686
711
  "标准流程:",
687
712
  "",
@@ -731,6 +756,22 @@ function buildManagedAgentsBlock(input) {
731
756
  "",
732
757
  "执行 DAG 前必须审查 profile routing、governance profile、writer 的 `writeSet`、`allowedPaths`、`forbiddenPaths`、shell verification 和 decision gate mode。不要执行占位或过宽的写入范围。",
733
758
  "",
759
+ "### 任务类型路由(taskKind)",
760
+ "",
761
+ "- 用户明确提出后端测试、接口/API 测试、pytest,或语境明确为后端的自动化测试时,必须把 `.harness/tasks/<task-id>/task.json` 的 `taskKind` 设置为 `\"backend-test\"`,不得保留默认 `standard`。",
762
+ "- `backend-test` 是 `taskKind`,不是 `--profile` 的可选值;运行 `dag run-task` 时继续使用 `--profile auto`,也可按需显式选择 `minimal` / `standard` / `reviewed` / `supervised`,不要把业务模板名当作 profile。",
763
+ "- 仅出现“自动化测试”且无法判断前后端时,先阅读任务源与目标项目技术栈再决定,禁止无条件路由到 `backend-test`。",
764
+ "",
765
+ "### 运行看板(只读)",
766
+ "",
767
+ "启动本地只读运行看板:",
768
+ "",
769
+ "```bash",
770
+ "agent-worker observe serve --repo . --port 8787",
771
+ "```",
772
+ "",
773
+ "浏览器打开 `http://127.0.0.1:8787/`。看板只读,默认只绑定本机 `127.0.0.1`;不要直接暴露到公开网络。",
774
+ "",
734
775
  "### DAG 诊断与收口",
735
776
  "",
736
777
  "执行后优先使用 `loop-agent dag report --run-id <run-id> --markdown` 读取 run facts;失败或 paused run 使用 `loop-agent dag doctor --run-id <run-id> --markdown` 诊断。失败 DAG run 不应写成成功 closeout,应使用 `loop-agent dag closeout-draft --run-id <run-id>` 生成 failure handoff,保留 what failed、evidence、classification、recommended follow-up、safe retry conditions 和 human decision needed。",
@@ -822,6 +863,9 @@ export function buildManagedGitignoreBlock() {
822
863
  ".harness/task-pool/*",
823
864
  ".task-pool/",
824
865
  "",
866
+ "# repo-local skill dependencies installed inside projected skills",
867
+ ".agents/skills/*/node_modules/",
868
+ "",
825
869
  "# multi-worktree parallel mode",
826
870
  ".worktrees/",
827
871
  GITIGNORE_BLOCK_END,
@@ -1242,7 +1286,7 @@ async function buildCurrentSurfaceState(input) {
1242
1286
  repoRoot: input.repoRoot,
1243
1287
  projectName: input.projectName,
1244
1288
  governanceRoot: input.governanceRoot,
1245
- entry,
1289
+ entry: manifestEntry,
1246
1290
  });
1247
1291
  const sourceSha256 = desired.content === undefined ? undefined : sha256Text(desired.content);
1248
1292
  const base = {
@@ -1318,6 +1362,19 @@ async function buildCurrentSurfaceState(input) {
1318
1362
  }
1319
1363
  async function writeInitSurfaceState(input) {
1320
1364
  const state = await buildCurrentSurfaceState(input);
1365
+ if (input.stateKind === "recorded" && input.preserveOwnershipFrom) {
1366
+ for (const [pathName, file] of Object.entries(state.files)) {
1367
+ if (file.relationship !== "local-existing-unknown")
1368
+ continue;
1369
+ const priorHash = input.preserveOwnershipFrom.files[pathName]?.currentSha256;
1370
+ if (priorHash !== undefined) {
1371
+ file.currentSha256 = priorHash;
1372
+ }
1373
+ else {
1374
+ delete file.currentSha256;
1375
+ }
1376
+ }
1377
+ }
1321
1378
  const target = path.join(input.repoRoot, INIT_SURFACE_STATE_PATH);
1322
1379
  await mkdir(path.dirname(target), { recursive: true });
1323
1380
  await writeFile(target, `${JSON.stringify(state, null, 2)}\n`, "utf-8");
@@ -1867,9 +1924,28 @@ function buildTargetFeatureWorkflow(input) {
1867
1924
  "",
1868
1925
  "- `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.",
1869
1926
  "- `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.",
1927
+ "- `taskKind: \"knowledge-sync\"` selects the Feature-scoped test-knowledge write-back DAG (collect → draft → validate → apply → pointer). Bind `featureId` in `task.json` (or hardConstraints / requirement text). It writes only under `features/<featureId>/…` after final verification evidence exists.",
1928
+ "- `taskKind: \"knowledge-graph-bootstrap\"` selects the business knowledge-graph bootstrap DAG (preflight → inventory → propose → validate → review → gate → promote → materialize). AI writes only `knowledge/bootstrap/staging/**`; promote is merge-new-only.",
1870
1929
  "- `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.",
1871
1930
  "- 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`.",
1872
1931
  "",
1932
+ "Use the package-backed public knowledge CLI for graph operations. Do not require target projects to run package-only kb runtime scripts:",
1933
+ "",
1934
+ "```bash",
1935
+ "loop-agent knowledge graph-init --product-name <name>",
1936
+ "# edit knowledge/bootstrap/scope.yaml, then:",
1937
+ "loop-agent dag run-task <task-id> # taskKind: knowledge-graph-bootstrap",
1938
+ "loop-agent knowledge query --mode by_feature --feature F-2026-004 --json",
1939
+ "loop-agent knowledge query --mode by_id --id SVC-order --json",
1940
+ "loop-agent knowledge query --mode search --text \"keyword\" --json",
1941
+ "loop-agent knowledge graph-incremental-prepare --feature F-2026-004 --service <service>",
1942
+ "# review the prepared scope/staging; for a manual reviewed promotion:",
1943
+ "loop-agent knowledge graph-promote",
1944
+ "loop-agent knowledge graph-materialize",
1945
+ "```",
1946
+ "",
1947
+ "Daily Feature test-knowledge write-back still uses `taskKind: \"knowledge-sync\"` with a bound `featureId`, separate from graph bootstrap/incremental entry points.",
1948
+ "",
1873
1949
  "## Verification",
1874
1950
  "",
1875
1951
  `Use \`${input.governanceRoot}/verification-matrix.md\` to choose the narrowest command that proves the claim.`,
@@ -2563,38 +2639,31 @@ export async function applyInitUpdate(input) {
2563
2639
  });
2564
2640
  }
2565
2641
  if (input.applySafe) {
2642
+ const existingSurface = await readExistingSurfaceState(repoRoot);
2643
+ // Preserve source strength: recorded stays recorded so unchanged owned files
2644
+ // remain deterministic refresh candidates; bootstrap/inferred stays inferred.
2645
+ const preservedStateKind = existingSurface?.stateKind === "recorded" ? "recorded" : "inferred-baseline";
2566
2646
  const report = await checkInitUpdate({ repoRoot, projectName, governanceRoot });
2567
2647
  for (const action of report.deterministicActions) {
2568
2648
  if (action.type === "bootstrap-surface") {
2569
2649
  skipped.push(action);
2570
2650
  continue;
2571
2651
  }
2572
- if (action.type !== "strip-pi-requires-api-key" &&
2573
- action.type !== "add-harness-schema-ref" &&
2574
- action.type !== "refresh-owned-file" &&
2575
- action.type !== "migrate-harness-governance-root" &&
2576
- action.type !== "migrate-harness-model-fields" &&
2577
- action.type !== "migrate-owned-file" &&
2578
- action.type !== "remove-owned-file" &&
2579
- action.type !== "remove-empty-directory") {
2580
- const currentState = await buildCurrentSurfaceState({
2581
- repoRoot,
2582
- projectName,
2583
- governanceRoot,
2584
- stateKind: "inferred-baseline",
2585
- });
2586
- const relationship = currentState.files[action.path]?.relationship;
2587
- if (relationship === "local-existing-unknown") {
2588
- skipped.push(action);
2589
- continue;
2590
- }
2591
- }
2652
+ // The report was produced immediately before this batch. Each action also
2653
+ // performs its own target check; missing-file writes refuse existing paths,
2654
+ // while managed blocks merge into the latest user-authored content.
2592
2655
  if (await applySafeAction({ repoRoot, projectName, governanceRoot, action }))
2593
2656
  applied.push(action);
2594
2657
  else
2595
2658
  skipped.push(action);
2596
2659
  }
2597
- await writeInitSurfaceState({ repoRoot, projectName, governanceRoot, stateKind: "inferred-baseline" });
2660
+ await writeInitSurfaceState({
2661
+ repoRoot,
2662
+ projectName,
2663
+ governanceRoot,
2664
+ stateKind: preservedStateKind,
2665
+ preserveOwnershipFrom: existingSurface,
2666
+ });
2598
2667
  }
2599
2668
  return {
2600
2669
  applied,