@khoavu882/doflow 2.0.0-beta.5 → 2.0.1

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (494) hide show
  1. package/README.md +16 -16
  2. package/bin/doflow.js +22 -12
  3. package/core/.antigravity-plugin/plugin.json +1 -2
  4. package/core/.claude-plugin/plugin.json +1 -1
  5. package/core/.codex-plugin/plugin.json +1 -1
  6. package/core/.plugin/plugin.json +1 -1
  7. package/core/harnesses/claude/hooks/lib.sh +43 -24
  8. package/core/harnesses/claude/hooks/mcp-tool-guard.sh +4 -1
  9. package/core/harnesses/claude/hooks/permission-audit.sh +3 -0
  10. package/core/harnesses/claude/hooks/post-compact.sh +35 -32
  11. package/core/harnesses/claude/hooks/post-edit-lint.sh +2 -0
  12. package/core/harnesses/claude/hooks/post-shell-observe.sh +48 -0
  13. package/core/harnesses/claude/hooks/post-tool-failure.sh +3 -0
  14. package/core/harnesses/claude/hooks/pre-compact.sh +23 -27
  15. package/core/harnesses/claude/hooks/pre-implement-gate.sh +4 -1
  16. package/core/harnesses/claude/hooks/session-end.sh +23 -10
  17. package/core/harnesses/claude/hooks/skill-config-audit.sh +3 -0
  18. package/core/harnesses/claude/settings/settings.json +26 -9
  19. package/core/harnesses/claude/statusline/doflow-statusline.sh +1 -0
  20. package/core/harnesses/codex/agents/core-implementer.toml +1 -0
  21. package/core/harnesses/codex/agents/delivery-lead.toml +10 -0
  22. package/core/harnesses/codex/agents/quality-guardian.toml +1 -1
  23. package/core/harnesses/codex/agents/research-writer.toml +1 -1
  24. package/core/harnesses/codex/agents/reviewer.toml +10 -0
  25. package/core/harnesses/codex/agents/spec-analyst.toml +1 -1
  26. package/core/harnesses/codex/agents/system-architect.toml +1 -1
  27. package/core/harnesses/codex/hooks/hooks.json +0 -10
  28. package/core/harnesses/codex/hooks/lib.sh +44 -25
  29. package/core/harnesses/codex/hooks/mcp-tool-guard.sh +4 -1
  30. package/core/harnesses/codex/hooks/post-edit-lint.impl.sh +3 -1
  31. package/core/harnesses/codex/hooks/pre-compact.impl.sh +29 -26
  32. package/core/harnesses/codex/hooks/pre-implement-gate.sh +4 -1
  33. package/core/harnesses/codex/hooks/session-end.impl.sh +23 -10
  34. package/core/harnesses/codex/hooks/subagent-audit.sh +1 -0
  35. package/core/harnesses/copilot/hooks/doflow-lib.sh +94 -0
  36. package/core/harnesses/copilot/hooks/doflow-mcp-tool-guard.sh +9 -0
  37. package/core/harnesses/copilot/hooks/doflow-pre-implement-gate.sh +9 -0
  38. package/core/harnesses/copilot/hooks/doflow-session-start.sh +9 -0
  39. package/core/harnesses/copilot/hooks/doflow-stop-check.sh +9 -0
  40. package/core/harnesses/copilot/hooks/doflow-subagent-start.sh +9 -0
  41. package/core/harnesses/copilot/hooks/doflow-subagent-stop.sh +9 -0
  42. package/core/harnesses/copilot/hooks/doflow.json +51 -0
  43. package/core/harnesses/kiro/agents/doflow.json +1 -11
  44. package/core/harnesses/kiro/hooks/doflow.json +0 -10
  45. package/core/harnesses/kiro/hooks/lib.sh +26 -6
  46. package/core/harnesses/kiro/hooks/mcp-tool-guard.sh +8 -3
  47. package/core/harnesses/kiro/hooks/pre-implement-gate.sh +8 -3
  48. package/core/harnesses/kiro/hooks/session-start.sh +1 -0
  49. package/core/harnesses/kiro/hooks/stop-check.sh +1 -0
  50. package/core/harnesses/pi/extensions/doflow-guard.js +11 -2
  51. package/core/harnesses/shared/hooks/ENVELOPE_MIGRATION.md +1 -2
  52. package/core/harnesses/shared/hooks/adapters/antigravity.js +1 -1
  53. package/core/harnesses/shared/hooks/bridge/bridge.sh +126 -23
  54. package/core/harnesses/shared/hooks/bridge/envelope.jq +87 -18
  55. package/core/harnesses/shared/hooks/bridge/observe-model.sh +75 -0
  56. package/core/harnesses/shared/hooks/bridge/respond.sh +16 -2
  57. package/core/harnesses/shared/hooks/policies/capture-failure.sh +49 -16
  58. package/core/harnesses/shared/hooks/policies/compact-text.sh +46 -0
  59. package/core/harnesses/shared/hooks/policies/contract.sh +3 -0
  60. package/core/harnesses/shared/hooks/policies/deny-json.sh +20 -7
  61. package/core/harnesses/shared/hooks/policies/emission-rules.sh +37 -0
  62. package/core/harnesses/shared/hooks/policies/emission.jq +209 -0
  63. package/core/harnesses/shared/hooks/policies/emission.sh +383 -0
  64. package/core/harnesses/shared/hooks/policies/identity.sh +177 -0
  65. package/core/harnesses/shared/hooks/policies/lib.sh +63 -40
  66. package/core/harnesses/shared/hooks/policies/mcp-policy.conf +1 -1
  67. package/core/harnesses/shared/hooks/policies/mcp-tool-guard.sh +7 -8
  68. package/core/harnesses/shared/hooks/policies/pre-implementation-gate.sh +132 -57
  69. package/core/harnesses/shared/hooks/policies/session-context.sh +30 -1
  70. package/core/harnesses/shared/hooks/policies/stop-check.sh +27 -15
  71. package/core/harnesses/shared/hooks/policies/subagent-audit.sh +6 -3
  72. package/core/harnesses/shared/hooks/policies/summary-store.sh +347 -0
  73. package/core/harnesses/shared/hooks/policies/user-prompt-submit.sh +60 -155
  74. package/core/harnesses/shared/hooks/stream-hook-runner.js +58 -20
  75. package/core/harnesses/shared/locator/doflow-run +2 -3
  76. package/core/registry/advice.json +3 -3
  77. package/core/registry/assets.json +55 -82
  78. package/core/registry/capabilities.json +12 -0
  79. package/core/registry/contracts.json +58 -31
  80. package/core/registry/contribution-points.json +35 -0
  81. package/core/registry/gates.json +32 -0
  82. package/core/registry/guidance-caps.json +40 -0
  83. package/core/registry/harnesses.json +1445 -366
  84. package/core/registry/intake.json +53 -0
  85. package/core/registry/lifecycle.json +599 -996
  86. package/core/registry/mcp.json +5 -1
  87. package/core/registry/models.json +7 -1
  88. package/core/registry/package-templates/README.md +19 -0
  89. package/core/registry/package-templates/agent/files/agent.md +9 -0
  90. package/core/registry/package-templates/agent/template.json +4 -0
  91. package/core/registry/package-templates/capability-provider/files/provider.json +9 -0
  92. package/core/registry/package-templates/capability-provider/template.json +11 -0
  93. package/core/registry/package-templates/debate-preset/files/preset.json +26 -0
  94. package/core/registry/package-templates/debate-preset/template.json +4 -0
  95. package/core/registry/package-templates/intake-category/files/category.json +8 -0
  96. package/core/registry/package-templates/intake-category/template.json +4 -0
  97. package/core/registry/package-templates/review-preset/files/preset.json +30 -0
  98. package/core/registry/package-templates/review-preset/template.json +4 -0
  99. package/core/registry/package-templates/skill/files/SKILL.md +8 -0
  100. package/core/registry/package-templates/skill/template.json +4 -0
  101. package/core/registry/package-templates/worker/files/worker.json +92 -0
  102. package/core/registry/package-templates/worker/template.json +11 -0
  103. package/core/registry/packages/doflow/doflow-package.json +15 -0
  104. package/core/registry/packages/doflow/presets/debate-3.json +26 -0
  105. package/core/registry/protocols.json +61 -0
  106. package/core/registry/routes.json +17 -0
  107. package/core/registry/rules.json +431 -0
  108. package/core/registry/settings.json +272 -0
  109. package/core/registry/storage.json +687 -31
  110. package/core/registry/telemetry.json +236 -0
  111. package/core/registry/transcripts.json +142 -0
  112. package/core/registry/verification.json +76 -6
  113. package/core/registry/workflows.json +55 -0
  114. package/core/shared/agent-specs/core-implementer.md +3 -0
  115. package/core/shared/agent-specs/delivery-lead.md +68 -0
  116. package/core/shared/agent-specs/quality-guardian.md +5 -1
  117. package/core/shared/agent-specs/research-writer.md +10 -3
  118. package/core/shared/agent-specs/reviewer.md +53 -0
  119. package/core/shared/agent-specs/spec-analyst.md +5 -6
  120. package/core/shared/agent-specs/system-architect.md +5 -1
  121. package/core/shared/guidance/DOFLOW_CORE.md +1 -5
  122. package/core/shared/guidance/modes/MODE_DeepResearch.md +1 -1
  123. package/core/shared/guidance/modes/MODE_Orchestration.md +4 -3
  124. package/core/shared/guidance/modes/MODE_Task_Management.md +14 -14
  125. package/core/shared/guidance/pointers/codex.md +1 -4
  126. package/core/shared/guidance/references/ARTIFACT_FORMAT.md +30 -16
  127. package/core/shared/guidance/references/ARTIFACT_VOICE.md +3 -2
  128. package/core/shared/guidance/references/CONSTITUTION_BASE.md +17 -15
  129. package/core/shared/guidance/references/DIAGRAM_GUIDE.md +1 -1
  130. package/core/shared/guidance/references/DOFLOW_CHAIN.md +17 -19
  131. package/core/shared/guidance/references/EVIDENCE_LEDGER.md +7 -8
  132. package/core/shared/guidance/references/MODEL_SELECTION.md +5 -3
  133. package/core/shared/guidance/references/ORCHESTRATION.md +3 -2
  134. package/core/shared/guidance/references/WORKFLOW_HANDOFF.md +19 -1
  135. package/core/shared/guidance/rules/RULES.md +45 -0
  136. package/core/shared/scripts/doflow/bash/do-args.sh +37 -0
  137. package/core/shared/scripts/doflow/bash/do-exec-paths.sh +4 -0
  138. package/core/shared/scripts/doflow/bash/do-git-state.sh +15 -4
  139. package/core/shared/scripts/doflow/bash/do-parallel-check.sh +4 -0
  140. package/core/shared/scripts/doflow/bash/do-paths.sh +40 -2
  141. package/core/shared/scripts/doflow/bash/do-prereqs.sh +2 -1
  142. package/core/shared/scripts/doflow/bash/do-review-package.sh +4 -0
  143. package/core/shared/scripts/doflow/bash/do-task-brief.sh +58 -16
  144. package/core/shared/scripts/doflow/bash/render-audit.sh +26 -2
  145. package/core/shared/scripts/doflow/bash/render-diagrams.sh +1 -0
  146. package/core/shared/scripts/doflow/bash/render-puml.sh +2 -1
  147. package/core/shared/scripts/doflow/bash/validate-artifacts.sh +49 -5
  148. package/core/shared/scripts/doflow/bin/doflow-run +152 -34
  149. package/core/shared/skills/do/SKILL.md +14 -12
  150. package/core/shared/skills/do/references/advice_calls.md +26 -0
  151. package/core/shared/skills/do/references/pm_routing.md +1 -2
  152. package/core/shared/skills/do/references/program_mode.md +31 -0
  153. package/core/shared/skills/do-brainstorm/SKILL.md +45 -97
  154. package/core/shared/skills/do-brainstorm/references/handoff_branches.md +36 -0
  155. package/core/shared/skills/do-brainstorm/references/intent_seed.md +21 -0
  156. package/core/shared/skills/do-brainstorm/references/round_log.md +17 -0
  157. package/core/shared/skills/do-code-review/SKILL.md +48 -148
  158. package/core/shared/skills/do-code-review/content-types/markdown.md +24 -2
  159. package/core/shared/skills/do-code-review/references/tools.md +90 -0
  160. package/core/shared/skills/do-code-review/scripts/doc_quality_checker.py +549 -7
  161. package/core/shared/skills/do-design/SKILL.md +23 -20
  162. package/core/shared/skills/do-diagnose/SKILL.md +18 -6
  163. package/core/shared/skills/do-document/SKILL.md +12 -1
  164. package/core/shared/skills/do-document/references/deep_research.md +1 -2
  165. package/core/shared/skills/do-document/references/embedded-research.md +19 -7
  166. package/core/shared/skills/do-document/references/implementation-flow.md +5 -6
  167. package/core/shared/skills/do-execute-plan/SKILL.md +19 -60
  168. package/core/shared/skills/do-execute-plan/references/handoff_record.md +7 -2
  169. package/core/shared/skills/do-execute-plan/references/parallel_dispatch.md +13 -0
  170. package/core/shared/skills/do-execute-plan/references/readiness_gate.md +26 -1
  171. package/core/shared/skills/do-execute-plan/references/run_position.md +16 -2
  172. package/core/shared/skills/do-execute-plan/references/scaffold.md +17 -9
  173. package/core/shared/skills/do-execute-plan/references/state_checkpoint.md +11 -0
  174. package/core/shared/skills/do-execute-plan/references/task_attempts.md +78 -24
  175. package/core/shared/skills/do-flow/SKILL.md +10 -11
  176. package/core/shared/skills/do-flow/references/task_classes.md +5 -5
  177. package/core/shared/skills/do-git/SKILL.md +4 -0
  178. package/core/shared/skills/do-implement/SKILL.md +13 -14
  179. package/core/shared/skills/do-plan/SKILL.md +34 -20
  180. package/core/shared/skills/do-test/SKILL.md +7 -4
  181. package/core/shared/templates/doflow/constitution-template.md +9 -3
  182. package/core/shared/templates/doflow/data-model-template.md +1 -1
  183. package/core/shared/templates/doflow/design-template.md +113 -16
  184. package/core/shared/templates/doflow/plan-template.md +11 -10
  185. package/core/shared/templates/doflow/question-log-template.md +14 -2
  186. package/core/shared/templates/doflow/requirement-template.md +1 -1
  187. package/core/shared/workflows/do-flow-chain.md +2 -0
  188. package/core/worker-evidence/antigravity/checks.json +14 -0
  189. package/core/worker-evidence/codex/2026-10-18-cli-check.json +107 -0
  190. package/core/worker-evidence/codex/2026-10-18-live-run-edit.json +73 -0
  191. package/core/worker-evidence/codex/2026-10-18-live-run-read-only.json +62 -0
  192. package/core/worker-evidence/codex/2026-10-24-cli-check.json +126 -0
  193. package/core/worker-evidence/codex/checks.json +38 -0
  194. package/package.json +10 -6
  195. package/src/adapters/antigravity/index.js +143 -66
  196. package/src/adapters/claude/index.js +46 -5
  197. package/src/adapters/codex/agents.js +25 -15
  198. package/src/adapters/codex/hooks.js +39 -3
  199. package/src/adapters/codex/index.js +61 -13
  200. package/src/adapters/codex/native-projection.js +6 -2
  201. package/src/adapters/copilot/index.js +58 -23
  202. package/src/adapters/copy-tree.js +291 -46
  203. package/src/adapters/guidance-manifest.js +71 -0
  204. package/src/adapters/guidance-pointer.js +19 -0
  205. package/src/adapters/hook-commands.js +6 -10
  206. package/src/adapters/index.js +1 -0
  207. package/src/adapters/kiro/index.js +23 -12
  208. package/src/adapters/opencode/index.js +8 -8
  209. package/src/adapters/pi/hooks.js +2 -1
  210. package/src/adapters/pi/index.js +14 -7
  211. package/src/adapters/resolve-source.js +26 -2
  212. package/src/cli/commands/install.js +2 -1
  213. package/src/cli/commands/reconcile.js +53 -9
  214. package/src/cli/commands/remove.js +2 -2
  215. package/src/cli/commands/rollback.js +6 -3
  216. package/src/cli/commands/self-update.js +18 -9
  217. package/src/cli/commands/status.js +22 -3
  218. package/src/cli/commands/ui.js +99 -0
  219. package/src/cli/commands/update.js +2 -1
  220. package/src/cli/index.js +337 -32
  221. package/src/cli/runtime-commands.js +220 -60
  222. package/src/cli/shared.js +0 -2
  223. package/src/helper/git.js +1 -1
  224. package/src/helper/guardrails.js +1 -1
  225. package/src/helper/marker-merge.js +31 -13
  226. package/src/helper/package-ids.js +37 -0
  227. package/src/helper/semver.js +94 -0
  228. package/src/install/backup.js +105 -15
  229. package/src/install/context.js +1 -1
  230. package/src/install/targets.js +31 -16
  231. package/src/lifecycle/coverage.js +4 -16
  232. package/src/lifecycle/hook-tier.js +160 -0
  233. package/src/lifecycle/index.js +412 -78
  234. package/src/lifecycle/retired-harnesses.js +318 -0
  235. package/src/lifecycle/view.js +35 -15
  236. package/src/registry/index.js +551 -26
  237. package/src/registry/worker-ids.js +45 -0
  238. package/src/release/build-package.js +0 -3
  239. package/src/release/docs-blocks.js +472 -0
  240. package/src/release/preflight.js +425 -0
  241. package/src/release/rehearse.js +401 -0
  242. package/src/release/release-workflow.js +733 -0
  243. package/src/release/sync-plugin-versions.js +43 -7
  244. package/src/runtime/advice/bench-gate.js +25 -0
  245. package/src/runtime/advice/cli.js +59 -16
  246. package/src/runtime/advice/client.js +32 -9
  247. package/src/runtime/advice/config.js +98 -133
  248. package/src/runtime/advice/doctor.js +1 -1
  249. package/src/runtime/advice/elevation.js +97 -0
  250. package/src/runtime/advice/endpoint-guard.js +9 -3
  251. package/src/runtime/advice/mode.js +37 -0
  252. package/src/runtime/advice/record.js +18 -5
  253. package/src/runtime/advice/registry.js +4 -1
  254. package/src/runtime/advice/shadow-config.js +229 -0
  255. package/src/runtime/advice/shadow-dispatcher.js +276 -0
  256. package/src/runtime/brief-rules.js +81 -0
  257. package/src/runtime/brief-tools.js +111 -34
  258. package/src/runtime/candidate.js +20 -11
  259. package/src/runtime/capabilities/executor.js +450 -0
  260. package/src/runtime/capabilities/loopback.js +41 -0
  261. package/src/runtime/capabilities/sanitizer.js +88 -0
  262. package/src/runtime/capability-router.js +135 -3
  263. package/src/runtime/checkouts.js +73 -11
  264. package/src/runtime/claims.js +13 -7
  265. package/src/runtime/cli.js +196 -19
  266. package/src/runtime/config-home.js +42 -0
  267. package/src/runtime/context/arbitrate.js +767 -0
  268. package/src/runtime/context/delivery-store.js +4 -6
  269. package/src/runtime/context/emission-rules.js +118 -0
  270. package/src/runtime/context/identity.js +227 -0
  271. package/src/runtime/context/pointer.js +67 -12
  272. package/src/runtime/context/primary-command.js +117 -0
  273. package/src/runtime/context/primary.js +344 -0
  274. package/src/runtime/context/summary-store.js +655 -0
  275. package/src/runtime/context-pack.js +158 -79
  276. package/src/runtime/decision-register.js +13 -4
  277. package/src/runtime/dispatch/admission.js +392 -0
  278. package/src/runtime/dispatch/attempt-end.js +274 -0
  279. package/src/runtime/dispatch/command.js +628 -0
  280. package/src/runtime/dispatch/controls.js +904 -0
  281. package/src/runtime/dispatch/envelope.js +276 -0
  282. package/src/runtime/dispatch/grants.js +310 -0
  283. package/src/runtime/dispatch/integrate.js +617 -0
  284. package/src/runtime/dispatch/loop.js +1835 -0
  285. package/src/runtime/dispatch/store.js +352 -0
  286. package/src/runtime/dispatch/verify-run.js +201 -0
  287. package/src/runtime/evidence-ledger.js +52 -7
  288. package/src/runtime/failure/capture.js +3 -1
  289. package/src/runtime/failure/cli.js +25 -9
  290. package/src/runtime/failure/home.js +57 -30
  291. package/src/runtime/failure/store.js +7 -2
  292. package/src/runtime/feature-pointer.js +174 -0
  293. package/src/runtime/feature-resolve.js +13 -2
  294. package/src/runtime/fleet/command.js +77 -0
  295. package/src/runtime/fleet/projects.js +178 -0
  296. package/src/runtime/fleet/tree.js +383 -0
  297. package/src/runtime/freshness.js +33 -3
  298. package/src/runtime/git-memo.js +46 -0
  299. package/src/runtime/guidance/ablation.js +427 -0
  300. package/src/runtime/health.js +624 -18
  301. package/src/runtime/history-compactor.js +13 -3
  302. package/src/runtime/implementation-gate.js +281 -26
  303. package/src/runtime/intake/engine.js +677 -0
  304. package/src/runtime/intake/index.js +136 -0
  305. package/src/runtime/intake/manifest.js +140 -0
  306. package/src/runtime/intake/taxonomy.js +206 -0
  307. package/src/runtime/inventory/coverage.js +1 -1
  308. package/src/runtime/inventory/index.js +1 -1
  309. package/src/runtime/inventory/precedence.js +2 -2
  310. package/src/runtime/inventory/siblings.js +6 -4
  311. package/src/runtime/knowledge/code-corpus.js +277 -0
  312. package/src/runtime/knowledge/code-lexical.js +130 -0
  313. package/src/runtime/knowledge/code-retrieval.js +307 -0
  314. package/src/runtime/knowledge/code-validation.js +106 -0
  315. package/src/runtime/knowledge/gp3-gate.js +74 -0
  316. package/src/runtime/knowledge/graph-adapter.js +288 -0
  317. package/src/runtime/knowledge/graph-fallback.js +394 -0
  318. package/src/runtime/knowledge/hybrid.js +136 -8
  319. package/src/runtime/knowledge/retrieval.js +34 -1
  320. package/src/runtime/knowledge/rtk-compress.js +77 -0
  321. package/src/runtime/knowledge/semble-bridge.py +106 -0
  322. package/src/runtime/knowledge/semble-lifecycle.js +114 -0
  323. package/src/runtime/knowledge/semble-provider.js +365 -0
  324. package/src/runtime/lifecycle/cli.js +88 -10
  325. package/src/runtime/lifecycle/event-store.js +8 -6
  326. package/src/runtime/lifecycle/followup.js +38 -7
  327. package/src/runtime/lifecycle/overview.js +26 -2
  328. package/src/runtime/lifecycle/report-store.js +8 -10
  329. package/src/runtime/lifecycle/retention.js +95 -31
  330. package/src/runtime/lifecycle/root.js +9 -1
  331. package/src/runtime/lifecycle/status.js +34 -17
  332. package/src/runtime/lifecycle/store-upkeep.js +56 -7
  333. package/src/runtime/mask.js +134 -7
  334. package/src/runtime/mcp-consultations.js +40 -6
  335. package/src/runtime/model-router.js +79 -7
  336. package/src/runtime/models/catalogue.js +191 -0
  337. package/src/runtime/models/command.js +153 -0
  338. package/src/runtime/off-words.js +12 -0
  339. package/src/runtime/outcome.js +2 -2
  340. package/src/runtime/packages/command.js +1009 -0
  341. package/src/runtime/packages/contributions.js +116 -0
  342. package/src/runtime/packages/digest.js +132 -0
  343. package/src/runtime/packages/fetch.js +182 -0
  344. package/src/runtime/packages/grants.js +192 -0
  345. package/src/runtime/packages/index-file.js +134 -0
  346. package/src/runtime/packages/instruction.js +90 -0
  347. package/src/runtime/packages/manifest.js +331 -0
  348. package/src/runtime/packages/points.js +487 -0
  349. package/src/runtime/packages/programs.js +216 -0
  350. package/src/runtime/packages/scaffold.js +277 -0
  351. package/src/runtime/packages/source.js +90 -0
  352. package/src/runtime/packages/state.js +164 -0
  353. package/src/runtime/packages/store.js +449 -0
  354. package/src/runtime/packages/tar.js +106 -0
  355. package/src/runtime/packages/view.js +406 -0
  356. package/src/runtime/plan-check.js +59 -0
  357. package/src/runtime/plan-content.js +324 -0
  358. package/src/runtime/policy-init.js +118 -0
  359. package/src/runtime/profiles/doctor.js +96 -0
  360. package/src/runtime/profiles/resolve.js +244 -0
  361. package/src/runtime/profiles/rollback.js +254 -0
  362. package/src/runtime/profiles/sampler.js +41 -0
  363. package/src/runtime/readiness-record.js +16 -11
  364. package/src/runtime/readiness.js +46 -5
  365. package/src/runtime/research-request.js +50 -25
  366. package/src/runtime/retrieval-plan.js +10 -30
  367. package/src/runtime/retrieval-record.js +75 -5
  368. package/src/runtime/review/command.js +246 -0
  369. package/src/runtime/review/dominance.js +68 -0
  370. package/src/runtime/review/findings.js +434 -0
  371. package/src/runtime/review/identity.js +255 -0
  372. package/src/runtime/review/protocol-command.js +109 -0
  373. package/src/runtime/review/protocols.js +405 -0
  374. package/src/runtime/review/resolve-protocol.js +302 -0
  375. package/src/runtime/review/start.js +530 -0
  376. package/src/runtime/roadmap/attendance.js +137 -0
  377. package/src/runtime/roadmap/facts.js +479 -0
  378. package/src/runtime/roadmap/gates.js +273 -0
  379. package/src/runtime/roadmap/loop.js +1719 -0
  380. package/src/runtime/roadmap/merge.js +390 -0
  381. package/src/runtime/roadmap/rows.js +1122 -0
  382. package/src/runtime/roadmap/seed.js +1063 -0
  383. package/src/runtime/roadmap/worktree-cleanup.js +147 -0
  384. package/src/runtime/rules-report.js +336 -0
  385. package/src/runtime/scaffold/artifacts.js +60 -9
  386. package/src/runtime/scaffold/generate.js +21 -9
  387. package/src/runtime/settings/autopilot.js +106 -0
  388. package/src/runtime/settings/cli.js +280 -0
  389. package/src/runtime/settings/config-write.js +314 -0
  390. package/src/runtime/settings/files.js +271 -0
  391. package/src/runtime/settings/legacy.js +154 -0
  392. package/src/runtime/settings/lexical.js +56 -0
  393. package/src/runtime/settings/prepared-run.js +269 -0
  394. package/src/runtime/settings/project-layers.js +118 -0
  395. package/src/runtime/settings/refs.js +288 -0
  396. package/src/runtime/settings/registry.js +553 -0
  397. package/src/runtime/settings/resolve.js +713 -0
  398. package/src/runtime/settings/shared.js +37 -0
  399. package/src/runtime/settings/worker-billing.js +107 -0
  400. package/src/runtime/settings/write.js +269 -0
  401. package/src/runtime/slot-command.js +78 -0
  402. package/src/runtime/slots.js +671 -0
  403. package/src/runtime/source-version.js +1 -0
  404. package/src/runtime/state-root.js +217 -0
  405. package/src/runtime/storage/cli.js +12 -5
  406. package/src/runtime/storage/engine.js +9 -2
  407. package/src/runtime/storage/registry.js +14 -1
  408. package/src/runtime/storage/roots.js +66 -16
  409. package/src/runtime/storage/rules.js +82 -10
  410. package/src/runtime/storage/upkeep.js +10 -2
  411. package/src/runtime/storage/work-status.js +245 -26
  412. package/src/runtime/task-attempts.js +589 -69
  413. package/src/runtime/task-classifier.js +85 -14
  414. package/src/runtime/task-graph.js +373 -0
  415. package/src/runtime/task-run.js +778 -0
  416. package/src/runtime/task-scope.js +176 -55
  417. package/src/runtime/task-sources.js +147 -0
  418. package/src/runtime/task-state.js +373 -64
  419. package/src/runtime/team/admission.js +301 -0
  420. package/src/runtime/team/envelope.js +324 -0
  421. package/src/runtime/team/review-guard.js +156 -0
  422. package/src/runtime/trace/analyze.js +427 -0
  423. package/src/runtime/trace/baseline.js +770 -0
  424. package/src/runtime/trace/ledger.js +63 -140
  425. package/src/runtime/trace/otlp-export.js +568 -0
  426. package/src/runtime/trace/otlp-map.js +481 -0
  427. package/src/runtime/trace/spans.js +745 -0
  428. package/src/runtime/trace/telemetry.js +225 -0
  429. package/src/runtime/trace/views.js +1 -0
  430. package/src/runtime/transcripts/command.js +98 -0
  431. package/src/runtime/transcripts/cursor.js +326 -0
  432. package/src/runtime/transcripts/read.js +126 -0
  433. package/src/runtime/transcripts/readers/claude-jsonl.js +74 -0
  434. package/src/runtime/transcripts/readers/codex-rollout.js +70 -0
  435. package/src/runtime/transcripts/readers/copilot-events.js +90 -0
  436. package/src/runtime/transcripts/readers/kiro-jsonl.js +77 -0
  437. package/src/runtime/transcripts/readers/pi-jsonl.js +59 -0
  438. package/src/runtime/transcripts/registry.js +161 -0
  439. package/src/runtime/transcripts/stats.js +161 -0
  440. package/src/runtime/verb-view.js +267 -0
  441. package/src/runtime/verification/check-key.js +628 -0
  442. package/src/runtime/verification/contract-runner.js +546 -11
  443. package/src/runtime/verification/engine.js +499 -54
  444. package/src/runtime/verification/impact.js +617 -0
  445. package/src/runtime/verification/inflight.js +205 -0
  446. package/src/runtime/verification/registry.js +176 -0
  447. package/src/runtime/verification/reuse.js +184 -0
  448. package/src/runtime/verification/telemetry-emit.js +254 -0
  449. package/src/runtime/verification/test-selection.js +67 -7
  450. package/src/runtime/worker/active.js +90 -0
  451. package/src/runtime/worker/cancel.js +222 -0
  452. package/src/runtime/worker/catalogue.js +122 -0
  453. package/src/runtime/worker/command.js +677 -0
  454. package/src/runtime/worker/evidence.js +288 -0
  455. package/src/runtime/worker/launch.js +256 -0
  456. package/src/runtime/worker/models.js +137 -0
  457. package/src/runtime/worker/parsers.js +218 -0
  458. package/src/runtime/worker/probes/index.js +706 -0
  459. package/src/runtime/worker/process-tree.js +415 -0
  460. package/src/runtime/worker/quota.js +43 -0
  461. package/src/runtime/worker/readiness.js +713 -0
  462. package/src/runtime/worker/run-store.js +166 -0
  463. package/src/runtime/worker/supervisor.js +541 -0
  464. package/src/runtime/worker/worktree-check.js +252 -0
  465. package/src/runtime/workflow-engine.js +5 -1
  466. package/src/runtime/workflow-orchestrator.js +610 -67
  467. package/src/runtime/worktree.js +149 -22
  468. package/src/state/index.js +1 -1
  469. package/src/state/lockfile.js +64 -10
  470. package/src/state/run-lock.js +1 -1
  471. package/types/node-commonjs.d.ts +106 -7
  472. package/core/harnesses/claude/hooks/pre-bash-guard.sh +0 -10
  473. package/core/harnesses/codex/hooks/pre-bash-guard.sh +0 -10
  474. package/core/harnesses/gemini/hooks/hooks.json +0 -77
  475. package/core/harnesses/gemini/hooks/lib.sh +0 -302
  476. package/core/harnesses/gemini/hooks/mcp-tool-guard.sh +0 -10
  477. package/core/harnesses/gemini/hooks/post-edit-lint.sh +0 -39
  478. package/core/harnesses/gemini/hooks/pre-bash-guard.sh +0 -10
  479. package/core/harnesses/gemini/hooks/pre-compact.sh +0 -38
  480. package/core/harnesses/gemini/hooks/pre-implement-gate.sh +0 -10
  481. package/core/harnesses/gemini/hooks/session-end.impl.sh +0 -89
  482. package/core/harnesses/gemini/hooks/session-end.sh +0 -5
  483. package/core/harnesses/gemini/hooks/session-start.sh +0 -7
  484. package/core/harnesses/gemini/settings/adapter-defaults.json +0 -4
  485. package/core/harnesses/kiro/hooks/pre-bash-guard.sh +0 -24
  486. package/core/harnesses/shared/hooks/policies/blocked-patterns.conf +0 -91
  487. package/core/harnesses/shared/hooks/policies/pre-bash-guard.sh +0 -378
  488. package/core/shared/guidance/FLAGS.md +0 -25
  489. package/core/shared/guidance/rules/RULE_01_SAFETY.md +0 -25
  490. package/core/shared/guidance/rules/RULE_02_WORKFLOW.md +0 -23
  491. package/core/shared/guidance/rules/RULE_03_QUALITY.md +0 -14
  492. package/core/shared/guidance/rules/RULE_04_QUESTIONS.md +0 -46
  493. package/src/adapters/gemini/hooks.js +0 -251
  494. package/src/adapters/gemini/index.js +0 -429
@@ -0,0 +1,126 @@
1
+ {
2
+ "binary": "codex",
3
+ "checks": [
4
+ {
5
+ "argv": [
6
+ "exec",
7
+ "--help"
8
+ ],
9
+ "establishes": [
10
+ "runnableProbe",
11
+ "oneShot"
12
+ ],
13
+ "exit": 0,
14
+ "expect": [
15
+ "^Usage: codex exec \\[OPTIONS\\] \\[PROMPT\\]",
16
+ "instructions are read from stdin"
17
+ ],
18
+ "id": "exec-one-shot",
19
+ "matched": [
20
+ "Usage: codex exec [OPTIONS] [PROMPT]",
21
+ " instructions are read from stdin. If stdin is piped and a prompt is also provided, stdin"
22
+ ],
23
+ "result": "pass"
24
+ },
25
+ {
26
+ "argv": [
27
+ "exec",
28
+ "--help"
29
+ ],
30
+ "establishes": [
31
+ "structuredOutput"
32
+ ],
33
+ "exit": 0,
34
+ "expect": [
35
+ "^\\s+--json$",
36
+ "Print events to stdout as JSONL",
37
+ "-o, --output-last-message"
38
+ ],
39
+ "id": "exec-json",
40
+ "matched": [
41
+ " --json",
42
+ " Print events to stdout as JSONL",
43
+ " -o, --output-last-message <FILE>"
44
+ ],
45
+ "result": "pass"
46
+ },
47
+ {
48
+ "argv": [
49
+ "exec",
50
+ "--help"
51
+ ],
52
+ "establishes": [
53
+ "readOnly",
54
+ "isolatedEdit"
55
+ ],
56
+ "exit": 0,
57
+ "expect": [
58
+ "-s, --sandbox <SANDBOX_MODE>",
59
+ "read-only, workspace-write"
60
+ ],
61
+ "id": "exec-sandbox",
62
+ "matched": [
63
+ " -s, --sandbox <SANDBOX_MODE>",
64
+ " [possible values: read-only, workspace-write, danger-full-access]"
65
+ ],
66
+ "result": "pass"
67
+ },
68
+ {
69
+ "argv": [
70
+ "features",
71
+ "list",
72
+ "--disable",
73
+ "multi_agent",
74
+ "--disable",
75
+ "multi_agent_v2"
76
+ ],
77
+ "establishes": [
78
+ "spawnDenial"
79
+ ],
80
+ "exit": 0,
81
+ "expect": [
82
+ "^multi_agent\\s+\\S+\\s+false$",
83
+ "^multi_agent_v2\\s+\\S+\\s+false$"
84
+ ],
85
+ "id": "spawn-denial",
86
+ "matched": [
87
+ "multi_agent stable false",
88
+ "multi_agent_v2 stable false"
89
+ ],
90
+ "result": "pass"
91
+ },
92
+ {
93
+ "argv": [
94
+ "exec",
95
+ "--help"
96
+ ],
97
+ "establishes": [
98
+ "model"
99
+ ],
100
+ "exit": 0,
101
+ "expect": [
102
+ "^\\s+-m, --model <MODEL>$"
103
+ ],
104
+ "id": "exec-model",
105
+ "matched": [
106
+ " -m, --model <MODEL>"
107
+ ],
108
+ "result": "pass"
109
+ }
110
+ ],
111
+ "cliVersion": "codex-cli 0.164.0",
112
+ "establishes": [
113
+ "isolatedEdit",
114
+ "model",
115
+ "oneShot",
116
+ "readOnly",
117
+ "runnableProbe",
118
+ "spawnDenial",
119
+ "structuredOutput"
120
+ ],
121
+ "harness": "codex",
122
+ "kind": "cli-check",
123
+ "recordedAt": "2026-10-24T10:45:22.229Z",
124
+ "run": null,
125
+ "schema": "doflow-worker-evidence-v1"
126
+ }
@@ -0,0 +1,38 @@
1
+ {
2
+ "schema": "doflow-worker-checks-v1",
3
+ "harness": "codex",
4
+ "binary": "codex",
5
+ "version": { "argv": ["--version"], "expect": "^codex-cli \\d+\\.\\d+\\.\\d+" },
6
+ "checks": [
7
+ {
8
+ "id": "exec-one-shot",
9
+ "argv": ["exec", "--help"],
10
+ "expect": ["^Usage: codex exec \\[OPTIONS\\] \\[PROMPT\\]", "instructions are read from stdin"],
11
+ "establishes": ["runnableProbe", "oneShot"]
12
+ },
13
+ {
14
+ "id": "exec-json",
15
+ "argv": ["exec", "--help"],
16
+ "expect": ["^\\s+--json$", "Print events to stdout as JSONL", "-o, --output-last-message"],
17
+ "establishes": ["structuredOutput"]
18
+ },
19
+ {
20
+ "id": "exec-sandbox",
21
+ "argv": ["exec", "--help"],
22
+ "expect": ["-s, --sandbox <SANDBOX_MODE>", "read-only, workspace-write"],
23
+ "establishes": ["readOnly", "isolatedEdit"]
24
+ },
25
+ {
26
+ "id": "spawn-denial",
27
+ "argv": ["features", "list", "--disable", "multi_agent", "--disable", "multi_agent_v2"],
28
+ "expect": ["^multi_agent\\s+\\S+\\s+false$", "^multi_agent_v2\\s+\\S+\\s+false$"],
29
+ "establishes": ["spawnDenial"]
30
+ },
31
+ {
32
+ "id": "exec-model",
33
+ "argv": ["exec", "--help"],
34
+ "expect": ["^\\s+-m, --model <MODEL>$"],
35
+ "establishes": ["model"]
36
+ }
37
+ ]
38
+ }
package/package.json CHANGED
@@ -1,11 +1,10 @@
1
1
  {
2
2
  "name": "@khoavu882/doflow",
3
- "version": "2.0.0-beta.5",
3
+ "version": "2.0.1",
4
4
  "description": "DoFlow config installer — npx CLI for the registry-driven multi-harness install/update/remove lifecycle",
5
5
  "keywords": [
6
6
  "claude-code",
7
7
  "codex",
8
- "gemini",
9
8
  "opencode",
10
9
  "ai-coding-agent",
11
10
  "skills",
@@ -26,16 +25,21 @@
26
25
  "doflow": "bin/doflow.js"
27
26
  },
28
27
  "engines": {
29
- "node": "^22.18.0 || >=24.3.0"
28
+ "node": ">=24.22.1"
30
29
  },
31
30
  "scripts": {
32
- "test": "node --test \"test/**/*.test.js\"",
31
+ "test": "node --test \"test/**/*.test.js\" \"test/**/*.test.ts\"",
32
+ "test:fast": "node test/helper/fast-tier.ts",
33
33
  "typecheck": "npx -y -p typescript@5.7.2 tsc -p tsconfig.json",
34
34
  "build:package": "node src/release/build-package.js .pack",
35
- "bench": "node bench/runner.js",
35
+ "bench": "node bench/runner.ts",
36
36
  "drift": "node scripts/check-format-drift.js",
37
+ "emission-rules": "node src/runtime/context/emission-rules.js --check",
37
38
  "release-notes": "node src/release/changelog-section.js",
38
- "version": "node src/release/sync-plugin-versions.js && git add core/.codex-plugin/plugin.json core/.claude-plugin/plugin.json core/.plugin/plugin.json"
39
+ "docs:blocks": "node src/release/docs-blocks.js --check",
40
+ "release:preflight": "node src/release/preflight.js",
41
+ "release:rehearse": "node src/release/rehearse.js",
42
+ "version": "node src/release/sync-plugin-versions.js && git add core/.codex-plugin/plugin.json core/.claude-plugin/plugin.json core/.plugin/plugin.json core/registry/packages/doflow/doflow-package.json core/registry/contribution-points.json"
39
43
  },
40
44
  "files": [
41
45
  "bin/",
@@ -4,9 +4,11 @@
4
4
 
5
5
  // Antigravity CLI adapter (#8). Scope follows the surfaces verified against Antigravity's own
6
6
  // docs (antigravity.google/docs/cli/*):
7
- // instructions — marker-managed section in PROJECT AGENTS.md only. Global memory is
8
- // ~/.gemini/GEMINI.md, shared with the Gemini CLI harness; two adapters writing one file with
9
- // one marker pair would fight, so global instructions are reported, never written.
7
+ // instructions — marker-managed section in project AGENTS.md and global ~/.gemini/GEMINI.md (left
8
+ // alone while another live harness declares it); a retired harness's span there is taken over in
9
+ // one write (row 127 IC-007), a person-edited file kept until --force. See instructionTarget.
10
+ // rules — the core set (DOFLOW_CORE.md and the files it imports), flat, in project .agents/rules
11
+ // only; the full guidance tree stays in .doflow/guidance.
10
12
  // skills — folder-form copy-tree into project .agents/skills or user ~/.gemini/config/skills.
11
13
  // agents — copy-tree into project .agents/agents or user ~/.gemini/config/agents.
12
14
  // mcp — entries of the mcpServers object in .agents/mcp_config.json (workspace) or
@@ -20,9 +22,10 @@ const fs = require('node:fs');
20
22
  const os = require('node:os');
21
23
  const path = require('node:path');
22
24
 
23
- const { MARKER_START, MARKER_END } = require('../../helper/marker-merge.js');
24
- const { planTree, applyTree, removeTree, verifyTree, copyTreeAssets, ledgerFileResources, ledgerSiblingFingerprints, siblingReplacedNotices, fingerprint, readJson, sourceDirFor } = require('../copy-tree.js');
25
+ const { MARKER_START, MARKER_END, removeMarkedSection } = require('../../helper/marker-merge.js');
26
+ const { planTree, applyTree, removeTree, verifyTree, resolveTransform, copyTreeAssets, ledgerFileResources, ledgerSiblingFingerprints, siblingReplacedNotices, fingerprint, readJson, sourceDirFor } = require('../copy-tree.js');
25
27
  const { declaredHarnessPaths, resolveHarnessPaths } = require('../../helper/harness-paths.js');
28
+ const { renderGuidancePointer } = require('../guidance-pointer.js');
26
29
  const { readMcpFiles, planMcpEntries, verifyMcpEntries, ownedMcpIds, writeMcpEntries } = require('../mcp-entries.js');
27
30
 
28
31
  const HARNESS = 'antigravity';
@@ -136,8 +139,8 @@ function sha256File(fsImpl , file ) {
136
139
 
137
140
  /** Native paths per scope, resolved from the declaration in core/registry/harnesses.json
138
141
  * ("paths"): project customization lives at <root>/.agents, global config at ~/.gemini/config
139
- * (the shared-customization root); instructions and skills are project-only surfaces, so no user
140
- * rule is declared for them and they resolve to null there. */
142
+ * (the shared-customization root); instructions are AGENTS.md in the project and ~/.gemini/GEMINI.md
143
+ * globally; the hook surfaces are project-only, so no user rule is declared and they resolve to null. */
141
144
  function resolveNativePaths(declaredPaths , { scope, scopeRoot, homeDir } = {}) {
142
145
  if (scope !== 'project' && scope !== 'global') throw new Error(`Unsupported Antigravity scope '${scope}'`);
143
146
  const resolved = resolveHarnessPaths(declaredPaths, { scope, scopeRoot, homeDir });
@@ -212,16 +215,25 @@ function render({ content = '' } = {}) {
212
215
  return `${MARKER_START}\n${String(content).trimEnd()}\n${MARKER_END}\n`;
213
216
  }
214
217
 
215
- function managedInstruction(existing , rendered ) {
218
+ const INSTRUCTIONS_IDENTITY = `doflow:${HARNESS}:instructions:managed-section`;
219
+ /** The short start marker the retired harness wrote into ~/.gemini/GEMINI.md (row 127). It is read
220
+ * only in a file this adapter is taking over, never written: the span it opens is replaced with ours. */
221
+ const PREDECESSOR_MARKER_START = '<!-- doflow:start -->';
222
+
223
+ /** The file's content with `rendered` as its DoFlow span: created, appended to a file with none, or
224
+ * replacing the span in place. `predecessor` also accepts the retired harness's start marker, for a
225
+ * file being taken over. `name` is the file's name in the conflict. */
226
+ function managedInstruction(existing , rendered , { name = 'AGENTS.md', predecessor = false } = {}) {
216
227
  if (existing === null) return { ok: true, operation: 'create', content: rendered };
217
- const start = existing.indexOf(MARKER_START);
228
+ let start = existing.indexOf(MARKER_START);
229
+ if (start === -1 && predecessor) start = existing.indexOf(PREDECESSOR_MARKER_START);
218
230
  const end = existing.indexOf(MARKER_END);
219
231
  if (start === -1 && end === -1) {
220
232
  const separator = existing === '' || existing.endsWith('\n') ? '\n' : '\n\n';
221
233
  const content = `${existing}${separator}${rendered}`;
222
234
  return { ok: true, operation: 'merge', content };
223
235
  }
224
- if (start === -1 || end === -1 || end < start) return { ok: false, conflict: 'AGENTS.md has malformed DoFlow managed-section markers' };
236
+ if (start === -1 || end === -1 || end < start) return { ok: false, conflict: `${name} has malformed DoFlow managed-section markers` };
225
237
  const content = `${existing.slice(0, start)}${rendered}${existing.slice(end + MARKER_END.length).replace(/^\n?/, '')}`;
226
238
  return { ok: true, operation: content === existing ? 'none' : 'merge', content };
227
239
  }
@@ -279,7 +291,7 @@ function planTrees({ assets, paths, scope, neutralResources, removing, repoRoot,
279
291
  for (const { asset, destDir } of targets) {
280
292
  const sourceDir = sourceDirFor(asset, { repoRoot }, fsImpl, HARNESS);
281
293
  const previousResources = ledgerFileResources(neutralResources, HARNESS, asset.id);
282
- const result = planTree({ sourceDir, destDir, previousResources, siblingFingerprints: ledgerSiblingFingerprints(neutralResources, HARNESS), operation: removing ? 'remove' : 'apply', fsImpl, layout: asset.layout, keepModified: !removing,
294
+ const result = planTree({ sourceDir, destDir, previousResources, siblingFingerprints: ledgerSiblingFingerprints(neutralResources, HARNESS), operation: removing ? 'remove' : 'apply', fsImpl, layout: asset.layout, transform: asset.transform, select: asset.select, keepModified: !removing,
283
295
  // Forwarded so the CLI's --force reaches planTree's conflict check; omitting it let
284
296
  // planTree's own `force = false` default stand in silently. Gated on `!removing` for the
285
297
  // reason codex/index.ts states in full: force heals drift on apply, but a hand-edited file
@@ -297,6 +309,7 @@ function planTrees({ assets, paths, scope, neutralResources, removing, repoRoot,
297
309
  ownershipIdentity: `doflow:${HARNESS}:copy-tree:${asset.id}:${change.relPath}`,
298
310
  kind: 'copy-tree-file', identity: change.relPath,
299
311
  afterFingerprint: change.fingerprint, fingerprint: change.fingerprint, sourceVersion: 'registry-v1',
312
+ transformName: asset.transform || null,
300
313
  ...(change.kept ? { retained: true, retainedFor: [] } : {}),
301
314
  projection: { renderer: 'copy-tree' },
302
315
  });
@@ -315,7 +328,8 @@ function runTreeChanges(changes , mode ) {
315
328
  .filter((c ) => c.projection?.renderer === 'copy-tree' || c.kind === 'copy-tree-file')
316
329
  .map((c ) => ({ relPath: c.identity ?? c.relPath, target: c.target,
317
330
  source: c._text ? undefined : c.source, operation: c.operation,
318
- fingerprint: c.fingerprint, pruneGuard: c.pruneGuard, ...(c._text ? { _text: c._text } : {}) }));
331
+ fingerprint: c.fingerprint, pruneGuard: c.pruneGuard, transformName: c.transformName || null,
332
+ ...(c._text ? { _text: c._text } : {}) }));
319
333
  // Content-managed tree files (hook scripts): write rendered text with +x, not a byte copy.
320
334
  for (const t of treeChanges) {
321
335
  if (t._text === undefined) continue;
@@ -330,58 +344,100 @@ function runTreeChanges(changes , mode ) {
330
344
  const plain = treeChanges.filter((t ) => t._text === undefined);
331
345
  const writes = plain.filter((c ) => c.operation !== 'remove');
332
346
  const removals = plain.filter((c ) => c.operation === 'remove');
333
- const applied = writes.length ? applyTree({ changes: writes }).applied : 0;
347
+ // A projection that declares a transform (the rules' always_on header) is re-derived from the
348
+ // source at write time, so each change is applied under its own transform.
349
+ const byTransform = new Map ();
350
+ for (const change of writes) byTransform.set(change.transformName, [...(byTransform.get(change.transformName) || []), change]);
351
+ let applied = 0;
352
+ for (const [transformName, group] of byTransform) {
353
+ applied += applyTree({ changes: group, transform: transformName ? resolveTransform(transformName) : undefined }).applied;
354
+ }
334
355
  const removed = removals.length ? removeTree({ changes: removals }).removed : 0;
335
356
  return { applied, removed };
336
357
  })(),
337
358
  };
338
- const writes = treeChanges.filter((c ) => c.operation !== 'remove');
339
- const removals = treeChanges.filter((c ) => c.operation === 'remove');
340
- const applied = writes.length ? applyTree({ changes: writes }).applied : 0;
341
- const removed = removals.length ? removeTree({ changes: removals }).removed : 0;
342
- return { applied, removed };
343
359
  }
344
360
 
345
361
  // ---- instructions component ----
346
362
 
347
- function planInstructions({ paths, assets, removing, repoRoot, fsImpl = fs } ) {
348
- if (scopeOf(paths) !== 'project') return { changes: [], conflicts: [] };
349
- void repoRoot;
363
+ /** The instruction file this run manages, or null: project AGENTS.md as ever; the global GEMINI.md
364
+ * only when the pointer asset is selected and no other live harness in `registry` declares that same
365
+ * file (until the harness that owned it retires, its adapter keeps it and this one stays out). */
366
+ function instructionTarget({ paths, assets, registry } ) {
367
+ if (!paths.instruction) return null;
368
+ if (scopeOf(paths) === 'project') return paths.instruction;
369
+ if (!(assets ?? []).some((asset ) => asset.id === POINTER_ASSET_ID)) return null;
370
+ const declaredBy = (harness ) => {
371
+ if (harness?.id === HARNESS || !harness?.paths?.instruction) return false;
372
+ try { return resolveHarnessPaths({ instruction: harness.paths.instruction }, { scope: 'global', scopeRoot: paths.root, homeDir: paths.root }).instruction === paths.instruction; } catch { return false; }
373
+ };
374
+ return (registry?.harnesses ?? []).some(declaredBy) ? null : paths.instruction;
375
+ }
376
+
377
+ /** How this run stands to a section it took over (IC-007): the lifecycle's handover verdict for the
378
+ * file, this harness's own row on it, and whether a person-edited file stays as it is (`retained`:
379
+ * edited before the handover, or kept since, and no --force). `predecessor` lets the retired
380
+ * harness's span count as the section to replace; `keptRow` is a row recorded as kept. A handover
381
+ * file whose DoFlow span already is this harness's render was written by DoFlow itself (a run that
382
+ * threw after that write and before its ledger write), so it does not count as edited. */
383
+ function instructionState({ target, context, resources, paths, fsImpl = fs } ) {
384
+ const handover = (context.handovers ?? []).find((item ) => item.target === target) ?? null;
385
+ const ownRow = (resources ?? []).find((row ) => row.harness === HARNESS && row.target === target && row.ownershipIdentity === INSTRUCTIONS_IDENTITY) ?? null;
386
+ const ownWrite = () => {
387
+ const rendered = renderedInstruction(paths, fsImpl);
388
+ if (rendered === null || !fsImpl.existsSync(target)) return false;
389
+ const outcome = managedInstruction(fsImpl.readFileSync(target, 'utf8'), rendered);
390
+ return outcome.ok && outcome.operation === 'none';
391
+ };
392
+ const edited = (handover?.edited === true && !ownWrite()) || ownRow?.retainedEdit === true;
393
+ return { predecessor: Boolean(handover) || ownRow?.retainedEdit === true, retained: edited && context.force !== true,
394
+ keptRow: ownRow?.retainedEdit === true };
395
+ }
396
+
397
+ function instructionsChange(target , fields ) {
398
+ return { assetId: POINTER_ASSET_ID, target, ownershipIdentity: INSTRUCTIONS_IDENTITY,
399
+ kind: 'instructions-section', identity: path.basename(target), projection: { renderer: 'antigravity-instructions' }, ...fields };
400
+ }
401
+
402
+ function planInstructions({ paths, target, removing, state, fsImpl = fs } ) {
403
+ const none = { changes: [], conflicts: [], notices: [] };
404
+ if (!target) return none;
350
405
  if (removing) {
351
406
  // Removal must strip the section DoFlow owns while leaving foreign bytes untouched — same
352
407
  // contract as the other AGENTS-style adapters.
353
- if (!fsImpl.existsSync(paths.instruction)) return { changes: [], conflicts: [] };
354
- const text = fsImpl.readFileSync(paths.instruction, 'utf8');
355
- if (!text.includes(MARKER_START)) return { changes: [], conflicts: [] };
356
- return {
357
- changes: [{
358
- assetId: POINTER_ASSET_ID, target: paths.instruction, operation: 'remove',
359
- ownershipIdentity: `doflow:${HARNESS}:instructions:managed-section`,
360
- kind: 'instructions-section', identity: 'AGENTS.md',
361
- projection: { renderer: 'antigravity-instructions' },
362
- }],
363
- conflicts: [],
364
- };
408
+ if (!fsImpl.existsSync(target)) return none;
409
+ const text = fsImpl.readFileSync(target, 'utf8');
410
+ // A kept edited file with no span left still carries this harness's row: the remove change
411
+ // releases the row, and apply finds no span to strip, so the person's file is not touched.
412
+ if (!text.includes(MARKER_START) && !state.keptRow) return none;
413
+ return { ...none, changes: [instructionsChange(target, { operation: 'remove' })] };
365
414
  }
366
- const sourceText = pointerBody(fsImpl);
367
- if (!sourceText) return { changes: [], conflicts: [] };
368
- const existing = fsImpl.existsSync(paths.instruction) ? fsImpl.readFileSync(paths.instruction, 'utf8') : null;
369
- const outcome = managedInstruction(existing, render({ content: sourceText }));
370
- if (!outcome.ok) return { changes: [], conflicts: [outcome.conflict] };
371
- if (outcome.operation === 'none') return { changes: [], conflicts: [] };
415
+ if (state.retained) {
416
+ const shown = scopeOf(paths) === 'global' ? `~/${path.relative(paths.root, target)}` : path.relative(paths.root, target);
417
+ return { ...none, notices: [`kept ${shown}: changed before handover; --force replaces the DoFlow section`] };
418
+ }
419
+ const rendered = renderedInstruction(paths, fsImpl);
420
+ if (rendered === null) return none;
421
+ const existing = fsImpl.existsSync(target) ? fsImpl.readFileSync(target, 'utf8') : null;
422
+ const outcome = managedInstruction(existing, rendered, { name: path.basename(target), predecessor: state.predecessor });
423
+ if (!outcome.ok) return { ...none, conflicts: [outcome.conflict] };
424
+ if (outcome.operation === 'none') return none;
372
425
  return {
373
- changes: [{
374
- assetId: POINTER_ASSET_ID, target: paths.instruction, operation: existing === null ? 'create' : 'update',
375
- ownershipIdentity: `doflow:${HARNESS}:instructions:managed-section`,
376
- kind: 'instructions-section', identity: 'AGENTS.md',
426
+ ...none,
427
+ changes: [instructionsChange(target, {
428
+ operation: existing === null ? 'create' : 'update',
377
429
  afterFingerprint: fingerprint(outcome.content), sourceVersion: 'registry-v1',
378
- projection: { renderer: 'antigravity-instructions' },
379
430
  _content: outcome.content,
380
- }],
381
- conflicts: [],
431
+ })],
382
432
  };
383
433
  }
384
434
 
435
+ /** This scope's DoFlow section: the shared pointer rendered for the scope, inside the markers. */
436
+ function renderedInstruction(paths , fsImpl ) {
437
+ const sourceText = pointerBody(fsImpl);
438
+ return sourceText ? render({ content: renderGuidancePointer(sourceText, { scope: scopeOf(paths), scopeRoot: paths.root }) }) : null;
439
+ }
440
+
385
441
  function pointerBody(fsImpl ) {
386
442
  // The shared pointer prose ships once; read it through the same repo-relative anchor the other
387
443
  // AGENTS-style adapters use.
@@ -432,13 +488,18 @@ function plan(options = {}, impl = {}) {
432
488
  const selectedServers = Array.isArray(options.mcp) ? options.mcp : [];
433
489
  const discovery = options.discovery ?? discover(options, impl);
434
490
 
435
- const instructions = planInstructions({ paths, assets: options.assets, removing, repoRoot: context.repoRoot, fsImpl });
491
+ const instructionFile = instructionTarget({ paths, assets: options.assets, registry: options.registry });
492
+ const instructions = planInstructions({ paths, target: instructionFile, removing, fsImpl,
493
+ state: instructionState({ target: instructionFile, context, resources: neutralResources, paths, fsImpl }) });
436
494
  const trees = planTrees({ assets: options.assets, paths, scope, neutralResources, removing, repoRoot: context.repoRoot, force: context.force === true, fsImpl });
437
495
  const mcp = planMcpEntries({
438
496
  ...mcpEntriesInput({ paths, mcp: selectedServers, mcpAdoptable: options.mcpAdoptable, resources: neutralResources }),
439
497
  files: discovery.mcpSnapshot, removing,
440
498
  });
441
- const hooksPlan = planHooks({ paths, scope, neutralResources, removing, repoRoot: context.repoRoot, fsImpl });
499
+ // Hook tiers (maint-hooks): outside `hooks.harnesses` this plan carries no hook change; the lifecycle
500
+ // plans the removal of what an earlier run wrote, from the ledger, against the full registry.
501
+ const hooksPlan = context.hooksOff === true && !removing ? { changes: [], conflicts: [] }
502
+ : planHooks({ paths, scope, neutralResources, removing, repoRoot: context.repoRoot, fsImpl });
442
503
 
443
504
  const changes = [...instructions.changes, ...trees.changes, ...mcp.changes, ...hooksPlan.changes];
444
505
  const conflicts = [...instructions.conflicts, ...trees.conflicts, ...mcp.conflicts, ...hooksPlan.conflicts];
@@ -447,7 +508,7 @@ function plan(options = {}, impl = {}) {
447
508
  conflicts,
448
509
  prerequisites: [],
449
510
  requiredNativeResources: changes,
450
- notices: [...trees.notices, ...mcp.notices],
511
+ notices: [...instructions.notices, ...trees.notices, ...mcp.notices],
451
512
  };
452
513
  }
453
514
 
@@ -485,14 +546,26 @@ function apply(options = {}, impl = {}) {
485
546
 
486
547
  for (const change of changes.filter((c ) => c.projection?.renderer === 'antigravity-instructions')) {
487
548
  if (change.operation === 'remove') {
488
- // pi precedent: strip only the managed span; the file survives even when nothing remains.
489
549
  if (!fsImpl.existsSync(change.target)) continue;
550
+ // The global file is the person's: the span goes with the one newline put before it, so their
551
+ // bytes come back exactly (and a file that held only the span goes with it). A kept file taken
552
+ // over from the retired harness may still hold that harness's span, under its short marker.
553
+ if ((options.scope ?? 'project') === 'global') { removeMarkedSection(change.target, { startMarkers: [MARKER_START, PREDECESSOR_MARKER_START] }); continue; }
554
+ // pi precedent: strip only the managed span; the file survives even when nothing remains.
490
555
  const next = strippedInstruction(fsImpl.readFileSync(change.target, 'utf8'));
491
556
  if (next !== null) fsImpl.writeFileSync(change.target, next, 'utf8');
492
557
  continue;
493
558
  }
559
+ // One rename onto the file: no reader, and no failure, ever sees it without its DoFlow span.
494
560
  fsImpl.mkdirSync(path.dirname(change.target), { recursive: true });
495
- fsImpl.writeFileSync(change.target, change._content ?? render({ content: '' }), 'utf8');
561
+ const tmp = `${change.target}.${process.pid}.tmp`;
562
+ try {
563
+ fsImpl.writeFileSync(tmp, change._content ?? render({ content: '' }), 'utf8');
564
+ fsImpl.renameSync(tmp, change.target);
565
+ } catch (error) {
566
+ fsImpl.rmSync(tmp, { force: true });
567
+ throw error;
568
+ }
496
569
  }
497
570
  for (const change of changes.filter((c ) => c.projection?.renderer === 'antigravity-hooks')) {
498
571
  if (change.kind === 'copy-tree-file') continue; // handled by runTreeChanges below
@@ -594,24 +667,28 @@ function verify(options = {}, impl = {}) {
594
667
  const statuses = [];
595
668
  const resources = [];
596
669
 
597
- const instruction = paths.instruction && fsImpl.existsSync(paths.instruction)
598
- ? fsImpl.readFileSync(paths.instruction, 'utf8') : null;
599
- const managed = instruction !== null && instruction.includes(MARKER_START) && instruction.includes(MARKER_END);
600
- if (paths.instruction) {
670
+ const instructionFile = instructionTarget({ paths, assets: options.assets, registry: options.registry });
671
+ const state = instructionState({ target: instructionFile, context, resources: ledgerResources(options), paths, fsImpl });
672
+ const instruction = instructionFile && fsImpl.existsSync(instructionFile)
673
+ ? fsImpl.readFileSync(instructionFile, 'utf8') : null;
674
+ const managed = instruction !== null && instruction.includes(MARKER_END)
675
+ && (instruction.includes(MARKER_START) || (state.predecessor && instruction.includes(PREDECESSOR_MARKER_START)));
676
+ // A kept, person-edited file (IC-007) is owned as it is now, markers or not: an edit can drop the
677
+ // span, and without its row the next run would see no owner and append the section unasked.
678
+ const kept = !removing && state.retained && instruction !== null;
679
+ if (instructionFile) {
601
680
  // Removal verification asks "did our section go away?"; install/update asks "is it managed?".
602
681
  statuses.push({
603
682
  assetId: POINTER_ASSET_ID, capability: 'instructions',
604
- status: removing ? (managed ? 'retained' : 'absent') : (managed ? 'managed' : 'missing'),
605
- target: paths.instruction,
683
+ status: removing ? (managed ? 'retained' : 'absent') : (managed ? 'managed' : (kept ? 'retained' : 'missing')),
684
+ target: instructionFile,
606
685
  });
607
- if (managed && !removing) {
608
- resources.push({
609
- assetId: POINTER_ASSET_ID, target: paths.instruction,
610
- ownershipIdentity: `doflow:${HARNESS}:instructions:managed-section`,
611
- kind: 'instructions-section', identity: 'AGENTS.md',
686
+ if (!removing && (managed || kept)) {
687
+ // Recorded with the file as it is now; a kept one is flagged so later runs keep it until --force.
688
+ resources.push(instructionsChange(instructionFile, {
612
689
  fingerprint: fingerprint(instruction), sourceVersion: 'registry-v1',
613
- projection: { renderer: 'antigravity-instructions' },
614
- });
690
+ ...(state.retained ? { retainedEdit: true } : {}),
691
+ }));
615
692
  }
616
693
  }
617
694
 
@@ -619,7 +696,7 @@ function verify(options = {}, impl = {}) {
619
696
  const destDir = treeDestFor(asset, paths, scope);
620
697
  if (!destDir) continue;
621
698
  const sourceDir = sourceDirFor(asset, { repoRoot: context.repoRoot }, fsImpl, HARNESS);
622
- const result = verifyTree({ sourceDir, destDir, fsImpl, layout: asset.layout, plannedWrites: context.plannedWrites });
699
+ const result = verifyTree({ sourceDir, destDir, fsImpl, layout: asset.layout, transform: asset.transform, select: asset.select, plannedWrites: context.plannedWrites });
623
700
  conflictsToStatuses(result.conflicts, asset.id, statuses);
624
701
  for (const resource of result.resources) {
625
702
  resources.push({
@@ -642,7 +719,7 @@ function verify(options = {}, impl = {}) {
642
719
  resources.push(...mcp.resources);
643
720
 
644
721
  // Hooks projection (project scope): the shims' bytes and the registered groups.
645
- if (scope === 'project') {
722
+ if (scope === 'project' && context.hooksOff !== true) {
646
723
  const hooks = verifyHooks({ options, paths, context, fsImpl });
647
724
  statuses.push(...hooks.statuses);
648
725
  resources.push(...hooks.resources);