@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,324 @@
1
+ 'use strict';
2
+
3
+ // TypeScript migration (agent-docs/BRIEF_GOAL_DOFLOW.md): run directly by Node native type-stripping.
4
+
5
+ /**
6
+ * Row 134: what a plan says, checked deterministically, beside the task-graph verdict
7
+ * `planVerdict` makes. Each finding carries a `path:line` locator and a severity:
8
+ * - `fix`: the plan has a hole the self-review must close (an untraced requirement id, a placeholder);
9
+ * - `refuses-exit`: the planning stage cannot complete while it stands;
10
+ * - `advisory`: recorded and reported, never blocking.
11
+ * Read-only: nothing here writes.
12
+ */
13
+
14
+ const fs = require('node:fs');
15
+ const path = require('node:path');
16
+ const { REPO_ROOT } = require('../helper/repo-root.js');
17
+
18
+
19
+
20
+ /** The visible Markdown of a file: fenced code blanked and HTML comments removed, and inline code
21
+ * spans too unless `keepCode` is set, so a placeholder quoted as an example, a table left in a
22
+ * comment or a template's guidance is not read. A fence closes only on its own character, a run at
23
+ * least as long as its opener and nothing after it (CommonMark; doc_quality_checker.py since row
24
+ * 132). Line numbers are kept: index i is line i + 1. */
25
+ function proseLines(text , { keepCode = false } = {}) {
26
+ const out = [];
27
+ let fence = null;
28
+ let comment = false;
29
+ for (const raw of text.split(/\r?\n/)) {
30
+ const run = raw.match(/^ {0,3}(`{3,}|~{3,})(.*)$/);
31
+ if (fence === null && run && !(run[1][0] === '`' && run[2].includes('`'))) { fence = run[1]; out.push(''); continue; }
32
+ if (fence !== null) {
33
+ if (run && run[1][0] === fence[0] && run[1].length >= fence.length && run[2].trim() === '') fence = null;
34
+ out.push('');
35
+ continue;
36
+ }
37
+ let line = raw;
38
+ let kept = '';
39
+ while (line.length) {
40
+ if (comment) {
41
+ const end = line.indexOf('-->');
42
+ if (end === -1) { line = ''; break; }
43
+ comment = false;
44
+ line = line.slice(end + 3);
45
+ } else {
46
+ const start = line.indexOf('<!--');
47
+ if (start === -1) { kept += line; break; }
48
+ kept += line.slice(0, start);
49
+ comment = true;
50
+ line = line.slice(start + 4);
51
+ }
52
+ }
53
+ out.push(keepCode ? kept : kept.replace(/`[^`]*`/g, ''));
54
+ }
55
+ return out;
56
+ }
57
+
58
+ const PLACEHOLDERS = [
59
+ /\b(?:TBD|TODO|FIXME)\b/,
60
+ /\bto be (?:decided|determined|defined)\b/i,
61
+ // "later" only as a placeholder phrasing: "fill in later", or alone as a table cell. Prose such
62
+ // as "later phases" or "add filters later" is a plan, not a hole.
63
+ /\bfill(?: it)? in later\b/i,
64
+ /\|\s*later\s*(?=\|)/i,
65
+ ];
66
+
67
+ function placeholderFindings(text , displayPath ) {
68
+ const findings = [];
69
+ proseLines(text).forEach((line, index) => {
70
+ const hit = PLACEHOLDERS.map((re) => line.match(re)).find(Boolean);
71
+ if (!hit) return;
72
+ findings.push({
73
+ rule: 'placeholder', severity: 'fix', path: displayPath, line: index + 1,
74
+ message: `'${hit[0]}' is a placeholder: state the decision or the task, or record it as a gap in §3`,
75
+ });
76
+ });
77
+ return findings;
78
+ }
79
+
80
+ const REQUIREMENT_ID = /\b(?:US\d+|FR-\d+|NFR-\d+)\b/;
81
+
82
+ /** The ids requirement.md defines and still holds live: a user story bullet (`**US1`) or an index
83
+ * row (`| FR-001 |`) whose row is not `Superseded`, read up to the History section. The first
84
+ * defining line of each id is its locator. */
85
+ function requirementIds(text ) {
86
+ const ids = new Map ();
87
+ const lines = proseLines(text);
88
+ for (let i = 0; i < lines.length; i += 1) {
89
+ const line = lines[i];
90
+ if (/^##\s+(?:\d+\.\s*)?History\b/i.test(line)) break;
91
+ const story = line.match(/^\s*[-*]\s+\*\*(US\d+)\b/);
92
+ const row = line.match(/^\s*\|\s*((?:FR|NFR)-\d+)\s*\|/);
93
+ const id = story?.[1] || (row && !/\bSuperseded\b/i.test(line) ? row[1] : null);
94
+ if (id && !ids.has(id)) ids.set(id, i + 1);
95
+ }
96
+ return [...ids].map(([id, line]) => ({ id, line }));
97
+ }
98
+
99
+ function coverageFindings(planText , planPath , requirementText , requirementPath ) {
100
+ const visible = proseLines(planText, { keepCode: true });
101
+ return requirementIds(requirementText)
102
+ .filter(({ id }) => !visible.some((line) => new RegExp(`\\b${id}\\b`).test(line)))
103
+ .map(({ id, line }) => ({
104
+ rule: 'coverage', severity: 'fix' , path: requirementPath, line, id,
105
+ message: `${id} is not traced anywhere in ${planPath}: name it on the task that delivers it, or on the §7 row that verifies it`,
106
+ }));
107
+ }
108
+
109
+ /** The requirement next to a plan, found the way the path resolver finds it: `intention/`
110
+ * under the structured layout, beside the plan otherwise. */
111
+ function requirementBeside(planAbs ) {
112
+ const dir = path.dirname(planAbs);
113
+ return [path.join(dir, 'intention', 'requirement.md'), path.join(dir, 'requirement.md')].find((f) => fs.existsSync(f)) || null;
114
+ }
115
+
116
+ // ── constitution (row 134 item 4: a MUST conflict refuses the planning stage's exit) ──────────────
117
+
118
+ /** Where the base tier is, beside a runtime root: the checkout's `core/shared` copy, else the
119
+ * install's guidance tree, a sibling of `<install>/.doflow/runtime` (which carries no core/shared),
120
+ * resolved the way `resolveBashHelper` finds the bash helpers. */
121
+ function constitutionBaseCandidates(runtimeRoot = REPO_ROOT) {
122
+ return [
123
+ path.join(runtimeRoot, 'core', 'shared', 'guidance', 'references', 'CONSTITUTION_BASE.md'),
124
+ path.resolve(runtimeRoot, '..', 'guidance', 'references', 'CONSTITUTION_BASE.md'),
125
+ ];
126
+ }
127
+ function constitutionBaseFile(runtimeRoot = REPO_ROOT) {
128
+ return constitutionBaseCandidates(runtimeRoot).find((file) => fs.existsSync(file)) || null;
129
+ }
130
+ const CONSTITUTION_BASE = constitutionBaseFile() || constitutionBaseCandidates()[0];
131
+ const CONSTITUTION_LOCAL = 'agent-docs/constitution.md';
132
+ const UNBLOCK = 'revise the plan until it passes and record its row, or have a person amend the constitution with /do-constitution; there is no waiver';
133
+
134
+
135
+
136
+ /** A heading's principle id: the text before ` — `, else its first word. */
137
+ function principleId(cell ) {
138
+ const plain = cell.replace(/[*`]/g, '').trim();
139
+ return (plain.split(/\s+[—–-]\s+/)[0].split(/\s+/)[0] || '').trim();
140
+ }
141
+
142
+ /** The principles a constitution file declares: each `### ` heading under `## Principles`, MUST
143
+ * unless its body carries `**Tier:** SHOULD`. */
144
+ function parsePrinciples(text , source ) {
145
+ const principles = [];
146
+ const lines = proseLines(text, { keepCode: true });
147
+ let inside = false;
148
+ let current = null;
149
+ lines.forEach((line, index) => {
150
+ if (/^##\s/.test(line)) { inside = /^##\s+Principles\b/i.test(line); current = null; return; }
151
+ if (!inside) return;
152
+ const heading = line.match(/^###\s+(.+?)\s*$/);
153
+ if (heading) {
154
+ current = { id: principleId(heading[1]), tier: 'MUST', source, line: index + 1 };
155
+ if (current.id) principles.push(current);
156
+ return;
157
+ }
158
+ const tier = line.match(/^\s*\*\*Tier:\*\*\s*(MUST|SHOULD)\b/i);
159
+ if (tier && current) current.tier = tier[1].toUpperCase() ;
160
+ });
161
+ return principles;
162
+ }
163
+
164
+ /** A principle id declared twice in one file, named with both lines; null when every id is unique. */
165
+ function duplicateId(principles , file ) {
166
+ const seen = new Map ();
167
+ for (const p of principles) {
168
+ if (seen.has(p.id)) return `${file} declares ${p.id} twice (lines ${seen.get(p.id)} and ${p.line})`;
169
+ seen.set(p.id, p.line);
170
+ }
171
+ return null;
172
+ }
173
+
174
+ /** Both tiers, tier-2 taking precedence: a tier-2 principle with a base id replaces it in place,
175
+ * a new id is appended. `error` is set when either file cannot be read, has no `## Principles`
176
+ * section with a principle in it, or declares an id twice; the gate then refuses rather than
177
+ * check the plan against fewer principles than the constitution holds. A base MUST the overlay
178
+ * makes SHOULD is allowed (the designed tier-2 path) and listed in `downgrades`, never silent. */
179
+ function loadConstitution({ checkoutRoot, runtimeRoot = REPO_ROOT } ) {
180
+ const none = { principles: [] , downgrades: [] };
181
+ const baseFile = constitutionBaseFile(runtimeRoot);
182
+ if (!baseFile) return { ...none, error: `the base constitution cannot be found (searched ${constitutionBaseCandidates(runtimeRoot).join(', ')})` };
183
+ let base ;
184
+ try { base = fs.readFileSync(baseFile, 'utf8'); } catch (error ) {
185
+ return { ...none, error: `the base constitution ${baseFile} cannot be read (${error.code || error.message})` };
186
+ }
187
+ const principles = parsePrinciples(base, 'CONSTITUTION_BASE.md');
188
+ if (!principles.length) return { ...none, error: `the base constitution ${baseFile} declares no principle` };
189
+ const baseDuplicate = duplicateId(principles, baseFile);
190
+ if (baseDuplicate) return { ...none, error: baseDuplicate };
191
+ const localFile = path.join(checkoutRoot, CONSTITUTION_LOCAL);
192
+ let local = null;
193
+ try { local = fs.readFileSync(localFile, 'utf8'); } catch (error ) {
194
+ if (error.code !== 'ENOENT') return { ...none, error: `the repo constitution ${CONSTITUTION_LOCAL} cannot be read (${error.code || error.message})` };
195
+ }
196
+ if (local === null) return { principles, downgrades: none.downgrades, error: null };
197
+ const overlay = parsePrinciples(local, CONSTITUTION_LOCAL);
198
+ if (!overlay.length) {
199
+ return { ...none, error: `the repo constitution ${CONSTITUTION_LOCAL} has no \`## Principles\` section with a \`### <ID> — <name>\` principle, so its principles cannot be read` };
200
+ }
201
+ const overlayDuplicate = duplicateId(overlay, CONSTITUTION_LOCAL);
202
+ if (overlayDuplicate) return { ...none, error: overlayDuplicate };
203
+ const version = (proseLines(local).join('\n').match(/\*\*Version:\*\*\s*([^\s·]+)/) || [])[1] || null;
204
+ const downgrades = [];
205
+ for (const principle of overlay) {
206
+ const at = principles.findIndex((p) => p.id === principle.id);
207
+ if (at === -1) { principles.push(principle); continue; }
208
+ if (principles[at].tier === 'MUST' && principle.tier === 'SHOULD') downgrades.push({ ...principle, version });
209
+ principles[at] = principle;
210
+ }
211
+ return { principles, downgrades, error: null };
212
+ }
213
+
214
+ /** The §2 "Constitution Check" record in the plan's visible Markdown: one table row per
215
+ * principle, read by its `Principle` and `Result` columns. A header row with no `|---|` separator
216
+ * under it is no table; `unparseable` is then that header's line. */
217
+ function constitutionRecord(planText ) {
218
+ const lines = proseLines(planText, { keepCode: true });
219
+ const start = lines.findIndex((line) => /^##\s+(?:\d+\.\s*)?Constitution Check\b/i.test(line));
220
+ const rows = [];
221
+ if (start === -1) return { heading: null, rows, unparseable: null };
222
+ const cellsOf = (line ) => line.trim().replace(/^\||\|$/g, '').split('|').map((cell) => cell.trim());
223
+ let columns = null;
224
+ for (let i = start + 1; i < lines.length && !/^##\s/.test(lines[i]); i += 1) {
225
+ if (!/^\s*\|/.test(lines[i])) { if (columns) break; continue; }
226
+ const cells = cellsOf(lines[i]);
227
+ if (!columns) {
228
+ const names = cells.map((cell) => cell.replace(/[*`]/g, '').toLowerCase());
229
+ if (!(names.includes('principle') && names.includes('result'))) continue;
230
+ if (!(lines[i + 1] && cellsOf(lines[i + 1]).every((cell) => /^:?-+:?$/.test(cell)))) return { heading: start + 1, rows, unparseable: i + 1 };
231
+ columns = { principle: names.indexOf('principle'), result: names.indexOf('result') };
232
+ i += 1;
233
+ continue;
234
+ }
235
+ rows.push({ id: principleId(cells[columns.principle] || ''), result: (cells[columns.result] || '').replace(/[*`]/g, '').trim().toUpperCase(), line: i + 1 });
236
+ }
237
+ return { heading: start + 1, rows, unparseable: null };
238
+ }
239
+
240
+ /** One finding per principle that is not recorded as passing: a MUST marked FAIL or without a
241
+ * PASS/FAIL row refuses exit; a SHOULD marked FAIL is advisory. The tier is the constitution's,
242
+ * whatever the row says, so a plan cannot downgrade a MUST. */
243
+ function constitutionFindings({ planText, planPath, principles } ) {
244
+ const { heading, rows, unparseable } = constitutionRecord(planText);
245
+ if (unparseable) {
246
+ return [{ rule: 'constitution-unparseable', severity: 'refuses-exit', path: planPath, line: unparseable,
247
+ message: `no parseable Constitution Check: the table header has no |---| separator row under it, so no principle is recorded; ${UNBLOCK}` }];
248
+ }
249
+ const findings = [];
250
+ for (const principle of principles) {
251
+ const recorded = rows.filter((r) => r.id === principle.id && (r.result === 'PASS' || r.result === 'FAIL'));
252
+ const failed = recorded.find((r) => r.result === 'FAIL');
253
+ const tier = `${principle.id} (${principle.tier})`;
254
+ if (principle.tier === 'MUST' && failed) {
255
+ findings.push({ rule: 'constitution-must-fail', severity: 'refuses-exit', path: planPath, line: failed.line, id: principle.id,
256
+ message: `${tier} is marked FAIL in the Constitution Check: ${UNBLOCK}` });
257
+ } else if (principle.tier === 'MUST' && !recorded.length) {
258
+ findings.push({ rule: 'constitution-must-missing', severity: 'refuses-exit', path: planPath, line: heading || 1, id: principle.id,
259
+ message: `${tier} has no PASS/FAIL row in the Constitution Check (${principle.source}): add \`| ${principle.id} | MUST | PASS | <how> |\` once the plan complies, or ${UNBLOCK}` });
260
+ } else if (failed) {
261
+ findings.push({ rule: 'constitution-should-fail', severity: 'advisory', path: planPath, line: failed.line, id: principle.id,
262
+ message: `${tier} is marked FAIL in the Constitution Check: advisory, recorded and not blocking` });
263
+ }
264
+ }
265
+ return findings;
266
+ }
267
+
268
+ /** The checkout a plan belongs to: the nearest directory above it holding `.git`, else `fallback`. */
269
+ function checkoutOf(file , fallback ) {
270
+ for (let dir = path.dirname(file); ; dir = path.dirname(dir)) {
271
+ if (fs.existsSync(path.join(dir, '.git'))) return dir;
272
+ if (path.dirname(dir) === dir) return fallback;
273
+ }
274
+ }
275
+
276
+ /** The constitution findings, or one refusal when the constitution itself cannot be read. */
277
+ function constitutionCheck({ planText, planPath, checkoutRoot } ) {
278
+ const { principles, downgrades, error } = loadConstitution({ checkoutRoot });
279
+ if (error) return [{ rule: 'constitution-unreadable', severity: 'refuses-exit', path: planPath, line: 1, message: `${error}: nothing can be checked, so the plan is refused` }];
280
+ const notes = downgrades.map((d) => ({ rule: 'constitution-downgrade', severity: 'advisory' , path: d.source, line: d.line, id: d.id,
281
+ message: `${d.id} is MUST in the base constitution and SHOULD in ${d.source}${d.version ? ` ${d.version}` : ''}: the overlay downgrades it, recorded and not blocking` }));
282
+ return [...notes, ...constitutionFindings({ planText, planPath, principles })];
283
+ }
284
+
285
+ /** Every content finding for one plan file. Paths are shown relative to `cwd`. */
286
+ function planFindings({ planAbs, text, displayPath, cwd } ) {
287
+ const findings = placeholderFindings(text, displayPath);
288
+ const requirement = requirementBeside(planAbs);
289
+ if (requirement) {
290
+ let requirementText = null;
291
+ try { requirementText = fs.readFileSync(requirement, 'utf8'); } catch { /* unreadable: no coverage claim either way */ }
292
+ if (requirementText !== null) findings.push(...coverageFindings(text, displayPath, requirementText, path.relative(cwd, requirement)));
293
+ }
294
+ findings.push(...constitutionCheck({ planText: text, planPath: displayPath, checkoutRoot: checkoutOf(planAbs, cwd) }));
295
+ return findings;
296
+ }
297
+
298
+ /** The planning stage's exit (row 134): the feature's plan.md, found under the first root that has
299
+ * it, checked against both constitution tiers of that checkout. `refusals` refuse the exit;
300
+ * `advisories` are printed and recorded nowhere else. A run with no feature, or a feature with no
301
+ * plan, is refused: the planning stage exists to produce that plan. */
302
+ function planStageExit({ roots, slug } ) {
303
+ // plan.md, else planning/plan.md under the structured layout (the roadmap facts read the same two).
304
+ const feature = slug ? path.join('agent-docs', 'doflow', slug) : null;
305
+ const found = feature ? roots.flatMap((r) => ['plan.md', path.join('planning', 'plan.md')].map((rel) => ({ r, rel: path.join(feature, rel) })))
306
+ .find(({ r, rel }) => fs.existsSync(path.join(r, rel))) : undefined;
307
+ const relative = found ? found.rel : feature ? path.join(feature, 'plan.md') : null;
308
+ const root = found?.r;
309
+ if (!relative || !root) {
310
+ const where = relative ? `${relative} (or planning/plan.md) under ${roots.join(', ')}` : 'a plan: the run names no feature';
311
+ return { refusals: [{ rule: 'plan-missing', severity: 'refuses-exit', path: relative || 'plan.md', line: 1, message: `no plan to check (looked for ${where}); write plan.md before completing the planning stage` }] , advisories: [] };
312
+ }
313
+ let planText ;
314
+ try { planText = fs.readFileSync(path.join(root, relative), 'utf8'); } catch (error ) {
315
+ return { refusals: [{ rule: 'plan-missing', severity: 'refuses-exit', path: relative, line: 1, message: `${relative} cannot be read (${error.code || error.message})` }] , advisories: [] };
316
+ }
317
+ const findings = constitutionCheck({ planText, planPath: relative.split(path.sep).join('/'), checkoutRoot: root });
318
+ return { refusals: findings.filter((f) => f.severity === 'refuses-exit'), advisories: findings.filter((f) => f.severity === 'advisory') };
319
+ }
320
+
321
+ module.exports = {
322
+ placeholderFindings, coverageFindings, requirementIds, planFindings, proseLines,
323
+ parsePrinciples, loadConstitution, constitutionFindings, planStageExit, CONSTITUTION_BASE, constitutionBaseFile,
324
+ };
@@ -0,0 +1,118 @@
1
+ 'use strict';
2
+
3
+ /**
4
+ * `doflow roadmap --action init-policy --commit`: a person-run command, kept out of src/runtime/roadmap/**
5
+ * so the autopilot loop's git reach (G53, G54) does not widen. It adds one commit to the local develop that
6
+ * touches only core/registry/gates.json, built with git plumbing in a temporary index so the index, the
7
+ * working tree and the checked-out branch stay as they are. The bytes are the reviewed working copy when
8
+ * there is one, else the packaged policy; invalid bytes are refused. A develop checked out in any worktree
9
+ * is not moved (that worktree's index would go stale): the commands to run there are printed instead. The
10
+ * ref moves with compare-and-swap. Nothing is staged, pushed, tagged or published, and the loop still reads
11
+ * the policy only from develop's committed head.
12
+ */
13
+
14
+ const fs = require('node:fs');
15
+ const crypto = require('node:crypto');
16
+ const os = require('node:os');
17
+ const path = require('node:path');
18
+ const { execFileSync: defaultExecFileSync } = require('node:child_process');
19
+ const { loadPolicy } = require('./roadmap/gates.js');
20
+ const { resolveMainRoot } = require('./roadmap/loop.js');
21
+
22
+ const REL = 'core/registry/gates.json';
23
+ const MESSAGE = 'chore(roadmap): add the autopilot gate policy';
24
+ const shellQuote = (text ) => ["'", text.split("'").join("'\\''"), "'"].join('');
25
+
26
+ /** Every git command addresses the named checkout; inherited routing variables are dropped. */
27
+ function optionsFor(root , env ) {
28
+ const environment = { ...env };
29
+ for (const key of Object.keys(environment)) if (/^GIT_(?:DIR|WORK_TREE|COMMON_DIR|INDEX_FILE|OBJECT_DIRECTORY|ALTERNATE_OBJECT_DIRECTORIES|CONFIG_COUNT|CONFIG_KEY_\d+|CONFIG_VALUE_\d+)$/.test(key)) delete environment[key];
30
+ return { cwd: root, encoding: 'utf8', env: environment, stdio: ['ignore', 'pipe', 'pipe'], maxBuffer: 64 * 1024 * 1024 };
31
+ }
32
+
33
+ /** The path of the worktree that has `ref` checked out, if any. */
34
+ function checkedOutAt(execFileSync , root , opts , ref ) {
35
+ const out = String(execFileSync('git', ['-C', root, 'worktree', 'list', '--porcelain', '-z'], opts));
36
+ for (const block of out.split('\0\0').filter(Boolean)) {
37
+ const fields = block.split('\0');
38
+ const listed = fields.find((s) => s.startsWith('worktree '))?.slice(9);
39
+ if (listed && fields.find((s) => s.startsWith('branch '))?.slice(7) === ref) return path.resolve(listed);
40
+ }
41
+ return undefined;
42
+ }
43
+
44
+ function commitPolicyCommand(options ) {
45
+ const { json = false, fsImpl = fs } = options;
46
+ const root = options.root || resolveMainRoot(options.cwd || process.cwd());
47
+ const execFileSync = options.execFileSync || defaultExecFileSync;
48
+ const opts = optionsFor(root, options.env || process.env);
49
+ const target = path.join(root, REL);
50
+ const packaged = path.join(options.repoRoot, REL);
51
+ const reason = (error ) => String(error?.stderr || error?.message || error).trim();
52
+ const fail = (message ) => {
53
+ if (json) console.log(JSON.stringify({ schema: 1, action: 'init-policy', error: 'not-committed', detail: message }));
54
+ else console.error(`doflow roadmap: ${message}`);
55
+ process.exitCode = 1;
56
+ return 1;
57
+ };
58
+
59
+ let old ;
60
+ try { old = String(execFileSync('git', ['-C', root, 'rev-parse', '--verify', '-q', 'refs/heads/develop'], opts)).trim(); }
61
+ catch { return fail('no local develop branch (or not a git repository); create develop first, the loop reads the policy only from its head'); }
62
+ let present = true;
63
+ try { execFileSync('git', ['-C', root, 'cat-file', '-e', `${old}:${REL}`], opts); } catch { present = false; }
64
+ if (present) return fail(`develop already has ${REL}; nothing changed`);
65
+
66
+ let workingCopy = null;
67
+ try { workingCopy = fsImpl.readFileSync(target); }
68
+ catch (error ) { if (error.code !== 'ENOENT') return fail(`cannot read ${target}: ${error.message}`); }
69
+ const bytes = workingCopy ?? fsImpl.readFileSync(packaged);
70
+ const verdict = loadPolicy(bytes);
71
+ if (!verdict.ok) return fail(`${workingCopy ? target : 'the packaged policy'} is not a valid policy (${verdict.reason}); nothing changed`);
72
+
73
+ const elsewhere = checkedOutAt(execFileSync, root, opts, 'refs/heads/develop');
74
+ if (elsewhere) {
75
+ const destination = path.join(elsewhere, REL);
76
+ const source = workingCopy ? target : packaged;
77
+ const commands = [`mkdir -p ${shellQuote(path.dirname(destination))}`];
78
+ if (path.resolve(source) !== path.resolve(destination)) commands.push(`cp ${shellQuote(source)} ${shellQuote(destination)}`);
79
+ commands.push(`git -C ${shellQuote(elsewhere)} add -- ${REL}`, `git -C ${shellQuote(elsewhere)} commit -m ${shellQuote(MESSAGE)} -- ${REL}`);
80
+ return fail(`develop is checked out at ${elsewhere}; moving its branch would leave that worktree's index stale, so nothing was changed. Run instead:\n ${commands.join('\n ')}`);
81
+ }
82
+
83
+ // git itself creates and locks this temporary index (read-tree, update-index, write-tree); this module writes no file.
84
+ const scratch = path.join(os.tmpdir(), `doflow-policy-${crypto.randomBytes(8).toString('hex')}.index`);
85
+ const indexed = { ...opts, env: { ...opts.env, GIT_INDEX_FILE: scratch } };
86
+ let commit ;
87
+ try {
88
+ const blob = String(execFileSync('git', ['-C', root, 'hash-object', '-w', '--stdin'], { ...opts, stdio: ['pipe', 'pipe', 'pipe'], input: bytes })).trim();
89
+ execFileSync('git', ['-C', root, 'read-tree', old], indexed);
90
+ execFileSync('git', ['-C', root, 'update-index', '--add', '--cacheinfo', `100644,${blob},${REL}`], indexed);
91
+ const tree = String(execFileSync('git', ['-C', root, 'write-tree'], indexed)).trim();
92
+ commit = String(execFileSync('git', ['-C', root, 'commit-tree', tree, '-p', old, '-m', MESSAGE, '--no-gpg-sign'], opts)).trim();
93
+ } catch (error ) {
94
+ return fail(`cannot build the commit: ${reason(error)}; nothing changed`);
95
+ } finally {
96
+ for (const leftover of [scratch, `${scratch}.lock`]) fsImpl.rmSync(leftover, { force: true });
97
+ }
98
+ try { execFileSync('git', ['-C', root, 'update-ref', 'refs/heads/develop', commit, old], opts); }
99
+ catch (error ) { return fail(`develop moved or could not be updated (${reason(error)}); nothing changed, run the command again`); }
100
+
101
+ // The working copy is now tracked on develop: an identical untracked copy would collide with a later merge of develop.
102
+ let copy = 'none';
103
+ let copyNote = '';
104
+ if (workingCopy) {
105
+ let tracked = false;
106
+ try { tracked = String(execFileSync('git', ['-C', root, 'ls-files', '--', REL], opts)).trim() !== ''; } catch { /* untracked */ }
107
+ let now = null;
108
+ try { now = fsImpl.readFileSync(target); } catch { /* gone already */ }
109
+ if (tracked) { copy = 'kept'; copyNote = `kept ${target}: it is tracked in the checked-out branch`; }
110
+ else if (now && Buffer.from(now).equals(Buffer.from(bytes))) { fsImpl.unlinkSync(target); copy = 'removed'; copyNote = `removed ${target} (identical to the committed bytes, now tracked on develop)`; }
111
+ else if (now) { copy = 'kept'; copyNote = `kept ${target}: it differs from the committed bytes`; }
112
+ }
113
+ if (json) console.log(JSON.stringify({ schema: 1, action: 'init-policy', committed: true, commit, previous: old, file: REL, root, workingCopy: copy }));
114
+ else console.log(`develop ${old} -> ${commit} (${REL} only)${copyNote ? `\n${copyNote}` : ''}\nNothing was pushed; that is yours.`);
115
+ return 0;
116
+ }
117
+
118
+ module.exports = { commitPolicyCommand };
@@ -0,0 +1,96 @@
1
+ 'use strict';
2
+
3
+ const fs = require('node:fs');
4
+ const path = require('node:path');
5
+ const { resolveRolloutProfile, isCapabilityActive } = require('./resolve.js');
6
+ const { checkRollbackState, tripRollback, resetRollback } = require('./rollback.js');
7
+ const { REPO_ROOT } = require('../../helper/repo-root.js');
8
+
9
+
10
+
11
+
12
+
13
+
14
+
15
+
16
+
17
+
18
+
19
+ function buildProfilesDoctor(options
20
+
21
+
22
+
23
+
24
+ ) {
25
+ const fsImpl = options?.fsImpl || fs;
26
+ const repoRoot = options?.repoRoot || REPO_ROOT;
27
+
28
+ const profile = resolveRolloutProfile(options);
29
+ const rollback = checkRollbackState(options);
30
+
31
+ let harnessCount = 0;
32
+ let verifiedFacts = true;
33
+ let nativeTelemetry = true;
34
+
35
+ try {
36
+ const harnessesPath = path.join(repoRoot, 'core', 'registry', 'harnesses.json');
37
+ if (fsImpl.existsSync(harnessesPath)) {
38
+ const data = JSON.parse(fsImpl.readFileSync(harnessesPath, 'utf8'));
39
+ if (Array.isArray(data.harnesses)) {
40
+ harnessCount = data.harnesses.length;
41
+ for (const h of data.harnesses) {
42
+ if (!h.contextProfile || typeof h.contextProfile.capacityTokens?.value !== 'number') {
43
+ verifiedFacts = false;
44
+ }
45
+ if (!h.nativeTelemetry || !Array.isArray(h.nativeTelemetry.signals)) {
46
+ nativeTelemetry = false;
47
+ }
48
+ }
49
+ }
50
+ }
51
+ } catch {
52
+ verifiedFacts = false;
53
+ nativeTelemetry = false;
54
+ }
55
+
56
+ return {
57
+ profile,
58
+ rollback,
59
+ registryVerified: {
60
+ harnessCount,
61
+ verifiedFacts,
62
+ nativeTelemetry,
63
+ },
64
+ };
65
+ }
66
+
67
+ function printProfilesDoctor(report ) {
68
+ console.log('\n[Rollout Profile & Governance]');
69
+ const p = report.profile;
70
+ const r = report.rollback;
71
+
72
+ console.log(` profile ${p.name.padEnd(12)} (${p.origin.source}: ${p.origin.detail || 'default'})`);
73
+ if (r.active) {
74
+ console.log(` rollback ACTIVE (${r.reason}, origin: ${r.origin}) -> forced baseline`);
75
+ } else {
76
+ console.log(' rollback inactive (normal operation)');
77
+ }
78
+
79
+ const caps = p.capabilities;
80
+ console.log(` capabilities retrieval: ${caps.retrieval}, advisor: ${caps.advisor}, graph: ${caps.graph}, verification: ${caps.verification}`);
81
+ console.log(` canary tag ${caps.telemetryCanaryTag ? 'yes' : 'no'} (sample rate: ${(p.canarySampleRate * 100).toFixed(0)}%)`);
82
+
83
+ const reg = report.registryVerified;
84
+ const regStatus = reg.verifiedFacts && reg.nativeTelemetry ? 'PASS' : 'UNVERIFIED';
85
+ console.log(` harness registry ${reg.harnessCount} harnesses checked (${regStatus})`);
86
+ }
87
+
88
+ module.exports = {
89
+ buildProfilesDoctor,
90
+ printProfilesDoctor,
91
+ resolveRolloutProfile,
92
+ checkRollbackState,
93
+ isCapabilityActive,
94
+ tripRollback,
95
+ resetRollback,
96
+ };