@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
@@ -3,16 +3,16 @@
3
3
  // TypeScript migration (agent-docs/BRIEF_GOAL_DOFLOW.md): run directly by Node native type-stripping.
4
4
 
5
5
  const fs = require('node:fs');
6
- const os = require('node:os');
7
6
  const path = require('node:path');
7
+ const { configHome } = require('../config-home.js');
8
8
 
9
9
  function absolute(value ) { return typeof value === 'string' && path.isAbsolute(value) ? value : null; }
10
10
 
11
11
  /** Resolves IC-001's five physical roots; -g/global deliberately omits project roots. */
12
12
  function resolveRoots({ registry, projectRoot, global = false, env = process.env } = {}) {
13
- const home = absolute(env.HOME) || os.homedir();
14
- const xdgBase = env.XDG_CONFIG_HOME === undefined || env.XDG_CONFIG_HOME === ''
15
- ? path.join(home, '.config') : absolute(env.XDG_CONFIG_HOME);
13
+ // No home variable means no home base and no config home: nothing falls back to the account home (DD-7).
14
+ const home = absolute(env.HOME);
15
+ const xdgBase = configHome(env).base;
16
16
  const project = global ? null : absolute(projectRoot);
17
17
  const bases = { project, home, 'xdg-config': xdgBase };
18
18
  return Object.fromEntries(Object.entries(registry.roots).map(([id, root] ) => {
@@ -21,21 +21,71 @@ function resolveRoots({ registry, projectRoot, global = false, env = process.env
21
21
  }));
22
22
  }
23
23
 
24
- function readSetting(file , fsImpl ) {
25
- try {
26
- const first = fsImpl.readFileSync(file, 'utf8').split(/\r?\n/, 1)[0].trim().toLowerCase();
27
- return first === 'on' || first === 'off' ? first : 'off';
28
- } catch { return 'off'; }
24
+ /** Creates one IC-014 resolver for all roots in a command; a project view can also read global scope. */
25
+ function createPruneSettingsResolver({ roots, fsImpl = fs, onView } = {}) {
26
+ const resolverEnv = {};
27
+ if (roots['config-home']) resolverEnv.XDG_CONFIG_HOME = path.dirname(roots['config-home']);
28
+ let view = null;
29
+ let loadedView = false;
30
+ return (rootId ) => {
31
+ if (!loadedView) {
32
+ loadedView = true;
33
+ try {
34
+ let settingsRegistry;
35
+ if (fsImpl !== fs) {
36
+ const { loadSettingsRegistry } = require('../settings/registry.js');
37
+ const loaded = loadSettingsRegistry({ fsImpl });
38
+ if (!loaded.ok) throw new Error(loaded.detail);
39
+ settingsRegistry = loaded.registry;
40
+ }
41
+ const { loadSettings } = require('../settings/resolve.js');
42
+ const projectRoot = roots['project-doflow'] ? path.dirname(roots['project-doflow']) : null;
43
+ view = loadSettings({ projectRoot, env: resolverEnv, fsImpl, ...(settingsRegistry ? { registry: settingsRegistry } : {}) });
44
+ } catch {
45
+ // A settings registry fault fails closed for every root, as it did for each old call.
46
+ view = null;
47
+ }
48
+ if (typeof onView === 'function') onView(view);
49
+ }
50
+ if (!view) return { setting: 'off', decidedBy: null };
51
+ try {
52
+ const usesProject = rootId === 'project-doflow' || rootId === 'project-state';
53
+ const resolved = view.get('storage.prune', usesProject ? 'project' : 'global');
54
+ return {
55
+ setting: resolved.value === 'on' ? 'on' : 'off',
56
+ decidedBy: resolved.origin.layer === 'default' ? null : resolved.origin.source,
57
+ };
58
+ } catch {
59
+ return { setting: 'off', decidedBy: null };
60
+ }
61
+ };
29
62
  }
30
63
 
31
64
  /** Reads IC-014 and reports exactly which present file made the decision, if any. */
32
- function readPruneSetting({ registry, roots, rootId, fsImpl = fs } = {}) {
33
- const projectFile = roots['project-doflow'] ? path.join(roots['project-doflow'], registry.settings.optOutFile) : null;
34
- const userFile = roots['config-home'] ? path.join(roots['config-home'], registry.settings.optOutFile) : null;
65
+ function readPruneSetting({ roots, rootId, fsImpl = fs } = {}) {
35
66
  const usesProject = rootId === 'project-doflow' || rootId === 'project-state';
36
- if (usesProject && projectFile && fsImpl.existsSync(projectFile)) return { setting: readSetting(projectFile, fsImpl), decidedBy: projectFile };
37
- if (userFile && fsImpl.existsSync(userFile)) return { setting: readSetting(userFile, fsImpl), decidedBy: userFile };
38
- return { setting: 'on', decidedBy: null };
67
+ const global = !usesProject;
68
+ const projectRoot = !global && roots['project-doflow'] ? path.dirname(roots['project-doflow']) : null;
69
+ const resolverEnv = {};
70
+ if (roots['config-home']) resolverEnv.XDG_CONFIG_HOME = path.dirname(roots['config-home']);
71
+ try {
72
+ let settingsRegistry;
73
+ if (fsImpl !== fs) {
74
+ const { loadSettingsRegistry } = require('../settings/registry.js');
75
+ const loaded = loadSettingsRegistry({ fsImpl });
76
+ if (!loaded.ok) throw new Error(loaded.detail);
77
+ settingsRegistry = loaded.registry;
78
+ }
79
+ const { loadSettings } = require('../settings/resolve.js');
80
+ const view = loadSettings({ projectRoot, global, env: resolverEnv, fsImpl, ...(settingsRegistry ? { registry: settingsRegistry } : {}) });
81
+ const resolved = view.get('storage.prune', global ? 'global' : 'project');
82
+ return {
83
+ setting: resolved.value === 'on' ? 'on' : 'off',
84
+ decidedBy: resolved.origin.layer === 'default' ? null : resolved.origin.source,
85
+ };
86
+ } catch {
87
+ return { setting: 'off', decidedBy: null };
88
+ }
39
89
  }
40
90
 
41
91
  function linked(file , fsImpl ) {
@@ -60,4 +110,4 @@ function resolveStorePath({ store, roots, fsImpl = fs } = {})
60
110
  return current;
61
111
  }
62
112
 
63
- module.exports = { resolveRoots, readPruneSetting, resolveStorePath };
113
+ module.exports = { resolveRoots, readPruneSetting, createPruneSettingsResolver, resolveStorePath };
@@ -4,7 +4,7 @@
4
4
 
5
5
  const fs = require('node:fs');
6
6
  const path = require('node:path');
7
- const { workStatus, createWorkCache, refreshedWorkCache } = require('./work-status.js');
7
+ const { workStatus, recordExtension, createWorkCache, refreshedWorkCache } = require('./work-status.js');
8
8
  const { projectKey } = require('../lifecycle/report-store.js');
9
9
  const { readEvents } = require('../lifecycle/event-store.js');
10
10
 
@@ -50,7 +50,7 @@ function workCandidates(store , entries , context ) {
50
50
  const project = projectRoot(roots);
51
51
  if (!project) return [];
52
52
  const cache = context.cache || createWorkCache({ projectRoot: project, fsImpl });
53
- const recordMatch = new RegExp(store.match), selected = [];
53
+ const recordMatch = new RegExp(store.match), extensionLength = recordExtension(store.match).length, selected = [];
54
54
  const visit = (dir , namespace = null) => {
55
55
  let children;
56
56
  try { children = names(fsImpl, dir); } catch { return true; }
@@ -61,7 +61,7 @@ function workCandidates(store , entries , context ) {
61
61
  if (TMP.test(name) && now - stat.mtimeMs > settings.staleTmpHours * HOUR) {
62
62
  selected.push({ name: namespace ? `${namespace}/${name}` : name, reason: 'stale-tmp', bytes: stat.size, mtimeMs: stat.mtimeMs, recordStat: stat });
63
63
  } else if (recordMatch.test(name)) {
64
- const result = workStatus({ projectRoot: project, store: store.id, taskId: name.slice(0, -5), namespace, mtimeMs: stat.mtimeMs, cache, fsImpl, shouldStop });
64
+ const result = workStatus({ projectRoot: project, store: store.id, taskId: name.slice(0, -extensionLength), namespace, mtimeMs: stat.mtimeMs, cache, fsImpl, shouldStop });
65
65
  if (result.incomplete || shouldStop?.()) return false;
66
66
  if (result.state === 'finished' && now - result.since > store.bound.finishedDays * DAY)
67
67
  selected.push({ name: namespace ? `${namespace}/${name}` : name, reason: 'finished-work', bytes: stat.size, mtimeMs: result.since, recordStat: stat });
@@ -92,7 +92,7 @@ function recordStillCandidate(store , candidate , info , context
92
92
  if (!snapshot?.ok || JSON.stringify(current) !== JSON.stringify(snapshot.value)) return false;
93
93
  }
94
94
  const fresh = cache ? refreshedWorkCache(cache) : undefined;
95
- const status = workStatus({ projectRoot: projectRoot(roots), store: store.id, taskId: name.slice(0, -5), namespace, mtimeMs: info.mtimeMs, cache: fresh, fsImpl, shouldStop });
95
+ const status = workStatus({ projectRoot: projectRoot(roots), store: store.id, taskId: name.slice(0, -recordExtension(store.match).length), namespace, mtimeMs: info.mtimeMs, cache: fresh, fsImpl, shouldStop });
96
96
  return !status.incomplete && !shouldStop?.() && status.state === 'finished'
97
97
  && status.since === candidate.mtimeMs && now - status.since > store.bound.finishedDays * DAY;
98
98
  }
@@ -138,7 +138,7 @@ function protectedLogs({ registry, roots, fsImpl, cache, shouldStop } ) {
138
138
  continue;
139
139
  }
140
140
  if (!stat.isFile() || !recordMatch.test(name)) continue;
141
- const status = workStatus({ projectRoot: project, store: store.id, taskId: name.slice(0, -5), namespace, mtimeMs: stat.mtimeMs, cache: workCache, fsImpl, shouldStop });
141
+ const status = workStatus({ projectRoot: project, store: store.id, taskId: name.slice(0, -recordExtension(store.match).length), namespace, mtimeMs: stat.mtimeMs, cache: workCache, fsImpl, shouldStop });
142
142
  if (status.incomplete || shouldStop?.()) return false;
143
143
  if (status.state === 'finished') continue;
144
144
  try {
@@ -158,6 +158,73 @@ function protectedLogs({ registry, roots, fsImpl, cache, shouldStop } ) {
158
158
  }
159
159
  return { names: protectedNames, incomplete: false };
160
160
  }
161
+ const WORKER_UNIT = /^L\.([A-Za-z0-9][A-Za-z0-9_-]{0,55})\.([A-Za-z0-9][A-Za-z0-9_-]{0,55})\.([1-9][0-9]{0,3})\.json$/;
162
+ /** Every `<slug>.json` store file of `.doflow/state/<dir>` read by `read`; [] when the folder is
163
+ * absent, null when a link sits on the path or any file cannot be read (the caller fails closed). */
164
+ function stateStores(project , dir , read , fsImpl , shouldStop ) {
165
+ let current = project;
166
+ for (const segment of ['.doflow', 'state', dir]) {
167
+ current = path.join(current, segment);
168
+ let info;
169
+ try { info = fsImpl.lstatSync(current); }
170
+ catch (error ) { if (error.code === 'ENOENT' || error.code === 'ENOTDIR') return []; return null; }
171
+ if (info.isSymbolicLink() || !info.isDirectory()) return null;
172
+ }
173
+ const stores = [];
174
+ let list;
175
+ try { list = names(fsImpl, current); } catch { return null; }
176
+ for (const name of list) {
177
+ if (shouldStop?.()) return null;
178
+ if (!name.endsWith('.json')) continue;
179
+ const info = safeStat(fsImpl, path.join(current, name));
180
+ if (!info || info.isSymbolicLink() || !info.isFile()) return null;
181
+ try { stores.push(read(path.join(current, name), fsImpl)); } catch { return null; }
182
+ }
183
+ return stores;
184
+ }
185
+ /**
186
+ * Protect kind `unfinished-run` (row 120 IC-005): of the candidate names `L.<run>.<lineage>.<attempt>.json`,
187
+ * the ones to keep. A name is released only when this project's worker run store holds at least one
188
+ * run whose `identity` is that unit and every such run is terminal, and no dispatch naming one of
189
+ * those runs (`workerRunId`) is still open. Terminal is the one end phase each store has: a worker
190
+ * run's `phase: 'ended'` (run-store.ts PHASES, which `transition` never leaves) and a dispatch's
191
+ * `phase: 'ended'` (dispatch/store.ts NEXT_PHASES, add-only once reached). Everything else is kept
192
+ * (fail closed): an unparsable name, no project, an unknown unit (another project's file, or a run
193
+ * record pruned first), a link on a store path or any store file that cannot be read.
194
+ */
195
+ function unfinishedRuns({ roots, fsImpl, names: candidates, shouldStop } ) {
196
+ const all = new Set (candidates);
197
+ const project = projectRoot(roots);
198
+ if (!project) return { names: all, incomplete: false };
199
+ const { readRuns } = require('../worker/run-store.js');
200
+ const { readDispatch } = require('../dispatch/store.js');
201
+ const runStores = stateStores(project, 'worker-runs', (file, impl) => ({ runs: readRuns(file, impl) }), fsImpl, shouldStop);
202
+ if (shouldStop?.()) return { names: all, incomplete: true };
203
+ const dispatchStores = runStores && stateStores(project, 'dispatch', readDispatch, fsImpl, shouldStop);
204
+ if (shouldStop?.()) return { names: all, incomplete: true };
205
+ if (!runStores || !dispatchStores) return { names: all, incomplete: false };
206
+ const units = new Map ();
207
+ for (const store of runStores) for (const [runId, run] of Object.entries(store.runs) ) {
208
+ const id = run?.identity;
209
+ if (!id || typeof id.run !== 'string' || typeof id.lineage !== 'string' || typeof id.attempt !== 'string') continue;
210
+ const key = `${id.run}.${id.lineage}.${id.attempt}`;
211
+ const unit = units.get(key) || { ended: true, runIds: [] };
212
+ unit.ended = unit.ended && run.phase === 'ended';
213
+ unit.runIds.push(runId);
214
+ units.set(key, unit);
215
+ }
216
+ const openRuns = new Set ();
217
+ for (const store of dispatchStores) for (const dispatch of Object.values(store.dispatches) ) {
218
+ if (dispatch.phase !== 'ended' && typeof dispatch.workerRunId === 'string') openRuns.add(dispatch.workerRunId);
219
+ }
220
+ const kept = new Set ();
221
+ for (const name of candidates) {
222
+ const match = WORKER_UNIT.exec(name);
223
+ const unit = match && units.get(`${match[1]}.${match[2]}.${match[3]}`);
224
+ if (!unit || !unit.ended || unit.runIds.some((runId) => openRuns.has(runId))) kept.add(name);
225
+ }
226
+ return { names: kept, incomplete: false };
227
+ }
161
228
  function lifecyclePathsSafe(project , fsImpl ) {
162
229
  for (const rel of [path.join('.doflow'), path.join('.doflow', 'state'), path.join('.doflow', 'state', 'lifecycle'), path.join('.doflow', 'state', 'lifecycle', 'events')]) {
163
230
  try { if (fsImpl.lstatSync(path.join(project, rel)).isSymbolicLink()) return false; }
@@ -236,14 +303,19 @@ function selectCandidates(store , entries , context ) {
236
303
  const { now, fsImpl, storeDir, roots, shouldStop } = context;
237
304
  switch (store.rule) {
238
305
  case 'count-and-age': {
239
- const ordered = [...entries].sort((a, b) => Number(b.name.slice(0, 13)) - Number(a.name.slice(0, 13)) || a.name.localeCompare(b.name));
306
+ const hasTimestamp = (entry ) => /^[0-9]{13}/.test(entry.name);
307
+ const entryTime = (entry ) => hasTimestamp(entry) ? Number(entry.name.slice(0, 13)) : entry.stat.mtimeMs;
308
+ const ordered = [...entries].sort((a, b) => entryTime(b) - entryTime(a) || a.name.localeCompare(b.name));
240
309
  if (stopped(context)) return null;
241
310
  const selected = [];
242
311
  for (let index = 0; index < ordered.length; index += 1) {
243
312
  if (shouldStop?.()) return null;
244
- const entry = ordered[index], time = Number(entry.name.slice(0, 13));
245
- if (index >= store.bound.keepNewest || now - time > store.bound.maxAgeDays * DAY)
246
- selected.push({ name: entry.name, reason: index >= store.bound.keepNewest ? 'count' : 'age', bytes: entry.stat.size, mtimeMs: time });
313
+ const entry = ordered[index], time = entryTime(entry);
314
+ const beyondCount = index >= store.bound.keepNewest, beyondAge = now - time > store.bound.maxAgeDays * DAY;
315
+ // Preserve timestamped stores' count-or-age policy; mtime entries must exceed both bounds unless bound.either is set.
316
+ const eitherBound = hasTimestamp(entry) || store.bound?.either === true;
317
+ if (eitherBound ? beyondCount || beyondAge : beyondCount && beyondAge)
318
+ selected.push({ name: entry.name, reason: beyondCount ? 'count' : 'age', bytes: entry.stat.size, mtimeMs: time });
247
319
  }
248
320
  return selected;
249
321
  }
@@ -279,4 +351,4 @@ function selectCandidates(store , entries , context ) {
279
351
  default: throw new Error(`Unknown storage rule '${store.rule}'`);
280
352
  }
281
353
  }
282
- module.exports={selectCandidates,recordStillCandidate,protectedLogs,removableRules,ruleOrder,projectRoot,BODY};
354
+ module.exports={selectCandidates,recordStillCandidate,protectedLogs,unfinishedRuns,removableRules,ruleOrder,projectRoot,BODY};
@@ -9,7 +9,7 @@ const { REPO_ROOT } = require('../../helper/repo-root.js');
9
9
  const { loadStorageRegistry } = require('./registry.js');
10
10
  const { resolveRoots, readPruneSetting } = require('./roots.js');
11
11
  const engine = require('./engine.js');
12
- const { RunLedger } = require('../trace/ledger.js');
12
+ const { RunLedger, outerProjectRoot } = require('../trace/ledger.js');
13
13
 
14
14
  // Load once: a not-due moment only reads the three small markers, never the catalogue again.
15
15
  let registry ;
@@ -147,7 +147,10 @@ function passForRoot({ roots, rootId, stores, now, env, fsImpl, throttled = fals
147
147
 
148
148
  /** IC-009: silent throttled upkeep after a verb, using that verb's resolved store root. */
149
149
  function upkeepAfterVerb({ projectRoot, now = Date.now(), env = process.env, fsImpl = fs } = {}) {
150
+ // IC-004: the read switch, exact `off` like DOFLOW_TELEMETRY; nothing at all is written.
151
+ if (env.DOFLOW_UPKEEP === 'off') return;
150
152
  return silently(() => {
153
+ projectRoot = projectRoot && outerProjectRoot(projectRoot);
151
154
  const roots = resolveRoots({ registry, projectRoot, env });
152
155
  for (const rootId of ['project-state', 'user-state']) {
153
156
  try { ensureIgnore({ roots, rootId, projectRoot, fsImpl }); } catch { /* continue other roots */ }
@@ -165,14 +168,19 @@ function upkeepAfterVerb({ projectRoot, now = Date.now(), env = process.env, fsI
165
168
 
166
169
  /** IC-010: the verify moment is project-only and unthrottled. Wiring belongs to D.3. */
167
170
  function upkeepAfterVerify({ projectRoot, now = Date.now(), env = process.env, fsImpl = fs } = {}) {
171
+ // IC-004: the switch covers every upkeep moment, so `off` prunes, locks and writes nothing here either.
172
+ if (env.DOFLOW_UPKEEP === 'off') return;
168
173
  return silently(() => {
174
+ projectRoot = projectRoot && outerProjectRoot(projectRoot);
169
175
  const roots = resolveRoots({ registry, projectRoot, env });
170
- return passForRoot({ roots, rootId: 'project-state', stores: ['verification-logs'], now, env, fsImpl });
176
+ return passForRoot({ roots, rootId: 'project-state', stores: ['verification-logs', 'verification-reuse'], now, env, fsImpl });
171
177
  });
172
178
  }
173
179
 
174
180
  /** IC-011: only this scope's recovery store; install/update call sites belong to D.4. */
175
181
  function storageAfterInstall({ scope, scopeRoot, now = Date.now(), env = process.env, fsImpl = fs } = {}) {
182
+ // IC-004: no ignore file, prune pass or lock at install time under the switch either.
183
+ if (env.DOFLOW_UPKEEP === 'off') return;
176
184
  return silently(() => {
177
185
  if (!['project', 'global'].includes(scope)) return;
178
186
  const global = scope === 'global';