@khoavu882/doflow 2.0.0-beta.5 → 2.0.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 (471) hide show
  1. package/README.md +12 -11
  2. package/bin/doflow.js +21 -11
  3. package/core/.antigravity-plugin/plugin.json +1 -2
  4. package/core/.claude-plugin/plugin.json +1 -1
  5. package/core/.codex-plugin/plugin.json +1 -1
  6. package/core/.plugin/plugin.json +1 -1
  7. package/core/harnesses/claude/hooks/lib.sh +43 -24
  8. package/core/harnesses/claude/hooks/permission-audit.sh +3 -0
  9. package/core/harnesses/claude/hooks/post-compact.sh +35 -32
  10. package/core/harnesses/claude/hooks/post-edit-lint.sh +2 -0
  11. package/core/harnesses/claude/hooks/post-shell-observe.sh +48 -0
  12. package/core/harnesses/claude/hooks/post-tool-failure.sh +3 -0
  13. package/core/harnesses/claude/hooks/pre-compact.sh +23 -27
  14. package/core/harnesses/claude/hooks/session-end.sh +23 -10
  15. package/core/harnesses/claude/hooks/skill-config-audit.sh +3 -0
  16. package/core/harnesses/claude/settings/settings.json +18 -0
  17. package/core/harnesses/claude/statusline/doflow-statusline.sh +1 -0
  18. package/core/harnesses/codex/agents/core-implementer.toml +1 -0
  19. package/core/harnesses/codex/agents/delivery-lead.toml +10 -0
  20. package/core/harnesses/codex/agents/quality-guardian.toml +1 -1
  21. package/core/harnesses/codex/agents/research-writer.toml +1 -1
  22. package/core/harnesses/codex/agents/reviewer.toml +10 -0
  23. package/core/harnesses/codex/agents/spec-analyst.toml +1 -1
  24. package/core/harnesses/codex/agents/system-architect.toml +1 -1
  25. package/core/harnesses/codex/hooks/lib.sh +44 -25
  26. package/core/harnesses/codex/hooks/post-edit-lint.impl.sh +3 -1
  27. package/core/harnesses/codex/hooks/pre-compact.impl.sh +29 -26
  28. package/core/harnesses/codex/hooks/session-end.impl.sh +23 -10
  29. package/core/harnesses/codex/hooks/subagent-audit.sh +1 -0
  30. package/core/harnesses/copilot/hooks/doflow-lib.sh +93 -0
  31. package/core/harnesses/copilot/hooks/doflow-mcp-tool-guard.sh +9 -0
  32. package/core/harnesses/copilot/hooks/doflow-pre-bash-guard.sh +9 -0
  33. package/core/harnesses/copilot/hooks/doflow-pre-implement-gate.sh +9 -0
  34. package/core/harnesses/copilot/hooks/doflow-session-start.sh +9 -0
  35. package/core/harnesses/copilot/hooks/doflow-stop-check.sh +9 -0
  36. package/core/harnesses/copilot/hooks/doflow-subagent-start.sh +9 -0
  37. package/core/harnesses/copilot/hooks/doflow-subagent-stop.sh +9 -0
  38. package/core/harnesses/copilot/hooks/doflow.json +57 -0
  39. package/core/harnesses/kiro/agents/doflow.json +1 -1
  40. package/core/harnesses/kiro/hooks/lib.sh +26 -6
  41. package/core/harnesses/kiro/hooks/mcp-tool-guard.sh +1 -0
  42. package/core/harnesses/kiro/hooks/pre-bash-guard.sh +1 -0
  43. package/core/harnesses/kiro/hooks/pre-implement-gate.sh +1 -0
  44. package/core/harnesses/kiro/hooks/session-start.sh +1 -0
  45. package/core/harnesses/kiro/hooks/stop-check.sh +1 -0
  46. package/core/harnesses/pi/extensions/doflow-guard.js +8 -0
  47. package/core/harnesses/shared/hooks/ENVELOPE_MIGRATION.md +0 -1
  48. package/core/harnesses/shared/hooks/bridge/bridge.sh +102 -9
  49. package/core/harnesses/shared/hooks/bridge/envelope.jq +87 -18
  50. package/core/harnesses/shared/hooks/bridge/observe-model.sh +75 -0
  51. package/core/harnesses/shared/hooks/bridge/respond.sh +10 -2
  52. package/core/harnesses/shared/hooks/policies/blocked-patterns.conf +28 -14
  53. package/core/harnesses/shared/hooks/policies/capture-failure.sh +48 -15
  54. package/core/harnesses/shared/hooks/policies/compact-text.sh +46 -0
  55. package/core/harnesses/shared/hooks/policies/contract.sh +3 -0
  56. package/core/harnesses/shared/hooks/policies/deny-json.sh +2 -11
  57. package/core/harnesses/shared/hooks/policies/emission-rules.sh +37 -0
  58. package/core/harnesses/shared/hooks/policies/emission.jq +209 -0
  59. package/core/harnesses/shared/hooks/policies/emission.sh +383 -0
  60. package/core/harnesses/shared/hooks/policies/identity.sh +177 -0
  61. package/core/harnesses/shared/hooks/policies/lib.sh +63 -40
  62. package/core/harnesses/shared/hooks/policies/mcp-tool-guard.sh +3 -2
  63. package/core/harnesses/shared/hooks/policies/pre-bash-guard.sh +213 -12
  64. package/core/harnesses/shared/hooks/policies/pre-implementation-gate.sh +114 -38
  65. package/core/harnesses/shared/hooks/policies/session-context.sh +30 -1
  66. package/core/harnesses/shared/hooks/policies/stop-check.sh +20 -9
  67. package/core/harnesses/shared/hooks/policies/subagent-audit.sh +5 -2
  68. package/core/harnesses/shared/hooks/policies/summary-store.sh +347 -0
  69. package/core/harnesses/shared/hooks/policies/user-prompt-submit.sh +60 -155
  70. package/core/harnesses/shared/hooks/stream-hook-runner.js +47 -8
  71. package/core/harnesses/shared/locator/doflow-run +2 -3
  72. package/core/registry/advice.json +3 -3
  73. package/core/registry/assets.json +55 -82
  74. package/core/registry/capabilities.json +12 -0
  75. package/core/registry/contracts.json +58 -31
  76. package/core/registry/contribution-points.json +32 -0
  77. package/core/registry/gates.json +32 -0
  78. package/core/registry/guidance-caps.json +40 -0
  79. package/core/registry/harnesses.json +1442 -363
  80. package/core/registry/lifecycle.json +485 -304
  81. package/core/registry/mcp.json +5 -1
  82. package/core/registry/models.json +7 -1
  83. package/core/registry/package-templates/README.md +19 -0
  84. package/core/registry/package-templates/agent/files/agent.md +9 -0
  85. package/core/registry/package-templates/agent/template.json +4 -0
  86. package/core/registry/package-templates/capability-provider/files/provider.json +9 -0
  87. package/core/registry/package-templates/capability-provider/template.json +11 -0
  88. package/core/registry/package-templates/debate-preset/files/preset.json +26 -0
  89. package/core/registry/package-templates/debate-preset/template.json +4 -0
  90. package/core/registry/package-templates/review-preset/files/preset.json +30 -0
  91. package/core/registry/package-templates/review-preset/template.json +4 -0
  92. package/core/registry/package-templates/skill/files/SKILL.md +8 -0
  93. package/core/registry/package-templates/skill/template.json +4 -0
  94. package/core/registry/package-templates/worker/files/worker.json +92 -0
  95. package/core/registry/package-templates/worker/template.json +11 -0
  96. package/core/registry/packages/doflow/doflow-package.json +15 -0
  97. package/core/registry/packages/doflow/presets/debate-3.json +26 -0
  98. package/core/registry/protocols.json +61 -0
  99. package/core/registry/routes.json +17 -0
  100. package/core/registry/rules.json +431 -0
  101. package/core/registry/settings.json +276 -0
  102. package/core/registry/storage.json +679 -31
  103. package/core/registry/telemetry.json +236 -0
  104. package/core/registry/transcripts.json +142 -0
  105. package/core/registry/verification.json +76 -1
  106. package/core/registry/workflows.json +55 -0
  107. package/core/shared/agent-specs/core-implementer.md +3 -0
  108. package/core/shared/agent-specs/delivery-lead.md +68 -0
  109. package/core/shared/agent-specs/quality-guardian.md +5 -1
  110. package/core/shared/agent-specs/research-writer.md +10 -3
  111. package/core/shared/agent-specs/reviewer.md +53 -0
  112. package/core/shared/agent-specs/spec-analyst.md +5 -6
  113. package/core/shared/agent-specs/system-architect.md +5 -1
  114. package/core/shared/guidance/DOFLOW_CORE.md +1 -5
  115. package/core/shared/guidance/modes/MODE_DeepResearch.md +1 -1
  116. package/core/shared/guidance/modes/MODE_Orchestration.md +4 -3
  117. package/core/shared/guidance/modes/MODE_Task_Management.md +14 -14
  118. package/core/shared/guidance/pointers/codex.md +1 -4
  119. package/core/shared/guidance/references/ARTIFACT_FORMAT.md +30 -16
  120. package/core/shared/guidance/references/ARTIFACT_VOICE.md +3 -2
  121. package/core/shared/guidance/references/CONSTITUTION_BASE.md +17 -15
  122. package/core/shared/guidance/references/DIAGRAM_GUIDE.md +1 -1
  123. package/core/shared/guidance/references/DOFLOW_CHAIN.md +17 -19
  124. package/core/shared/guidance/references/EVIDENCE_LEDGER.md +7 -8
  125. package/core/shared/guidance/references/MODEL_SELECTION.md +5 -3
  126. package/core/shared/guidance/references/ORCHESTRATION.md +1 -2
  127. package/core/shared/guidance/rules/RULES.md +45 -0
  128. package/core/shared/scripts/doflow/bash/do-args.sh +37 -0
  129. package/core/shared/scripts/doflow/bash/do-exec-paths.sh +4 -0
  130. package/core/shared/scripts/doflow/bash/do-git-state.sh +15 -4
  131. package/core/shared/scripts/doflow/bash/do-parallel-check.sh +4 -0
  132. package/core/shared/scripts/doflow/bash/do-paths.sh +40 -2
  133. package/core/shared/scripts/doflow/bash/do-prereqs.sh +2 -1
  134. package/core/shared/scripts/doflow/bash/do-review-package.sh +4 -0
  135. package/core/shared/scripts/doflow/bash/do-task-brief.sh +58 -16
  136. package/core/shared/scripts/doflow/bash/render-audit.sh +26 -2
  137. package/core/shared/scripts/doflow/bash/render-diagrams.sh +1 -0
  138. package/core/shared/scripts/doflow/bash/render-puml.sh +2 -1
  139. package/core/shared/scripts/doflow/bash/validate-artifacts.sh +48 -4
  140. package/core/shared/scripts/doflow/bin/doflow-run +149 -34
  141. package/core/shared/skills/do/SKILL.md +12 -10
  142. package/core/shared/skills/do/references/advice_calls.md +26 -0
  143. package/core/shared/skills/do/references/pm_routing.md +1 -2
  144. package/core/shared/skills/do/references/program_mode.md +31 -0
  145. package/core/shared/skills/do-brainstorm/SKILL.md +20 -74
  146. package/core/shared/skills/do-brainstorm/references/handoff_branches.md +35 -0
  147. package/core/shared/skills/do-brainstorm/references/intent_seed.md +21 -0
  148. package/core/shared/skills/do-brainstorm/references/round_log.md +17 -0
  149. package/core/shared/skills/do-code-review/SKILL.md +41 -144
  150. package/core/shared/skills/do-code-review/content-types/markdown.md +24 -2
  151. package/core/shared/skills/do-code-review/references/tools.md +90 -0
  152. package/core/shared/skills/do-code-review/scripts/doc_quality_checker.py +549 -7
  153. package/core/shared/skills/do-design/SKILL.md +18 -17
  154. package/core/shared/skills/do-diagnose/SKILL.md +14 -4
  155. package/core/shared/skills/do-document/SKILL.md +11 -1
  156. package/core/shared/skills/do-document/references/deep_research.md +1 -2
  157. package/core/shared/skills/do-document/references/embedded-research.md +18 -6
  158. package/core/shared/skills/do-document/references/implementation-flow.md +5 -6
  159. package/core/shared/skills/do-execute-plan/SKILL.md +15 -58
  160. package/core/shared/skills/do-execute-plan/references/handoff_record.md +7 -2
  161. package/core/shared/skills/do-execute-plan/references/parallel_dispatch.md +13 -0
  162. package/core/shared/skills/do-execute-plan/references/readiness_gate.md +26 -1
  163. package/core/shared/skills/do-execute-plan/references/run_position.md +13 -1
  164. package/core/shared/skills/do-execute-plan/references/scaffold.md +17 -9
  165. package/core/shared/skills/do-execute-plan/references/state_checkpoint.md +11 -0
  166. package/core/shared/skills/do-execute-plan/references/task_attempts.md +78 -24
  167. package/core/shared/skills/do-flow/SKILL.md +8 -9
  168. package/core/shared/skills/do-flow/references/task_classes.md +2 -2
  169. package/core/shared/skills/do-git/SKILL.md +4 -0
  170. package/core/shared/skills/do-implement/SKILL.md +4 -7
  171. package/core/shared/skills/do-plan/SKILL.md +26 -15
  172. package/core/shared/skills/do-test/SKILL.md +7 -4
  173. package/core/shared/templates/doflow/constitution-template.md +9 -3
  174. package/core/shared/templates/doflow/data-model-template.md +1 -1
  175. package/core/shared/templates/doflow/design-template.md +113 -16
  176. package/core/shared/templates/doflow/plan-template.md +11 -10
  177. package/core/shared/templates/doflow/question-log-template.md +14 -2
  178. package/core/shared/templates/doflow/requirement-template.md +1 -1
  179. package/core/worker-evidence/antigravity/checks.json +14 -0
  180. package/core/worker-evidence/codex/2026-10-18-cli-check.json +107 -0
  181. package/core/worker-evidence/codex/2026-10-18-live-run-edit.json +73 -0
  182. package/core/worker-evidence/codex/2026-10-18-live-run-read-only.json +62 -0
  183. package/core/worker-evidence/codex/2026-10-24-cli-check.json +126 -0
  184. package/core/worker-evidence/codex/checks.json +38 -0
  185. package/package.json +10 -6
  186. package/src/adapters/antigravity/index.js +143 -66
  187. package/src/adapters/claude/index.js +24 -4
  188. package/src/adapters/codex/agents.js +25 -15
  189. package/src/adapters/codex/index.js +48 -13
  190. package/src/adapters/codex/native-projection.js +6 -2
  191. package/src/adapters/copilot/index.js +58 -23
  192. package/src/adapters/copy-tree.js +290 -44
  193. package/src/adapters/guidance-manifest.js +71 -0
  194. package/src/adapters/guidance-pointer.js +19 -0
  195. package/src/adapters/hook-commands.js +6 -10
  196. package/src/adapters/index.js +1 -0
  197. package/src/adapters/kiro/index.js +23 -12
  198. package/src/adapters/opencode/index.js +8 -8
  199. package/src/adapters/pi/hooks.js +2 -1
  200. package/src/adapters/pi/index.js +14 -7
  201. package/src/adapters/resolve-source.js +26 -2
  202. package/src/cli/commands/install.js +2 -1
  203. package/src/cli/commands/reconcile.js +53 -9
  204. package/src/cli/commands/remove.js +2 -2
  205. package/src/cli/commands/rollback.js +6 -3
  206. package/src/cli/commands/self-update.js +18 -9
  207. package/src/cli/commands/status.js +21 -2
  208. package/src/cli/commands/ui.js +99 -0
  209. package/src/cli/commands/update.js +2 -1
  210. package/src/cli/index.js +322 -29
  211. package/src/cli/runtime-commands.js +209 -57
  212. package/src/cli/shared.js +0 -2
  213. package/src/helper/git.js +1 -1
  214. package/src/helper/guardrails.js +1 -1
  215. package/src/helper/marker-merge.js +31 -13
  216. package/src/helper/package-ids.js +37 -0
  217. package/src/helper/semver.js +94 -0
  218. package/src/install/backup.js +105 -15
  219. package/src/install/context.js +1 -1
  220. package/src/install/targets.js +31 -16
  221. package/src/lifecycle/coverage.js +20 -3
  222. package/src/lifecycle/hook-tier.js +160 -0
  223. package/src/lifecycle/index.js +412 -78
  224. package/src/lifecycle/retired-harnesses.js +318 -0
  225. package/src/lifecycle/view.js +35 -15
  226. package/src/registry/index.js +551 -26
  227. package/src/registry/worker-ids.js +45 -0
  228. package/src/release/build-package.js +0 -3
  229. package/src/release/docs-blocks.js +492 -0
  230. package/src/release/preflight.js +425 -0
  231. package/src/release/rehearse.js +401 -0
  232. package/src/release/release-workflow.js +733 -0
  233. package/src/release/sync-plugin-versions.js +43 -7
  234. package/src/runtime/advice/bench-gate.js +25 -0
  235. package/src/runtime/advice/cli.js +59 -16
  236. package/src/runtime/advice/client.js +32 -9
  237. package/src/runtime/advice/config.js +98 -133
  238. package/src/runtime/advice/doctor.js +1 -1
  239. package/src/runtime/advice/elevation.js +97 -0
  240. package/src/runtime/advice/endpoint-guard.js +9 -3
  241. package/src/runtime/advice/mode.js +37 -0
  242. package/src/runtime/advice/record.js +18 -5
  243. package/src/runtime/advice/registry.js +4 -1
  244. package/src/runtime/advice/shadow-config.js +229 -0
  245. package/src/runtime/advice/shadow-dispatcher.js +276 -0
  246. package/src/runtime/brief-rules.js +81 -0
  247. package/src/runtime/brief-tools.js +111 -34
  248. package/src/runtime/candidate.js +20 -11
  249. package/src/runtime/capabilities/executor.js +450 -0
  250. package/src/runtime/capabilities/loopback.js +41 -0
  251. package/src/runtime/capabilities/sanitizer.js +88 -0
  252. package/src/runtime/capability-router.js +135 -3
  253. package/src/runtime/checkouts.js +73 -11
  254. package/src/runtime/claims.js +13 -7
  255. package/src/runtime/cli.js +196 -19
  256. package/src/runtime/config-home.js +42 -0
  257. package/src/runtime/context/arbitrate.js +767 -0
  258. package/src/runtime/context/delivery-store.js +4 -6
  259. package/src/runtime/context/emission-rules.js +118 -0
  260. package/src/runtime/context/identity.js +227 -0
  261. package/src/runtime/context/primary-command.js +117 -0
  262. package/src/runtime/context/primary.js +344 -0
  263. package/src/runtime/context/summary-store.js +655 -0
  264. package/src/runtime/context-pack.js +154 -78
  265. package/src/runtime/decision-register.js +13 -4
  266. package/src/runtime/dispatch/admission.js +392 -0
  267. package/src/runtime/dispatch/attempt-end.js +274 -0
  268. package/src/runtime/dispatch/command.js +628 -0
  269. package/src/runtime/dispatch/controls.js +904 -0
  270. package/src/runtime/dispatch/envelope.js +276 -0
  271. package/src/runtime/dispatch/grants.js +310 -0
  272. package/src/runtime/dispatch/integrate.js +617 -0
  273. package/src/runtime/dispatch/loop.js +1835 -0
  274. package/src/runtime/dispatch/store.js +352 -0
  275. package/src/runtime/dispatch/verify-run.js +201 -0
  276. package/src/runtime/evidence-ledger.js +34 -7
  277. package/src/runtime/failure/capture.js +3 -1
  278. package/src/runtime/failure/cli.js +25 -9
  279. package/src/runtime/failure/home.js +57 -30
  280. package/src/runtime/failure/store.js +7 -2
  281. package/src/runtime/feature-pointer.js +174 -0
  282. package/src/runtime/feature-resolve.js +13 -2
  283. package/src/runtime/fleet/command.js +77 -0
  284. package/src/runtime/fleet/projects.js +178 -0
  285. package/src/runtime/fleet/tree.js +383 -0
  286. package/src/runtime/freshness.js +33 -3
  287. package/src/runtime/git-memo.js +46 -0
  288. package/src/runtime/guidance/ablation.js +427 -0
  289. package/src/runtime/health.js +565 -17
  290. package/src/runtime/history-compactor.js +13 -3
  291. package/src/runtime/implementation-gate.js +277 -22
  292. package/src/runtime/inventory/coverage.js +1 -1
  293. package/src/runtime/inventory/index.js +1 -1
  294. package/src/runtime/inventory/precedence.js +2 -2
  295. package/src/runtime/inventory/siblings.js +6 -4
  296. package/src/runtime/knowledge/code-corpus.js +277 -0
  297. package/src/runtime/knowledge/code-lexical.js +130 -0
  298. package/src/runtime/knowledge/code-retrieval.js +307 -0
  299. package/src/runtime/knowledge/code-validation.js +106 -0
  300. package/src/runtime/knowledge/gp3-gate.js +74 -0
  301. package/src/runtime/knowledge/graph-adapter.js +288 -0
  302. package/src/runtime/knowledge/graph-fallback.js +394 -0
  303. package/src/runtime/knowledge/hybrid.js +136 -8
  304. package/src/runtime/knowledge/retrieval.js +34 -1
  305. package/src/runtime/knowledge/rtk-compress.js +77 -0
  306. package/src/runtime/knowledge/semble-bridge.py +106 -0
  307. package/src/runtime/knowledge/semble-lifecycle.js +114 -0
  308. package/src/runtime/knowledge/semble-provider.js +365 -0
  309. package/src/runtime/lifecycle/cli.js +16 -6
  310. package/src/runtime/lifecycle/event-store.js +8 -6
  311. package/src/runtime/lifecycle/followup.js +6 -1
  312. package/src/runtime/lifecycle/overview.js +24 -1
  313. package/src/runtime/lifecycle/report-store.js +8 -10
  314. package/src/runtime/lifecycle/retention.js +95 -31
  315. package/src/runtime/lifecycle/root.js +9 -1
  316. package/src/runtime/lifecycle/status.js +34 -17
  317. package/src/runtime/lifecycle/store-upkeep.js +56 -7
  318. package/src/runtime/mask.js +134 -7
  319. package/src/runtime/mcp-consultations.js +40 -6
  320. package/src/runtime/model-router.js +79 -7
  321. package/src/runtime/models/catalogue.js +191 -0
  322. package/src/runtime/models/command.js +153 -0
  323. package/src/runtime/off-words.js +12 -0
  324. package/src/runtime/outcome.js +2 -2
  325. package/src/runtime/packages/command.js +1009 -0
  326. package/src/runtime/packages/contributions.js +116 -0
  327. package/src/runtime/packages/digest.js +132 -0
  328. package/src/runtime/packages/fetch.js +182 -0
  329. package/src/runtime/packages/grants.js +192 -0
  330. package/src/runtime/packages/index-file.js +134 -0
  331. package/src/runtime/packages/instruction.js +90 -0
  332. package/src/runtime/packages/manifest.js +331 -0
  333. package/src/runtime/packages/points.js +477 -0
  334. package/src/runtime/packages/programs.js +216 -0
  335. package/src/runtime/packages/scaffold.js +277 -0
  336. package/src/runtime/packages/source.js +90 -0
  337. package/src/runtime/packages/state.js +164 -0
  338. package/src/runtime/packages/store.js +449 -0
  339. package/src/runtime/packages/tar.js +106 -0
  340. package/src/runtime/packages/view.js +406 -0
  341. package/src/runtime/plan-check.js +59 -0
  342. package/src/runtime/plan-content.js +324 -0
  343. package/src/runtime/policy-init.js +118 -0
  344. package/src/runtime/profiles/doctor.js +96 -0
  345. package/src/runtime/profiles/resolve.js +244 -0
  346. package/src/runtime/profiles/rollback.js +254 -0
  347. package/src/runtime/profiles/sampler.js +41 -0
  348. package/src/runtime/readiness-record.js +16 -11
  349. package/src/runtime/readiness.js +46 -5
  350. package/src/runtime/research-request.js +50 -25
  351. package/src/runtime/retrieval-plan.js +10 -30
  352. package/src/runtime/retrieval-record.js +75 -5
  353. package/src/runtime/review/command.js +246 -0
  354. package/src/runtime/review/dominance.js +68 -0
  355. package/src/runtime/review/findings.js +434 -0
  356. package/src/runtime/review/identity.js +255 -0
  357. package/src/runtime/review/protocol-command.js +109 -0
  358. package/src/runtime/review/protocols.js +405 -0
  359. package/src/runtime/review/resolve-protocol.js +302 -0
  360. package/src/runtime/review/start.js +530 -0
  361. package/src/runtime/roadmap/facts.js +479 -0
  362. package/src/runtime/roadmap/gates.js +270 -0
  363. package/src/runtime/roadmap/loop.js +1636 -0
  364. package/src/runtime/roadmap/merge.js +381 -0
  365. package/src/runtime/roadmap/rows.js +1113 -0
  366. package/src/runtime/roadmap/seed.js +951 -0
  367. package/src/runtime/rules-report.js +336 -0
  368. package/src/runtime/scaffold/artifacts.js +60 -9
  369. package/src/runtime/scaffold/generate.js +21 -9
  370. package/src/runtime/settings/autopilot.js +106 -0
  371. package/src/runtime/settings/cli.js +280 -0
  372. package/src/runtime/settings/config-write.js +314 -0
  373. package/src/runtime/settings/files.js +271 -0
  374. package/src/runtime/settings/legacy.js +154 -0
  375. package/src/runtime/settings/lexical.js +56 -0
  376. package/src/runtime/settings/prepared-run.js +269 -0
  377. package/src/runtime/settings/project-layers.js +118 -0
  378. package/src/runtime/settings/refs.js +288 -0
  379. package/src/runtime/settings/registry.js +553 -0
  380. package/src/runtime/settings/resolve.js +713 -0
  381. package/src/runtime/settings/shared.js +37 -0
  382. package/src/runtime/settings/worker-billing.js +107 -0
  383. package/src/runtime/settings/write.js +269 -0
  384. package/src/runtime/slot-command.js +78 -0
  385. package/src/runtime/slots.js +671 -0
  386. package/src/runtime/source-version.js +1 -0
  387. package/src/runtime/state-root.js +217 -0
  388. package/src/runtime/storage/cli.js +12 -5
  389. package/src/runtime/storage/engine.js +9 -2
  390. package/src/runtime/storage/registry.js +14 -1
  391. package/src/runtime/storage/roots.js +66 -16
  392. package/src/runtime/storage/rules.js +82 -10
  393. package/src/runtime/storage/upkeep.js +10 -2
  394. package/src/runtime/storage/work-status.js +245 -26
  395. package/src/runtime/task-attempts.js +589 -69
  396. package/src/runtime/task-classifier.js +47 -11
  397. package/src/runtime/task-graph.js +373 -0
  398. package/src/runtime/task-run.js +778 -0
  399. package/src/runtime/task-scope.js +176 -55
  400. package/src/runtime/task-sources.js +147 -0
  401. package/src/runtime/task-state.js +374 -64
  402. package/src/runtime/team/admission.js +301 -0
  403. package/src/runtime/team/envelope.js +324 -0
  404. package/src/runtime/team/review-guard.js +156 -0
  405. package/src/runtime/trace/analyze.js +427 -0
  406. package/src/runtime/trace/baseline.js +770 -0
  407. package/src/runtime/trace/ledger.js +63 -140
  408. package/src/runtime/trace/otlp-export.js +568 -0
  409. package/src/runtime/trace/otlp-map.js +481 -0
  410. package/src/runtime/trace/spans.js +745 -0
  411. package/src/runtime/trace/telemetry.js +225 -0
  412. package/src/runtime/trace/views.js +1 -0
  413. package/src/runtime/transcripts/command.js +98 -0
  414. package/src/runtime/transcripts/cursor.js +326 -0
  415. package/src/runtime/transcripts/read.js +126 -0
  416. package/src/runtime/transcripts/readers/claude-jsonl.js +74 -0
  417. package/src/runtime/transcripts/readers/codex-rollout.js +70 -0
  418. package/src/runtime/transcripts/readers/copilot-events.js +90 -0
  419. package/src/runtime/transcripts/readers/kiro-jsonl.js +77 -0
  420. package/src/runtime/transcripts/readers/pi-jsonl.js +59 -0
  421. package/src/runtime/transcripts/registry.js +161 -0
  422. package/src/runtime/transcripts/stats.js +161 -0
  423. package/src/runtime/verification/check-key.js +628 -0
  424. package/src/runtime/verification/contract-runner.js +546 -11
  425. package/src/runtime/verification/engine.js +499 -9
  426. package/src/runtime/verification/impact.js +617 -0
  427. package/src/runtime/verification/inflight.js +205 -0
  428. package/src/runtime/verification/registry.js +176 -0
  429. package/src/runtime/verification/reuse.js +184 -0
  430. package/src/runtime/verification/telemetry-emit.js +254 -0
  431. package/src/runtime/verification/test-selection.js +67 -7
  432. package/src/runtime/worker/active.js +90 -0
  433. package/src/runtime/worker/cancel.js +222 -0
  434. package/src/runtime/worker/catalogue.js +122 -0
  435. package/src/runtime/worker/command.js +677 -0
  436. package/src/runtime/worker/evidence.js +288 -0
  437. package/src/runtime/worker/launch.js +288 -0
  438. package/src/runtime/worker/models.js +137 -0
  439. package/src/runtime/worker/parsers.js +218 -0
  440. package/src/runtime/worker/probes/index.js +706 -0
  441. package/src/runtime/worker/process-tree.js +415 -0
  442. package/src/runtime/worker/quota.js +43 -0
  443. package/src/runtime/worker/readiness.js +713 -0
  444. package/src/runtime/worker/run-store.js +166 -0
  445. package/src/runtime/worker/supervisor.js +541 -0
  446. package/src/runtime/worker/worktree-check.js +252 -0
  447. package/src/runtime/workflow-engine.js +5 -1
  448. package/src/runtime/workflow-orchestrator.js +578 -63
  449. package/src/runtime/worktree.js +149 -22
  450. package/src/state/index.js +1 -1
  451. package/src/state/lockfile.js +64 -10
  452. package/src/state/run-lock.js +1 -1
  453. package/types/node-commonjs.d.ts +106 -7
  454. package/core/harnesses/gemini/hooks/hooks.json +0 -77
  455. package/core/harnesses/gemini/hooks/lib.sh +0 -302
  456. package/core/harnesses/gemini/hooks/mcp-tool-guard.sh +0 -10
  457. package/core/harnesses/gemini/hooks/post-edit-lint.sh +0 -39
  458. package/core/harnesses/gemini/hooks/pre-bash-guard.sh +0 -10
  459. package/core/harnesses/gemini/hooks/pre-compact.sh +0 -38
  460. package/core/harnesses/gemini/hooks/pre-implement-gate.sh +0 -10
  461. package/core/harnesses/gemini/hooks/session-end.impl.sh +0 -89
  462. package/core/harnesses/gemini/hooks/session-end.sh +0 -5
  463. package/core/harnesses/gemini/hooks/session-start.sh +0 -7
  464. package/core/harnesses/gemini/settings/adapter-defaults.json +0 -4
  465. package/core/shared/guidance/FLAGS.md +0 -25
  466. package/core/shared/guidance/rules/RULE_01_SAFETY.md +0 -25
  467. package/core/shared/guidance/rules/RULE_02_WORKFLOW.md +0 -23
  468. package/core/shared/guidance/rules/RULE_03_QUALITY.md +0 -14
  469. package/core/shared/guidance/rules/RULE_04_QUESTIONS.md +0 -46
  470. package/src/adapters/gemini/hooks.js +0 -251
  471. package/src/adapters/gemini/index.js +0 -429
@@ -0,0 +1,401 @@
1
+ 'use strict';
2
+
3
+ // Release rehearsal: runs the stages a tagged cut depends on against a clone of a committed
4
+ // revision, on the declared floor Node, with a child environment built from nothing so a result
5
+ // cannot depend on the operator's machine. It never publishes, tags, pushes or touches the
6
+ // invoking checkout. Contract: IC-001 and IC-002 of the 085a specs.
7
+ const fs = require('node:fs');
8
+ const os = require('node:os');
9
+ const path = require('node:path');
10
+ const { spawnSync } = require('node:child_process');
11
+ const { REPO_ROOT } = require('../helper/repo-root.js');
12
+
13
+ /**
14
+ * Tools linked into the child PATH when they live outside /usr/bin and /bin on the operator's
15
+ * machine. An entry needs a source showing the GitHub ubuntu and macOS runner images carry it.
16
+ * git - actions/checkout runs on every runner image, and every workflow here starts with it.
17
+ * jq - .github/workflows/drift.yml:54 calls jq on ubuntu-latest.
18
+ * python3 - .github/workflows/cross-os-tests.yml:81 states python3 is preinstalled on ubuntu-latest.
19
+ * The macOS side of each row is not confirmed by a repo file; check the macOS image readme in
20
+ * github.com/actions/runner-images before relying on it (design.md R6).
21
+ */
22
+ const RUNNER_TOOLS = ['git', 'jq', 'python3'];
23
+
24
+ const SYSTEM_PATH = ['/usr/bin', '/bin', '/usr/sbin', '/sbin'];
25
+ const SEED_COMMIT = '0864b39a';
26
+ // What each seed's expected failure must print, all of it. plantuml: with the stub removed (the
27
+ // revert) and no PlantUML on the scratch PATH, render-puml.sh exits before the splice, so the first
28
+ // test fails on design.md still holding its old block. raw-ts: Node refuses .ts under node_modules.
29
+ const SEED_SIGNATURES = {
30
+ plantuml: [
31
+ 'not ok 1 - a projector that writes to stderr does not pollute the generated block',
32
+ 'old <!-- end generated -->',
33
+ ],
34
+ 'raw-ts': ['ERR_UNSUPPORTED_NODE_MODULES_TYPE_STRIPPING'],
35
+ };
36
+ const SMOKE_TESTS = [
37
+ 'test/e2e/packed-install.e2e.test.ts',
38
+ 'test/e2e/node-floor-guard.test.ts',
39
+ 'test/e2e/compile-cache.test.ts',
40
+ 'test/e2e/install-shapes.test.ts',
41
+ ];
42
+ const MINUTE = 60 * 1000;
43
+ const USAGE = 'usage: node src/release/rehearse.js [--node <path>] [--ref <rev>] [--seed-fault plantuml|raw-ts] [--registry] [--keep]';
44
+
45
+
46
+
47
+
48
+
49
+
50
+
51
+
52
+ function parseArgs(argv ) {
53
+ const options = { node: null, ref: 'HEAD', seed: null, registry: false, keep: false };
54
+ const seen = new Set ();
55
+ for (let i = 0; i < argv.length; i++) {
56
+ const flag = argv[i];
57
+ if (!['--node', '--ref', '--seed-fault', '--registry', '--keep'].includes(flag) || seen.has(flag)) {
58
+ throw new Error(USAGE);
59
+ }
60
+ seen.add(flag);
61
+ if (flag === '--registry') {
62
+ options.registry = true;
63
+ } else if (flag === '--keep') {
64
+ options.keep = true;
65
+ } else {
66
+ const value = argv[++i];
67
+ if (!value || value.startsWith('-')) throw new Error(USAGE);
68
+ if (flag === '--node') options.node = value;
69
+ else if (flag === '--ref') options.ref = value;
70
+ else if (value === 'plantuml' || value === 'raw-ts') options.seed = value;
71
+ else throw new Error(USAGE);
72
+ }
73
+ }
74
+ return options;
75
+ }
76
+
77
+ /** Child environment built from nothing: it never spreads the parent environment. */
78
+ function ciEnv({ scratch, nodeDir, shimDir, npmCli, base = {} }
79
+
80
+ ) {
81
+ const home = path.join(scratch, 'home');
82
+ const env = {
83
+ PATH: [nodeDir, shimDir, ...SYSTEM_PATH].join(path.delimiter),
84
+ HOME: home,
85
+ USERPROFILE: home,
86
+ XDG_CONFIG_HOME: path.join(scratch, 'xdg', 'config'),
87
+ XDG_DATA_HOME: path.join(scratch, 'xdg', 'data'),
88
+ XDG_STATE_HOME: path.join(scratch, 'xdg', 'state'),
89
+ XDG_CACHE_HOME: path.join(scratch, 'xdg', 'cache'),
90
+ npm_config_cache: path.join(scratch, 'npm-cache'),
91
+ npm_config_update_notifier: 'false',
92
+ npm_config_fund: 'false',
93
+ npm_config_audit: 'false',
94
+ npm_execpath: npmCli,
95
+ CI: 'true',
96
+ TERM: 'dumb',
97
+ };
98
+ // Deep scratch paths can exceed the macOS socket path limit, so temp stays where tests expect it.
99
+ for (const key of ['TMPDIR', 'LANG']) if (base[key]) env[key] = base[key] ;
100
+ return env;
101
+ }
102
+
103
+ /** The ordered stages with their skip reasons for a seed. `seed` is a stage only in seed mode. */
104
+ function stagePlan({ seed = null } = {}) {
105
+ const only = {
106
+ plantuml: ['env', 'clone', 'seed', 'suite'],
107
+ 'raw-ts': ['env', 'clone', 'pack', 'install', 'version'],
108
+ };
109
+ const all = ['env', 'clone', 'preflight', 'seed', 'suite', 'smoke', 'build', 'pack', 'install', 'version', 'install-g', 'verb'];
110
+ const ids = seed ? all : all.filter((id) => id !== 'seed');
111
+ return ids.map((id) => {
112
+ if (!seed || only[seed].includes(id)) return { id, run: true };
113
+ return { id, run: false, reason: id === 'seed' ? 'raw-ts needs no tree change' : `not part of the ${seed} seed` };
114
+ });
115
+ }
116
+
117
+ function tail(text , stageId ) {
118
+ const allLines = text.split(/\r?\n/).filter((line, i, all) => line !== '' || i < all.length - 1);
119
+ const tailLines = allLines.slice(-40).map((line) => ` ${line}`);
120
+ if (stageId === 'suite') {
121
+ const failingTests = allLines.filter((line) => /^\s*(?:✖|not ok)\s+/.test(line)).map((line) => ` [FAIL] ${line.trim()}`);
122
+ const summaryLines = allLines.filter((line) => /^\s*(?:ℹ\s+(?:tests|pass|fail|cancelled|skipped|todo|duration_ms)|#\s+(?:tests|pass|fail))\b/.test(line)).map((line) => ` [SUMMARY] ${line.trim()}`);
123
+ const result = [];
124
+ if (failingTests.length > 0) {
125
+ result.push(' Failing test names:');
126
+ result.push(...failingTests);
127
+ }
128
+ if (summaryLines.length > 0) {
129
+ result.push(' Suite summary counts:');
130
+ result.push(...summaryLines);
131
+ }
132
+ result.push(...tailLines);
133
+ return result;
134
+ }
135
+ return tailLines;
136
+ }
137
+
138
+ /** First match of `name` on `pathVar`, as a real path. */
139
+ function findTool(name , pathVar , fsImpl ) {
140
+ for (const dir of String(pathVar || '').split(path.delimiter)) {
141
+ if (!dir) continue;
142
+ const candidate = path.join(dir, name);
143
+ if (fsImpl.existsSync(candidate)) return candidate;
144
+ }
145
+ return null;
146
+ }
147
+
148
+ function spawnRun(command , args , { cwd, env, input, timeout } ) {
149
+ const result = spawnSync(command, args, {
150
+ cwd, env, input, timeout, encoding: 'utf8', maxBuffer: 256 * 1024 * 1024,
151
+ });
152
+ return { status: result.status, stdout: result.stdout || '', stderr: result.stderr || '', error: result.error };
153
+ }
154
+
155
+ /**
156
+ * Runs the rehearsal. `run` is the only way anything is spawned; `scratchRoot` holds the scratch
157
+ * directory; `baseEnv` supplies the inherited PATH, DOFLOW_REHEARSE_NODE and npm_execpath;
158
+ * `invokingNode` is the Node used by the smoke stage and the default floor candidate.
159
+ */
160
+ function runRehearse({
161
+ repoRoot = REPO_ROOT,
162
+ options = {},
163
+ run = spawnRun,
164
+ fsImpl = fs,
165
+ scratchRoot = os.tmpdir(),
166
+ baseEnv = process.env,
167
+ invokingNode = process.execPath,
168
+ }
169
+
170
+
171
+
172
+
173
+
174
+
175
+
176
+ = {}) {
177
+ const opts = { node: null, ref: 'HEAD', seed: null, registry: false, keep: false, ...options };
178
+ const lines = [];
179
+ const envFail = (message ) => ({ exitCode: 3, lines: [...lines, `FAIL env: ${message}`] });
180
+
181
+ // env: nothing here uses the scratch directory, so a failure leaves nothing behind.
182
+ const git = run('git', ['--version'], { cwd: repoRoot, env: baseEnv });
183
+ if (git.status !== 0) return envFail('git was not found on PATH');
184
+ const pkgText = run('git', ['show', `${opts.ref}:package.json`], { cwd: repoRoot, env: baseEnv });
185
+ if (pkgText.status !== 0) return envFail(`cannot read package.json at ${opts.ref}: ${(pkgText.stderr || '').trim()}`);
186
+ let version ;
187
+ let floor ;
188
+ try {
189
+ const pkg = JSON.parse(pkgText.stdout);
190
+ version = String(pkg.version);
191
+ floor = String(pkg.engines.node).match(/\d+\.\d+\.\d+/) [0];
192
+ } catch {
193
+ return envFail(`package.json at ${opts.ref} has no engines.node floor version`);
194
+ }
195
+ const nodeBin = path.resolve(opts.node || baseEnv.DOFLOW_REHEARSE_NODE || invokingNode);
196
+ const nodeVersion = run(nodeBin, ['--version'], { env: baseEnv });
197
+ const gotVersion = nodeVersion.status === 0 ? nodeVersion.stdout.trim() : '(not runnable)';
198
+ if (gotVersion !== `v${floor}`) {
199
+ return envFail(`need Node v${floor} but ${nodeBin} is ${gotVersion}; resolve it with `
200
+ + `\`npx -y -p node@${floor} node -p process.execPath\` and pass it as --node or DOFLOW_REHEARSE_NODE`);
201
+ }
202
+ let npmCli = baseEnv.npm_execpath && fsImpl.existsSync(baseEnv.npm_execpath) ? baseEnv.npm_execpath : null;
203
+ if (!npmCli) {
204
+ const found = findTool('npm', baseEnv.PATH, fsImpl);
205
+ if (found) npmCli = fsImpl.realpathSync(found);
206
+ }
207
+ if (!npmCli) return envFail('no npm CLI was found (set npm_execpath or put npm on PATH)');
208
+ lines.push(`PASS env: Node v${floor} at ${nodeBin}, npm ${npmCli}, package version ${version}`);
209
+
210
+ const scratch = fsImpl.mkdtempSync(path.join(scratchRoot, 'doflow-rehearse-'));
211
+ const dir = (name ) => path.join(scratch, name);
212
+ const shimDir = dir('bin');
213
+ for (const sub of ['home', 'xdg/config', 'xdg/data', 'xdg/state', 'xdg/cache', 'npm-cache', 'bin', 'project', 'tarballs']) {
214
+ fsImpl.mkdirSync(dir(sub), { recursive: true });
215
+ }
216
+ fsImpl.writeFileSync(path.join(shimDir, 'npm'), `#!/bin/sh\nexec node ${JSON.stringify(npmCli)} "$@"\n`, { mode: 0o755 });
217
+ for (const tool of RUNNER_TOOLS) {
218
+ if (SYSTEM_PATH.slice(0, 2).some((d) => fsImpl.existsSync(path.join(d, tool)))) continue;
219
+ const found = findTool(tool, baseEnv.PATH, fsImpl);
220
+ if (found) fsImpl.symlinkSync(found, path.join(shimDir, tool));
221
+ }
222
+
223
+ const clone = dir('repo');
224
+ const prefix = dir('prefix');
225
+ // The child PATH gets a directory holding only a `node` link, never the folder the binary lives
226
+ // in: that folder (Homebrew bin, ~/.local/bin) carries unrelated tools such as plantuml and jq.
227
+ const nodeShim = (name , binary ) => {
228
+ const shim = dir(name);
229
+ fsImpl.mkdirSync(shim, { recursive: true });
230
+ fsImpl.symlinkSync(binary, path.join(shim, 'node'));
231
+ return shim;
232
+ };
233
+ const floorEnv = ciEnv({ scratch, nodeDir: nodeShim('node-floor', nodeBin), shimDir, npmCli, base: baseEnv });
234
+ const invokingEnv = ciEnv({ scratch, nodeDir: nodeShim('node-invoking', invokingNode), shimDir, npmCli, base: baseEnv });
235
+ let sha = '';
236
+ let tarball = '';
237
+ let packSource = dir('stage');
238
+
239
+ const child = (command , args , {
240
+ cwd = clone, env = floorEnv, input, timeout = 5 * MINUTE,
241
+ } = {}) => {
242
+ const result = run(command, args, { cwd, env, input, timeout });
243
+ const output = `${result.stdout || ''}${result.stderr || ''}`;
244
+ if (result.error) {
245
+ const timedOut = result.error.code === 'ETIMEDOUT';
246
+ return {
247
+ ok: false, output, stdout: result.stdout || '', kind: timedOut ? 'timeout' : 'spawn',
248
+ message: timedOut ? `timed out after ${Math.round(timeout / MINUTE)} min` : `could not run ${command}: ${result.error.message}`,
249
+ };
250
+ }
251
+ if (result.status !== 0) return { ok: false, output, stdout: result.stdout || '', kind: 'exit', message: `exit ${result.status}` };
252
+ return { ok: true, output, stdout: result.stdout || '', message: 'exit 0' };
253
+ };
254
+ const failed = (c , what ) => (
255
+ { ok: false, message: `${what}: ${c.message}`, output: c.output, kind: c.kind }
256
+ );
257
+ const nodeNpm = (args , options = {}) => child(nodeBin, [npmCli , ...args], options);
258
+
259
+ const stages = {
260
+ clone: () => {
261
+ const rev = child('git', ['rev-parse', '--verify', `${opts.ref}^{commit}`], { cwd: repoRoot });
262
+ if (!rev.ok) return failed(rev, `cannot resolve ${opts.ref}`);
263
+ sha = rev.output.trim();
264
+ const cloned = child('git', ['clone', '--quiet', '--no-local', repoRoot, clone], { cwd: scratch });
265
+ if (!cloned.ok) return failed(cloned, 'git clone');
266
+ const checkout = child('git', ['-C', clone, 'checkout', '--quiet', '--detach', sha], { cwd: scratch });
267
+ if (!checkout.ok) return failed(checkout, 'git checkout');
268
+ return { ok: true, message: `${opts.ref} is ${sha.slice(0, 12)}, cloned to ${clone}` };
269
+ },
270
+ preflight: () => {
271
+ const c = child(nodeBin, ['src/release/preflight.js', ...(opts.registry ? [] : ['--offline'])]);
272
+ return c.ok ? { ok: true, message: opts.registry ? 'preflight passed' : 'preflight passed (--offline)' } : failed(c, 'preflight');
273
+ },
274
+ seed: () => {
275
+ const c = child('git', ['revert', '--no-commit', SEED_COMMIT]);
276
+ if (c.ok) return { ok: true, message: `reverted ${SEED_COMMIT} in the clone` };
277
+ return { ...failed(c, `cannot apply seed plantuml (revert of ${SEED_COMMIT})`), fatal: true };
278
+ },
279
+ suite: () => {
280
+ const seeded = opts.seed === 'plantuml';
281
+ const c = child(nodeBin, ['--test', ...(seeded ? ['test/runtime/render-puml-stderr.test.ts'] : ['test/**/*.test.ts'])], { timeout: seeded ? 5 * MINUTE : 45 * MINUTE });
282
+ if (c.ok) return { ok: true, message: seeded ? 'render-puml-stderr passed' : 'test suite passed' };
283
+ return failed(c, seeded ? 'render-puml-stderr' : 'test suite');
284
+ },
285
+ smoke: () => {
286
+ const c = child(invokingNode, ['--test', ...SMOKE_TESTS], { env: invokingEnv });
287
+ return c.ok ? { ok: true, message: `${SMOKE_TESTS.length} files passed on the invoking Node` } : failed(c, 'smoke tests');
288
+ },
289
+ build: () => {
290
+ const c = child(nodeBin, ['src/release/build-package.js', packSource]);
291
+ return c.ok ? { ok: true, message: `built ${packSource}` } : failed(c, 'build-package');
292
+ },
293
+ pack: () => {
294
+ if (opts.seed === 'raw-ts') packSource = clone;
295
+ const c = nodeNpm(['pack', packSource, '--pack-destination', dir('tarballs')]);
296
+ if (!c.ok) return failed(c, 'npm pack');
297
+ // npm prints the tarball name alone on stdout; its `npm notice filename:` line is on stderr.
298
+ const names = [...new Set(c.stdout.split(/\r?\n/).map((l) => l.trim()).filter((l) => l.endsWith('.tgz')))];
299
+ if (names.length !== 1) return { ok: false, message: `npm pack printed ${names.length} tarballs, expected 1`, output: c.output, kind: 'exit' };
300
+ tarball = path.join(dir('tarballs'), path.basename(names[0]));
301
+ return { ok: true, message: `packed ${path.basename(tarball)} from ${packSource}` };
302
+ },
303
+ install: () => {
304
+ const c = nodeNpm(['install', '--offline', '--prefix', prefix, tarball], { cwd: dir('project') });
305
+ return c.ok ? { ok: true, message: `installed into ${prefix}` } : failed(c, 'npm install');
306
+ },
307
+ version: () => {
308
+ const c = child(path.join(prefix, 'node_modules', '.bin', 'doflow'), ['--version'], { cwd: dir('project') });
309
+ if (!c.ok) return failed(c, 'doflow --version');
310
+ const got = c.stdout.trim();
311
+ return got === version ? { ok: true, message: `doflow --version is ${got}` }
312
+ : { ok: false, message: `doflow --version printed ${JSON.stringify(got)}, expected ${version}`, output: c.output, kind: 'exit' };
313
+ },
314
+ 'install-g': () => {
315
+ const c = child(path.join(prefix, 'node_modules', '.bin', 'doflow'), ['install', '-g', '-f', '--no-backup', '-t', 'claude'], { cwd: dir('project'), input: '\n' });
316
+ return c.ok ? { ok: true, message: 'global install into the scratch HOME passed' } : failed(c, 'doflow install -g');
317
+ },
318
+ verb: () => {
319
+ const c = child('bash', [path.join(dir('home'), '.claude', 'bin', 'doflow-run'), 'paths', '--json'], { cwd: dir('project') });
320
+ if (!c.ok) return failed(c, 'doflow-run paths');
321
+ try {
322
+ JSON.parse(c.stdout);
323
+ } catch {
324
+ return { ok: false, message: 'doflow-run paths --json did not print JSON', output: c.output, kind: 'exit' };
325
+ }
326
+ return { ok: true, message: 'doflow-run paths --json printed JSON' };
327
+ },
328
+ };
329
+
330
+ const outcomes = new Map ();
331
+ let chainFailed = null;
332
+ let anyFail = false;
333
+ let fatal = false;
334
+ for (const stage of stagePlan({ seed: opts.seed })) {
335
+ if (stage.id === 'env') continue;
336
+ if (!stage.run) {
337
+ lines.push(`SKIP ${stage.id}: ${stage.reason}`);
338
+ continue;
339
+ }
340
+ if (chainFailed) {
341
+ lines.push(`SKIP ${stage.id}: after ${chainFailed} failed`);
342
+ continue;
343
+ }
344
+ const result = stages[stage.id]();
345
+ outcomes.set(stage.id, { id: stage.id, status: result.ok ? 'PASS' : 'FAIL', output: result.output || '', kind: result.kind });
346
+ lines.push(`${result.ok ? 'PASS' : 'FAIL'} ${stage.id}: ${result.message}`);
347
+ if (!result.ok) {
348
+ anyFail = true;
349
+ if (result.output) lines.push(...tail(result.output, stage.id));
350
+ if (stage.id !== 'preflight') chainFailed = stage.id;
351
+ if (result.fatal) fatal = true;
352
+ }
353
+ }
354
+
355
+ let exitCode ;
356
+ if (fatal) {
357
+ exitCode = 3;
358
+ } else if (opts.seed) {
359
+ const expected = opts.seed === 'plantuml' ? 'suite' : 'version';
360
+ const got = outcomes.get(expected);
361
+ const missing = got ? SEED_SIGNATURES[opts.seed].filter((part) => !got.output.includes(part)) : [];
362
+ const reproduced = Boolean(got && got.status === 'FAIL' && got.kind === 'exit' && missing.length === 0);
363
+ if (reproduced) {
364
+ lines.push(`SEED reproduced: ${opts.seed} failed at ${expected}`);
365
+ } else {
366
+ let outcome ;
367
+ if (!got) outcome = `FAIL at ${chainFailed}`;
368
+ else if (got.status === 'PASS') outcome = 'PASS';
369
+ else if (got.kind !== 'exit') outcome = `FAIL (${got.kind})`;
370
+ else outcome = `FAIL without ${missing[0]}`;
371
+ lines.push(`SEED not reproduced: ${opts.seed} expected ${expected}, got ${outcome}`);
372
+ }
373
+ exitCode = reproduced ? 0 : 1;
374
+ } else {
375
+ exitCode = anyFail ? 1 : 0;
376
+ }
377
+
378
+ if (exitCode === 0 && !opts.keep) {
379
+ fsImpl.rmSync(scratch, { recursive: true, force: true });
380
+ } else {
381
+ lines.push(`scratch: ${scratch}`);
382
+ }
383
+ return { exitCode, lines };
384
+ }
385
+
386
+ if (require.main === module) {
387
+ let options ;
388
+ try {
389
+ options = parseArgs(process.argv.slice(2));
390
+ } catch (error ) {
391
+ process.stderr.write(`${error.message}\n`);
392
+ process.exitCode = 2;
393
+ }
394
+ if (options) {
395
+ const result = runRehearse({ options });
396
+ process.stdout.write(`${result.lines.join('\n')}\n`);
397
+ process.exitCode = result.exitCode;
398
+ }
399
+ }
400
+
401
+ module.exports = { RUNNER_TOOLS, parseArgs, ciEnv, stagePlan, runRehearse };