@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
@@ -0,0 +1,392 @@
1
+ 'use strict';
2
+
3
+ // Feature 082 C.1 (IC-007, IC-008 reservation, IC-009 drivers; DEC-002, DEC-003, DEC-018, DEC-019,
4
+ // DEC-033, DEC-038, DEC-040, DEC-047, DEC-059): two-section admission, reservations and drivers.
5
+ //
6
+ // Drivers (IC-009). Each invocation registers `{ pid, start, registeredAt }` in one locked write.
7
+ // Before it, outside the lock because `ps` is a process, every other driver with no `endedAt` and
8
+ // not yet marked lost is read with `alive`; the write applies those readings to the drivers it read
9
+ // only. `false` is lost `driver-lost`, `unknown` is lost `driver-liveness-unknown` (DEC-040), and a
10
+ // lost driver sets the run `resume-required` with that reason. Drivers are read, never signalled
11
+ // (DEC-047): nothing here sends a signal.
12
+ //
13
+ // Admission (IC-007). Outside every lock: 080 `inspect`, the 081 status of each prior dispatch's
14
+ // worker run, and the caller's `modeFor` per candidate (IC-022 lives with the loop, so admission
15
+ // never requires `loop.ts`). First section, one `mutateDispatch`: IC-007 steps 1 to 8, overlap from
16
+ // task-graph's exported `overlaps` (DEC-059) checked against every non-ended dispatch, not only the
17
+ // candidates of this pass (DEC-003, DEC-033). Then each admitted worktree is created outside the
18
+ // lock, and the second section, one `mutateDispatch` per dispatch, re-checks the slot and makes the
19
+ // in-process 080 `claim` with `reserveTokens` (IC-008), `execWorktree`, `epoch` and `owner`. A
20
+ // refusal or a throw drops the slot in the same write; `removeVerified` runs outside the lock. A
21
+ // budget refusal is a gap with cause `budget` (IC-027).
22
+ //
23
+ // Every write goes through `store.ts` (`updateTaskState`); this module makes no fs write call.
24
+ // Every function is synchronous, so a barrier race worker can call it directly.
25
+
26
+ const fs = require('node:fs');
27
+ const { inspect, claim } = require('../task-attempts.js');
28
+ const { overlaps } = require('../task-graph.js');
29
+ const { normalizeFile } = require('./envelope.js');
30
+ const { readTaskState } = require('../task-state.js');
31
+ const { procStart, alive } = require('../worker/process-tree.js');
32
+ const { storeFileFor: runStoreFileFor, readRuns } = require('../worker/run-store.js');
33
+ const { statusView } = require('../worker/command.js');
34
+ const { storeFileFor, readDispatch, mutateDispatch, newDispatchId, setRunState, DispatchStoreError } = require('./store.js');
35
+ const { managerFor, createAttemptWorktree } = require('./integrate.js');
36
+ const { copyGrant } = require('./grants.js');
37
+ const { resolveBinding } = require('../worker/models.js');
38
+
39
+ /** DEC-002: concurrency bounds and default. */
40
+ const CONCURRENCY_MIN = 1;
41
+ const CONCURRENCY_MAX = 4;
42
+ const CONCURRENCY_DEFAULT = 2;
43
+ /** IC-022's main-session modes: at most one such dispatch is non-ended (IC-007 step 7). */
44
+ const MAIN_SESSION_MODES = Object.freeze(['sequential', 'manual']);
45
+ const MODES = Object.freeze(['subagent', 'sequential', 'manual']);
46
+ /** 080 claim refusals that are a gap with cause `budget` (IC-007, IC-027). */
47
+ const BUDGET_REFUSALS = Object.freeze(['aggregate-exhausted', 'budget-exhausted', 'reservation-required']);
48
+ /** IC-009 lost reasons, by `alive` reading. */
49
+ const LOST_REASONS = Object.freeze({ false: 'driver-lost', unknown: 'driver-liveness-unknown' });
50
+ /** 081 statuses that mean a worker run is not gone (IC-007 step 8). */
51
+ const LIVE_WORKER_STATES = Object.freeze(['starting', 'running']);
52
+ const REASON_CHARS = 200;
53
+
54
+
55
+
56
+ function usage(message ) {
57
+ return new DispatchStoreError('usage', message);
58
+ }
59
+
60
+ const sameDriver = (a , b ) => !!a && !!b && a.pid === b.pid && (a.start ?? null) === (b.start ?? null)
61
+ && (a.registeredAt ?? null) === (b.registeredAt ?? null);
62
+
63
+ const clip = (text ) => String(text ?? '').slice(0, REASON_CHARS);
64
+
65
+ /** One StepAction (IC-003). */
66
+ function action(name , d , reason , ms = 0) {
67
+ return { action: name, dispatchId: d.dispatchId ?? null, task: d.task ?? null, token: d.token ?? null, reason: clip(reason), ms };
68
+ }
69
+
70
+ // ── drivers (IC-009) ─────────────────────────────────────────────────────────────────────────────
71
+
72
+ /**
73
+ * IC-009: registers this invocation's driver. Every other driver with no `endedAt` and no `lost`
74
+ * is read with `alive` outside the lock; the locked write marks each one read `false` or
75
+ * `unknown` lost (`lost` its reason) and sets the run `resume-required` with `resumeReason`.
76
+ * A driver registered after the read is left for the next reading. `aliveImpl` and `startImpl` are
77
+ * seams for an injected reading. Returns `{ driver, lost: [{ pid, start, reason }], state }`.
78
+ */
79
+ function registerDriver({
80
+ file, pid = process.pid, now = new Date(), aliveImpl = alive, startImpl = procStart, fsImpl = fs,
81
+ } ) {
82
+ if (typeof file !== 'string') throw usage('registerDriver needs the dispatch store file');
83
+ if (!Number.isInteger(pid) || pid <= 0) throw usage(`driver pid '${pid}' is not a positive whole number`);
84
+ const driver = { pid, start: startImpl(pid) ?? null, registeredAt: now.toISOString(), endedAt: null };
85
+
86
+ // Outside the lock: the readings, `ps` being a process.
87
+ const before = readDispatch(file, fsImpl);
88
+ const readings = (before.drivers )
89
+ .filter((d) => d && !d.endedAt && !d.lost)
90
+ .map((d) => ({ driver: { pid: d.pid, start: d.start ?? null, registeredAt: d.registeredAt ?? null }, live: aliveImpl({ pid: d.pid, pgid: d.pid, start: d.start ?? null }) }));
91
+
92
+ return mutateDispatch(file, (store ) => {
93
+ const lost = [];
94
+ for (const { driver: read, live } of readings) {
95
+ if (live === true) continue;
96
+ const reason = live === false ? LOST_REASONS.false : LOST_REASONS.unknown;
97
+ const stored = (store.drivers ).find((d) => sameDriver(d, read));
98
+ if (!stored || stored.endedAt || stored.lost) continue;
99
+ stored.lost = reason;
100
+ lost.push({ pid: stored.pid, start: stored.start ?? null, reason });
101
+ }
102
+ store.drivers.push(driver);
103
+ if (lost.length && store.run && setRunState(store, 'resume-required')) store.run.resumeReason = lost[0].reason;
104
+ return { write: true, result: { driver: structuredClone(driver), lost, state: store.run ? store.run.state : null } };
105
+ }, fsImpl);
106
+ }
107
+
108
+ /**
109
+ * IC-009: writes `endedAt` on this invocation's driver, add-only. With `endReason: 'threw'` (a pass
110
+ * that threw, RT-5) the same write records the reason and sets the run `resume-required`, reason
111
+ * `driver-threw`, unless it holds a state another writer owns, so IC-032 settles what the pass left
112
+ * in flight. `{ ended }`.
113
+ */
114
+ function endDriver({ file, driver, now = new Date(), endReason = null, fsImpl = fs } ) {
115
+ if (!driver || !Number.isInteger(driver.pid)) throw usage('endDriver needs the driver registerDriver returned');
116
+ return mutateDispatch(file, (store ) => {
117
+ const stored = (store.drivers ).find((d) => sameDriver(d, driver));
118
+ if (!stored || stored.endedAt) return { write: false, result: { ended: false } };
119
+ stored.endedAt = now.toISOString();
120
+ if (endReason === 'threw') {
121
+ stored.endReason = 'threw';
122
+ if (store.run && setRunState(store, 'resume-required')) store.run.resumeReason = 'driver-threw';
123
+ }
124
+ return { write: true, result: { ended: true } };
125
+ }, fsImpl);
126
+ }
127
+
128
+ // ── admission (IC-007) ───────────────────────────────────────────────────────────────────────────
129
+
130
+ /** `modeFor`'s answer as `{ mode, harness, selection }`, or `{ hold }` for a held task (106 IC-004). */
131
+ function modeOf(answer , task ) {
132
+ if (answer && typeof answer.hold === 'string') return { hold: answer.hold };
133
+ const out = typeof answer === 'string' ? { mode: answer } : (answer && typeof answer === 'object' ? answer : {});
134
+ if (!MODES.includes(out.mode)) throw usage(`modeFor('${task}') returned mode '${out.mode}', not one of ${MODES.join(', ')}`);
135
+ return { mode: out.mode, harness: out.mode === 'subagent' ? out.harness ?? null : null, selection: out.selection ?? null };
136
+ }
137
+
138
+ /** IC-013 / IC-010: validate and copy an optional admission model snapshot. */
139
+ function modelOf(answer , task ) {
140
+ if (answer === undefined || answer === null) {
141
+ return { model: { tier: null, requested: null, source: null }, primary: null };
142
+ }
143
+ const object = (value ) => value !== null && typeof value === 'object' && !Array.isArray(value);
144
+ const nullableString = (value ) => value === null || typeof value === 'string';
145
+ const model = answer.model;
146
+ const primary = answer.primary;
147
+ if (!object(answer) || !object(model) || !['light', 'standard', 'frontier'].includes(model.tier)
148
+ || !nullableString(model.requested) || !['binding', 'harness-default'].includes(model.source)
149
+ || (primary !== null && (!object(primary)
150
+ || Object.keys(primary).sort().join(',') !== 'harness,model,state'
151
+ || !nullableString(primary.harness) || !nullableString(primary.model)
152
+ || typeof primary.state !== 'string' || primary.state.length === 0))) {
153
+ throw usage(`modelFor('${task}') returned an invalid model snapshot`);
154
+ }
155
+ return {
156
+ model: { tier: model.tier, requested: model.requested, source: model.source },
157
+ primary: primary === null ? null : { harness: primary.harness, model: primary.model, state: primary.state },
158
+ };
159
+ }
160
+
161
+ /** IC-013 / IC-010: resolve record metadata without choosing launch argv or reading settings. */
162
+ function dispatchModelFor({ mode, harness, tier, bindings, primary } ) {
163
+ const worker = mode === 'subagent' ? harness : mode === 'sequential' ? primary?.harness : null;
164
+ const binding = worker ? resolveBinding({ worker, tier, bindings, descriptor: null }) : null;
165
+ const bound = binding?.source === 'binding';
166
+ return {
167
+ model: { tier, requested: bound ? binding.model : null, source: bound ? 'binding' : 'harness-default' },
168
+ primary: mode === 'sequential' && primary
169
+ ? { harness: primary.harness, model: primary.model, state: primary.state }
170
+ : null,
171
+ };
172
+ }
173
+
174
+ /** The 081 status of every worker run a dispatch of `store` names, read outside the lock. */
175
+ function workerStatuses(root , slug , store , ledgerFile , fsImpl , nowMs ) {
176
+ const named = (Object.values(store.dispatches) ).filter((d) => d.workerRunId);
177
+ const out = new Map ();
178
+ if (!named.length) return out;
179
+ const runs = readRuns(runStoreFileFor(root, slug), fsImpl);
180
+ const ledger = readTaskState(fsImpl, ledgerFile) || { tasks: {}, runs: {} };
181
+ for (const d of named) {
182
+ const run = runs[d.workerRunId];
183
+ out.set(d.workerRunId, run ? statusView(run, ledger, { platform: process.platform, nowMs }) : null);
184
+ }
185
+ return out;
186
+ }
187
+
188
+ /** IC-007 step 8: a prior ended dispatch of `task` whose worker run is not gone, or null. */
189
+ function workerNotGone(store , task , statuses ) {
190
+ for (const d of Object.values(store.dispatches) ) {
191
+ if (d.task !== task || d.phase !== 'ended' || !d.workerRunId) continue;
192
+ const status = statuses.get(d.workerRunId);
193
+ const cleanup = d.cleanup ? d.cleanup.cleanup ?? d.cleanup : status ? status.cleanup : null;
194
+ if ((status && LIVE_WORKER_STATES.includes(status.state)) || (cleanup && cleanup.status === 'survivors')) return d;
195
+ }
196
+ return null;
197
+ }
198
+
199
+ const isCandidate = (record ) => record.state === 'READY' || (record.state === 'FAILED' && record.claimable === true);
200
+
201
+ /**
202
+ * IC-007, phase 6 of IC-003. `ctx` is B.3's 080 context (`ledgerFile`, `roots`, `slug`, `env`,
203
+ * `cwd`, `fsImpl`); `root` the lifecycle root holding the dispatch store and worktrees; `driver` the
204
+ * `{ pid, start }` this pass registered; `by` the owner when a plan task names none; `modeFor(task,
205
+ * { record, store })` IC-022's choice, called outside the lock once per candidate, returning a mode
206
+ * or `{ mode, harness, selection }`. Optional `modelFor(task, { mode, harness, selection })`
207
+ * supplies IC-013 / IC-010 metadata beside that choice, outside every lock and never for a hold.
208
+ *
209
+ * Returns `{ outcome, admitted, skipped, refused, gaps, actions }`: `outcome` is `admitted` when a
210
+ * dispatch was claimed, else `none` or the reason nothing was admitted (`paused`, the run's state,
211
+ * `no-run`, `verification-undeclared`, `concurrency-full`). `actions` are IC-003 StepActions for the
212
+ * caller's step record.
213
+ */
214
+ function admit({
215
+ root, slug, ctx, driver, by, modeFor, modelFor, env = process.env, now = () => new Date(), storeFile = null,
216
+ } ) {
217
+ if (typeof modeFor !== 'function') throw usage('admit needs modeFor, IC-022\'s mode choice');
218
+ if (!ctx || typeof ctx.ledgerFile !== 'string' || !Array.isArray(ctx.roots)) throw usage('admit needs ctx with ledgerFile and roots');
219
+ const fsImpl = ctx.fsImpl || fs;
220
+ const file = storeFile ?? storeFileFor(root, slug);
221
+ const who = driver ? { pid: driver.pid, start: driver.start ?? null } : { pid: process.pid, start: null };
222
+ const empty = (outcome , extra = {}) => ({ outcome, admitted: [], skipped: [], refused: [], gaps: [], actions: [], ...extra });
223
+
224
+ // Outside every lock: 080 inspect, 081 statuses and the mode per candidate.
225
+ const view = inspect({ file: ctx.ledgerFile, fsImpl, roots: ctx.roots, slug, env: ctx.env ?? env, cwd: ctx.cwd });
226
+ const pre = readDispatch(file, fsImpl);
227
+ const statuses = workerStatuses(root, slug, pre, ctx.ledgerFile, fsImpl, now().getTime());
228
+ const graph = { tasks: view.graph.tasks };
229
+ const filesOf = new Map (view.graph.tasks.map((t ) => [t.id, (t.files || []).map(normalizeFile).filter(Boolean)]));
230
+ const ownerOf = new Map (view.graph.tasks.map((t ) => [t.id, t.owner ?? null]));
231
+ const pairs = new Set (overlaps(graph).flatMap((p ) => [`${p.a}\u0000${p.b}`, `${p.b}\u0000${p.a}`]));
232
+ const modes = new Map ();
233
+ const models = new Map ();
234
+ for (const record of view.tasks) {
235
+ if (!isCandidate(record)) continue;
236
+ const choice = modeOf(modeFor(record.id, { record, store: pre }), record.id);
237
+ modes.set(record.id, choice);
238
+ if (choice.hold) continue;
239
+ models.set(record.id, modelOf(typeof modelFor === 'function' ? modelFor(record.id, choice) : null, record.id));
240
+ }
241
+ const manager = managerFor(root, slug, 'attempt', env);
242
+
243
+ // First section: IC-007 steps 1 to 8 and the admitted slots.
244
+ const first = mutateDispatch(file, (store ) => {
245
+ const run = store.run;
246
+ if (!run) return { write: false, result: empty('no-run') };
247
+ if (run.state !== 'running' || view.run.control !== 'running') {
248
+ return { write: false, result: empty(view.run.control === 'paused' ? 'paused' : run.state !== 'running' ? run.state : view.run.control) };
249
+ }
250
+ if (!run.verify || !Array.isArray(run.verify.argv)) return { write: false, result: empty('verification-undeclared') };
251
+ const concurrency = Number.isInteger(run.concurrency) ? run.concurrency : CONCURRENCY_DEFAULT;
252
+ const nonEnded = (Object.values(store.dispatches) ).filter((d) => d.phase !== 'ended');
253
+ if (nonEnded.length >= concurrency) return { write: false, result: empty('concurrency-full') };
254
+
255
+ // Every non-ended dispatch's task, the ones admitted below included.
256
+ const busy = nonEnded.map((d) => ({ task: d.task, dispatchId: d.dispatchId, mode: d.mode }));
257
+ // The write sets a candidate is checked against: every non-ended dispatch, not only this pass's (DEC-003).
258
+ const holders = busy.map((b) => ({ task: b.task, dispatchId: b.dispatchId }));
259
+ const admitted = [];
260
+ const skipped = [];
261
+ for (const record of view.tasks) {
262
+ const task = record.id;
263
+ const active = busy.find((b) => b.task === task);
264
+ if (active) { skipped.push({ task, reason: 'active-dispatch', dispatchId: active.dispatchId }); continue; }
265
+ if (!isCandidate(record)) continue;
266
+ if (modes.get(task)?.hold) { skipped.push({ task, reason: `held:${modes.get(task).hold}` }); continue; }
267
+ if (nonEnded.length + admitted.length >= concurrency) { skipped.push({ task, reason: 'concurrency' }); continue; }
268
+ const mine = filesOf.get(task) || [];
269
+ const clash = holders.find((b) => !mine.length || !(filesOf.get(b.task) || []).length || pairs.has(`${task}\u0000${b.task}`));
270
+ if (clash) { skipped.push({ task, reason: 'overlap', dispatchId: clash.dispatchId, with: clash.task }); continue; }
271
+ const choice = modes.get(task);
272
+ if (!choice) { skipped.push({ task, reason: 'no-mode' }); continue; }
273
+ const mainBusy = MAIN_SESSION_MODES.includes(choice.mode) && busy.find((b) => MAIN_SESSION_MODES.includes(b.mode));
274
+ if (mainBusy) { skipped.push({ task, reason: 'main-session-busy', dispatchId: mainBusy.dispatchId }); continue; }
275
+ const gone = workerNotGone(store, task, statuses);
276
+ if (gone) { skipped.push({ task, reason: 'worker-not-gone', dispatchId: gone.dispatchId }); continue; }
277
+
278
+ const dispatchId = newDispatchId();
279
+ const metadata = models.get(task);
280
+ store.dispatches[dispatchId] = {
281
+ dispatchId, dispatchRunId: run.dispatchRunId ?? null, parentRunKey: run.runKey ?? view.run.runKey ?? null,
282
+ task, token: null, epoch: null, phase: 'admitted', mode: choice.mode, harness: choice.harness,
283
+ selection: choice.selection, grant: copyGrant(run.spawnGrant ?? null, choice.mode),
284
+ model: { ...metadata.model, served: null },
285
+ ...(choice.mode === 'sequential' && metadata.primary ? { primary: { ...metadata.primary } } : {}),
286
+ workerRunId: null, disposition: null, failureClass: null,
287
+ attempt: { worktree: manager.pathFor(dispatchId), branch: manager.branchFor(dispatchId), base: run.integration ? run.integration.head : null },
288
+ admittedAt: now().toISOString(), admittedBy: who,
289
+ };
290
+ if (MAIN_SESSION_MODES.includes(choice.mode) && run.held && Object.hasOwn(run.held, task)) delete run.held[task];
291
+ busy.push({ task, dispatchId, mode: choice.mode });
292
+ holders.push({ task, dispatchId });
293
+ admitted.push({ dispatchId, task, base: store.dispatches[dispatchId].attempt.base });
294
+ }
295
+ return { write: admitted.length > 0, result: { outcome: admitted.length ? 'admitted' : 'none', slots: admitted, skipped } };
296
+ }, fsImpl);
297
+ if (!first.slots) return first;
298
+
299
+ const result = { outcome: 'none', admitted: [], skipped: first.skipped, refused: [], gaps: [], actions: [] };
300
+ for (const s of first.skipped) result.actions.push(action('admit', { dispatchId: s.dispatchId, task: s.task }, `skipped:${s.reason}`));
301
+
302
+ for (const slot of first.slots) {
303
+ const started = Date.now();
304
+ const { dispatchId, task } = slot;
305
+ // Outside the lock: the attempt worktree (IC-016).
306
+ let made = null;
307
+ let madeError = null;
308
+ try {
309
+ if (slot.base) made = createAttemptWorktree({ root, slug, dispatchId, base: slot.base, env });
310
+ else madeError = 'integration-head-unknown';
311
+ } catch (error ) {
312
+ madeError = `worktree-failed:${error && (error.status ?? error.code) ? String(error.status ?? error.code) : 'error'}`;
313
+ }
314
+
315
+ // Second section: re-check the slot, then the in-process 080 claim.
316
+ const second = mutateDispatch(file, (store ) => {
317
+ const d = store.dispatches[dispatchId];
318
+ if (!d || d.phase !== 'admitted') return { write: false, result: { kind: 'gone', phase: d ? d.phase : null } };
319
+ const drop = (reason , refusal = null) => {
320
+ delete store.dispatches[dispatchId];
321
+ return { write: true, result: { kind: 'refused', reason, refusal } };
322
+ };
323
+ if (madeError) return drop(madeError);
324
+ if (!store.run || store.run.state !== 'running') return drop(`run-${store.run ? store.run.state : 'missing'}`);
325
+ const reserve = Number.isInteger(store.run.reserveTokens) ? store.run.reserveTokens : null;
326
+ let claimed ;
327
+ try {
328
+ claimed = claim({
329
+ file: ctx.ledgerFile, fsImpl, roots: ctx.roots, slug, task, owner: ownerOf.get(task) || by, mode: d.mode,
330
+ epoch: view.run.epoch, reserveTokens: reserve, execWorktree: made.worktree,
331
+ env: ctx.env ?? env, cwd: ctx.cwd, now: now(),
332
+ });
333
+ } catch (error ) {
334
+ return drop(`error:${error && error.code ? error.code : 'throw'}`, { message: clip(error && error.message) });
335
+ }
336
+ if (!claimed || claimed.disposition !== 'claimed') return drop(claimed ? claimed.reason : 'no-result', claimed);
337
+ Object.assign(d, {
338
+ phase: 'claimed', token: claimed.token, epoch: claimed.epoch ?? view.run.epoch,
339
+ parentRunKey: claimed.runKey ?? d.parentRunKey, attempt: made, reservation: { tokens: reserve },
340
+ claimedAt: now().toISOString(), claimedBy: who,
341
+ });
342
+ return { write: true, result: { kind: 'claimed', dispatch: structuredClone(d) } };
343
+ }, fsImpl);
344
+
345
+ const ms = Date.now() - started;
346
+ if (second.kind === 'claimed') {
347
+ const d = second.dispatch;
348
+ result.admitted.push({ dispatchId, task, token: d.token, epoch: d.epoch, mode: d.mode, harness: d.harness, worktree: d.attempt.worktree });
349
+ result.actions.push(action('admit', d, `claimed:${d.mode}`, ms));
350
+ continue;
351
+ }
352
+ if (second.kind === 'gone') {
353
+ // A cancel or resume dropped the slot before its worktree existed: remove it here (RT-14).
354
+ if (made) manager.removeVerified(dispatchId);
355
+ result.actions.push(action('admit', { dispatchId, task }, `slot-moved:${second.phase ?? 'dropped'}`, ms));
356
+ continue;
357
+ }
358
+ // A dropped slot: its worktree is removed outside the lock.
359
+ const removal = made || madeError ? manager.removeVerified(dispatchId) : null;
360
+ const refused = { dispatchId, task, reason: second.reason, refusal: second.refusal, removal };
361
+ if (BUDGET_REFUSALS.includes(second.reason)) {
362
+ refused.gap = { task, kind: 'claim-refused', cause: 'budget', reason: second.reason };
363
+ result.gaps.push(refused.gap);
364
+ }
365
+ result.refused.push(refused);
366
+ result.actions.push(action('claim-refused', { dispatchId, task }, second.reason, ms));
367
+ }
368
+ result.outcome = result.admitted.length ? 'admitted' : 'none';
369
+ return result;
370
+ }
371
+
372
+ /** DEC-002: `value` as a concurrency, default 2; anything outside 1 to 4 is `usage`. */
373
+ function concurrencyOf(value ) {
374
+ if (value === undefined || value === null) return CONCURRENCY_DEFAULT;
375
+ const n = typeof value === 'string' && /^\d+$/.test(value) ? Number(value) : value;
376
+ if (!Number.isInteger(n) || n < CONCURRENCY_MIN || n > CONCURRENCY_MAX) throw usage(`--concurrency expects ${CONCURRENCY_MIN} to ${CONCURRENCY_MAX}, got '${value}'`);
377
+ return n;
378
+ }
379
+
380
+ module.exports = {
381
+ registerDriver,
382
+ endDriver,
383
+ admit,
384
+ dispatchModelFor,
385
+ concurrencyOf,
386
+ CONCURRENCY_MIN,
387
+ CONCURRENCY_MAX,
388
+ CONCURRENCY_DEFAULT,
389
+ MAIN_SESSION_MODES,
390
+ BUDGET_REFUSALS,
391
+ LOST_REASONS,
392
+ };