@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
@@ -0,0 +1,244 @@
1
+ 'use strict';
2
+
3
+ const fs = require('node:fs');
4
+ const path = require('node:path');
5
+ const { checkRollbackState } = require('./rollback.js');
6
+ const { shouldSample } = require('./sampler.js');
7
+ const { configHome } = require('../config-home.js');
8
+
9
+
10
+
11
+
12
+
13
+
14
+
15
+
16
+
17
+
18
+
19
+
20
+
21
+
22
+
23
+
24
+
25
+
26
+
27
+
28
+
29
+
30
+
31
+
32
+
33
+
34
+
35
+ const PROFILE_CAPABILITIES = Object.freeze({
36
+ baseline: {
37
+ retrieval: 'lexical',
38
+ advisor: 'off',
39
+ graph: 'off',
40
+ verification: 'L0',
41
+ telemetryCanaryTag: false,
42
+ },
43
+ canary: {
44
+ retrieval: 'canary-hybrid',
45
+ advisor: 'shadow',
46
+ graph: 'advisory',
47
+ verification: 'L0-L1',
48
+ telemetryCanaryTag: true,
49
+ },
50
+ staged: {
51
+ retrieval: 'staged-hybrid',
52
+ advisor: 'staged',
53
+ graph: 'bounded',
54
+ verification: 'L0-L2',
55
+ telemetryCanaryTag: false,
56
+ },
57
+ full: {
58
+ retrieval: 'full-hybrid',
59
+ advisor: 'act',
60
+ graph: 'full',
61
+ verification: 'L0-L3',
62
+ telemetryCanaryTag: false,
63
+ },
64
+ });
65
+
66
+ const VALID_PROFILES = new Set (['baseline', 'canary', 'staged', 'full']);
67
+
68
+ function getSettingValue(obj , key ) {
69
+ if (!obj || typeof obj !== 'object') return undefined;
70
+ if (Object.hasOwn(obj, key)) return obj[key];
71
+ const parts = key.split('.');
72
+ let cur = obj;
73
+ for (let i = 0; i < parts.length; i++) {
74
+ if (!cur || typeof cur !== 'object') return undefined;
75
+ const p = parts[i];
76
+ if (Object.hasOwn(cur, p)) {
77
+ cur = cur[p];
78
+ } else {
79
+ const rest = parts.slice(i).join('.');
80
+ if (Object.hasOwn(cur, rest)) return cur[rest];
81
+ return undefined;
82
+ }
83
+ }
84
+ return cur;
85
+ }
86
+
87
+ function readJsonFile(filePath , fsImpl ) {
88
+ try {
89
+ const text = fsImpl.readFileSync(filePath, 'utf8');
90
+ return JSON.parse(text);
91
+ } catch {
92
+ return null;
93
+ }
94
+ }
95
+
96
+ /**
97
+ * Resolves the effective rollout profile by consulting:
98
+ * 1. Rollback Controller (checkRollbackState - forces baseline if active)
99
+ * 2. Environment override (DOFLOW_ROLLOUT_PROFILE)
100
+ * 3. Layered settings (.doflow/settings.local.json -> settings.json -> user settings)
101
+ * 4. Registry default (baseline)
102
+ *
103
+ * Guarantees <= 5ms evaluation latency. Never throws.
104
+ */
105
+ function resolveRolloutProfile(options ) {
106
+ const fsImpl = options?.fsImpl || fs;
107
+ const env = options?.env ?? process.env;
108
+ const projectRoot = options?.projectRoot ? path.resolve(options.projectRoot) : process.cwd();
109
+
110
+ // 1. Check Rollback Controller (forces baseline on trip)
111
+ const rollback = checkRollbackState({ projectRoot, env, fsImpl });
112
+ if (rollback.active) {
113
+ const originSource = rollback.origin === 'env' ? 'env' : 'sentinel';
114
+ return {
115
+ name: 'baseline',
116
+ origin: {
117
+ source: originSource,
118
+ detail: rollback.reason || (rollback.origin === 'env' ? 'DOFLOW_ROLLOUT_PROFILE=baseline' : 'rollback-sentinel-active'),
119
+ },
120
+ capabilities: PROFILE_CAPABILITIES.baseline,
121
+ canarySampleRate: 0.10,
122
+ };
123
+ }
124
+
125
+ // 2. Environment Override Fast-Path
126
+ const envProfile = env.DOFLOW_ROLLOUT_PROFILE;
127
+ if (typeof envProfile === 'string' && envProfile.trim()) {
128
+ const clean = envProfile.trim() ;
129
+ if (VALID_PROFILES.has(clean)) {
130
+ return {
131
+ name: clean,
132
+ origin: {
133
+ source: 'env',
134
+ detail: 'DOFLOW_ROLLOUT_PROFILE',
135
+ },
136
+ capabilities: PROFILE_CAPABILITIES[clean],
137
+ canarySampleRate: 0.10,
138
+ };
139
+ } else {
140
+ // Invalid env profile falls safe to baseline
141
+ return {
142
+ name: 'baseline',
143
+ origin: {
144
+ source: 'default',
145
+ detail: `invalid-profile-value:${clean}`,
146
+ },
147
+ capabilities: PROFILE_CAPABILITIES.baseline,
148
+ canarySampleRate: 0.10,
149
+ };
150
+ }
151
+ }
152
+
153
+ // 3. Inspect Candidate Layered Settings Files (local -> project -> user)
154
+ const candidateFiles = [];
155
+ if (projectRoot) {
156
+ candidateFiles.push({
157
+ layer: 'project',
158
+ path: path.join(projectRoot, '.doflow', 'settings.local.json'),
159
+ });
160
+ candidateFiles.push({
161
+ layer: 'project',
162
+ path: path.join(projectRoot, '.doflow', 'settings.json'),
163
+ });
164
+ }
165
+
166
+ const userHome = configHome(env).dir;
167
+ const userConfigDir = userHome;
168
+
169
+ if (userConfigDir) {
170
+ candidateFiles.push({
171
+ layer: 'user',
172
+ path: path.join(userConfigDir, 'settings.json'),
173
+ });
174
+ }
175
+
176
+ for (const { layer, path: filePath } of candidateFiles) {
177
+ const content = readJsonFile(filePath, fsImpl);
178
+ if (!content) continue;
179
+
180
+ const rawVal = getSettingValue(content, 'rollout.profile');
181
+ if (typeof rawVal === 'string' && rawVal.trim()) {
182
+ const clean = rawVal.trim() ;
183
+ if (VALID_PROFILES.has(clean)) {
184
+ return {
185
+ name: clean,
186
+ origin: {
187
+ source: layer,
188
+ detail: `${layer}:${filePath}`,
189
+ },
190
+ capabilities: PROFILE_CAPABILITIES[clean],
191
+ canarySampleRate: 0.10,
192
+ };
193
+ } else {
194
+ // Unknown or invalid profile fails safe to baseline (ERR_PROFILE_INVALID)
195
+ return {
196
+ name: 'baseline',
197
+ origin: {
198
+ source: 'default',
199
+ detail: `invalid-profile-value:${clean}`,
200
+ },
201
+ capabilities: PROFILE_CAPABILITIES.baseline,
202
+ canarySampleRate: 0.10,
203
+ };
204
+ }
205
+ }
206
+ }
207
+
208
+ // 4. Default baseline fallback
209
+ return {
210
+ name: 'baseline',
211
+ origin: {
212
+ source: 'default',
213
+ detail: 'registry-default',
214
+ },
215
+ capabilities: PROFILE_CAPABILITIES.baseline,
216
+ canarySampleRate: 0.10,
217
+ };
218
+ }
219
+
220
+ /**
221
+ * Checks whether a specific feature capability is active under the current profile.
222
+ */
223
+ function isCapabilityActive(
224
+ capability ,
225
+ options
226
+ ) {
227
+ const profile = resolveRolloutProfile(options);
228
+ const val = profile.capabilities[capability];
229
+
230
+ if (capability === 'retrieval') return val !== 'lexical';
231
+ if (capability === 'advisor') return val !== 'off';
232
+ if (capability === 'graph') return val !== 'off';
233
+ if (capability === 'verification') return val !== 'L0';
234
+ if (capability === 'telemetryCanaryTag') return Boolean(val);
235
+
236
+ return false;
237
+ }
238
+
239
+ module.exports = {
240
+ resolveRolloutProfile,
241
+ isCapabilityActive,
242
+ PROFILE_CAPABILITIES,
243
+ VALID_PROFILES,
244
+ };
@@ -0,0 +1,254 @@
1
+ 'use strict';
2
+
3
+ const fs = require('node:fs');
4
+ const path = require('node:path');
5
+
6
+
7
+
8
+
9
+
10
+
11
+
12
+
13
+
14
+
15
+
16
+
17
+
18
+
19
+
20
+ function resolveSentinelPath(projectRoot ) {
21
+ const root = projectRoot ? path.resolve(projectRoot) : process.cwd();
22
+ return path.join(root, '.doflow', 'state', 'rollback.json');
23
+ }
24
+
25
+ function resolveCircuitBreakerPath(projectRoot ) {
26
+ const root = projectRoot ? path.resolve(projectRoot) : process.cwd();
27
+ return path.join(root, '.doflow', 'state', 'circuit-breaker.json');
28
+ }
29
+
30
+ /**
31
+ * Checks whether rollback mode is active.
32
+ * Checked at process start and before every major subsystem dispatch.
33
+ * Sub-5ms evaluation latency. Never throws.
34
+ */
35
+ function checkRollbackState(options
36
+
37
+
38
+
39
+ ) {
40
+ try {
41
+ const env = options?.env || process.env;
42
+
43
+ // 1. Tier 1: Ephemeral Env Fast-Path (0ms, 0 I/O)
44
+ if (env.DOFLOW_ROLLOUT_PROFILE === 'baseline') {
45
+ return {
46
+ active: true,
47
+ reason: 'DOFLOW_ROLLOUT_PROFILE=baseline',
48
+ triggeredAt: null,
49
+ origin: 'env',
50
+ targetProfile: 'baseline',
51
+ };
52
+ }
53
+
54
+ const fsImpl = options?.fsImpl || fs;
55
+ const sentinelPath = resolveSentinelPath(options?.projectRoot);
56
+
57
+ // 2. Tier 2: Sentinel State Fast-Path (.doflow/state/rollback.json)
58
+ // Read it directly: existsSync reports false for an unreadable path (EACCES), which would hide a
59
+ // tripped rollback. Only a sentinel that is absent means no rollback; any other read error fails closed.
60
+ let raw = null;
61
+ try {
62
+ raw = fsImpl.readFileSync(sentinelPath, 'utf8');
63
+ } catch (error ) {
64
+ if (error?.code !== 'ENOENT' && error?.code !== 'ENOTDIR') throw error;
65
+ }
66
+ if (raw !== null) {
67
+ let data ;
68
+ try {
69
+ data = JSON.parse(raw);
70
+ } catch {
71
+ // Corrupt sentinel fails closed to active rollback
72
+ return {
73
+ active: true,
74
+ reason: 'unparseable-rollback-sentinel',
75
+ triggeredAt: null,
76
+ origin: 'sentinel',
77
+ targetProfile: 'baseline',
78
+ };
79
+ }
80
+ if (data && data.active !== false) {
81
+ return {
82
+ active: true,
83
+ reason: data.reason || 'manual-sentinel',
84
+ triggeredAt: data.triggeredAt || null,
85
+ origin: data.origin === 'circuit-breaker' ? 'circuit-breaker' : 'sentinel',
86
+ targetProfile: 'baseline',
87
+ };
88
+ }
89
+ }
90
+
91
+ return {
92
+ active: false,
93
+ reason: null,
94
+ triggeredAt: null,
95
+ origin: 'none',
96
+ targetProfile: 'baseline',
97
+ };
98
+ } catch {
99
+ // The rollback state could not be read: fail closed, as for a corrupt sentinel.
100
+ return {
101
+ active: true,
102
+ reason: 'rollback-state-unavailable',
103
+ triggeredAt: null,
104
+ origin: 'sentinel',
105
+ targetProfile: 'baseline',
106
+ };
107
+ }
108
+ }
109
+
110
+ /**
111
+ * Trips instant rollback by writing the sentinel .doflow/state/rollback.json.
112
+ * Does NOT touch any git-tracked files or require git commits.
113
+ */
114
+ function tripRollback(options ) {
115
+ const sentinelPath = resolveSentinelPath(options.projectRoot);
116
+ const fsImpl = options.fsImpl || fs;
117
+ try {
118
+ const dir = path.dirname(sentinelPath);
119
+ fsImpl.mkdirSync(dir, { recursive: true });
120
+
121
+ const payload = {
122
+ schema: 1,
123
+ active: true,
124
+ reason: options.reason || 'manual-rollback',
125
+ triggeredAt: new Date().toISOString(),
126
+ origin: 'sentinel',
127
+ targetProfile: 'baseline',
128
+ };
129
+
130
+ const tmpPath = `${sentinelPath}.${process.pid}.${Date.now()}.tmp`;
131
+ fsImpl.writeFileSync(tmpPath, JSON.stringify(payload, null, 2), 'utf8');
132
+ try {
133
+ fsImpl.renameSync(tmpPath, sentinelPath);
134
+ } catch {
135
+ fsImpl.writeFileSync(sentinelPath, JSON.stringify(payload, null, 2), 'utf8');
136
+ try { fsImpl.unlinkSync(tmpPath); } catch {}
137
+ }
138
+
139
+ return { ok: true, path: sentinelPath };
140
+ } catch {
141
+ return { ok: false, path: sentinelPath };
142
+ }
143
+ }
144
+
145
+ /**
146
+ * Resets rollback mode by removing the sentinel file.
147
+ */
148
+ function resetRollback(options ) {
149
+ const sentinelPath = resolveSentinelPath(options?.projectRoot);
150
+ const cbPath = resolveCircuitBreakerPath(options?.projectRoot);
151
+ const fsImpl = options?.fsImpl || fs;
152
+
153
+ // A file already gone is the goal; any other failure leaves rollback mode on and is reported.
154
+ let ok = true;
155
+ for (const file of [sentinelPath, cbPath]) {
156
+ try {
157
+ fsImpl.unlinkSync(file);
158
+ } catch (error ) {
159
+ if (error?.code !== 'ENOENT') ok = false;
160
+ }
161
+ }
162
+
163
+ return { ok };
164
+ }
165
+
166
+ /**
167
+ * Records a provider failure (Ollama, Semble, Graphify) and trips the
168
+ * circuit breaker if consecutive failures exceed the threshold (default: 3).
169
+ */
170
+ function recordProviderFailure(
171
+ providerId ,
172
+ error ,
173
+ options
174
+ ) {
175
+ const fsImpl = options?.fsImpl || fs;
176
+ const cbPath = resolveCircuitBreakerPath(options?.projectRoot);
177
+ const threshold = options?.threshold ?? 3;
178
+ const errorMsg = typeof error === 'string' ? error : error?.message || 'unknown error';
179
+
180
+ let cbData = {};
181
+ try {
182
+ if (fsImpl.existsSync(cbPath)) {
183
+ cbData = JSON.parse(fsImpl.readFileSync(cbPath, 'utf8')) || {};
184
+ }
185
+ } catch {
186
+ cbData = {};
187
+ }
188
+
189
+ const currentCount = (cbData[providerId]?.failureCount || 0) + 1;
190
+ cbData[providerId] = {
191
+ failureCount: currentCount,
192
+ lastError: errorMsg,
193
+ lastFailureAt: new Date().toISOString(),
194
+ };
195
+
196
+ try {
197
+ const dir = path.dirname(cbPath);
198
+ fsImpl.mkdirSync(dir, { recursive: true });
199
+ fsImpl.writeFileSync(cbPath, JSON.stringify(cbData, null, 2), 'utf8');
200
+ } catch {}
201
+
202
+ if (currentCount >= threshold) {
203
+ // Trip circuit-breaker rollback sentinel
204
+ const sentinelPath = resolveSentinelPath(options?.projectRoot);
205
+ try {
206
+ const dir = path.dirname(sentinelPath);
207
+ fsImpl.mkdirSync(dir, { recursive: true });
208
+ const payload = {
209
+ schema: 1,
210
+ active: true,
211
+ reason: `Provider '${providerId}' failed ${currentCount} consecutive times: ${errorMsg}`,
212
+ triggeredAt: new Date().toISOString(),
213
+ origin: 'circuit-breaker',
214
+ targetProfile: 'baseline',
215
+ };
216
+ fsImpl.writeFileSync(sentinelPath, JSON.stringify(payload, null, 2), 'utf8');
217
+ } catch {}
218
+
219
+ return { tripped: true, failureCount: currentCount };
220
+ }
221
+
222
+ return { tripped: false, failureCount: currentCount };
223
+ }
224
+
225
+ /**
226
+ * Records provider success to reset consecutive failure count.
227
+ */
228
+ function recordProviderSuccess(
229
+ providerId ,
230
+ options
231
+ ) {
232
+ const fsImpl = options?.fsImpl || fs;
233
+ const cbPath = resolveCircuitBreakerPath(options?.projectRoot);
234
+
235
+ try {
236
+ if (fsImpl.existsSync(cbPath)) {
237
+ const cbData = JSON.parse(fsImpl.readFileSync(cbPath, 'utf8')) || {};
238
+ if (cbData[providerId]) {
239
+ cbData[providerId].failureCount = 0;
240
+ fsImpl.writeFileSync(cbPath, JSON.stringify(cbData, null, 2), 'utf8');
241
+ }
242
+ }
243
+ } catch {}
244
+
245
+ return { failureCount: 0 };
246
+ }
247
+
248
+ module.exports = {
249
+ checkRollbackState,
250
+ tripRollback,
251
+ resetRollback,
252
+ recordProviderFailure,
253
+ recordProviderSuccess,
254
+ };
@@ -0,0 +1,41 @@
1
+ 'use strict';
2
+
3
+ const crypto = require('node:crypto');
4
+
5
+ /**
6
+ * Deterministic canary sampler based on consistent hashing of unitKey.
7
+ * Pure Node.js with zero external dependencies.
8
+ */
9
+ function hashKey(key ) {
10
+ if (typeof key !== 'string' || !key) return 0;
11
+ const hash = crypto.createHash('sha256').update(key).digest('hex').slice(0, 8);
12
+ return parseInt(hash, 16);
13
+ }
14
+
15
+ /**
16
+ * Deterministic sampling check.
17
+ * @param unitKey Distinct identifier (e.g. session ID, task ID, query hash)
18
+ * @param sampleRate Number between 0.0 and 1.0 (e.g. 0.10 for 10%)
19
+ */
20
+ function shouldSample(unitKey , sampleRate ) {
21
+ if (typeof sampleRate !== 'number' || Number.isNaN(sampleRate) || sampleRate <= 0) return false;
22
+ if (sampleRate >= 1.0) return true;
23
+ const hashVal = hashKey(unitKey);
24
+ const normalized = (hashVal % 10000) / 10000;
25
+ return normalized < sampleRate;
26
+ }
27
+
28
+ class CanarySampler {
29
+ shouldSample(unitKey , sampleRate = 0.10) {
30
+ return shouldSample(unitKey, sampleRate);
31
+ }
32
+ hashKey(key ) {
33
+ return hashKey(key);
34
+ }
35
+ }
36
+
37
+ module.exports = {
38
+ hashKey,
39
+ shouldSample,
40
+ CanarySampler,
41
+ };
@@ -5,7 +5,7 @@
5
5
  const fs = require('node:fs');
6
6
  const path = require('node:path');
7
7
  const { updateTaskState } = require('./task-state.js');
8
- const { resolveTaskScope } = require('./task-scope.js');
8
+ const { resolveTaskScope, flatRecordIsOurs } = require('./task-scope.js');
9
9
  const { findStateFile } = require('./checkouts.js');
10
10
 
11
11
  // The readiness record: the latest evaluation of one task, kept where `readiness` ran.
@@ -20,7 +20,7 @@ const STORE = path.join('.doflow', 'state', 'readiness');
20
20
 
21
21
  /**
22
22
  * Where a task's record may be under one checkout, in the order every reader takes them: under the
23
- * feature's namespace, then flat. The writer, `verify`, `orchestrate` and the edit hook all use this
23
+ * feature's namespace, then flat. `verify`, `orchestrate` and the edit hook all read through this
24
24
  * one list, so a record written anywhere is found by each of them from any checkout.
25
25
  * @param {string} taskId
26
26
  * @param {string|null} slug the task's feature slug, when one is known
@@ -89,10 +89,10 @@ function priorRecord(file , fsImpl ) {
89
89
  function writeReadinessRecord({ stateRoot, taskId, slug = null, report, inputs, declaredScope = null, mode, now = new Date(), fsImpl = fs } ) {
90
90
  const scope = resolveTaskScope({ projectRoot: stateRoot, taskId, slug });
91
91
  const recordSlug = scope.slug || slug || null;
92
- // The record a reader would find in this checkout is the one replaced; with none, the record goes
93
- // where the task's evidence goes (under the feature's namespace when it has a register).
94
- const file = recordCandidates(taskId, recordSlug).map((rel) => path.join(stateRoot, rel)).find((f) => fsImpl.existsSync(f))
95
- || path.join(stateRoot, STORE, ...(scope.namespace ? [scope.namespace] : []), `${taskId}.json`);
92
+ // Written where the task's evidence goes (115 C-1): under the feature's namespace whenever one
93
+ // applies. A flat record of the task from before that rule stays where it is, and is no longer
94
+ // read once this one exists.
95
+ const file = path.join(stateRoot, STORE, ...(scope.namespace ? [scope.namespace] : []), `${taskId}.json`);
96
96
  const record = {
97
97
  version: RECORD_VERSION,
98
98
  taskId,
@@ -124,20 +124,25 @@ function writeReadinessRecord({ stateRoot, taskId, slug = null, report, inputs,
124
124
  }
125
125
 
126
126
  /**
127
- * The task's record in this checkout, else in exactly one other checkout, at the first of
128
- * `recordCandidates` that exists in each. No resolver is run: the candidates depend only on the
129
- * task id and the slug the caller names.
127
+ * The task's record where `findStateFile` looks (the main checkout first from a linked worktree),
128
+ * at the first of `recordCandidates` that exists in each checkout; the flat candidate of a
129
+ * namespaced task only when it is this feature's or names none (D-3). No resolver is run: the
130
+ * candidates depend only on the task id and the slug the caller names. `conflict` is a worktree
131
+ * copy that differs from the main checkout's (115 C-3).
130
132
  * @param {Object} options
131
133
  * @param {string} options.stateRoot
132
134
  * @param {string} options.taskId
133
135
  * @param {string|null} [options.slug]
134
136
  * @param {Function} [options.exec]
135
137
  * @param {Object} [options.fsImpl]
136
- * @returns {{status: 'found'|'missing'|'ambiguous'|'unreadable', record: Object|null, file: string|null,
138
+ * @returns {{status: 'found'|'missing'|'ambiguous'|'conflict'|'unreadable', record: Object|null, file: string|null,
137
139
  * origin: 'current'|'other'|null, candidates: Array<string>, detail: string|null}}
138
140
  */
139
141
  function readReadinessRecord({ stateRoot, taskId, slug = null, exec, fsImpl = fs } ) {
140
- const found = findStateFile({ stateRoot, relPath: recordCandidates(taskId, slug), ...(exec ? { exec } : {}), fsImpl });
142
+ const [first, flat] = recordCandidates(taskId, slug);
143
+ const relPath = flat === undefined ? first
144
+ : (root ) => (fsImpl.existsSync(path.join(root, first)) ? first : flatRecordIsOurs(path.join(root, flat), slug, fsImpl) ? flat : null);
145
+ const found = findStateFile({ stateRoot, relPath, ...(exec ? { exec } : {}), fsImpl });
141
146
  const base = { record: null, file: found.file, origin: found.origin, candidates: found.candidates, detail: null };
142
147
  if (found.status !== 'found') return { ...base, status: found.status };
143
148
  try {