@tea-agent/loop-agent 0.7.5 → 0.8.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 (127) hide show
  1. package/AGENTS.md +143 -142
  2. package/CHANGELOG.md +148 -164
  3. package/README.md +206 -204
  4. package/bin/agent-worker.js +22 -22
  5. package/bin/loop-agent.js +21 -21
  6. package/dist/commands/init.js +518 -488
  7. package/dist/commands/loop-benchmark.js +11 -11
  8. package/dist/commands/pi-reuse-benchmark.js +16 -16
  9. package/dist/executors/cursor-executor.js +1 -1
  10. package/dist/governance/manifest-types.js +1 -1
  11. package/dist/task/runtime.js +27 -27
  12. package/dist/worker/cli.js +3 -3
  13. package/dist/worker/observability/event-store.js +2 -1
  14. package/dist/worker/observability/read-model.js +13 -11
  15. package/dist/worker/observe/paths.js +2 -2
  16. package/dist/worker/observe/routes.js +4 -3
  17. package/dist/worker/observe/static/app.js +1479 -1480
  18. package/dist/worker/observe/static/dag-layout.d.ts +31 -31
  19. package/dist/worker/observe/static/dag-layout.js +83 -83
  20. package/dist/worker/observe/static/index.html +63 -63
  21. package/dist/worker/observe/static/styles.css +722 -722
  22. package/dist/worker/pool/run-store.js +7 -8
  23. package/dist/worker/run-task/run-task.js +11 -2
  24. package/dist/worker/runner/run-ready.js +1 -1
  25. package/dist/workflows/dag/canvas-observer.js +275 -275
  26. package/docs/README.md +80 -79
  27. package/docs/agent-dag-recovery-playbook.md +184 -184
  28. package/docs/agent-dag-runner.md +42 -42
  29. package/docs/architecture/runtime-boundaries.md +162 -162
  30. package/docs/cursor-executor-usage.md +25 -25
  31. package/docs/decisions/README.md +3 -3
  32. package/docs/design/README.md +49 -49
  33. package/docs/development-principles.md +73 -73
  34. package/docs/dynamic-workflow-dag-engine-roadmap.md +1749 -1749
  35. package/docs/exec-plans/README.md +6 -6
  36. package/docs/exec-plans/active/README.md +11 -11
  37. package/docs/exec-plans/completed/README.md +35 -34
  38. package/docs/feature-workflow.md +187 -187
  39. package/docs/harness-methodology-debugging.md +153 -153
  40. package/docs/harness-methodology-tdd.md +130 -130
  41. package/docs/harness-methodology-verification.md +27 -27
  42. package/docs/init-surface.manifest.json +245 -241
  43. package/docs/loop-agent-harness.md +63 -55
  44. package/docs/production-readiness.md +96 -96
  45. package/docs/progress/README.md +3 -3
  46. package/docs/reports/README.md +9 -9
  47. package/docs/skills/README.md +6 -6
  48. package/docs/skills/vetted-skill-registry.md +26 -26
  49. package/docs/templates/adr.md +60 -60
  50. package/docs/templates/agent-dag-authority-surface-audit.prompt.md +94 -94
  51. package/docs/templates/agent-dag-decision-envelope.schema.json +213 -213
  52. package/docs/templates/agent-dag-decision-gate-dogfood-report.md +117 -117
  53. package/docs/templates/agent-dag-decision-gate.prompt.md +246 -246
  54. package/docs/templates/agent-dag-process-supervisor.prompt.md +98 -98
  55. package/docs/templates/agent-dag-report.schema.json +454 -454
  56. package/docs/templates/agent-dag-review-verdict.prompt.md +68 -68
  57. package/docs/templates/agent-dag.base.json +195 -195
  58. package/docs/templates/agent-dag.final-verification.json +190 -190
  59. package/docs/templates/agent-dag.schema.json +316 -316
  60. package/docs/templates/agent-dag.supervised-implementation.json +500 -500
  61. package/docs/templates/exec-plan.md +64 -64
  62. package/docs/templates/feature-spec.md +53 -53
  63. package/docs/templates/harness.schema.json +218 -0
  64. package/docs/templates/hybrid-dag.json +193 -193
  65. package/docs/templates/init-evolution-review.md +33 -33
  66. package/docs/templates/interactive-ui-round2-experiment.md +66 -66
  67. package/docs/templates/product-line/AGENTS.md +8 -8
  68. package/docs/templates/product-line/README.md +9 -9
  69. package/docs/templates/product-line/acceptance.yaml +14 -14
  70. package/docs/templates/product-line/closeout.yaml +9 -9
  71. package/docs/templates/product-line/design.md +13 -13
  72. package/docs/templates/product-line/links.md +10 -10
  73. package/docs/templates/product-line/requirement.md +17 -17
  74. package/docs/templates/product-line/task-graph.yaml +15 -15
  75. package/docs/templates/product-line/task.yaml +65 -65
  76. package/docs/templates/product-line/test-plan.md +7 -7
  77. package/docs/templates/production-readiness-checklist.md +57 -57
  78. package/docs/templates/progress-log.md +17 -17
  79. package/docs/templates/project-start-checklist.md +9 -9
  80. package/docs/templates/qa-report.md +48 -48
  81. package/docs/templates/sprint-contract.md +29 -29
  82. package/docs/templates/worker-dogfood-evidence.md +52 -52
  83. package/docs/templates/worker-dogfood-setup.md +48 -48
  84. package/docs/verification-matrix.md +49 -49
  85. package/examples/decision-gate-agent-dag.json +123 -123
  86. package/examples/example-dag.json +51 -51
  87. package/examples/hybrid-loop-agent-dag.json +194 -194
  88. package/harness.json +73 -71
  89. package/package.json +68 -67
  90. package/scripts/check-product-line-docs.sh +22 -22
  91. package/scripts/check-task-pool-root.sh +32 -0
  92. package/skills/ai-engineering-context/SKILL.md +48 -48
  93. package/skills/code-review-core/SKILL.md +20 -20
  94. package/skills/codebase-scout/SKILL.md +19 -19
  95. package/skills/init-capability-evolution/SKILL.md +69 -69
  96. package/skills/loop-agent/SKILL.md +149 -149
  97. package/skills/loop-agent/references/README.md +67 -67
  98. package/skills/loop-agent/references/command-reference.md +432 -412
  99. package/skills/loop-agent/references/harness-policy.md +263 -263
  100. package/skills/loop-agent/references/hybrid-dag.md +216 -216
  101. package/skills/loop-agent/references/learned/README.md +21 -21
  102. package/skills/loop-agent/references/long-running-loop.md +59 -59
  103. package/skills/loop-agent/references/model-routing.md +36 -36
  104. package/skills/loop-agent/references/multi-worktree.md +54 -54
  105. package/skills/loop-agent/references/one-shot-runs.md +85 -85
  106. package/skills/loop-agent/references/orchestrator-and-interventions.md +169 -169
  107. package/skills/loop-agent/references/pi-prompt.md +23 -23
  108. package/skills/loop-agent/references/pi-subagent-assisted-mode.md +81 -81
  109. package/skills/loop-agent/references/post-implementation-and-patterns.md +44 -44
  110. package/skills/loop-agent/references/task-workflow.md +89 -89
  111. package/skills/loop-agent/references/verification-and-failure-handling.md +128 -128
  112. package/skills/requesting-code-review/SKILL.md +101 -101
  113. package/skills/requesting-code-review/code-reviewer.md +168 -168
  114. package/skills/systematic-debugging/CREATION-LOG.md +119 -119
  115. package/skills/systematic-debugging/SKILL.md +296 -296
  116. package/skills/systematic-debugging/condition-based-waiting-example.ts +158 -158
  117. package/skills/systematic-debugging/condition-based-waiting.md +115 -115
  118. package/skills/systematic-debugging/defense-in-depth.md +122 -122
  119. package/skills/systematic-debugging/find-polluter.sh +63 -63
  120. package/skills/systematic-debugging/root-cause-tracing.md +169 -169
  121. package/skills/systematic-debugging/test-academic.md +14 -14
  122. package/skills/systematic-debugging/test-pressure-1.md +58 -58
  123. package/skills/systematic-debugging/test-pressure-2.md +68 -68
  124. package/skills/systematic-debugging/test-pressure-3.md +69 -69
  125. package/skills/test-driven-development/SKILL.md +20 -20
  126. package/skills/verification-before-completion/SKILL.md +154 -154
  127. package/skills/webapp-testing/SKILL.md +19 -19
@@ -92,501 +92,501 @@ const COMPAT_PROMPTS = {
92
92
  ].join("\n"),
93
93
  };
94
94
  const GOVERNANCE_ROOT_TOKEN = "__LOOP_AGENT_GOVERNANCE_ROOT__";
95
- const INIT_CHECK_ENGINEERING_STRUCTURE_SH = `#!/usr/bin/env bash
96
- set -euo pipefail
97
-
98
- ROOT_DIR="$(cd "$(dirname "\${BASH_SOURCE[0]}")/.." && pwd)"
99
- cd "\${ROOT_DIR}"
100
-
101
- required_paths=(
102
- "README.md"
103
- "harness.json"
104
- "AGENTS.md"
105
- "${GOVERNANCE_ROOT_TOKEN}/README.md"
106
- "${GOVERNANCE_ROOT_TOKEN}/development-principles.md"
107
- "${GOVERNANCE_ROOT_TOKEN}/feature-workflow.md"
108
- "${GOVERNANCE_ROOT_TOKEN}/verification-matrix.md"
109
- "${GOVERNANCE_ROOT_TOKEN}/architecture/runtime-boundaries.md"
110
- "${GOVERNANCE_ROOT_TOKEN}/templates"
111
- "skills/loop-agent/SKILL.md"
112
- ".harness/prompts/analyze.md"
113
- ".harness/prompts/plan.md"
114
- ".harness/tasks"
115
- ".harness/dag-runs/active"
116
- ".harness/dag-runs/completed"
117
- ".harness/dag-runs/paused"
118
- ".harness/runs/active"
119
- ".harness/runs/completed"
120
- ".harness/runs/failed"
121
- "scripts/check-engineering-structure.sh"
122
- "scripts/check-doc-index.sh"
123
- "scripts/check-doc-links.sh"
124
- "scripts/check-active-plan-status.sh"
125
- "scripts/check-exec-plan-index-sync.sh"
126
- "scripts/check-harness-runtime-clean.sh"
127
- "scripts/check-architecture-boundaries.sh"
128
- "scripts/check-skill-entry.sh"
129
- "scripts/check-repo.sh"
130
- "scripts/ci-governance.sh"
131
- "scripts/ci-tests.sh"
132
- "scripts/ci.sh"
133
- )
134
-
135
- missing=()
136
- for item in "\${required_paths[@]}"; do
137
- if [[ ! -e "\${item}" ]]; then
138
- missing+=("\${item}")
139
- fi
140
- done
141
-
142
- if (( \${#missing[@]} > 0 )); then
143
- echo "loop-agent 初始化检查失败,缺少必要路径:"
144
- for item in "\${missing[@]}"; do
145
- echo " - \${item}"
146
- done
147
- exit 1
148
- fi
149
-
150
- echo "loop-agent 工程结构检查通过"
95
+ const INIT_CHECK_ENGINEERING_STRUCTURE_SH = `#!/usr/bin/env bash
96
+ set -euo pipefail
97
+
98
+ ROOT_DIR="$(cd "$(dirname "\${BASH_SOURCE[0]}")/.." && pwd)"
99
+ cd "\${ROOT_DIR}"
100
+
101
+ required_paths=(
102
+ "README.md"
103
+ "harness.json"
104
+ "AGENTS.md"
105
+ "${GOVERNANCE_ROOT_TOKEN}/README.md"
106
+ "${GOVERNANCE_ROOT_TOKEN}/development-principles.md"
107
+ "${GOVERNANCE_ROOT_TOKEN}/feature-workflow.md"
108
+ "${GOVERNANCE_ROOT_TOKEN}/verification-matrix.md"
109
+ "${GOVERNANCE_ROOT_TOKEN}/architecture/runtime-boundaries.md"
110
+ "${GOVERNANCE_ROOT_TOKEN}/templates"
111
+ "skills/loop-agent/SKILL.md"
112
+ ".harness/prompts/analyze.md"
113
+ ".harness/prompts/plan.md"
114
+ ".harness/tasks"
115
+ ".harness/dag-runs/active"
116
+ ".harness/dag-runs/completed"
117
+ ".harness/dag-runs/paused"
118
+ ".harness/runs/active"
119
+ ".harness/runs/completed"
120
+ ".harness/runs/failed"
121
+ "scripts/check-engineering-structure.sh"
122
+ "scripts/check-doc-index.sh"
123
+ "scripts/check-doc-links.sh"
124
+ "scripts/check-active-plan-status.sh"
125
+ "scripts/check-exec-plan-index-sync.sh"
126
+ "scripts/check-harness-runtime-clean.sh"
127
+ "scripts/check-architecture-boundaries.sh"
128
+ "scripts/check-skill-entry.sh"
129
+ "scripts/check-repo.sh"
130
+ "scripts/ci-governance.sh"
131
+ "scripts/ci-tests.sh"
132
+ "scripts/ci.sh"
133
+ )
134
+
135
+ missing=()
136
+ for item in "\${required_paths[@]}"; do
137
+ if [[ ! -e "\${item}" ]]; then
138
+ missing+=("\${item}")
139
+ fi
140
+ done
141
+
142
+ if (( \${#missing[@]} > 0 )); then
143
+ echo "loop-agent 初始化检查失败,缺少必要路径:"
144
+ for item in "\${missing[@]}"; do
145
+ echo " - \${item}"
146
+ done
147
+ exit 1
148
+ fi
149
+
150
+ echo "loop-agent 工程结构检查通过"
151
151
  `;
152
- const INIT_CHECK_DOC_INDEX_SH = `#!/usr/bin/env bash
153
- set -euo pipefail
154
-
155
- ROOT_DIR="$(cd "$(dirname "\${BASH_SOURCE[0]}")/.." && pwd)"
156
- cd "\${ROOT_DIR}"
157
-
158
- required_docs=(
159
- "${GOVERNANCE_ROOT_TOKEN}/README.md"
160
- "${GOVERNANCE_ROOT_TOKEN}/development-principles.md"
161
- "${GOVERNANCE_ROOT_TOKEN}/feature-workflow.md"
162
- "${GOVERNANCE_ROOT_TOKEN}/verification-matrix.md"
163
- "${GOVERNANCE_ROOT_TOKEN}/architecture/runtime-boundaries.md"
164
- "${GOVERNANCE_ROOT_TOKEN}/loop-agent-harness.md"
165
- "${GOVERNANCE_ROOT_TOKEN}/harness-methodology-tdd.md"
166
- "${GOVERNANCE_ROOT_TOKEN}/harness-methodology-verification.md"
167
- "${GOVERNANCE_ROOT_TOKEN}/harness-methodology-debugging.md"
168
- "${GOVERNANCE_ROOT_TOKEN}/templates"
169
- "${GOVERNANCE_ROOT_TOKEN}/exec-plans/active/README.md"
170
- "${GOVERNANCE_ROOT_TOKEN}/exec-plans/completed/README.md"
171
- "${GOVERNANCE_ROOT_TOKEN}/progress/README.md"
172
- "${GOVERNANCE_ROOT_TOKEN}/reports/README.md"
173
- "${GOVERNANCE_ROOT_TOKEN}/decisions/README.md"
174
- )
175
-
176
- missing=()
177
- for item in "\${required_docs[@]}"; do
178
- if [[ ! -e "\${item}" ]]; then
179
- missing+=("\${item}")
180
- fi
181
- done
182
-
183
- if (( \${#missing[@]} > 0 )); then
184
- echo "docs 索引检查失败,缺少必要文档或目录:" >&2
185
- for item in "\${missing[@]}"; do
186
- echo " - \${item}" >&2
187
- done
188
- exit 1
189
- fi
190
-
191
- echo "docs 索引检查通过"
152
+ const INIT_CHECK_DOC_INDEX_SH = `#!/usr/bin/env bash
153
+ set -euo pipefail
154
+
155
+ ROOT_DIR="$(cd "$(dirname "\${BASH_SOURCE[0]}")/.." && pwd)"
156
+ cd "\${ROOT_DIR}"
157
+
158
+ required_docs=(
159
+ "${GOVERNANCE_ROOT_TOKEN}/README.md"
160
+ "${GOVERNANCE_ROOT_TOKEN}/development-principles.md"
161
+ "${GOVERNANCE_ROOT_TOKEN}/feature-workflow.md"
162
+ "${GOVERNANCE_ROOT_TOKEN}/verification-matrix.md"
163
+ "${GOVERNANCE_ROOT_TOKEN}/architecture/runtime-boundaries.md"
164
+ "${GOVERNANCE_ROOT_TOKEN}/loop-agent-harness.md"
165
+ "${GOVERNANCE_ROOT_TOKEN}/harness-methodology-tdd.md"
166
+ "${GOVERNANCE_ROOT_TOKEN}/harness-methodology-verification.md"
167
+ "${GOVERNANCE_ROOT_TOKEN}/harness-methodology-debugging.md"
168
+ "${GOVERNANCE_ROOT_TOKEN}/templates"
169
+ "${GOVERNANCE_ROOT_TOKEN}/exec-plans/active/README.md"
170
+ "${GOVERNANCE_ROOT_TOKEN}/exec-plans/completed/README.md"
171
+ "${GOVERNANCE_ROOT_TOKEN}/progress/README.md"
172
+ "${GOVERNANCE_ROOT_TOKEN}/reports/README.md"
173
+ "${GOVERNANCE_ROOT_TOKEN}/decisions/README.md"
174
+ )
175
+
176
+ missing=()
177
+ for item in "\${required_docs[@]}"; do
178
+ if [[ ! -e "\${item}" ]]; then
179
+ missing+=("\${item}")
180
+ fi
181
+ done
182
+
183
+ if (( \${#missing[@]} > 0 )); then
184
+ echo "docs 索引检查失败,缺少必要文档或目录:" >&2
185
+ for item in "\${missing[@]}"; do
186
+ echo " - \${item}" >&2
187
+ done
188
+ exit 1
189
+ fi
190
+
191
+ echo "docs 索引检查通过"
192
192
  `;
193
- const INIT_CHECK_DOC_LINKS_SH = `#!/usr/bin/env bash
194
- set -euo pipefail
195
-
196
- ROOT_DIR="$(cd "$(dirname "\${BASH_SOURCE[0]}")/.." && pwd)"
197
- cd "\${ROOT_DIR}"
198
-
199
- if [[ ! -d "${GOVERNANCE_ROOT_TOKEN}" ]]; then
200
- echo "docs 链接检查失败:缺少 ${GOVERNANCE_ROOT_TOKEN}/" >&2
201
- exit 1
202
- fi
203
-
204
- missing=()
205
- while IFS= read -r -d '' file; do
206
- while IFS= read -r link; do
207
- [[ -z "\${link}" ]] && continue
208
- [[ "\${link}" == http://* || "\${link}" == https://* || "\${link}" == mailto:* || "\${link}" == "#"* ]] && continue
209
- [[ "\${link}" == *"://"* ]] && continue
210
- target="\${link%%#*}"
211
- [[ -z "\${target}" ]] && continue
212
- [[ "\${target}" == /* ]] && continue
213
- base="$(dirname "\${file}")"
214
- if [[ ! -e "\${base}/\${target}" ]]; then
215
- missing+=("\${file}: \${link}")
216
- fi
217
- done < <(grep -Eo '\\[[^]]+\\]\\([^)]+\\)' "\${file}" | sed -E 's/^.*\\(([^)]+)\\)$/\\1/' || true)
218
- done < <(find "${GOVERNANCE_ROOT_TOKEN}" -type f -name '*.md' -print0)
219
-
220
- if (( \${#missing[@]} > 0 )); then
221
- echo "docs 链接检查失败:" >&2
222
- for item in "\${missing[@]}"; do
223
- echo " - \${item}" >&2
224
- done
225
- exit 1
226
- fi
227
-
228
- echo "docs 链接检查通过"
193
+ const INIT_CHECK_DOC_LINKS_SH = `#!/usr/bin/env bash
194
+ set -euo pipefail
195
+
196
+ ROOT_DIR="$(cd "$(dirname "\${BASH_SOURCE[0]}")/.." && pwd)"
197
+ cd "\${ROOT_DIR}"
198
+
199
+ if [[ ! -d "${GOVERNANCE_ROOT_TOKEN}" ]]; then
200
+ echo "docs 链接检查失败:缺少 ${GOVERNANCE_ROOT_TOKEN}/" >&2
201
+ exit 1
202
+ fi
203
+
204
+ missing=()
205
+ while IFS= read -r -d '' file; do
206
+ while IFS= read -r link; do
207
+ [[ -z "\${link}" ]] && continue
208
+ [[ "\${link}" == http://* || "\${link}" == https://* || "\${link}" == mailto:* || "\${link}" == "#"* ]] && continue
209
+ [[ "\${link}" == *"://"* ]] && continue
210
+ target="\${link%%#*}"
211
+ [[ -z "\${target}" ]] && continue
212
+ [[ "\${target}" == /* ]] && continue
213
+ base="$(dirname "\${file}")"
214
+ if [[ ! -e "\${base}/\${target}" ]]; then
215
+ missing+=("\${file}: \${link}")
216
+ fi
217
+ done < <(grep -Eo '\\[[^]]+\\]\\([^)]+\\)' "\${file}" | sed -E 's/^.*\\(([^)]+)\\)$/\\1/' || true)
218
+ done < <(find "${GOVERNANCE_ROOT_TOKEN}" -type f -name '*.md' -print0)
219
+
220
+ if (( \${#missing[@]} > 0 )); then
221
+ echo "docs 链接检查失败:" >&2
222
+ for item in "\${missing[@]}"; do
223
+ echo " - \${item}" >&2
224
+ done
225
+ exit 1
226
+ fi
227
+
228
+ echo "docs 链接检查通过"
229
229
  `;
230
- const INIT_CHECK_ACTIVE_PLAN_STATUS_SH = `#!/usr/bin/env bash
231
- set -euo pipefail
232
-
233
- ROOT_DIR="$(cd "$(dirname "\${BASH_SOURCE[0]}")/.." && pwd)"
234
- cd "\${ROOT_DIR}"
235
-
236
- active_dir="${GOVERNANCE_ROOT_TOKEN}/exec-plans/active"
237
- [[ -d "\${active_dir}" ]] || { echo "active plan 检查失败:缺少 \${active_dir}" >&2; exit 1; }
238
-
239
- bad=()
240
- while IFS= read -r -d '' file; do
241
- name="$(basename "\${file}")"
242
- [[ "\${name}" == "README.md" ]] && continue
243
- if grep -Eiq 'status:[[:space:]]*(completed|done|closed)|状态[::][[:space:]]*(已完成|完成|关闭)' "\${file}"; then
244
- bad+=("\${file}")
245
- fi
246
- done < <(find "\${active_dir}" -maxdepth 1 -type f -name '*.md' -print0)
247
-
248
- if (( \${#bad[@]} > 0 )); then
249
- echo "active plan 状态检查失败:已完成计划不应留在 active 目录:" >&2
250
- for item in "\${bad[@]}"; do
251
- echo " - \${item}" >&2
252
- done
253
- exit 1
254
- fi
255
-
256
- echo "active plan 状态检查通过"
230
+ const INIT_CHECK_ACTIVE_PLAN_STATUS_SH = `#!/usr/bin/env bash
231
+ set -euo pipefail
232
+
233
+ ROOT_DIR="$(cd "$(dirname "\${BASH_SOURCE[0]}")/.." && pwd)"
234
+ cd "\${ROOT_DIR}"
235
+
236
+ active_dir="${GOVERNANCE_ROOT_TOKEN}/exec-plans/active"
237
+ [[ -d "\${active_dir}" ]] || { echo "active plan 检查失败:缺少 \${active_dir}" >&2; exit 1; }
238
+
239
+ bad=()
240
+ while IFS= read -r -d '' file; do
241
+ name="$(basename "\${file}")"
242
+ [[ "\${name}" == "README.md" ]] && continue
243
+ if grep -Eiq 'status:[[:space:]]*(completed|done|closed)|状态[::][[:space:]]*(已完成|完成|关闭)' "\${file}"; then
244
+ bad+=("\${file}")
245
+ fi
246
+ done < <(find "\${active_dir}" -maxdepth 1 -type f -name '*.md' -print0)
247
+
248
+ if (( \${#bad[@]} > 0 )); then
249
+ echo "active plan 状态检查失败:已完成计划不应留在 active 目录:" >&2
250
+ for item in "\${bad[@]}"; do
251
+ echo " - \${item}" >&2
252
+ done
253
+ exit 1
254
+ fi
255
+
256
+ echo "active plan 状态检查通过"
257
257
  `;
258
- const INIT_CHECK_EXEC_PLAN_INDEX_SYNC_SH = `#!/usr/bin/env bash
259
- set -euo pipefail
260
-
261
- ROOT_DIR="$(cd "$(dirname "\${BASH_SOURCE[0]}")/.." && pwd)"
262
- cd "\${ROOT_DIR}"
263
-
264
- required=(
265
- "${GOVERNANCE_ROOT_TOKEN}/exec-plans/README.md"
266
- "${GOVERNANCE_ROOT_TOKEN}/exec-plans/active/README.md"
267
- "${GOVERNANCE_ROOT_TOKEN}/exec-plans/completed/README.md"
268
- )
269
-
270
- for item in "\${required[@]}"; do
271
- if [[ ! -f "\${item}" ]]; then
272
- echo "exec-plan 索引同步检查失败:缺少 \${item}" >&2
273
- exit 1
274
- fi
275
- done
276
-
277
- echo "exec-plan 索引同步检查通过"
258
+ const INIT_CHECK_EXEC_PLAN_INDEX_SYNC_SH = `#!/usr/bin/env bash
259
+ set -euo pipefail
260
+
261
+ ROOT_DIR="$(cd "$(dirname "\${BASH_SOURCE[0]}")/.." && pwd)"
262
+ cd "\${ROOT_DIR}"
263
+
264
+ required=(
265
+ "${GOVERNANCE_ROOT_TOKEN}/exec-plans/README.md"
266
+ "${GOVERNANCE_ROOT_TOKEN}/exec-plans/active/README.md"
267
+ "${GOVERNANCE_ROOT_TOKEN}/exec-plans/completed/README.md"
268
+ )
269
+
270
+ for item in "\${required[@]}"; do
271
+ if [[ ! -f "\${item}" ]]; then
272
+ echo "exec-plan 索引同步检查失败:缺少 \${item}" >&2
273
+ exit 1
274
+ fi
275
+ done
276
+
277
+ echo "exec-plan 索引同步检查通过"
278
278
  `;
279
- const INIT_CHECK_HARNESS_RUNTIME_CLEAN_SH = `#!/usr/bin/env bash
280
- set -euo pipefail
281
-
282
- ROOT_DIR="$(cd "$(dirname "\${BASH_SOURCE[0]}")/.." && pwd)"
283
- cd "\${ROOT_DIR}"
284
-
285
- failures=()
286
-
287
- count_entries() {
288
- local dir="$1"
289
- if [[ ! -d "\${dir}" ]]; then
290
- echo 0
291
- return
292
- fi
293
- find "\${dir}" -mindepth 1 -maxdepth 1 ! -name .gitkeep | wc -l | tr -d ' '
294
- }
295
-
296
- if [[ "\${HARNESS_ALLOW_ACTIVE_DAG_RUNS:-}" != "1" ]]; then
297
- active_dag_count="$(count_entries ".harness/dag-runs/active")"
298
- [[ "\${active_dag_count}" == "0" ]] || failures+=(".harness/dag-runs/active contains \${active_dag_count} entries")
299
- fi
300
-
301
- if [[ "\${HARNESS_ALLOW_ACTIVE_TOOL_RUNS:-\${HARNESS_ALLOW_ACTIVE_ONE_SHOT_RUNS:-}}" != "1" ]]; then
302
- active_run_count="$(count_entries ".harness/runs/active")"
303
- [[ "\${active_run_count}" == "0" ]] || failures+=(".harness/runs/active contains \${active_run_count} entries")
304
- fi
305
-
306
- if [[ -d artifacts ]]; then
307
- artifact_count="$(find artifacts -mindepth 1 -maxdepth 1 ! -name .gitkeep | wc -l | tr -d ' ')"
308
- [[ "\${artifact_count}" == "0" ]] || failures+=("root artifacts/ contains \${artifact_count} entries; use docs/reports or .harness run artifacts")
309
- fi
310
-
311
- if (( \${#failures[@]} > 0 )); then
312
- echo "[HARNESS RUNTIME DIRTY]" >&2
313
- for item in "\${failures[@]}"; do
314
- echo " - \${item}" >&2
315
- done
316
- exit 1
317
- fi
318
-
319
- echo "harness runtime clean check passed"
279
+ const INIT_CHECK_HARNESS_RUNTIME_CLEAN_SH = `#!/usr/bin/env bash
280
+ set -euo pipefail
281
+
282
+ ROOT_DIR="$(cd "$(dirname "\${BASH_SOURCE[0]}")/.." && pwd)"
283
+ cd "\${ROOT_DIR}"
284
+
285
+ failures=()
286
+
287
+ count_entries() {
288
+ local dir="$1"
289
+ if [[ ! -d "\${dir}" ]]; then
290
+ echo 0
291
+ return
292
+ fi
293
+ find "\${dir}" -mindepth 1 -maxdepth 1 ! -name .gitkeep | wc -l | tr -d ' '
294
+ }
295
+
296
+ if [[ "\${HARNESS_ALLOW_ACTIVE_DAG_RUNS:-}" != "1" ]]; then
297
+ active_dag_count="$(count_entries ".harness/dag-runs/active")"
298
+ [[ "\${active_dag_count}" == "0" ]] || failures+=(".harness/dag-runs/active contains \${active_dag_count} entries")
299
+ fi
300
+
301
+ if [[ "\${HARNESS_ALLOW_ACTIVE_TOOL_RUNS:-\${HARNESS_ALLOW_ACTIVE_ONE_SHOT_RUNS:-}}" != "1" ]]; then
302
+ active_run_count="$(count_entries ".harness/runs/active")"
303
+ [[ "\${active_run_count}" == "0" ]] || failures+=(".harness/runs/active contains \${active_run_count} entries")
304
+ fi
305
+
306
+ if [[ -d artifacts ]]; then
307
+ artifact_count="$(find artifacts -mindepth 1 -maxdepth 1 ! -name .gitkeep | wc -l | tr -d ' ')"
308
+ [[ "\${artifact_count}" == "0" ]] || failures+=("root artifacts/ contains \${artifact_count} entries; use docs/reports or .harness run artifacts")
309
+ fi
310
+
311
+ if (( \${#failures[@]} > 0 )); then
312
+ echo "[HARNESS RUNTIME DIRTY]" >&2
313
+ for item in "\${failures[@]}"; do
314
+ echo " - \${item}" >&2
315
+ done
316
+ exit 1
317
+ fi
318
+
319
+ echo "harness runtime clean check passed"
320
320
  `;
321
- const INIT_CHECK_ARCHITECTURE_BOUNDARIES_SH = `#!/usr/bin/env bash
322
- set -euo pipefail
323
-
324
- ROOT_DIR="$(cd "$(dirname "\${BASH_SOURCE[0]}")/.." && pwd)"
325
- cd "\${ROOT_DIR}"
326
-
327
- boundary_doc="${GOVERNANCE_ROOT_TOKEN}/architecture/runtime-boundaries.md"
328
- if [[ ! -f "\${boundary_doc}" ]]; then
329
- echo "architecture boundary 检查失败:缺少 \${boundary_doc}" >&2
330
- exit 1
331
- fi
332
-
333
- violations=()
334
-
335
- check_ts_import_boundary() {
336
- local from_dir="$1"
337
- local forbidden_dir="$2"
338
- local label="$3"
339
- [[ -d "\${from_dir}" && -d "\${forbidden_dir}" ]] || return 0
340
- while IFS= read -r -d '' file; do
341
- if grep -Eq "from ['\\\"][^'\\\"]*\${forbidden_dir}/|import\\(['\\\"][^'\\\"]*\${forbidden_dir}/|require\\(['\\\"][^'\\\"]*\${forbidden_dir}/" "\${file}"; then
342
- violations+=("\${label}: \${file} imports \${forbidden_dir}")
343
- fi
344
- done < <(find "\${from_dir}" -type f \\( -name '*.ts' -o -name '*.tsx' -o -name '*.js' -o -name '*.jsx' -o -name '*.mjs' -o -name '*.cjs' \\) -print0)
345
- }
346
-
347
- # These checks are intentionally optional and stack-agnostic. They activate only
348
- # when a target repository has recognizable source directories.
349
- check_ts_import_boundary "src/workflows" "src/commands" "workflow-runtime"
350
- check_ts_import_boundary "src/executors" "src/commands" "executors"
351
- check_ts_import_boundary "src/domain" "src/infrastructure" "domain"
352
-
353
- if (( \${#violations[@]} > 0 )); then
354
- echo "architecture boundary 检查失败:" >&2
355
- for item in "\${violations[@]}"; do
356
- echo " - \${item}" >&2
357
- done
358
- echo "请更新 \${boundary_doc} 中的层边界,或修正反向依赖。" >&2
359
- exit 1
360
- fi
361
-
362
- echo "architecture boundary 检查通过"
321
+ const INIT_CHECK_ARCHITECTURE_BOUNDARIES_SH = `#!/usr/bin/env bash
322
+ set -euo pipefail
323
+
324
+ ROOT_DIR="$(cd "$(dirname "\${BASH_SOURCE[0]}")/.." && pwd)"
325
+ cd "\${ROOT_DIR}"
326
+
327
+ boundary_doc="${GOVERNANCE_ROOT_TOKEN}/architecture/runtime-boundaries.md"
328
+ if [[ ! -f "\${boundary_doc}" ]]; then
329
+ echo "architecture boundary 检查失败:缺少 \${boundary_doc}" >&2
330
+ exit 1
331
+ fi
332
+
333
+ violations=()
334
+
335
+ check_ts_import_boundary() {
336
+ local from_dir="$1"
337
+ local forbidden_dir="$2"
338
+ local label="$3"
339
+ [[ -d "\${from_dir}" && -d "\${forbidden_dir}" ]] || return 0
340
+ while IFS= read -r -d '' file; do
341
+ if grep -Eq "from ['\\\"][^'\\\"]*\${forbidden_dir}/|import\\(['\\\"][^'\\\"]*\${forbidden_dir}/|require\\(['\\\"][^'\\\"]*\${forbidden_dir}/" "\${file}"; then
342
+ violations+=("\${label}: \${file} imports \${forbidden_dir}")
343
+ fi
344
+ done < <(find "\${from_dir}" -type f \\( -name '*.ts' -o -name '*.tsx' -o -name '*.js' -o -name '*.jsx' -o -name '*.mjs' -o -name '*.cjs' \\) -print0)
345
+ }
346
+
347
+ # These checks are intentionally optional and stack-agnostic. They activate only
348
+ # when a target repository has recognizable source directories.
349
+ check_ts_import_boundary "src/workflows" "src/commands" "workflow-runtime"
350
+ check_ts_import_boundary "src/executors" "src/commands" "executors"
351
+ check_ts_import_boundary "src/domain" "src/infrastructure" "domain"
352
+
353
+ if (( \${#violations[@]} > 0 )); then
354
+ echo "architecture boundary 检查失败:" >&2
355
+ for item in "\${violations[@]}"; do
356
+ echo " - \${item}" >&2
357
+ done
358
+ echo "请更新 \${boundary_doc} 中的层边界,或修正反向依赖。" >&2
359
+ exit 1
360
+ fi
361
+
362
+ echo "architecture boundary 检查通过"
363
363
  `;
364
- const INIT_CHECK_SKILL_ENTRY_SH = `#!/usr/bin/env bash
365
- set -euo pipefail
366
-
367
- ROOT_DIR="$(cd "$(dirname "\${BASH_SOURCE[0]}")/.." && pwd)"
368
- cd "\${ROOT_DIR}"
369
-
370
- skill_md="skills/loop-agent/SKILL.md"
371
- if [[ ! -f "\${skill_md}" ]]; then
372
- echo "skill entry 检查失败:缺少 \${skill_md}" >&2
373
- exit 1
374
- fi
375
-
376
- required_refs=(
377
- "references/harness-policy.md"
378
- "references/hybrid-dag.md"
379
- "references/verification-and-failure-handling.md"
380
- "references/command-reference.md"
381
- )
382
-
383
- missing=()
384
- for ref in "\${required_refs[@]}"; do
385
- [[ -f "skills/loop-agent/\${ref}" ]] || missing+=("\${ref}")
386
- done
387
-
388
- while IFS= read -r ref; do
389
- [[ -z "\${ref}" ]] && continue
390
- [[ -f "skills/loop-agent/\${ref}" ]] || missing+=("\${ref}")
391
- done < <(grep -Eo 'references/[A-Za-z0-9._/-]+\\.md' "\${skill_md}" | sort -u || true)
392
-
393
- if (( \${#missing[@]} > 0 )); then
394
- echo "skill entry 检查失败:引用的 reference 文件不存在:" >&2
395
- printf ' - %s\\n' "\${missing[@]}" >&2
396
- exit 1
397
- fi
398
-
399
- line_count="$(wc -l < "\${skill_md}" | tr -d ' ')"
400
- if [[ "\${line_count}" =~ ^[0-9]+$ && "\${line_count}" -gt 220 ]]; then
401
- echo "skill entry 检查警告:\${skill_md} 行数为 \${line_count},建议保持入口精简并把细节放入 references/" >&2
402
- fi
403
-
404
- echo "skill entry 检查通过:references ok, lines=\${line_count}"
364
+ const INIT_CHECK_SKILL_ENTRY_SH = `#!/usr/bin/env bash
365
+ set -euo pipefail
366
+
367
+ ROOT_DIR="$(cd "$(dirname "\${BASH_SOURCE[0]}")/.." && pwd)"
368
+ cd "\${ROOT_DIR}"
369
+
370
+ skill_md="skills/loop-agent/SKILL.md"
371
+ if [[ ! -f "\${skill_md}" ]]; then
372
+ echo "skill entry 检查失败:缺少 \${skill_md}" >&2
373
+ exit 1
374
+ fi
375
+
376
+ required_refs=(
377
+ "references/harness-policy.md"
378
+ "references/hybrid-dag.md"
379
+ "references/verification-and-failure-handling.md"
380
+ "references/command-reference.md"
381
+ )
382
+
383
+ missing=()
384
+ for ref in "\${required_refs[@]}"; do
385
+ [[ -f "skills/loop-agent/\${ref}" ]] || missing+=("\${ref}")
386
+ done
387
+
388
+ while IFS= read -r ref; do
389
+ [[ -z "\${ref}" ]] && continue
390
+ [[ -f "skills/loop-agent/\${ref}" ]] || missing+=("\${ref}")
391
+ done < <(grep -Eo 'references/[A-Za-z0-9._/-]+\\.md' "\${skill_md}" | sort -u || true)
392
+
393
+ if (( \${#missing[@]} > 0 )); then
394
+ echo "skill entry 检查失败:引用的 reference 文件不存在:" >&2
395
+ printf ' - %s\\n' "\${missing[@]}" >&2
396
+ exit 1
397
+ fi
398
+
399
+ line_count="$(wc -l < "\${skill_md}" | tr -d ' ')"
400
+ if [[ "\${line_count}" =~ ^[0-9]+$ && "\${line_count}" -gt 220 ]]; then
401
+ echo "skill entry 检查警告:\${skill_md} 行数为 \${line_count},建议保持入口精简并把细节放入 references/" >&2
402
+ fi
403
+
404
+ echo "skill entry 检查通过:references ok, lines=\${line_count}"
405
405
  `;
406
- const INIT_CHECK_REPO_SH = `#!/usr/bin/env bash
407
- set -euo pipefail
408
-
409
- ROOT_DIR="$(cd "$(dirname "\${BASH_SOURCE[0]}")/.." && pwd)"
410
- cd "\${ROOT_DIR}"
411
-
412
- checks=(
413
- "scripts/check-engineering-structure.sh"
414
- "scripts/check-doc-index.sh"
415
- "scripts/check-doc-links.sh"
416
- "scripts/check-active-plan-status.sh"
417
- "scripts/check-exec-plan-index-sync.sh"
418
- "scripts/check-harness-runtime-clean.sh"
419
- "scripts/check-architecture-boundaries.sh"
420
- "scripts/check-skill-entry.sh"
421
- "scripts/check-product-line-docs.sh"
422
- )
423
-
424
- for check in "\${checks[@]}"; do
425
- echo "==> bash \${check}"
426
- bash "\${check}"
427
- echo
428
- done
429
-
430
- echo "仓库治理检查全部通过"
406
+ const INIT_CHECK_REPO_SH = `#!/usr/bin/env bash
407
+ set -euo pipefail
408
+
409
+ ROOT_DIR="$(cd "$(dirname "\${BASH_SOURCE[0]}")/.." && pwd)"
410
+ cd "\${ROOT_DIR}"
411
+
412
+ checks=(
413
+ "scripts/check-engineering-structure.sh"
414
+ "scripts/check-doc-index.sh"
415
+ "scripts/check-doc-links.sh"
416
+ "scripts/check-active-plan-status.sh"
417
+ "scripts/check-exec-plan-index-sync.sh"
418
+ "scripts/check-harness-runtime-clean.sh"
419
+ "scripts/check-architecture-boundaries.sh"
420
+ "scripts/check-skill-entry.sh"
421
+ "scripts/check-product-line-docs.sh"
422
+ )
423
+
424
+ for check in "\${checks[@]}"; do
425
+ echo "==> bash \${check}"
426
+ bash "\${check}"
427
+ echo
428
+ done
429
+
430
+ echo "仓库治理检查全部通过"
431
431
  `;
432
- const INIT_CHECK_PRODUCT_LINE_DOCS_SH = `#!/usr/bin/env bash
433
- set -euo pipefail
434
-
435
- ROOT_DIR="$(cd "$(dirname "\${BASH_SOURCE[0]}")/.." && pwd)"
436
- cd "\${ROOT_DIR}"
437
-
438
- if ! command -v agent-worker >/dev/null 2>&1; then
439
- echo "product-line docs check skipped: agent-worker is not installed"
440
- exit 0
441
- fi
442
-
443
- feature_dirs=()
444
- for root in features product/features dogfood/features; do
445
- [[ -d "\${root}" ]] || continue
446
- while IFS= read -r acceptance; do
447
- feature_dirs+=("$(dirname "\${acceptance}")")
448
- done < <(find "\${root}" -mindepth 2 -maxdepth 2 -name acceptance.yaml -type f | sort)
449
- done
450
-
451
- for feature_dir in "\${feature_dirs[@]}"; do
452
- echo "==> validate product-line feature: \${feature_dir}"
453
- agent-worker task validate-feature "\${feature_dir}"
454
- done
455
-
456
- echo "product-line docs checks passed: \${#feature_dirs[@]} feature packet(s)"
432
+ const INIT_CHECK_PRODUCT_LINE_DOCS_SH = `#!/usr/bin/env bash
433
+ set -euo pipefail
434
+
435
+ ROOT_DIR="$(cd "$(dirname "\${BASH_SOURCE[0]}")/.." && pwd)"
436
+ cd "\${ROOT_DIR}"
437
+
438
+ if ! command -v agent-worker >/dev/null 2>&1; then
439
+ echo "product-line docs check skipped: agent-worker is not installed"
440
+ exit 0
441
+ fi
442
+
443
+ feature_dirs=()
444
+ for root in features product/features dogfood/features; do
445
+ [[ -d "\${root}" ]] || continue
446
+ while IFS= read -r acceptance; do
447
+ feature_dirs+=("$(dirname "\${acceptance}")")
448
+ done < <(find "\${root}" -mindepth 2 -maxdepth 2 -name acceptance.yaml -type f | sort)
449
+ done
450
+
451
+ for feature_dir in "\${feature_dirs[@]}"; do
452
+ echo "==> validate product-line feature: \${feature_dir}"
453
+ agent-worker task validate-feature "\${feature_dir}"
454
+ done
455
+
456
+ echo "product-line docs checks passed: \${#feature_dirs[@]} feature packet(s)"
457
457
  `;
458
- const INIT_CI_GOVERNANCE_SH = `#!/usr/bin/env bash
459
- set -euo pipefail
460
-
461
- ROOT_DIR="$(cd "$(dirname "\${BASH_SOURCE[0]}")/.." && pwd)"
462
- cd "\${ROOT_DIR}"
463
-
464
- bash scripts/check-repo.sh
458
+ const INIT_CI_GOVERNANCE_SH = `#!/usr/bin/env bash
459
+ set -euo pipefail
460
+
461
+ ROOT_DIR="$(cd "$(dirname "\${BASH_SOURCE[0]}")/.." && pwd)"
462
+ cd "\${ROOT_DIR}"
463
+
464
+ bash scripts/check-repo.sh
465
465
  `;
466
- const INIT_CI_TESTS_SH = `#!/usr/bin/env bash
467
- set -euo pipefail
468
-
469
- ROOT_DIR="$(cd "$(dirname "\${BASH_SOURCE[0]}")/.." && pwd)"
470
- cd "\${ROOT_DIR}"
471
-
472
- ran=0
473
- notes=()
474
-
475
- run_cmd() {
476
- echo "==> $*"
477
- "$@"
478
- ran=1
479
- }
480
-
481
- run_bash() {
482
- echo "==> $*"
483
- bash -lc "$*"
484
- ran=1
485
- }
486
-
487
- has_make_target() {
488
- local target="$1"
489
- [[ -f Makefile || -f makefile ]] || return 1
490
- grep -Eq "^[[:alnum:]_.-]*\${target}[[:alnum:]_.-]*:" Makefile makefile 2>/dev/null
491
- }
492
-
493
- has_npm_script() {
494
- local script="$1"
495
- [[ -f package.json ]] || return 1
496
- command -v node >/dev/null 2>&1 || return 1
497
- 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
498
- }
499
-
500
- if [[ -f package.json ]]; then
501
- if command -v npm >/dev/null 2>&1; then
502
- for script in lint typecheck test build; do
503
- if has_npm_script "\${script}"; then
504
- run_cmd npm run "\${script}"
505
- fi
506
- done
507
- else
508
- notes+=("package.json exists but npm is not available")
509
- fi
510
- fi
511
-
512
- if has_make_target verify; then
513
- run_cmd make verify
514
- elif has_make_target test; then
515
- run_cmd make test
516
- fi
517
-
518
- if [[ -f go.mod ]]; then
519
- if command -v go >/dev/null 2>&1; then
520
- run_cmd go test ./...
521
- else
522
- notes+=("go.mod exists but go is not available")
523
- fi
524
- fi
525
-
526
- if [[ -f Cargo.toml ]]; then
527
- if command -v cargo >/dev/null 2>&1; then
528
- run_cmd cargo test
529
- else
530
- notes+=("Cargo.toml exists but cargo is not available")
531
- fi
532
- fi
533
-
534
- if [[ -f pyproject.toml || -f pytest.ini || -f tox.ini ]]; then
535
- if command -v pytest >/dev/null 2>&1; then
536
- run_cmd pytest
537
- elif command -v tox >/dev/null 2>&1 && [[ -f tox.ini ]]; then
538
- run_cmd tox
539
- else
540
- notes+=("Python project metadata found but pytest/tox is not available")
541
- fi
542
- fi
543
-
544
- if [[ -f pom.xml ]]; then
545
- if command -v mvn >/dev/null 2>&1; then
546
- run_cmd mvn test
547
- else
548
- notes+=("pom.xml exists but mvn is not available")
549
- fi
550
- fi
551
-
552
- if [[ -f build.gradle || -f build.gradle.kts || -f settings.gradle || -f settings.gradle.kts ]]; then
553
- if [[ -x ./gradlew ]]; then
554
- run_cmd ./gradlew test
555
- elif command -v gradle >/dev/null 2>&1; then
556
- run_cmd gradle test
557
- else
558
- notes+=("Gradle project metadata found but gradle/gradlew is not available")
559
- fi
560
- fi
561
-
562
- if compgen -G "*.sln" >/dev/null || compgen -G "*.csproj" >/dev/null; then
563
- if command -v dotnet >/dev/null 2>&1; then
564
- run_cmd dotnet test
565
- else
566
- notes+=(".NET project metadata found but dotnet is not available")
567
- fi
568
- fi
569
-
570
- if (( ran == 0 )); then
571
- echo "未检测到可安全自动运行的项目测试入口。"
572
- echo "loop-agent 治理检查仍可运行;请让初始化模型根据目标项目技术栈补充 scripts/ci-tests.sh 与 docs/verification-matrix.md。"
573
- fi
574
-
575
- if (( \${#notes[@]} > 0 )); then
576
- echo "项目验证探测备注:"
577
- for note in "\${notes[@]}"; do
578
- echo " - \${note}"
579
- done
580
- fi
466
+ const INIT_CI_TESTS_SH = `#!/usr/bin/env bash
467
+ set -euo pipefail
468
+
469
+ ROOT_DIR="$(cd "$(dirname "\${BASH_SOURCE[0]}")/.." && pwd)"
470
+ cd "\${ROOT_DIR}"
471
+
472
+ ran=0
473
+ notes=()
474
+
475
+ run_cmd() {
476
+ echo "==> $*"
477
+ "$@"
478
+ ran=1
479
+ }
480
+
481
+ run_bash() {
482
+ echo "==> $*"
483
+ bash -lc "$*"
484
+ ran=1
485
+ }
486
+
487
+ has_make_target() {
488
+ local target="$1"
489
+ [[ -f Makefile || -f makefile ]] || return 1
490
+ grep -Eq "^[[:alnum:]_.-]*\${target}[[:alnum:]_.-]*:" Makefile makefile 2>/dev/null
491
+ }
492
+
493
+ has_npm_script() {
494
+ local script="$1"
495
+ [[ -f package.json ]] || return 1
496
+ command -v node >/dev/null 2>&1 || return 1
497
+ 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
498
+ }
499
+
500
+ if [[ -f package.json ]]; then
501
+ if command -v npm >/dev/null 2>&1; then
502
+ for script in lint typecheck test build; do
503
+ if has_npm_script "\${script}"; then
504
+ run_cmd npm run "\${script}"
505
+ fi
506
+ done
507
+ else
508
+ notes+=("package.json exists but npm is not available")
509
+ fi
510
+ fi
511
+
512
+ if has_make_target verify; then
513
+ run_cmd make verify
514
+ elif has_make_target test; then
515
+ run_cmd make test
516
+ fi
517
+
518
+ if [[ -f go.mod ]]; then
519
+ if command -v go >/dev/null 2>&1; then
520
+ run_cmd go test ./...
521
+ else
522
+ notes+=("go.mod exists but go is not available")
523
+ fi
524
+ fi
525
+
526
+ if [[ -f Cargo.toml ]]; then
527
+ if command -v cargo >/dev/null 2>&1; then
528
+ run_cmd cargo test
529
+ else
530
+ notes+=("Cargo.toml exists but cargo is not available")
531
+ fi
532
+ fi
533
+
534
+ if [[ -f pyproject.toml || -f pytest.ini || -f tox.ini ]]; then
535
+ if command -v pytest >/dev/null 2>&1; then
536
+ run_cmd pytest
537
+ elif command -v tox >/dev/null 2>&1 && [[ -f tox.ini ]]; then
538
+ run_cmd tox
539
+ else
540
+ notes+=("Python project metadata found but pytest/tox is not available")
541
+ fi
542
+ fi
543
+
544
+ if [[ -f pom.xml ]]; then
545
+ if command -v mvn >/dev/null 2>&1; then
546
+ run_cmd mvn test
547
+ else
548
+ notes+=("pom.xml exists but mvn is not available")
549
+ fi
550
+ fi
551
+
552
+ if [[ -f build.gradle || -f build.gradle.kts || -f settings.gradle || -f settings.gradle.kts ]]; then
553
+ if [[ -x ./gradlew ]]; then
554
+ run_cmd ./gradlew test
555
+ elif command -v gradle >/dev/null 2>&1; then
556
+ run_cmd gradle test
557
+ else
558
+ notes+=("Gradle project metadata found but gradle/gradlew is not available")
559
+ fi
560
+ fi
561
+
562
+ if compgen -G "*.sln" >/dev/null || compgen -G "*.csproj" >/dev/null; then
563
+ if command -v dotnet >/dev/null 2>&1; then
564
+ run_cmd dotnet test
565
+ else
566
+ notes+=(".NET project metadata found but dotnet is not available")
567
+ fi
568
+ fi
569
+
570
+ if (( ran == 0 )); then
571
+ echo "未检测到可安全自动运行的项目测试入口。"
572
+ echo "loop-agent 治理检查仍可运行;请让初始化模型根据目标项目技术栈补充 scripts/ci-tests.sh 与 docs/verification-matrix.md。"
573
+ fi
574
+
575
+ if (( \${#notes[@]} > 0 )); then
576
+ echo "项目验证探测备注:"
577
+ for note in "\${notes[@]}"; do
578
+ echo " - \${note}"
579
+ done
580
+ fi
581
581
  `;
582
- const INIT_CI_SH = `#!/usr/bin/env bash
583
- set -euo pipefail
584
-
585
- ROOT_DIR="$(cd "$(dirname "\${BASH_SOURCE[0]}")/.." && pwd)"
586
- cd "\${ROOT_DIR}"
587
-
588
- bash scripts/ci-governance.sh
589
- bash scripts/ci-tests.sh
582
+ const INIT_CI_SH = `#!/usr/bin/env bash
583
+ set -euo pipefail
584
+
585
+ ROOT_DIR="$(cd "$(dirname "\${BASH_SOURCE[0]}")/.." && pwd)"
586
+ cd "\${ROOT_DIR}"
587
+
588
+ bash scripts/ci-governance.sh
589
+ bash scripts/ci-tests.sh
590
590
  `;
591
591
  const INIT_SCRIPT_FILES = {
592
592
  "scripts/check-engineering-structure.sh": INIT_CHECK_ENGINEERING_STRUCTURE_SH,
@@ -789,6 +789,7 @@ export function buildManagedGitignoreBlock() {
789
789
  ".harness/init-surface.json",
790
790
  "",
791
791
  "# worker task pool",
792
+ ".harness/task-pool/*",
792
793
  ".task-pool/",
793
794
  "",
794
795
  "# multi-worktree parallel mode",
@@ -833,6 +834,7 @@ function buildHarness(input) {
833
834
  }
834
835
  const harness = {
835
836
  ...input.existing,
837
+ $schema: expectedHarnessSchemaRef(input.governanceRoot),
836
838
  version: 1,
837
839
  project: input.projectName,
838
840
  adapter: "loop-agent",
@@ -854,7 +856,7 @@ function buildHarness(input) {
854
856
  progressDir: `${input.governanceRoot}/progress`,
855
857
  reportsDir: `${input.governanceRoot}/reports`,
856
858
  decisionsDir: `${input.governanceRoot}/decisions`,
857
- taskPoolDir: ".task-pool",
859
+ taskPoolDir: ".harness/task-pool",
858
860
  }),
859
861
  scripts: mergeRecord(input.existing.scripts, {
860
862
  checkEngineeringStructure: "scripts/check-engineering-structure.sh",
@@ -981,6 +983,9 @@ function isRecord(value) {
981
983
  function normalizeRelativePath(relativePath) {
982
984
  return relativePath.split(path.sep).join("/");
983
985
  }
986
+ function expectedHarnessSchemaRef(governanceRoot) {
987
+ return `./${governanceRoot}/templates/harness.schema.json`;
988
+ }
984
989
  function manifestPathToTargetPath(relativePath, governanceRoot) {
985
990
  if (governanceRoot !== "docs" && relativePath.startsWith("docs/")) {
986
991
  return `${governanceRoot}/${relativePath.slice("docs/".length)}`;
@@ -1386,7 +1391,7 @@ function buildTargetRuntimeBoundaries(input) {
1386
1391
  "- Application / Use-case layer 可以依赖 Domain / Workflow、Infrastructure 和 Integrations。",
1387
1392
  "- Domain / Workflow layer 不应依赖 Entry layer 的格式化、argv、HTTP/UI 细节。",
1388
1393
  "- Executors / Integrations 不应依赖 Entry layer 的输出格式。",
1389
- "- Worker adapter 应把 `.task-pool/` 作为独立运行事实区;它通过 CLI/subprocess contract 调用 loop-agent,不能复制或直接耦合 target command/application 实现。",
1394
+ "- Worker adapter 应把 `.harness/task-pool/` 作为独立运行事实区;它通过 CLI/subprocess contract 调用 loop-agent,不能复制或直接耦合 target command/application 实现。",
1390
1395
  "- Infrastructure / Store 应集中副作用,不把 raw path mutation 或持久化细节扩散给上层。",
1391
1396
  "",
1392
1397
  "## 目标项目适配",
@@ -1528,7 +1533,7 @@ function buildTargetLoopAgentHarness(input) {
1528
1533
  "- `.harness/tasks/` stores task state and source materials.",
1529
1534
  "- `.harness/dag-runs/` stores DAG run facts.",
1530
1535
  "- `.harness/runs/` stores one-shot executor facts.",
1531
- "- `.task-pool/` stores optional agent-worker Task Pool state, batch artifacts, failure handoffs, and local Observe events; it is runtime state and normally ignored by Git.",
1536
+ "- `.harness/task-pool/` stores optional agent-worker Task Pool state, batch artifacts, failure handoffs, and local Observe events; it is runtime state and normally ignored by Git.",
1532
1537
  "- `docs/` stores durable governance, plans, reports, progress, and decisions.",
1533
1538
  "- `skills/` stores repo-local skill instructions; the CLI can fall back to bundled skills when needed.",
1534
1539
  "",
@@ -1612,7 +1617,7 @@ export function buildInitInstructions(input) {
1612
1617
  "- Enrich the root `README.md`: keep the deterministic project title and the loop-agent managed block intact, and fill the human-authored sections (项目概览, 技术栈与目录结构, 开发与验证) from the target project's actual files. The root README must serve both as a human-first project entry and as an agent work entry; replace the initialization-model supplement comments when the project files provide the information.",
1613
1618
  "- Populate `docs/verification-matrix.md` with the target project's actual quick, standard, and full verification commands derived from its real language and toolchain, keeping the governance rows intact.",
1614
1619
  "- Copy repo-local skills by default so the target repo has auditable skill instructions; full profile also mirrors skills into `.agents/skills/` for external agents.",
1615
- "- Merge a loop-agent managed block into `.gitignore` that ignores harness runtime facts (tasks, dag-runs, runs, live, cache, init-surface.json, .task-pool) while keeping prompts and directory placeholders shareable.",
1620
+ "- Merge a loop-agent managed block into `.gitignore` that ignores harness runtime facts (tasks, dag-runs, runs, live, cache, init-surface.json, .harness/task-pool, legacy .task-pool residue) while keeping prompts and directory placeholders shareable.",
1616
1621
  "- Do not copy examples by default; examples stay bundled in the tool and are available through `loop-agent examples`.",
1617
1622
  "- Add or update a loop-agent managed block in AGENTS.md.",
1618
1623
  "- The generated AGENTS.md must include documentation convergence and structured DAG write-boundary rules so target projects keep the same working discipline as this repository.",
@@ -1916,6 +1921,15 @@ export async function checkInitUpdate(input) {
1916
1921
  if (await exists(harnessPath)) {
1917
1922
  try {
1918
1923
  const harness = JSON.parse(await readFile(harnessPath, "utf-8"));
1924
+ if (recordedState &&
1925
+ isRecord(harness) &&
1926
+ harness.$schema !== expectedHarnessSchemaRef(governanceRoot)) {
1927
+ deterministicActions.push({
1928
+ type: "add-harness-schema-ref",
1929
+ path: "harness.json",
1930
+ reason: "harness.json is missing or has a stale IDE JSON Schema reference",
1931
+ });
1932
+ }
1919
1933
  if (isRecord(harness) &&
1920
1934
  isRecord(harness.executors) &&
1921
1935
  isRecord(harness.executors.pi) &&
@@ -1954,6 +1968,22 @@ export async function checkInitUpdate(input) {
1954
1968
  };
1955
1969
  }
1956
1970
  async function applySafeAction(input) {
1971
+ if (input.action.type === "add-harness-schema-ref") {
1972
+ const target = path.join(input.repoRoot, "harness.json");
1973
+ if (!(await exists(target)))
1974
+ return false;
1975
+ const harness = JSON.parse(await readFile(target, "utf-8"));
1976
+ if (!isRecord(harness))
1977
+ return false;
1978
+ if (harness.$schema === expectedHarnessSchemaRef(input.governanceRoot))
1979
+ return false;
1980
+ const next = {
1981
+ ...harness,
1982
+ $schema: expectedHarnessSchemaRef(input.governanceRoot),
1983
+ };
1984
+ await writeFile(target, `${JSON.stringify(next, null, 2)}\n`, "utf-8");
1985
+ return true;
1986
+ }
1957
1987
  if (input.action.type === "strip-pi-requires-api-key") {
1958
1988
  const target = path.join(input.repoRoot, "harness.json");
1959
1989
  if (!(await exists(target)))
@@ -2046,7 +2076,7 @@ export async function applyInitUpdate(input) {
2046
2076
  skipped.push(action);
2047
2077
  continue;
2048
2078
  }
2049
- if (action.type !== "strip-pi-requires-api-key") {
2079
+ if (action.type !== "strip-pi-requires-api-key" && action.type !== "add-harness-schema-ref") {
2050
2080
  const currentState = await buildCurrentSurfaceState({
2051
2081
  repoRoot,
2052
2082
  projectName,