@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,141 @@
1
+ #!/usr/bin/env bash
2
+ # session-context.sh — Canonical Policy Library: SessionStart guard policy
3
+ #
4
+ # Fires when a harness starts a new session. Captures git state into a
5
+ # session-scoped file so a harness's user-prompt-submit hook can inject it on
6
+ # the first prompt.
7
+ #
8
+ # Cannot inject into the LLM context from this event — side effects only.
9
+ # Must complete in <200ms. Must never exit non-zero or produce unexpected stderr.
10
+ #
11
+ # Canonical Policy Script Contract (design.md §4):
12
+ # env DOFLOW_PROJECT_DIR, DOFLOW_AGENT (both optional here; DOFLOW_AGENT
13
+ # only affects the "last_agent" field recorded in meta.json)
14
+ # stdin the harness's native SessionStart JSON payload — must expose at
15
+ # least ".session_id" and ".cwd"
16
+ # exit this policy never denies — it always exits 0 (side-effect only)
17
+ #
18
+ # Depends on lib.sh (require_jq, json_field, ensure_session_dir,
19
+ # ensure_project_dir, cwd_hash, run_with_timeout, $SESSIONS_LOG) being
20
+ # discoverable next to this script when it runs — a front door invoking this
21
+ # canonical script is responsible for making lib.sh resolvable via
22
+ # "$(dirname "$0")/lib.sh", exactly as every harness's own SessionStart script
23
+ # already required before this policy moved to a shared location.
24
+
25
+ set -euo pipefail
26
+ # shellcheck source=lib.sh
27
+ source "$(dirname "$0")/lib.sh"
28
+ require_jq
29
+
30
+ INPUT=$(cat)
31
+ SESSION_ID=$(json_field "$INPUT" ".session_id")
32
+ CWD=$(json_field "$INPUT" ".cwd")
33
+
34
+ # Guard: if we can't determine the session, nothing to do
35
+ [[ -z "$SESSION_ID" ]] && exit 0
36
+
37
+ SESSION_PATH=$(ensure_session_dir "$SESSION_ID")
38
+
39
+ # Clean up stale injected flag from a prior crashed session
40
+ rm -f "$SESSION_PATH/injected"
41
+
42
+ TIMESTAMP=$(date -u +"%Y-%m-%dT%H:%M:%SZ")
43
+
44
+ # ── Git state capture ─────────────────────────────────────────────────────────
45
+
46
+ IS_GIT_REPO=false
47
+ BRANCH=""
48
+ SHA=""
49
+ COMMITS_JSON="[]"
50
+ UNCOMMITTED=0
51
+ STASH_COUNT=0
52
+ UPSTREAM_BEHIND=0
53
+
54
+ if [[ -n "$CWD" ]] && is_git_worktree "$CWD"; then
55
+ IS_GIT_REPO=true
56
+
57
+ BRANCH=$(git_branch_of "$CWD" || echo "")
58
+ SHA=$(git_short_sha_of "$CWD" || echo "")
59
+
60
+ # Last 5 commits as a JSON array of one-liner strings.
61
+ # Capture git's raw output first (never fatal under pipefail), then build
62
+ # the JSON array from that captured text in a single jq call whose failure
63
+ # replaces COMMITS_JSON via assignment rather than appending via echo —
64
+ # a trailing `|| echo "[]"` on the pipe would double-emit when git log
65
+ # fails (e.g. zero-commit repo) but jq still prints "[]" downstream.
66
+ COMMITS_RAW=$(run_with_timeout 1 -- git -C "$CWD" log --oneline -5 2>/dev/null || true)
67
+ COMMITS_JSON=$(printf '%s' "$COMMITS_RAW" | jq -Rs 'split("\n") | map(select(length > 0))' 2>/dev/null) || COMMITS_JSON="[]"
68
+
69
+ # Count uncommitted (staged + unstaged) files
70
+ UNCOMMITTED=$(git_uncommitted_count_of "$CWD" || echo "0")
71
+
72
+ # Count stash entries
73
+ STASH_COUNT=$(run_with_timeout 1 -- git -C "$CWD" stash list 2>/dev/null | wc -l | tr -d ' ' || echo "0")
74
+
75
+ # How far behind upstream (0 if no upstream configured)
76
+ # shellcheck disable=SC1083 # @{u} is git upstream ref syntax, not a shell brace expression
77
+ UPSTREAM_BEHIND=$(run_with_timeout 1 -- git -C "$CWD" rev-list --count HEAD..@{u} 2>/dev/null || echo "0")
78
+ fi
79
+
80
+ # ── Write git-context.json ────────────────────────────────────────────────────
81
+
82
+ # Use jq -n for full construction — avoids heredoc variable interpolation
83
+ # which can produce invalid JSON if numeric fields contain unexpected output.
84
+ jq -n \
85
+ --arg branch "$BRANCH" \
86
+ --arg sha "$SHA" \
87
+ --argjson commits "$COMMITS_JSON" \
88
+ --argjson uncommitted "$UNCOMMITTED" \
89
+ --argjson stash "$STASH_COUNT" \
90
+ --argjson behind "$UPSTREAM_BEHIND" \
91
+ --argjson is_git "$IS_GIT_REPO" \
92
+ --arg cwd "$CWD" \
93
+ --arg captured_at "$TIMESTAMP" \
94
+ '{
95
+ branch: $branch,
96
+ sha: $sha,
97
+ commits: $commits,
98
+ uncommitted_count: $uncommitted,
99
+ stash_count: $stash,
100
+ upstream_behind: $behind,
101
+ is_git_repo: $is_git,
102
+ cwd: $cwd,
103
+ captured_at: $captured_at
104
+ }' > "$SESSION_PATH/git-context.json"
105
+
106
+ # ── Write meta.json ───────────────────────────────────────────────────────────
107
+
108
+ if [[ -n "$CWD" ]]; then
109
+ PROJECT_DIR=$(ensure_project_dir "$CWD")
110
+ # Preserve compacted_at from the prior session if present
111
+ PRIOR_COMPACTED_AT=""
112
+ if [[ -f "$PROJECT_DIR/meta.json" ]]; then
113
+ PRIOR_COMPACTED_AT=$(jq -r '.compacted_at // empty' "$PROJECT_DIR/meta.json" 2>/dev/null || echo "")
114
+ fi
115
+ META_TMP=$(mktemp "$PROJECT_DIR/.meta.XXXXXX")
116
+ trap 'rm -f "$META_TMP" 2>/dev/null || true' EXIT
117
+ jq -n \
118
+ --arg cwd "$CWD" \
119
+ --arg cwd_hash "$(cwd_hash "$CWD")" \
120
+ --arg last_agent "$DOFLOW_AGENT" \
121
+ --arg last_active "$TIMESTAMP" \
122
+ --arg compacted_at "${PRIOR_COMPACTED_AT:-}" \
123
+ --arg branch "${BRANCH:-}" \
124
+ '{
125
+ cwd: $cwd,
126
+ cwd_hash: $cwd_hash,
127
+ last_agent: $last_agent,
128
+ last_active: $last_active,
129
+ compacted_at: (if $compacted_at == "" then null else $compacted_at end),
130
+ branch: $branch
131
+ }' > "$META_TMP" && mv "$META_TMP" "$PROJECT_DIR/meta.json" \
132
+ || rm -f "$META_TMP" 2>/dev/null || true
133
+ fi
134
+
135
+ # ── Append to sessions.log ────────────────────────────────────────────────────
136
+
137
+ mkdir -p "$(dirname "$SESSIONS_LOG")"
138
+ echo "$TIMESTAMP START $SESSION_ID ${CWD:-unknown}" >> "$SESSIONS_LOG"
139
+
140
+ storage_upkeep_async "$CWD"
141
+ exit 0
@@ -0,0 +1,264 @@
1
+ #!/usr/bin/env bash
2
+ # stop-check.sh — Canonical Policy Library: Stop hook
3
+ #
4
+ # Two responsibilities:
5
+ # 1. Batch lint dispatch: reads the list of files edited this turn
6
+ # (written by a harness's own post-edit-lint hook), dispatches
7
+ # formatters async and linters sync with a 2s timeout, then clears the
8
+ # list. Only runs when the incoming payload carries a session_id — a
9
+ # harness with no edited-files queue of its own (e.g. Antigravity, which
10
+ # wires no PostToolUse editor hook yet) simply has nothing to drain here.
11
+ # 2. Stub detection: takes the payload's last_assistant_message, or else the
12
+ # last assistant message in the JSONL transcript (Claude Code, Codex and
13
+ # flat {role,content} shapes), then checks for unfinished-work markers.
14
+ # Exits non-zero if stubs are found (blocks the session from stopping).
15
+ # Runs independently of (1) — it needs only the payload field or a
16
+ # transcript path, not a session_id, so it still fires for a harness that
17
+ # has no edited-files queue. A given message blocks once: harnesses without
18
+ # stop_hook_active (Antigravity, Kiro) have no other loop guard.
19
+ # 3. Process-leak scan: DoFlow's own identifiers (FR-###, agent-docs/, chain
20
+ # artifact names) reaching files that ship. Warns, never blocks.
21
+ #
22
+ # Multi-session safe: reads/writes only from sessions/{session_id}/.
23
+ # Async lint uses </dev/null >/dev/null to avoid holding stdin fd.
24
+ #
25
+ # Canonical Policy Script Contract (design.md §4):
26
+ # env DOFLOW_PROJECT_DIR, DOFLOW_AGENT (both optional here)
27
+ # stdin a Stop-shaped JSON payload. session_id and transcript path field
28
+ # names both vary by harness (transcript_path vs. Antigravity's
29
+ # camelCase transcriptPath) — this script reads the union of known
30
+ # field names rather than assuming one, since a native front door
31
+ # (Claude/Codex/Kiro) execs this script directly with no payload
32
+ # translation of its own.
33
+ # exit 0 = allow the stop, non-zero = deny (block the stop) with the
34
+ # reason on stderr.
35
+ #
36
+ # Depends on lib.sh (require_jq, json_field, ensure_session_dir,
37
+ # run_with_timeout) being discoverable next to this script when it runs — see
38
+ # session-context.sh's header note; the same front-door responsibility
39
+ # applies here.
40
+ #
41
+ # Reconciliation note (022-normalize-hooks, Phase A): claude's own copy of
42
+ # this policy additionally ran a process-leak scan (step 3) that
43
+ # codex/kiro's copies did not have; that step is folded in here as the more
44
+ # complete, already-proven behavior (D3) rather than dropped. Antigravity's
45
+ # copy runs stub detection only (no lint dispatch, no leak scan — it has no
46
+ # edited-files queue to drain), gated on session_id being absent being a
47
+ # no-op rather than an early exit, so stub detection still fires for it.
48
+
49
+ set -euo pipefail
50
+ # shellcheck source=lib.sh
51
+ source "$(dirname "$0")/lib.sh"
52
+ require_jq
53
+
54
+ INPUT=$(cat)
55
+ SESSION_ID=$(json_field "$INPUT" ".session_id")
56
+
57
+ TRANSCRIPT_PATH=$(json_field "$INPUT" ".transcript_path")
58
+ [ -z "$TRANSCRIPT_PATH" ] && TRANSCRIPT_PATH=$(json_field "$INPUT" ".transcriptPath")
59
+
60
+ # ── 1. Lint dispatch (only when we have a session-scoped edited-files queue) ──
61
+
62
+ if [ -n "$SESSION_ID" ]; then
63
+ SESSION_PATH=$(ensure_session_dir "$SESSION_ID")
64
+ EDITED_FILES="$SESSION_PATH/edited-files.txt"
65
+ PROC_FILE="$SESSION_PATH/edited-files.txt.proc"
66
+
67
+ # Atomic read-and-clear: mv before reading so concurrent PostToolUse writes
68
+ # go to a fresh edited-files.txt, not the file we're about to process.
69
+ mv "$EDITED_FILES" "$PROC_FILE" 2>/dev/null || true
70
+
71
+ if [ -f "$PROC_FILE" ] && [ -s "$PROC_FILE" ]; then
72
+ # Partition paths by extension
73
+ py_files=()
74
+ js_files=()
75
+ go_files=()
76
+ leak_files=()
77
+ java_has_files=false
78
+
79
+ # The resolver for the leak-scan verb. Absent install -> the scan is
80
+ # skipped, like every other tool below: this hook has never required
81
+ # anything to be present.
82
+ DOFLOW_RUN=""
83
+ for candidate in \
84
+ "${CLAUDE_CONFIG_DIR:-$HOME/.claude}/scripts/doflow/bin/doflow-run" \
85
+ "$HOME/.doflow/scripts/doflow/bin/doflow-run"
86
+ do
87
+ [ -x "$candidate" ] && { DOFLOW_RUN="$candidate"; break; }
88
+ done
89
+
90
+ while IFS= read -r path; do
91
+ [ -z "$path" ] && continue
92
+ case "$path" in
93
+ *.py) py_files+=("$path") ;;
94
+ *.ts|*.tsx|*.js|*.jsx) js_files+=("$path") ;;
95
+ *.go) go_files+=("$path") ;;
96
+ *.java) java_has_files=true ;;
97
+ esac
98
+ # Every edited path is a leak-scan candidate regardless of language;
99
+ # the verb decides what it can read and reports the rest as unscanned.
100
+ case "$path" in
101
+ */agent-docs/*|agent-docs/*) ;; # correct usage there; the verb excludes it too
102
+ *) leak_files+=("$path") ;;
103
+ esac
104
+ done < "$PROC_FILE"
105
+
106
+ # Python: async format, sync check (output goes to stderr: on Codex, text on stdout
107
+ # before the {} reply is invalid hook output)
108
+ if [ ${#py_files[@]} -gt 0 ]; then
109
+ if command -v ruff &>/dev/null; then
110
+ nohup ruff format "${py_files[@]}" </dev/null >/dev/null 2>&1 &
111
+ run_with_timeout 2 -- ruff check "${py_files[@]}" >&2 || true
112
+ fi
113
+ fi
114
+
115
+ # JS/TS: async fix only (eslint --fix rarely needs the caller's immediate attention)
116
+ if [ ${#js_files[@]} -gt 0 ]; then
117
+ if command -v eslint &>/dev/null; then
118
+ nohup eslint --fix "${js_files[@]}" </dev/null >/dev/null 2>&1 &
119
+ fi
120
+ fi
121
+
122
+ # Go: sync format (gofmt is fast, <100ms for typical files)
123
+ if [ ${#go_files[@]} -gt 0 ]; then
124
+ if command -v gofmt &>/dev/null; then
125
+ run_with_timeout 2 -- gofmt -w "${go_files[@]}" >&2 || true
126
+ fi
127
+ fi
128
+
129
+ # Java: async spotlessApply (slow — only if gradlew exists in cwd)
130
+ if [ "$java_has_files" = "true" ]; then
131
+ if [ -x "./gradlew" ]; then
132
+ nohup ./gradlew spotlessApply </dev/null >/dev/null 2>&1 &
133
+ fi
134
+ fi
135
+
136
+ # Process-leak scan: DoFlow's own identifiers (FR-###, agent-docs/, chain
137
+ # artifact names) reaching files that ship. Warns, never blocks — a
138
+ # legitimate occurrence exists in docs *about* DoFlow, and a false
139
+ # positive that failed a turn would cost more than the leak it prevented.
140
+ if [ ${#leak_files[@]} -gt 0 ]; then
141
+ leak_args=()
142
+ for p in "${leak_files[@]}"; do leak_args+=(--path "$p"); done
143
+ if [ -n "$DOFLOW_RUN" ]; then
144
+ leak_out="$(run_with_timeout 2 -- "$DOFLOW_RUN" leak-scan "${leak_args[@]}" 2>/dev/null || true)"
145
+ if [ -n "$leak_out" ] && printf '%s' "$leak_out" | grep -q ':[0-9]'; then
146
+ printf 'doflow: internal identifiers found in shipped files (warning, not a block):\n%s\n' \
147
+ "$leak_out" >&2
148
+ fi
149
+ fi
150
+ fi
151
+
152
+ rm -f "$PROC_FILE"
153
+ fi
154
+ fi
155
+
156
+ # ── 2. Stub detection ─────────────────────────────────────────────────────────
157
+
158
+ # A stop that continues an earlier block has already been asked to finish once;
159
+ # re-blocking it would loop, so only the lint queue above runs for it.
160
+ [ "$(printf '%s' "$INPUT" | jq -r '.stop_hook_active // false' 2>/dev/null)" = "true" ] && exit 0
161
+
162
+ # The payload's own last_assistant_message is the response being stopped on. A present key
163
+ # (even null or empty) is authoritative: the transcript is only read when the key is absent.
164
+ # jq filter for the transcript fallback: one JSON object per line, assistant text from three
165
+ # shapes — Claude Code (.message with text blocks), Codex rollout (response_item .payload with
166
+ # output_text blocks) and the flat {role,content} line. A partial or foreign line yields "".
167
+ read -r -d '' LAST_ASSISTANT_JQ <<'JQ' || true
168
+ def text: if type == "string" then .
169
+ elif type == "array" then [ .[]? | objects | select(.type == "text" or .type == "output_text") | .text | strings ] | join("\n")
170
+ else "" end;
171
+ [ inputs | fromjson? | objects
172
+ | if ((.message | objects | .role) // null) == "assistant" then .message.content
173
+ elif .type == "response_item" and ((.payload | objects | .role) // null) == "assistant" then .payload.content
174
+ elif .role == "assistant" then .content
175
+ else empty end
176
+ | text | select(length > 0) ] | last // ""
177
+ JQ
178
+
179
+ if printf '%s' "$INPUT" | jq -e 'has("last_assistant_message")' >/dev/null 2>&1; then
180
+ LAST_ASSISTANT_CONTENT=$(printf '%s' "$INPUT" | jq -r '.last_assistant_message // ""' 2>/dev/null || true)
181
+ else
182
+ # Only parse transcript if we have a path to it
183
+ [ -z "$TRANSCRIPT_PATH" ] && exit 0
184
+ [ -f "$TRANSCRIPT_PATH" ] || exit 0
185
+
186
+ # tail-scan is O(constant) regardless of transcript size — the last assistant
187
+ # entry is always near the end of the file. 200 lines covers any realistic
188
+ # single response without loading the entire (potentially multi-MB) transcript.
189
+ LAST_ASSISTANT_CONTENT=$(tail -n 200 "$TRANSCRIPT_PATH" | jq -Rnr "$LAST_ASSISTANT_JQ" 2>/dev/null || true)
190
+ fi
191
+
192
+ [ -z "$LAST_ASSISTANT_CONTENT" ] && exit 0
193
+
194
+ # Text that only resembles a marker is cleaned before the match, outside ``` fences only, except
195
+ # URLs: a markdown heading loses its leading hashes (## TODO list, # Todo) so a real marker later on
196
+ # the same line still counts; "the // TODO comment" mentions (a marker, comment(s) or marker(s), then
197
+ # the end of the sentence) are cut out; a URL, up to a space, quote, ) or //, is cut out
198
+ # (http://todo-app.example.com). The text is lowercased, which the case-insensitive match ignores.
199
+ # Every step is linear in the line length: a line with no "://" is not touched by the URL step,
200
+ # and the URL step splits on "://" and trims each scheme (at most 32 characters) backwards.
201
+ # Ceiling: an unfenced title-case `# Todo`/`# Fixme` at the start of a line reads as a heading, and an
202
+ # unfenced `## TODO: x` as a heading, not a Python comment.
203
+ STUB_TEXT=$(printf '%s\n' "$LAST_ASSISTANT_CONTENT" | awk '
204
+ function strip_urls(s, n, parts, k, cur, out, L, m, frag) {
205
+ if (index(s, "://") == 0) return s
206
+ n = split(s, parts, "://")
207
+ cur = parts[1]; out = ""
208
+ for (k = 2; k <= n; k++) {
209
+ L = length(cur); m = 0
210
+ while (m < 32 && m < L && substr(cur, L - m, 1) ~ /[A-Za-z0-9+.-]/) m++
211
+ while (m > 0 && substr(cur, L - m + 1, 1) !~ /[A-Za-z]/) m--
212
+ if (m > 0) {
213
+ out = out substr(cur, 1, L - m)
214
+ frag = parts[k]
215
+ cur = match(frag, urlend) ? substr(frag, RSTART) : ""
216
+ } else {
217
+ out = out cur "://"
218
+ cur = parts[k]
219
+ }
220
+ }
221
+ return out cur
222
+ }
223
+ BEGIN {
224
+ q = "\047"
225
+ urlend = "[[:space:]\"" q "`)]|//"
226
+ mention = "(#|//)[[:space:]]*(todo|fixme)s?[[:space:]]+(comments?|markers?)[[:space:]]*([.,;!?)]|$)"
227
+ }
228
+ /^[[:space:]]*(```|~~~)/ { fence = !fence }
229
+ {
230
+ if (!fence) {
231
+ if ($0 ~ /^ ? ? ?###*[[:space:]]+/) sub(/^ ? ? ?#+[[:space:]]+/, "")
232
+ else if ($0 ~ /^ ? ? ?#[[:space:]]+(Todo|Fixme)([^[:alnum:]_]|$)/) sub(/^ ? ? ?#[[:space:]]+/, "")
233
+ }
234
+ line = tolower($0)
235
+ line = strip_urls(line)
236
+ if (!fence) gsub(mention, " ", line)
237
+ print line
238
+ }') || STUB_TEXT=$LAST_ASSISTANT_CONTENT
239
+
240
+ # Search extracted content for unfinished-work markers
241
+ # Match stubs only inside code comment context to avoid false positives from
242
+ # explanatory prose (e.g. "I removed the TODO comment" should not trigger).
243
+ # POSIX ERE has no \b; require what follows TODO/FIXME/stub to be a
244
+ # non-word character or end-of-string instead, so "TODOX" doesn't match.
245
+ STUB_PATTERN='(#|//)[[:space:]]*(TODO|FIXME)([^[:alnum:]_]|$)|raise NotImplementedError|throw new Error\(.*[Nn]ot [Ii]mplemented|(#|//)[[:space:]]*stub([^[:alnum:]_]|$)'
246
+
247
+ if grep -qiE -- "$STUB_PATTERN" <<<"$STUB_TEXT" 2>/dev/null; then
248
+ # Block a given message once: the continuation that follows is judged on new text, and a
249
+ # harness with no stop_hook_active would otherwise be blocked on this one forever. State is
250
+ # per session, or per transcript when the harness sends no session_id; any failure here
251
+ # leaves the block in force only for this call.
252
+ GUARD_KEY="$SESSION_ID"
253
+ [ -z "$GUARD_KEY" ] && GUARD_KEY="t$(printf '%s' "$TRANSCRIPT_PATH" | cksum | cut -d' ' -f1)"
254
+ GUARD_FILE="$(ensure_session_dir "$GUARD_KEY" 2>/dev/null)/stop-last-blocked" || GUARD_FILE=""
255
+ MESSAGE_SUM=$(printf '%s' "$LAST_ASSISTANT_CONTENT" | cksum 2>/dev/null) || MESSAGE_SUM=""
256
+ if [ -n "$MESSAGE_SUM" ] && [ -n "$GUARD_FILE" ] && [ "$(cat "$GUARD_FILE" 2>/dev/null)" = "$MESSAGE_SUM" ]; then
257
+ exit 0
258
+ fi
259
+ [ -n "$MESSAGE_SUM" ] && [ -n "$GUARD_FILE" ] && { printf '%s\n' "$MESSAGE_SUM" > "$GUARD_FILE"; } 2>/dev/null || true
260
+ echo "[stop-check] The last response contains an unfinished-work marker (TODO/FIXME/stub comment or a not-implemented raise/throw)." >&2
261
+ exit 2
262
+ fi
263
+
264
+ exit 0
@@ -0,0 +1,46 @@
1
+ #!/usr/bin/env bash
2
+ # subagent-audit.sh — Canonical Policy Library: SubagentStart + SubagentStop hook
3
+ # (pure observability, no deny path)
4
+ #
5
+ # 022-hooks-remaining-duplication: claude and codex's copies were byte-identical — moved here as
6
+ # the single canonical copy. Gemini has no SubagentStart/SubagentStop-equivalent event.
7
+ #
8
+ # Appends {timestamp, session_id, event, agent_type, agent_id} to a session-scoped audit log.
9
+ # Today there is zero record of which of the installed agents/ specialists actually run, how often, or
10
+ # whether one is invoked outside its intended use (e.g. everything routing through general-purpose
11
+ # instead of do-code-review/security-engineer) — this hook is the evidence base a future policy
12
+ # hook (e.g. an agent-aware pre-bash-guard extension) would need before writing rules on a guess.
13
+ # Per agent-docs/research/hook-governance-agent-tool-mcp-skill.md §3.1: pure logging, no deny path,
14
+ # safe to ship immediately, and the recommended first step before any tighter agent governance.
15
+ #
16
+ # Multi-session safe: writes only to sessions/{session_id}/subagent-audit.log.
17
+ # Must never exit non-zero or block a subagent from starting/stopping.
18
+
19
+ set -euo pipefail
20
+ # shellcheck source=lib.sh
21
+ source "$(dirname "$0")/lib.sh"
22
+ require_jq
23
+
24
+ INPUT=$(cat)
25
+ SESSION_ID=$(json_field "$INPUT" ".session_id")
26
+
27
+ # Guard: if we can't determine the session, nothing to do
28
+ [[ -z "$SESSION_ID" ]] && exit 0
29
+
30
+ EVENT=$(json_field "$INPUT" ".hook_event_name")
31
+ AGENT_TYPE=$(json_field "$INPUT" ".agent_type")
32
+ AGENT_ID=$(json_field "$INPUT" ".agent_id")
33
+ TIMESTAMP=$(date -u +%FT%TZ)
34
+
35
+ SESSION_PATH=$(ensure_session_dir "$SESSION_ID")
36
+
37
+ jq -nc \
38
+ --arg ts "$TIMESTAMP" \
39
+ --arg session "$SESSION_ID" \
40
+ --arg event "$EVENT" \
41
+ --arg agent_type "$AGENT_TYPE" \
42
+ --arg agent_id "$AGENT_ID" \
43
+ '{timestamp: $ts, session_id: $session, event: $event, agent_type: $agent_type, agent_id: $agent_id}' \
44
+ >> "$SESSION_PATH/subagent-audit.log" 2>/dev/null || true
45
+
46
+ exit 0