@khoavu882/doflow 2.0.0-beta.4 → 2.0.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (497) hide show
  1. package/README.md +12 -11
  2. package/bin/doflow.js +21 -11
  3. package/core/.antigravity-plugin/plugin.json +1 -3
  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 +7 -17
  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-bash-guard.sh +7 -17
  15. package/core/harnesses/claude/hooks/pre-compact.sh +23 -27
  16. package/core/harnesses/claude/hooks/pre-implement-gate.sh +7 -18
  17. package/core/harnesses/claude/hooks/session-end.sh +23 -10
  18. package/core/harnesses/claude/hooks/session-start.sh +5 -3
  19. package/core/harnesses/claude/hooks/skill-config-audit.sh +3 -0
  20. package/core/harnesses/claude/hooks/stop-check.sh +5 -3
  21. package/core/harnesses/claude/hooks/subagent-audit.sh +5 -5
  22. package/core/harnesses/claude/hooks/user-prompt-submit.sh +5 -3
  23. package/core/harnesses/claude/settings/settings.json +18 -0
  24. package/core/harnesses/claude/statusline/doflow-statusline.sh +1 -0
  25. package/core/harnesses/codex/agents/core-implementer.toml +1 -0
  26. package/core/harnesses/codex/agents/delivery-lead.toml +10 -0
  27. package/core/harnesses/codex/agents/quality-guardian.toml +1 -1
  28. package/core/harnesses/codex/agents/research-writer.toml +1 -1
  29. package/core/harnesses/codex/agents/reviewer.toml +10 -0
  30. package/core/harnesses/codex/agents/spec-analyst.toml +1 -1
  31. package/core/harnesses/codex/agents/system-architect.toml +1 -1
  32. package/core/harnesses/codex/hooks/lib.sh +44 -25
  33. package/core/harnesses/codex/hooks/mcp-tool-guard.sh +7 -15
  34. package/core/harnesses/codex/hooks/post-edit-lint.impl.sh +3 -1
  35. package/core/harnesses/codex/hooks/pre-bash-guard.sh +7 -15
  36. package/core/harnesses/codex/hooks/pre-compact.impl.sh +29 -26
  37. package/core/harnesses/codex/hooks/pre-implement-gate.sh +7 -16
  38. package/core/harnesses/codex/hooks/session-end.impl.sh +23 -10
  39. package/core/harnesses/codex/hooks/session-start.sh +5 -3
  40. package/core/harnesses/codex/hooks/stop-check.sh +6 -5
  41. package/core/harnesses/codex/hooks/subagent-audit.sh +18 -6
  42. package/core/harnesses/codex/hooks/user-prompt-submit.sh +5 -4
  43. package/core/harnesses/copilot/hooks/doflow-lib.sh +93 -0
  44. package/core/harnesses/copilot/hooks/doflow-mcp-tool-guard.sh +9 -0
  45. package/core/harnesses/copilot/hooks/doflow-pre-bash-guard.sh +9 -0
  46. package/core/harnesses/copilot/hooks/doflow-pre-implement-gate.sh +9 -0
  47. package/core/harnesses/copilot/hooks/doflow-session-start.sh +9 -0
  48. package/core/harnesses/copilot/hooks/doflow-stop-check.sh +9 -0
  49. package/core/harnesses/copilot/hooks/doflow-subagent-start.sh +9 -0
  50. package/core/harnesses/copilot/hooks/doflow-subagent-stop.sh +9 -0
  51. package/core/harnesses/copilot/hooks/doflow.json +57 -0
  52. package/core/harnesses/kiro/agents/doflow.json +1 -1
  53. package/core/harnesses/kiro/hooks/lib.sh +26 -6
  54. package/core/harnesses/kiro/hooks/mcp-tool-guard.sh +21 -5
  55. package/core/harnesses/kiro/hooks/pre-bash-guard.sh +21 -5
  56. package/core/harnesses/kiro/hooks/pre-implement-gate.sh +21 -5
  57. package/core/harnesses/kiro/hooks/session-start.sh +12 -5
  58. package/core/harnesses/kiro/hooks/stop-check.sh +22 -30
  59. package/core/harnesses/pi/extensions/doflow-guard.js +167 -0
  60. package/core/harnesses/shared/hooks/ENVELOPE_MIGRATION.md +27 -12
  61. package/core/harnesses/shared/hooks/adapters/antigravity.js +14 -57
  62. package/core/harnesses/shared/hooks/bridge/bridge.sh +277 -0
  63. package/core/harnesses/shared/hooks/bridge/envelope.jq +129 -0
  64. package/core/harnesses/shared/hooks/bridge/observe-model.sh +75 -0
  65. package/core/harnesses/shared/hooks/bridge/respond.sh +70 -0
  66. package/core/harnesses/shared/hooks/policies/blocked-patterns.conf +28 -14
  67. package/core/harnesses/shared/hooks/policies/capture-failure.sh +51 -16
  68. package/core/harnesses/shared/hooks/policies/compact-text.sh +46 -0
  69. package/core/harnesses/shared/hooks/policies/contract.sh +78 -0
  70. package/core/harnesses/shared/hooks/policies/deny-json.sh +35 -9
  71. package/core/harnesses/shared/hooks/policies/emission-rules.sh +37 -0
  72. package/core/harnesses/shared/hooks/policies/emission.jq +209 -0
  73. package/core/harnesses/shared/hooks/policies/emission.sh +383 -0
  74. package/core/harnesses/shared/hooks/policies/identity.sh +177 -0
  75. package/core/harnesses/shared/hooks/policies/lib.sh +65 -40
  76. package/core/harnesses/shared/hooks/policies/mcp-tool-guard.sh +48 -35
  77. package/core/harnesses/shared/hooks/policies/pre-bash-guard.sh +284 -33
  78. package/core/harnesses/shared/hooks/policies/pre-implementation-gate.sh +180 -110
  79. package/core/harnesses/shared/hooks/policies/session-context.sh +66 -7
  80. package/core/harnesses/shared/hooks/policies/stop-check.sh +61 -23
  81. package/core/harnesses/shared/hooks/policies/subagent-audit.sh +39 -6
  82. package/core/harnesses/shared/hooks/policies/summary-store.sh +347 -0
  83. package/core/harnesses/shared/hooks/policies/user-prompt-submit.sh +97 -159
  84. package/core/harnesses/shared/hooks/stream-hook-runner.js +114 -187
  85. package/core/harnesses/shared/locator/doflow-run +2 -3
  86. package/core/registry/advice.json +3 -3
  87. package/core/registry/assets.json +72 -80
  88. package/core/registry/capabilities.json +12 -0
  89. package/core/registry/contracts.json +60 -33
  90. package/core/registry/contribution-points.json +32 -0
  91. package/core/registry/gates.json +32 -0
  92. package/core/registry/guidance-caps.json +40 -0
  93. package/core/registry/harnesses.json +1542 -277
  94. package/core/registry/lifecycle.json +2837 -37
  95. package/core/registry/mcp.json +5 -1
  96. package/core/registry/models.json +7 -1
  97. package/core/registry/package-templates/README.md +19 -0
  98. package/core/registry/package-templates/agent/files/agent.md +9 -0
  99. package/core/registry/package-templates/agent/template.json +4 -0
  100. package/core/registry/package-templates/capability-provider/files/provider.json +9 -0
  101. package/core/registry/package-templates/capability-provider/template.json +11 -0
  102. package/core/registry/package-templates/debate-preset/files/preset.json +26 -0
  103. package/core/registry/package-templates/debate-preset/template.json +4 -0
  104. package/core/registry/package-templates/review-preset/files/preset.json +30 -0
  105. package/core/registry/package-templates/review-preset/template.json +4 -0
  106. package/core/registry/package-templates/skill/files/SKILL.md +8 -0
  107. package/core/registry/package-templates/skill/template.json +4 -0
  108. package/core/registry/package-templates/worker/files/worker.json +92 -0
  109. package/core/registry/package-templates/worker/template.json +11 -0
  110. package/core/registry/packages/doflow/doflow-package.json +15 -0
  111. package/core/registry/packages/doflow/presets/debate-3.json +26 -0
  112. package/core/registry/protocols.json +61 -0
  113. package/core/registry/routes.json +17 -0
  114. package/core/registry/rules.json +431 -0
  115. package/core/registry/settings.json +276 -0
  116. package/core/registry/storage.json +701 -30
  117. package/core/registry/telemetry.json +236 -0
  118. package/core/registry/transcripts.json +142 -0
  119. package/core/registry/verification.json +76 -1
  120. package/core/registry/workflows.json +55 -0
  121. package/core/shared/agent-specs/core-implementer.md +3 -0
  122. package/core/shared/agent-specs/delivery-lead.md +68 -0
  123. package/core/shared/agent-specs/quality-guardian.md +5 -1
  124. package/core/shared/agent-specs/research-writer.md +10 -3
  125. package/core/shared/agent-specs/reviewer.md +53 -0
  126. package/core/shared/agent-specs/spec-analyst.md +5 -6
  127. package/core/shared/agent-specs/system-architect.md +5 -1
  128. package/core/shared/guidance/DOFLOW_CORE.md +1 -5
  129. package/core/shared/guidance/modes/MODE_DeepResearch.md +1 -1
  130. package/core/shared/guidance/modes/MODE_Orchestration.md +4 -3
  131. package/core/shared/guidance/modes/MODE_Task_Management.md +14 -14
  132. package/core/shared/guidance/pointers/codex.md +1 -4
  133. package/core/shared/guidance/references/ARTIFACT_FORMAT.md +30 -16
  134. package/core/shared/guidance/references/ARTIFACT_VOICE.md +3 -2
  135. package/core/shared/guidance/references/CONSTITUTION_BASE.md +17 -15
  136. package/core/shared/guidance/references/DIAGRAM_GUIDE.md +1 -1
  137. package/core/shared/guidance/references/DOFLOW_CHAIN.md +17 -19
  138. package/core/shared/guidance/references/EVIDENCE_LEDGER.md +7 -8
  139. package/core/shared/guidance/references/MODEL_SELECTION.md +5 -3
  140. package/core/shared/guidance/references/ORCHESTRATION.md +1 -2
  141. package/core/shared/guidance/rules/RULES.md +45 -0
  142. package/core/shared/scripts/doflow/bash/do-args.sh +37 -0
  143. package/core/shared/scripts/doflow/bash/do-exec-paths.sh +4 -0
  144. package/core/shared/scripts/doflow/bash/do-git-state.sh +15 -4
  145. package/core/shared/scripts/doflow/bash/do-parallel-check.sh +4 -0
  146. package/core/shared/scripts/doflow/bash/do-paths.sh +40 -2
  147. package/core/shared/scripts/doflow/bash/do-prereqs.sh +2 -1
  148. package/core/shared/scripts/doflow/bash/do-review-package.sh +4 -0
  149. package/core/shared/scripts/doflow/bash/do-task-brief.sh +58 -16
  150. package/core/shared/scripts/doflow/bash/render-audit.sh +26 -2
  151. package/core/shared/scripts/doflow/bash/render-diagrams.sh +1 -0
  152. package/core/shared/scripts/doflow/bash/render-puml.sh +2 -1
  153. package/core/shared/scripts/doflow/bash/validate-artifacts.sh +48 -4
  154. package/core/shared/scripts/doflow/bin/doflow-run +154 -35
  155. package/core/shared/skills/do/SKILL.md +12 -10
  156. package/core/shared/skills/do/references/advice_calls.md +26 -0
  157. package/core/shared/skills/do/references/pm_routing.md +1 -2
  158. package/core/shared/skills/do/references/program_mode.md +31 -0
  159. package/core/shared/skills/do-brainstorm/SKILL.md +20 -74
  160. package/core/shared/skills/do-brainstorm/references/handoff_branches.md +35 -0
  161. package/core/shared/skills/do-brainstorm/references/intent_seed.md +21 -0
  162. package/core/shared/skills/do-brainstorm/references/round_log.md +17 -0
  163. package/core/shared/skills/do-code-review/SKILL.md +41 -144
  164. package/core/shared/skills/do-code-review/content-types/markdown.md +24 -2
  165. package/core/shared/skills/do-code-review/references/tools.md +90 -0
  166. package/core/shared/skills/do-code-review/scripts/doc_quality_checker.py +549 -7
  167. package/core/shared/skills/do-design/SKILL.md +24 -23
  168. package/core/shared/skills/do-diagnose/SKILL.md +14 -4
  169. package/core/shared/skills/do-document/SKILL.md +11 -1
  170. package/core/shared/skills/do-document/references/deep_research.md +1 -2
  171. package/core/shared/skills/do-document/references/embedded-research.md +18 -6
  172. package/core/shared/skills/do-document/references/implementation-flow.md +5 -6
  173. package/core/shared/skills/do-execute-plan/SKILL.md +17 -59
  174. package/core/shared/skills/do-execute-plan/references/handoff_record.md +7 -2
  175. package/core/shared/skills/do-execute-plan/references/parallel_dispatch.md +13 -0
  176. package/core/shared/skills/do-execute-plan/references/readiness_gate.md +28 -1
  177. package/core/shared/skills/do-execute-plan/references/run_position.md +13 -1
  178. package/core/shared/skills/do-execute-plan/references/scaffold.md +17 -9
  179. package/core/shared/skills/do-execute-plan/references/state_checkpoint.md +11 -0
  180. package/core/shared/skills/do-execute-plan/references/task_attempts.md +78 -24
  181. package/core/shared/skills/do-flow/SKILL.md +8 -9
  182. package/core/shared/skills/do-flow/references/task_classes.md +2 -2
  183. package/core/shared/skills/do-git/SKILL.md +4 -0
  184. package/core/shared/skills/do-implement/SKILL.md +7 -9
  185. package/core/shared/skills/do-plan/SKILL.md +29 -19
  186. package/core/shared/skills/do-test/SKILL.md +7 -4
  187. package/core/shared/templates/doflow/constitution-template.md +9 -3
  188. package/core/shared/templates/doflow/data-model-template.md +1 -1
  189. package/core/shared/templates/doflow/design-template.md +113 -16
  190. package/core/shared/templates/doflow/plan-template.md +11 -10
  191. package/core/shared/templates/doflow/question-log-template.md +14 -2
  192. package/core/shared/templates/doflow/requirement-template.md +1 -1
  193. package/core/worker-evidence/antigravity/checks.json +14 -0
  194. package/core/worker-evidence/codex/2026-10-18-cli-check.json +107 -0
  195. package/core/worker-evidence/codex/2026-10-18-live-run-edit.json +73 -0
  196. package/core/worker-evidence/codex/2026-10-18-live-run-read-only.json +62 -0
  197. package/core/worker-evidence/codex/2026-10-24-cli-check.json +126 -0
  198. package/core/worker-evidence/codex/checks.json +38 -0
  199. package/package.json +10 -6
  200. package/src/adapters/antigravity/index.js +226 -113
  201. package/src/adapters/claude/index.js +39 -5
  202. package/src/adapters/codex/agents.js +25 -15
  203. package/src/adapters/codex/hooks.js +40 -5
  204. package/src/adapters/codex/index.js +100 -22
  205. package/src/adapters/codex/native-projection.js +6 -2
  206. package/src/adapters/copilot/index.js +58 -23
  207. package/src/adapters/copy-tree.js +294 -48
  208. package/src/adapters/guidance-manifest.js +71 -0
  209. package/src/adapters/guidance-pointer.js +19 -0
  210. package/src/adapters/hook-commands.js +6 -10
  211. package/src/adapters/index.js +1 -0
  212. package/src/adapters/kiro/index.js +38 -13
  213. package/src/adapters/opencode/index.js +8 -8
  214. package/src/adapters/pi/hooks.js +120 -0
  215. package/src/adapters/pi/index.js +48 -16
  216. package/src/adapters/resolve-source.js +26 -2
  217. package/src/cli/commands/install.js +3 -2
  218. package/src/cli/commands/reconcile.js +53 -9
  219. package/src/cli/commands/remove.js +2 -2
  220. package/src/cli/commands/rollback.js +6 -3
  221. package/src/cli/commands/self-update.js +18 -9
  222. package/src/cli/commands/status.js +21 -2
  223. package/src/cli/commands/ui.js +99 -0
  224. package/src/cli/commands/update.js +3 -2
  225. package/src/cli/index.js +338 -33
  226. package/src/cli/runtime-commands.js +243 -52
  227. package/src/cli/shared.js +0 -2
  228. package/src/helper/git.js +1 -1
  229. package/src/helper/guardrails.js +1 -1
  230. package/src/helper/marker-merge.js +31 -13
  231. package/src/helper/package-ids.js +37 -0
  232. package/src/helper/semver.js +94 -0
  233. package/src/install/backup.js +105 -15
  234. package/src/install/context.js +1 -1
  235. package/src/install/targets.js +31 -16
  236. package/src/lifecycle/coverage.js +74 -0
  237. package/src/lifecycle/hook-step.js +61 -0
  238. package/src/lifecycle/hook-tier.js +160 -0
  239. package/src/lifecycle/index.js +434 -86
  240. package/src/lifecycle/retired-harnesses.js +318 -0
  241. package/src/lifecycle/view.js +35 -15
  242. package/src/registry/index.js +686 -32
  243. package/src/registry/worker-ids.js +45 -0
  244. package/src/release/build-package.js +0 -3
  245. package/src/release/docs-blocks.js +492 -0
  246. package/src/release/preflight.js +425 -0
  247. package/src/release/rehearse.js +401 -0
  248. package/src/release/release-workflow.js +733 -0
  249. package/src/release/sync-plugin-versions.js +43 -7
  250. package/src/runtime/advice/bench-gate.js +25 -0
  251. package/src/runtime/advice/cli.js +59 -16
  252. package/src/runtime/advice/client.js +32 -9
  253. package/src/runtime/advice/config.js +98 -133
  254. package/src/runtime/advice/doctor.js +1 -1
  255. package/src/runtime/advice/elevation.js +97 -0
  256. package/src/runtime/advice/endpoint-guard.js +9 -3
  257. package/src/runtime/advice/mode.js +37 -0
  258. package/src/runtime/advice/record.js +18 -5
  259. package/src/runtime/advice/registry.js +4 -1
  260. package/src/runtime/advice/shadow-config.js +229 -0
  261. package/src/runtime/advice/shadow-dispatcher.js +276 -0
  262. package/src/runtime/brief-rules.js +81 -0
  263. package/src/runtime/brief-tools.js +111 -34
  264. package/src/runtime/candidate.js +514 -0
  265. package/src/runtime/capabilities/executor.js +450 -0
  266. package/src/runtime/capabilities/loopback.js +41 -0
  267. package/src/runtime/capabilities/sanitizer.js +88 -0
  268. package/src/runtime/capability-router.js +135 -3
  269. package/src/runtime/checkouts.js +73 -11
  270. package/src/runtime/claims.js +27 -12
  271. package/src/runtime/cli-result.js +11 -4
  272. package/src/runtime/cli.js +221 -277
  273. package/src/runtime/config-home.js +42 -0
  274. package/src/runtime/context/arbitrate.js +767 -0
  275. package/src/runtime/context/budget.js +203 -0
  276. package/src/runtime/context/compose.js +1367 -0
  277. package/src/runtime/context/delivery-store.js +100 -0
  278. package/src/runtime/context/emission-rules.js +118 -0
  279. package/src/runtime/context/identity.js +227 -0
  280. package/src/runtime/context/mandatory.js +594 -0
  281. package/src/runtime/context/pointer.js +142 -0
  282. package/src/runtime/context/primary-command.js +117 -0
  283. package/src/runtime/context/primary.js +344 -0
  284. package/src/runtime/context/summary-store.js +655 -0
  285. package/src/runtime/context-pack.js +1106 -245
  286. package/src/runtime/decision-register.js +13 -4
  287. package/src/runtime/dispatch/admission.js +392 -0
  288. package/src/runtime/dispatch/attempt-end.js +274 -0
  289. package/src/runtime/dispatch/command.js +628 -0
  290. package/src/runtime/dispatch/controls.js +904 -0
  291. package/src/runtime/dispatch/envelope.js +276 -0
  292. package/src/runtime/dispatch/grants.js +310 -0
  293. package/src/runtime/dispatch/integrate.js +617 -0
  294. package/src/runtime/dispatch/loop.js +1835 -0
  295. package/src/runtime/dispatch/store.js +352 -0
  296. package/src/runtime/dispatch/verify-run.js +201 -0
  297. package/src/runtime/evidence-fields.js +39 -0
  298. package/src/runtime/evidence-ledger.js +41 -7
  299. package/src/runtime/failure/capture.js +3 -1
  300. package/src/runtime/failure/cli.js +25 -9
  301. package/src/runtime/failure/home.js +57 -30
  302. package/src/runtime/failure/store.js +7 -2
  303. package/src/runtime/feature-pointer.js +174 -0
  304. package/src/runtime/feature-resolve.js +13 -2
  305. package/src/runtime/fleet/command.js +77 -0
  306. package/src/runtime/fleet/projects.js +178 -0
  307. package/src/runtime/fleet/tree.js +383 -0
  308. package/src/runtime/freshness.js +77 -10
  309. package/src/runtime/git-memo.js +46 -0
  310. package/src/runtime/guidance/ablation.js +427 -0
  311. package/src/runtime/health.js +565 -17
  312. package/src/runtime/history-compactor.js +13 -3
  313. package/src/runtime/implementation-gate.js +277 -22
  314. package/src/runtime/inventory/coverage.js +1 -1
  315. package/src/runtime/inventory/index.js +1 -1
  316. package/src/runtime/inventory/precedence.js +2 -2
  317. package/src/runtime/inventory/siblings.js +6 -4
  318. package/src/runtime/knowledge/code-corpus.js +277 -0
  319. package/src/runtime/knowledge/code-lexical.js +130 -0
  320. package/src/runtime/knowledge/code-retrieval.js +307 -0
  321. package/src/runtime/knowledge/code-validation.js +106 -0
  322. package/src/runtime/knowledge/gp3-gate.js +74 -0
  323. package/src/runtime/knowledge/graph-adapter.js +288 -0
  324. package/src/runtime/knowledge/graph-fallback.js +394 -0
  325. package/src/runtime/knowledge/hybrid.js +136 -8
  326. package/src/runtime/knowledge/retrieval.js +34 -1
  327. package/src/runtime/knowledge/rtk-compress.js +77 -0
  328. package/src/runtime/knowledge/semble-bridge.py +106 -0
  329. package/src/runtime/knowledge/semble-lifecycle.js +114 -0
  330. package/src/runtime/knowledge/semble-provider.js +365 -0
  331. package/src/runtime/lifecycle/cli.js +16 -6
  332. package/src/runtime/lifecycle/event-store.js +8 -6
  333. package/src/runtime/lifecycle/followup.js +6 -1
  334. package/src/runtime/lifecycle/overview.js +24 -1
  335. package/src/runtime/lifecycle/report-store.js +8 -10
  336. package/src/runtime/lifecycle/retention.js +95 -31
  337. package/src/runtime/lifecycle/root.js +9 -1
  338. package/src/runtime/lifecycle/status.js +34 -17
  339. package/src/runtime/lifecycle/store-upkeep.js +56 -7
  340. package/src/runtime/mask.js +134 -7
  341. package/src/runtime/mcp-consultations.js +40 -6
  342. package/src/runtime/model-router.js +79 -7
  343. package/src/runtime/models/catalogue.js +191 -0
  344. package/src/runtime/models/command.js +153 -0
  345. package/src/runtime/off-words.js +12 -0
  346. package/src/runtime/outcome.js +3 -3
  347. package/src/runtime/packages/command.js +1009 -0
  348. package/src/runtime/packages/contributions.js +116 -0
  349. package/src/runtime/packages/digest.js +132 -0
  350. package/src/runtime/packages/fetch.js +182 -0
  351. package/src/runtime/packages/grants.js +192 -0
  352. package/src/runtime/packages/index-file.js +134 -0
  353. package/src/runtime/packages/instruction.js +90 -0
  354. package/src/runtime/packages/manifest.js +331 -0
  355. package/src/runtime/packages/points.js +477 -0
  356. package/src/runtime/packages/programs.js +216 -0
  357. package/src/runtime/packages/scaffold.js +277 -0
  358. package/src/runtime/packages/source.js +90 -0
  359. package/src/runtime/packages/state.js +164 -0
  360. package/src/runtime/packages/store.js +449 -0
  361. package/src/runtime/packages/tar.js +106 -0
  362. package/src/runtime/packages/view.js +406 -0
  363. package/src/runtime/plan-check.js +59 -0
  364. package/src/runtime/plan-content.js +324 -0
  365. package/src/runtime/policy-init.js +118 -0
  366. package/src/runtime/profiles/doctor.js +96 -0
  367. package/src/runtime/profiles/resolve.js +244 -0
  368. package/src/runtime/profiles/rollback.js +254 -0
  369. package/src/runtime/profiles/sampler.js +41 -0
  370. package/src/runtime/readiness-record.js +16 -11
  371. package/src/runtime/readiness.js +127 -16
  372. package/src/runtime/research-request.js +50 -25
  373. package/src/runtime/retrieval-plan.js +402 -73
  374. package/src/runtime/retrieval-record.js +293 -0
  375. package/src/runtime/review/command.js +246 -0
  376. package/src/runtime/review/dominance.js +68 -0
  377. package/src/runtime/review/findings.js +434 -0
  378. package/src/runtime/review/identity.js +255 -0
  379. package/src/runtime/review/protocol-command.js +109 -0
  380. package/src/runtime/review/protocols.js +405 -0
  381. package/src/runtime/review/resolve-protocol.js +302 -0
  382. package/src/runtime/review/start.js +530 -0
  383. package/src/runtime/roadmap/facts.js +479 -0
  384. package/src/runtime/roadmap/gates.js +270 -0
  385. package/src/runtime/roadmap/loop.js +1636 -0
  386. package/src/runtime/roadmap/merge.js +381 -0
  387. package/src/runtime/roadmap/rows.js +1113 -0
  388. package/src/runtime/roadmap/seed.js +951 -0
  389. package/src/runtime/rules-report.js +336 -0
  390. package/src/runtime/scaffold/artifacts.js +63 -9
  391. package/src/runtime/scaffold/generate.js +21 -9
  392. package/src/runtime/settings/autopilot.js +106 -0
  393. package/src/runtime/settings/cli.js +280 -0
  394. package/src/runtime/settings/config-write.js +314 -0
  395. package/src/runtime/settings/files.js +271 -0
  396. package/src/runtime/settings/legacy.js +154 -0
  397. package/src/runtime/settings/lexical.js +56 -0
  398. package/src/runtime/settings/prepared-run.js +269 -0
  399. package/src/runtime/settings/project-layers.js +118 -0
  400. package/src/runtime/settings/refs.js +288 -0
  401. package/src/runtime/settings/registry.js +553 -0
  402. package/src/runtime/settings/resolve.js +713 -0
  403. package/src/runtime/settings/shared.js +37 -0
  404. package/src/runtime/settings/worker-billing.js +107 -0
  405. package/src/runtime/settings/write.js +269 -0
  406. package/src/runtime/slot-command.js +78 -0
  407. package/src/runtime/slots.js +671 -0
  408. package/src/runtime/source-version.js +290 -0
  409. package/src/runtime/state-root.js +217 -0
  410. package/src/runtime/storage/cli.js +12 -5
  411. package/src/runtime/storage/engine.js +9 -2
  412. package/src/runtime/storage/registry.js +14 -1
  413. package/src/runtime/storage/roots.js +66 -16
  414. package/src/runtime/storage/rules.js +82 -10
  415. package/src/runtime/storage/upkeep.js +10 -2
  416. package/src/runtime/storage/work-status.js +245 -26
  417. package/src/runtime/task-attempts.js +589 -69
  418. package/src/runtime/task-classifier.js +47 -11
  419. package/src/runtime/task-graph.js +373 -0
  420. package/src/runtime/task-run.js +778 -0
  421. package/src/runtime/task-scope.js +202 -56
  422. package/src/runtime/task-sources.js +147 -0
  423. package/src/runtime/task-state.js +440 -65
  424. package/src/runtime/team/admission.js +301 -0
  425. package/src/runtime/team/envelope.js +324 -0
  426. package/src/runtime/team/review-guard.js +156 -0
  427. package/src/runtime/trace/analyze.js +427 -0
  428. package/src/runtime/trace/baseline.js +770 -0
  429. package/src/runtime/trace/ledger.js +63 -140
  430. package/src/runtime/trace/otlp-export.js +568 -0
  431. package/src/runtime/trace/otlp-map.js +481 -0
  432. package/src/runtime/trace/spans.js +745 -0
  433. package/src/runtime/trace/telemetry.js +225 -0
  434. package/src/runtime/trace/views.js +1 -0
  435. package/src/runtime/transcripts/command.js +98 -0
  436. package/src/runtime/transcripts/cursor.js +326 -0
  437. package/src/runtime/transcripts/read.js +126 -0
  438. package/src/runtime/transcripts/readers/claude-jsonl.js +74 -0
  439. package/src/runtime/transcripts/readers/codex-rollout.js +70 -0
  440. package/src/runtime/transcripts/readers/copilot-events.js +90 -0
  441. package/src/runtime/transcripts/readers/kiro-jsonl.js +77 -0
  442. package/src/runtime/transcripts/readers/pi-jsonl.js +59 -0
  443. package/src/runtime/transcripts/registry.js +161 -0
  444. package/src/runtime/transcripts/stats.js +161 -0
  445. package/src/runtime/verification/check-key.js +628 -0
  446. package/src/runtime/verification/contract-runner.js +546 -11
  447. package/src/runtime/verification/engine.js +499 -9
  448. package/src/runtime/verification/impact.js +617 -0
  449. package/src/runtime/verification/inflight.js +205 -0
  450. package/src/runtime/verification/registry.js +176 -0
  451. package/src/runtime/verification/reuse.js +184 -0
  452. package/src/runtime/verification/telemetry-emit.js +254 -0
  453. package/src/runtime/verification/test-selection.js +67 -7
  454. package/src/runtime/worker/active.js +90 -0
  455. package/src/runtime/worker/cancel.js +222 -0
  456. package/src/runtime/worker/catalogue.js +122 -0
  457. package/src/runtime/worker/command.js +677 -0
  458. package/src/runtime/worker/evidence.js +288 -0
  459. package/src/runtime/worker/launch.js +288 -0
  460. package/src/runtime/worker/models.js +137 -0
  461. package/src/runtime/worker/parsers.js +218 -0
  462. package/src/runtime/worker/probes/index.js +706 -0
  463. package/src/runtime/worker/process-tree.js +415 -0
  464. package/src/runtime/worker/quota.js +43 -0
  465. package/src/runtime/worker/readiness.js +713 -0
  466. package/src/runtime/worker/run-store.js +166 -0
  467. package/src/runtime/worker/supervisor.js +541 -0
  468. package/src/runtime/worker/worktree-check.js +252 -0
  469. package/src/runtime/workflow-engine.js +5 -1
  470. package/src/runtime/workflow-orchestrator.js +578 -63
  471. package/src/runtime/worktree.js +149 -22
  472. package/src/state/index.js +1 -1
  473. package/src/state/lockfile.js +64 -10
  474. package/src/state/run-lock.js +1 -1
  475. package/types/node-commonjs.d.ts +106 -7
  476. package/core/.antigravity-plugin/hooks.json +0 -39
  477. package/core/harnesses/gemini/hooks/hooks.json +0 -77
  478. package/core/harnesses/gemini/hooks/lib.sh +0 -302
  479. package/core/harnesses/gemini/hooks/mcp-tool-guard.sh +0 -21
  480. package/core/harnesses/gemini/hooks/post-edit-lint.sh +0 -39
  481. package/core/harnesses/gemini/hooks/pre-bash-guard.sh +0 -21
  482. package/core/harnesses/gemini/hooks/pre-compact.sh +0 -38
  483. package/core/harnesses/gemini/hooks/pre-implement-gate.sh +0 -22
  484. package/core/harnesses/gemini/hooks/session-end.impl.sh +0 -89
  485. package/core/harnesses/gemini/hooks/session-end.sh +0 -5
  486. package/core/harnesses/gemini/hooks/session-start.sh +0 -5
  487. package/core/harnesses/gemini/settings/adapter-defaults.json +0 -4
  488. package/core/harnesses/shared/hooks/adapters/arg-fields.js +0 -19
  489. package/core/harnesses/shared/hooks/adapters/gemini.js +0 -114
  490. package/core/harnesses/shared/hooks/hooks.json +0 -47
  491. package/core/shared/guidance/FLAGS.md +0 -25
  492. package/core/shared/guidance/rules/RULE_01_SAFETY.md +0 -25
  493. package/core/shared/guidance/rules/RULE_02_WORKFLOW.md +0 -23
  494. package/core/shared/guidance/rules/RULE_03_QUALITY.md +0 -14
  495. package/core/shared/guidance/rules/RULE_04_QUESTIONS.md +0 -46
  496. package/src/adapters/gemini/hooks.js +0 -210
  497. package/src/adapters/gemini/index.js +0 -390
@@ -84,6 +84,38 @@ class CapabilityRouter {
84
84
  throw new Error(`Invalid registry file '${capsPath}':\n- ${providerErrors.join('\n- ')}`);
85
85
  }
86
86
  this.routes = routesData.routes || {};
87
+
88
+ try {
89
+ const { contributionsFor } = require('./packages/contributions.js');
90
+ const packageContribs = contributionsFor('capability-provider', 1, {
91
+ repoRoot: this.repoRoot,
92
+ fsImpl: this.fsImpl,
93
+ projectRoot: this.projectRoot,
94
+ });
95
+ for (const contrib of packageContribs) {
96
+ const data = contrib.data;
97
+ if (data && typeof data === 'object' && data.capability) {
98
+ if (!this.capabilities[data.capability]) {
99
+ this.capabilities[data.capability] = {
100
+ description: data.name || data.capability,
101
+ providers: [],
102
+ };
103
+ }
104
+ this.capabilities[data.capability].providers.push({
105
+ id: contrib.qualifiedId,
106
+ name: data.name,
107
+ kind: data.kind,
108
+ sourceMode: data.sourceMode || 'live',
109
+ costTier: data.costTier || 'free',
110
+ timeoutMs: data.timeoutMs || 10000,
111
+ ...data,
112
+ packageId: contrib.packageId,
113
+ });
114
+ }
115
+ }
116
+ } catch {
117
+ // best effort if package contributions cannot be queried
118
+ }
87
119
  }
88
120
 
89
121
  /**
@@ -179,11 +211,36 @@ class CapabilityRouter {
179
211
  return { status: 'HEALTHY', facts };
180
212
  }
181
213
 
182
- if (provider.binary) {
183
- const available = this.isBinaryAvailable(provider.binary);
214
+ if (provider.kind === 'http' || provider.endpoint) {
215
+ const { validateLoopbackUrl } = require('./capabilities/loopback.js');
216
+ const valid = validateLoopbackUrl(provider.endpoint);
217
+ if (!valid.ok) {
218
+ facts.installed = false;
219
+ facts.responsive = false;
220
+ return { status: 'UNAVAILABLE', details: `Disallowed endpoint: ${valid.reason}`, facts };
221
+ }
222
+ facts.installed = true;
223
+ if (deepCheck) {
224
+ if (provider.checkCommand) {
225
+ const smoke = this.executeSmokeCheck(provider.checkCommand);
226
+ facts.responsive = smoke.ok;
227
+ if (!smoke.ok) {
228
+ return { status: 'UNAVAILABLE', details: `Smoke check failed: ${smoke.error}`, facts };
229
+ }
230
+ return { status: 'HEALTHY', facts };
231
+ }
232
+ facts.responsive = false;
233
+ return { status: 'UNAVAILABLE', details: 'HTTP provider reachability cannot be confirmed without checkCommand', facts };
234
+ }
235
+ return { status: 'HEALTHY', facts };
236
+ }
237
+
238
+ const binary = provider.binary || provider.program;
239
+ if (binary) {
240
+ const available = this.isBinaryAvailable(binary);
184
241
  facts.installed = available;
185
242
  if (!available) {
186
- return { status: 'UNAVAILABLE', details: `Tool binary '${provider.binary}' not found`, facts };
243
+ return { status: 'UNAVAILABLE', details: `Tool binary '${binary}' not found`, facts };
187
244
  }
188
245
  if (deepCheck && provider.checkCommand) {
189
246
  const smoke = this.executeSmokeCheck(provider.checkCommand);
@@ -329,6 +386,18 @@ class CapabilityRouter {
329
386
  });
330
387
  }
331
388
 
389
+ if (provider.kind === 'http' || provider.endpoint) {
390
+ const method = provider.method || 'POST';
391
+ return {
392
+ cliCommand: null,
393
+ argv: null,
394
+ httpEndpoint: provider.endpoint,
395
+ method,
396
+ args: params,
397
+ display: `HTTP ${method} ${provider.endpoint}`,
398
+ };
399
+ }
400
+
332
401
  return withDisplay({
333
402
  argv: [provider.binary || provider.id, query],
334
403
  args: params,
@@ -432,6 +501,69 @@ class CapabilityRouter {
432
501
  }
433
502
  return report;
434
503
  }
504
+
505
+ async executeCapability(
506
+ capabilityId ,
507
+ input = {},
508
+ options = {}
509
+ ) {
510
+ const { LocalCapabilityExecutor } = require('./capabilities/executor.js');
511
+ const executor = new LocalCapabilityExecutor({
512
+ fsImpl: this.fsImpl,
513
+ fetchImpl: options.fetchImpl,
514
+ execFileImpl: options.execFileImpl,
515
+ maxBufferBytes: options.maxBufferBytes,
516
+ });
517
+
518
+ let targetCapId = capabilityId;
519
+ let fallbackCaps = [];
520
+ if (this.routes[capabilityId]) {
521
+ targetCapId = this.routes[capabilityId].capability;
522
+ fallbackCaps = this.routes[capabilityId].fallback || [];
523
+ } else {
524
+ const matchingRoute = Object.values(this.routes).find((r ) => r.capability === capabilityId);
525
+ if (matchingRoute) fallbackCaps = matchingRoute.fallback || [];
526
+ }
527
+
528
+ const capsToTry = [targetCapId, ...fallbackCaps];
529
+ for (let c = 0; c < capsToTry.length; c++) {
530
+ const curCap = capsToTry[c];
531
+ const capDef = this.capabilities[curCap];
532
+ if (!capDef || !Array.isArray(capDef.providers) || capDef.providers.length === 0) continue;
533
+
534
+ for (const provider of capDef.providers) {
535
+ const res = await executor.execute(curCap, provider, input, options);
536
+ if (res.ok) {
537
+ return {
538
+ ...res,
539
+ status: c === 0 ? 'HEALTHY' : 'FALLBACK',
540
+ };
541
+ }
542
+ if (
543
+ res.status === 'ERROR' ||
544
+ (res.error && (
545
+ res.error.includes('DECISION_INJECTION_REFUSED') ||
546
+ res.error.includes('DISALLOWED_REMOTE_ENDPOINT') ||
547
+ res.error.includes('exceeded buffer limit')
548
+ ))
549
+ ) {
550
+ return {
551
+ ...res,
552
+ status: 'ERROR',
553
+ };
554
+ }
555
+ }
556
+ }
557
+
558
+ return {
559
+ ok: false,
560
+ capabilityId,
561
+ providerId: null,
562
+ status: 'UNAVAILABLE',
563
+ data: null,
564
+ error: 'No available healthy providers found for capability',
565
+ };
566
+ }
435
567
  }
436
568
 
437
569
  /**
@@ -27,7 +27,7 @@ function realOrNull(p , fsImpl ) {
27
27
 
28
28
  function failed(reason , detail ) {
29
29
  return {
30
- ok: false, reason, detail, current: null, main: null, mainReason: null, others: [], isLinked: false, sandbox: false,
30
+ ok: false, reason, detail, current: null, main: null, mainReason: null, others: [], isLinked: false, sandbox: false, entries: [],
31
31
  };
32
32
  }
33
33
 
@@ -38,13 +38,16 @@ function failed(reason , detail ) {
38
38
  * DoFlow sandbox); `current` is the entry that is the longest real-path prefix of `cwd`, so a
39
39
  * sandbox nested under the main checkout is told apart from it. A sandbox (a checkout holding
40
40
  * `.doflow-worktree-base`) is never offered as another checkout and sees none itself: it exists
41
- * to be isolated. Writes nothing.
41
+ * to be isolated. `entries` is every non-bare checkout that exists, in porcelain order, with its
42
+ * branch (`refs/heads/` stripped; null when detached) and HEAD from the same porcelain; from a
43
+ * sandbox it is the sandbox alone. Writes nothing.
42
44
  * @param {Object} options
43
45
  * @param {string} options.cwd
44
46
  * @param {Function} [options.exec] spawnSync-compatible
45
47
  * @param {Object} [options.fsImpl]
46
48
  * @returns {{ok: boolean, reason: string|null, detail: string|null, current: string|null, main: string|null,
47
- * mainReason: string|null, others: Array<string>, isLinked: boolean, sandbox: boolean}}
49
+ * mainReason: string|null, others: Array<string>, isLinked: boolean, sandbox: boolean,
50
+ * entries: Array<{path: string, branch: string|null, head: string|null, sandbox: boolean}>}}
48
51
  */
49
52
  function listCheckouts({ cwd, exec = spawnSync, fsImpl = fs } ) {
50
53
  const realCwd = realOrNull(cwd, fsImpl) || path.resolve(cwd);
@@ -72,15 +75,23 @@ function listCheckouts({ cwd, exec = spawnSync, fsImpl = fs }
72
75
  }
73
76
 
74
77
  function fromPorcelain(stdout , realCwd , fsImpl ) {
75
- const entries = [];
78
+ const entries = [];
76
79
  for (const block of stdout.split(/\n\s*\n/)) {
77
80
  const lines = block.split('\n').filter(Boolean);
78
81
  if (lines.length === 0 || !lines[0].startsWith('worktree ')) continue;
79
82
  const real = realOrNull(lines[0].slice('worktree '.length), fsImpl);
83
+ const value = (prefix ) => {
84
+ const line = lines.find((l) => l.startsWith(prefix));
85
+ return line === undefined ? null : line.slice(prefix.length);
86
+ };
87
+ const ref = value('branch ');
88
+ const head = value('HEAD ');
80
89
  entries.push({
81
90
  real,
82
91
  bare: lines.includes('bare'),
83
92
  sandbox: real !== null && fsImpl.existsSync(path.join(real, BASE_FILE)),
93
+ branch: ref === null ? null : ref.replace(/^refs\/heads\//, ''),
94
+ head: head !== null && /^[0-9a-f]{40,64}$/.test(head) && !/^0+$/.test(head) ? head : null,
84
95
  });
85
96
  }
86
97
 
@@ -104,6 +115,10 @@ function fromPorcelain(stdout , realCwd , fsImpl ) {
104
115
  .filter((e) => e.real !== null && !e.bare && !e.sandbox && e !== current)
105
116
  .map((e) => e.real );
106
117
  const currentPath = current ? current.real : null;
118
+ const seen = new Set ();
119
+ const listed = (sandbox ? [current] : entries)
120
+ .filter((e ) => e.real !== null && !e.bare && !seen.has(e.real) && seen.add(e.real))
121
+ .map((e ) => ({ path: e.real , branch: e.branch, head: e.head, sandbox: e.sandbox }));
107
122
  return {
108
123
  ok: true,
109
124
  reason: null,
@@ -114,19 +129,52 @@ function fromPorcelain(stdout , realCwd , fsImpl ) {
114
129
  others: [...new Set(others)],
115
130
  isLinked: currentPath !== null && main !== null && currentPath !== main,
116
131
  sandbox,
132
+ entries: listed,
117
133
  };
118
134
  }
119
135
 
136
+ /**
137
+ * The `listCheckouts` entry whose path is the longest real-path prefix of `p` (`p` itself when it
138
+ * cannot be resolved), or null. A sandbox entry can be the answer, so a caller tells a sandbox
139
+ * nested under a checkout apart from that checkout. Writes nothing.
140
+ */
141
+ function checkoutContaining(entries , p , fsImpl = fs) {
142
+ if (typeof p !== 'string' || !path.isAbsolute(p)) return null;
143
+ const real = realOrNull(p, fsImpl) || path.resolve(p);
144
+ let best = null;
145
+ for (const e of entries) {
146
+ if ((real === e.path || real.startsWith(e.path + path.sep)) && (best === null || e.path.length > best.path.length)) best = e;
147
+ }
148
+ return best;
149
+ }
150
+
120
151
  /** Forgets every memoized `listCheckouts` result (tests that rebuild a repository in place). */
121
152
  function clearCheckoutCache() {
122
153
  cache.clear();
123
154
  }
124
155
 
156
+ /** Whether `dir` can sit in a linked worktree: the nearest `.git` above it is a file (a worktree's
157
+ * pointer), not the main checkout's directory. A main checkout then needs no `git worktree list`. */
158
+ function mayBeLinked(dir , fsImpl = fs) {
159
+ for (let at = path.resolve(dir); ; at = path.dirname(at)) {
160
+ try { return fsImpl.statSync(path.join(at, '.git')).isFile(); } catch { /* not here */ }
161
+ if (path.dirname(at) === at) return false;
162
+ }
163
+ }
164
+
165
+ /** Whether two files hold the same bytes; a file that cannot be read differs from any other. */
166
+ function sameBytes(a , b , fsImpl ) {
167
+ try { return fsImpl.readFileSync(a).equals(fsImpl.readFileSync(b)); } catch { return false; }
168
+ }
169
+
125
170
  /**
126
171
  * A state file in the checkout the verb resolves to, else in exactly one other checkout.
127
172
  *
128
- * The current checkout is read first and, when the file is there, no `git` call is made. Two or
129
- * more other checkouts holding it is `ambiguous` rather than a pick: which one is meant is not
173
+ * From a linked worktree the main checkout is read first, since every per-task record lives there
174
+ * (115 IC-004): a copy at the same path in the worktree with other bytes is a `conflict` (C-3),
175
+ * never a pick; with none in the main checkout the worktree's own is read, then the others. From any
176
+ * other checkout the current one is read first and, when the file is there, no `git` call is made.
177
+ * Two or more other checkouts holding it is `ambiguous` rather than a pick: which one is meant is not
130
178
  * something a path can decide. Writes nothing.
131
179
  * @param {Object} options
132
180
  * @param {string} options.stateRoot the root the verb resolves today
@@ -135,8 +183,9 @@ function clearCheckoutCache() {
135
183
  * for a store whose location differs per checkout (null skips that root)
136
184
  * @param {Function} [options.exec]
137
185
  * @param {Object} [options.fsImpl]
138
- * @returns {{status: 'found'|'missing'|'ambiguous', file: string|null, root: string|null,
139
- * origin: 'current'|'other'|null, candidates: Array<string>}}
186
+ * @returns {{status: 'found'|'missing'|'ambiguous'|'conflict', file: string|null, root: string|null,
187
+ * origin: 'current'|'other'|null, candidates: Array<string>}} `conflict` names the worktree's file
188
+ * then the main checkout's
140
189
  */
141
190
  function findStateFile({ stateRoot, relPath, exec = spawnSync, fsImpl = fs } ) {
142
191
  const at = (root , isCurrent ) => {
@@ -149,14 +198,27 @@ function findStateFile({ stateRoot, relPath, exec = spawnSync, fsImpl = fs }
149
198
  return null;
150
199
  };
151
200
  const missing = { status: 'missing', file: null, root: null, origin: null, candidates: [] };
152
-
201
+ const linked = mayBeLinked(stateRoot, fsImpl) ? listCheckouts({ cwd: stateRoot, exec, fsImpl }) : null;
202
+ const main = linked?.ok && linked.isLinked && !linked.sandbox ? linked.main : null;
203
+
204
+ if (main) {
205
+ const there = at(main, false);
206
+ if (there) {
207
+ const copy = path.join(stateRoot, path.relative(main, there));
208
+ if (fsImpl.existsSync(copy) && !sameBytes(copy, there, fsImpl)) {
209
+ return { status: 'conflict', file: null, root: null, origin: null, candidates: [copy, there] };
210
+ }
211
+ return { status: 'found', file: there, root: main, origin: 'other', candidates: [] };
212
+ }
213
+ }
153
214
  const here = at(stateRoot, true);
154
215
  if (here) return { status: 'found', file: here, root: stateRoot, origin: 'current', candidates: [] };
155
216
 
156
- const checkouts = listCheckouts({ cwd: stateRoot, exec, fsImpl });
217
+ const checkouts = linked || listCheckouts({ cwd: stateRoot, exec, fsImpl });
157
218
  if (!checkouts.ok || checkouts.sandbox) return missing;
158
219
  const matches = [];
159
220
  for (const root of checkouts.others ) {
221
+ if (root === main) continue;
160
222
  const file = at(root, false);
161
223
  if (file) matches.push({ file, root });
162
224
  }
@@ -167,4 +229,4 @@ function findStateFile({ stateRoot, relPath, exec = spawnSync, fsImpl = fs }
167
229
  return { status: 'found', file: matches[0].file, root: matches[0].root, origin: 'other', candidates: [] };
168
230
  }
169
231
 
170
- module.exports = { listCheckouts, findStateFile, clearCheckoutCache };
232
+ module.exports = { listCheckouts, findStateFile, clearCheckoutCache, mayBeLinked, checkoutContaining };
@@ -8,7 +8,7 @@ const crypto = require('node:crypto');
8
8
  // Shared with EvidenceLedger so both stores enforce one definition of a safe task id.
9
9
  const { assertSafeTaskId, EvidenceLedger } = require('./evidence-ledger.js');
10
10
  const { updateTaskState, readTaskState, mergeRecords } = require('./task-state.js');
11
- const { taskStoreDir } = require('./task-scope.js');
11
+ const { taskRecord } = require('./task-scope.js');
12
12
  const { finishRuntime, usageError } = require('./cli-result.js');
13
13
  const { REPO_ROOT } = require('../helper/repo-root.js');
14
14
 
@@ -67,11 +67,16 @@ class ClaimsManager {
67
67
  this.seq = 0;
68
68
  }
69
69
 
70
- /** Where this task's claims file lives: beside its evidence, in the feature's namespace when it has one. */
70
+ /** Where this task's claims file is written: beside its evidence, in the feature's namespace when it has one. */
71
71
  fileFor(taskId ) {
72
- const dir = this.fixedStateDir
73
- || taskStoreDir({ projectRoot: this.repoRoot, store: 'evidence', taskId, slug: this.slug });
74
- return path.join(dir, `${assertSafeTaskId(taskId)}_claims.json`);
72
+ return this.recordFor(taskId).file;
73
+ }
74
+
75
+ /** The task's claims file, where it is read from and the write lock's seed (task-scope.ts). */
76
+ recordFor(taskId ) {
77
+ const name = `${assertSafeTaskId(taskId)}_claims.json`;
78
+ if (this.fixedStateDir) { const file = path.join(this.fixedStateDir, name); return { file, read: file, seed: () => {} }; }
79
+ return taskRecord({ projectRoot: this.repoRoot, store: 'evidence', taskId, slug: this.slug, name, fsImpl: this.fsImpl });
75
80
  }
76
81
 
77
82
  generateId() {
@@ -193,22 +198,28 @@ class ClaimsManager {
193
198
  }
194
199
 
195
200
  let hasFreshSupport = false;
196
- let hasFreshContradiction = false;
197
201
  let hasStaleSupport = false;
202
+ let hasFreshContradiction = false;
203
+ let hasUnknownContradiction = false;
198
204
 
199
205
  for (const evId of claim.supportingEvidence) {
200
206
  const ev = this.evidenceLedger ? this.evidenceLedger.getEvidence(evId) : null;
201
207
  if (!ev || ev.freshness?.status === 'STALE') {
202
208
  hasStaleSupport = true;
203
- } else {
209
+ } else if (ev.freshness?.status === 'FRESH') {
204
210
  hasFreshSupport = true;
205
211
  }
206
212
  }
207
213
 
208
214
  for (const evId of claim.contradictingEvidence) {
209
215
  const ev = this.evidenceLedger ? this.evidenceLedger.getEvidence(evId) : null;
210
- if (ev && ev.freshness?.status !== 'STALE') {
211
- hasFreshContradiction = true;
216
+ if (ev) {
217
+ const status = ev.freshness?.status;
218
+ if (status === 'FRESH') {
219
+ hasFreshContradiction = true;
220
+ } else if (status !== 'STALE') {
221
+ hasUnknownContradiction = true;
222
+ }
212
223
  }
213
224
  }
214
225
 
@@ -219,9 +230,12 @@ class ClaimsManager {
219
230
  // settled. Support that has merely gone stale still counts as support, so a claim that once
220
231
  // had backing stays 'conflicted' rather than being declared false on a technicality.
221
232
  claim.status = claim.supportingEvidence.length === 0 ? 'rejected' : 'conflicted';
233
+ } else if (hasUnknownContradiction) {
234
+ // A contradiction whose freshness is unknown cannot prove the claim false, so it never yields 'rejected' (DEC-016).
235
+ claim.status = claim.supportingEvidence.length > 0 ? 'conflicted' : 'hypothesis';
222
236
  } else if (hasFreshSupport) {
223
237
  claim.status = 'supported';
224
- } else if (hasStaleSupport && !hasFreshSupport) {
238
+ } else if (hasStaleSupport) {
225
239
  claim.status = 'invalidated';
226
240
  } else {
227
241
  claim.status = 'hypothesis';
@@ -323,9 +337,10 @@ class ClaimsManager {
323
337
  * @returns {string} filePath
324
338
  */
325
339
  save(taskId = 'default') {
326
- const targetFile = this.fileFor(taskId);
340
+ const { file: targetFile, seed } = this.recordFor(taskId);
327
341
  let merged ;
328
342
  const file = updateTaskState({
343
+ prepare: seed,
329
344
  fsImpl: this.fsImpl,
330
345
  file: targetFile,
331
346
  build: (disk ) => {
@@ -346,7 +361,7 @@ class ClaimsManager {
346
361
  * @returns {number}
347
362
  */
348
363
  load(taskId = 'default') {
349
- const targetFile = this.fileFor(taskId);
364
+ const targetFile = this.recordFor(taskId).read;
350
365
  const data = readTaskState(this.fsImpl, targetFile);
351
366
  if (data && Array.isArray(data.claims)) {
352
367
  for (const item of data.claims) {
@@ -11,6 +11,13 @@
11
11
  * it, and requires only the mask module.
12
12
  */
13
13
 
14
+ const EXIT = Object.freeze({
15
+ OK: 0,
16
+ EMPTY: 1,
17
+ USAGE: 2,
18
+ OVERFLOW: 3,
19
+ });
20
+
14
21
  /**
15
22
  * Sets the process exit code.
16
23
  * @param {number} code
@@ -46,10 +53,10 @@ function captureCaught(error , command , exit ) {
46
53
  * @returns {number} 2 (USAGE error exit code)
47
54
  */
48
55
  function usageError(verb , message , json , error ) {
49
- if (error !== undefined) captureCaught(error, verb, 2);
50
- if (json) console.log(JSON.stringify({ ok: false, status: 'USAGE', exitCode: 2, error: 'usage', summary: message }, null, 2));
56
+ if (error !== undefined) captureCaught(error, verb, EXIT.USAGE);
57
+ if (json) console.log(JSON.stringify({ ok: false, status: 'USAGE', exitCode: EXIT.USAGE, error: 'usage', summary: message }, null, 2));
51
58
  else console.error(`doflow ${verb}: ${message}`);
52
- return finishRuntime(2);
59
+ return finishRuntime(EXIT.USAGE);
53
60
  }
54
61
 
55
- module.exports = { finishRuntime, usageError, captureCaught };
62
+ module.exports = { finishRuntime, usageError, captureCaught, EXIT };