@khoavu882/doflow 0.0.0-stage → 2.0.0-beta.4

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 (409) hide show
  1. package/LICENSE +21 -0
  2. package/README.md +132 -2
  3. package/bin/doflow.js +44 -0
  4. package/core/.antigravity-plugin/hooks.json +39 -0
  5. package/core/.antigravity-plugin/mcp_config.json +18 -0
  6. package/core/.antigravity-plugin/plugin.json +31 -0
  7. package/core/.claude-plugin/marketplace.json +20 -0
  8. package/core/.claude-plugin/plugin.json +21 -0
  9. package/core/.codex-plugin/marketplace.json +20 -0
  10. package/core/.codex-plugin/plugin.json +35 -0
  11. package/core/.plugin/plugin.json +19 -0
  12. package/core/harnesses/antigravity/hooks/pre-implementation-gate.sh +9 -0
  13. package/core/harnesses/antigravity/hooks/stop-check.sh +10 -0
  14. package/core/harnesses/claude/hooks/lib.sh +304 -0
  15. package/core/harnesses/claude/hooks/mcp-tool-guard.sh +20 -0
  16. package/core/harnesses/claude/hooks/permission-audit.sh +47 -0
  17. package/core/harnesses/claude/hooks/post-compact.sh +74 -0
  18. package/core/harnesses/claude/hooks/post-edit-lint.sh +36 -0
  19. package/core/harnesses/claude/hooks/post-tool-failure.sh +47 -0
  20. package/core/harnesses/claude/hooks/pre-bash-guard.sh +20 -0
  21. package/core/harnesses/claude/hooks/pre-compact.sh +43 -0
  22. package/core/harnesses/claude/hooks/pre-implement-gate.sh +21 -0
  23. package/core/harnesses/claude/hooks/session-end.sh +89 -0
  24. package/core/harnesses/claude/hooks/session-start.sh +5 -0
  25. package/core/harnesses/claude/hooks/skill-config-audit.sh +39 -0
  26. package/core/harnesses/claude/hooks/stop-check.sh +5 -0
  27. package/core/harnesses/claude/hooks/subagent-audit.sh +7 -0
  28. package/core/harnesses/claude/hooks/user-prompt-submit.sh +5 -0
  29. package/core/harnesses/claude/settings/keybindings.json +20 -0
  30. package/core/harnesses/claude/settings/settings.json +201 -0
  31. package/core/harnesses/claude/statusline/doflow-statusline.sh +49 -0
  32. package/core/harnesses/codex/agents/core-implementer.toml +7 -0
  33. package/core/harnesses/codex/agents/quality-guardian.toml +8 -0
  34. package/core/harnesses/codex/agents/research-writer.toml +8 -0
  35. package/core/harnesses/codex/agents/spec-analyst.toml +8 -0
  36. package/core/harnesses/codex/agents/system-architect.toml +9 -0
  37. package/core/harnesses/codex/config/config.toml +10 -0
  38. package/core/harnesses/codex/hooks/hooks.json +122 -0
  39. package/core/harnesses/codex/hooks/lib.sh +335 -0
  40. package/core/harnesses/codex/hooks/mcp-tool-guard.sh +18 -0
  41. package/core/harnesses/codex/hooks/post-edit-lint.impl.sh +52 -0
  42. package/core/harnesses/codex/hooks/post-edit-lint.sh +6 -0
  43. package/core/harnesses/codex/hooks/pre-bash-guard.sh +18 -0
  44. package/core/harnesses/codex/hooks/pre-compact.impl.sh +46 -0
  45. package/core/harnesses/codex/hooks/pre-compact.sh +9 -0
  46. package/core/harnesses/codex/hooks/pre-implement-gate.sh +19 -0
  47. package/core/harnesses/codex/hooks/session-end.impl.sh +92 -0
  48. package/core/harnesses/codex/hooks/session-end.sh +5 -0
  49. package/core/harnesses/codex/hooks/session-start.sh +5 -0
  50. package/core/harnesses/codex/hooks/stop-check.sh +8 -0
  51. package/core/harnesses/codex/hooks/subagent-audit.sh +8 -0
  52. package/core/harnesses/codex/hooks/user-prompt-submit.sh +6 -0
  53. package/core/harnesses/gemini/hooks/hooks.json +77 -0
  54. package/core/harnesses/gemini/hooks/lib.sh +302 -0
  55. package/core/harnesses/gemini/hooks/mcp-tool-guard.sh +21 -0
  56. package/core/harnesses/gemini/hooks/post-edit-lint.sh +39 -0
  57. package/core/harnesses/gemini/hooks/pre-bash-guard.sh +21 -0
  58. package/core/harnesses/gemini/hooks/pre-compact.sh +38 -0
  59. package/core/harnesses/gemini/hooks/pre-implement-gate.sh +22 -0
  60. package/core/harnesses/gemini/hooks/session-end.impl.sh +89 -0
  61. package/core/harnesses/gemini/hooks/session-end.sh +5 -0
  62. package/core/harnesses/gemini/hooks/session-start.sh +5 -0
  63. package/core/harnesses/gemini/settings/adapter-defaults.json +4 -0
  64. package/core/harnesses/kiro/agents/doflow.json +58 -0
  65. package/core/harnesses/kiro/hooks/doflow.json +53 -0
  66. package/core/harnesses/kiro/hooks/lib.sh +324 -0
  67. package/core/harnesses/kiro/hooks/mcp-tool-guard.sh +9 -0
  68. package/core/harnesses/kiro/hooks/pre-bash-guard.sh +9 -0
  69. package/core/harnesses/kiro/hooks/pre-implement-gate.sh +9 -0
  70. package/core/harnesses/kiro/hooks/session-start.sh +9 -0
  71. package/core/harnesses/kiro/hooks/stop-check.sh +43 -0
  72. package/core/harnesses/shared/hooks/ENVELOPE_MIGRATION.md +39 -0
  73. package/core/harnesses/shared/hooks/adapters/antigravity.js +111 -0
  74. package/core/harnesses/shared/hooks/adapters/arg-fields.js +19 -0
  75. package/core/harnesses/shared/hooks/adapters/gemini.js +114 -0
  76. package/core/harnesses/shared/hooks/hooks.json +47 -0
  77. package/core/harnesses/shared/hooks/policies/blocked-patterns.conf +91 -0
  78. package/core/harnesses/shared/hooks/policies/capture-failure.sh +97 -0
  79. package/core/harnesses/shared/hooks/policies/deny-json.sh +29 -0
  80. package/core/harnesses/shared/hooks/policies/lib.sh +501 -0
  81. package/core/harnesses/shared/hooks/policies/mcp-policy.conf +21 -0
  82. package/core/harnesses/shared/hooks/policies/mcp-tool-guard.sh +91 -0
  83. package/core/harnesses/shared/hooks/policies/pre-bash-guard.sh +328 -0
  84. package/core/harnesses/shared/hooks/policies/pre-implementation-gate.sh +496 -0
  85. package/core/harnesses/shared/hooks/policies/prompt-nudge.jq +131 -0
  86. package/core/harnesses/shared/hooks/policies/session-context.sh +141 -0
  87. package/core/harnesses/shared/hooks/policies/stop-check.sh +264 -0
  88. package/core/harnesses/shared/hooks/policies/subagent-audit.sh +46 -0
  89. package/core/harnesses/shared/hooks/policies/user-prompt-submit.sh +235 -0
  90. package/core/harnesses/shared/hooks/stream-hook-runner.js +590 -0
  91. package/core/harnesses/shared/locator/doflow-run +87 -0
  92. package/core/registry/advice.json +101 -0
  93. package/core/registry/assets.json +792 -0
  94. package/core/registry/capabilities.json +120 -0
  95. package/core/registry/contracts.json +189 -0
  96. package/core/registry/external-tools.json +191 -0
  97. package/core/registry/harnesses.json +2062 -0
  98. package/core/registry/lifecycle.json +231 -0
  99. package/core/registry/mcp.json +18 -0
  100. package/core/registry/models.json +79 -0
  101. package/core/registry/readiness-templates.json +118 -0
  102. package/core/registry/routes.json +47 -0
  103. package/core/registry/storage.json +1061 -0
  104. package/core/registry/verification.json +258 -0
  105. package/core/registry/workflows.json +790 -0
  106. package/core/shared/agent-specs/core-implementer.md +73 -0
  107. package/core/shared/agent-specs/quality-guardian.md +28 -0
  108. package/core/shared/agent-specs/research-writer.md +31 -0
  109. package/core/shared/agent-specs/spec-analyst.md +33 -0
  110. package/core/shared/agent-specs/system-architect.md +29 -0
  111. package/core/shared/guidance/DOFLOW_CORE.md +8 -0
  112. package/core/shared/guidance/FLAGS.md +25 -0
  113. package/core/shared/guidance/PRINCIPLES.md +61 -0
  114. package/core/shared/guidance/VERSION +1 -0
  115. package/core/shared/guidance/mcp/MCP_Context7.md +18 -0
  116. package/core/shared/guidance/mcp/MCP_Sequential.md +17 -0
  117. package/core/shared/guidance/modes/MODE_Brainstorming.md +46 -0
  118. package/core/shared/guidance/modes/MODE_DeepResearch.md +69 -0
  119. package/core/shared/guidance/modes/MODE_Introspection.md +33 -0
  120. package/core/shared/guidance/modes/MODE_Orchestration.md +57 -0
  121. package/core/shared/guidance/modes/MODE_Task_Management.md +74 -0
  122. package/core/shared/guidance/pointers/claude-gemini.md +2 -0
  123. package/core/shared/guidance/pointers/codex.md +6 -0
  124. package/core/shared/guidance/references/ARTIFACT_FORMAT.md +373 -0
  125. package/core/shared/guidance/references/ARTIFACT_VOICE.md +104 -0
  126. package/core/shared/guidance/references/CONSTITUTION_BASE.md +47 -0
  127. package/core/shared/guidance/references/DIAGRAM_GUIDE.md +161 -0
  128. package/core/shared/guidance/references/DOFLOW_CHAIN.md +87 -0
  129. package/core/shared/guidance/references/EVIDENCE_LEDGER.md +93 -0
  130. package/core/shared/guidance/references/MODEL_SELECTION.md +74 -0
  131. package/core/shared/guidance/references/ORCHESTRATION.md +36 -0
  132. package/core/shared/guidance/references/RESEARCH_CONFIG.md +21 -0
  133. package/core/shared/guidance/references/WORKFLOW_HANDOFF.md +81 -0
  134. package/core/shared/guidance/rules/RULE_01_SAFETY.md +25 -0
  135. package/core/shared/guidance/rules/RULE_02_WORKFLOW.md +23 -0
  136. package/core/shared/guidance/rules/RULE_03_QUALITY.md +14 -0
  137. package/core/shared/guidance/rules/RULE_04_QUESTIONS.md +46 -0
  138. package/core/shared/scripts/doflow/assets/mermaid-theme.json +46 -0
  139. package/core/shared/scripts/doflow/bash/do-exec-paths.sh +167 -0
  140. package/core/shared/scripts/doflow/bash/do-git-state.sh +546 -0
  141. package/core/shared/scripts/doflow/bash/do-parallel-check.sh +208 -0
  142. package/core/shared/scripts/doflow/bash/do-paths.sh +347 -0
  143. package/core/shared/scripts/doflow/bash/do-prereqs.sh +66 -0
  144. package/core/shared/scripts/doflow/bash/do-review-package.sh +127 -0
  145. package/core/shared/scripts/doflow/bash/do-task-brief.sh +698 -0
  146. package/core/shared/scripts/doflow/bash/render-audit.sh +224 -0
  147. package/core/shared/scripts/doflow/bash/render-diagrams.sh +177 -0
  148. package/core/shared/scripts/doflow/bash/render-puml.sh +223 -0
  149. package/core/shared/scripts/doflow/bash/sync-context.sh +66 -0
  150. package/core/shared/scripts/doflow/bash/validate-artifacts.sh +526 -0
  151. package/core/shared/scripts/doflow/bin/doflow-run +592 -0
  152. package/core/shared/skills/do/SKILL.md +128 -0
  153. package/core/shared/skills/do/references/estimation.md +13 -0
  154. package/core/shared/skills/do/references/pm_routing.md +25 -0
  155. package/core/shared/skills/do/references/tool_matrix.md +52 -0
  156. package/core/shared/skills/do-brainstorm/SKILL.md +252 -0
  157. package/core/shared/skills/do-code-review/README.md +49 -0
  158. package/core/shared/skills/do-code-review/SKILL.md +333 -0
  159. package/core/shared/skills/do-code-review/assets/sample_c_clean.c +71 -0
  160. package/core/shared/skills/do-code-review/assets/sample_c_smells.c +66 -0
  161. package/core/shared/skills/do-code-review/assets/sample_cpp_shift.cpp +19 -0
  162. package/core/shared/skills/do-code-review/assets/sample_csharp_clean.cs +100 -0
  163. package/core/shared/skills/do-code-review/assets/sample_csharp_smells.cs +78 -0
  164. package/core/shared/skills/do-code-review/assets/sample_java_clean.java +55 -0
  165. package/core/shared/skills/do-code-review/assets/sample_java_smells.java +56 -0
  166. package/core/shared/skills/do-code-review/assets/sample_json_clean.json +7 -0
  167. package/core/shared/skills/do-code-review/assets/sample_markdown_clean.md +30 -0
  168. package/core/shared/skills/do-code-review/assets/sample_markdown_smells.md +29 -0
  169. package/core/shared/skills/do-code-review/assets/sample_shell_heredoc.sh +38 -0
  170. package/core/shared/skills/do-code-review/assets/sample_shell_smells.sh +15 -0
  171. package/core/shared/skills/do-code-review/assets/sample_typescript_strings.ts +36 -0
  172. package/core/shared/skills/do-code-review/assets/sample_yaml_smells.yaml +6 -0
  173. package/core/shared/skills/do-code-review/content-types/config.md +83 -0
  174. package/core/shared/skills/do-code-review/content-types/markdown.md +132 -0
  175. package/core/shared/skills/do-code-review/expected_outputs/sample_c_clean_quality.json +79 -0
  176. package/core/shared/skills/do-code-review/expected_outputs/sample_c_smells_quality.json +169 -0
  177. package/core/shared/skills/do-code-review/expected_outputs/sample_cpp_shift_quality.json +49 -0
  178. package/core/shared/skills/do-code-review/expected_outputs/sample_csharp_clean_quality.json +149 -0
  179. package/core/shared/skills/do-code-review/expected_outputs/sample_csharp_smells_quality.json +157 -0
  180. package/core/shared/skills/do-code-review/expected_outputs/sample_java_clean_quality.json +67 -0
  181. package/core/shared/skills/do-code-review/expected_outputs/sample_java_smells_quality.json +97 -0
  182. package/core/shared/skills/do-code-review/expected_outputs/sample_json_clean_quality.json +33 -0
  183. package/core/shared/skills/do-code-review/expected_outputs/sample_markdown_clean_quality.json +1 -0
  184. package/core/shared/skills/do-code-review/expected_outputs/sample_markdown_smells_quality.json +16 -0
  185. package/core/shared/skills/do-code-review/expected_outputs/sample_shell_heredoc_quality.json +54 -0
  186. package/core/shared/skills/do-code-review/expected_outputs/sample_shell_smells_quality.json +91 -0
  187. package/core/shared/skills/do-code-review/expected_outputs/sample_typescript_strings_quality.json +60 -0
  188. package/core/shared/skills/do-code-review/expected_outputs/sample_yaml_smells_quality.json +46 -0
  189. package/core/shared/skills/do-code-review/languages/c.md +103 -0
  190. package/core/shared/skills/do-code-review/languages/cpp.md +103 -0
  191. package/core/shared/skills/do-code-review/languages/csharp.md +97 -0
  192. package/core/shared/skills/do-code-review/languages/dart.md +108 -0
  193. package/core/shared/skills/do-code-review/languages/go.md +92 -0
  194. package/core/shared/skills/do-code-review/languages/java.md +103 -0
  195. package/core/shared/skills/do-code-review/languages/kotlin.md +88 -0
  196. package/core/shared/skills/do-code-review/languages/php.md +109 -0
  197. package/core/shared/skills/do-code-review/languages/python.md +94 -0
  198. package/core/shared/skills/do-code-review/languages/ruby.md +105 -0
  199. package/core/shared/skills/do-code-review/languages/rust.md +99 -0
  200. package/core/shared/skills/do-code-review/languages/shell.md +90 -0
  201. package/core/shared/skills/do-code-review/languages/swift.md +88 -0
  202. package/core/shared/skills/do-code-review/languages/typescript.md +97 -0
  203. package/core/shared/skills/do-code-review/review-policy.json +47 -0
  204. package/core/shared/skills/do-code-review/rules/universal.md +49 -0
  205. package/core/shared/skills/do-code-review/scripts/code_quality_checker.py +1696 -0
  206. package/core/shared/skills/do-code-review/scripts/doc_quality_checker.py +532 -0
  207. package/core/shared/skills/do-code-review/scripts/pr_analyzer.py +620 -0
  208. package/core/shared/skills/do-code-review/scripts/review_report_generator.py +505 -0
  209. package/core/shared/skills/do-constitution/SKILL.md +72 -0
  210. package/core/shared/skills/do-design/SKILL.md +212 -0
  211. package/core/shared/skills/do-diagnose/SKILL.md +156 -0
  212. package/core/shared/skills/do-diagnose/references/code_audit.md +15 -0
  213. package/core/shared/skills/do-diagnose/references/refactoring.md +12 -0
  214. package/core/shared/skills/do-diagnose/references/root_cause.md +17 -0
  215. package/core/shared/skills/do-document/SKILL.md +81 -0
  216. package/core/shared/skills/do-document/references/api-reference.md +42 -0
  217. package/core/shared/skills/do-document/references/deep_research.md +18 -0
  218. package/core/shared/skills/do-document/references/embedded-research.md +11 -0
  219. package/core/shared/skills/do-document/references/implementation-flow.md +105 -0
  220. package/core/shared/skills/do-document/references/index_generator.md +9 -0
  221. package/core/shared/skills/do-document/references/user-guide.md +22 -0
  222. package/core/shared/skills/do-execute-plan/SKILL.md +261 -0
  223. package/core/shared/skills/do-execute-plan/references/handoff_record.md +57 -0
  224. package/core/shared/skills/do-execute-plan/references/parallel_dispatch.md +92 -0
  225. package/core/shared/skills/do-execute-plan/references/readiness_gate.md +155 -0
  226. package/core/shared/skills/do-execute-plan/references/run_position.md +63 -0
  227. package/core/shared/skills/do-execute-plan/references/scaffold.md +441 -0
  228. package/core/shared/skills/do-execute-plan/references/task_attempts.md +41 -0
  229. package/core/shared/skills/do-flow/SKILL.md +186 -0
  230. package/core/shared/skills/do-flow/references/task_classes.md +134 -0
  231. package/core/shared/skills/do-git/SKILL.md +115 -0
  232. package/core/shared/skills/do-git/references/hotfix-ritual.md +44 -0
  233. package/core/shared/skills/do-git/references/lifecycle-policy.md +54 -0
  234. package/core/shared/skills/do-git/references/release-ritual.md +64 -0
  235. package/core/shared/skills/do-implement/SKILL.md +222 -0
  236. package/core/shared/skills/do-plan/SKILL.md +219 -0
  237. package/core/shared/skills/do-test/SKILL.md +113 -0
  238. package/core/shared/templates/doflow/constitution-template.md +28 -0
  239. package/core/shared/templates/doflow/data-model-template.md +169 -0
  240. package/core/shared/templates/doflow/design-template.md +193 -0
  241. package/core/shared/templates/doflow/external-contract-template.md +35 -0
  242. package/core/shared/templates/doflow/intent-template.md +45 -0
  243. package/core/shared/templates/doflow/plan-template.md +151 -0
  244. package/core/shared/templates/doflow/question-log-template.md +51 -0
  245. package/core/shared/templates/doflow/requirement-template.md +126 -0
  246. package/core/shared/templates/doflow/specs-template.md +55 -0
  247. package/core/shared/templates/doflow/state-template.md +59 -0
  248. package/core/shared/workflows/do-flow-chain.md +17 -0
  249. package/package.json +48 -4
  250. package/src/adapters/antigravity/index.js +631 -0
  251. package/src/adapters/claude/index.js +548 -0
  252. package/src/adapters/claude/mcp.js +94 -0
  253. package/src/adapters/codex/agents.js +208 -0
  254. package/src/adapters/codex/config.js +272 -0
  255. package/src/adapters/codex/hooks.js +203 -0
  256. package/src/adapters/codex/index.js +707 -0
  257. package/src/adapters/codex/mcp.js +271 -0
  258. package/src/adapters/codex/native-projection.js +34 -0
  259. package/src/adapters/copilot/index.js +413 -0
  260. package/src/adapters/copy-tree.js +620 -0
  261. package/src/adapters/gemini/hooks.js +210 -0
  262. package/src/adapters/gemini/index.js +390 -0
  263. package/src/adapters/hook-commands.js +60 -0
  264. package/src/adapters/index.js +106 -0
  265. package/src/adapters/kiro/index.js +310 -0
  266. package/src/adapters/mcp-entries.js +331 -0
  267. package/src/adapters/opencode/index.js +466 -0
  268. package/src/adapters/pi/index.js +279 -0
  269. package/src/adapters/pi/json-members.js +185 -0
  270. package/src/adapters/pi/mcp.js +373 -0
  271. package/src/adapters/resolve-source.js +19 -0
  272. package/src/cli/commands/install.js +218 -0
  273. package/src/cli/commands/list-backups.js +21 -0
  274. package/src/cli/commands/reconcile.js +120 -0
  275. package/src/cli/commands/remove.js +82 -0
  276. package/src/cli/commands/rollback.js +172 -0
  277. package/src/cli/commands/self-update.js +33 -0
  278. package/src/cli/commands/status.js +138 -0
  279. package/src/cli/commands/tools.js +92 -0
  280. package/src/cli/commands/update.js +162 -0
  281. package/src/cli/index.js +568 -0
  282. package/src/cli/runtime-commands.js +281 -0
  283. package/src/cli/shared.js +218 -0
  284. package/src/helper/bash-helper.js +34 -0
  285. package/src/helper/git.js +24 -0
  286. package/src/helper/guardrails.js +49 -0
  287. package/src/helper/harness-paths.js +140 -0
  288. package/src/helper/marker-merge.js +116 -0
  289. package/src/helper/prompt.js +61 -0
  290. package/src/helper/repo-root.js +29 -0
  291. package/src/helper/settings-merge.js +151 -0
  292. package/src/helper/settings-scope.js +33 -0
  293. package/src/helper/toml.js +244 -0
  294. package/src/install/backup-set.js +149 -0
  295. package/src/install/backup.js +724 -0
  296. package/src/install/context.js +58 -0
  297. package/src/install/manifest.js +145 -0
  298. package/src/install/mcp.js +254 -0
  299. package/src/install/paths.js +84 -0
  300. package/src/install/targets.js +90 -0
  301. package/src/install/tool-lifecycle.js +151 -0
  302. package/src/lifecycle/bash-availability.js +25 -0
  303. package/src/lifecycle/index.js +812 -0
  304. package/src/lifecycle/mcp-index.js +28 -0
  305. package/src/lifecycle/policies.js +73 -0
  306. package/src/lifecycle/view.js +175 -0
  307. package/src/registry/index.js +611 -0
  308. package/src/release/build-package.js +91 -0
  309. package/src/release/changelog-section.js +70 -0
  310. package/src/release/sync-plugin-versions.js +66 -0
  311. package/src/runtime/advice/cli.js +283 -0
  312. package/src/runtime/advice/client.js +324 -0
  313. package/src/runtime/advice/config.js +189 -0
  314. package/src/runtime/advice/doctor.js +169 -0
  315. package/src/runtime/advice/endpoint-guard.js +134 -0
  316. package/src/runtime/advice/kinds.js +154 -0
  317. package/src/runtime/advice/providers/ollama-systemone.js +209 -0
  318. package/src/runtime/advice/record.js +166 -0
  319. package/src/runtime/advice/registry.js +170 -0
  320. package/src/runtime/advice/strength.js +66 -0
  321. package/src/runtime/brief-tools.js +342 -0
  322. package/src/runtime/c4-project.js +371 -0
  323. package/src/runtime/capability-router.js +484 -0
  324. package/src/runtime/checkouts.js +170 -0
  325. package/src/runtime/claims.js +468 -0
  326. package/src/runtime/cli-result.js +55 -0
  327. package/src/runtime/cli.js +678 -0
  328. package/src/runtime/command-detect.js +516 -0
  329. package/src/runtime/context-pack.js +492 -0
  330. package/src/runtime/decision-register.js +493 -0
  331. package/src/runtime/evidence-ledger.js +338 -0
  332. package/src/runtime/failure/capture.js +272 -0
  333. package/src/runtime/failure/classifier.js +68 -0
  334. package/src/runtime/failure/cli.js +178 -0
  335. package/src/runtime/failure/home.js +64 -0
  336. package/src/runtime/failure/store.js +226 -0
  337. package/src/runtime/feature-resolve.js +79 -0
  338. package/src/runtime/freshness.js +177 -0
  339. package/src/runtime/health.js +863 -0
  340. package/src/runtime/history-compactor.js +237 -0
  341. package/src/runtime/implementation-gate.js +321 -0
  342. package/src/runtime/inventory/coverage.js +218 -0
  343. package/src/runtime/inventory/identity.js +65 -0
  344. package/src/runtime/inventory/index.js +705 -0
  345. package/src/runtime/inventory/precedence.js +134 -0
  346. package/src/runtime/inventory/read-scopes.js +131 -0
  347. package/src/runtime/inventory/siblings.js +192 -0
  348. package/src/runtime/knowledge/chunker.js +124 -0
  349. package/src/runtime/knowledge/hybrid.js +149 -0
  350. package/src/runtime/knowledge/index-store.js +145 -0
  351. package/src/runtime/knowledge/retrieval.js +194 -0
  352. package/src/runtime/leak-scan.js +185 -0
  353. package/src/runtime/lifecycle/cli.js +276 -0
  354. package/src/runtime/lifecycle/event-store.js +340 -0
  355. package/src/runtime/lifecycle/fold.js +353 -0
  356. package/src/runtime/lifecycle/followup.js +432 -0
  357. package/src/runtime/lifecycle/goal.js +249 -0
  358. package/src/runtime/lifecycle/intent-writer.js +86 -0
  359. package/src/runtime/lifecycle/overview.js +292 -0
  360. package/src/runtime/lifecycle/release.js +241 -0
  361. package/src/runtime/lifecycle/report-store.js +221 -0
  362. package/src/runtime/lifecycle/retention.js +212 -0
  363. package/src/runtime/lifecycle/root.js +71 -0
  364. package/src/runtime/lifecycle/status.js +353 -0
  365. package/src/runtime/lifecycle/store-upkeep.js +393 -0
  366. package/src/runtime/locator-resolve.js +158 -0
  367. package/src/runtime/mask.js +210 -0
  368. package/src/runtime/mcp-consultations.js +412 -0
  369. package/src/runtime/mcp-reach.js +157 -0
  370. package/src/runtime/model-router.js +153 -0
  371. package/src/runtime/outcome.js +467 -0
  372. package/src/runtime/reach.js +148 -0
  373. package/src/runtime/readiness-record.js +150 -0
  374. package/src/runtime/readiness.js +435 -0
  375. package/src/runtime/recovery.js +282 -0
  376. package/src/runtime/research-request.js +231 -0
  377. package/src/runtime/retrieval-plan.js +578 -0
  378. package/src/runtime/scaffold/artifacts.js +217 -0
  379. package/src/runtime/scaffold/fingerprint.js +56 -0
  380. package/src/runtime/scaffold/generate.js +911 -0
  381. package/src/runtime/scaffold/languages.js +245 -0
  382. package/src/runtime/storage/cli.js +64 -0
  383. package/src/runtime/storage/engine.js +249 -0
  384. package/src/runtime/storage/registry.js +130 -0
  385. package/src/runtime/storage/roots.js +63 -0
  386. package/src/runtime/storage/rules.js +282 -0
  387. package/src/runtime/storage/upkeep.js +243 -0
  388. package/src/runtime/storage/work-status.js +326 -0
  389. package/src/runtime/task-attempts.js +415 -0
  390. package/src/runtime/task-classifier.js +550 -0
  391. package/src/runtime/task-scope.js +130 -0
  392. package/src/runtime/task-state.js +176 -0
  393. package/src/runtime/trace/indicators.js +235 -0
  394. package/src/runtime/trace/ledger.js +626 -0
  395. package/src/runtime/trace/render.js +76 -0
  396. package/src/runtime/trace/views.js +459 -0
  397. package/src/runtime/verification/contract-runner.js +341 -0
  398. package/src/runtime/verification/engine.js +1461 -0
  399. package/src/runtime/verification/registry.js +130 -0
  400. package/src/runtime/verification/scope-bound.js +418 -0
  401. package/src/runtime/verification/test-selection.js +172 -0
  402. package/src/runtime/workflow-engine.js +588 -0
  403. package/src/runtime/workflow-orchestrator.js +953 -0
  404. package/src/runtime/worktree.js +340 -0
  405. package/src/state/index.js +193 -0
  406. package/src/state/lockfile.js +136 -0
  407. package/src/state/run-lock.js +408 -0
  408. package/types/node-commonjs.d.ts +68 -0
  409. package/types/runtime.d.ts +91 -0
@@ -0,0 +1,77 @@
1
+ {
2
+ "description": "DoFlow lifecycle hooks for Gemini CLI. Gemini fingerprints hook name/command and warns before executing a changed one.",
3
+ "hooks": {
4
+ "SessionStart": [
5
+ {
6
+ "hooks": [
7
+ {
8
+ "type": "command",
9
+ "command": "bash \"$GEMINI_PROJECT_DIR/.gemini/hooks/session-start.sh\""
10
+ }
11
+ ]
12
+ }
13
+ ],
14
+ "SessionEnd": [
15
+ {
16
+ "hooks": [
17
+ {
18
+ "type": "command",
19
+ "command": "bash \"$GEMINI_PROJECT_DIR/.gemini/hooks/session-end.sh\"",
20
+ "timeout": 3000
21
+ }
22
+ ]
23
+ }
24
+ ],
25
+ "BeforeTool": [
26
+ {
27
+ "matcher": "^run_shell_command$",
28
+ "hooks": [
29
+ {
30
+ "type": "command",
31
+ "command": "bash \"$GEMINI_PROJECT_DIR/.gemini/hooks/pre-bash-guard.sh\""
32
+ }
33
+ ]
34
+ },
35
+ {
36
+ "matcher": "^mcp_.*",
37
+ "hooks": [
38
+ {
39
+ "type": "command",
40
+ "command": "bash \"$GEMINI_PROJECT_DIR/.gemini/hooks/mcp-tool-guard.sh\""
41
+ }
42
+ ]
43
+ },
44
+ {
45
+ "matcher": "^(write_file|replace)$",
46
+ "hooks": [
47
+ {
48
+ "type": "command",
49
+ "command": "bash \"$GEMINI_PROJECT_DIR/.gemini/hooks/pre-implement-gate.sh\""
50
+ }
51
+ ]
52
+ }
53
+ ],
54
+ "AfterTool": [
55
+ {
56
+ "matcher": "^(write_file|replace)$",
57
+ "hooks": [
58
+ {
59
+ "type": "command",
60
+ "command": "bash \"$GEMINI_PROJECT_DIR/.gemini/hooks/post-edit-lint.sh\""
61
+ }
62
+ ]
63
+ }
64
+ ],
65
+ "PreCompress": [
66
+ {
67
+ "hooks": [
68
+ {
69
+ "type": "command",
70
+ "command": "bash \"$GEMINI_PROJECT_DIR/.gemini/hooks/pre-compact.sh\"",
71
+ "timeout": 3000
72
+ }
73
+ ]
74
+ }
75
+ ]
76
+ }
77
+ }
@@ -0,0 +1,302 @@
1
+ #!/usr/bin/env bash
2
+ # lib.sh — shared constants and helpers for session lifecycle hooks
3
+ #
4
+ # Usage: source "$(dirname "$0")/lib.sh"
5
+ #
6
+ # All hooks must:
7
+ # 1. source this file at the top
8
+ # 2. call require_jq immediately after
9
+ # 3. capture stdin once: INPUT=$(cat)
10
+ # 4. use: json_field "$INPUT" ".field_name"
11
+ #
12
+ # Deployment:
13
+ # This file is installed by the doflow CLI and overwritten on update — do
14
+ # not edit an installed copy directly.
15
+
16
+ set -euo pipefail
17
+
18
+ # ── State directories ────────────────────────────────────────────────────────
19
+
20
+ # XDG-compliant, agent-agnostic store shared by Claude Code, Codex, Gemini, etc.
21
+ DOFLOW_HOME="${XDG_CONFIG_HOME:-$HOME/.config}/doflow"
22
+ STATE_DIR="$DOFLOW_HOME/session-env"
23
+ SESSION_DIR="$STATE_DIR/sessions"
24
+ PROJECTS_DIR="$STATE_DIR/projects"
25
+ # shellcheck disable=SC2034 # used by session-start.sh and session-end.sh which source this file
26
+ SESSIONS_LOG="$DOFLOW_HOME/sessions.log"
27
+
28
+ # Identifies which agent is running. Override via env var for non-Claude agents.
29
+ export DOFLOW_AGENT="${DOFLOW_AGENT:-unknown}"
30
+
31
+ # ── Portability primitives ───────────────────────────────────────────────────
32
+ #
33
+ # The helpers in this section replace non-portable GNU/Linux-only dependencies
34
+ # (realpath -e, flock, GNU timeout, bare sha256sum) with equivalents that run
35
+ # on stock macOS, Git Bash/MSYS2, and common Linux distros without requiring
36
+ # any additional package install (no Homebrew coreutils assumed).
37
+
38
+ # Print an absolute, symlink-resolved form of <path> to stdout when <path>
39
+ # exists; otherwise print <path> unchanged. Replaces `realpath -e "$1" ||
40
+ # echo "$1"`, which already fails silently on stock macOS (BSD realpath has
41
+ # no -e flag) and falls back to an uncanonicalized path. Uses only primitives
42
+ # present on every target: cd, pwd -P, dirname, basename.
43
+ #
44
+ # Hardening notes:
45
+ # - `CDPATH=` resets CDPATH for the internal `cd` so a user's exported
46
+ # CDPATH can't redirect it to an unrelated directory of the same name
47
+ # (and can't make `cd` echo a stray "found via CDPATH" line to stdout).
48
+ # - `--` guards `dirname`/`basename`/`cd` against a path that begins with
49
+ # `-` being parsed as an option.
50
+ # - if the internal `cd` fails for any reason, `||` falls through to the
51
+ # uncanonicalized-path branch instead of aborting under this file's
52
+ # `set -e` (matching the old `realpath ... || echo "$1"` degrade path).
53
+ # - a root-level parent directory ("/") is special-cased so the result
54
+ # never gets a leading `//`, which POSIX leaves undefined and which
55
+ # Cygwin/MSYS2 (a DoFlow target platform) interprets as a UNC path.
56
+ canonicalize_path() {
57
+ local path="$1" dir base
58
+ if [[ -e "$path" ]] \
59
+ && dir=$(CDPATH= cd -P -- "$(dirname -- "$path")" 2>/dev/null && pwd -P); then
60
+ base=$(basename -- "$path")
61
+ if [[ "$dir" == "/" ]]; then
62
+ printf '/%s\n' "$base"
63
+ else
64
+ printf '%s/%s\n' "$dir" "$base"
65
+ fi
66
+ else
67
+ printf '%s\n' "$path"
68
+ fi
69
+ }
70
+
71
+ # Internal: age in whole seconds of <path>'s mtime, or nothing (and a
72
+ # non-zero return) if it cannot be determined. Handles both GNU stat
73
+ # (-c %Y) and BSD/macOS stat (-f %m) since this file assumes neither.
74
+ lock_dir_age_seconds() {
75
+ local path="$1"
76
+ local mtime
77
+ mtime=$(stat -c %Y "$path" 2>/dev/null) || mtime=$(stat -f %m "$path" 2>/dev/null) || return 1
78
+ echo $(( $(date +%s) - mtime ))
79
+ }
80
+
81
+ # A lock dir older than this is presumed abandoned (holder crashed or was
82
+ # killed before it could release) and eligible for reclaim. Deliberately
83
+ # independent of any given with_file_lock call's own <timeout_seconds>: a
84
+ # caller's polling budget is "how long am I willing to wait," which is
85
+ # unrelated to "is the current holder still plausibly alive." Reusing
86
+ # timeout_seconds for both would let a live holder's lock get stolen out
87
+ # from under it the moment a contending caller's own wait approaches its
88
+ # timeout — reclaim needs a threshold generous enough that no legitimate
89
+ # hook invocation is still running, not tied to a contender's patience.
90
+ LOCK_STALE_SECONDS=${LOCK_STALE_SECONDS:-300}
91
+
92
+ # Acquire an exclusive lock on <lockfile>, using atomic mkdir (atomic on
93
+ # every filesystem DoFlow runs on, including NTFS via MSYS2). Replaces
94
+ # `flock -x -w <seconds> 200`, which is confirmed absent entirely on macOS
95
+ # (util-linux only). Gives up after <timeout_seconds> instead of blocking
96
+ # indefinitely, returning non-zero on timeout.
97
+ #
98
+ # Unlike `flock`, a `mkdir`-based lock has no kernel-backed release on
99
+ # holder crash/kill, so this also reclaims the lock directory once it is
100
+ # older than LOCK_STALE_SECONDS (treating it as abandoned), and separately
101
+ # clears — rather than waits out the full timeout on — a non-directory
102
+ # occupying <lockfile>, since a live holder created here always makes a
103
+ # directory. That second case matters on upgrade: hosts that ran the old
104
+ # `flock -x 200>"$LOCK_FILE"` implementation already have a *regular file*
105
+ # at that path, which `mkdir` would otherwise EEXIST against forever.
106
+ #
107
+ # Calling convention: on success, installs a matching release via an EXIT
108
+ # trap (fires on normal exit, on `set -e` abort, and on a killed subshell —
109
+ # unlike a RETURN trap, which never fires for a top-level script, only for
110
+ # a function return), so the caller does not need to remember to release:
111
+ #
112
+ # if with_file_lock "$lockfile" 5; then
113
+ # ... guarded section ...
114
+ # else
115
+ # echo "[hooks] timed out waiting for lock: $lockfile" >&2
116
+ # fi
117
+ with_file_lock() {
118
+ local lockfile="$1"
119
+ local timeout_seconds="$2"
120
+ local waited=0 age
121
+ while true; do
122
+ if mkdir "$lockfile" 2>/dev/null; then
123
+ trap 'release_file_lock "'"$lockfile"'"' EXIT
124
+ return 0
125
+ fi
126
+ if [[ -e "$lockfile" && ! -d "$lockfile" ]]; then
127
+ rm -f "$lockfile" 2>/dev/null || true
128
+ continue
129
+ fi
130
+ if [[ -d "$lockfile" ]]; then
131
+ age=$(lock_dir_age_seconds "$lockfile") || age=""
132
+ if [[ -n "$age" ]] && (( age >= LOCK_STALE_SECONDS )); then
133
+ rmdir "$lockfile" 2>/dev/null || true
134
+ continue
135
+ fi
136
+ fi
137
+ if (( waited >= timeout_seconds )); then
138
+ return 1
139
+ fi
140
+ sleep 1
141
+ waited=$((waited + 1))
142
+ done
143
+ }
144
+
145
+ # Release a lock acquired with with_file_lock. Normally invoked via the
146
+ # EXIT trap with_file_lock installs on success; safe to call directly too.
147
+ release_file_lock() {
148
+ local lockfile="$1"
149
+ rmdir "$lockfile" 2>/dev/null || true
150
+ }
151
+
152
+ # Run <command...> (after a literal `--` separator), terminating it if it
153
+ # exceeds <seconds>. Replaces a bare dependency on GNU `timeout`, which is
154
+ # not installed by default on stock macOS without Homebrew coreutils. When
155
+ # neither `timeout` nor `gtimeout` is on PATH, runs <command...> directly
156
+ # with no enforced budget (soft safety net, not a correctness requirement).
157
+ #
158
+ # `command -v timeout` is verified to actually be GNU coreutils' `timeout`
159
+ # before use: Git Bash inherits the Windows PATH, where `timeout` can
160
+ # resolve to System32's interactive delay command instead — a completely
161
+ # different, incompatible CLI that would reject our arguments and prevent
162
+ # the wrapped command from running at all. `timeout --version` succeeds
163
+ # only on the GNU coreutils build; the Windows binary errors on it.
164
+ #
165
+ # Usage: run_with_timeout 5 -- some_command --with --args
166
+ run_with_timeout() {
167
+ local seconds="$1"
168
+ shift
169
+ if [[ "${1:-}" == "--" ]]; then
170
+ shift
171
+ fi
172
+ if command -v timeout &>/dev/null && timeout --version &>/dev/null; then
173
+ timeout "$seconds" "$@"
174
+ elif command -v gtimeout &>/dev/null; then
175
+ gtimeout "$seconds" "$@"
176
+ else
177
+ "$@"
178
+ fi
179
+ }
180
+
181
+ # ── cwd_hash ─────────────────────────────────────────────────────────────────
182
+
183
+ # Derive a stable 16-char hash of an absolute directory path.
184
+ # Used to namespace per-project state (compact summaries, warnings).
185
+ # Normalizes symlinks and ../ components so equivalent paths hash identically.
186
+ #
187
+ # For a path that is (or resolves to) an existing directory — the case this
188
+ # function exists for — fully resolves it, including a symlink at the path's
189
+ # own leaf component, via `(cd "$1" && pwd -P)`, so equivalent directories
190
+ # always hash identically. Callers that ever pass a non-directory or
191
+ # nonexistent path fall back to the general-purpose canonicalize_path, which
192
+ # — being usable by any file or missing path, not just directories — only
193
+ # resolves symlinks in the parent chain, not the leaf itself.
194
+ cwd_hash() {
195
+ local canonical
196
+ if [ -d "$1" ]; then
197
+ canonical=$(cd "$1" && pwd -P)
198
+ else
199
+ canonical=$(canonicalize_path "$1")
200
+ fi
201
+ if command -v sha256sum &>/dev/null; then
202
+ echo "$canonical" | sha256sum | cut -c1-16
203
+ elif command -v shasum &>/dev/null; then
204
+ echo "$canonical" | shasum -a 256 | cut -c1-16
205
+ else
206
+ printf '%016x\n' "$(echo "$canonical" | cksum | cut -d' ' -f1)"
207
+ fi
208
+ }
209
+
210
+ # ── Git state helpers ────────────────────────────────────────────────────────
211
+ #
212
+ # Thin wrappers around `git -C <cwd> ...` with the project's standard 1s
213
+ # timeout. Each echoes git's own output (or nothing/0 on failure) and leaves
214
+ # stderr suppressed -- callers keep their own `|| echo <fallback>` around a
215
+ # call for a script-specific default, exactly as the inline git calls these
216
+ # replace did (022-hooks-remaining-duplication). Kept in this per-harness
217
+ # copy rather than moved to the canonical lib.sh's sourcing path: this
218
+ # script's own with_file_lock/other APIs have not been reconciled with the
219
+ # canonical copy, so repointing the `source` line is a separate, larger
220
+ # change this refactor does not make.
221
+
222
+ is_git_worktree() {
223
+ run_with_timeout 1 -- git -C "$1" rev-parse --is-inside-work-tree &>/dev/null
224
+ }
225
+
226
+ git_branch_of() {
227
+ run_with_timeout 1 -- git -C "$1" branch --show-current 2>/dev/null
228
+ }
229
+
230
+ git_short_sha_of() {
231
+ run_with_timeout 1 -- git -C "$1" rev-parse --short HEAD 2>/dev/null
232
+ }
233
+
234
+ git_uncommitted_count_of() {
235
+ run_with_timeout 1 -- git -C "$1" status --porcelain 2>/dev/null | wc -l | tr -d ' '
236
+ }
237
+
238
+ has_uncommitted_changes() {
239
+ run_with_timeout 1 -- git -C "$1" status --porcelain 2>/dev/null | grep -q .
240
+ }
241
+
242
+ # ── Directory helpers ─────────────────────────────────────────────────────────
243
+
244
+ # Create and return the session-scoped state directory for a given session_id.
245
+ # Safe to call multiple times (mkdir -p is idempotent).
246
+ ensure_session_dir() {
247
+ local session_id="$1"
248
+ mkdir -p "$SESSION_DIR/$session_id"
249
+ echo "$SESSION_DIR/$session_id"
250
+ }
251
+
252
+ # Create and return the project-scoped state directory for a given cwd.
253
+ # Shared across all sessions in the same directory.
254
+ ensure_project_dir() {
255
+ local cwd="$1"
256
+ local hash
257
+ hash=$(cwd_hash "$cwd")
258
+ mkdir -p "$PROJECTS_DIR/$hash"
259
+ echo "$PROJECTS_DIR/$hash"
260
+ }
261
+
262
+ # ── JSON helpers ──────────────────────────────────────────────────────────────
263
+
264
+ # Extract a field from a JSON string.
265
+ # Usage: json_field "$INPUT" ".field_name"
266
+ # Returns empty string if field is null or jq fails.
267
+ json_field() {
268
+ local json="$1"
269
+ local query="$2"
270
+ echo "$json" | jq -r "$query // empty" 2>/dev/null || echo ""
271
+ }
272
+
273
+ # ── Dependency guard ──────────────────────────────────────────────────────────
274
+
275
+ # Verify jq is available at runtime. If absent, emit a diagnostic to stderr
276
+ # and exit 0 (never block the harness — degraded operation is preferable to failure).
277
+ require_jq() {
278
+ if ! command -v jq &>/dev/null; then
279
+ echo "[hooks] jq not found — install jq to enable session lifecycle hooks (apt install jq / brew install jq)" >&2
280
+ exit 0
281
+ fi
282
+ }
283
+
284
+ # ── Session role ──────────────────────────────────────────────────────────────
285
+
286
+ # Print `main` or `worker` for this session, read from DOFLOW_SESSION_ROLE (matched
287
+ # case-insensitively). Unset or empty is `main`; a value that is neither `main` nor
288
+ # `worker` is `worker` and writes one line to stderr. A worker never writes or claims the
289
+ # project's compact summary or warning. Always returns 0. bash 3.2 safe (no ${var,,}).
290
+ doflow_session_role() {
291
+ local role
292
+ role=$(printf '%s' "${DOFLOW_SESSION_ROLE:-}" | tr '[:upper:]' '[:lower:]') || role=""
293
+ case "$role" in
294
+ ""|main) printf 'main\n' ;;
295
+ worker) printf 'worker\n' ;;
296
+ *)
297
+ echo "[doflow] unknown DOFLOW_SESSION_ROLE; treating session as worker" >&2
298
+ printf 'worker\n'
299
+ ;;
300
+ esac
301
+ return 0
302
+ }
@@ -0,0 +1,21 @@
1
+ #!/usr/bin/env bash
2
+ # Gemini front door: delegates the mcp-tool-guard decision to the Canonical
3
+ # Policy Library, then translates it into Gemini's verified deny contract.
4
+ #
5
+ # Gemini's hook output schema (packages/core/src/hooks/types.ts, confirmed this
6
+ # session) is a top-level {"decision": "deny", "reason": "..."} — NOT nested
7
+ # under hookSpecificOutput.permissionDecision like Claude/Codex. Exit code alone
8
+ # is not sufficient here, so this front door is a translator, not a bare exec
9
+ # (unlike session-context, which never needs this translation).
10
+ set -uo pipefail
11
+ export DOFLOW_AGENT="${DOFLOW_AGENT:-gemini}"
12
+
13
+ command -v jq >/dev/null 2>&1 || exit 0
14
+ source "$(dirname "$0")/../../.doflow/shared/hooks/policies/deny-json.sh"
15
+
16
+ POLICY="$(dirname "$0")/../../.doflow/shared/hooks/policies/mcp-tool-guard.sh"
17
+ REASON=$(bash "$POLICY" 2>&1 >/dev/null)
18
+ CODE=$?
19
+
20
+ [ "$CODE" -ne 0 ] && emit_pretooluse_deny_flat "${REASON:-MCP tool call blocked by mcp-tool-guard}"
21
+ exit 0
@@ -0,0 +1,39 @@
1
+ #!/usr/bin/env bash
2
+ # post-edit-lint.sh — AfterTool(write_file|replace) hook
3
+ #
4
+ # Pure collector: appends the edited/written file_path to a session-scoped
5
+ # list. The actual lint work happens in stop-check.sh at the end of each
6
+ # turn, where all paths can be batched by extension in one pass.
7
+ #
8
+ # Gemini's write_file/replace tools both use a "file_path" tool_input key
9
+ # (docs/reference/tools.md) — same field as Claude's
10
+ # Edit/Write, unlike Codex's apply_patch (which needed patch-text parsing).
11
+ #
12
+ # KNOWN GAP: stop-check.sh (Claude's/Codex's consumer of edited-files.txt, run on the
13
+ # Stop event) is NOT ported to Gemini — Gemini has no Stop-equivalent event (design.md
14
+ # §8, this feature). This collector currently writes data nothing reads. Shipped anyway
15
+ # as forward-looking infrastructure, same precedent as this repo's own mcp-policy.conf
16
+ # (ships empty, ahead of real usage) — revisit once/if a Gemini turn-end consumer exists.
17
+ #
18
+ # Multi-session safe: writes only to sessions/{session_id}/edited-files.txt.
19
+ # Must complete in <20ms. Must never exit non-zero or produce unexpected output.
20
+
21
+ set -euo pipefail
22
+ # shellcheck source=lib.sh
23
+ source "$(dirname "$0")/lib.sh"
24
+ require_jq
25
+
26
+ INPUT=$(cat)
27
+ SESSION_ID=$(json_field "$INPUT" ".session_id")
28
+ TOOL_NAME=$(json_field "$INPUT" ".tool_name")
29
+
30
+ [[ "$TOOL_NAME" != "write_file" && "$TOOL_NAME" != "replace" ]] && exit 0
31
+ [[ -z "$SESSION_ID" ]] && exit 0
32
+
33
+ FILE_PATH=$(json_field "$INPUT" ".tool_input.file_path")
34
+ [[ -z "$FILE_PATH" ]] && exit 0
35
+
36
+ SESSION_PATH=$(ensure_session_dir "$SESSION_ID")
37
+ echo "$FILE_PATH" >> "$SESSION_PATH/edited-files.txt"
38
+
39
+ exit 0
@@ -0,0 +1,21 @@
1
+ #!/usr/bin/env bash
2
+ # Gemini front door: delegates the pre-bash-guard decision to the Canonical
3
+ # Policy Library, then translates it into Gemini's verified deny contract.
4
+ #
5
+ # Gemini's hook output schema (packages/core/src/hooks/types.ts, confirmed this
6
+ # session) is a top-level {"decision": "deny", "reason": "..."} — NOT nested
7
+ # under hookSpecificOutput.permissionDecision like Claude/Codex. Exit code alone
8
+ # is not sufficient here, so this front door is a translator, not a bare exec
9
+ # (unlike session-context, which never needs this translation).
10
+ set -uo pipefail
11
+ export DOFLOW_AGENT="${DOFLOW_AGENT:-gemini}"
12
+
13
+ command -v jq >/dev/null 2>&1 || exit 0
14
+ source "$(dirname "$0")/../../.doflow/shared/hooks/policies/deny-json.sh"
15
+
16
+ POLICY="$(dirname "$0")/../../.doflow/shared/hooks/policies/pre-bash-guard.sh"
17
+ REASON=$(bash "$POLICY" 2>&1 >/dev/null)
18
+ CODE=$?
19
+
20
+ [ "$CODE" -ne 0 ] && emit_pretooluse_deny_flat "${REASON:-Command blocked by pre-bash-guard}"
21
+ exit 0
@@ -0,0 +1,38 @@
1
+ #!/usr/bin/env bash
2
+ # pre-compact.sh — PreCompress hook
3
+ #
4
+ # Gemini's PreCompress output schema (docs/hooks/reference.md) accepts a
5
+ # "systemMessage" field, displayed to the user before compression — no
6
+ # additionalContext-style field that feeds compaction content directly, same
7
+ # limitation as Codex's PreCompact. Gathers the same git-state summary Claude's/
8
+ # Codex's pre-compact scripts do, surfaced as a systemMessage instead.
9
+ #
10
+ # Must never exit non-zero or block.
11
+
12
+ set -euo pipefail
13
+ # shellcheck source=lib.sh
14
+ source "$(dirname "$0")/lib.sh"
15
+ require_jq
16
+
17
+ INPUT=$(cat)
18
+ CWD=$(json_field "$INPUT" ".cwd")
19
+
20
+ BRANCH=""
21
+ SHA=""
22
+ UNCOMMITTED=0
23
+
24
+ if [[ -n "$CWD" ]] && is_git_worktree "$CWD"; then
25
+ BRANCH=$(git_branch_of "$CWD" || echo "")
26
+ SHA=$(git_short_sha_of "$CWD" || echo "")
27
+ UNCOMMITTED=$(git_uncommitted_count_of "$CWD" || echo "0")
28
+ RECENT=$(run_with_timeout 1 -- git -C "$CWD" log --format="%h %s" -2 2>/dev/null | paste -sd ' | ' - || echo "")
29
+
30
+ MSG=$(printf 'Compacting session — git branch: %s sha: %s, recent commits: %s, uncommitted files: %s, cwd: %s' \
31
+ "${BRANCH:-unknown}" "${SHA:-unknown}" "${RECENT:-none}" "$UNCOMMITTED" "${CWD:-unknown}")
32
+ else
33
+ MSG=$(printf 'Compacting session — cwd: %s (not a git repository)' "${CWD:-unknown}")
34
+ fi
35
+
36
+ MSG="${MSG:0:490}"
37
+ jq -n --arg systemMessage "$MSG" '{systemMessage: $systemMessage}'
38
+ exit 0
@@ -0,0 +1,22 @@
1
+ #!/usr/bin/env bash
2
+ # Gemini front door: delegates the pre-implementation-gate decision to the
3
+ # Canonical Policy Library, then translates it into Gemini's verified deny
4
+ # contract.
5
+ #
6
+ # Gemini's hook output schema (packages/core/src/hooks/types.ts, confirmed this
7
+ # session) is a top-level {"decision": "deny", "reason": "..."} — NOT nested
8
+ # under hookSpecificOutput.permissionDecision like Claude/Codex. Exit code alone
9
+ # is not sufficient here, so this front door is a translator, not a bare exec
10
+ # (unlike session-context, which never needs this translation).
11
+ set -uo pipefail
12
+ export DOFLOW_AGENT="${DOFLOW_AGENT:-gemini}"
13
+
14
+ command -v jq >/dev/null 2>&1 || exit 0
15
+ source "$(dirname "$0")/../../.doflow/shared/hooks/policies/deny-json.sh"
16
+
17
+ POLICY="$(dirname "$0")/../../.doflow/shared/hooks/policies/pre-implementation-gate.sh"
18
+ REASON=$(bash "$POLICY" 2>&1 >/dev/null)
19
+ CODE=$?
20
+
21
+ [ "$CODE" -ne 0 ] && emit_pretooluse_deny_flat "${REASON:-Implementation requires an approved plan.md}"
22
+ exit 0
@@ -0,0 +1,89 @@
1
+ #!/usr/bin/env bash
2
+ # session-end.sh — SessionEnd hook
3
+ #
4
+ # Runs when Claude Code closes a session. Responsibilities:
5
+ # 1. Append END marker to sessions.log
6
+ # 2. Write uncommitted-warning.txt if the working tree is dirty
7
+ # 3. Delete the session-scoped state directory (cleanup)
8
+ # 4. Trim sessions.log to last 500 lines (lock-guarded for parallel safety)
9
+ #
10
+ # Multi-session safe: with_file_lock prevents concurrent sessions from
11
+ # corrupting the log trim. Session directory deletion is per session_id so
12
+ # sessions don't interfere.
13
+ # Must never exit non-zero or block (SessionEnd is fire-and-forget).
14
+
15
+ set -euo pipefail
16
+ # shellcheck source=lib.sh
17
+ source "$(dirname "$0")/lib.sh"
18
+ require_jq
19
+
20
+ INPUT=$(cat)
21
+ SESSION_ID=$(json_field "$INPUT" ".session_id")
22
+ CWD=$(json_field "$INPUT" ".cwd")
23
+
24
+ TIMESTAMP=$(date -u +"%Y-%m-%dT%H:%M:%SZ")
25
+
26
+ # ── 1. Log session end ────────────────────────────────────────────────────────
27
+
28
+ mkdir -p "$(dirname "$SESSIONS_LOG")"
29
+ echo "$TIMESTAMP END ${SESSION_ID:-unknown} ${CWD:-unknown}" >> "$SESSIONS_LOG"
30
+
31
+ # ── 2. Uncommitted-changes warning ────────────────────────────────────────────
32
+
33
+ # A worker session never writes the project's warning; it is left for the main session.
34
+ if [[ "$(doflow_session_role || echo main)" != "worker" ]] && [[ -n "$CWD" ]] && is_git_worktree "$CWD"; then
35
+ if has_uncommitted_changes "$CWD"; then
36
+ BRANCH=$(git_branch_of "$CWD" || echo "unknown")
37
+ PROJECT_DIR=$(ensure_project_dir "$CWD")
38
+ echo "Session ${SESSION_ID:-unknown} ended with uncommitted changes on branch ${BRANCH}" \
39
+ > "$PROJECT_DIR/uncommitted-warning.txt"
40
+ fi
41
+ fi
42
+
43
+ # ── 2b. Update meta.json last_active ─────────────────────────────────────────
44
+
45
+ if [[ -n "$CWD" ]]; then
46
+ PROJECT_DIR=$(ensure_project_dir "$CWD")
47
+ if [[ -f "$PROJECT_DIR/meta.json" ]]; then
48
+ META_TMP=$(mktemp "$PROJECT_DIR/.meta.XXXXXX")
49
+ jq --arg ts "$TIMESTAMP" '.last_active = $ts' "$PROJECT_DIR/meta.json" \
50
+ > "$META_TMP" && mv "$META_TMP" "$PROJECT_DIR/meta.json" \
51
+ || rm -f "$META_TMP" 2>/dev/null || true
52
+ fi
53
+ fi
54
+
55
+ # ── 3. Delete session directory ───────────────────────────────────────────────
56
+
57
+ if [[ -n "$SESSION_ID" ]]; then
58
+ SESSION_PATH="$SESSION_DIR/$SESSION_ID"
59
+ rm -rf "$SESSION_PATH" 2>/dev/null || true
60
+ fi
61
+
62
+ (
63
+ SHARED_POLICY_LIB="$(dirname "$0")/../../.doflow/shared/hooks/policies/lib.sh"
64
+ if [[ ! -f "$SHARED_POLICY_LIB" ]]; then
65
+ SHARED_POLICY_LIB="$(dirname "$0")/../../shared/hooks/policies/lib.sh"
66
+ fi
67
+ if [[ -f "$SHARED_POLICY_LIB" ]]; then
68
+ source "$SHARED_POLICY_LIB"
69
+ storage_upkeep_async "$CWD"
70
+ fi
71
+ ) >/dev/null 2>&1 || true
72
+
73
+ # ── 4. Trim sessions.log (lock-guarded) ───────────────────────────────────────
74
+
75
+ LOCK_FILE="${SESSIONS_LOG}.lock"
76
+ if with_file_lock "$LOCK_FILE" 5; then
77
+ if [[ -f "$SESSIONS_LOG" ]]; then
78
+ TMP=$(mktemp "${SESSIONS_LOG}.XXXXXX")
79
+ if tail -n 500 "$SESSIONS_LOG" > "$TMP"; then
80
+ mv "$TMP" "$SESSIONS_LOG" || rm -f "$TMP"
81
+ else
82
+ rm -f "$TMP"
83
+ fi
84
+ fi
85
+ else
86
+ echo "[hooks] timed out waiting for lock: $LOCK_FILE" >&2 # Give up after 5s rather than block indefinitely
87
+ fi
88
+
89
+ exit 0
@@ -0,0 +1,5 @@
1
+ #!/usr/bin/env bash
2
+ # Gemini adapter: reuse the shared session closer with Gemini attribution.
3
+ set -euo pipefail
4
+ export DOFLOW_AGENT=gemini
5
+ exec bash "$(dirname "$0")/session-end.impl.sh"
@@ -0,0 +1,5 @@
1
+ #!/usr/bin/env bash
2
+ # Gemini adapter: reuse the Canonical Policy Library's session-context policy.
3
+ set -euo pipefail
4
+ export DOFLOW_AGENT="${DOFLOW_AGENT:-gemini}"
5
+ exec bash "$(dirname "$0")/../../.doflow/shared/hooks/policies/session-context.sh"
@@ -0,0 +1,4 @@
1
+ {
2
+ "mcpKey": "mcpServers",
3
+ "extensionInstall": "native-host-workflow"
4
+ }