@tea-agent/loop-agent 0.3.0 → 0.4.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 (119) hide show
  1. package/AGENTS.md +135 -133
  2. package/CHANGELOG.md +88 -63
  3. package/README.md +171 -168
  4. package/bin/agent-worker.js +22 -0
  5. package/bin/loop-agent.js +21 -21
  6. package/dist/commands/init.js +457 -457
  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/executors/dag-pi-executor.js +8 -1
  11. package/dist/task/runtime.js +27 -27
  12. package/dist/worker/cli.js +119 -0
  13. package/dist/worker/loop-agent/command-result.js +1 -0
  14. package/dist/worker/loop-agent/loop-agent-client.js +105 -0
  15. package/dist/worker/loop-agent/parse-json.js +14 -0
  16. package/dist/worker/materialize/harness-task-materializer.js +157 -0
  17. package/dist/worker/pool/failure-routing.js +98 -0
  18. package/dist/worker/pool/run-store.js +117 -0
  19. package/dist/worker/pool/types.js +1 -0
  20. package/dist/worker/preflight.js +108 -0
  21. package/dist/worker/profile-mapping.js +76 -0
  22. package/dist/worker/progress-reporter.js +81 -0
  23. package/dist/worker/report/morning-report.js +69 -0
  24. package/dist/worker/repos/repo-resolver.js +23 -0
  25. package/dist/worker/run-task/run-task.js +359 -0
  26. package/dist/worker/runner/run-ready.js +216 -0
  27. package/dist/worker/task-graph/acceptance-schema.js +25 -0
  28. package/dist/worker/task-graph/ready-queue.js +23 -0
  29. package/dist/worker/task-graph/task-graph-schema.js +28 -0
  30. package/dist/worker/task-graph/types.js +1 -0
  31. package/dist/worker/task-graph/validate.js +188 -0
  32. package/dist/worker/task-spec/complexity-mapping.js +8 -0
  33. package/dist/worker/task-spec/schema.js +116 -0
  34. package/dist/worker/task-spec/types.js +1 -0
  35. package/dist/worker/task-spec/validate.js +352 -0
  36. package/dist/workflows/dag/canvas-observer.js +275 -275
  37. package/docs/README.md +65 -61
  38. package/docs/agent-dag-recovery-playbook.md +184 -184
  39. package/docs/agent-dag-runner.md +42 -42
  40. package/docs/architecture/runtime-boundaries.md +147 -147
  41. package/docs/cursor-executor-usage.md +25 -25
  42. package/docs/decisions/README.md +3 -3
  43. package/docs/design/README.md +36 -36
  44. package/docs/development-principles.md +73 -71
  45. package/docs/dynamic-workflow-dag-engine-roadmap.md +1749 -1749
  46. package/docs/exec-plans/README.md +6 -6
  47. package/docs/exec-plans/active/README.md +7 -7
  48. package/docs/exec-plans/completed/README.md +19 -11
  49. package/docs/feature-workflow.md +186 -186
  50. package/docs/harness-methodology-debugging.md +153 -153
  51. package/docs/harness-methodology-tdd.md +130 -130
  52. package/docs/harness-methodology-verification.md +27 -27
  53. package/docs/loop-agent-harness.md +42 -42
  54. package/docs/production-readiness.md +96 -96
  55. package/docs/progress/README.md +3 -3
  56. package/docs/reports/README.md +5 -5
  57. package/docs/skills/README.md +6 -6
  58. package/docs/skills/vetted-skill-registry.md +22 -22
  59. package/docs/templates/adr.md +60 -60
  60. package/docs/templates/agent-dag-authority-surface-audit.prompt.md +94 -94
  61. package/docs/templates/agent-dag-decision-envelope.schema.json +213 -213
  62. package/docs/templates/agent-dag-decision-gate-dogfood-report.md +117 -117
  63. package/docs/templates/agent-dag-decision-gate.prompt.md +246 -246
  64. package/docs/templates/agent-dag-process-supervisor.prompt.md +98 -98
  65. package/docs/templates/agent-dag-report.schema.json +454 -454
  66. package/docs/templates/agent-dag-review-verdict.prompt.md +68 -68
  67. package/docs/templates/agent-dag.base.json +195 -195
  68. package/docs/templates/agent-dag.final-verification.json +190 -190
  69. package/docs/templates/agent-dag.schema.json +316 -316
  70. package/docs/templates/agent-dag.supervised-implementation.json +500 -500
  71. package/docs/templates/exec-plan.md +64 -64
  72. package/docs/templates/feature-spec.md +53 -53
  73. package/docs/templates/hybrid-dag.json +193 -193
  74. package/docs/templates/production-readiness-checklist.md +57 -57
  75. package/docs/templates/progress-log.md +17 -17
  76. package/docs/templates/project-start-checklist.md +9 -9
  77. package/docs/templates/qa-report.md +48 -48
  78. package/docs/templates/sprint-contract.md +29 -29
  79. package/docs/verification-matrix.md +41 -41
  80. package/examples/decision-gate-agent-dag.json +123 -123
  81. package/examples/example-dag.json +51 -51
  82. package/examples/hybrid-loop-agent-dag.json +194 -194
  83. package/harness.json +89 -89
  84. package/package.json +60 -58
  85. package/skills/ai-engineering-context/SKILL.md +48 -48
  86. package/skills/code-review-core/SKILL.md +20 -20
  87. package/skills/codebase-scout/SKILL.md +19 -19
  88. package/skills/loop-agent/SKILL.md +147 -145
  89. package/skills/loop-agent/references/README.md +67 -67
  90. package/skills/loop-agent/references/command-reference.md +368 -340
  91. package/skills/loop-agent/references/harness-policy.md +259 -258
  92. package/skills/loop-agent/references/hybrid-dag.md +216 -216
  93. package/skills/loop-agent/references/learned/README.md +21 -21
  94. package/skills/loop-agent/references/long-running-loop.md +59 -59
  95. package/skills/loop-agent/references/model-routing.md +36 -36
  96. package/skills/loop-agent/references/multi-worktree.md +54 -54
  97. package/skills/loop-agent/references/one-shot-runs.md +85 -85
  98. package/skills/loop-agent/references/orchestrator-and-interventions.md +169 -169
  99. package/skills/loop-agent/references/pi-prompt.md +23 -23
  100. package/skills/loop-agent/references/pi-subagent-assisted-mode.md +81 -81
  101. package/skills/loop-agent/references/post-implementation-and-patterns.md +44 -44
  102. package/skills/loop-agent/references/task-workflow.md +84 -84
  103. package/skills/loop-agent/references/verification-and-failure-handling.md +128 -128
  104. package/skills/requesting-code-review/SKILL.md +101 -101
  105. package/skills/requesting-code-review/code-reviewer.md +168 -168
  106. package/skills/systematic-debugging/CREATION-LOG.md +119 -119
  107. package/skills/systematic-debugging/SKILL.md +296 -296
  108. package/skills/systematic-debugging/condition-based-waiting-example.ts +158 -158
  109. package/skills/systematic-debugging/condition-based-waiting.md +115 -115
  110. package/skills/systematic-debugging/defense-in-depth.md +122 -122
  111. package/skills/systematic-debugging/find-polluter.sh +63 -63
  112. package/skills/systematic-debugging/root-cause-tracing.md +169 -169
  113. package/skills/systematic-debugging/test-academic.md +14 -14
  114. package/skills/systematic-debugging/test-pressure-1.md +58 -58
  115. package/skills/systematic-debugging/test-pressure-2.md +68 -68
  116. package/skills/systematic-debugging/test-pressure-3.md +69 -69
  117. package/skills/test-driven-development/SKILL.md +20 -20
  118. package/skills/verification-before-completion/SKILL.md +154 -154
  119. package/skills/webapp-testing/SKILL.md +19 -19
@@ -90,474 +90,474 @@ const COMPAT_PROMPTS = {
90
90
  ].join("\n"),
91
91
  };
92
92
  const GOVERNANCE_ROOT_TOKEN = "__LOOP_AGENT_GOVERNANCE_ROOT__";
93
- const INIT_CHECK_ENGINEERING_STRUCTURE_SH = `#!/usr/bin/env bash
94
- set -euo pipefail
95
-
96
- ROOT_DIR="$(cd "$(dirname "\${BASH_SOURCE[0]}")/.." && pwd)"
97
- cd "\${ROOT_DIR}"
98
-
99
- required_paths=(
100
- "README.md"
101
- "harness.json"
102
- "AGENTS.md"
103
- "${GOVERNANCE_ROOT_TOKEN}/README.md"
104
- "${GOVERNANCE_ROOT_TOKEN}/development-principles.md"
105
- "${GOVERNANCE_ROOT_TOKEN}/feature-workflow.md"
106
- "${GOVERNANCE_ROOT_TOKEN}/verification-matrix.md"
107
- "${GOVERNANCE_ROOT_TOKEN}/architecture/runtime-boundaries.md"
108
- "${GOVERNANCE_ROOT_TOKEN}/templates"
109
- "skills/loop-agent/SKILL.md"
110
- ".harness/prompts/analyze.md"
111
- ".harness/prompts/plan.md"
112
- ".harness/tasks"
113
- ".harness/dag-runs/active"
114
- ".harness/dag-runs/completed"
115
- ".harness/dag-runs/paused"
116
- ".harness/runs/active"
117
- ".harness/runs/completed"
118
- ".harness/runs/failed"
119
- "scripts/check-engineering-structure.sh"
120
- "scripts/check-doc-index.sh"
121
- "scripts/check-doc-links.sh"
122
- "scripts/check-active-plan-status.sh"
123
- "scripts/check-exec-plan-index-sync.sh"
124
- "scripts/check-harness-runtime-clean.sh"
125
- "scripts/check-architecture-boundaries.sh"
126
- "scripts/check-skill-entry.sh"
127
- "scripts/check-repo.sh"
128
- "scripts/ci-governance.sh"
129
- "scripts/ci-tests.sh"
130
- "scripts/ci.sh"
131
- )
132
-
133
- missing=()
134
- for item in "\${required_paths[@]}"; do
135
- if [[ ! -e "\${item}" ]]; then
136
- missing+=("\${item}")
137
- fi
138
- done
139
-
140
- if (( \${#missing[@]} > 0 )); then
141
- echo "loop-agent 初始化检查失败,缺少必要路径:"
142
- for item in "\${missing[@]}"; do
143
- echo " - \${item}"
144
- done
145
- exit 1
146
- fi
147
-
148
- echo "loop-agent 工程结构检查通过"
93
+ const INIT_CHECK_ENGINEERING_STRUCTURE_SH = `#!/usr/bin/env bash
94
+ set -euo pipefail
95
+
96
+ ROOT_DIR="$(cd "$(dirname "\${BASH_SOURCE[0]}")/.." && pwd)"
97
+ cd "\${ROOT_DIR}"
98
+
99
+ required_paths=(
100
+ "README.md"
101
+ "harness.json"
102
+ "AGENTS.md"
103
+ "${GOVERNANCE_ROOT_TOKEN}/README.md"
104
+ "${GOVERNANCE_ROOT_TOKEN}/development-principles.md"
105
+ "${GOVERNANCE_ROOT_TOKEN}/feature-workflow.md"
106
+ "${GOVERNANCE_ROOT_TOKEN}/verification-matrix.md"
107
+ "${GOVERNANCE_ROOT_TOKEN}/architecture/runtime-boundaries.md"
108
+ "${GOVERNANCE_ROOT_TOKEN}/templates"
109
+ "skills/loop-agent/SKILL.md"
110
+ ".harness/prompts/analyze.md"
111
+ ".harness/prompts/plan.md"
112
+ ".harness/tasks"
113
+ ".harness/dag-runs/active"
114
+ ".harness/dag-runs/completed"
115
+ ".harness/dag-runs/paused"
116
+ ".harness/runs/active"
117
+ ".harness/runs/completed"
118
+ ".harness/runs/failed"
119
+ "scripts/check-engineering-structure.sh"
120
+ "scripts/check-doc-index.sh"
121
+ "scripts/check-doc-links.sh"
122
+ "scripts/check-active-plan-status.sh"
123
+ "scripts/check-exec-plan-index-sync.sh"
124
+ "scripts/check-harness-runtime-clean.sh"
125
+ "scripts/check-architecture-boundaries.sh"
126
+ "scripts/check-skill-entry.sh"
127
+ "scripts/check-repo.sh"
128
+ "scripts/ci-governance.sh"
129
+ "scripts/ci-tests.sh"
130
+ "scripts/ci.sh"
131
+ )
132
+
133
+ missing=()
134
+ for item in "\${required_paths[@]}"; do
135
+ if [[ ! -e "\${item}" ]]; then
136
+ missing+=("\${item}")
137
+ fi
138
+ done
139
+
140
+ if (( \${#missing[@]} > 0 )); then
141
+ echo "loop-agent 初始化检查失败,缺少必要路径:"
142
+ for item in "\${missing[@]}"; do
143
+ echo " - \${item}"
144
+ done
145
+ exit 1
146
+ fi
147
+
148
+ echo "loop-agent 工程结构检查通过"
149
149
  `;
150
- const INIT_CHECK_DOC_INDEX_SH = `#!/usr/bin/env bash
151
- set -euo pipefail
152
-
153
- ROOT_DIR="$(cd "$(dirname "\${BASH_SOURCE[0]}")/.." && pwd)"
154
- cd "\${ROOT_DIR}"
155
-
156
- required_docs=(
157
- "${GOVERNANCE_ROOT_TOKEN}/README.md"
158
- "${GOVERNANCE_ROOT_TOKEN}/development-principles.md"
159
- "${GOVERNANCE_ROOT_TOKEN}/feature-workflow.md"
160
- "${GOVERNANCE_ROOT_TOKEN}/verification-matrix.md"
161
- "${GOVERNANCE_ROOT_TOKEN}/architecture/runtime-boundaries.md"
162
- "${GOVERNANCE_ROOT_TOKEN}/loop-agent-harness.md"
163
- "${GOVERNANCE_ROOT_TOKEN}/harness-methodology-tdd.md"
164
- "${GOVERNANCE_ROOT_TOKEN}/harness-methodology-verification.md"
165
- "${GOVERNANCE_ROOT_TOKEN}/harness-methodology-debugging.md"
166
- "${GOVERNANCE_ROOT_TOKEN}/templates"
167
- "${GOVERNANCE_ROOT_TOKEN}/exec-plans/active/README.md"
168
- "${GOVERNANCE_ROOT_TOKEN}/exec-plans/completed/README.md"
169
- "${GOVERNANCE_ROOT_TOKEN}/progress/README.md"
170
- "${GOVERNANCE_ROOT_TOKEN}/reports/README.md"
171
- "${GOVERNANCE_ROOT_TOKEN}/decisions/README.md"
172
- )
173
-
174
- missing=()
175
- for item in "\${required_docs[@]}"; do
176
- if [[ ! -e "\${item}" ]]; then
177
- missing+=("\${item}")
178
- fi
179
- done
180
-
181
- if (( \${#missing[@]} > 0 )); then
182
- echo "docs 索引检查失败,缺少必要文档或目录:" >&2
183
- for item in "\${missing[@]}"; do
184
- echo " - \${item}" >&2
185
- done
186
- exit 1
187
- fi
188
-
189
- echo "docs 索引检查通过"
150
+ const INIT_CHECK_DOC_INDEX_SH = `#!/usr/bin/env bash
151
+ set -euo pipefail
152
+
153
+ ROOT_DIR="$(cd "$(dirname "\${BASH_SOURCE[0]}")/.." && pwd)"
154
+ cd "\${ROOT_DIR}"
155
+
156
+ required_docs=(
157
+ "${GOVERNANCE_ROOT_TOKEN}/README.md"
158
+ "${GOVERNANCE_ROOT_TOKEN}/development-principles.md"
159
+ "${GOVERNANCE_ROOT_TOKEN}/feature-workflow.md"
160
+ "${GOVERNANCE_ROOT_TOKEN}/verification-matrix.md"
161
+ "${GOVERNANCE_ROOT_TOKEN}/architecture/runtime-boundaries.md"
162
+ "${GOVERNANCE_ROOT_TOKEN}/loop-agent-harness.md"
163
+ "${GOVERNANCE_ROOT_TOKEN}/harness-methodology-tdd.md"
164
+ "${GOVERNANCE_ROOT_TOKEN}/harness-methodology-verification.md"
165
+ "${GOVERNANCE_ROOT_TOKEN}/harness-methodology-debugging.md"
166
+ "${GOVERNANCE_ROOT_TOKEN}/templates"
167
+ "${GOVERNANCE_ROOT_TOKEN}/exec-plans/active/README.md"
168
+ "${GOVERNANCE_ROOT_TOKEN}/exec-plans/completed/README.md"
169
+ "${GOVERNANCE_ROOT_TOKEN}/progress/README.md"
170
+ "${GOVERNANCE_ROOT_TOKEN}/reports/README.md"
171
+ "${GOVERNANCE_ROOT_TOKEN}/decisions/README.md"
172
+ )
173
+
174
+ missing=()
175
+ for item in "\${required_docs[@]}"; do
176
+ if [[ ! -e "\${item}" ]]; then
177
+ missing+=("\${item}")
178
+ fi
179
+ done
180
+
181
+ if (( \${#missing[@]} > 0 )); then
182
+ echo "docs 索引检查失败,缺少必要文档或目录:" >&2
183
+ for item in "\${missing[@]}"; do
184
+ echo " - \${item}" >&2
185
+ done
186
+ exit 1
187
+ fi
188
+
189
+ echo "docs 索引检查通过"
190
190
  `;
191
- const INIT_CHECK_DOC_LINKS_SH = `#!/usr/bin/env bash
192
- set -euo pipefail
193
-
194
- ROOT_DIR="$(cd "$(dirname "\${BASH_SOURCE[0]}")/.." && pwd)"
195
- cd "\${ROOT_DIR}"
196
-
197
- if [[ ! -d "${GOVERNANCE_ROOT_TOKEN}" ]]; then
198
- echo "docs 链接检查失败:缺少 ${GOVERNANCE_ROOT_TOKEN}/" >&2
199
- exit 1
200
- fi
201
-
202
- missing=()
203
- while IFS= read -r -d '' file; do
204
- while IFS= read -r link; do
205
- [[ -z "\${link}" ]] && continue
206
- [[ "\${link}" == http://* || "\${link}" == https://* || "\${link}" == mailto:* || "\${link}" == "#"* ]] && continue
207
- [[ "\${link}" == *"://"* ]] && continue
208
- target="\${link%%#*}"
209
- [[ -z "\${target}" ]] && continue
210
- [[ "\${target}" == /* ]] && continue
211
- base="$(dirname "\${file}")"
212
- if [[ ! -e "\${base}/\${target}" ]]; then
213
- missing+=("\${file}: \${link}")
214
- fi
215
- done < <(grep -Eo '\\[[^]]+\\]\\([^)]+\\)' "\${file}" | sed -E 's/^.*\\(([^)]+)\\)$/\\1/' || true)
216
- done < <(find "${GOVERNANCE_ROOT_TOKEN}" -type f -name '*.md' -print0)
217
-
218
- if (( \${#missing[@]} > 0 )); then
219
- echo "docs 链接检查失败:" >&2
220
- for item in "\${missing[@]}"; do
221
- echo " - \${item}" >&2
222
- done
223
- exit 1
224
- fi
225
-
226
- echo "docs 链接检查通过"
191
+ const INIT_CHECK_DOC_LINKS_SH = `#!/usr/bin/env bash
192
+ set -euo pipefail
193
+
194
+ ROOT_DIR="$(cd "$(dirname "\${BASH_SOURCE[0]}")/.." && pwd)"
195
+ cd "\${ROOT_DIR}"
196
+
197
+ if [[ ! -d "${GOVERNANCE_ROOT_TOKEN}" ]]; then
198
+ echo "docs 链接检查失败:缺少 ${GOVERNANCE_ROOT_TOKEN}/" >&2
199
+ exit 1
200
+ fi
201
+
202
+ missing=()
203
+ while IFS= read -r -d '' file; do
204
+ while IFS= read -r link; do
205
+ [[ -z "\${link}" ]] && continue
206
+ [[ "\${link}" == http://* || "\${link}" == https://* || "\${link}" == mailto:* || "\${link}" == "#"* ]] && continue
207
+ [[ "\${link}" == *"://"* ]] && continue
208
+ target="\${link%%#*}"
209
+ [[ -z "\${target}" ]] && continue
210
+ [[ "\${target}" == /* ]] && continue
211
+ base="$(dirname "\${file}")"
212
+ if [[ ! -e "\${base}/\${target}" ]]; then
213
+ missing+=("\${file}: \${link}")
214
+ fi
215
+ done < <(grep -Eo '\\[[^]]+\\]\\([^)]+\\)' "\${file}" | sed -E 's/^.*\\(([^)]+)\\)$/\\1/' || true)
216
+ done < <(find "${GOVERNANCE_ROOT_TOKEN}" -type f -name '*.md' -print0)
217
+
218
+ if (( \${#missing[@]} > 0 )); then
219
+ echo "docs 链接检查失败:" >&2
220
+ for item in "\${missing[@]}"; do
221
+ echo " - \${item}" >&2
222
+ done
223
+ exit 1
224
+ fi
225
+
226
+ echo "docs 链接检查通过"
227
227
  `;
228
- const INIT_CHECK_ACTIVE_PLAN_STATUS_SH = `#!/usr/bin/env bash
229
- set -euo pipefail
230
-
231
- ROOT_DIR="$(cd "$(dirname "\${BASH_SOURCE[0]}")/.." && pwd)"
232
- cd "\${ROOT_DIR}"
233
-
234
- active_dir="${GOVERNANCE_ROOT_TOKEN}/exec-plans/active"
235
- [[ -d "\${active_dir}" ]] || { echo "active plan 检查失败:缺少 \${active_dir}" >&2; exit 1; }
236
-
237
- bad=()
238
- while IFS= read -r -d '' file; do
239
- name="$(basename "\${file}")"
240
- [[ "\${name}" == "README.md" ]] && continue
241
- if grep -Eiq 'status:[[:space:]]*(completed|done|closed)|状态[::][[:space:]]*(已完成|完成|关闭)' "\${file}"; then
242
- bad+=("\${file}")
243
- fi
244
- done < <(find "\${active_dir}" -maxdepth 1 -type f -name '*.md' -print0)
245
-
246
- if (( \${#bad[@]} > 0 )); then
247
- echo "active plan 状态检查失败:已完成计划不应留在 active 目录:" >&2
248
- for item in "\${bad[@]}"; do
249
- echo " - \${item}" >&2
250
- done
251
- exit 1
252
- fi
253
-
254
- echo "active plan 状态检查通过"
228
+ const INIT_CHECK_ACTIVE_PLAN_STATUS_SH = `#!/usr/bin/env bash
229
+ set -euo pipefail
230
+
231
+ ROOT_DIR="$(cd "$(dirname "\${BASH_SOURCE[0]}")/.." && pwd)"
232
+ cd "\${ROOT_DIR}"
233
+
234
+ active_dir="${GOVERNANCE_ROOT_TOKEN}/exec-plans/active"
235
+ [[ -d "\${active_dir}" ]] || { echo "active plan 检查失败:缺少 \${active_dir}" >&2; exit 1; }
236
+
237
+ bad=()
238
+ while IFS= read -r -d '' file; do
239
+ name="$(basename "\${file}")"
240
+ [[ "\${name}" == "README.md" ]] && continue
241
+ if grep -Eiq 'status:[[:space:]]*(completed|done|closed)|状态[::][[:space:]]*(已完成|完成|关闭)' "\${file}"; then
242
+ bad+=("\${file}")
243
+ fi
244
+ done < <(find "\${active_dir}" -maxdepth 1 -type f -name '*.md' -print0)
245
+
246
+ if (( \${#bad[@]} > 0 )); then
247
+ echo "active plan 状态检查失败:已完成计划不应留在 active 目录:" >&2
248
+ for item in "\${bad[@]}"; do
249
+ echo " - \${item}" >&2
250
+ done
251
+ exit 1
252
+ fi
253
+
254
+ echo "active plan 状态检查通过"
255
255
  `;
256
- const INIT_CHECK_EXEC_PLAN_INDEX_SYNC_SH = `#!/usr/bin/env bash
257
- set -euo pipefail
258
-
259
- ROOT_DIR="$(cd "$(dirname "\${BASH_SOURCE[0]}")/.." && pwd)"
260
- cd "\${ROOT_DIR}"
261
-
262
- required=(
263
- "${GOVERNANCE_ROOT_TOKEN}/exec-plans/README.md"
264
- "${GOVERNANCE_ROOT_TOKEN}/exec-plans/active/README.md"
265
- "${GOVERNANCE_ROOT_TOKEN}/exec-plans/completed/README.md"
266
- )
267
-
268
- for item in "\${required[@]}"; do
269
- if [[ ! -f "\${item}" ]]; then
270
- echo "exec-plan 索引同步检查失败:缺少 \${item}" >&2
271
- exit 1
272
- fi
273
- done
274
-
275
- echo "exec-plan 索引同步检查通过"
256
+ const INIT_CHECK_EXEC_PLAN_INDEX_SYNC_SH = `#!/usr/bin/env bash
257
+ set -euo pipefail
258
+
259
+ ROOT_DIR="$(cd "$(dirname "\${BASH_SOURCE[0]}")/.." && pwd)"
260
+ cd "\${ROOT_DIR}"
261
+
262
+ required=(
263
+ "${GOVERNANCE_ROOT_TOKEN}/exec-plans/README.md"
264
+ "${GOVERNANCE_ROOT_TOKEN}/exec-plans/active/README.md"
265
+ "${GOVERNANCE_ROOT_TOKEN}/exec-plans/completed/README.md"
266
+ )
267
+
268
+ for item in "\${required[@]}"; do
269
+ if [[ ! -f "\${item}" ]]; then
270
+ echo "exec-plan 索引同步检查失败:缺少 \${item}" >&2
271
+ exit 1
272
+ fi
273
+ done
274
+
275
+ echo "exec-plan 索引同步检查通过"
276
276
  `;
277
- const INIT_CHECK_HARNESS_RUNTIME_CLEAN_SH = `#!/usr/bin/env bash
278
- set -euo pipefail
279
-
280
- ROOT_DIR="$(cd "$(dirname "\${BASH_SOURCE[0]}")/.." && pwd)"
281
- cd "\${ROOT_DIR}"
282
-
283
- failures=()
284
-
285
- count_entries() {
286
- local dir="$1"
287
- if [[ ! -d "\${dir}" ]]; then
288
- echo 0
289
- return
290
- fi
291
- find "\${dir}" -mindepth 1 -maxdepth 1 ! -name .gitkeep | wc -l | tr -d ' '
292
- }
293
-
294
- if [[ "\${HARNESS_ALLOW_ACTIVE_DAG_RUNS:-}" != "1" ]]; then
295
- active_dag_count="$(count_entries ".harness/dag-runs/active")"
296
- [[ "\${active_dag_count}" == "0" ]] || failures+=(".harness/dag-runs/active contains \${active_dag_count} entries")
297
- fi
298
-
299
- if [[ "\${HARNESS_ALLOW_ACTIVE_TOOL_RUNS:-\${HARNESS_ALLOW_ACTIVE_ONE_SHOT_RUNS:-}}" != "1" ]]; then
300
- active_run_count="$(count_entries ".harness/runs/active")"
301
- [[ "\${active_run_count}" == "0" ]] || failures+=(".harness/runs/active contains \${active_run_count} entries")
302
- fi
303
-
304
- if [[ -d artifacts ]]; then
305
- artifact_count="$(find artifacts -mindepth 1 -maxdepth 1 ! -name .gitkeep | wc -l | tr -d ' ')"
306
- [[ "\${artifact_count}" == "0" ]] || failures+=("root artifacts/ contains \${artifact_count} entries; use docs/reports or .harness run artifacts")
307
- fi
308
-
309
- if (( \${#failures[@]} > 0 )); then
310
- echo "[HARNESS RUNTIME DIRTY]" >&2
311
- for item in "\${failures[@]}"; do
312
- echo " - \${item}" >&2
313
- done
314
- exit 1
315
- fi
316
-
317
- echo "harness runtime clean check passed"
277
+ const INIT_CHECK_HARNESS_RUNTIME_CLEAN_SH = `#!/usr/bin/env bash
278
+ set -euo pipefail
279
+
280
+ ROOT_DIR="$(cd "$(dirname "\${BASH_SOURCE[0]}")/.." && pwd)"
281
+ cd "\${ROOT_DIR}"
282
+
283
+ failures=()
284
+
285
+ count_entries() {
286
+ local dir="$1"
287
+ if [[ ! -d "\${dir}" ]]; then
288
+ echo 0
289
+ return
290
+ fi
291
+ find "\${dir}" -mindepth 1 -maxdepth 1 ! -name .gitkeep | wc -l | tr -d ' '
292
+ }
293
+
294
+ if [[ "\${HARNESS_ALLOW_ACTIVE_DAG_RUNS:-}" != "1" ]]; then
295
+ active_dag_count="$(count_entries ".harness/dag-runs/active")"
296
+ [[ "\${active_dag_count}" == "0" ]] || failures+=(".harness/dag-runs/active contains \${active_dag_count} entries")
297
+ fi
298
+
299
+ if [[ "\${HARNESS_ALLOW_ACTIVE_TOOL_RUNS:-\${HARNESS_ALLOW_ACTIVE_ONE_SHOT_RUNS:-}}" != "1" ]]; then
300
+ active_run_count="$(count_entries ".harness/runs/active")"
301
+ [[ "\${active_run_count}" == "0" ]] || failures+=(".harness/runs/active contains \${active_run_count} entries")
302
+ fi
303
+
304
+ if [[ -d artifacts ]]; then
305
+ artifact_count="$(find artifacts -mindepth 1 -maxdepth 1 ! -name .gitkeep | wc -l | tr -d ' ')"
306
+ [[ "\${artifact_count}" == "0" ]] || failures+=("root artifacts/ contains \${artifact_count} entries; use docs/reports or .harness run artifacts")
307
+ fi
308
+
309
+ if (( \${#failures[@]} > 0 )); then
310
+ echo "[HARNESS RUNTIME DIRTY]" >&2
311
+ for item in "\${failures[@]}"; do
312
+ echo " - \${item}" >&2
313
+ done
314
+ exit 1
315
+ fi
316
+
317
+ echo "harness runtime clean check passed"
318
318
  `;
319
- const INIT_CHECK_ARCHITECTURE_BOUNDARIES_SH = `#!/usr/bin/env bash
320
- set -euo pipefail
321
-
322
- ROOT_DIR="$(cd "$(dirname "\${BASH_SOURCE[0]}")/.." && pwd)"
323
- cd "\${ROOT_DIR}"
324
-
325
- boundary_doc="${GOVERNANCE_ROOT_TOKEN}/architecture/runtime-boundaries.md"
326
- if [[ ! -f "\${boundary_doc}" ]]; then
327
- echo "architecture boundary 检查失败:缺少 \${boundary_doc}" >&2
328
- exit 1
329
- fi
330
-
331
- violations=()
332
-
333
- check_ts_import_boundary() {
334
- local from_dir="$1"
335
- local forbidden_dir="$2"
336
- local label="$3"
337
- [[ -d "\${from_dir}" && -d "\${forbidden_dir}" ]] || return 0
338
- while IFS= read -r -d '' file; do
339
- if grep -Eq "from ['\\\"][^'\\\"]*\${forbidden_dir}/|import\\(['\\\"][^'\\\"]*\${forbidden_dir}/|require\\(['\\\"][^'\\\"]*\${forbidden_dir}/" "\${file}"; then
340
- violations+=("\${label}: \${file} imports \${forbidden_dir}")
341
- fi
342
- done < <(find "\${from_dir}" -type f \\( -name '*.ts' -o -name '*.tsx' -o -name '*.js' -o -name '*.jsx' -o -name '*.mjs' -o -name '*.cjs' \\) -print0)
343
- }
344
-
345
- # These checks are intentionally optional and stack-agnostic. They activate only
346
- # when a target repository has recognizable source directories.
347
- check_ts_import_boundary "src/workflows" "src/commands" "workflow-runtime"
348
- check_ts_import_boundary "src/executors" "src/commands" "executors"
349
- check_ts_import_boundary "src/domain" "src/infrastructure" "domain"
350
-
351
- if (( \${#violations[@]} > 0 )); then
352
- echo "architecture boundary 检查失败:" >&2
353
- for item in "\${violations[@]}"; do
354
- echo " - \${item}" >&2
355
- done
356
- echo "请更新 \${boundary_doc} 中的层边界,或修正反向依赖。" >&2
357
- exit 1
358
- fi
359
-
360
- echo "architecture boundary 检查通过"
319
+ const INIT_CHECK_ARCHITECTURE_BOUNDARIES_SH = `#!/usr/bin/env bash
320
+ set -euo pipefail
321
+
322
+ ROOT_DIR="$(cd "$(dirname "\${BASH_SOURCE[0]}")/.." && pwd)"
323
+ cd "\${ROOT_DIR}"
324
+
325
+ boundary_doc="${GOVERNANCE_ROOT_TOKEN}/architecture/runtime-boundaries.md"
326
+ if [[ ! -f "\${boundary_doc}" ]]; then
327
+ echo "architecture boundary 检查失败:缺少 \${boundary_doc}" >&2
328
+ exit 1
329
+ fi
330
+
331
+ violations=()
332
+
333
+ check_ts_import_boundary() {
334
+ local from_dir="$1"
335
+ local forbidden_dir="$2"
336
+ local label="$3"
337
+ [[ -d "\${from_dir}" && -d "\${forbidden_dir}" ]] || return 0
338
+ while IFS= read -r -d '' file; do
339
+ if grep -Eq "from ['\\\"][^'\\\"]*\${forbidden_dir}/|import\\(['\\\"][^'\\\"]*\${forbidden_dir}/|require\\(['\\\"][^'\\\"]*\${forbidden_dir}/" "\${file}"; then
340
+ violations+=("\${label}: \${file} imports \${forbidden_dir}")
341
+ fi
342
+ done < <(find "\${from_dir}" -type f \\( -name '*.ts' -o -name '*.tsx' -o -name '*.js' -o -name '*.jsx' -o -name '*.mjs' -o -name '*.cjs' \\) -print0)
343
+ }
344
+
345
+ # These checks are intentionally optional and stack-agnostic. They activate only
346
+ # when a target repository has recognizable source directories.
347
+ check_ts_import_boundary "src/workflows" "src/commands" "workflow-runtime"
348
+ check_ts_import_boundary "src/executors" "src/commands" "executors"
349
+ check_ts_import_boundary "src/domain" "src/infrastructure" "domain"
350
+
351
+ if (( \${#violations[@]} > 0 )); then
352
+ echo "architecture boundary 检查失败:" >&2
353
+ for item in "\${violations[@]}"; do
354
+ echo " - \${item}" >&2
355
+ done
356
+ echo "请更新 \${boundary_doc} 中的层边界,或修正反向依赖。" >&2
357
+ exit 1
358
+ fi
359
+
360
+ echo "architecture boundary 检查通过"
361
361
  `;
362
- const INIT_CHECK_SKILL_ENTRY_SH = `#!/usr/bin/env bash
363
- set -euo pipefail
364
-
365
- ROOT_DIR="$(cd "$(dirname "\${BASH_SOURCE[0]}")/.." && pwd)"
366
- cd "\${ROOT_DIR}"
367
-
368
- skill_md="skills/loop-agent/SKILL.md"
369
- if [[ ! -f "\${skill_md}" ]]; then
370
- echo "skill entry 检查失败:缺少 \${skill_md}" >&2
371
- exit 1
372
- fi
373
-
374
- required_refs=(
375
- "references/harness-policy.md"
376
- "references/hybrid-dag.md"
377
- "references/verification-and-failure-handling.md"
378
- "references/command-reference.md"
379
- )
380
-
381
- missing=()
382
- for ref in "\${required_refs[@]}"; do
383
- [[ -f "skills/loop-agent/\${ref}" ]] || missing+=("\${ref}")
384
- done
385
-
386
- while IFS= read -r ref; do
387
- [[ -z "\${ref}" ]] && continue
388
- [[ -f "skills/loop-agent/\${ref}" ]] || missing+=("\${ref}")
389
- done < <(grep -Eo 'references/[A-Za-z0-9._/-]+\\.md' "\${skill_md}" | sort -u || true)
390
-
391
- if (( \${#missing[@]} > 0 )); then
392
- echo "skill entry 检查失败:引用的 reference 文件不存在:" >&2
393
- printf ' - %s\\n' "\${missing[@]}" >&2
394
- exit 1
395
- fi
396
-
397
- line_count="$(wc -l < "\${skill_md}" | tr -d ' ')"
398
- if [[ "\${line_count}" =~ ^[0-9]+$ && "\${line_count}" -gt 220 ]]; then
399
- echo "skill entry 检查警告:\${skill_md} 行数为 \${line_count},建议保持入口精简并把细节放入 references/" >&2
400
- fi
401
-
402
- echo "skill entry 检查通过:references ok, lines=\${line_count}"
362
+ const INIT_CHECK_SKILL_ENTRY_SH = `#!/usr/bin/env bash
363
+ set -euo pipefail
364
+
365
+ ROOT_DIR="$(cd "$(dirname "\${BASH_SOURCE[0]}")/.." && pwd)"
366
+ cd "\${ROOT_DIR}"
367
+
368
+ skill_md="skills/loop-agent/SKILL.md"
369
+ if [[ ! -f "\${skill_md}" ]]; then
370
+ echo "skill entry 检查失败:缺少 \${skill_md}" >&2
371
+ exit 1
372
+ fi
373
+
374
+ required_refs=(
375
+ "references/harness-policy.md"
376
+ "references/hybrid-dag.md"
377
+ "references/verification-and-failure-handling.md"
378
+ "references/command-reference.md"
379
+ )
380
+
381
+ missing=()
382
+ for ref in "\${required_refs[@]}"; do
383
+ [[ -f "skills/loop-agent/\${ref}" ]] || missing+=("\${ref}")
384
+ done
385
+
386
+ while IFS= read -r ref; do
387
+ [[ -z "\${ref}" ]] && continue
388
+ [[ -f "skills/loop-agent/\${ref}" ]] || missing+=("\${ref}")
389
+ done < <(grep -Eo 'references/[A-Za-z0-9._/-]+\\.md' "\${skill_md}" | sort -u || true)
390
+
391
+ if (( \${#missing[@]} > 0 )); then
392
+ echo "skill entry 检查失败:引用的 reference 文件不存在:" >&2
393
+ printf ' - %s\\n' "\${missing[@]}" >&2
394
+ exit 1
395
+ fi
396
+
397
+ line_count="$(wc -l < "\${skill_md}" | tr -d ' ')"
398
+ if [[ "\${line_count}" =~ ^[0-9]+$ && "\${line_count}" -gt 220 ]]; then
399
+ echo "skill entry 检查警告:\${skill_md} 行数为 \${line_count},建议保持入口精简并把细节放入 references/" >&2
400
+ fi
401
+
402
+ echo "skill entry 检查通过:references ok, lines=\${line_count}"
403
403
  `;
404
- const INIT_CHECK_REPO_SH = `#!/usr/bin/env bash
405
- set -euo pipefail
406
-
407
- ROOT_DIR="$(cd "$(dirname "\${BASH_SOURCE[0]}")/.." && pwd)"
408
- cd "\${ROOT_DIR}"
409
-
410
- checks=(
411
- "scripts/check-engineering-structure.sh"
412
- "scripts/check-doc-index.sh"
413
- "scripts/check-doc-links.sh"
414
- "scripts/check-active-plan-status.sh"
415
- "scripts/check-exec-plan-index-sync.sh"
416
- "scripts/check-harness-runtime-clean.sh"
417
- "scripts/check-architecture-boundaries.sh"
418
- "scripts/check-skill-entry.sh"
419
- )
420
-
421
- for check in "\${checks[@]}"; do
422
- echo "==> bash \${check}"
423
- bash "\${check}"
424
- echo
425
- done
426
-
427
- echo "仓库治理检查全部通过"
404
+ const INIT_CHECK_REPO_SH = `#!/usr/bin/env bash
405
+ set -euo pipefail
406
+
407
+ ROOT_DIR="$(cd "$(dirname "\${BASH_SOURCE[0]}")/.." && pwd)"
408
+ cd "\${ROOT_DIR}"
409
+
410
+ checks=(
411
+ "scripts/check-engineering-structure.sh"
412
+ "scripts/check-doc-index.sh"
413
+ "scripts/check-doc-links.sh"
414
+ "scripts/check-active-plan-status.sh"
415
+ "scripts/check-exec-plan-index-sync.sh"
416
+ "scripts/check-harness-runtime-clean.sh"
417
+ "scripts/check-architecture-boundaries.sh"
418
+ "scripts/check-skill-entry.sh"
419
+ )
420
+
421
+ for check in "\${checks[@]}"; do
422
+ echo "==> bash \${check}"
423
+ bash "\${check}"
424
+ echo
425
+ done
426
+
427
+ echo "仓库治理检查全部通过"
428
428
  `;
429
- const INIT_CI_GOVERNANCE_SH = `#!/usr/bin/env bash
430
- set -euo pipefail
431
-
432
- ROOT_DIR="$(cd "$(dirname "\${BASH_SOURCE[0]}")/.." && pwd)"
433
- cd "\${ROOT_DIR}"
434
-
435
- bash scripts/check-repo.sh
429
+ const INIT_CI_GOVERNANCE_SH = `#!/usr/bin/env bash
430
+ set -euo pipefail
431
+
432
+ ROOT_DIR="$(cd "$(dirname "\${BASH_SOURCE[0]}")/.." && pwd)"
433
+ cd "\${ROOT_DIR}"
434
+
435
+ bash scripts/check-repo.sh
436
436
  `;
437
- const INIT_CI_TESTS_SH = `#!/usr/bin/env bash
438
- set -euo pipefail
439
-
440
- ROOT_DIR="$(cd "$(dirname "\${BASH_SOURCE[0]}")/.." && pwd)"
441
- cd "\${ROOT_DIR}"
442
-
443
- ran=0
444
- notes=()
445
-
446
- run_cmd() {
447
- echo "==> $*"
448
- "$@"
449
- ran=1
450
- }
451
-
452
- run_bash() {
453
- echo "==> $*"
454
- bash -lc "$*"
455
- ran=1
456
- }
457
-
458
- has_make_target() {
459
- local target="$1"
460
- [[ -f Makefile || -f makefile ]] || return 1
461
- grep -Eq "^[[:alnum:]_.-]*\${target}[[:alnum:]_.-]*:" Makefile makefile 2>/dev/null
462
- }
463
-
464
- has_npm_script() {
465
- local script="$1"
466
- [[ -f package.json ]] || return 1
467
- command -v node >/dev/null 2>&1 || return 1
468
- 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
469
- }
470
-
471
- if [[ -f package.json ]]; then
472
- if command -v npm >/dev/null 2>&1; then
473
- for script in lint typecheck test build; do
474
- if has_npm_script "\${script}"; then
475
- run_cmd npm run "\${script}"
476
- fi
477
- done
478
- else
479
- notes+=("package.json exists but npm is not available")
480
- fi
481
- fi
482
-
483
- if has_make_target verify; then
484
- run_cmd make verify
485
- elif has_make_target test; then
486
- run_cmd make test
487
- fi
488
-
489
- if [[ -f go.mod ]]; then
490
- if command -v go >/dev/null 2>&1; then
491
- run_cmd go test ./...
492
- else
493
- notes+=("go.mod exists but go is not available")
494
- fi
495
- fi
496
-
497
- if [[ -f Cargo.toml ]]; then
498
- if command -v cargo >/dev/null 2>&1; then
499
- run_cmd cargo test
500
- else
501
- notes+=("Cargo.toml exists but cargo is not available")
502
- fi
503
- fi
504
-
505
- if [[ -f pyproject.toml || -f pytest.ini || -f tox.ini ]]; then
506
- if command -v pytest >/dev/null 2>&1; then
507
- run_cmd pytest
508
- elif command -v tox >/dev/null 2>&1 && [[ -f tox.ini ]]; then
509
- run_cmd tox
510
- else
511
- notes+=("Python project metadata found but pytest/tox is not available")
512
- fi
513
- fi
514
-
515
- if [[ -f pom.xml ]]; then
516
- if command -v mvn >/dev/null 2>&1; then
517
- run_cmd mvn test
518
- else
519
- notes+=("pom.xml exists but mvn is not available")
520
- fi
521
- fi
522
-
523
- if [[ -f build.gradle || -f build.gradle.kts || -f settings.gradle || -f settings.gradle.kts ]]; then
524
- if [[ -x ./gradlew ]]; then
525
- run_cmd ./gradlew test
526
- elif command -v gradle >/dev/null 2>&1; then
527
- run_cmd gradle test
528
- else
529
- notes+=("Gradle project metadata found but gradle/gradlew is not available")
530
- fi
531
- fi
532
-
533
- if compgen -G "*.sln" >/dev/null || compgen -G "*.csproj" >/dev/null; then
534
- if command -v dotnet >/dev/null 2>&1; then
535
- run_cmd dotnet test
536
- else
537
- notes+=(".NET project metadata found but dotnet is not available")
538
- fi
539
- fi
540
-
541
- if (( ran == 0 )); then
542
- echo "未检测到可安全自动运行的项目测试入口。"
543
- echo "loop-agent 治理检查仍可运行;请让初始化模型根据目标项目技术栈补充 scripts/ci-tests.sh 与 docs/verification-matrix.md。"
544
- fi
545
-
546
- if (( \${#notes[@]} > 0 )); then
547
- echo "项目验证探测备注:"
548
- for note in "\${notes[@]}"; do
549
- echo " - \${note}"
550
- done
551
- fi
437
+ const INIT_CI_TESTS_SH = `#!/usr/bin/env bash
438
+ set -euo pipefail
439
+
440
+ ROOT_DIR="$(cd "$(dirname "\${BASH_SOURCE[0]}")/.." && pwd)"
441
+ cd "\${ROOT_DIR}"
442
+
443
+ ran=0
444
+ notes=()
445
+
446
+ run_cmd() {
447
+ echo "==> $*"
448
+ "$@"
449
+ ran=1
450
+ }
451
+
452
+ run_bash() {
453
+ echo "==> $*"
454
+ bash -lc "$*"
455
+ ran=1
456
+ }
457
+
458
+ has_make_target() {
459
+ local target="$1"
460
+ [[ -f Makefile || -f makefile ]] || return 1
461
+ grep -Eq "^[[:alnum:]_.-]*\${target}[[:alnum:]_.-]*:" Makefile makefile 2>/dev/null
462
+ }
463
+
464
+ has_npm_script() {
465
+ local script="$1"
466
+ [[ -f package.json ]] || return 1
467
+ command -v node >/dev/null 2>&1 || return 1
468
+ 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
469
+ }
470
+
471
+ if [[ -f package.json ]]; then
472
+ if command -v npm >/dev/null 2>&1; then
473
+ for script in lint typecheck test build; do
474
+ if has_npm_script "\${script}"; then
475
+ run_cmd npm run "\${script}"
476
+ fi
477
+ done
478
+ else
479
+ notes+=("package.json exists but npm is not available")
480
+ fi
481
+ fi
482
+
483
+ if has_make_target verify; then
484
+ run_cmd make verify
485
+ elif has_make_target test; then
486
+ run_cmd make test
487
+ fi
488
+
489
+ if [[ -f go.mod ]]; then
490
+ if command -v go >/dev/null 2>&1; then
491
+ run_cmd go test ./...
492
+ else
493
+ notes+=("go.mod exists but go is not available")
494
+ fi
495
+ fi
496
+
497
+ if [[ -f Cargo.toml ]]; then
498
+ if command -v cargo >/dev/null 2>&1; then
499
+ run_cmd cargo test
500
+ else
501
+ notes+=("Cargo.toml exists but cargo is not available")
502
+ fi
503
+ fi
504
+
505
+ if [[ -f pyproject.toml || -f pytest.ini || -f tox.ini ]]; then
506
+ if command -v pytest >/dev/null 2>&1; then
507
+ run_cmd pytest
508
+ elif command -v tox >/dev/null 2>&1 && [[ -f tox.ini ]]; then
509
+ run_cmd tox
510
+ else
511
+ notes+=("Python project metadata found but pytest/tox is not available")
512
+ fi
513
+ fi
514
+
515
+ if [[ -f pom.xml ]]; then
516
+ if command -v mvn >/dev/null 2>&1; then
517
+ run_cmd mvn test
518
+ else
519
+ notes+=("pom.xml exists but mvn is not available")
520
+ fi
521
+ fi
522
+
523
+ if [[ -f build.gradle || -f build.gradle.kts || -f settings.gradle || -f settings.gradle.kts ]]; then
524
+ if [[ -x ./gradlew ]]; then
525
+ run_cmd ./gradlew test
526
+ elif command -v gradle >/dev/null 2>&1; then
527
+ run_cmd gradle test
528
+ else
529
+ notes+=("Gradle project metadata found but gradle/gradlew is not available")
530
+ fi
531
+ fi
532
+
533
+ if compgen -G "*.sln" >/dev/null || compgen -G "*.csproj" >/dev/null; then
534
+ if command -v dotnet >/dev/null 2>&1; then
535
+ run_cmd dotnet test
536
+ else
537
+ notes+=(".NET project metadata found but dotnet is not available")
538
+ fi
539
+ fi
540
+
541
+ if (( ran == 0 )); then
542
+ echo "未检测到可安全自动运行的项目测试入口。"
543
+ echo "loop-agent 治理检查仍可运行;请让初始化模型根据目标项目技术栈补充 scripts/ci-tests.sh 与 docs/verification-matrix.md。"
544
+ fi
545
+
546
+ if (( \${#notes[@]} > 0 )); then
547
+ echo "项目验证探测备注:"
548
+ for note in "\${notes[@]}"; do
549
+ echo " - \${note}"
550
+ done
551
+ fi
552
552
  `;
553
- const INIT_CI_SH = `#!/usr/bin/env bash
554
- set -euo pipefail
555
-
556
- ROOT_DIR="$(cd "$(dirname "\${BASH_SOURCE[0]}")/.." && pwd)"
557
- cd "\${ROOT_DIR}"
558
-
559
- bash scripts/ci-governance.sh
560
- bash scripts/ci-tests.sh
553
+ const INIT_CI_SH = `#!/usr/bin/env bash
554
+ set -euo pipefail
555
+
556
+ ROOT_DIR="$(cd "$(dirname "\${BASH_SOURCE[0]}")/.." && pwd)"
557
+ cd "\${ROOT_DIR}"
558
+
559
+ bash scripts/ci-governance.sh
560
+ bash scripts/ci-tests.sh
561
561
  `;
562
562
  const INIT_SCRIPT_FILES = {
563
563
  "scripts/check-engineering-structure.sh": INIT_CHECK_ENGINEERING_STRUCTURE_SH,