@khoavu882/doflow 2.0.0-beta.5 → 2.0.1

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 (494) hide show
  1. package/README.md +16 -16
  2. package/bin/doflow.js +22 -12
  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/mcp-tool-guard.sh +4 -1
  9. package/core/harnesses/claude/hooks/permission-audit.sh +3 -0
  10. package/core/harnesses/claude/hooks/post-compact.sh +35 -32
  11. package/core/harnesses/claude/hooks/post-edit-lint.sh +2 -0
  12. package/core/harnesses/claude/hooks/post-shell-observe.sh +48 -0
  13. package/core/harnesses/claude/hooks/post-tool-failure.sh +3 -0
  14. package/core/harnesses/claude/hooks/pre-compact.sh +23 -27
  15. package/core/harnesses/claude/hooks/pre-implement-gate.sh +4 -1
  16. package/core/harnesses/claude/hooks/session-end.sh +23 -10
  17. package/core/harnesses/claude/hooks/skill-config-audit.sh +3 -0
  18. package/core/harnesses/claude/settings/settings.json +26 -9
  19. package/core/harnesses/claude/statusline/doflow-statusline.sh +1 -0
  20. package/core/harnesses/codex/agents/core-implementer.toml +1 -0
  21. package/core/harnesses/codex/agents/delivery-lead.toml +10 -0
  22. package/core/harnesses/codex/agents/quality-guardian.toml +1 -1
  23. package/core/harnesses/codex/agents/research-writer.toml +1 -1
  24. package/core/harnesses/codex/agents/reviewer.toml +10 -0
  25. package/core/harnesses/codex/agents/spec-analyst.toml +1 -1
  26. package/core/harnesses/codex/agents/system-architect.toml +1 -1
  27. package/core/harnesses/codex/hooks/hooks.json +0 -10
  28. package/core/harnesses/codex/hooks/lib.sh +44 -25
  29. package/core/harnesses/codex/hooks/mcp-tool-guard.sh +4 -1
  30. package/core/harnesses/codex/hooks/post-edit-lint.impl.sh +3 -1
  31. package/core/harnesses/codex/hooks/pre-compact.impl.sh +29 -26
  32. package/core/harnesses/codex/hooks/pre-implement-gate.sh +4 -1
  33. package/core/harnesses/codex/hooks/session-end.impl.sh +23 -10
  34. package/core/harnesses/codex/hooks/subagent-audit.sh +1 -0
  35. package/core/harnesses/copilot/hooks/doflow-lib.sh +94 -0
  36. package/core/harnesses/copilot/hooks/doflow-mcp-tool-guard.sh +9 -0
  37. package/core/harnesses/copilot/hooks/doflow-pre-implement-gate.sh +9 -0
  38. package/core/harnesses/copilot/hooks/doflow-session-start.sh +9 -0
  39. package/core/harnesses/copilot/hooks/doflow-stop-check.sh +9 -0
  40. package/core/harnesses/copilot/hooks/doflow-subagent-start.sh +9 -0
  41. package/core/harnesses/copilot/hooks/doflow-subagent-stop.sh +9 -0
  42. package/core/harnesses/copilot/hooks/doflow.json +51 -0
  43. package/core/harnesses/kiro/agents/doflow.json +1 -11
  44. package/core/harnesses/kiro/hooks/doflow.json +0 -10
  45. package/core/harnesses/kiro/hooks/lib.sh +26 -6
  46. package/core/harnesses/kiro/hooks/mcp-tool-guard.sh +8 -3
  47. package/core/harnesses/kiro/hooks/pre-implement-gate.sh +8 -3
  48. package/core/harnesses/kiro/hooks/session-start.sh +1 -0
  49. package/core/harnesses/kiro/hooks/stop-check.sh +1 -0
  50. package/core/harnesses/pi/extensions/doflow-guard.js +11 -2
  51. package/core/harnesses/shared/hooks/ENVELOPE_MIGRATION.md +1 -2
  52. package/core/harnesses/shared/hooks/adapters/antigravity.js +1 -1
  53. package/core/harnesses/shared/hooks/bridge/bridge.sh +126 -23
  54. package/core/harnesses/shared/hooks/bridge/envelope.jq +87 -18
  55. package/core/harnesses/shared/hooks/bridge/observe-model.sh +75 -0
  56. package/core/harnesses/shared/hooks/bridge/respond.sh +16 -2
  57. package/core/harnesses/shared/hooks/policies/capture-failure.sh +49 -16
  58. package/core/harnesses/shared/hooks/policies/compact-text.sh +46 -0
  59. package/core/harnesses/shared/hooks/policies/contract.sh +3 -0
  60. package/core/harnesses/shared/hooks/policies/deny-json.sh +20 -7
  61. package/core/harnesses/shared/hooks/policies/emission-rules.sh +37 -0
  62. package/core/harnesses/shared/hooks/policies/emission.jq +209 -0
  63. package/core/harnesses/shared/hooks/policies/emission.sh +383 -0
  64. package/core/harnesses/shared/hooks/policies/identity.sh +177 -0
  65. package/core/harnesses/shared/hooks/policies/lib.sh +63 -40
  66. package/core/harnesses/shared/hooks/policies/mcp-policy.conf +1 -1
  67. package/core/harnesses/shared/hooks/policies/mcp-tool-guard.sh +7 -8
  68. package/core/harnesses/shared/hooks/policies/pre-implementation-gate.sh +132 -57
  69. package/core/harnesses/shared/hooks/policies/session-context.sh +30 -1
  70. package/core/harnesses/shared/hooks/policies/stop-check.sh +27 -15
  71. package/core/harnesses/shared/hooks/policies/subagent-audit.sh +6 -3
  72. package/core/harnesses/shared/hooks/policies/summary-store.sh +347 -0
  73. package/core/harnesses/shared/hooks/policies/user-prompt-submit.sh +60 -155
  74. package/core/harnesses/shared/hooks/stream-hook-runner.js +58 -20
  75. package/core/harnesses/shared/locator/doflow-run +2 -3
  76. package/core/registry/advice.json +3 -3
  77. package/core/registry/assets.json +55 -82
  78. package/core/registry/capabilities.json +12 -0
  79. package/core/registry/contracts.json +58 -31
  80. package/core/registry/contribution-points.json +35 -0
  81. package/core/registry/gates.json +32 -0
  82. package/core/registry/guidance-caps.json +40 -0
  83. package/core/registry/harnesses.json +1445 -366
  84. package/core/registry/intake.json +53 -0
  85. package/core/registry/lifecycle.json +599 -996
  86. package/core/registry/mcp.json +5 -1
  87. package/core/registry/models.json +7 -1
  88. package/core/registry/package-templates/README.md +19 -0
  89. package/core/registry/package-templates/agent/files/agent.md +9 -0
  90. package/core/registry/package-templates/agent/template.json +4 -0
  91. package/core/registry/package-templates/capability-provider/files/provider.json +9 -0
  92. package/core/registry/package-templates/capability-provider/template.json +11 -0
  93. package/core/registry/package-templates/debate-preset/files/preset.json +26 -0
  94. package/core/registry/package-templates/debate-preset/template.json +4 -0
  95. package/core/registry/package-templates/intake-category/files/category.json +8 -0
  96. package/core/registry/package-templates/intake-category/template.json +4 -0
  97. package/core/registry/package-templates/review-preset/files/preset.json +30 -0
  98. package/core/registry/package-templates/review-preset/template.json +4 -0
  99. package/core/registry/package-templates/skill/files/SKILL.md +8 -0
  100. package/core/registry/package-templates/skill/template.json +4 -0
  101. package/core/registry/package-templates/worker/files/worker.json +92 -0
  102. package/core/registry/package-templates/worker/template.json +11 -0
  103. package/core/registry/packages/doflow/doflow-package.json +15 -0
  104. package/core/registry/packages/doflow/presets/debate-3.json +26 -0
  105. package/core/registry/protocols.json +61 -0
  106. package/core/registry/routes.json +17 -0
  107. package/core/registry/rules.json +431 -0
  108. package/core/registry/settings.json +272 -0
  109. package/core/registry/storage.json +687 -31
  110. package/core/registry/telemetry.json +236 -0
  111. package/core/registry/transcripts.json +142 -0
  112. package/core/registry/verification.json +76 -6
  113. package/core/registry/workflows.json +55 -0
  114. package/core/shared/agent-specs/core-implementer.md +3 -0
  115. package/core/shared/agent-specs/delivery-lead.md +68 -0
  116. package/core/shared/agent-specs/quality-guardian.md +5 -1
  117. package/core/shared/agent-specs/research-writer.md +10 -3
  118. package/core/shared/agent-specs/reviewer.md +53 -0
  119. package/core/shared/agent-specs/spec-analyst.md +5 -6
  120. package/core/shared/agent-specs/system-architect.md +5 -1
  121. package/core/shared/guidance/DOFLOW_CORE.md +1 -5
  122. package/core/shared/guidance/modes/MODE_DeepResearch.md +1 -1
  123. package/core/shared/guidance/modes/MODE_Orchestration.md +4 -3
  124. package/core/shared/guidance/modes/MODE_Task_Management.md +14 -14
  125. package/core/shared/guidance/pointers/codex.md +1 -4
  126. package/core/shared/guidance/references/ARTIFACT_FORMAT.md +30 -16
  127. package/core/shared/guidance/references/ARTIFACT_VOICE.md +3 -2
  128. package/core/shared/guidance/references/CONSTITUTION_BASE.md +17 -15
  129. package/core/shared/guidance/references/DIAGRAM_GUIDE.md +1 -1
  130. package/core/shared/guidance/references/DOFLOW_CHAIN.md +17 -19
  131. package/core/shared/guidance/references/EVIDENCE_LEDGER.md +7 -8
  132. package/core/shared/guidance/references/MODEL_SELECTION.md +5 -3
  133. package/core/shared/guidance/references/ORCHESTRATION.md +3 -2
  134. package/core/shared/guidance/references/WORKFLOW_HANDOFF.md +19 -1
  135. package/core/shared/guidance/rules/RULES.md +45 -0
  136. package/core/shared/scripts/doflow/bash/do-args.sh +37 -0
  137. package/core/shared/scripts/doflow/bash/do-exec-paths.sh +4 -0
  138. package/core/shared/scripts/doflow/bash/do-git-state.sh +15 -4
  139. package/core/shared/scripts/doflow/bash/do-parallel-check.sh +4 -0
  140. package/core/shared/scripts/doflow/bash/do-paths.sh +40 -2
  141. package/core/shared/scripts/doflow/bash/do-prereqs.sh +2 -1
  142. package/core/shared/scripts/doflow/bash/do-review-package.sh +4 -0
  143. package/core/shared/scripts/doflow/bash/do-task-brief.sh +58 -16
  144. package/core/shared/scripts/doflow/bash/render-audit.sh +26 -2
  145. package/core/shared/scripts/doflow/bash/render-diagrams.sh +1 -0
  146. package/core/shared/scripts/doflow/bash/render-puml.sh +2 -1
  147. package/core/shared/scripts/doflow/bash/validate-artifacts.sh +49 -5
  148. package/core/shared/scripts/doflow/bin/doflow-run +152 -34
  149. package/core/shared/skills/do/SKILL.md +14 -12
  150. package/core/shared/skills/do/references/advice_calls.md +26 -0
  151. package/core/shared/skills/do/references/pm_routing.md +1 -2
  152. package/core/shared/skills/do/references/program_mode.md +31 -0
  153. package/core/shared/skills/do-brainstorm/SKILL.md +45 -97
  154. package/core/shared/skills/do-brainstorm/references/handoff_branches.md +36 -0
  155. package/core/shared/skills/do-brainstorm/references/intent_seed.md +21 -0
  156. package/core/shared/skills/do-brainstorm/references/round_log.md +17 -0
  157. package/core/shared/skills/do-code-review/SKILL.md +48 -148
  158. package/core/shared/skills/do-code-review/content-types/markdown.md +24 -2
  159. package/core/shared/skills/do-code-review/references/tools.md +90 -0
  160. package/core/shared/skills/do-code-review/scripts/doc_quality_checker.py +549 -7
  161. package/core/shared/skills/do-design/SKILL.md +23 -20
  162. package/core/shared/skills/do-diagnose/SKILL.md +18 -6
  163. package/core/shared/skills/do-document/SKILL.md +12 -1
  164. package/core/shared/skills/do-document/references/deep_research.md +1 -2
  165. package/core/shared/skills/do-document/references/embedded-research.md +19 -7
  166. package/core/shared/skills/do-document/references/implementation-flow.md +5 -6
  167. package/core/shared/skills/do-execute-plan/SKILL.md +19 -60
  168. package/core/shared/skills/do-execute-plan/references/handoff_record.md +7 -2
  169. package/core/shared/skills/do-execute-plan/references/parallel_dispatch.md +13 -0
  170. package/core/shared/skills/do-execute-plan/references/readiness_gate.md +26 -1
  171. package/core/shared/skills/do-execute-plan/references/run_position.md +16 -2
  172. package/core/shared/skills/do-execute-plan/references/scaffold.md +17 -9
  173. package/core/shared/skills/do-execute-plan/references/state_checkpoint.md +11 -0
  174. package/core/shared/skills/do-execute-plan/references/task_attempts.md +78 -24
  175. package/core/shared/skills/do-flow/SKILL.md +10 -11
  176. package/core/shared/skills/do-flow/references/task_classes.md +5 -5
  177. package/core/shared/skills/do-git/SKILL.md +4 -0
  178. package/core/shared/skills/do-implement/SKILL.md +13 -14
  179. package/core/shared/skills/do-plan/SKILL.md +34 -20
  180. package/core/shared/skills/do-test/SKILL.md +7 -4
  181. package/core/shared/templates/doflow/constitution-template.md +9 -3
  182. package/core/shared/templates/doflow/data-model-template.md +1 -1
  183. package/core/shared/templates/doflow/design-template.md +113 -16
  184. package/core/shared/templates/doflow/plan-template.md +11 -10
  185. package/core/shared/templates/doflow/question-log-template.md +14 -2
  186. package/core/shared/templates/doflow/requirement-template.md +1 -1
  187. package/core/shared/workflows/do-flow-chain.md +2 -0
  188. package/core/worker-evidence/antigravity/checks.json +14 -0
  189. package/core/worker-evidence/codex/2026-10-18-cli-check.json +107 -0
  190. package/core/worker-evidence/codex/2026-10-18-live-run-edit.json +73 -0
  191. package/core/worker-evidence/codex/2026-10-18-live-run-read-only.json +62 -0
  192. package/core/worker-evidence/codex/2026-10-24-cli-check.json +126 -0
  193. package/core/worker-evidence/codex/checks.json +38 -0
  194. package/package.json +10 -6
  195. package/src/adapters/antigravity/index.js +143 -66
  196. package/src/adapters/claude/index.js +46 -5
  197. package/src/adapters/codex/agents.js +25 -15
  198. package/src/adapters/codex/hooks.js +39 -3
  199. package/src/adapters/codex/index.js +61 -13
  200. package/src/adapters/codex/native-projection.js +6 -2
  201. package/src/adapters/copilot/index.js +58 -23
  202. package/src/adapters/copy-tree.js +291 -46
  203. package/src/adapters/guidance-manifest.js +71 -0
  204. package/src/adapters/guidance-pointer.js +19 -0
  205. package/src/adapters/hook-commands.js +6 -10
  206. package/src/adapters/index.js +1 -0
  207. package/src/adapters/kiro/index.js +23 -12
  208. package/src/adapters/opencode/index.js +8 -8
  209. package/src/adapters/pi/hooks.js +2 -1
  210. package/src/adapters/pi/index.js +14 -7
  211. package/src/adapters/resolve-source.js +26 -2
  212. package/src/cli/commands/install.js +2 -1
  213. package/src/cli/commands/reconcile.js +53 -9
  214. package/src/cli/commands/remove.js +2 -2
  215. package/src/cli/commands/rollback.js +6 -3
  216. package/src/cli/commands/self-update.js +18 -9
  217. package/src/cli/commands/status.js +22 -3
  218. package/src/cli/commands/ui.js +99 -0
  219. package/src/cli/commands/update.js +2 -1
  220. package/src/cli/index.js +337 -32
  221. package/src/cli/runtime-commands.js +220 -60
  222. package/src/cli/shared.js +0 -2
  223. package/src/helper/git.js +1 -1
  224. package/src/helper/guardrails.js +1 -1
  225. package/src/helper/marker-merge.js +31 -13
  226. package/src/helper/package-ids.js +37 -0
  227. package/src/helper/semver.js +94 -0
  228. package/src/install/backup.js +105 -15
  229. package/src/install/context.js +1 -1
  230. package/src/install/targets.js +31 -16
  231. package/src/lifecycle/coverage.js +4 -16
  232. package/src/lifecycle/hook-tier.js +160 -0
  233. package/src/lifecycle/index.js +412 -78
  234. package/src/lifecycle/retired-harnesses.js +318 -0
  235. package/src/lifecycle/view.js +35 -15
  236. package/src/registry/index.js +551 -26
  237. package/src/registry/worker-ids.js +45 -0
  238. package/src/release/build-package.js +0 -3
  239. package/src/release/docs-blocks.js +472 -0
  240. package/src/release/preflight.js +425 -0
  241. package/src/release/rehearse.js +401 -0
  242. package/src/release/release-workflow.js +733 -0
  243. package/src/release/sync-plugin-versions.js +43 -7
  244. package/src/runtime/advice/bench-gate.js +25 -0
  245. package/src/runtime/advice/cli.js +59 -16
  246. package/src/runtime/advice/client.js +32 -9
  247. package/src/runtime/advice/config.js +98 -133
  248. package/src/runtime/advice/doctor.js +1 -1
  249. package/src/runtime/advice/elevation.js +97 -0
  250. package/src/runtime/advice/endpoint-guard.js +9 -3
  251. package/src/runtime/advice/mode.js +37 -0
  252. package/src/runtime/advice/record.js +18 -5
  253. package/src/runtime/advice/registry.js +4 -1
  254. package/src/runtime/advice/shadow-config.js +229 -0
  255. package/src/runtime/advice/shadow-dispatcher.js +276 -0
  256. package/src/runtime/brief-rules.js +81 -0
  257. package/src/runtime/brief-tools.js +111 -34
  258. package/src/runtime/candidate.js +20 -11
  259. package/src/runtime/capabilities/executor.js +450 -0
  260. package/src/runtime/capabilities/loopback.js +41 -0
  261. package/src/runtime/capabilities/sanitizer.js +88 -0
  262. package/src/runtime/capability-router.js +135 -3
  263. package/src/runtime/checkouts.js +73 -11
  264. package/src/runtime/claims.js +13 -7
  265. package/src/runtime/cli.js +196 -19
  266. package/src/runtime/config-home.js +42 -0
  267. package/src/runtime/context/arbitrate.js +767 -0
  268. package/src/runtime/context/delivery-store.js +4 -6
  269. package/src/runtime/context/emission-rules.js +118 -0
  270. package/src/runtime/context/identity.js +227 -0
  271. package/src/runtime/context/pointer.js +67 -12
  272. package/src/runtime/context/primary-command.js +117 -0
  273. package/src/runtime/context/primary.js +344 -0
  274. package/src/runtime/context/summary-store.js +655 -0
  275. package/src/runtime/context-pack.js +158 -79
  276. package/src/runtime/decision-register.js +13 -4
  277. package/src/runtime/dispatch/admission.js +392 -0
  278. package/src/runtime/dispatch/attempt-end.js +274 -0
  279. package/src/runtime/dispatch/command.js +628 -0
  280. package/src/runtime/dispatch/controls.js +904 -0
  281. package/src/runtime/dispatch/envelope.js +276 -0
  282. package/src/runtime/dispatch/grants.js +310 -0
  283. package/src/runtime/dispatch/integrate.js +617 -0
  284. package/src/runtime/dispatch/loop.js +1835 -0
  285. package/src/runtime/dispatch/store.js +352 -0
  286. package/src/runtime/dispatch/verify-run.js +201 -0
  287. package/src/runtime/evidence-ledger.js +52 -7
  288. package/src/runtime/failure/capture.js +3 -1
  289. package/src/runtime/failure/cli.js +25 -9
  290. package/src/runtime/failure/home.js +57 -30
  291. package/src/runtime/failure/store.js +7 -2
  292. package/src/runtime/feature-pointer.js +174 -0
  293. package/src/runtime/feature-resolve.js +13 -2
  294. package/src/runtime/fleet/command.js +77 -0
  295. package/src/runtime/fleet/projects.js +178 -0
  296. package/src/runtime/fleet/tree.js +383 -0
  297. package/src/runtime/freshness.js +33 -3
  298. package/src/runtime/git-memo.js +46 -0
  299. package/src/runtime/guidance/ablation.js +427 -0
  300. package/src/runtime/health.js +624 -18
  301. package/src/runtime/history-compactor.js +13 -3
  302. package/src/runtime/implementation-gate.js +281 -26
  303. package/src/runtime/intake/engine.js +677 -0
  304. package/src/runtime/intake/index.js +136 -0
  305. package/src/runtime/intake/manifest.js +140 -0
  306. package/src/runtime/intake/taxonomy.js +206 -0
  307. package/src/runtime/inventory/coverage.js +1 -1
  308. package/src/runtime/inventory/index.js +1 -1
  309. package/src/runtime/inventory/precedence.js +2 -2
  310. package/src/runtime/inventory/siblings.js +6 -4
  311. package/src/runtime/knowledge/code-corpus.js +277 -0
  312. package/src/runtime/knowledge/code-lexical.js +130 -0
  313. package/src/runtime/knowledge/code-retrieval.js +307 -0
  314. package/src/runtime/knowledge/code-validation.js +106 -0
  315. package/src/runtime/knowledge/gp3-gate.js +74 -0
  316. package/src/runtime/knowledge/graph-adapter.js +288 -0
  317. package/src/runtime/knowledge/graph-fallback.js +394 -0
  318. package/src/runtime/knowledge/hybrid.js +136 -8
  319. package/src/runtime/knowledge/retrieval.js +34 -1
  320. package/src/runtime/knowledge/rtk-compress.js +77 -0
  321. package/src/runtime/knowledge/semble-bridge.py +106 -0
  322. package/src/runtime/knowledge/semble-lifecycle.js +114 -0
  323. package/src/runtime/knowledge/semble-provider.js +365 -0
  324. package/src/runtime/lifecycle/cli.js +88 -10
  325. package/src/runtime/lifecycle/event-store.js +8 -6
  326. package/src/runtime/lifecycle/followup.js +38 -7
  327. package/src/runtime/lifecycle/overview.js +26 -2
  328. package/src/runtime/lifecycle/report-store.js +8 -10
  329. package/src/runtime/lifecycle/retention.js +95 -31
  330. package/src/runtime/lifecycle/root.js +9 -1
  331. package/src/runtime/lifecycle/status.js +34 -17
  332. package/src/runtime/lifecycle/store-upkeep.js +56 -7
  333. package/src/runtime/mask.js +134 -7
  334. package/src/runtime/mcp-consultations.js +40 -6
  335. package/src/runtime/model-router.js +79 -7
  336. package/src/runtime/models/catalogue.js +191 -0
  337. package/src/runtime/models/command.js +153 -0
  338. package/src/runtime/off-words.js +12 -0
  339. package/src/runtime/outcome.js +2 -2
  340. package/src/runtime/packages/command.js +1009 -0
  341. package/src/runtime/packages/contributions.js +116 -0
  342. package/src/runtime/packages/digest.js +132 -0
  343. package/src/runtime/packages/fetch.js +182 -0
  344. package/src/runtime/packages/grants.js +192 -0
  345. package/src/runtime/packages/index-file.js +134 -0
  346. package/src/runtime/packages/instruction.js +90 -0
  347. package/src/runtime/packages/manifest.js +331 -0
  348. package/src/runtime/packages/points.js +487 -0
  349. package/src/runtime/packages/programs.js +216 -0
  350. package/src/runtime/packages/scaffold.js +277 -0
  351. package/src/runtime/packages/source.js +90 -0
  352. package/src/runtime/packages/state.js +164 -0
  353. package/src/runtime/packages/store.js +449 -0
  354. package/src/runtime/packages/tar.js +106 -0
  355. package/src/runtime/packages/view.js +406 -0
  356. package/src/runtime/plan-check.js +59 -0
  357. package/src/runtime/plan-content.js +324 -0
  358. package/src/runtime/policy-init.js +118 -0
  359. package/src/runtime/profiles/doctor.js +96 -0
  360. package/src/runtime/profiles/resolve.js +244 -0
  361. package/src/runtime/profiles/rollback.js +254 -0
  362. package/src/runtime/profiles/sampler.js +41 -0
  363. package/src/runtime/readiness-record.js +16 -11
  364. package/src/runtime/readiness.js +46 -5
  365. package/src/runtime/research-request.js +50 -25
  366. package/src/runtime/retrieval-plan.js +10 -30
  367. package/src/runtime/retrieval-record.js +75 -5
  368. package/src/runtime/review/command.js +246 -0
  369. package/src/runtime/review/dominance.js +68 -0
  370. package/src/runtime/review/findings.js +434 -0
  371. package/src/runtime/review/identity.js +255 -0
  372. package/src/runtime/review/protocol-command.js +109 -0
  373. package/src/runtime/review/protocols.js +405 -0
  374. package/src/runtime/review/resolve-protocol.js +302 -0
  375. package/src/runtime/review/start.js +530 -0
  376. package/src/runtime/roadmap/attendance.js +137 -0
  377. package/src/runtime/roadmap/facts.js +479 -0
  378. package/src/runtime/roadmap/gates.js +273 -0
  379. package/src/runtime/roadmap/loop.js +1719 -0
  380. package/src/runtime/roadmap/merge.js +390 -0
  381. package/src/runtime/roadmap/rows.js +1122 -0
  382. package/src/runtime/roadmap/seed.js +1063 -0
  383. package/src/runtime/roadmap/worktree-cleanup.js +147 -0
  384. package/src/runtime/rules-report.js +336 -0
  385. package/src/runtime/scaffold/artifacts.js +60 -9
  386. package/src/runtime/scaffold/generate.js +21 -9
  387. package/src/runtime/settings/autopilot.js +106 -0
  388. package/src/runtime/settings/cli.js +280 -0
  389. package/src/runtime/settings/config-write.js +314 -0
  390. package/src/runtime/settings/files.js +271 -0
  391. package/src/runtime/settings/legacy.js +154 -0
  392. package/src/runtime/settings/lexical.js +56 -0
  393. package/src/runtime/settings/prepared-run.js +269 -0
  394. package/src/runtime/settings/project-layers.js +118 -0
  395. package/src/runtime/settings/refs.js +288 -0
  396. package/src/runtime/settings/registry.js +553 -0
  397. package/src/runtime/settings/resolve.js +713 -0
  398. package/src/runtime/settings/shared.js +37 -0
  399. package/src/runtime/settings/worker-billing.js +107 -0
  400. package/src/runtime/settings/write.js +269 -0
  401. package/src/runtime/slot-command.js +78 -0
  402. package/src/runtime/slots.js +671 -0
  403. package/src/runtime/source-version.js +1 -0
  404. package/src/runtime/state-root.js +217 -0
  405. package/src/runtime/storage/cli.js +12 -5
  406. package/src/runtime/storage/engine.js +9 -2
  407. package/src/runtime/storage/registry.js +14 -1
  408. package/src/runtime/storage/roots.js +66 -16
  409. package/src/runtime/storage/rules.js +82 -10
  410. package/src/runtime/storage/upkeep.js +10 -2
  411. package/src/runtime/storage/work-status.js +245 -26
  412. package/src/runtime/task-attempts.js +589 -69
  413. package/src/runtime/task-classifier.js +85 -14
  414. package/src/runtime/task-graph.js +373 -0
  415. package/src/runtime/task-run.js +778 -0
  416. package/src/runtime/task-scope.js +176 -55
  417. package/src/runtime/task-sources.js +147 -0
  418. package/src/runtime/task-state.js +373 -64
  419. package/src/runtime/team/admission.js +301 -0
  420. package/src/runtime/team/envelope.js +324 -0
  421. package/src/runtime/team/review-guard.js +156 -0
  422. package/src/runtime/trace/analyze.js +427 -0
  423. package/src/runtime/trace/baseline.js +770 -0
  424. package/src/runtime/trace/ledger.js +63 -140
  425. package/src/runtime/trace/otlp-export.js +568 -0
  426. package/src/runtime/trace/otlp-map.js +481 -0
  427. package/src/runtime/trace/spans.js +745 -0
  428. package/src/runtime/trace/telemetry.js +225 -0
  429. package/src/runtime/trace/views.js +1 -0
  430. package/src/runtime/transcripts/command.js +98 -0
  431. package/src/runtime/transcripts/cursor.js +326 -0
  432. package/src/runtime/transcripts/read.js +126 -0
  433. package/src/runtime/transcripts/readers/claude-jsonl.js +74 -0
  434. package/src/runtime/transcripts/readers/codex-rollout.js +70 -0
  435. package/src/runtime/transcripts/readers/copilot-events.js +90 -0
  436. package/src/runtime/transcripts/readers/kiro-jsonl.js +77 -0
  437. package/src/runtime/transcripts/readers/pi-jsonl.js +59 -0
  438. package/src/runtime/transcripts/registry.js +161 -0
  439. package/src/runtime/transcripts/stats.js +161 -0
  440. package/src/runtime/verb-view.js +267 -0
  441. package/src/runtime/verification/check-key.js +628 -0
  442. package/src/runtime/verification/contract-runner.js +546 -11
  443. package/src/runtime/verification/engine.js +499 -54
  444. package/src/runtime/verification/impact.js +617 -0
  445. package/src/runtime/verification/inflight.js +205 -0
  446. package/src/runtime/verification/registry.js +176 -0
  447. package/src/runtime/verification/reuse.js +184 -0
  448. package/src/runtime/verification/telemetry-emit.js +254 -0
  449. package/src/runtime/verification/test-selection.js +67 -7
  450. package/src/runtime/worker/active.js +90 -0
  451. package/src/runtime/worker/cancel.js +222 -0
  452. package/src/runtime/worker/catalogue.js +122 -0
  453. package/src/runtime/worker/command.js +677 -0
  454. package/src/runtime/worker/evidence.js +288 -0
  455. package/src/runtime/worker/launch.js +256 -0
  456. package/src/runtime/worker/models.js +137 -0
  457. package/src/runtime/worker/parsers.js +218 -0
  458. package/src/runtime/worker/probes/index.js +706 -0
  459. package/src/runtime/worker/process-tree.js +415 -0
  460. package/src/runtime/worker/quota.js +43 -0
  461. package/src/runtime/worker/readiness.js +713 -0
  462. package/src/runtime/worker/run-store.js +166 -0
  463. package/src/runtime/worker/supervisor.js +541 -0
  464. package/src/runtime/worker/worktree-check.js +252 -0
  465. package/src/runtime/workflow-engine.js +5 -1
  466. package/src/runtime/workflow-orchestrator.js +610 -67
  467. package/src/runtime/worktree.js +149 -22
  468. package/src/state/index.js +1 -1
  469. package/src/state/lockfile.js +64 -10
  470. package/src/state/run-lock.js +1 -1
  471. package/types/node-commonjs.d.ts +106 -7
  472. package/core/harnesses/claude/hooks/pre-bash-guard.sh +0 -10
  473. package/core/harnesses/codex/hooks/pre-bash-guard.sh +0 -10
  474. package/core/harnesses/gemini/hooks/hooks.json +0 -77
  475. package/core/harnesses/gemini/hooks/lib.sh +0 -302
  476. package/core/harnesses/gemini/hooks/mcp-tool-guard.sh +0 -10
  477. package/core/harnesses/gemini/hooks/post-edit-lint.sh +0 -39
  478. package/core/harnesses/gemini/hooks/pre-bash-guard.sh +0 -10
  479. package/core/harnesses/gemini/hooks/pre-compact.sh +0 -38
  480. package/core/harnesses/gemini/hooks/pre-implement-gate.sh +0 -10
  481. package/core/harnesses/gemini/hooks/session-end.impl.sh +0 -89
  482. package/core/harnesses/gemini/hooks/session-end.sh +0 -5
  483. package/core/harnesses/gemini/hooks/session-start.sh +0 -7
  484. package/core/harnesses/gemini/settings/adapter-defaults.json +0 -4
  485. package/core/harnesses/kiro/hooks/pre-bash-guard.sh +0 -24
  486. package/core/harnesses/shared/hooks/policies/blocked-patterns.conf +0 -91
  487. package/core/harnesses/shared/hooks/policies/pre-bash-guard.sh +0 -378
  488. package/core/shared/guidance/FLAGS.md +0 -25
  489. package/core/shared/guidance/rules/RULE_01_SAFETY.md +0 -25
  490. package/core/shared/guidance/rules/RULE_02_WORKFLOW.md +0 -23
  491. package/core/shared/guidance/rules/RULE_03_QUALITY.md +0 -14
  492. package/core/shared/guidance/rules/RULE_04_QUESTIONS.md +0 -46
  493. package/src/adapters/gemini/hooks.js +0 -251
  494. package/src/adapters/gemini/index.js +0 -429
@@ -18,11 +18,11 @@
18
18
  // handle<Name>Command(...)` — to cross-check the dispatcher's verb table in both directions. Keep
19
19
  // every case in exactly that shape.
20
20
  // TypeScript migration (agent-docs/BRIEF_GOAL_DOFLOW.md): run directly by Node native type-stripping.
21
- const fs = require('node:fs');
22
21
  const os = require('node:os');
23
22
  const path = require('node:path');
24
23
  const {
25
24
  handleCapabilitiesCommand, handleReadinessCommand, handleEvidenceCommand,
25
+ handleContextEmitCommand, handleContextGrantCommand,
26
26
  } = require('../runtime/cli.js');
27
27
  const { loadRegistry } = require('../registry/index.js');
28
28
  const { enforcementFor, UnknownEnforcementTarget } = require('../lifecycle/coverage.js');
@@ -41,37 +41,135 @@ const { handleWorkflowCommand } = require('../runtime/workflow-engine.js');
41
41
  const { handleOrchestrateCommand } = require('../runtime/workflow-orchestrator.js');
42
42
  const { handleResearchRequestCommand } = require('../runtime/research-request.js');
43
43
  const { handleTaskAttemptCommand } = require('../runtime/task-attempts.js');
44
+ const { handleWorkerCommand } = require('../runtime/worker/command.js');
45
+ const { handleDispatchCommand } = require('../runtime/dispatch/command.js');
44
46
  const { handleRetrieveCommand } = require('../runtime/knowledge/retrieval.js');
45
47
  const { handleModelRoleCommand } = require('../runtime/model-router.js');
46
48
  const { handleRouteCommand } = require('../runtime/capability-router.js');
47
49
  const { handleContextPackCommand } = require('../runtime/context-pack.js');
48
50
  const { handleRetrievalPlanCommand } = require('../runtime/retrieval-plan.js');
49
51
  const { handleOutcomeCommand } = require('../runtime/outcome.js');
50
- const { handleVerifyCommand } = require('../runtime/verification/engine.js');
52
+ const { handleVerifyCommand, verifyStateRoot } = require('../runtime/verification/engine.js');
51
53
  const { handleLeakScanCommand } = require('../runtime/leak-scan.js');
52
54
  const { handleRecoverCommand } = require('../runtime/recovery.js');
53
55
  const { handleScaffoldCommand } = require('../runtime/scaffold/generate.js');
54
- const { handleDecisionCommand } = require('../runtime/decision-register.js');
56
+ const { handleDecisionCommand, isReservedChannel, CHANNEL_RESERVED } = require('../runtime/decision-register.js');
57
+ const { handleIntakeCommand } = require('../runtime/intake/index.js');
55
58
  const { handleFollowupCommand, handleLifecycleCommand, handleGoalCommand } = require('../runtime/lifecycle/cli.js');
56
59
  const { projectRoot: lifecycleProjectRoot } = require('../runtime/lifecycle/root.js');
57
60
  const { upkeepAfterVerb } = require('../runtime/storage/upkeep.js');
58
61
  const { handleStorageCommand } = require('../runtime/storage/cli.js');
62
+ const { handleRoadmapCommand, resolveMainRoot } = require('../runtime/roadmap/loop.js');
63
+ const { handlePlanCheckCommand } = require('../runtime/plan-check.js');
64
+ const { handleSlotCommand } = require('../runtime/slot-command.js');
65
+ const { handleReviewCommand } = require('../runtime/review/command.js');
66
+ const { handleProtocolCommand } = require('../runtime/review/protocol-command.js');
67
+ const { handleRulesCommand } = require('../runtime/rules-report.js');
68
+ const { handlePackageCommand } = require('../runtime/packages/command.js');
69
+ const { handleModelsCommand } = require('../runtime/models/command.js');
70
+ const { handleWorktreeCommand } = require('../runtime/roadmap/worktree-cleanup.js');
71
+ const { handleAttendanceCommand } = require('../runtime/roadmap/attendance.js');
72
+ // `plan-check` is read-only (115 IC-001): no upkeep, which would write `.gitignore` and `upkeep-due`.
73
+ // `review` writes only its one telemetry line (095 IC-003).
74
+ // `protocol` only prints the registry and the resolved protocol (119 IC-004), so it has nothing to keep up.
75
+ // `rules` only prints the values the runtime owns, with their sources, and writes nothing.
76
+ // `primary` only prints the resolved main session (120 IC-008) and writes nothing.
77
+ // `fleet` only lists the projects this machine knows from two read-only stores (093 IC-019) and writes nothing.
78
+ // `transcript` only reads agents' transcripts and DoFlow's own records and prints them (093 IC-022, IC-023); it writes nothing.
79
+ // `attendance` is read-only; `worktree --action cleanup` removes a merged feature's worktree under the roadmap lease and writes no DoFlow state, so neither runs upkeep.
80
+ // `package` stays here (122 IC-012): `new` writes only the target folder; `add --plan`, `update --plan` and `remove` write the store and lock and run upkeep (see `runsUpkeep`).
81
+ // `slot` is not here: `run`, `list` and `release` write the slot files and run upkeep; only `slot --action peek` is read-only and skips it (093 IC-018 b, see `runsUpkeep`).
82
+ const NO_UPKEEP = new Set(['storage', 'config', 'plan-check', 'review', 'protocol', 'rules', 'primary', 'package', 'models', 'fleet', 'transcript', 'worktree', 'attendance']);
83
+ const runsUpkeep = (o ) => (!NO_UPKEEP.has(o.cmd) && !(o.cmd === 'slot' && o.actionGiven && o.action === 'peek'))
84
+ || (o.cmd === 'package' && ((typeof o.planId === 'string' && (o.action === 'add' || o.action === 'update')) || o.action === 'remove'));
59
85
  // Required on first use, so a CLI whose failure modules cannot be loaded still runs every other verb.
60
86
  function handleFailureCommand(options ) { return require('../runtime/failure/cli.js').handleFailureCommand(options); }
87
+ // The seed validator loads only for `roadmap seed`, and only this file may require it (G54).
88
+ function handleSeedCommand(options ) { return require('../runtime/roadmap/seed.js').handleSeedCommand(options); }
89
+ // maint-thin: `roadmap promote <id...>` lives in seed.ts too, so it stays out of every autopilot module (G54).
90
+ function handlePromoteCommand(options ) { return require('../runtime/roadmap/seed.js').handlePromoteCommand(options); }
91
+ // Settings support is needed only when the config verb runs.
92
+ function handleConfigCommand(options ) { return require('../runtime/settings/cli.js').handleConfigCommand(options); }
93
+ // The primary verb (row 120 A.4) needs the settings resolver only when it runs.
94
+ function handlePrimaryCommand(options ) { return require('../runtime/context/primary-command.js').handlePrimaryCommand(options); }
95
+ // The fleet verb (093 V.3) loads only when it runs.
96
+ function handleFleetCommand(options ) { return require('../runtime/fleet/command.js').handleFleetCommand(options); }
97
+ // The transcript verb (093 V.6) loads only when it runs.
98
+ function handleTranscriptCommand(options ) { return require('../runtime/transcripts/command.js').handleTranscriptCommand(options); }
61
99
  const { handleInventoryCommand } = require('../runtime/inventory/index.js');
62
100
  const { finishRuntime, usageError } = require('../runtime/cli-result.js');
63
- const { setDefaultSlug, invalidSlugRefusal, slugNamesNoFeature, resolveFeature } = require('../runtime/task-scope.js');
64
- const { listCheckouts } = require('../runtime/checkouts.js');
101
+ const { setRecordSlug, callerFeatureSlug, invalidSlugRefusal, slugNamesNoFeature } = require('../runtime/task-scope.js');
102
+ const { listCheckouts, mayBeLinked } = require('../runtime/checkouts.js');
103
+ const { taskStateRoot, sweepWorktreeRecords } = require('../runtime/state-root.js');
65
104
  const { featureSlugFor } = require('../runtime/implementation-gate.js');
66
105
  const { handleBriefToolsCommand } = require('../runtime/brief-tools.js');
67
- const { handleAdviseCommand } = require('../runtime/advice/cli.js');
106
+ // Advice writers load settings/write.ts, so keep that surface off installer and other verb paths.
107
+ function handleAdviseCommand(options ) { return require('../runtime/advice/cli.js').handleAdviseCommand(options); }
68
108
  const { REPO_ROOT, buildAdapterRegistry } = require('./shared.js');
69
109
 
70
110
  /** Where `readiness`/`evidence` read and write per-task state. Mirrors scopeOf()'s rules so these
71
111
  * commands are scope-aware like the rest of the CLI, rather than defaulting to the DoFlow install
72
112
  * directory — which for an npm install is inside node_modules/. */
73
113
  function evidenceRoot(o ) {
74
- return o.global ? os.homedir() : path.resolve(o.positional[0] || '.');
114
+ if (o.global) return os.homedir();
115
+ // `roadmap seed [<project>]` (113 IC-001): the sub-verb takes the first positional slot, so the project root is the one after it.
116
+ if (o.cmd === 'roadmap' && o.positional[0] === 'seed') return path.resolve(o.positional[1] || '.');
117
+ return path.resolve(o.positional[0] || '.');
118
+ }
119
+
120
+ /** The `trace` views that take the first positional slot: `spans` (088 IC-011), `analyze` (091 IC-001), `export` (091 IC-006). */
121
+ const TRACE_VIEWS = new Set(['spans', 'analyze', 'export']);
122
+
123
+ /** `trace spans|analyze|export [<project>]`: the view name takes the first positional slot, so the
124
+ * project root is the one after it. Every other call is `evidenceRoot(o)`. */
125
+ function traceViewRoot(o ) {
126
+ return o.cmd === 'trace' && TRACE_VIEWS.has(o.positional[0]) && !o.global ? path.resolve(o.positional[1] || '.') : evidenceRoot(o);
127
+ }
128
+
129
+ /** `roadmap`: the runner, the `seed` sub-verb (113 IC-001), or the `promote` sub-verb (maint-thin), each taking the
130
+ * first positional slot and setting the exit code itself; `promote` runs on the main checkout of the working directory. */
131
+ function handleRoadmapVerbCommand(o ) {
132
+ const action = o.actionGiven ? o.action : undefined;
133
+ if (o.positional[0] === 'seed') return finishRuntime(handleSeedCommand({ action, draft: o.draft, json: o.json, cwd: process.cwd(), root: resolveMainRoot(evidenceRoot(o)) }));
134
+ if (o.positional[0] === 'promote') return finishRuntime(handlePromoteCommand({ ids: o.positional.slice(1), json: o.json, root: resolveMainRoot(process.cwd()) }));
135
+ // `init-policy --commit` commits the policy onto develop; it lives outside the loop's tree (G53, G54). Any other action with --commit is the loop's exit 2.
136
+ if (o.commit && action === 'init-policy') return require('../runtime/policy-init.js').commitPolicyCommand({ json: o.json, root: resolveMainRoot(evidenceRoot(o)), repoRoot: REPO_ROOT });
137
+ return handleRoadmapCommand({ action, check: o.check, commit: o.commit, json: o.json, run: o.run, row: o.row, cwd: evidenceRoot(o), repoRoot: REPO_ROOT });
138
+ }
139
+
140
+ /**
141
+ * Where `trace analyze --emit followups --task-id` reads the task's evidence ledger: the store root
142
+ * and record slug the `evidence` verb writes under (115 IC-004, C-1), so a linked worktree reads the
143
+ * main checkout's namespaced ledger. Read only: no sweep, so a record still left in the worktree's
144
+ * own store is not cited. Undefined when no ledger is read; the handler refuses the flag mix itself.
145
+ */
146
+ function analyzeLedgerRoot(o ) {
147
+ if (o.emit !== 'followups' || typeof o.taskId !== 'string') return undefined;
148
+ const caller = traceViewRoot(o);
149
+ const checkouts = !o.global && mayBeLinked(caller) ? listCheckouts({ cwd: caller }) : null;
150
+ setRecordSlug(() => o.slug || callerFeatureSlug({ projectRoot: caller, taskId: o.taskId }) || null);
151
+ return taskStateRoot({ global: o.global, positional: [caller] }, checkouts).root;
152
+ }
153
+
154
+ /** `trace`: the ledger trajectory, unchanged, or the `spans`, `analyze` or `export` view, whose modules load
155
+ * only for that view so `trace` and `stats` read nothing new (NFR-010, 091 NFR-009). */
156
+ function handleTraceViewCommand(o ) {
157
+ if (o.positional[0] === 'analyze') {
158
+ return require('../runtime/trace/analyze.js').handleTraceAnalyze({ positional: o.positional.slice(1), run: o.run, json: o.json, global: o.global,
159
+ emit: o.emit, taskId: o.taskId, stateRoot: analyzeLedgerRoot(o) });
160
+ }
161
+ if (o.positional[0] === 'export') {
162
+ return require('../runtime/trace/otlp-export.js').handleTraceExport({
163
+ positional: o.positional.slice(1),
164
+ run: o.run,
165
+ json: o.json,
166
+ global: o.global,
167
+ dryRun: o.dryRun,
168
+ otlpHttp: o.otlpHttp,
169
+ });
170
+ }
171
+ if (o.positional[0] !== 'spans') return handleTraceCommand({ json: o.json, days: o.days, global: o.global, projectRoot: evidenceRoot(o) });
172
+ return require('../runtime/trace/spans.js').handleTraceSpans({ positional: o.positional.slice(1), run: o.run, json: o.json, global: o.global });
75
173
  }
76
174
 
77
175
  /**
@@ -130,33 +228,21 @@ function evidenceItemFromFlags(o ) {
130
228
  return item;
131
229
  }
132
230
 
133
- /** Verbs that read or write per-task records, and so accept `--slug` (IC-002). */
134
- const TASK_STORE_VERBS = new Set(['evidence', 'claim', 'readiness', 'context-pack', 'research-request', 'outcome', 'retrieval-plan']);
231
+ /** Verbs that read or write per-task records, and so accept `--slug` (IC-002). Their records, and
232
+ * `orchestrate`'s run and `context-emit`'s delivery, live in `taskStateRoot` (115 IC-004). */
233
+ const TASK_STORE_VERBS = new Set(['evidence', 'claim', 'readiness', 'context-pack', 'research-request', 'outcome', 'retrieval-plan', 'retrieve']);
135
234
 
136
- /** Verbs whose task records live beside the feature folder when run from a linked worktree that
137
- * does not contain it. */
138
- const FEATURE_STORE_VERBS = new Set(['evidence', 'claim', 'readiness', 'retrieval-plan']);
235
+ /** The checkout a call runs in: `context-emit`'s `--cwd`, else the positional project root. */
236
+ function callerRoot(o ) {
237
+ return o.cmd === 'context-emit' && typeof o.cwd === 'string' && o.cwd !== '' ? path.resolve(o.cwd) : evidenceRoot(o);
238
+ }
139
239
 
140
- /**
141
- * The main checkout, when `o` runs one of FEATURE_STORE_VERBS in a linked worktree that lacks the
142
- * task's feature folder and the main checkout holds it; null otherwise. The feature is `--slug`,
143
- * else the branch's. A locator such as `agent-docs/doflow/<slug>/plan.md` resolves only there, and
144
- * the readiness record written there is the one verify, orchestrate and the edit hook read from
145
- * the worktree.
146
- */
147
- function featureStoreRoot(o , checkouts ) {
148
- if (!FEATURE_STORE_VERBS.has(o.cmd) || o.global) return null;
149
- if (!checkouts.isLinked) return null;
150
- let slug = o.slug || null;
151
- if (!slug) {
152
- try {
153
- const feature = resolveFeature({ projectRoot: checkouts.current });
154
- slug = !feature.error && feature.paths ? feature.paths.feature_slug : null;
155
- } catch { /* a failed branch lookup cannot route state to a guessed feature */ }
156
- }
157
- const folder = (root ) => path.join(root, 'agent-docs', 'doflow', slug || '');
158
- if (!slug || fs.existsSync(folder(checkouts.current)) || !fs.existsSync(folder(checkouts.main))) return null;
159
- return { root: checkouts.main, slug };
240
+ /** The store conflicts a sweep found, one line each (IC-006). */
241
+ function conflictText(o , sweep ) {
242
+ const lines = sweep.conflicts.map((c ) => (c.reason === 'link' ? ` ${c.worktree} -> ${c.main}: a link on the way, nothing is moved through it`
243
+ : c.reason === 'same-file' ? ` ${c.worktree} and ${c.main} are one file` : ` ${c.worktree} differs from ${c.main}`));
244
+ return `doflow ${o.cmd}: store-conflict: ${sweep.conflicts.length} record(s) in this worktree could not be moved to the main checkout; `
245
+ + `files already moved stay moved. Keep one copy of each pair and remove the other, then re-run.\n${lines.join('\n')}`;
160
246
  }
161
247
 
162
248
  /**
@@ -166,6 +252,14 @@ function featureStoreRoot(o , checkouts )
166
252
  * to the engine module each case names.
167
253
  */
168
254
  function dispatchRuntimeCommandInner(o , moment ) {
255
+ // IC-005: no caller names a decider. orchestrate takes no --by, and the channel `policy` (decided
256
+ // by autopilot) is refused on every verb, before any state is read or written.
257
+ if (o.cmd === 'orchestrate' && o.by !== undefined) {
258
+ return usageError('orchestrate', '--by is not accepted; the runtime derives the gate decider', o.json);
259
+ }
260
+ if (isReservedChannel(o.channel)) {
261
+ return usageError(o.cmd, CHANNEL_RESERVED, o.json);
262
+ }
169
263
  // A slug becomes a directory name and a state key, so one that could name a path is refused
170
264
  // here, once, for every verb that reads `--slug`, before any of them reads or writes state
171
265
  // (FR-013, IC-009). A well-formed slug that names no feature is the verbs' own business.
@@ -179,32 +273,69 @@ function dispatchRuntimeCommandInner(o , moment ) {
179
273
  // here so the verbs whose handlers build their own ledger (readiness, evidence) route the same
180
274
  // way as the ones that take `slug` directly. The orchestration journal is keyed by slug already.
181
275
  // Reset on every dispatch, so one invocation's slug can never carry into the next in-process call.
182
- const checkouts = FEATURE_STORE_VERBS.has(o.cmd) && !o.global
183
- ? listCheckouts({ cwd: evidenceRoot(o) }) : null;
184
- const featureStore = featureStoreRoot(o, checkouts);
185
- const storeRoot = featureStore ? featureStore.root : evidenceRoot(o);
276
+ // `retrieve` is a task-store verb only as bound code retrieval (--scope code with --task-id or --slug):
277
+ // guidance retrieval and unbound code retrieval record nothing in a feature store, so they keep the
278
+ // pre-079 dispatch (no checkout listing, no feature resolver, no store note).
279
+ const storeVerb = (verbs ) => verbs.has(o.cmd) && (o.cmd !== 'retrieve' || (o.scope === 'code' && Boolean(o.taskId || o.slug)));
280
+ const recordVerb = storeVerb(TASK_STORE_VERBS) || o.cmd === 'orchestrate' || o.cmd === 'context-emit';
281
+ const caller = callerRoot(o);
282
+ // `evidence` always lists: its attempt lookup reuses the main checkout from this one listing.
283
+ const checkouts = recordVerb && !o.global && (o.cmd === 'evidence' || mayBeLinked(caller))
284
+ ? listCheckouts({ cwd: caller }) : null;
285
+ // 115 IC-004: a linked, non-sandbox worktree keeps every per-task record in the main checkout.
286
+ const { root: storeRoot, redirected } = recordVerb ? taskStateRoot(o, checkouts) : { root: evidenceRoot(o), redirected: false };
186
287
  const attemptRoot = checkouts?.ok && !checkouts.sandbox ? (checkouts.main || checkouts.current || null) : null;
187
288
  // Use the same root resolver as the handler: task redirection, the nearest run ledger,
188
289
  // and lifecycle's shared main-worktree store are deliberately different scopes.
189
290
  try {
190
291
  if (['trace', 'stats', 'discover'].includes(o.cmd)) {
191
- moment.projectRoot = path.dirname(resolveRunsLocation({ start: evidenceRoot(o), global: o.global }).configDir);
192
- } else if (['followup', 'lifecycle', 'goal', 'task-attempt'].includes(o.cmd)) {
292
+ moment.projectRoot = path.dirname(resolveRunsLocation({ start: traceViewRoot(o), global: o.global }).configDir);
293
+ } else if (['followup', 'lifecycle', 'goal', 'task-attempt', 'worker', 'dispatch'].includes(o.cmd)) {
193
294
  moment.projectRoot = lifecycleProjectRoot(evidenceRoot(o));
295
+ } else if (o.cmd === 'plan-check' || o.cmd === 'slot') {
296
+ moment.projectRoot = process.cwd(); // the first positional of plan-check is a file, never a project root
297
+ } else if (o.cmd === 'verify') {
298
+ moment.projectRoot = verifyStateRoot({ start: evidenceRoot(o) }).projectRoot; // the store verify writes, never a cwd fragment
194
299
  } else {
195
300
  moment.projectRoot = storeRoot;
196
301
  }
197
302
  } catch { /* a failed upkeep lookup must not change the verb's answer */ }
198
- const storeSlug = featureStore ? featureStore.slug : o.slug;
199
- setDefaultSlug(TASK_STORE_VERBS.has(o.cmd) ? storeSlug : null);
200
- if (featureStore) {
201
- console.error(`doflow ${o.cmd}: note: feature '${storeSlug}' lives in the main checkout ${storeRoot}; this task's records are read and written there`);
303
+ // 115 C-1: one record slug per call, `--slug`, else the feature of the checkout the verb runs in,
304
+ // used by every store the call touches (task-scope.ts). It is looked up on first use, so a
305
+ // `context-emit` event that compiles no pack spawns no resolver. Reset on every dispatch, so one
306
+ // invocation's slug can never carry into the next in-process call. `retrieve` is a task-store verb
307
+ // only as bound code retrieval (--scope code with --task-id or --slug).
308
+ let slugMemo ;
309
+ const recordSlug = () => {
310
+ if (slugMemo === undefined) {
311
+ try { slugMemo = o.slug || callerFeatureSlug({ projectRoot: caller, taskId: o.taskId }) || null; } catch { slugMemo = null; }
312
+ }
313
+ return slugMemo ;
314
+ };
315
+ setRecordSlug(recordVerb ? recordSlug : undefined);
316
+ const storeSlug = recordVerb && o.cmd !== 'context-emit' ? recordSlug() : undefined;
317
+ if (redirected && o.cmd !== 'context-emit') {
318
+ console.error(`doflow ${o.cmd}: note: records are kept in the main checkout ${storeRoot}`);
202
319
  }
203
- // A well-formed slug that names no feature changes nothing (the records go to the shared task
204
- // store), but the caller typed it expecting an effect, so say so once, on stderr only.
205
- if (!featureStore && TASK_STORE_VERBS.has(o.cmd) && typeof o.slug === 'string' && o.slug !== ''
206
- && slugNamesNoFeature({ projectRoot: evidenceRoot(o), slug: o.slug })) {
207
- console.error(`doflow ${o.cmd}: note: --slug '${o.slug}' names no feature; using the shared task store`);
320
+ // A well-formed slug that names no feature folder still names the records' namespace, but the
321
+ // caller typed it expecting a feature, so say so once, on stderr only.
322
+ if (storeVerb(TASK_STORE_VERBS) && typeof o.slug === 'string' && o.slug !== ''
323
+ && slugNamesNoFeature({ projectRoots: redirected ? [caller, storeRoot] : [caller], slug: o.slug })) {
324
+ console.error(`doflow ${o.cmd}: note: --slug '${o.slug}' names no feature folder; its records are kept under that slug`);
325
+ }
326
+ // 115 IC-006: every record left in the worktree's own store moves to the main checkout first, in one
327
+ // locked sweep; a record held in both with different bytes refuses the call before the verb runs.
328
+ // 092 IC-001, 093 IC-012: the orchestrate reads (list, status, timeline) write nothing, so they never sweep: they read the
329
+ // main checkout's store and see a record still left in this worktree as another checkout's
330
+ // (`orchestrationRuns`, `findRunFile`). The next write verb from here sweeps it as before.
331
+ const orchestrateRead = o.cmd === 'orchestrate' && (o.action === 'list' || o.action === 'status' || o.action === 'timeline');
332
+ if (redirected && !orchestrateRead) {
333
+ const sweep = sweepWorktreeRecords({ mainRoot: storeRoot, worktreeRoot: checkouts.current, recordSlug });
334
+ if (!sweep.ok) {
335
+ if (o.json) console.log(JSON.stringify(sweep, null, 2));
336
+ else console.error(conflictText(o, sweep));
337
+ return finishRuntime(2);
338
+ }
208
339
  }
209
340
  switch (o.cmd) {
210
341
  // REPO_ROOT locates the capability registry; projectRoot is the tree whose index freshness
@@ -226,13 +357,13 @@ function dispatchRuntimeCommandInner(o , moment ) {
226
357
  // all this does: the handler names them back under `callerAsserted` so a stated input is
227
358
  // never mistaken for a measured one.
228
359
  case 'readiness': return handleReadinessCommand({ taskClass: requireTaskClass(o), taskId: requireTaskId(o), verificationPlan: o.verificationPlan, scopeClear: o.scope, invariants: o.invariants, userDecisionPending: o.userDecisionPending, mode: o.mode, slug: storeSlug, json: o.json, repoRoot: REPO_ROOT, stateRoot: storeRoot, sourceRoot: evidenceRoot(o) });
229
- case 'evidence': return handleEvidenceCommand({ taskId: requireTaskId(o), action: o.action, item: evidenceItemFromFlags(o), batchPath: o.batchPath, evidenceId: o.evidenceId, replacedBy: o.replacedBy, json: o.json, repoRoot: REPO_ROOT, stateRoot: storeRoot, slug: storeSlug, sourceRoot: evidenceRoot(o), attemptRoot });
360
+ case 'evidence': return handleEvidenceCommand({ taskId: requireTaskId(o), action: o.action, item: evidenceItemFromFlags(o), batchPath: o.batchPath, evidenceId: o.evidenceId, replacedBy: o.replacedBy, stale: o.stale, json: o.json, repoRoot: REPO_ROOT, stateRoot: storeRoot, slug: storeSlug, sourceRoot: evidenceRoot(o), attemptRoot });
230
361
  // Run-ledger views. They resolve their own ledger the way the dispatcher does (nearest
231
362
  // `.doflow` walking up, or the global one) rather than assuming cwd is the project root, so
232
363
  // a view invoked from a subdirectory reads the runs that were actually recorded.
233
364
  // Exit codes follow design §4.2 and are set by the handler itself: 0 = answered, 1 = a
234
365
  // finding the caller must act on.
235
- case 'trace': return handleTraceCommand({ json: o.json, days: o.days, global: o.global, projectRoot: evidenceRoot(o) });
366
+ case 'trace': return handleTraceViewCommand(o);
236
367
  case 'stats': return handleStatsCommand({ json: o.json, days: o.days, global: o.global, projectRoot: evidenceRoot(o) });
237
368
  case 'indicators': return handleIndicatorsCommand({ json: o.json, projectRoot: evidenceRoot(o) });
238
369
  case 'discover': return handleDiscoverCommand({ json: o.json, days: o.days, global: o.global, projectRoot: evidenceRoot(o) });
@@ -243,6 +374,7 @@ function dispatchRuntimeCommandInner(o , moment ) {
243
374
  // the process home directory inside the lifecycle view (design R7) and is not an argument.
244
375
  case 'inventory': return handleInventoryCommand({ json: o.json, global: o.global, targets: o.targets, repoRoot: REPO_ROOT, projectRoot: path.resolve(o.positional[0] || '.') });
245
376
  case 'storage': return handleStorageCommand({ action: o.actionGiven ? o.action : 'report', json: o.json, global: o.global, projectRoot: evidenceRoot(o) });
377
+ case 'config': return handleConfigCommand({ json: o.json, global: o.global, showOrigin: o.showOrigin, positional: o.positional, layer: o.layer, preparedRun: o.preparedRun, repoRoot: REPO_ROOT });
246
378
  // No REPO_ROOT: the scaffold's repo root is the *caller's* repo, reported by the resolver,
247
379
  // because the plan's `files:` paths are relative to it. Passing the DoFlow install here
248
380
  // would detect the wrong language and mirror the wrong tree.
@@ -250,10 +382,12 @@ function dispatchRuntimeCommandInner(o , moment ) {
250
382
  // The feature is resolved from the working directory (or --slug) by the same resolver
251
383
  // `scaffold` uses; the flags are the caller's own statements, validated by the register module.
252
384
  case 'decision': return handleDecisionCommand({ action: o.action, projectRoot: evidenceRoot(o), slug: o.slug, json: o.json, flags: { topic: o.topic, statement: o.statement, channel: o.channel, stage: o.stage, rationale: o.rationale, supersedes: o.supersedes, refs: o.refs, source: o.source, batch: o.batchPath, all: o.all } });
385
+ // 136: the feature is resolved the way `decision` resolves it; the engine moves files only inside its additional-context folder.
386
+ case 'intake': return handleIntakeCommand({ action: o.action, projectRoot: evidenceRoot(o), slug: o.slug, json: o.json, flags: { runId: o.runId, stdin: o.stdin, file: o.file, stage: o.stage } });
253
387
  // Feature 046: the project's follow-up store lives at the repository root (never `-g`, which
254
388
  // the handlers refuse), so the working directory is the starting point, not a scope switch.
255
- case 'followup': return handleFollowupCommand({ action: o.actionGiven ? o.action : undefined, cwd: evidenceRoot(o), global: o.global, slug: o.slug, json: o.json, flags: { statement: o.statement, stage: o.stage, source: o.source, taskClass: o.taskClass, taskId: o.taskId, release: o.release, batch: o.batchPath, channel: o.channel, state: o.state, ids: o.ids, as: o.as, reason: o.reason, evidence: o.evidence, title: o.title, file: o.file, stdin: o.stdin, text: o.text, feature: o.feature, tag: o.tag, confirm: o.confirm, exclude: o.exclude } });
256
- case 'lifecycle': return handleLifecycleCommand({ action: o.actionGiven ? o.action : undefined, cwd: evidenceRoot(o), global: o.global, slug: o.slug, json: o.json, flags: { take: o.take, intent: o.intent, goal: o.goal, maintain: o.maintain, since: o.since, tag: o.tag, confirm: o.confirm, feature: o.feature, exclude: o.exclude, reason: o.reason, channel: o.channel } });
389
+ case 'followup': return handleFollowupCommand({ action: o.actionGiven ? o.action : undefined, cwd: evidenceRoot(o), global: o.global, slug: o.slug, json: o.json, flags: { statement: o.statement, stage: o.stage, source: o.source, taskClass: o.taskClass, taskId: o.taskId, release: o.release, batch: o.batchPath, channel: o.channel, state: o.state, ids: o.ids, view: o.view, cursor: o.cursor, limit: o.limit, as: o.as, reason: o.reason, evidence: o.evidence, title: o.title, file: o.file, stdin: o.stdin, text: o.text, feature: o.feature, tag: o.tag, confirm: o.confirm, exclude: o.exclude } });
390
+ case 'lifecycle': return handleLifecycleCommand({ action: o.actionGiven ? o.action : undefined, cwd: evidenceRoot(o), global: o.global, slug: o.slug, json: o.json, flags: { view: o.view, take: o.take, intent: o.intent, goal: o.goal, maintain: o.maintain, since: o.since, tag: o.tag, confirm: o.confirm, feature: o.feature, exclude: o.exclude, reason: o.reason, channel: o.channel } });
257
391
  case 'goal': return handleGoalCommand({ action: o.actionGiven ? o.action : undefined, cwd: evidenceRoot(o), global: o.global, slug: o.slug, json: o.json, flags: { goal: o.goal, statement: o.statement, item: o.item, text: o.text, evidence: o.evidence, unmet: o.unmet, replace: o.replace, reason: o.reason, channel: o.channel } });
258
392
  // The failure store is per machine, so `-g` changes nothing and the working directory only matters
259
393
  // to `settle --as imported`, which looks for the DoFlow repository from there.
@@ -261,25 +395,51 @@ function dispatchRuntimeCommandInner(o , moment ) {
261
395
  // The rest of design §4.2's Node arm. REPO_ROOT locates the registries that ship with the
262
396
  // package (workflows, capabilities, verification); evidenceRoot(o) locates the caller's own
263
397
  // state and source tree, following the same scope rules as every other command.
264
- case 'classify': return handleClassifyCommand({ taskClass: o.taskClass, rationale: o.rationale, proposedBy: o.proposedBy, callingSkill: o.callingSkill, request: o.request, requestFile: o.requestFile, taskId: o.taskId, projectRoot: evidenceRoot(o), json: o.json });
398
+ case 'classify': return handleClassifyCommand({ taskClass: o.taskClass, rationale: o.rationale, proposedBy: o.proposedBy, callingSkill: o.callingSkill, view: o.view, request: o.request, requestFile: o.requestFile, taskId: o.taskId, projectRoot: evidenceRoot(o), json: o.json });
265
399
  case 'workflow': return handleWorkflowCommand({ taskClass: o.taskClass, json: o.json });
266
- case 'orchestrate': return handleOrchestrateCommand({ action: o.action, taskId: o.taskId, taskClass: o.taskClass, stage: o.stage, gate: o.gate, node: o.node, decision: o.decision, note: o.note, reason: o.reason, forced: o.forced, verificationPlan: o.verificationPlan, scope: o.scope, invariants: o.invariants, result: o.result, mcpOutcome: o.mcpOutcome, callingSkill: o.callingSkill, slug: o.slug, json: o.json, repoRoot: REPO_ROOT, stateRoot: evidenceRoot(o), buildAdapters: buildAdapterRegistry });
267
- case 'research-request': return handleResearchRequestCommand({ slug: o.slug, action: o.action === 'status' ? 'list' : o.action, taskId: requireTaskId(o), stageId: o.stageId, question: o.question, reason: o.reason, blocking: o.blocking === undefined ? undefined : o.blocking === 'true' ? true : o.blocking === 'false' ? false : o.blocking, requestId: o.requestId, outcome: o.researchOutcome, claimId: o.claimId, evidenceIds: o.evidenceIds, gap: o.gap, json: o.json, projectRoot: evidenceRoot(o) });
400
+ case 'orchestrate': return handleOrchestrateCommand({ action: o.action, taskId: o.taskId, taskClass: o.taskClass, stage: o.stage, gate: o.gate, node: o.node, decision: o.decision, policy: o.policy, note: o.note, reason: o.reason, forced: o.forced, verificationPlan: o.verificationPlan, scope: o.scope, invariants: o.invariants, result: o.result, mcpOutcome: o.mcpOutcome, callingSkill: o.callingSkill, slug: o.slug, recordSlug: storeSlug, dryRun: o.dryRun, json: o.json, repoRoot: REPO_ROOT, stateRoot: storeRoot, sourceRoot: evidenceRoot(o), buildAdapters: buildAdapterRegistry });
401
+ case 'research-request': return handleResearchRequestCommand({ slug: storeSlug, action: o.action === 'status' ? 'list' : o.action, taskId: requireTaskId(o), stageId: o.stageId, question: o.question, reason: o.reason, blocking: o.blocking === undefined ? undefined : o.blocking === 'true' ? true : o.blocking === 'false' ? false : o.blocking, requestId: o.requestId, outcome: o.researchOutcome, claimId: o.claimId, evidenceIds: o.evidenceIds, gap: o.gap, json: o.json, projectRoot: storeRoot, sourceRoot: evidenceRoot(o) });
268
402
  // The store is shared by every linked worktree of the clone (lifecycle's main-worktree root); the
269
403
  // feature is `--slug`, else the branch's, resolved the way decision and scaffold resolve it.
270
- case 'task-attempt': return handleTaskAttemptCommand({ action: o.actionGiven ? o.action : undefined, slug: o.slug, task: o.task, owner: o.owner, mode: o.mode, token: o.token, result: o.result, evidenceId: o.evidenceId, reason: o.reason, json: o.json, cwd: evidenceRoot(o), resolveSlug: (cwd ) => featureSlugFor({ projectRoot: cwd }) });
271
- case 'retrieve': return handleRetrieveCommand({ query: o.query, top: o.top, json: o.json });
404
+ case 'task-attempt': return handleTaskAttemptCommand({ action: o.actionGiven ? o.action : undefined, slug: o.slug, task: o.task, owner: o.owner, mode: o.mode, token: o.token, result: o.result, evidenceId: o.evidenceId, reason: o.reason, ownerOverride: o.ownerOverride, epoch: o.epoch, reserveTokens: o.reserveTokens, execWorktree: o.execWorktree, tokens: o.tokens, tokensBasis: o.tokensBasis, budgetAttempts: o.budgetAttempts, budgetTokens: o.budgetTokens, by: o.by, ack: o.ack, adoptUnowned: Boolean(o.adoptUnowned), json: o.json, cwd: evidenceRoot(o), resolveSlug: (cwd ) => featureSlugFor({ projectRoot: cwd }) });
405
+ // 081 IC-026: the worker adapter reads and writes the same main-worktree store as task-attempt.
406
+ case 'worker': return handleWorkerCommand({ action: o.actionGiven ? o.action : undefined, slug: o.slug, harness: o.harness, need: o.need, modelCheck: o.modelCheck, budgetTokens: o.budgetTokens, task: o.task, token: o.token, promptFile: o.promptFile, timeoutSeconds: o.timeoutSeconds, wait: Boolean(o.wait), edit: Boolean(o.edit), childOf: o.childOf, request: o.request, execWorktree: o.execWorktree, workerRun: o.workerRun, checks: o.checks, out: o.out, by: o.by, reason: o.reason, json: o.json, env: process.env, cwd: evidenceRoot(o), resolveSlug: (cwd ) => featureSlugFor({ projectRoot: cwd }) });
407
+ // 082 IC-001, IC-038: the dispatch loop shares the main-worktree store root with task-attempt.
408
+ // `--status` is parsed under `attemptStatus` (retrieval-plan's key), so it is renamed here.
409
+ case 'dispatch': return handleDispatchCommand({ action: o.actionGiven ? o.action : undefined, slug: o.slug, by: o.by, reason: o.reason, concurrency: o.concurrency, mode: o.mode, billingCap: o.billingCap, verifyArgv: o.verifyArgv, verifySeconds: o.verifySeconds, attemptSeconds: o.attemptSeconds, reserveTokens: o.reserveTokens, budgetAttempts: o.budgetAttempts, budgetTokens: o.budgetTokens, spawnGrant: o.spawnGrant, harness: o.harness, need: o.need, maxSeconds: o.maxSeconds, dispatch: o.dispatch, status: o.attemptStatus, summary: o.summary, blocker: o.blocker, tokens: o.tokens, tokensBasis: o.tokensBasis, promptFile: o.promptFile, requestId: o.requestId, task: o.task, ack: o.ack, fallback: o.fallback, ladder: o.ladder, json: o.json, env: process.env, cwd: evidenceRoot(o), resolveSlug: (cwd ) => featureSlugFor({ projectRoot: cwd }) });
410
+ // Code scope keeps two roots: the search root is --root or cwd (the invoking checkout), the state root is
411
+ // the feature store above. Guidance gets no stateRoot, exactly as before 079, so it resolves from cwd.
412
+ case 'retrieve': return handleRetrieveCommand({ query: o.query, top: o.top, json: o.json, scope: o.scope,
413
+ profile: o.profile, root: o.root, indexAction: o.indexAction, modelPath: o.modelPath,
414
+ taskId: o.taskId, need: o.need, slug: storeSlug, stateRoot: o.scope === 'code' ? storeRoot : undefined, repoRoot: REPO_ROOT });
272
415
  case 'brief-tools': return handleBriefToolsCommand({ owner: o.owner, tier: o.tier, harness: o.harness, slug: o.slug, headingLevel: o.headingLevel, tasks: o.tasks, json: o.json, repoRoot: REPO_ROOT, projectRoot: storeRoot, buildAdapters: buildAdapterRegistry });
273
416
  case 'advise': return handleAdviseCommand({ action: o.action, actionGiven: o.actionGiven, kind: o.kind, server: o.server, state: o.state, stateFile: o.stateFile, staticAnswer: o.staticAnswer, questionsFile: o.questionsFile, taskId: o.taskId, pickId: o.pickId, actual: o.actual, model: o.model, endpoint: o.endpoint, off: o.off, project: o.project, force: o.force, global: o.global, json: o.json, projectRoot: evidenceRoot(o) });
274
- case 'model-role': return handleModelRoleCommand({ role: o.role, exclude: o.exclude, json: o.json, repoRoot: REPO_ROOT });
417
+ case 'model-role': return handleModelRoleCommand({ role: o.role, exclude: o.exclude, excludeFamilies: o.excludeFamily, json: o.json, repoRoot: REPO_ROOT });
275
418
  case 'route': return handleRouteCommand({ intent: o.intent, query: o.query, check: o.check, json: o.json, projectRoot: evidenceRoot(o) });
276
419
  case 'claim': return handleClaimCommand({ slug: storeSlug, taskId: requireTaskId(o), action: o.action, statement: o.statement, claimId: o.claimId, evidenceId: o.evidenceId, replacedBy: o.replacedBy, relation: o.relation, role: o.role, json: o.json, stateRoot: storeRoot });
277
- case 'context-pack': return handleContextPackCommand({ taskId: requireTaskId(o), taskClass: o.taskClass, objective: o.objective, json: o.json, stateRoot: evidenceRoot(o), slug: o.slug, mandatoryFile: o.mandatoryFile, harness: o.harness, maxBytes: o.maxBytes, bare: o.bare, noRecord: o.noRecord, reason: o.reason, since: o.since, expand: o.expand });
420
+ case 'context-pack': return handleContextPackCommand({ taskId: requireTaskId(o), taskClass: o.taskClass, objective: o.objective, json: o.json, stateRoot: storeRoot, sourceRoot: evidenceRoot(o), slug: storeSlug, explicitSlug: o.slug || null, mandatoryFile: o.mandatoryFile, harness: o.harness, maxBytes: o.maxBytes, bare: o.bare, noRecord: o.noRecord, reason: o.reason, since: o.since, expand: o.expand });
421
+ // 078 IC-005 and IC-013: identity is the process environment's alone, never a flag.
422
+ case 'context-emit': return handleContextEmitCommand({ event: o.event, cwd: o.cwd, session: o.session, harness: o.harness, nudge: o.nudge, maxBytes: o.maxBytes, taskId: o.taskId || undefined, slug: o.slug || undefined, stateRoot: redirected ? storeRoot : undefined, peek: o.peek, json: o.json });
423
+ case 'context-grant': return handleContextGrantCommand({ summary: o.summary, toRun: o.toRun, toLineage: o.toLineage, fromWorktree: o.fromWorktree, fromRun: o.fromRun, fromLineage: o.fromLineage, maxBytes: o.maxBytes, json: o.json });
278
424
  case 'retrieval-plan': return handleRetrievalPlanCommand({ slug: storeSlug, taskId: requireTaskId(o), action: o.action, need: o.need, stage: o.stage, provider: o.provider, attemptStatus: o.attemptStatus, reason: o.reason, note: o.note, json: o.json, repoRoot: REPO_ROOT, stateRoot: storeRoot, sourceRoot: evidenceRoot(o) });
279
- case 'outcome': return handleOutcomeCommand({ slug: o.slug, taskId: requireTaskId(o), action: o.action, state: o.state, taskClass: o.taskClass, stage: o.stage, readiness: o.readiness, verification: o.verification, json: o.json, repoRoot: REPO_ROOT, stateRoot: evidenceRoot(o) });
425
+ case 'outcome': return handleOutcomeCommand({ slug: storeSlug, taskId: requireTaskId(o), action: o.action, state: o.state, taskClass: o.taskClass, stage: o.stage, readiness: o.readiness, verification: o.verification, json: o.json, repoRoot: REPO_ROOT, stateRoot: storeRoot });
280
426
  case 'verify': return handleVerifyCommand({ slug: o.slug, taskId: requireTaskId(o), action: o.action, risk: o.risk, planPath: o.planPath, scope: o.scope, verificationInput: o.verificationInput, verificationPhase: o.verificationPhase, baselineRef: o.baselineRef, json: o.json, projectRoot: evidenceRoot(o) });
281
427
  case 'leak-scan': return handleLeakScanCommand({ paths: o.paths, exclude: o.exclude, json: o.json, repoRoot: evidenceRoot(o) });
282
428
  case 'recover': return handleRecoverCommand({ errorMessage: o.errorMessage, failedChecks: o.failedChecks, iteration: o.iteration, agent: o.agent, json: o.json });
429
+ case 'roadmap': return handleRoadmapVerbCommand(o);
430
+ case 'plan-check': return handlePlanCheckCommand({ positional: o.positional, extraFlags: o.extraFlags, json: o.json, cwd: process.cwd() });
431
+ // One --path only: a second occurrence reaches the handler as a list, which it refuses as usage.
432
+ case 'review': return handleReviewCommand({ action: o.actionGiven ? o.action : undefined, slug: o.slug, path: o.paths?.length === 1 ? o.paths[0] : o.paths, base: o.base, preset: o.preset, json: o.json, cwd: process.cwd(), env: process.env });
433
+ case 'protocol': return handleProtocolCommand({ action: o.actionGiven ? o.action : undefined, kind: o.kind, taskClass: o.taskClass, risk: o.risk, preset: o.preset, positional: o.positional, json: o.json, cwd: process.cwd() });
434
+ case 'rules': return handleRulesCommand({ taskClass: o.taskClass, json: o.json, global: o.global, positional: o.positional, env: process.env, cwd: process.cwd() });
435
+ case 'primary': return handlePrimaryCommand({ action: o.actionGiven ? o.action : undefined, json: o.json, flags: o.flagsGiven, env: process.env, cwd: process.cwd() });
436
+ case 'package': return handlePackageCommand({ action: o.actionGiven ? o.action : undefined, path: o.paths?.length === 1 ? o.paths[0] : o.paths, id: o.id, source: o.source, index: o.index, packageVersion: o.packageVersion, plan: o.planId, repair: o.repair, points: o.points, dir: o.dir, json: o.json });
437
+ case 'slot': return handleSlotCommand({ action: o.actionGiven ? o.action : undefined, name: o.name, label: o.label, timeout: o.timeout, noWait: Boolean(o.noWait), command: o.slotCommand, by: o.by, reason: o.reason, positional: o.positional, extraFlags: o.extraFlags, json: o.json, env: process.env, cwd: process.cwd() });
438
+ case 'fleet': return handleFleetCommand({ action: o.actionGiven ? o.action : undefined, json: o.json, flags: o.flagsGiven, env: process.env, cwd: process.cwd() });
439
+ case 'transcript': return handleTranscriptCommand({ action: o.actionGiven ? o.action : undefined, agent: o.agent, cursor: o.cursor, limit: o.limit, window: o.window, json: o.json, flags: o.flagsGiven, env: process.env, cwd: process.cwd() });
440
+ case 'models': return handleModelsCommand({ action: o.actionGiven ? o.action : (o.positional?.[0] || 'list'), positional: o.positional, harness: o.harness, model: o.model, json: o.json, projectRoot: evidenceRoot(o) });
441
+ case 'worktree': return handleWorktreeCommand({ action: o.actionGiven ? o.action : undefined, slug: o.slug, json: o.json, flags: o.flagsGiven, env: process.env, cwd: process.cwd() });
442
+ case 'attendance': return handleAttendanceCommand({ taskId: o.taskId, run: o.run, json: o.json, flags: o.flagsGiven, env: process.env, cwd: process.cwd() });
283
443
  default: console.error(`doflow: unknown command '${o.cmd}'`); process.exit(1);
284
444
  }
285
445
  }
@@ -288,7 +448,7 @@ function dispatchRuntimeCommandInner(o , moment ) {
288
448
  async function dispatchRuntimeCommand(o ) {
289
449
  const moment = {};
290
450
  const result = await dispatchRuntimeCommandInner(o, moment);
291
- if (o.cmd !== 'storage') upkeepAfterVerb({ projectRoot: moment.projectRoot });
451
+ if (runsUpkeep(o)) upkeepAfterVerb({ projectRoot: moment.projectRoot });
292
452
  return result;
293
453
  }
294
454
 
package/src/cli/shared.js CHANGED
@@ -20,7 +20,6 @@ const { createAdapterRegistry } = require('../adapters/index.js');
20
20
  const { declaredHarnessPaths } = require('../helper/harness-paths.js');
21
21
  const claudeAdapter = require('../adapters/claude/index.js');
22
22
  const codexAdapter = require('../adapters/codex/index.js');
23
- const { createGeminiAdapter } = require('../adapters/gemini/index.js');
24
23
  const { createOpenCodeAdapter } = require('../adapters/opencode/index.js');
25
24
  const { createPiAdapter } = require('../adapters/pi/index.js');
26
25
  const { createCopilotAdapter } = require('../adapters/copilot/index.js');
@@ -55,7 +54,6 @@ function buildAdapterRegistry() {
55
54
  return createAdapterRegistry({
56
55
  claude: claudeAdapter.createClaudeAdapter({ declaredPaths: declared.claude }),
57
56
  codex: codexAdapter.createCodexAdapter({ declaredPaths: declared.codex }),
58
- gemini: createGeminiAdapter({ declaredPaths: declared.gemini }),
59
57
  opencode: createOpenCodeAdapter({ declaredPaths: declared.opencode }),
60
58
  pi: createPiAdapter({ declaredPaths: declared.pi }),
61
59
  copilot: createCopilotAdapter({ declaredPaths: declared.copilot }),
package/src/helper/git.js CHANGED
@@ -5,7 +5,7 @@
5
5
  //
6
6
  // First module of the TypeScript migration (agent-docs/BRIEF_GOAL_DOFLOW.md). Authored as `.ts` and
7
7
  // run directly by Node's native type-stripping (process.features.typescript === 'strip', Node
8
- // ^22.18.0 || >=24.3.0), so no build step and no runtime dependency are added. The body stays CommonJS
8
+ // >=24.22.1), so no build step and no runtime dependency are added. The body stays CommonJS
9
9
  // (`module.exports`) so a `require('../helper/git.js')` from a `.js` caller keeps working while the
10
10
  // rest of the tree is still `.js`; the explicit `.ts` extension on those requires is what the
11
11
  // CommonJS resolver needs to find this file.
@@ -10,7 +10,7 @@
10
10
  // the inner command glob is what every other harness wants.
11
11
  //
12
12
  // TypeScript migration (agent-docs/BRIEF_GOAL_DOFLOW.md): authored as `.ts`, run directly by Node
13
- // native type-stripping (process.features.typescript === 'strip', Node ^22.18.0 || >=24.3.0) — no build step and
13
+ // native type-stripping (process.features.typescript === 'strip', Node >=24.22.1) — no build step and
14
14
  // no runtime dependency. The body stays CommonJS so a `.js` caller's `require('../helper/guardrails.js')`
15
15
  // keeps working while the rest of the tree is still `.js`; the explicit `.ts` extension is what the
16
16
  // CommonJS resolver needs to find this file.
@@ -16,9 +16,12 @@ const MARKER_END = '<!-- doflow:end -->';
16
16
  /**
17
17
  * Merge `srcAbs`'s content into `dstAbs` inside a doflow-owned marker span,
18
18
  * preserving any of `dstAbs`'s own content outside that span byte-for-byte.
19
+ * With `content`, that text is merged instead of the file `srcAbs` names.
19
20
  */
20
- function mergeMarkedSection(srcAbs , dstAbs , { dryRun = false } = {}) {
21
- const srcContent = fs.readFileSync(srcAbs, 'utf8').replace(/\s+$/, '');
21
+ function mergeMarkedSection(srcAbs , dstAbs , { dryRun = false, content } = {}) {
22
+ // `content` is already-rendered text (a pointer with its per-scope path filled in); it replaces
23
+ // reading `srcAbs`, so a caller never has to stage a temporary source file.
24
+ const srcContent = (content !== undefined ? content : fs.readFileSync(srcAbs, 'utf8')).replace(/\s+$/, '');
22
25
  const section = `${MARKER_START}\n${srcContent}\n${MARKER_END}\n`;
23
26
 
24
27
  // Read once, reused both for parsing and for the final no-op comparison below.
@@ -81,28 +84,43 @@ function mergeMarkedSection(srcAbs , dstAbs , { dryRun = false }
81
84
  return { changed: true };
82
85
  }
83
86
 
87
+ /**
88
+ * Where `text`'s doflow span is: the first of `startMarkers`, the first MARKER_END after it, and no
89
+ * start marker after that end (a second span is `malformed`). `after` is past the end marker and the
90
+ * one '\n' that follows it.
91
+ */
92
+ function markedSpan(text , startMarkers = [MARKER_START]) {
93
+ const found = startMarkers.map((marker) => ({ at: text.indexOf(marker), length: marker.length })).filter((item) => item.at !== -1);
94
+ if (!found.length) return { state: 'none' };
95
+ const first = found.reduce((a, b) => (b.at < a.at ? b : a));
96
+ const end = text.indexOf(MARKER_END, first.at + first.length);
97
+ if (end === -1) return { state: 'malformed' };
98
+ let after = end + MARKER_END.length;
99
+ if (startMarkers.some((marker) => text.indexOf(marker, after) !== -1)) return { state: 'malformed' };
100
+ if (text[after] === '\n') after += 1;
101
+ return { state: 'ok', start: first.at, after };
102
+ }
103
+
84
104
  /**
85
105
  * Strip only the doflow-managed span from `file`, leaving any surrounding content (before/after
86
106
  * the markers) byte-for-byte untouched. Companion to `mergeMarkedSection` — shared by the Claude
87
107
  * and Codex adapters' `remove()`, which had each carried an identical private copy of this.
88
108
  * A file that held nothing but the span is DoFlow's own and is deleted; any other file is written
89
- * back, even when only whitespace remains.
109
+ * back, even when only whitespace remains. `startMarkers` (default: MARKER_START alone) lets a
110
+ * caller also accept an older start marker; the retirement sweep is the only one that does.
90
111
  * @returns whether a managed span was found and stripped (false if the file doesn't
91
112
  * exist or has no doflow markers — both are no-ops, not errors)
92
113
  */
93
- function removeMarkedSection(file ) {
114
+ function removeMarkedSection(file , { startMarkers = [MARKER_START] } = {}) {
94
115
  if (!fs.existsSync(file)) return false;
95
116
  const existing = fs.readFileSync(file, 'utf8');
96
- const start = existing.indexOf(MARKER_START);
97
- if (start === -1) return false;
98
- const end = existing.indexOf(MARKER_END, start + MARKER_START.length);
99
- if (end === -1 || existing.indexOf(MARKER_START, end + MARKER_END.length) !== -1) {
117
+ const span = markedSpan(existing, startMarkers);
118
+ if (span.state === 'none') return false;
119
+ if (span.state === 'malformed') {
100
120
  throw new Error(`Refusing to remove malformed DoFlow markers in ${file}`);
101
121
  }
102
- let after = end + MARKER_END.length;
103
- if (existing[after] === '\n') after += 1;
104
- const before = existing.slice(0, start);
105
- const rest = existing.slice(after);
122
+ const before = existing.slice(0, span.start);
123
+ const rest = existing.slice(span.after);
106
124
  if (before === '' && rest === '') {
107
125
  fs.unlinkSync(file);
108
126
  return true;
@@ -113,4 +131,4 @@ function removeMarkedSection(file ) {
113
131
  return true;
114
132
  }
115
133
 
116
- module.exports = { mergeMarkedSection, removeMarkedSection, MARKER_START, MARKER_END };
134
+ module.exports = { mergeMarkedSection, removeMarkedSection, markedSpan, MARKER_START, MARKER_END };
@@ -0,0 +1,37 @@
1
+ 'use strict';
2
+
3
+ // Package, local, qualified and projected identifiers (122 IC-003, PN-3). Pure and dependency-free so
4
+ // `src/registry/` (row 120's worker ids) and `src/runtime/` import the one definition.
5
+
6
+ const PACKAGE_ID = /^[a-z][a-z0-9-]{0,14}[a-z0-9]$/;
7
+ const LOCAL_ID = /^[a-z][a-z0-9-]{0,13}[a-z0-9]$/;
8
+ const QUALIFIED_MAX = 32;
9
+ // Refused as a package id (reserved-id); `doflow` is usable only by the bundled first-party package.
10
+ const RESERVED = ['doflow', 'do', 'core', 'user', 'project', 'local', 'env', 'auto', 'package', 'packages'];
11
+
12
+ const isPackageId = (value ) => typeof value === 'string' && PACKAGE_ID.test(value) && !value.includes('--');
13
+ const isLocalId = (value ) => typeof value === 'string' && LOCAL_ID.test(value) && !value.includes('--');
14
+
15
+ /** True for a package id the grammar accepts but IC-003 reserves: the listed names and any `do-` or `doflow-` prefix. */
16
+ function isReservedPackageId(value ) {
17
+ return typeof value === 'string' && (RESERVED.includes(value) || value.startsWith('do-') || value.startsWith('doflow-'));
18
+ }
19
+
20
+ function isQualifiedId(value ) {
21
+ if (typeof value !== 'string' || value.length > QUALIFIED_MAX) return false;
22
+ const parts = value.split('.');
23
+ return parts.length === 2 && isPackageId(parts[0]) && isLocalId(parts[1]);
24
+ }
25
+
26
+ /** `<package id>.<local id>`, or null when either part breaks its grammar. */
27
+ function qualifiedId(packageId , localId ) {
28
+ const joined = `${packageId}.${localId}`;
29
+ return isPackageId(packageId) && isLocalId(localId) && joined.length <= QUALIFIED_MAX ? joined : null;
30
+ }
31
+
32
+ /** The harness-file name of a qualified id, `<package id>-<local id>`; null when the input is not a qualified id. */
33
+ function projectedName(qualified ) {
34
+ return isQualifiedId(qualified) ? qualified.replace('.', '-') : null;
35
+ }
36
+
37
+ module.exports = { isPackageId, isLocalId, isQualifiedId, isReservedPackageId, qualifiedId, projectedName };