@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
@@ -1,114 +0,0 @@
1
- 'use strict';
2
-
3
- /**
4
- * Gemini CLI payload/decision adapter for the Cross-Harness Hook Runner (design.md C2's
5
- * Payload Adapter / Decision Adapter seam, D2).
6
- *
7
- * Gemini's own native contract — evidenced by core/harnesses/gemini/hooks/*.sh and
8
- * core/harnesses/gemini/hooks/hooks.json, all currently invoked directly by bash rather than
9
- * through this runner — already speaks field names close to Claude/Codex/Kiro's, NOT
10
- * Antigravity's toolCall/args envelope:
11
- *
12
- * SessionStart : stdin { session_id, cwd } (session-start.sh)
13
- * BeforeTool (~PreToolUse): stdin { tool_name, tool_input: { file_path, command } }
14
- * stdout { decision: "allow"|"deny", reason } — TOP-LEVEL, not
15
- * nested under hookSpecificOutput.permissionDecision like
16
- * Claude/Codex (confirmed in gemini/hooks/pre-bash-guard.sh's header).
17
- * AfterTool (~PostToolUse): stdin { tool_name, tool_input: { file_path }, session_id }
18
- * (post-edit-lint.sh) — stdout {} (ack; no Phase A policy owns this
19
- * event, post-edit-lint.sh's collector role is out of FR-001's scope)
20
- * Stop : NOT a documented Gemini lifecycle event — gemini/hooks/
21
- * post-edit-lint.sh's own comment states "Gemini has no
22
- * Stop-equivalent event," and no stop-check.sh ships under
23
- * gemini/hooks/ today. Handled defensively below (same field-name
24
- * union stop-check.sh itself accepts) in case a future Gemini
25
- * version adds one, or in case core/harnesses/shared/hooks/hooks.json's
26
- * existing (currently dangling) Stop entry is corrected to a real target.
27
- *
28
- * NFR-002 note: core/harnesses/shared/hooks/hooks.json has historically routed PreToolUse through
29
- * this runner using Antigravity's { toolCall: { name, args } } envelope — inherited from this
30
- * runner's original Antigravity-only design (see the runner's own prior header comment), not
31
- * verified against Gemini's own documented schema above. toCanonical() below reads the
32
- * tool_name/tool_input shape first (Gemini's own evidenced contract) and falls back to the
33
- * toolCall envelope only if that shape isn't present, so this adapter is correct once that
34
- * wiring is corrected without silently breaking before it is.
35
- */
36
-
37
- const { FILE_PATH_ARG_FIELDS, COMMAND_ARG_FIELDS, firstArgField } = require('./arg-fields');
38
-
39
- function toCanonical(event, payload) {
40
- const safePayload = payload && typeof payload === 'object' ? payload : {};
41
-
42
- switch (event) {
43
- case 'SessionStart':
44
- return { session_id: safePayload.session_id || '', cwd: safePayload.cwd || '' };
45
-
46
- case 'PreToolUse': {
47
- if (safePayload.tool_name !== undefined || safePayload.tool_input !== undefined) {
48
- const toolInput = safePayload.tool_input || {};
49
- return {
50
- tool_name: safePayload.tool_name || '',
51
- tool_input: {
52
- file_path: toolInput.file_path || '',
53
- command: toolInput.command || '',
54
- },
55
- };
56
- }
57
- // Defensive fallback: Antigravity-shaped envelope (see header note).
58
- const toolCall = safePayload.toolCall || {};
59
- const args = toolCall.args || {};
60
- return {
61
- tool_name: toolCall.name || '',
62
- tool_input: {
63
- file_path: firstArgField(args, FILE_PATH_ARG_FIELDS),
64
- command: firstArgField(args, COMMAND_ARG_FIELDS),
65
- },
66
- };
67
- }
68
-
69
- case 'PostToolUse':
70
- return {
71
- tool_name: safePayload.tool_name || '',
72
- session_id: safePayload.session_id || '',
73
- tool_input: { file_path: (safePayload.tool_input && safePayload.tool_input.file_path) || '' },
74
- };
75
-
76
- case 'Stop':
77
- return {
78
- session_id: safePayload.session_id || '',
79
- transcript_path: safePayload.transcript_path || safePayload.transcriptPath || '',
80
- };
81
-
82
- default:
83
- return safePayload;
84
- }
85
- }
86
-
87
- function toNative(event, decision) {
88
- const safeDecision = decision || { decision: 'allow' };
89
-
90
- switch (event) {
91
- case 'PreToolUse':
92
- if (safeDecision.decision === 'deny') {
93
- return { decision: 'deny', reason: safeDecision.reason };
94
- }
95
- return { decision: 'allow' };
96
-
97
- case 'PostToolUse':
98
- return {};
99
-
100
- case 'Stop':
101
- if (safeDecision.decision === 'deny') {
102
- return { decision: 'deny', reason: safeDecision.reason };
103
- }
104
- return { decision: 'allow' };
105
-
106
- case 'SessionStart':
107
- return {};
108
-
109
- default:
110
- return { decision: 'allow' };
111
- }
112
- }
113
-
114
- module.exports = { toCanonical, toNative };
@@ -1,47 +0,0 @@
1
- {
2
- "description": "DoFlow shared lifecycle hooks schema for Antigravity, Gemini, and Claude.",
3
- "hooks": {
4
- "SessionStart": [
5
- {
6
- "hooks": [
7
- {
8
- "type": "command",
9
- "command": "bash \"$DOFLOW_PROJECT_DIR/.gemini/hooks/session-start.sh\""
10
- }
11
- ]
12
- }
13
- ],
14
- "PreToolUse": [
15
- {
16
- "matcher": "^(run_command|run_shell_command|replace_file_content|write_to_file|multi_replace_file_content|edit_file|Edit|Write)$",
17
- "hooks": [
18
- {
19
- "type": "command",
20
- "command": "node \"$DOFLOW_PROJECT_DIR/.doflow/scripts/stream-hook-runner.js\""
21
- }
22
- ]
23
- }
24
- ],
25
- "PostToolUse": [
26
- {
27
- "matcher": "^(replace_file_content|write_to_file|multi_replace_file_content|edit_file|Edit|Write)$",
28
- "hooks": [
29
- {
30
- "type": "command",
31
- "command": "bash \"$DOFLOW_PROJECT_DIR/.gemini/hooks/post-edit-lint.sh\""
32
- }
33
- ]
34
- }
35
- ],
36
- "Stop": [
37
- {
38
- "hooks": [
39
- {
40
- "type": "command",
41
- "command": "bash \"$DOFLOW_PROJECT_DIR/.gemini/hooks/stop-check.sh\""
42
- }
43
- ]
44
- }
45
- ]
46
- }
47
- }
@@ -1,25 +0,0 @@
1
- # Runtime Behavior and Flags
2
-
3
- Loaded into **every** session on every harness. What a flag used to request is now mostly
4
- unconditional, so this states the behavior once rather than listing knobs.
5
-
6
- ## Always on
7
-
8
- **Readiness gating** — a stage that edits source is graded against its class contract first;
9
- the verdict is one of four states, never a number.
10
- **Recovery bounds** — a failed verification is classified and retried under a bound the runtime
11
- sets. You do not pick a cycle count.
12
- **Run tracing** — every runtime call is recorded as it happens and read back; where a run
13
- stopped is read from that record, never reconstructed.
14
- **Capability routing** — an information need resolves to a provider healthy on this machine, not to
15
- a habitual tool.
16
-
17
- ## Flags
18
-
19
- What the user typed beats auto-detection. Every flag belongs to one skill and is declared in that
20
- skill's `argument-hint`, except this one, which crosses them:
21
-
22
- **--focus [quality|security|performance|architecture]** — narrows analysis to one domain. Consumed
23
- by `do-diagnose`.
24
-
25
- MCP short flags are generated per install into `MCP_INDEX.md`; this file names no server.
@@ -1,25 +0,0 @@
1
- # Safety Rules (CRITICAL)
2
-
3
- ## Priority System
4
- **CRITICAL** — Security, data safety, production — never compromise
5
- **IMPORTANT** — Quality, maintainability, professionalism — strong preference
6
- **RECOMMENDED** — Optimization, style, best practices — apply when practical
7
-
8
- Conflict order: Safety > Scope > Quality > Speed. Prototype != Production requirements.
9
-
10
- <important if="debugging, fixing a bug, or investigating a failure">
11
- ## Failure Investigation
12
- - Root cause always — understand WHY, not just THAT; fix the cause, not the symptom
13
- - Never skip/disable/comment-out tests or validation to pass builds
14
- </important>
15
-
16
- <important if="performing git operations or starting work on a codebase">
17
- ## Git Workflow
18
- - `git status && git branch` first; feature branches for ALL work; never force-push main
19
- - Commit incrementally with descriptive messages; `git diff` before staging; restore-point commit
20
- before anything risky
21
- </important>
22
-
23
- ## Temporal Awareness
24
- - Read the date from `<env>` before any temporal claim; never infer it from your knowledge cutoff,
25
- and state its source
@@ -1,23 +0,0 @@
1
- # Workflow Rules
2
-
3
- ## Planning
4
- - **Parallel by default** — sequential only for hard dependencies; a task list once past 3 tasks, when the session offers one
5
- - Validate before execution, verify after; run lint/typecheck before marking complete
6
- - Check deps (package.json) and existing patterns before any changes
7
- - Feature delivery follows the doflow chain — see `references/DOFLOW_CHAIN.md` for the phase-gated
8
- flow, artifact contracts, and the enforced gate
9
-
10
- <important if="planning or starting a multi-step task">
11
- ## Planning Efficiency
12
- - Identify concurrent vs sequential operations
13
- - Map dependencies; batch tool calls; estimate parallelization gains
14
- </important>
15
-
16
- ## Implementation Completeness
17
- - Start it = Finish it. No partial features, TODO stubs, mocks, or "not implemented" throws
18
- - All generated code must work as specified; no scaffolding placeholders
19
-
20
- ## Scope Discipline
21
- - Build ONLY what's asked — no bonus features, no enterprise bloat (auth/monitoring/deployment
22
- unless requested)
23
- - MVP first; YAGNI; single responsibility per component
@@ -1,14 +0,0 @@
1
- # Quality Rules
2
-
3
- ## Organization & Hygiene
4
- **Naming**: Follow language standards (camelCase JS, snake_case Python); no mixed conventions
5
- **Files**: Organize by feature/domain; tests → `tests/`; scripts → `scripts/`; reports → `agent-docs/`
6
- **Workspace**: Remove temp files, debug scripts, build artifacts after use; never leave clutter in VCS
7
-
8
- ## Professional Honesty
9
- - No marketing language ("blazingly fast", "100% secure", "magnificent")
10
- - No invented sources, figures, citations or quotes; leave out what you cannot trace; state "untested/MVP/needs validation" honestly
11
- - If you are not sure, say so plainly and name what is unknown; do not present a guess as established
12
- - Warn when a claim may be outdated: information from memory or an old source can have changed since it was written
13
- - Never attribute a statement or view to a real person unless you have verified it; otherwise omit the name
14
- - Push back on bad approaches; evidence-based claims only
@@ -1,46 +0,0 @@
1
- # Question & Clarification Rules
2
-
3
- ## When to Ask
4
- - Ask ONLY for genuine user-owned decisions unresolved by the request, the code, or sensible defaults
5
- - Enough to act → act; don't ask to confirm the obvious (see RULE_02 Scope Discipline)
6
- - One question that unblocks beats three that re-litigate settled choices
7
-
8
- <important if="asking the user a clarifying question or choosing between approaches">
9
- ## How to Ask (MANDATORY format)
10
- Structured multiple-choice — never a free-form question buried in prose.
11
- - **A native question tool exists in this session** (Claude Code's `AskUserQuestion`, or any
12
- harness tool that presents options and returns the user's choice): use it. Which harness this
13
- is is not the test — what THIS session offers is; Codex and Gemini sessions increasingly
14
- carry one.
15
- - **No native question tool** (truly non-interactive runs): write a `{stage}-questions.md` file
16
- with `[Answer]:` tags — the fallback, never the preference.
17
-
18
- Each question:
19
- - 2–4 **meaningful, mutually-exclusive** options covering the real scenarios
20
- - NEVER invent filler; an "Other"/free-text escape is always the last choice
21
- - One topic per question; specific and unambiguous; lead with your recommended default
22
- </important>
23
-
24
- <important if="writing a question file because this session has no native question tool">
25
- ## Question-File Format
26
- ```markdown
27
- ## Question 1 — [the question]
28
- A) [option] B) [option] X) Other (free text after the tag)
29
-
30
- [Answer]:
31
- ```
32
- Naming: `{stage}-questions.md` (e.g. `spec-questions.md`) in the directory the stage writes
33
- its output to — not a fixed path outside the repo's layout.
34
-
35
- Lifecycle: write the file → tell the user and wait for "done" → read answers →
36
- **Validate Before Proceeding** (below) → act. A missing `[Answer]:`, or one that is not a listed
37
- letter, means ask again — never guess, and never reinterpret free text as a letter choice.
38
- </important>
39
-
40
- <important if="reading the user's answers before you act on them">
41
- ## Validate Before Proceeding
42
- - Scan answers for contradictions (scope vs risk, quick fix vs multi-subsystem) and ambiguity
43
- - Conflict found → name it and ask one targeted follow-up in `{stage}-clarification-questions.md`,
44
- same format, citing the conflicting answer; never proceed on an unresolved contradiction, and
45
- never assume an answer to an ambiguous response
46
- </important>
@@ -1,210 +0,0 @@
1
- 'use strict';
2
-
3
- // TypeScript migration (agent-docs/BRIEF_GOAL_DOFLOW.md): run directly by Node native type-stripping.
4
-
5
- // Gemini hook planning. Unlike Codex (which owns a standalone hooks.json file), Gemini's hooks
6
- // live as a "hooks" key inside settings.json — a file DoFlow does not fully own (it commonly
7
- // pre-exists with unrelated content: mcpServers, ui, telemetry, model, etc.). planGeminiHooks
8
- // therefore returns a key-scoped merge plan, never a full-file replace.
9
- //
10
- // NOTE: validateHooksConfig below intentionally duplicates codex-hooks.js's shape-checking logic
11
- // (event -> array of {matcher, hooks:[{type,command,...}]} groups) rather than sharing it, since
12
- // unifying it would mean introducing a new shared module beyond this feature's planned scope
13
- // (agent-docs/doflow/013-codex-gemini-hooks-parity/plan.md's component list). Worth factoring out
14
- // if a third harness with the same shape is ever added.
15
- const fs = require('node:fs');
16
- const path = require('node:path');
17
- const { verifyHookCommands } = require('../hook-commands.js');
18
- const { mergeHooks } = require('../../helper/settings-merge.js');
19
-
20
- const SUPPORTED_EVENTS = new Set([
21
- 'SessionStart', 'SessionEnd', 'BeforeAgent', 'AfterAgent', 'BeforeModel', 'AfterModel',
22
- 'BeforeToolSelection', 'BeforeTool', 'AfterTool', 'PreCompress', 'Notification',
23
- ]);
24
-
25
- // Claude guardrail event -> Gemini event, only where a real Gemini event has matching semantics
26
- // (source: geminicli.com/docs/hooks/reference.md). UserPromptSubmit,
27
- // Stop, SubagentStart/Stop, and ConfigChange have no correct Gemini equivalent and are
28
- // intentionally omitted rather than approximated onto BeforeAgent/AfterAgent (design.md §7/§8 —
29
- // no false parity).
30
- const CLAUDE_TO_GEMINI_EVENT = {
31
- SessionStart: 'SessionStart',
32
- SessionEnd: 'SessionEnd',
33
- PreToolUse: 'BeforeTool',
34
- PostToolUse: 'AfterTool',
35
- PreCompact: 'PreCompress',
36
- };
37
-
38
- function validationError(errors , message ) { errors.push(message); }
39
-
40
- function validateHooksConfig(config ) {
41
- const errors = [];
42
- if (!config || typeof config !== 'object' || Array.isArray(config)) {
43
- return { ok: false, errors: ['Hook configuration must be an object'], events: [] };
44
- }
45
- if (!config.hooks || typeof config.hooks !== 'object' || Array.isArray(config.hooks)) {
46
- return { ok: false, errors: ['Hook configuration requires a hooks object'], events: [] };
47
- }
48
- for (const [event, groups] of Object.entries(config.hooks)) {
49
- if (!SUPPORTED_EVENTS.has(event)) {
50
- validationError(errors, `Unsupported Gemini hook event '${event}'`);
51
- continue;
52
- }
53
- if (!Array.isArray(groups) || groups.length === 0) {
54
- validationError(errors, `Hook event '${event}' requires a non-empty array of matcher groups`);
55
- continue;
56
- }
57
- groups.forEach((group , groupIndex ) => {
58
- if (!group || typeof group !== 'object' || Array.isArray(group)) {
59
- validationError(errors, `Hook event '${event}' group ${groupIndex} must be an object`);
60
- return;
61
- }
62
- if (group.matcher !== undefined && typeof group.matcher !== 'string') {
63
- validationError(errors, `Hook event '${event}' group ${groupIndex} matcher must be a string`);
64
- }
65
- if (!Array.isArray(group.hooks) || group.hooks.length === 0) {
66
- validationError(errors, `Hook event '${event}' group ${groupIndex} requires a non-empty hooks array`);
67
- return;
68
- }
69
- group.hooks.forEach((handler , handlerIndex ) => {
70
- const label = `Hook event '${event}' group ${groupIndex} handler ${handlerIndex}`;
71
- if (!handler || typeof handler !== 'object' || Array.isArray(handler)) {
72
- validationError(errors, `${label} must be an object`); return;
73
- }
74
- if (handler.type !== 'command') validationError(errors, `${label} must have type 'command'`);
75
- if (typeof handler.command !== 'string' || !handler.command.trim()) {
76
- validationError(errors, `${label} requires a non-empty command string`);
77
- }
78
- if (handler.timeout !== undefined && typeof handler.timeout !== 'number') {
79
- validationError(errors, `${label} timeout must be a number`);
80
- }
81
- });
82
- });
83
- }
84
- return { ok: errors.length === 0, errors, events: Object.keys(config.hooks) };
85
- }
86
-
87
- /** Maps Claude guardrail intent, never fabricating a Gemini equivalent for unavailable events. */
88
- function classifyClaudeGuardrails(claudeHooks = {}) {
89
- const supported = [];
90
- const unsupported = [];
91
- for (const [event, groups] of Object.entries(claudeHooks || {})) {
92
- const targetEvent = CLAUDE_TO_GEMINI_EVENT[event] || null;
93
- const item = { sourceEvent: event, targetEvent, groups: Array.isArray(groups) ? groups.length : 0 };
94
- if (targetEvent) supported.push(item);
95
- else unsupported.push({ ...item, reason: `Gemini has no equivalent lifecycle event for Claude's '${event}'` });
96
- }
97
- return { supported, unsupported };
98
- }
99
-
100
- /**
101
- * Plan a key-scoped merge of a "hooks" config into an existing (or absent) settings.json, never
102
- * touching any other key. Mirrors src/mcp.js's readJsonOrThrow discipline: a settings.json that
103
- * exists but fails to parse is a hard error, not silently treated as empty (this path merges
104
- * into content DoFlow does not own — a malformed-file work-around here risks losing it).
105
- */
106
- function planGeminiHooks({ config, sourceFile, sourceHooksDir, settingsFile, destinationHooksDir: declaredHooksDir, trusted = false, fsImpl = fs } = {}) {
107
- let desired = config;
108
- try {
109
- if (!desired && sourceFile) desired = JSON.parse(fsImpl.readFileSync(sourceFile, 'utf8'));
110
- } catch (error ) {
111
- return { ok: false, status: 'malformed', changes: [], errors: [`Could not parse ${sourceFile}: ${error.message}`] };
112
- }
113
- if (!settingsFile) return { ok: false, status: 'invalid-request', changes: [], errors: ['settingsFile is required'] };
114
- const schema = validateHooksConfig(desired);
115
- const commands = verifyHookCommands(desired || {}, { scriptsDir: sourceHooksDir, trusted, fsImpl });
116
- const errors = [...schema.errors, ...commands.checks.filter((check ) => !check.ok).map((check ) => `${check.event}: ${check.reason}${check.script ? ` (${check.script})` : ''}`)];
117
-
118
- let existing = {};
119
- if (fsImpl.existsSync(settingsFile)) {
120
- try { existing = JSON.parse(fsImpl.readFileSync(settingsFile, 'utf8')); }
121
- catch (error ) { return { ok: false, status: 'malformed', changes: [], errors: [`Refusing to touch malformed ${settingsFile}: ${error.message}`] }; }
122
- }
123
- if (errors.length) return { ok: false, status: 'invalid-request', settingsFile, existing, changes: [], errors, commands };
124
-
125
- const mergedHooks = existing.hooks ? mergeHooks(existing.hooks, desired.hooks) : desired.hooks;
126
- const merged = { ...existing, hooks: mergedHooks };
127
- const changed = JSON.stringify(existing.hooks) !== JSON.stringify(mergedHooks);
128
- // Preferred: the declared hooks directory (harnesses.json "paths".hooksDirectory); the derived
129
- // sibling-of-settings fallback stays for direct callers passing raw inputs, and resolves to the
130
- // same location.
131
- const destinationHooksDir = declaredHooksDir || path.join(path.dirname(settingsFile), 'hooks');
132
- // The scripts deployGeminiHooks copies beside settings.json, so a backup of this change holds them too.
133
- const shipped = sourceHooksDir && fsImpl.existsSync(sourceHooksDir)
134
- ? fsImpl.readdirSync(sourceHooksDir).filter((name ) => !name.endsWith('.json') && fsImpl.statSync(path.join(sourceHooksDir, name)).isFile())
135
- : [];
136
- const companionTargets = [...new Set([
137
- ...commands.checks.map((check ) => path.join(destinationHooksDir, check.script)),
138
- ...shipped.map((name ) => path.join(destinationHooksDir, name)),
139
- ])].sort();
140
- return { ok: true, status: changed ? 'change' : 'unchanged', settingsFile, existing, merged,
141
- changes: changed ? [{ type: fsImpl.existsSync(settingsFile) ? 'update' : 'create', file: settingsFile, key: 'hooks' }] : [],
142
- errors: [], commands, trust: commands.trust, scriptsDir: sourceHooksDir, destinationHooksDir, companionTargets };
143
- }
144
-
145
- function deployGeminiHooks(plan , { dryRun = false, fsImpl = fs } = {}) {
146
- if (!plan.ok) return { ...plan, applied: false };
147
- if (dryRun || plan.status === 'unchanged') return { ...plan, applied: false };
148
- fsImpl.mkdirSync(path.dirname(plan.settingsFile), { recursive: true });
149
- const content = `${JSON.stringify(plan.merged, null, 2)}\n`;
150
- const temporary = path.join(path.dirname(plan.settingsFile), `.${path.basename(plan.settingsFile)}.${process.pid}.${Date.now()}.tmp`);
151
- try {
152
- fsImpl.writeFileSync(temporary, content, { flag: 'wx' });
153
- fsImpl.renameSync(temporary, plan.settingsFile);
154
- } finally {
155
- if (fsImpl.existsSync(temporary)) fsImpl.unlinkSync(temporary);
156
- }
157
- const deployed = new Set ();
158
- for (const check of plan.commands.checks) {
159
- const target = path.join(plan.destinationHooksDir, check.script);
160
- fsImpl.mkdirSync(path.dirname(target), { recursive: true });
161
- fsImpl.copyFileSync(check.file, target);
162
- fsImpl.chmodSync(target, fsImpl.statSync(check.file).mode & 0o777);
163
- deployed.add(check.script);
164
- }
165
- if (plan.scriptsDir && fsImpl.existsSync(plan.scriptsDir)) {
166
- for (const name of fsImpl.readdirSync(plan.scriptsDir)) {
167
- if (deployed.has(name) || name.endsWith('.json')) continue;
168
- const source = path.join(plan.scriptsDir, name);
169
- if (!fsImpl.statSync(source).isFile()) continue;
170
- const target = path.join(plan.destinationHooksDir, name);
171
- fsImpl.mkdirSync(path.dirname(target), { recursive: true });
172
- fsImpl.copyFileSync(source, target);
173
- fsImpl.chmodSync(target, fsImpl.statSync(source).mode & 0o777);
174
- }
175
- }
176
- return { ...plan, applied: true };
177
- }
178
-
179
- /**
180
- * Plan stripping just the "hooks" key back out of settings.json — mirrors this codebase's
181
- * existing GEMINI.md-instructions removal (structural presence check, not a ledger fingerprint
182
- * cross-check): if the key isn't present, there's nothing to do; otherwise propose removing only
183
- * that key, leaving every other key in the shared file untouched (FR-002).
184
- */
185
- function planRemoveGeminiHooks({ settingsFile, fsImpl = fs } = {}) {
186
- if (!settingsFile) return { ok: false, status: 'invalid-request', changes: [], errors: ['settingsFile is required'] };
187
- if (!fsImpl.existsSync(settingsFile)) return { ok: true, status: 'unchanged', settingsFile, changes: [] };
188
- let existing;
189
- try { existing = JSON.parse(fsImpl.readFileSync(settingsFile, 'utf8')); }
190
- catch (error ) { return { ok: false, status: 'malformed', changes: [], errors: [`Could not parse ${settingsFile}: ${error.message}`] }; }
191
- if (existing.hooks === undefined) return { ok: true, status: 'unchanged', settingsFile, changes: [] };
192
- const { hooks: _dropped, ...merged } = existing;
193
- return { ok: true, status: 'change', settingsFile, merged, changes: [{ type: 'update', file: settingsFile, key: 'hooks', operation: 'remove' }] };
194
- }
195
-
196
- function deployRemoveGeminiHooks(plan , { dryRun = false, fsImpl = fs } = {}) {
197
- if (!plan.ok || plan.status !== 'change' || dryRun) return { ...plan, applied: false };
198
- fsImpl.mkdirSync(path.dirname(plan.settingsFile), { recursive: true });
199
- const content = `${JSON.stringify(plan.merged, null, 2)}\n`;
200
- const temporary = path.join(path.dirname(plan.settingsFile), `.${path.basename(plan.settingsFile)}.${process.pid}.${Date.now()}.tmp`);
201
- try {
202
- fsImpl.writeFileSync(temporary, content, { flag: 'wx' });
203
- fsImpl.renameSync(temporary, plan.settingsFile);
204
- } finally {
205
- if (fsImpl.existsSync(temporary)) fsImpl.unlinkSync(temporary);
206
- }
207
- return { ...plan, applied: true };
208
- }
209
-
210
- module.exports = { SUPPORTED_EVENTS, validateHooksConfig, classifyClaudeGuardrails, verifyHookCommands, planGeminiHooks, deployGeminiHooks, planRemoveGeminiHooks, deployRemoveGeminiHooks };