@tea-agent/loop-agent 0.1.0 → 0.2.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 (100) hide show
  1. package/CHANGELOG.md +17 -1
  2. package/README.md +127 -92
  3. package/dist/adapters/index.js +3 -2
  4. package/dist/adapters/loop-agent.js +44 -2
  5. package/dist/application/dag/args.js +420 -0
  6. package/dist/application/dag/generate-task-dag.js +280 -0
  7. package/dist/application/dag/report-dag.js +14 -0
  8. package/dist/application/dag/run-dag.js +93 -0
  9. package/dist/application/dag/validate-dag.js +101 -0
  10. package/dist/application/loop/run-action.js +23 -0
  11. package/dist/cli/catalog.js +2 -237
  12. package/dist/cli/command-definitions.js +571 -0
  13. package/dist/cli/index.js +2 -0
  14. package/dist/cli/program.js +65 -1
  15. package/dist/cli/router.js +13 -0
  16. package/dist/cli-governance/active-residue-check.js +38 -0
  17. package/dist/commands/dag-report.js +6 -107
  18. package/dist/commands/dag-run-task.js +8 -466
  19. package/dist/commands/dag-validate.js +7 -179
  20. package/dist/commands/examples.js +90 -0
  21. package/dist/commands/init.js +1495 -0
  22. package/dist/commands/loop.js +57 -31
  23. package/dist/commands/pi-prompt.js +2 -9
  24. package/dist/commands/run-dag.js +7 -180
  25. package/dist/executors/cursor-executor-artifacts.js +3 -4
  26. package/dist/executors/cursor-worker-client.js +13 -3
  27. package/dist/executors/dag-cursor-executor.js +2 -3
  28. package/dist/executors/dag-pi-executor.js +3 -4
  29. package/dist/executors/dag-static-executor.js +2 -5
  30. package/dist/executors/pi-defaults.js +9 -0
  31. package/dist/executors/shell-executor.js +12 -20
  32. package/dist/governance/manifest-types.js +1 -0
  33. package/dist/infrastructure/harness/active-residue-policy.js +73 -0
  34. package/dist/infrastructure/harness/artifact-store.js +72 -0
  35. package/dist/infrastructure/harness/atomic-write.js +49 -0
  36. package/dist/infrastructure/harness/completed-facts-guard.js +40 -0
  37. package/dist/infrastructure/harness/loop-action-store.js +23 -0
  38. package/dist/infrastructure/harness/loop-store.js +41 -0
  39. package/dist/infrastructure/harness/one-shot-run-store.js +94 -0
  40. package/dist/infrastructure/harness/task-store.js +77 -0
  41. package/dist/records/one-shot-runs.js +26 -61
  42. package/dist/records/promotion.js +3 -4
  43. package/dist/shared/artifacts-core.js +5 -5
  44. package/dist/shared/logger.js +9 -15
  45. package/dist/task/delegate.js +4 -4
  46. package/dist/task/runtime.js +5 -7
  47. package/dist/task/state.js +6 -20
  48. package/dist/workflows/dag/convergence/controller.js +277 -0
  49. package/dist/workflows/dag/dynamic-runtime/condition.js +48 -0
  50. package/dist/workflows/dag/dynamic-runtime/loop-until.js +156 -0
  51. package/dist/workflows/dag/dynamic-runtime/map.js +185 -0
  52. package/dist/workflows/dag/dynamic-runtime/reduction.js +72 -0
  53. package/dist/workflows/dag/dynamic-runtime/shared.js +133 -0
  54. package/dist/workflows/dag/lifecycle.js +6 -5
  55. package/dist/workflows/dag/node-execution.js +262 -0
  56. package/dist/workflows/dag/run-store.js +36 -0
  57. package/dist/workflows/dag/runner.js +82 -1341
  58. package/dist/workflows/dag/scheduler.js +84 -0
  59. package/dist/workflows/dag/upstream-artifacts.js +20 -18
  60. package/dist/workflows/loop/actions/cursor-fix.js +191 -0
  61. package/dist/workflows/loop/actions/dag-action.js +130 -0
  62. package/dist/workflows/loop/actions/pi-review.js +267 -0
  63. package/dist/workflows/loop/actions/shared.js +157 -0
  64. package/dist/workflows/loop/actions/shell-verify.js +82 -0
  65. package/dist/workflows/loop/actions/types.js +1 -0
  66. package/dist/workflows/loop/actions/workflow-action.js +255 -0
  67. package/dist/workflows/loop/actions.js +55 -1212
  68. package/dist/workflows/loop/closeout.js +5 -4
  69. package/dist/workflows/loop/context.js +2 -3
  70. package/dist/workflows/loop/events.js +3 -2
  71. package/dist/workflows/loop/policy/auto-policy.js +104 -0
  72. package/dist/workflows/loop/policy/cursor-fix-policy.js +31 -0
  73. package/dist/workflows/loop/rounds.js +3 -3
  74. package/dist/workflows/loop/signals.js +4 -7
  75. package/dist/workflows/loop/state.js +11 -11
  76. package/docs/README.md +3 -2
  77. package/docs/architecture/runtime-boundaries.md +147 -0
  78. package/docs/exec-plans/active/README.md +4 -0
  79. package/docs/exec-plans/completed/README.md +6 -2
  80. package/package.json +2 -1
  81. package/skills/ai-engineering-context/SKILL.md +21 -21
  82. package/skills/loop-agent/SKILL.md +73 -188
  83. package/skills/loop-agent/references/README.md +6 -2
  84. package/skills/loop-agent/references/harness-policy.md +113 -113
  85. package/skills/loop-agent/references/learned/README.md +13 -13
  86. package/skills/loop-agent/references/long-running-loop.md +59 -0
  87. package/skills/loop-agent/references/pi-subagent-assisted-mode.md +0 -2
  88. package/skills/loop-agent/references/verification-and-failure-handling.md +18 -0
  89. package/skills/requesting-code-review/SKILL.md +40 -40
  90. package/skills/requesting-code-review/code-reviewer.md +4 -4
  91. package/skills/systematic-debugging/CREATION-LOG.md +43 -43
  92. package/skills/systematic-debugging/SKILL.md +113 -113
  93. package/skills/systematic-debugging/condition-based-waiting.md +20 -20
  94. package/skills/systematic-debugging/defense-in-depth.md +27 -27
  95. package/skills/systematic-debugging/root-cause-tracing.md +38 -38
  96. package/skills/systematic-debugging/test-academic.md +6 -6
  97. package/skills/systematic-debugging/test-pressure-1.md +6 -6
  98. package/skills/systematic-debugging/test-pressure-2.md +2 -2
  99. package/skills/systematic-debugging/test-pressure-3.md +6 -6
  100. package/skills/verification-before-completion/SKILL.md +37 -37
@@ -0,0 +1,1495 @@
1
+ import { access, copyFile, mkdir, readdir, readFile, stat, writeFile } from "node:fs/promises";
2
+ import path from "node:path";
3
+ import { fileURLToPath } from "node:url";
4
+ import { copyDir } from "../shared/copy-dir.js";
5
+ import { loadHarnessManifest } from "../governance/harness.js";
6
+ const MANAGED_BLOCK_START = "<!-- LOOP_AGENT_INIT_START -->";
7
+ const MANAGED_BLOCK_END = "<!-- LOOP_AGENT_INIT_END -->";
8
+ const CORE_DOC_FILES = [
9
+ "README.md",
10
+ "architecture/runtime-boundaries.md",
11
+ "development-principles.md",
12
+ "feature-workflow.md",
13
+ "verification-matrix.md",
14
+ "loop-agent-harness.md",
15
+ "harness-methodology-tdd.md",
16
+ "harness-methodology-verification.md",
17
+ "harness-methodology-debugging.md",
18
+ ];
19
+ const GOVERNANCE_README_DIRS = [
20
+ "decisions",
21
+ "design",
22
+ "exec-plans",
23
+ "exec-plans/active",
24
+ "exec-plans/completed",
25
+ "progress",
26
+ "reports",
27
+ ];
28
+ const DAG_HARD_GATE_TRIGGER = "For changes that affect the project's public contract, execution surface, delivery pipeline, automation/governance, data model, security or permission model, cross-module behavior, or user-visible workflows, this is a hard pre-edit gate: create the task, write both source files, generate the DAG, and review the DAG/writeSet before editing implementation files.";
29
+ const COMPAT_PROMPTS = {
30
+ "analyze.md": [
31
+ "# Role: Task Analyst",
32
+ "",
33
+ "Read the repository entrypoints, task source materials, and relevant docs.",
34
+ "Return an analysis report covering objective, current state, affected files, constraints, risks, and open questions.",
35
+ "Do not modify files.",
36
+ "",
37
+ ].join("\n"),
38
+ "spec.md": [
39
+ "# Role: Specification Writer",
40
+ "",
41
+ "Turn the task source and analysis into a bounded implementation contract.",
42
+ "State scope, non-goals, acceptance criteria, allowed paths, forbidden paths, and verification commands.",
43
+ "Do not modify files outside task-owned artifacts.",
44
+ "",
45
+ ].join("\n"),
46
+ "plan.md": [
47
+ "# Role: Implementation Planner",
48
+ "",
49
+ "Create a minimal, ordered, verifiable implementation plan from the task source and analysis.",
50
+ "Keep the plan aligned with allowed paths, forbidden paths, hard constraints, rollback points, and verification.",
51
+ "Do not modify implementation files.",
52
+ "",
53
+ ].join("\n"),
54
+ "implement.md": [
55
+ "# Role: Bounded Implementer",
56
+ "",
57
+ "Implement the approved plan with the smallest focused change.",
58
+ "Stay within allowed paths and writeSet. Preserve unrelated user changes. Do not use placeholder implementations.",
59
+ "",
60
+ ].join("\n"),
61
+ "verify.md": [
62
+ "# Role: Verifier",
63
+ "",
64
+ "Run or specify deterministic verification for the completed change.",
65
+ "Report exact commands, pass/fail results, residual risk, and whether acceptance criteria are covered.",
66
+ "",
67
+ ].join("\n"),
68
+ "retrospective.md": [
69
+ "# Role: Retrospective Writer",
70
+ "",
71
+ "Summarize what changed, why, verification evidence, risks, and follow-up work.",
72
+ "Promote durable lessons to docs, reports, progress, tests, scripts, or templates when appropriate.",
73
+ "",
74
+ ].join("\n"),
75
+ "feature-study-analyze.md": [
76
+ "# Role: Feature Study Analyst",
77
+ "",
78
+ "Analyze configured reference repos/docs read-only. Identify architecture, state, data flow, and transferable patterns.",
79
+ "Do not edit reference repositories.",
80
+ "",
81
+ ].join("\n"),
82
+ "feature-study-plan.md": [
83
+ "# Role: Feature Study Planner",
84
+ "",
85
+ "Produce a lightweight implementation plan from the feature-study analysis.",
86
+ "Prefer simple recoverable files and verifiable increments over heavyweight storage or broad rewrites.",
87
+ "",
88
+ ].join("\n"),
89
+ };
90
+ const GOVERNANCE_ROOT_TOKEN = "__LOOP_AGENT_GOVERNANCE_ROOT__";
91
+ const INIT_CHECK_ENGINEERING_STRUCTURE_SH = `#!/usr/bin/env bash
92
+ set -euo pipefail
93
+
94
+ ROOT_DIR="$(cd "$(dirname "\${BASH_SOURCE[0]}")/.." && pwd)"
95
+ cd "\${ROOT_DIR}"
96
+
97
+ required_paths=(
98
+ "README.md"
99
+ "harness.json"
100
+ "AGENTS.md"
101
+ "${GOVERNANCE_ROOT_TOKEN}/README.md"
102
+ "${GOVERNANCE_ROOT_TOKEN}/development-principles.md"
103
+ "${GOVERNANCE_ROOT_TOKEN}/feature-workflow.md"
104
+ "${GOVERNANCE_ROOT_TOKEN}/verification-matrix.md"
105
+ "${GOVERNANCE_ROOT_TOKEN}/architecture/runtime-boundaries.md"
106
+ "${GOVERNANCE_ROOT_TOKEN}/templates"
107
+ "skills/loop-agent/SKILL.md"
108
+ ".harness/prompts/analyze.md"
109
+ ".harness/prompts/plan.md"
110
+ ".harness/tasks"
111
+ ".harness/dag-runs/active"
112
+ ".harness/dag-runs/completed"
113
+ ".harness/dag-runs/paused"
114
+ ".harness/runs/active"
115
+ ".harness/runs/completed"
116
+ ".harness/runs/failed"
117
+ "scripts/check-engineering-structure.sh"
118
+ "scripts/check-doc-index.sh"
119
+ "scripts/check-doc-links.sh"
120
+ "scripts/check-active-plan-status.sh"
121
+ "scripts/check-exec-plan-index-sync.sh"
122
+ "scripts/check-harness-runtime-clean.sh"
123
+ "scripts/check-architecture-boundaries.sh"
124
+ "scripts/check-skill-entry.sh"
125
+ "scripts/check-repo.sh"
126
+ "scripts/ci-governance.sh"
127
+ "scripts/ci-tests.sh"
128
+ "scripts/ci.sh"
129
+ )
130
+
131
+ missing=()
132
+ for item in "\${required_paths[@]}"; do
133
+ if [[ ! -e "\${item}" ]]; then
134
+ missing+=("\${item}")
135
+ fi
136
+ done
137
+
138
+ if (( \${#missing[@]} > 0 )); then
139
+ echo "loop-agent 初始化检查失败,缺少必要路径:"
140
+ for item in "\${missing[@]}"; do
141
+ echo " - \${item}"
142
+ done
143
+ exit 1
144
+ fi
145
+
146
+ echo "loop-agent 工程结构检查通过"
147
+ `;
148
+ const INIT_CHECK_DOC_INDEX_SH = `#!/usr/bin/env bash
149
+ set -euo pipefail
150
+
151
+ ROOT_DIR="$(cd "$(dirname "\${BASH_SOURCE[0]}")/.." && pwd)"
152
+ cd "\${ROOT_DIR}"
153
+
154
+ required_docs=(
155
+ "${GOVERNANCE_ROOT_TOKEN}/README.md"
156
+ "${GOVERNANCE_ROOT_TOKEN}/development-principles.md"
157
+ "${GOVERNANCE_ROOT_TOKEN}/feature-workflow.md"
158
+ "${GOVERNANCE_ROOT_TOKEN}/verification-matrix.md"
159
+ "${GOVERNANCE_ROOT_TOKEN}/architecture/runtime-boundaries.md"
160
+ "${GOVERNANCE_ROOT_TOKEN}/loop-agent-harness.md"
161
+ "${GOVERNANCE_ROOT_TOKEN}/harness-methodology-tdd.md"
162
+ "${GOVERNANCE_ROOT_TOKEN}/harness-methodology-verification.md"
163
+ "${GOVERNANCE_ROOT_TOKEN}/harness-methodology-debugging.md"
164
+ "${GOVERNANCE_ROOT_TOKEN}/templates"
165
+ "${GOVERNANCE_ROOT_TOKEN}/exec-plans/active/README.md"
166
+ "${GOVERNANCE_ROOT_TOKEN}/exec-plans/completed/README.md"
167
+ "${GOVERNANCE_ROOT_TOKEN}/progress/README.md"
168
+ "${GOVERNANCE_ROOT_TOKEN}/reports/README.md"
169
+ "${GOVERNANCE_ROOT_TOKEN}/decisions/README.md"
170
+ )
171
+
172
+ missing=()
173
+ for item in "\${required_docs[@]}"; do
174
+ if [[ ! -e "\${item}" ]]; then
175
+ missing+=("\${item}")
176
+ fi
177
+ done
178
+
179
+ if (( \${#missing[@]} > 0 )); then
180
+ echo "docs 索引检查失败,缺少必要文档或目录:" >&2
181
+ for item in "\${missing[@]}"; do
182
+ echo " - \${item}" >&2
183
+ done
184
+ exit 1
185
+ fi
186
+
187
+ echo "docs 索引检查通过"
188
+ `;
189
+ const INIT_CHECK_DOC_LINKS_SH = `#!/usr/bin/env bash
190
+ set -euo pipefail
191
+
192
+ ROOT_DIR="$(cd "$(dirname "\${BASH_SOURCE[0]}")/.." && pwd)"
193
+ cd "\${ROOT_DIR}"
194
+
195
+ if [[ ! -d "${GOVERNANCE_ROOT_TOKEN}" ]]; then
196
+ echo "docs 链接检查失败:缺少 ${GOVERNANCE_ROOT_TOKEN}/" >&2
197
+ exit 1
198
+ fi
199
+
200
+ missing=()
201
+ while IFS= read -r -d '' file; do
202
+ while IFS= read -r link; do
203
+ [[ -z "\${link}" ]] && continue
204
+ [[ "\${link}" == http://* || "\${link}" == https://* || "\${link}" == mailto:* || "\${link}" == "#"* ]] && continue
205
+ [[ "\${link}" == *"://"* ]] && continue
206
+ target="\${link%%#*}"
207
+ [[ -z "\${target}" ]] && continue
208
+ [[ "\${target}" == /* ]] && continue
209
+ base="$(dirname "\${file}")"
210
+ if [[ ! -e "\${base}/\${target}" ]]; then
211
+ missing+=("\${file}: \${link}")
212
+ fi
213
+ done < <(grep -Eo '\\[[^]]+\\]\\([^)]+\\)' "\${file}" | sed -E 's/^.*\\(([^)]+)\\)$/\\1/' || true)
214
+ done < <(find "${GOVERNANCE_ROOT_TOKEN}" -type f -name '*.md' -print0)
215
+
216
+ if (( \${#missing[@]} > 0 )); then
217
+ echo "docs 链接检查失败:" >&2
218
+ for item in "\${missing[@]}"; do
219
+ echo " - \${item}" >&2
220
+ done
221
+ exit 1
222
+ fi
223
+
224
+ echo "docs 链接检查通过"
225
+ `;
226
+ const INIT_CHECK_ACTIVE_PLAN_STATUS_SH = `#!/usr/bin/env bash
227
+ set -euo pipefail
228
+
229
+ ROOT_DIR="$(cd "$(dirname "\${BASH_SOURCE[0]}")/.." && pwd)"
230
+ cd "\${ROOT_DIR}"
231
+
232
+ active_dir="${GOVERNANCE_ROOT_TOKEN}/exec-plans/active"
233
+ [[ -d "\${active_dir}" ]] || { echo "active plan 检查失败:缺少 \${active_dir}" >&2; exit 1; }
234
+
235
+ bad=()
236
+ while IFS= read -r -d '' file; do
237
+ name="$(basename "\${file}")"
238
+ [[ "\${name}" == "README.md" ]] && continue
239
+ if grep -Eiq 'status:[[:space:]]*(completed|done|closed)|状态[::][[:space:]]*(已完成|完成|关闭)' "\${file}"; then
240
+ bad+=("\${file}")
241
+ fi
242
+ done < <(find "\${active_dir}" -maxdepth 1 -type f -name '*.md' -print0)
243
+
244
+ if (( \${#bad[@]} > 0 )); then
245
+ echo "active plan 状态检查失败:已完成计划不应留在 active 目录:" >&2
246
+ for item in "\${bad[@]}"; do
247
+ echo " - \${item}" >&2
248
+ done
249
+ exit 1
250
+ fi
251
+
252
+ echo "active plan 状态检查通过"
253
+ `;
254
+ const INIT_CHECK_EXEC_PLAN_INDEX_SYNC_SH = `#!/usr/bin/env bash
255
+ set -euo pipefail
256
+
257
+ ROOT_DIR="$(cd "$(dirname "\${BASH_SOURCE[0]}")/.." && pwd)"
258
+ cd "\${ROOT_DIR}"
259
+
260
+ required=(
261
+ "${GOVERNANCE_ROOT_TOKEN}/exec-plans/README.md"
262
+ "${GOVERNANCE_ROOT_TOKEN}/exec-plans/active/README.md"
263
+ "${GOVERNANCE_ROOT_TOKEN}/exec-plans/completed/README.md"
264
+ )
265
+
266
+ for item in "\${required[@]}"; do
267
+ if [[ ! -f "\${item}" ]]; then
268
+ echo "exec-plan 索引同步检查失败:缺少 \${item}" >&2
269
+ exit 1
270
+ fi
271
+ done
272
+
273
+ echo "exec-plan 索引同步检查通过"
274
+ `;
275
+ const INIT_CHECK_HARNESS_RUNTIME_CLEAN_SH = `#!/usr/bin/env bash
276
+ set -euo pipefail
277
+
278
+ ROOT_DIR="$(cd "$(dirname "\${BASH_SOURCE[0]}")/.." && pwd)"
279
+ cd "\${ROOT_DIR}"
280
+
281
+ failures=()
282
+
283
+ count_entries() {
284
+ local dir="$1"
285
+ if [[ ! -d "\${dir}" ]]; then
286
+ echo 0
287
+ return
288
+ fi
289
+ find "\${dir}" -mindepth 1 -maxdepth 1 ! -name .gitkeep | wc -l | tr -d ' '
290
+ }
291
+
292
+ if [[ "\${HARNESS_ALLOW_ACTIVE_DAG_RUNS:-}" != "1" ]]; then
293
+ active_dag_count="$(count_entries ".harness/dag-runs/active")"
294
+ [[ "\${active_dag_count}" == "0" ]] || failures+=(".harness/dag-runs/active contains \${active_dag_count} entries")
295
+ fi
296
+
297
+ if [[ "\${HARNESS_ALLOW_ACTIVE_TOOL_RUNS:-\${HARNESS_ALLOW_ACTIVE_ONE_SHOT_RUNS:-}}" != "1" ]]; then
298
+ active_run_count="$(count_entries ".harness/runs/active")"
299
+ [[ "\${active_run_count}" == "0" ]] || failures+=(".harness/runs/active contains \${active_run_count} entries")
300
+ fi
301
+
302
+ if [[ -d artifacts ]]; then
303
+ artifact_count="$(find artifacts -mindepth 1 -maxdepth 1 ! -name .gitkeep | wc -l | tr -d ' ')"
304
+ [[ "\${artifact_count}" == "0" ]] || failures+=("root artifacts/ contains \${artifact_count} entries; use docs/reports or .harness run artifacts")
305
+ fi
306
+
307
+ if (( \${#failures[@]} > 0 )); then
308
+ echo "[HARNESS RUNTIME DIRTY]" >&2
309
+ for item in "\${failures[@]}"; do
310
+ echo " - \${item}" >&2
311
+ done
312
+ exit 1
313
+ fi
314
+
315
+ echo "harness runtime clean check passed"
316
+ `;
317
+ const INIT_CHECK_ARCHITECTURE_BOUNDARIES_SH = `#!/usr/bin/env bash
318
+ set -euo pipefail
319
+
320
+ ROOT_DIR="$(cd "$(dirname "\${BASH_SOURCE[0]}")/.." && pwd)"
321
+ cd "\${ROOT_DIR}"
322
+
323
+ boundary_doc="${GOVERNANCE_ROOT_TOKEN}/architecture/runtime-boundaries.md"
324
+ if [[ ! -f "\${boundary_doc}" ]]; then
325
+ echo "architecture boundary 检查失败:缺少 \${boundary_doc}" >&2
326
+ exit 1
327
+ fi
328
+
329
+ violations=()
330
+
331
+ check_ts_import_boundary() {
332
+ local from_dir="$1"
333
+ local forbidden_dir="$2"
334
+ local label="$3"
335
+ [[ -d "\${from_dir}" && -d "\${forbidden_dir}" ]] || return 0
336
+ while IFS= read -r -d '' file; do
337
+ if grep -Eq "from ['\\\"][^'\\\"]*\${forbidden_dir}/|import\\(['\\\"][^'\\\"]*\${forbidden_dir}/|require\\(['\\\"][^'\\\"]*\${forbidden_dir}/" "\${file}"; then
338
+ violations+=("\${label}: \${file} imports \${forbidden_dir}")
339
+ fi
340
+ done < <(find "\${from_dir}" -type f \\( -name '*.ts' -o -name '*.tsx' -o -name '*.js' -o -name '*.jsx' -o -name '*.mjs' -o -name '*.cjs' \\) -print0)
341
+ }
342
+
343
+ # These checks are intentionally optional and stack-agnostic. They activate only
344
+ # when a target repository has recognizable source directories.
345
+ check_ts_import_boundary "src/workflows" "src/commands" "workflow-runtime"
346
+ check_ts_import_boundary "src/executors" "src/commands" "executors"
347
+ check_ts_import_boundary "src/domain" "src/infrastructure" "domain"
348
+
349
+ if (( \${#violations[@]} > 0 )); then
350
+ echo "architecture boundary 检查失败:" >&2
351
+ for item in "\${violations[@]}"; do
352
+ echo " - \${item}" >&2
353
+ done
354
+ echo "请更新 \${boundary_doc} 中的层边界,或修正反向依赖。" >&2
355
+ exit 1
356
+ fi
357
+
358
+ echo "architecture boundary 检查通过"
359
+ `;
360
+ const INIT_CHECK_SKILL_ENTRY_SH = `#!/usr/bin/env bash
361
+ set -euo pipefail
362
+
363
+ ROOT_DIR="$(cd "$(dirname "\${BASH_SOURCE[0]}")/.." && pwd)"
364
+ cd "\${ROOT_DIR}"
365
+
366
+ skill_md="skills/loop-agent/SKILL.md"
367
+ if [[ ! -f "\${skill_md}" ]]; then
368
+ echo "skill entry 检查失败:缺少 \${skill_md}" >&2
369
+ exit 1
370
+ fi
371
+
372
+ required_refs=(
373
+ "references/harness-policy.md"
374
+ "references/hybrid-dag.md"
375
+ "references/verification-and-failure-handling.md"
376
+ "references/command-reference.md"
377
+ )
378
+
379
+ missing=()
380
+ for ref in "\${required_refs[@]}"; do
381
+ [[ -f "skills/loop-agent/\${ref}" ]] || missing+=("\${ref}")
382
+ done
383
+
384
+ while IFS= read -r ref; do
385
+ [[ -z "\${ref}" ]] && continue
386
+ [[ -f "skills/loop-agent/\${ref}" ]] || missing+=("\${ref}")
387
+ done < <(grep -Eo 'references/[A-Za-z0-9._/-]+\\.md' "\${skill_md}" | sort -u || true)
388
+
389
+ if (( \${#missing[@]} > 0 )); then
390
+ echo "skill entry 检查失败:引用的 reference 文件不存在:" >&2
391
+ printf ' - %s\\n' "\${missing[@]}" >&2
392
+ exit 1
393
+ fi
394
+
395
+ line_count="$(wc -l < "\${skill_md}" | tr -d ' ')"
396
+ if [[ "\${line_count}" =~ ^[0-9]+$ && "\${line_count}" -gt 220 ]]; then
397
+ echo "skill entry 检查警告:\${skill_md} 行数为 \${line_count},建议保持入口精简并把细节放入 references/" >&2
398
+ fi
399
+
400
+ echo "skill entry 检查通过:references ok, lines=\${line_count}"
401
+ `;
402
+ const INIT_CHECK_REPO_SH = `#!/usr/bin/env bash
403
+ set -euo pipefail
404
+
405
+ ROOT_DIR="$(cd "$(dirname "\${BASH_SOURCE[0]}")/.." && pwd)"
406
+ cd "\${ROOT_DIR}"
407
+
408
+ checks=(
409
+ "scripts/check-engineering-structure.sh"
410
+ "scripts/check-doc-index.sh"
411
+ "scripts/check-doc-links.sh"
412
+ "scripts/check-active-plan-status.sh"
413
+ "scripts/check-exec-plan-index-sync.sh"
414
+ "scripts/check-harness-runtime-clean.sh"
415
+ "scripts/check-architecture-boundaries.sh"
416
+ "scripts/check-skill-entry.sh"
417
+ )
418
+
419
+ for check in "\${checks[@]}"; do
420
+ echo "==> bash \${check}"
421
+ bash "\${check}"
422
+ echo
423
+ done
424
+
425
+ echo "仓库治理检查全部通过"
426
+ `;
427
+ const INIT_CI_GOVERNANCE_SH = `#!/usr/bin/env bash
428
+ set -euo pipefail
429
+
430
+ ROOT_DIR="$(cd "$(dirname "\${BASH_SOURCE[0]}")/.." && pwd)"
431
+ cd "\${ROOT_DIR}"
432
+
433
+ bash scripts/check-repo.sh
434
+ `;
435
+ const INIT_CI_TESTS_SH = `#!/usr/bin/env bash
436
+ set -euo pipefail
437
+
438
+ ROOT_DIR="$(cd "$(dirname "\${BASH_SOURCE[0]}")/.." && pwd)"
439
+ cd "\${ROOT_DIR}"
440
+
441
+ ran=0
442
+ notes=()
443
+
444
+ run_cmd() {
445
+ echo "==> $*"
446
+ "$@"
447
+ ran=1
448
+ }
449
+
450
+ run_bash() {
451
+ echo "==> $*"
452
+ bash -lc "$*"
453
+ ran=1
454
+ }
455
+
456
+ has_make_target() {
457
+ local target="$1"
458
+ [[ -f Makefile || -f makefile ]] || return 1
459
+ grep -Eq "^[[:alnum:]_.-]*\${target}[[:alnum:]_.-]*:" Makefile makefile 2>/dev/null
460
+ }
461
+
462
+ has_npm_script() {
463
+ local script="$1"
464
+ [[ -f package.json ]] || return 1
465
+ command -v node >/dev/null 2>&1 || return 1
466
+ 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
467
+ }
468
+
469
+ if [[ -f package.json ]]; then
470
+ if command -v npm >/dev/null 2>&1; then
471
+ for script in lint typecheck test build; do
472
+ if has_npm_script "\${script}"; then
473
+ run_cmd npm run "\${script}"
474
+ fi
475
+ done
476
+ else
477
+ notes+=("package.json exists but npm is not available")
478
+ fi
479
+ fi
480
+
481
+ if has_make_target verify; then
482
+ run_cmd make verify
483
+ elif has_make_target test; then
484
+ run_cmd make test
485
+ fi
486
+
487
+ if [[ -f go.mod ]]; then
488
+ if command -v go >/dev/null 2>&1; then
489
+ run_cmd go test ./...
490
+ else
491
+ notes+=("go.mod exists but go is not available")
492
+ fi
493
+ fi
494
+
495
+ if [[ -f Cargo.toml ]]; then
496
+ if command -v cargo >/dev/null 2>&1; then
497
+ run_cmd cargo test
498
+ else
499
+ notes+=("Cargo.toml exists but cargo is not available")
500
+ fi
501
+ fi
502
+
503
+ if [[ -f pyproject.toml || -f pytest.ini || -f tox.ini ]]; then
504
+ if command -v pytest >/dev/null 2>&1; then
505
+ run_cmd pytest
506
+ elif command -v tox >/dev/null 2>&1 && [[ -f tox.ini ]]; then
507
+ run_cmd tox
508
+ else
509
+ notes+=("Python project metadata found but pytest/tox is not available")
510
+ fi
511
+ fi
512
+
513
+ if [[ -f pom.xml ]]; then
514
+ if command -v mvn >/dev/null 2>&1; then
515
+ run_cmd mvn test
516
+ else
517
+ notes+=("pom.xml exists but mvn is not available")
518
+ fi
519
+ fi
520
+
521
+ if [[ -f build.gradle || -f build.gradle.kts || -f settings.gradle || -f settings.gradle.kts ]]; then
522
+ if [[ -x ./gradlew ]]; then
523
+ run_cmd ./gradlew test
524
+ elif command -v gradle >/dev/null 2>&1; then
525
+ run_cmd gradle test
526
+ else
527
+ notes+=("Gradle project metadata found but gradle/gradlew is not available")
528
+ fi
529
+ fi
530
+
531
+ if compgen -G "*.sln" >/dev/null || compgen -G "*.csproj" >/dev/null; then
532
+ if command -v dotnet >/dev/null 2>&1; then
533
+ run_cmd dotnet test
534
+ else
535
+ notes+=(".NET project metadata found but dotnet is not available")
536
+ fi
537
+ fi
538
+
539
+ if (( ran == 0 )); then
540
+ echo "未检测到可安全自动运行的项目测试入口。"
541
+ echo "loop-agent 治理检查仍可运行;请让初始化模型根据目标项目技术栈补充 scripts/ci-tests.sh 与 docs/verification-matrix.md。"
542
+ fi
543
+
544
+ if (( \${#notes[@]} > 0 )); then
545
+ echo "项目验证探测备注:"
546
+ for note in "\${notes[@]}"; do
547
+ echo " - \${note}"
548
+ done
549
+ fi
550
+ `;
551
+ const INIT_CI_SH = `#!/usr/bin/env bash
552
+ set -euo pipefail
553
+
554
+ ROOT_DIR="$(cd "$(dirname "\${BASH_SOURCE[0]}")/.." && pwd)"
555
+ cd "\${ROOT_DIR}"
556
+
557
+ bash scripts/ci-governance.sh
558
+ bash scripts/ci-tests.sh
559
+ `;
560
+ const INIT_SCRIPT_FILES = {
561
+ "scripts/check-engineering-structure.sh": INIT_CHECK_ENGINEERING_STRUCTURE_SH,
562
+ "scripts/check-doc-index.sh": INIT_CHECK_DOC_INDEX_SH,
563
+ "scripts/check-doc-links.sh": INIT_CHECK_DOC_LINKS_SH,
564
+ "scripts/check-active-plan-status.sh": INIT_CHECK_ACTIVE_PLAN_STATUS_SH,
565
+ "scripts/check-exec-plan-index-sync.sh": INIT_CHECK_EXEC_PLAN_INDEX_SYNC_SH,
566
+ "scripts/check-harness-runtime-clean.sh": INIT_CHECK_HARNESS_RUNTIME_CLEAN_SH,
567
+ "scripts/check-architecture-boundaries.sh": INIT_CHECK_ARCHITECTURE_BOUNDARIES_SH,
568
+ "scripts/check-skill-entry.sh": INIT_CHECK_SKILL_ENTRY_SH,
569
+ "scripts/check-repo.sh": INIT_CHECK_REPO_SH,
570
+ "scripts/ci-governance.sh": INIT_CI_GOVERNANCE_SH,
571
+ "scripts/ci-tests.sh": INIT_CI_TESTS_SH,
572
+ "scripts/ci.sh": INIT_CI_SH,
573
+ };
574
+ function buildInitScriptFiles(governanceRoot) {
575
+ return Object.fromEntries(Object.entries(INIT_SCRIPT_FILES).map(([relativePath, content]) => [
576
+ relativePath,
577
+ content.replaceAll(GOVERNANCE_ROOT_TOKEN, governanceRoot),
578
+ ]));
579
+ }
580
+ function repoRelative(targetRoot, filePath) {
581
+ return path.relative(targetRoot, filePath).split(path.sep).join("/");
582
+ }
583
+ async function exists(filePath) {
584
+ return Boolean(await stat(filePath).catch(() => null));
585
+ }
586
+ async function findPackageRoot() {
587
+ let current = path.dirname(fileURLToPath(import.meta.url));
588
+ while (true) {
589
+ if (await exists(path.join(current, "package.json")))
590
+ return current;
591
+ const parent = path.dirname(current);
592
+ if (parent === current)
593
+ return path.resolve(".");
594
+ current = parent;
595
+ }
596
+ }
597
+ async function readJsonIfExists(filePath) {
598
+ if (!(await exists(filePath)))
599
+ return {};
600
+ return JSON.parse(await readFile(filePath, "utf-8"));
601
+ }
602
+ function mergeRecord(base, patch) {
603
+ return {
604
+ ...(typeof base === "object" && base !== null && !Array.isArray(base)
605
+ ? base
606
+ : {}),
607
+ ...patch,
608
+ };
609
+ }
610
+ function buildManagedAgentsBlock(input) {
611
+ return [
612
+ MANAGED_BLOCK_START,
613
+ "## loop-agent 治理",
614
+ "",
615
+ `本仓库已初始化为 \`${input.projectName}\` 的 loop-agent harness 项目。`,
616
+ "",
617
+ "### 默认立场",
618
+ "",
619
+ "- 仓库是记录系统:决策、契约、计划、验证、报告和交接应进入可追踪文件。",
620
+ "- 一次只推进一个有边界、可验证的工作块。",
621
+ "- 实现前先搜索现有代码、文档、脚本和测试,避免重复造轮子。",
622
+ "- Shell 验证是完成依据;模型建议不能替代命令证据。",
623
+ "- 保留无关的用户改动,不要回退自己没有做的修改。",
624
+ "",
625
+ "### 初始化闭环",
626
+ "",
627
+ "当用户要求在本仓库初始化 loop-agent,或发现 `README.md` / `docs/verification-matrix.md` 仍停留在通用初始化状态时,模型应在同一轮工作中完成初始化闭环,不要把补全文档和验证矩阵留给用户交互。",
628
+ "",
629
+ "标准流程:",
630
+ "",
631
+ "1. 运行 `loop-agent init instructions --repo-root .` 获取完整初始化指引。",
632
+ "2. 运行 `loop-agent init --repo-root . --profile full --merge` 完成确定性脚手架。",
633
+ "3. 立即读取目标项目的 README、manifest/build/config 文件和顶层源码/模块目录,识别项目类型、模块、运行入口和验证命令。",
634
+ "4. 基于真实项目文件补全或修正根 `README.md`、`docs/verification-matrix.md`,必要时适配 `scripts/ci-tests.sh`。",
635
+ "5. 运行 `loop-agent init doctor --repo-root .`、`loop-agent inspect --repo-root .`、`loop-agent docs audit --repo-root .` 和 quick verification。",
636
+ "",
637
+ "如果仓库信息不足,写明“尚未从仓库文件中识别到 ...”以及下一步需要的事实;不要留下泛化占位符,也不要只提示用户稍后手填。",
638
+ "",
639
+ "### 开始顺序",
640
+ "",
641
+ "改文件前先完成:",
642
+ "",
643
+ "1. 运行 `pwd`。",
644
+ "2. 阅读 `README.md`。",
645
+ "3. 阅读 `harness.json`。",
646
+ `4. 阅读 \`${input.governanceRoot}/README.md\`。`,
647
+ `5. 实现类工作继续阅读 \`${input.governanceRoot}/development-principles.md\`、\`${input.governanceRoot}/feature-workflow.md\` 和 \`${input.governanceRoot}/verification-matrix.md\`。`,
648
+ `6. 涉及测试、验证声明或调试时继续阅读 \`${input.governanceRoot}/harness-methodology-tdd.md\`、\`${input.governanceRoot}/harness-methodology-verification.md\` 和 \`${input.governanceRoot}/harness-methodology-debugging.md\`。`,
649
+ "7. 查看最近提交、相关 plan/progress/report,并检查 `git status --short --branch`。",
650
+ "8. 运行与本次任务相关的最小基线验证。",
651
+ "",
652
+ "### Agent DAG 路径",
653
+ "",
654
+ "默认使用 Agent DAG 作为实现工作流:",
655
+ "",
656
+ "```bash",
657
+ "loop-agent new-task <task-id> \"任务标题\"",
658
+ "# write .harness/tasks/<task-id>/source/需求.md",
659
+ "# write .harness/tasks/<task-id>/source/执行约束.md",
660
+ "loop-agent dag run-task <task-id> --profile auto --strict-models --output <temp-dir>/<task-id>-dag.json",
661
+ "loop-agent dag validate --dag <temp-dir>/<task-id>-dag.json --strict-models --strict-governance",
662
+ "loop-agent run-dag --dag <temp-dir>/<task-id>-dag.json --cwd .",
663
+ "```",
664
+ "",
665
+ "任务 source 是必需项。`source/需求.md` 写目标、范围、非目标、验收标准和相关链接;`source/执行约束.md` 写允许路径、禁止路径、受保护变更、不变量、预期验证和失败条件。",
666
+ "",
667
+ "凡是影响项目公共契约、执行入口、交付流水线、自动化/治理、数据模型、安全或权限模型、跨模块行为、用户可见工作流的改动,都必须在编辑实现文件前先创建任务、写好两个 source 文件、生成 DAG,并审查 DAG/writeSet。",
668
+ "",
669
+ "执行 DAG 前必须审查 profile routing、governance profile、writer 的 `writeSet`、`allowedPaths`、`forbiddenPaths`、shell verification 和 decision gate mode。不要执行占位或过宽的写入范围。",
670
+ "",
671
+ "### 运行态与 Skills",
672
+ "",
673
+ "- `.harness/tasks/` 保存任务状态和 source 材料。",
674
+ "- `.harness/dag-runs/` 与 `.harness/runs/` 保存运行事实;已完成事实只读。",
675
+ "- `skills/` 保存仓库本地 skill 指令;本地缺失时 runtime 可回退到 npm 包内置 skills。",
676
+ "- 示例内置在工具中;优先使用 `loop-agent examples list` 和 `loop-agent examples show <name>` 查看,不默认提交到目标仓库。",
677
+ "",
678
+ "### 验证",
679
+ "",
680
+ `使用 \`${input.governanceRoot}/verification-matrix.md\` 选择验证命令。常用门禁:`,
681
+ "",
682
+ "```bash",
683
+ "bash scripts/check-repo.sh",
684
+ "bash scripts/ci-governance.sh",
685
+ "bash scripts/ci-tests.sh",
686
+ "bash scripts/ci.sh",
687
+ "loop-agent inspect",
688
+ "loop-agent doctor",
689
+ "loop-agent docs audit",
690
+ "```",
691
+ "",
692
+ "`scripts/ci-tests.sh` 必须反映目标项目真实语言和工具链。初始化生成版本会保守探测常见入口;当已知项目专属命令时,应按目标项目实际情况适配。",
693
+ "",
694
+ "Windows 上运行 `scripts/*.sh` 时使用 Git Bash 或兼容 Bash。实际文件操作使用平台原生路径;`/` 仅用于稳定仓库引用、Markdown/JSON 证据引用和 glob 约定。",
695
+ "",
696
+ "### 交接",
697
+ "",
698
+ "较大的交接应说明改了什么、为什么这样改、验证命令和结果、影响到的 docs/tests/scripts/contracts、剩余风险和下一步。长期结论应进入 docs/progress、docs/reports、docs/exec-plans、docs/decisions、测试、脚本或模板。",
699
+ MANAGED_BLOCK_END,
700
+ ].join("\n");
701
+ }
702
+ function mergeManagedBlock(existing, block) {
703
+ const start = existing.indexOf(MANAGED_BLOCK_START);
704
+ const end = existing.indexOf(MANAGED_BLOCK_END);
705
+ if (start >= 0 && end > start) {
706
+ return `${existing.slice(0, start).trimEnd()}\n\n${block}\n${existing.slice(end + MANAGED_BLOCK_END.length).trimStart()}`.trimEnd() + "\n";
707
+ }
708
+ return `${existing.trimEnd()}\n\n${block}\n`;
709
+ }
710
+ function buildHarness(input) {
711
+ const modelOverride = input.provider || input.model
712
+ ? {
713
+ analyze: { provider: input.provider, model: input.model },
714
+ plan: { provider: input.provider, model: input.model },
715
+ implement: { provider: input.provider, model: input.model },
716
+ verify: { provider: input.provider, model: input.model },
717
+ retrospective: { provider: input.provider, model: input.model },
718
+ }
719
+ : undefined;
720
+ return {
721
+ ...input.existing,
722
+ version: 1,
723
+ project: input.projectName,
724
+ adapter: "loop-agent",
725
+ governanceRoot: input.governanceRoot,
726
+ features: mergeRecord(input.template.features, input.existing.features),
727
+ workflowPolicy: mergeRecord(input.template.workflowPolicy, input.existing.workflowPolicy),
728
+ entrypoints: mergeRecord(input.existing.entrypoints, {
729
+ readme: "README.md",
730
+ agents: "AGENTS.md",
731
+ governanceIndex: `${input.governanceRoot}/README.md`,
732
+ principles: `${input.governanceRoot}/development-principles.md`,
733
+ workflow: `${input.governanceRoot}/feature-workflow.md`,
734
+ verificationMatrix: `${input.governanceRoot}/verification-matrix.md`,
735
+ loopAgentHarness: `${input.governanceRoot}/loop-agent-harness.md`,
736
+ }),
737
+ artifacts: mergeRecord(input.existing.artifacts, {
738
+ templatesDir: `${input.governanceRoot}/templates`,
739
+ execPlansDir: `${input.governanceRoot}/exec-plans`,
740
+ progressDir: `${input.governanceRoot}/progress`,
741
+ reportsDir: `${input.governanceRoot}/reports`,
742
+ decisionsDir: `${input.governanceRoot}/decisions`,
743
+ }),
744
+ scripts: mergeRecord(input.existing.scripts, {
745
+ checkEngineeringStructure: "scripts/check-engineering-structure.sh",
746
+ checkDocIndex: "scripts/check-doc-index.sh",
747
+ checkDocLinks: "scripts/check-doc-links.sh",
748
+ checkActivePlanStatus: "scripts/check-active-plan-status.sh",
749
+ checkExecPlanIndexSync: "scripts/check-exec-plan-index-sync.sh",
750
+ checkHarnessRuntimeClean: "scripts/check-harness-runtime-clean.sh",
751
+ checkArchitectureBoundaries: "scripts/check-architecture-boundaries.sh",
752
+ checkSkillEntry: "scripts/check-skill-entry.sh",
753
+ checkRepo: "scripts/check-repo.sh",
754
+ ciGovernance: "scripts/ci-governance.sh",
755
+ ciTests: "scripts/ci-tests.sh",
756
+ ci: "scripts/ci.sh",
757
+ quickVerify: "bash scripts/check-repo.sh",
758
+ standardVerify: "bash scripts/ci-governance.sh",
759
+ fullVerify: "bash scripts/ci.sh",
760
+ }),
761
+ models: modelOverride ?? input.existing.models ?? input.template.models ?? {},
762
+ modelProfiles: input.existing.modelProfiles ?? input.template.modelProfiles ?? {},
763
+ modelRouting: input.existing.modelRouting ?? input.template.modelRouting ?? {},
764
+ executors: mergeRecord(input.template.executors, input.existing.executors),
765
+ };
766
+ }
767
+ async function writeTextIfMissing(input) {
768
+ const target = path.join(input.repoRoot, input.relativePath);
769
+ await mkdir(path.dirname(target), { recursive: true });
770
+ if (await exists(target)) {
771
+ input.skipped.push(input.relativePath);
772
+ return;
773
+ }
774
+ await writeFile(target, input.content, "utf-8");
775
+ input.written.push(input.relativePath);
776
+ }
777
+ async function writeText(input) {
778
+ const target = path.join(input.repoRoot, input.relativePath);
779
+ await mkdir(path.dirname(target), { recursive: true });
780
+ if (!input.merge && (await exists(target))) {
781
+ input.skipped.push(input.relativePath);
782
+ return;
783
+ }
784
+ await writeFile(target, input.content, "utf-8");
785
+ input.written.push(input.relativePath);
786
+ }
787
+ async function copyFileIfMissing(input) {
788
+ const source = path.join(input.assetRoot, input.sourceRelativePath);
789
+ const target = path.join(input.repoRoot, input.targetRelativePath);
790
+ await mkdir(path.dirname(target), { recursive: true });
791
+ if ((await exists(target)) && !input.merge) {
792
+ input.skipped.push(input.targetRelativePath);
793
+ return;
794
+ }
795
+ if (await exists(target)) {
796
+ input.skipped.push(input.targetRelativePath);
797
+ return;
798
+ }
799
+ await copyFile(source, target);
800
+ input.written.push(input.targetRelativePath);
801
+ }
802
+ async function copyDirMerge(input) {
803
+ const source = path.join(input.assetRoot, input.sourceRelativePath);
804
+ const target = path.join(input.repoRoot, input.targetRelativePath);
805
+ await copyDir(source, target);
806
+ input.written.push(input.targetRelativePath.endsWith("/") ? input.targetRelativePath : `${input.targetRelativePath}/`);
807
+ }
808
+ async function ensureHarnessDirs(repoRoot, written) {
809
+ const dirs = [
810
+ ".harness/prompts",
811
+ ".harness/tasks",
812
+ ".harness/dag-runs/active",
813
+ ".harness/dag-runs/completed",
814
+ ".harness/dag-runs/paused",
815
+ ".harness/runs/active",
816
+ ".harness/runs/completed",
817
+ ".harness/runs/failed",
818
+ ".harness/cache",
819
+ ".harness/live",
820
+ ];
821
+ for (const dir of dirs) {
822
+ await mkdir(path.join(repoRoot, dir), { recursive: true });
823
+ written.push(dir);
824
+ }
825
+ }
826
+ async function writeCompatPrompts(input) {
827
+ for (const [name, content] of Object.entries(COMPAT_PROMPTS)) {
828
+ await writeText({
829
+ repoRoot: input.repoRoot,
830
+ relativePath: path.join(".harness", "prompts", name),
831
+ content,
832
+ merge: input.merge,
833
+ written: input.written,
834
+ skipped: input.skipped,
835
+ });
836
+ }
837
+ }
838
+ function buildManagedReadmeBlock(input) {
839
+ return [
840
+ MANAGED_BLOCK_START,
841
+ "## loop-agent 治理",
842
+ "",
843
+ `本仓库已初始化为 \`${input.projectName}\` 的 loop-agent harness 项目。loop-agent 负责 Agent DAG 生成、校验、执行与收口,并保留运行态事实。下面的内容是 deterministic CLI 生成的保守入口;目标项目的具体语义(技术栈、模块、运行命令、验证命令)应由初始化模型根据实际文件补全。`,
844
+ "",
845
+ "### 项目入口",
846
+ "",
847
+ "- `README.md`(本文件):人类首次进入项目和 agent 开工的首入口,应同时覆盖项目概览与开发/验证入口。",
848
+ "- `harness.json`:loop-agent entrypoints、验证命令与 adapter 设置。",
849
+ "- `AGENTS.md`:agent 在本仓库的工作协议。",
850
+ `- \`${input.governanceRoot}/README.md\` - 治理文档索引(含原则、工作流、验证矩阵与方法论)`,
851
+ "",
852
+ "### 开发与验证入口",
853
+ "",
854
+ "开发、测试和门禁命令(按目标项目实际技术栈补全;下面是 loop-agent 治理脚本):",
855
+ "",
856
+ "```bash",
857
+ "bash scripts/check-repo.sh",
858
+ "bash scripts/ci-governance.sh",
859
+ "bash scripts/ci-tests.sh",
860
+ "bash scripts/ci.sh",
861
+ "loop-agent inspect",
862
+ "loop-agent doctor",
863
+ "loop-agent docs audit",
864
+ "```",
865
+ "",
866
+ "`scripts/ci-tests.sh` 必须反映目标项目真实语言和工具链。初始化生成版本会保守探测常见入口;当已知项目专属命令时,应按目标项目实际情况适配,并在 verification-matrix.md 中同步登记。",
867
+ "",
868
+ "### loop-agent 工作流入口",
869
+ "",
870
+ "默认使用 Agent DAG 作为实现工作流:",
871
+ "",
872
+ "```bash",
873
+ "loop-agent new-task <task-id> \"任务标题\"",
874
+ "# write .harness/tasks/<task-id>/source/需求.md",
875
+ "# write .harness/tasks/<task-id>/source/执行约束.md",
876
+ "loop-agent dag run-task <task-id> --profile auto --strict-models --output <temp-dir>/<task-id>-dag.json",
877
+ "loop-agent dag validate --dag <temp-dir>/<task-id>-dag.json --strict-models --strict-governance",
878
+ "loop-agent run-dag --dag <temp-dir>/<task-id>-dag.json --cwd .",
879
+ "```",
880
+ "",
881
+ `详细工作流见 \`${input.governanceRoot}/feature-workflow.md\`;验证矩阵见 \`${input.governanceRoot}/verification-matrix.md\`。任务 source 是必需项:\`source/需求.md\` 写目标、范围、非目标、验收标准和相关链接,\`source/执行约束.md\` 写允许路径、禁止路径、受保护变更、不变量、预期验证和失败条件。`,
882
+ "",
883
+ "### 文档导航",
884
+ "",
885
+ `- \`${input.governanceRoot}/README.md\` - 治理文档索引(含原则、工作流、验证矩阵与方法论)`,
886
+ `- \`${input.governanceRoot}/development-principles.md\` - 仓库开发原则`,
887
+ `- \`${input.governanceRoot}/architecture/runtime-boundaries.md\` - runtime 层边界与依赖方向`,
888
+ `- \`${input.governanceRoot}/feature-workflow.md\` - 有边界的功能工作流`,
889
+ `- \`${input.governanceRoot}/verification-matrix.md\` - 治理与项目专属验证命令`,
890
+ `- \`${input.governanceRoot}/loop-agent-harness.md\` - 目标项目如何使用 loop-agent`,
891
+ "- `AGENTS.md` - agent 工作协议",
892
+ "- `harness.json` - loop-agent 入口与验证命令配置",
893
+ "",
894
+ "Windows 上运行 `scripts/*.sh` 时使用 Git Bash 或兼容 Bash。实际文件操作使用平台原生路径;`/` 仅用于稳定仓库引用、Markdown/JSON 证据引用和 glob 约定。",
895
+ MANAGED_BLOCK_END,
896
+ ].join("\n");
897
+ }
898
+ function buildTargetReadme(input) {
899
+ return [
900
+ `# ${input.projectName}`,
901
+ "",
902
+ "> 本文件是项目入口。上面一行保留项目名称;下方 loop-agent managed block 由 deterministic CLI 生成。本文件正文人类可维护,用于描述项目概览、技术栈、目录结构、运行/验证命令等。初始化模型应根据目标项目实际文件补全本节正文。",
903
+ "",
904
+ "## 项目概览",
905
+ "",
906
+ "<!-- 初始化模型补充:项目是什么、解决什么问题、当前阶段。 -->",
907
+ "",
908
+ "## 技术栈与目录结构",
909
+ "",
910
+ "<!-- 初始化模型补充:语言、框架、构建工具、关键依赖与目录约定。 -->",
911
+ "",
912
+ "## 开发与验证",
913
+ "",
914
+ "<!-- 初始化模型补充:本地开发、测试、构建、门禁命令。 -->",
915
+ "",
916
+ buildManagedReadmeBlock(input),
917
+ "",
918
+ ].join("\n");
919
+ }
920
+ function buildTargetDocsReadme(input) {
921
+ return [
922
+ "# 文档索引 / Documentation Index",
923
+ "",
924
+ `本目录是 \`${input.projectName}\` 的 loop-agent 治理根目录,用于沉淀目标项目的持久工程上下文:决策、契约、计划、验证、报告与交接资料,与具体语言、框架或业务领域无关。`,
925
+ "",
926
+ `This directory is the loop-agent governance root for \`${input.projectName}\`. It records durable engineering context for the target project, independent of language, framework, or business domain.`,
927
+ "",
928
+ "## 核心文档 / Core Documents",
929
+ "",
930
+ "- `development-principles.md` - 仓库开发原则 / repository development principles",
931
+ "- `architecture/runtime-boundaries.md` - runtime 层边界与依赖方向 / runtime layer boundaries and dependency direction",
932
+ "- `feature-workflow.md` - 有边界的功能工作流 / bounded feature workflow",
933
+ "- `verification-matrix.md` - 治理与项目专属验证命令 / governance and project-specific verification commands",
934
+ "- `loop-agent-harness.md` - 目标项目如何使用 loop-agent / how this target project uses loop-agent",
935
+ "",
936
+ "## 方法论 / Methodology",
937
+ "",
938
+ "- `harness-methodology-tdd.md` - 行为变更与缺陷修复的 TDD 纪律 / TDD discipline for behavior changes and bug fixes",
939
+ "- `harness-methodology-verification.md` - 完成声明前的验证纪律 / verification discipline before completion claims",
940
+ "- `harness-methodology-debugging.md` - 修复前的系统性调试工作流 / systematic debugging workflow before fixes",
941
+ "",
942
+ "## 制品目录 / Artifacts",
943
+ "",
944
+ "- `design/README.md` - 设计笔记与实现契约 / design notes and implementation contracts",
945
+ "- `exec-plans/active/README.md` - 活跃执行计划 / active execution plans",
946
+ "- `exec-plans/completed/README.md` - 已完成执行计划 / completed execution plans",
947
+ "- `progress/README.md` - 进度交接日志 / progress handoff logs",
948
+ "- `reports/README.md` - 验证与审计报告 / verification and audit reports",
949
+ "- `decisions/README.md` - 架构决策 / architecture decisions",
950
+ "- `templates/` - 可复用的计划、报告与 DAG 模板 / reusable planning, reporting, and DAG templates",
951
+ "",
952
+ "## 验证 / Verification",
953
+ "",
954
+ "```bash",
955
+ "bash scripts/check-repo.sh",
956
+ "bash scripts/ci-tests.sh",
957
+ "bash scripts/ci.sh",
958
+ "```",
959
+ "",
960
+ "`ci-tests.sh` 刻意保持语言中立:它会探测常见的项目验证入口,初始化模型应在已知目标项目专属命令时按实际情况适配本文件。 / `ci-tests.sh` is intentionally language-neutral. It detects common project verification entrypoints and should be adapted by the initialization model when the target project has custom commands.",
961
+ "",
962
+ ].join("\n");
963
+ }
964
+ function buildTargetRuntimeBoundaries(input) {
965
+ return [
966
+ "# Runtime Boundaries",
967
+ "",
968
+ `本文定义 \`${input.projectName}\` 的 runtime 层边界、允许的依赖方向和治理检查入口。初始化版本是语言中立(language-neutral)模板;初始化模型应根据目标项目真实目录和技术栈补充具体层名、模块边界和例外。`,
969
+ "",
970
+ "## 默认分层",
971
+ "",
972
+ "```text",
973
+ "Interface / Entry layer",
974
+ " └─ CLI、HTTP API、UI 页面、job 入口或其他用户/系统入口",
975
+ "",
976
+ "Application / Use-case layer",
977
+ " └─ 一次用户意图或业务动作的编排接口",
978
+ "",
979
+ "Domain / Workflow layer",
980
+ " └─ 核心业务规则、状态机、工作流或领域模型",
981
+ "",
982
+ "Executors / Integrations layer",
983
+ " └─ 外部工具、SDK、数据库、消息队列、浏览器、模型或 shell 适配",
984
+ "",
985
+ "Infrastructure / Store layer",
986
+ " └─ 文件系统、数据库、缓存、运行事实、原子写入和生命周期副作用",
987
+ "",
988
+ "Governance layer",
989
+ " └─ scripts/check-*.sh、CI、文档审计、边界检查和验证矩阵",
990
+ "```",
991
+ "",
992
+ "## 依赖方向",
993
+ "",
994
+ "- Entry layer 可以依赖 Application / Use-case layer。",
995
+ "- Application / Use-case layer 可以依赖 Domain / Workflow、Infrastructure 和 Integrations。",
996
+ "- Domain / Workflow layer 不应依赖 Entry layer 的格式化、argv、HTTP/UI 细节。",
997
+ "- Executors / Integrations 不应依赖 Entry layer 的输出格式。",
998
+ "- Infrastructure / Store 应集中副作用,不把 raw path mutation 或持久化细节扩散给上层。",
999
+ "",
1000
+ "## 目标项目适配",
1001
+ "",
1002
+ "初始化后请根据真实项目结构补充:",
1003
+ "",
1004
+ "- 入口目录和入口文件。",
1005
+ "- 核心业务/domain/workflow 模块。",
1006
+ "- infrastructure/store/integration 模块。",
1007
+ "- 允许的例外、迁移计划和对应验证命令。",
1008
+ "",
1009
+ "## Governance hooks",
1010
+ "",
1011
+ "```bash",
1012
+ "bash scripts/check-architecture-boundaries.sh",
1013
+ "bash scripts/check-repo.sh",
1014
+ "```",
1015
+ "",
1016
+ "`scripts/check-architecture-boundaries.sh` 是保守模板:只有当目标项目存在可识别目录时才启用对应 import 检查。不要为了通过脚本删除真实边界问题;应更新本文或修正依赖方向。",
1017
+ "",
1018
+ ].join("\n");
1019
+ }
1020
+ function buildTargetDevelopmentPrinciples(input) {
1021
+ return [
1022
+ "# Development Principles",
1023
+ "",
1024
+ `\`${input.projectName}\` uses loop-agent governed development. These principles apply regardless of language, framework, or deployment model.`,
1025
+ "",
1026
+ "## Operating Stance",
1027
+ "",
1028
+ "- The repository is the record system. Decisions, contracts, plans, tests, reports, and handoffs belong in tracked files.",
1029
+ "- Work advances in small, reversible, verifiable increments.",
1030
+ "- Baseline verification comes before new work when the current state is uncertain.",
1031
+ "- Completion is defined by fresh evidence, not by intent or confidence.",
1032
+ "- Preserve unrelated user changes.",
1033
+ "",
1034
+ "## Principles",
1035
+ "",
1036
+ "1. One task advances one bounded work block.",
1037
+ "2. Search existing code, docs, scripts, and tests before designing new behavior.",
1038
+ "3. Shell verification is the completion authority.",
1039
+ "4. Runtime state belongs in `.harness/`; durable decisions belong in `docs/`.",
1040
+ "5. Model writer nodes must be bounded by explicit allowed and forbidden paths.",
1041
+ "6. Advisory model output must be followed by deterministic verification.",
1042
+ "7. Repeated constraints should become docs, tests, scripts, checks, or templates.",
1043
+ "8. Do not keep hidden process state only in chat.",
1044
+ "9. Do not add placeholders as completed implementation.",
1045
+ "10. Prefer existing local project patterns before adding new abstractions.",
1046
+ "",
1047
+ "## Target Project Adaptation",
1048
+ "",
1049
+ "The initialized scripts provide language-neutral governance. The initialization model should adapt project-specific verification commands after reading the target project's actual files and toolchain.",
1050
+ "",
1051
+ ].join("\n");
1052
+ }
1053
+ function buildTargetFeatureWorkflow(input) {
1054
+ return [
1055
+ "# Feature Workflow",
1056
+ "",
1057
+ "This document describes how work should move through this target repository using loop-agent.",
1058
+ "",
1059
+ "## Session Protocol",
1060
+ "",
1061
+ "1. Orient: read `README.md`, `harness.json`, `AGENTS.md`, and this docs index.",
1062
+ "2. Select: choose one bounded work block.",
1063
+ "3. Contract: state deliverables, non-goals, completion criteria, verification commands, and failure conditions.",
1064
+ "4. Implement: make the smallest coherent change and update required docs, scripts, and tests.",
1065
+ "5. Verify: run governance checks plus target project verification.",
1066
+ "6. Handoff: record evidence in docs/progress, docs/reports, an exec plan, or an ADR when useful.",
1067
+ "",
1068
+ "## Agent DAG Path",
1069
+ "",
1070
+ "```bash",
1071
+ "loop-agent new-task <task-id> \"Task title\"",
1072
+ "# write .harness/tasks/<task-id>/source/需求.md",
1073
+ "# write .harness/tasks/<task-id>/source/执行约束.md",
1074
+ "loop-agent dag run-task <task-id> --profile auto --strict-models --output <temp-dir>/<task-id>-dag.json",
1075
+ "loop-agent dag validate --dag <temp-dir>/<task-id>-dag.json --strict-models --strict-governance",
1076
+ "loop-agent run-dag --dag <temp-dir>/<task-id>-dag.json --cwd .",
1077
+ "```",
1078
+ "",
1079
+ DAG_HARD_GATE_TRIGGER,
1080
+ "",
1081
+ "Before executing a DAG, review profile routing, governance profile, writer writeSet, allowed paths, forbidden paths, shell verification, and decision gate mode.",
1082
+ "",
1083
+ "## Verification",
1084
+ "",
1085
+ `Use \`${input.governanceRoot}/verification-matrix.md\` to choose the narrowest command that proves the claim.`,
1086
+ "",
1087
+ ].join("\n");
1088
+ }
1089
+ function buildTargetVerificationMatrix() {
1090
+ return [
1091
+ "# Verification Matrix",
1092
+ "",
1093
+ "Use the narrowest command that proves the claim. This matrix is language-neutral: governance checks are generated by loop-agent, while project-specific checks should reflect the target project's actual toolchain.",
1094
+ "",
1095
+ "| Claim | Minimum verification | Stronger verification |",
1096
+ "|---|---|---|",
1097
+ "| loop-agent governance is valid | `bash scripts/check-repo.sh` | `bash scripts/ci-governance.sh` |",
1098
+ "| target project tests are valid | `bash scripts/ci-tests.sh` | project-specific full test/build command |",
1099
+ "| full local delivery is valid | `bash scripts/ci.sh` | add deployment/package-specific checks when relevant |",
1100
+ "| docs/governance changed | `bash scripts/check-repo.sh` | `loop-agent docs audit` plus `bash scripts/ci-governance.sh` |",
1101
+ "| model writer changed files | `git status --short` + relevant verification | `bash scripts/ci.sh` |",
1102
+ "",
1103
+ "## Generated Commands",
1104
+ "",
1105
+ "```bash",
1106
+ "bash scripts/check-engineering-structure.sh",
1107
+ "bash scripts/check-doc-index.sh",
1108
+ "bash scripts/check-doc-links.sh",
1109
+ "bash scripts/check-active-plan-status.sh",
1110
+ "bash scripts/check-exec-plan-index-sync.sh",
1111
+ "bash scripts/check-harness-runtime-clean.sh",
1112
+ "bash scripts/check-architecture-boundaries.sh",
1113
+ "bash scripts/check-skill-entry.sh",
1114
+ "bash scripts/check-repo.sh",
1115
+ "bash scripts/ci-governance.sh",
1116
+ "bash scripts/ci-tests.sh",
1117
+ "bash scripts/ci.sh",
1118
+ "```",
1119
+ "",
1120
+ "## Project-Specific Verification",
1121
+ "",
1122
+ "`scripts/ci-tests.sh` detects common entrypoints such as package.json, Makefile, go.mod, Cargo.toml, Python test metadata, Maven, Gradle, and .NET projects. If no safe command is detected, it exits successfully with a clear message so the initialization model can adapt this file to the target project.",
1123
+ "",
1124
+ "After initialization, update this matrix with the target project's actual quick, standard, and full verification commands.",
1125
+ "",
1126
+ ].join("\n");
1127
+ }
1128
+ function buildTargetLoopAgentHarness(input) {
1129
+ return [
1130
+ "# loop-agent Harness",
1131
+ "",
1132
+ `This target project, \`${input.projectName}\`, is initialized to use loop-agent for governed task execution.`,
1133
+ "",
1134
+ "## Runtime Layout",
1135
+ "",
1136
+ "- `.harness/tasks/` stores task state and source materials.",
1137
+ "- `.harness/dag-runs/` stores DAG run facts.",
1138
+ "- `.harness/runs/` stores one-shot executor facts.",
1139
+ "- `docs/` stores durable governance, plans, reports, progress, and decisions.",
1140
+ "- `skills/` stores repo-local skill instructions; the CLI can fall back to bundled skills when needed.",
1141
+ "",
1142
+ "## Default Workflow",
1143
+ "",
1144
+ "Use `loop-agent new-task`, `loop-agent dag run-task`, `loop-agent dag validate`, and `loop-agent run-dag` for non-trivial implementation work.",
1145
+ "",
1146
+ "## Script Matrix",
1147
+ "",
1148
+ "`scripts/check-repo.sh` verifies loop-agent governance. `scripts/ci-tests.sh` handles target project verification through conservative language/toolchain detection and should be adapted after reading the project.",
1149
+ "Copy or project only stack-agnostic governance scripts. For project-specific verification, packaging, release, or maintenance commands, generate the target-project version from templates plus the target repository's actual files instead of copying loop-agent's own TypeScript-specific scripts.",
1150
+ "",
1151
+ ].join("\n");
1152
+ }
1153
+ function buildGeneratedCoreDoc(input) {
1154
+ switch (input.doc) {
1155
+ case "README.md":
1156
+ return buildTargetDocsReadme({ projectName: input.projectName });
1157
+ case "architecture/runtime-boundaries.md":
1158
+ return buildTargetRuntimeBoundaries({ projectName: input.projectName });
1159
+ case "development-principles.md":
1160
+ return buildTargetDevelopmentPrinciples({ projectName: input.projectName });
1161
+ case "feature-workflow.md":
1162
+ return buildTargetFeatureWorkflow({ governanceRoot: input.governanceRoot });
1163
+ case "verification-matrix.md":
1164
+ return buildTargetVerificationMatrix();
1165
+ case "loop-agent-harness.md":
1166
+ return buildTargetLoopAgentHarness({ projectName: input.projectName });
1167
+ default:
1168
+ return undefined;
1169
+ }
1170
+ }
1171
+ function buildGovernanceDirectoryReadme(input) {
1172
+ const title = input.dir
1173
+ .split("/")
1174
+ .map((part) => part.replace(/-/g, " "))
1175
+ .join(" / ");
1176
+ return [
1177
+ `# ${title}`,
1178
+ "",
1179
+ `This directory stores ${input.projectName} governance artifacts generated during real work.`,
1180
+ "",
1181
+ "初始化只创建目录契约,不复制 loop-agent 源仓库的历史任务正文或历史索引。目标项目中的具体 plan、progress、report、decision 应由后续任务按真实执行事实生成。",
1182
+ "",
1183
+ ].join("\n");
1184
+ }
1185
+ export function buildInitInstructions(input) {
1186
+ const projectName = input.projectName ?? path.basename(path.resolve(input.repoRoot));
1187
+ const governanceRoot = input.governanceRoot ?? "docs";
1188
+ return [
1189
+ "# loop-agent Initialization Instructions",
1190
+ "",
1191
+ `Initialize the target repository as a loop-agent harness project: \`${input.repoRoot}\`.`,
1192
+ "",
1193
+ "## Confirm With User",
1194
+ "",
1195
+ `- Project name: default \`${projectName}\`.`,
1196
+ `- Governance root: default \`${governanceRoot}\`.`,
1197
+ "- Confirm provider/model. Defaults may be used, but the target project may need a different provider/model matrix.",
1198
+ "- Default: merge existing AGENTS.md, harness.json, and docs/ instead of overwriting user content.",
1199
+ "",
1200
+ "## Apply Defaults",
1201
+ "",
1202
+ "- Use the current loop-agent harness.json as the default template, but write target project name plus `adapter: \"loop-agent\"`.",
1203
+ `- ${DAG_HARD_GATE_TRIGGER}`,
1204
+ "- Generate the target project's loop-agent script matrix from templates: structure check, docs index/link checks, active plan status, exec-plan index sync, harness runtime cleanliness, architecture boundaries, skill entry integrity, governance CI, project-test CI, and full CI.",
1205
+ "- Copy or project only stack-agnostic governance scripts. For project-specific verification, packaging, release, or maintenance commands, generate the target-project version from templates plus the target repository's actual files instead of copying loop-agent's own TypeScript-specific scripts.",
1206
+ "- Do not assume the target project is TypeScript, Node.js, frontend, backend, or any other specific stack.",
1207
+ "- `scripts/ci-tests.sh` must be language-neutral: detect common project verification entrypoints conservatively, run only commands that exist, and clearly report when project-specific verification needs model/user adaptation.",
1208
+ "- Default verification entries: quick `bash scripts/check-repo.sh`, standard `bash scripts/ci-governance.sh`, full `bash scripts/ci.sh`.",
1209
+ `- Generate target-project versions of \`${governanceRoot}/README.md\`, \`${governanceRoot}/development-principles.md\`, \`${governanceRoot}/architecture/runtime-boundaries.md\`, \`${governanceRoot}/feature-workflow.md\`, \`${governanceRoot}/verification-matrix.md\`, and \`${governanceRoot}/loop-agent-harness.md\`; copy only generic methodology/template material as-is.`,
1210
+ "- After deterministic initialization, inspect README/config/build files (for example package.json, pyproject.toml, go.mod, Cargo.toml, pom.xml, Gradle files, Makefile, .sln/.csproj, or project-specific scripts) and adapt `scripts/ci-tests.sh` plus the verification matrix to the real project.",
1211
+ "- 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.",
1212
+ "- 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.",
1213
+ "- Copy repo-local skills by default so the target repo has auditable skill instructions.",
1214
+ "- Do not copy examples by default; examples stay bundled in the tool and are available through `loop-agent examples`.",
1215
+ "- Add or update a loop-agent managed block in AGENTS.md.",
1216
+ "- Create `.harness/` runtime directories but do not create historical run facts.",
1217
+ "",
1218
+ "## Automatic Workflow For Model-Executed Init",
1219
+ "",
1220
+ "When a model/agent is asked to initialize a target project, treat initialization as one automated workflow. Do not run deterministic init and then wait for another user turn to fill project-specific content.",
1221
+ "",
1222
+ "1. Resolve only the inputs that are genuinely unsafe to assume: provider/model, non-default governance root, overwrite policy, credentials, cost, or deployment side effects.",
1223
+ "2. Run deterministic init with merge defaults.",
1224
+ "3. Continue immediately into project inspection and adaptation.",
1225
+ "4. Finish by running the init health checks and quick verification.",
1226
+ "",
1227
+ "If provider/model is not specified and the existing/default harness values are usable, proceed with those defaults and record the assumption in the handoff. Ask the user only when the choice affects credentials, cost, availability, or an explicitly requested model backend.",
1228
+ "",
1229
+ "## Required Model Adaptation",
1230
+ "",
1231
+ "Do not stop after the deterministic `loop-agent init` command. When these instructions are executed by an agent/model, the initialization is not complete until the target project has been inspected and the generated scaffolding has been adapted.",
1232
+ "",
1233
+ "Required post-init steps:",
1234
+ "",
1235
+ "1. Read the target project's existing README, manifest/build/config files, and top-level source/module directories.",
1236
+ "2. Replace the root README's `初始化模型补充` comments when the information can be inferred from files. At minimum, fill project overview, technology stack/directory structure, and development/verification commands.",
1237
+ "3. Update `docs/verification-matrix.md` with the target project's actual quick, standard, and full verification commands.",
1238
+ "4. Update `scripts/ci-tests.sh` only when the conservative generated detector is insufficient for the target project.",
1239
+ "5. Run `loop-agent init doctor`, `loop-agent inspect`, `loop-agent docs audit`, and the quick verification command.",
1240
+ "",
1241
+ "Completion rule: if target files provide enough evidence, the final README should not leave generic `初始化模型补充` comments in the sections that can be filled. If a section truly cannot be inferred, write a short explicit note such as `尚未从仓库文件中识别到 ...` instead of asking the user to fill it later.",
1242
+ "",
1243
+ "## Suggested Command",
1244
+ "",
1245
+ "```bash",
1246
+ `loop-agent init --repo-root ${input.repoRoot} --profile full --merge`,
1247
+ "loop-agent init doctor --repo-root <target>",
1248
+ "loop-agent inspect --repo-root <target>",
1249
+ "loop-agent docs audit --repo-root <target>",
1250
+ "```",
1251
+ ].join("\n");
1252
+ }
1253
+ export async function initializeLoopAgentProject(options) {
1254
+ const repoRoot = path.resolve(options.repoRoot);
1255
+ const projectName = options.projectName ?? path.basename(repoRoot);
1256
+ const governanceRoot = options.governanceRoot ?? "docs";
1257
+ const profile = options.profile ?? "full";
1258
+ const merge = options.merge ?? true;
1259
+ const written = [];
1260
+ const skipped = [];
1261
+ const assetRoot = await findPackageRoot();
1262
+ const template = await readJsonIfExists(path.join(assetRoot, "harness.json"));
1263
+ const existingHarness = await readJsonIfExists(path.join(repoRoot, "harness.json"));
1264
+ await mkdir(repoRoot, { recursive: true });
1265
+ const readmePath = path.join(repoRoot, "README.md");
1266
+ const existingReadme = (await exists(readmePath)) ? await readFile(readmePath, "utf-8") : undefined;
1267
+ const readmeContent = existingReadme
1268
+ ? mergeManagedBlock(existingReadme, buildManagedReadmeBlock({ projectName, governanceRoot }))
1269
+ : buildTargetReadme({ projectName, governanceRoot });
1270
+ await writeText({
1271
+ repoRoot,
1272
+ relativePath: "README.md",
1273
+ content: readmeContent,
1274
+ merge: true,
1275
+ written,
1276
+ skipped,
1277
+ });
1278
+ const harness = buildHarness({
1279
+ existing: existingHarness,
1280
+ template,
1281
+ projectName,
1282
+ governanceRoot,
1283
+ provider: options.provider,
1284
+ model: options.model,
1285
+ });
1286
+ await writeText({
1287
+ repoRoot,
1288
+ relativePath: "harness.json",
1289
+ content: `${JSON.stringify(harness, null, 2)}\n`,
1290
+ merge: true,
1291
+ written,
1292
+ skipped,
1293
+ });
1294
+ const agentsPath = path.join(repoRoot, "AGENTS.md");
1295
+ const existingAgents = (await exists(agentsPath)) ? await readFile(agentsPath, "utf-8") : `# AGENTS.md\n`;
1296
+ await writeText({
1297
+ repoRoot,
1298
+ relativePath: "AGENTS.md",
1299
+ content: mergeManagedBlock(existingAgents, buildManagedAgentsBlock({ projectName, governanceRoot })),
1300
+ merge: true,
1301
+ written,
1302
+ skipped,
1303
+ });
1304
+ for (const doc of CORE_DOC_FILES) {
1305
+ const generated = buildGeneratedCoreDoc({ doc, projectName, governanceRoot });
1306
+ if (generated) {
1307
+ await writeTextIfMissing({
1308
+ repoRoot,
1309
+ relativePath: path.join(governanceRoot, doc),
1310
+ content: generated,
1311
+ merge,
1312
+ written,
1313
+ skipped,
1314
+ });
1315
+ continue;
1316
+ }
1317
+ await copyFileIfMissing({
1318
+ assetRoot,
1319
+ repoRoot,
1320
+ sourceRelativePath: path.join("docs", doc),
1321
+ targetRelativePath: path.join(governanceRoot, doc),
1322
+ merge,
1323
+ written,
1324
+ skipped,
1325
+ });
1326
+ }
1327
+ for (const dir of GOVERNANCE_README_DIRS) {
1328
+ await writeTextIfMissing({
1329
+ repoRoot,
1330
+ relativePath: path.join(governanceRoot, dir, "README.md"),
1331
+ content: buildGovernanceDirectoryReadme({ dir, projectName }),
1332
+ merge,
1333
+ written,
1334
+ skipped,
1335
+ });
1336
+ }
1337
+ await copyDirMerge({
1338
+ assetRoot,
1339
+ repoRoot,
1340
+ sourceRelativePath: "docs/templates",
1341
+ targetRelativePath: path.join(governanceRoot, "templates"),
1342
+ written,
1343
+ });
1344
+ if (profile === "full") {
1345
+ await copyDirMerge({
1346
+ assetRoot,
1347
+ repoRoot,
1348
+ sourceRelativePath: "skills",
1349
+ targetRelativePath: "skills",
1350
+ written,
1351
+ });
1352
+ }
1353
+ else {
1354
+ skipped.push("skills/");
1355
+ }
1356
+ skipped.push("examples/");
1357
+ for (const [relativePath, content] of Object.entries(buildInitScriptFiles(governanceRoot))) {
1358
+ await writeText({
1359
+ repoRoot,
1360
+ relativePath,
1361
+ content,
1362
+ merge: true,
1363
+ written,
1364
+ skipped,
1365
+ });
1366
+ }
1367
+ await ensureHarnessDirs(repoRoot, written);
1368
+ await writeCompatPrompts({ repoRoot, merge, written, skipped });
1369
+ return { repoRoot, projectName, governanceRoot, profile, written, skipped };
1370
+ }
1371
+ export async function runInitDoctor(input) {
1372
+ const repoRoot = path.resolve(input.repoRoot);
1373
+ const checks = [];
1374
+ const add = (name, ok, message) => checks.push({ name, ok, message });
1375
+ try {
1376
+ const manifest = await loadHarnessManifest(repoRoot);
1377
+ add("harness.json", manifest.adapter === "loop-agent" || manifest.project === "loop-agent", `project=${manifest.project}`);
1378
+ add("governance root", await exists(path.join(repoRoot, manifest.governanceRoot, "README.md")), manifest.governanceRoot);
1379
+ }
1380
+ catch (error) {
1381
+ add("harness.json", false, error instanceof Error ? error.message : String(error));
1382
+ }
1383
+ const agents = path.join(repoRoot, "AGENTS.md");
1384
+ add("AGENTS.md loop-agent block", (await exists(agents)) && (await readFile(agents, "utf-8")).includes(MANAGED_BLOCK_START), "managed block present");
1385
+ const readme = path.join(repoRoot, "README.md");
1386
+ add("README loop-agent block", (await exists(readme)) && (await readFile(readme, "utf-8")).includes(MANAGED_BLOCK_START), "managed block present");
1387
+ add("repo-local skills", await exists(path.join(repoRoot, "skills", "loop-agent", "SKILL.md")), "skills/loop-agent/SKILL.md");
1388
+ const requiredScripts = Object.keys(INIT_SCRIPT_FILES);
1389
+ const missingScripts = [];
1390
+ for (const script of requiredScripts) {
1391
+ if (!(await exists(path.join(repoRoot, script))))
1392
+ missingScripts.push(script);
1393
+ }
1394
+ add("script matrix", missingScripts.length === 0, missingScripts.length === 0 ? `${requiredScripts.length} scripts` : `missing: ${missingScripts.join(", ")}`);
1395
+ add("compat prompts", await exists(path.join(repoRoot, ".harness", "prompts", "analyze.md")) && await exists(path.join(repoRoot, ".harness", "prompts", "plan.md")), ".harness/prompts/analyze.md");
1396
+ add("harness runtime dirs", await exists(path.join(repoRoot, ".harness", "dag-runs", "active")), ".harness/dag-runs/active");
1397
+ return {
1398
+ ok: checks.every((check) => check.ok),
1399
+ repoRoot,
1400
+ checks,
1401
+ };
1402
+ }
1403
+ function parseInitArgs(repoRoot, args) {
1404
+ let subcommand;
1405
+ let projectName;
1406
+ let governanceRoot = "docs";
1407
+ let profile = "full";
1408
+ let merge = true;
1409
+ let provider;
1410
+ let model;
1411
+ let json = false;
1412
+ for (let i = 0; i < args.length; i += 1) {
1413
+ const arg = args[i];
1414
+ if ((arg === "instructions" || arg === "doctor") && !subcommand) {
1415
+ subcommand = arg;
1416
+ continue;
1417
+ }
1418
+ if (arg === "--project-name")
1419
+ projectName = args[++i];
1420
+ else if (arg.startsWith("--project-name="))
1421
+ projectName = arg.slice("--project-name=".length);
1422
+ else if (arg === "--governance-root")
1423
+ governanceRoot = args[++i] ?? governanceRoot;
1424
+ else if (arg.startsWith("--governance-root="))
1425
+ governanceRoot = arg.slice("--governance-root=".length);
1426
+ else if (arg === "--profile")
1427
+ profile = args[++i] ?? profile;
1428
+ else if (arg.startsWith("--profile="))
1429
+ profile = arg.slice("--profile=".length);
1430
+ else if (arg === "--merge")
1431
+ merge = true;
1432
+ else if (arg === "--no-merge")
1433
+ merge = false;
1434
+ else if (arg === "--provider")
1435
+ provider = args[++i];
1436
+ else if (arg.startsWith("--provider="))
1437
+ provider = arg.slice("--provider=".length);
1438
+ else if (arg === "--model")
1439
+ model = args[++i];
1440
+ else if (arg.startsWith("--model="))
1441
+ model = arg.slice("--model=".length);
1442
+ else if (arg === "--json")
1443
+ json = true;
1444
+ else if (arg.startsWith("-"))
1445
+ throw new Error(`unknown init flag: ${arg}`);
1446
+ else
1447
+ throw new Error(`unexpected init argument: ${arg}`);
1448
+ }
1449
+ if (profile !== "full" && profile !== "minimal")
1450
+ throw new Error("init --profile must be full or minimal");
1451
+ return { repoRoot, projectName, governanceRoot, profile, merge, provider, model, subcommand, json };
1452
+ }
1453
+ export async function runInit(repoRoot, rawArgs) {
1454
+ const parsed = parseInitArgs(repoRoot, rawArgs);
1455
+ if (parsed.subcommand === "instructions") {
1456
+ console.log(buildInitInstructions(parsed));
1457
+ return;
1458
+ }
1459
+ if (parsed.subcommand === "doctor") {
1460
+ const report = await runInitDoctor({ repoRoot: parsed.repoRoot });
1461
+ console.log(JSON.stringify(report, null, 2));
1462
+ if (!report.ok)
1463
+ process.exitCode = 1;
1464
+ return;
1465
+ }
1466
+ const result = await initializeLoopAgentProject(parsed);
1467
+ console.log(parsed.json ? JSON.stringify(result, null, 2) : formatInitResult(result));
1468
+ }
1469
+ function formatInitResult(result) {
1470
+ return [
1471
+ `Initialized loop-agent harness at ${result.repoRoot}`,
1472
+ `project: ${result.projectName}`,
1473
+ `governanceRoot: ${result.governanceRoot}`,
1474
+ `profile: ${result.profile}`,
1475
+ `written: ${result.written.length}`,
1476
+ `skipped: ${result.skipped.length}`,
1477
+ "next: loop-agent init doctor --repo-root <target>",
1478
+ "model-executed init: continue automatically by inspecting the target project, adapting README.md, docs/verification-matrix.md, and scripts/ci-tests.sh when needed, then run inspect/docs audit/quick verification.",
1479
+ ].join("\n");
1480
+ }
1481
+ export async function listInitializedFiles(repoRoot) {
1482
+ const files = [];
1483
+ async function walk(dir) {
1484
+ for (const entry of await readdir(dir, { withFileTypes: true })) {
1485
+ const full = path.join(dir, entry.name);
1486
+ if (entry.isDirectory())
1487
+ await walk(full);
1488
+ else
1489
+ files.push(repoRelative(repoRoot, full));
1490
+ }
1491
+ }
1492
+ await access(repoRoot);
1493
+ await walk(repoRoot);
1494
+ return files.sort();
1495
+ }