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

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 (407) 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 +1057 -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 +46 -4
  250. package/src/adapters/antigravity/index.ts +631 -0
  251. package/src/adapters/claude/index.ts +548 -0
  252. package/src/adapters/claude/mcp.ts +94 -0
  253. package/src/adapters/codex/agents.ts +208 -0
  254. package/src/adapters/codex/config.ts +272 -0
  255. package/src/adapters/codex/hooks.ts +203 -0
  256. package/src/adapters/codex/index.ts +707 -0
  257. package/src/adapters/codex/mcp.ts +271 -0
  258. package/src/adapters/codex/native-projection.ts +34 -0
  259. package/src/adapters/copilot/index.ts +413 -0
  260. package/src/adapters/copy-tree.ts +620 -0
  261. package/src/adapters/gemini/hooks.ts +210 -0
  262. package/src/adapters/gemini/index.ts +390 -0
  263. package/src/adapters/hook-commands.ts +60 -0
  264. package/src/adapters/index.ts +106 -0
  265. package/src/adapters/kiro/index.ts +310 -0
  266. package/src/adapters/mcp-entries.ts +331 -0
  267. package/src/adapters/opencode/index.ts +466 -0
  268. package/src/adapters/pi/index.ts +279 -0
  269. package/src/adapters/pi/json-members.ts +185 -0
  270. package/src/adapters/pi/mcp.ts +373 -0
  271. package/src/adapters/resolve-source.ts +19 -0
  272. package/src/cli/commands/install.ts +218 -0
  273. package/src/cli/commands/list-backups.ts +21 -0
  274. package/src/cli/commands/reconcile.ts +120 -0
  275. package/src/cli/commands/remove.ts +82 -0
  276. package/src/cli/commands/rollback.ts +172 -0
  277. package/src/cli/commands/self-update.ts +33 -0
  278. package/src/cli/commands/status.ts +138 -0
  279. package/src/cli/commands/tools.ts +92 -0
  280. package/src/cli/commands/update.ts +162 -0
  281. package/src/cli/index.ts +568 -0
  282. package/src/cli/runtime-commands.ts +281 -0
  283. package/src/cli/shared.ts +218 -0
  284. package/src/helper/bash-helper.ts +34 -0
  285. package/src/helper/git.ts +24 -0
  286. package/src/helper/guardrails.ts +49 -0
  287. package/src/helper/harness-paths.ts +140 -0
  288. package/src/helper/marker-merge.ts +116 -0
  289. package/src/helper/prompt.ts +61 -0
  290. package/src/helper/repo-root.ts +29 -0
  291. package/src/helper/settings-merge.ts +151 -0
  292. package/src/helper/settings-scope.ts +33 -0
  293. package/src/helper/toml.ts +244 -0
  294. package/src/install/backup-set.ts +149 -0
  295. package/src/install/backup.ts +724 -0
  296. package/src/install/context.ts +58 -0
  297. package/src/install/manifest.ts +145 -0
  298. package/src/install/mcp.ts +254 -0
  299. package/src/install/paths.ts +84 -0
  300. package/src/install/targets.ts +90 -0
  301. package/src/install/tool-lifecycle.ts +151 -0
  302. package/src/lifecycle/bash-availability.ts +25 -0
  303. package/src/lifecycle/index.ts +812 -0
  304. package/src/lifecycle/mcp-index.ts +28 -0
  305. package/src/lifecycle/policies.ts +73 -0
  306. package/src/lifecycle/view.ts +175 -0
  307. package/src/registry/index.ts +611 -0
  308. package/src/release/sync-plugin-versions.ts +66 -0
  309. package/src/runtime/advice/cli.ts +283 -0
  310. package/src/runtime/advice/client.ts +324 -0
  311. package/src/runtime/advice/config.ts +189 -0
  312. package/src/runtime/advice/doctor.ts +169 -0
  313. package/src/runtime/advice/endpoint-guard.ts +134 -0
  314. package/src/runtime/advice/kinds.ts +154 -0
  315. package/src/runtime/advice/providers/ollama-systemone.ts +209 -0
  316. package/src/runtime/advice/record.ts +166 -0
  317. package/src/runtime/advice/registry.ts +170 -0
  318. package/src/runtime/advice/strength.ts +66 -0
  319. package/src/runtime/brief-tools.ts +342 -0
  320. package/src/runtime/c4-project.ts +371 -0
  321. package/src/runtime/capability-router.ts +484 -0
  322. package/src/runtime/checkouts.ts +170 -0
  323. package/src/runtime/claims.ts +468 -0
  324. package/src/runtime/cli-result.ts +55 -0
  325. package/src/runtime/cli.ts +678 -0
  326. package/src/runtime/command-detect.ts +516 -0
  327. package/src/runtime/context-pack.ts +492 -0
  328. package/src/runtime/decision-register.ts +493 -0
  329. package/src/runtime/evidence-ledger.ts +338 -0
  330. package/src/runtime/failure/capture.ts +272 -0
  331. package/src/runtime/failure/classifier.ts +68 -0
  332. package/src/runtime/failure/cli.ts +178 -0
  333. package/src/runtime/failure/home.ts +64 -0
  334. package/src/runtime/failure/store.ts +226 -0
  335. package/src/runtime/feature-resolve.ts +79 -0
  336. package/src/runtime/freshness.ts +177 -0
  337. package/src/runtime/health.ts +863 -0
  338. package/src/runtime/history-compactor.ts +237 -0
  339. package/src/runtime/implementation-gate.ts +321 -0
  340. package/src/runtime/inventory/coverage.ts +218 -0
  341. package/src/runtime/inventory/identity.ts +65 -0
  342. package/src/runtime/inventory/index.ts +705 -0
  343. package/src/runtime/inventory/precedence.ts +134 -0
  344. package/src/runtime/inventory/read-scopes.ts +131 -0
  345. package/src/runtime/inventory/siblings.ts +192 -0
  346. package/src/runtime/knowledge/chunker.ts +124 -0
  347. package/src/runtime/knowledge/hybrid.ts +149 -0
  348. package/src/runtime/knowledge/index-store.ts +145 -0
  349. package/src/runtime/knowledge/retrieval.ts +194 -0
  350. package/src/runtime/leak-scan.ts +185 -0
  351. package/src/runtime/lifecycle/cli.ts +276 -0
  352. package/src/runtime/lifecycle/event-store.ts +340 -0
  353. package/src/runtime/lifecycle/fold.ts +353 -0
  354. package/src/runtime/lifecycle/followup.ts +432 -0
  355. package/src/runtime/lifecycle/goal.ts +249 -0
  356. package/src/runtime/lifecycle/intent-writer.ts +86 -0
  357. package/src/runtime/lifecycle/overview.ts +292 -0
  358. package/src/runtime/lifecycle/release.ts +241 -0
  359. package/src/runtime/lifecycle/report-store.ts +221 -0
  360. package/src/runtime/lifecycle/retention.ts +212 -0
  361. package/src/runtime/lifecycle/root.ts +71 -0
  362. package/src/runtime/lifecycle/status.ts +353 -0
  363. package/src/runtime/lifecycle/store-upkeep.ts +393 -0
  364. package/src/runtime/locator-resolve.ts +158 -0
  365. package/src/runtime/mask.ts +210 -0
  366. package/src/runtime/mcp-consultations.ts +412 -0
  367. package/src/runtime/mcp-reach.ts +157 -0
  368. package/src/runtime/model-router.ts +153 -0
  369. package/src/runtime/outcome.ts +467 -0
  370. package/src/runtime/reach.ts +148 -0
  371. package/src/runtime/readiness-record.ts +150 -0
  372. package/src/runtime/readiness.ts +435 -0
  373. package/src/runtime/recovery.ts +282 -0
  374. package/src/runtime/research-request.ts +231 -0
  375. package/src/runtime/retrieval-plan.ts +578 -0
  376. package/src/runtime/scaffold/artifacts.ts +217 -0
  377. package/src/runtime/scaffold/fingerprint.ts +56 -0
  378. package/src/runtime/scaffold/generate.ts +911 -0
  379. package/src/runtime/scaffold/languages.ts +245 -0
  380. package/src/runtime/storage/cli.ts +64 -0
  381. package/src/runtime/storage/engine.ts +249 -0
  382. package/src/runtime/storage/registry.ts +130 -0
  383. package/src/runtime/storage/roots.ts +63 -0
  384. package/src/runtime/storage/rules.ts +282 -0
  385. package/src/runtime/storage/upkeep.ts +243 -0
  386. package/src/runtime/storage/work-status.ts +326 -0
  387. package/src/runtime/task-attempts.ts +415 -0
  388. package/src/runtime/task-classifier.ts +550 -0
  389. package/src/runtime/task-scope.ts +130 -0
  390. package/src/runtime/task-state.ts +176 -0
  391. package/src/runtime/trace/indicators.ts +235 -0
  392. package/src/runtime/trace/ledger.ts +626 -0
  393. package/src/runtime/trace/render.ts +76 -0
  394. package/src/runtime/trace/views.ts +459 -0
  395. package/src/runtime/verification/contract-runner.ts +341 -0
  396. package/src/runtime/verification/engine.ts +1461 -0
  397. package/src/runtime/verification/registry.ts +130 -0
  398. package/src/runtime/verification/scope-bound.ts +418 -0
  399. package/src/runtime/verification/test-selection.ts +172 -0
  400. package/src/runtime/workflow-engine.ts +588 -0
  401. package/src/runtime/workflow-orchestrator.ts +953 -0
  402. package/src/runtime/worktree.ts +340 -0
  403. package/src/state/index.ts +193 -0
  404. package/src/state/lockfile.ts +136 -0
  405. package/src/state/run-lock.ts +408 -0
  406. package/types/node-commonjs.d.ts +68 -0
  407. package/types/runtime.d.ts +91 -0
@@ -0,0 +1,592 @@
1
+ #!/usr/bin/env bash
2
+ # doflow-run — the single runtime seam every skill calls through.
3
+ #
4
+ # One verb namespace (design.md §4.2), one place that decides whether a verb is served by a
5
+ # shell helper or the Node CLI, and one place that records that a verb ran. Callers never learn
6
+ # which side serves a verb, which is what lets a verb move between them without touching skills.
7
+ #
8
+ # Self-resolution is from this file's own REAL path, symlinks followed — never fixed-depth
9
+ # `../../../..` arithmetic. Its predecessor `doflow.sh` did exactly that: installed at
10
+ # ~/.doflow/scripts/doflow/ it computed a repo root of /Users and every Node-backed verb died
11
+ # with "Cannot find module '/Users/bin/doflow.js'". The same script must answer identically from
12
+ # a source checkout, a project-local `.doflow/`, a global `~/.doflow/`, and from a symlink on
13
+ # PATH pointing at any of them.
14
+ #
15
+ # Usage: doflow-run <verb> [args...]
16
+ # Every verb accepts --json. Exit 0 = success, 1 = an actionable finding, 2 = usage or
17
+ # resolution error. Arguments, stdin and exit status pass through the dispatcher unmodified —
18
+ # `sync-context` reads its block body from stdin, so anything that buffered or consumed it here
19
+ # would break that verb rather than merely inconvenience it.
20
+
21
+ set -euo pipefail
22
+
23
+ # ------------------------------------------------------------------------------ failure capture
24
+
25
+ # DoFlow's own failures, recorded on this machine (feature 046, IC-011, IC-014, IC-017). A side
26
+ # channel: it never changes what the dispatcher prints or the status it exits with, never blocks
27
+ # anything, and is silent. It runs in a subshell with all output discarded and ends in `|| true`, so
28
+ # `set -euo pipefail` never stops on it; nothing in it can reach the dispatcher's own options or
29
+ # variables. Appends one JSON line of at most 1000 bytes (longer appends from concurrent writers can
30
+ # interleave) and never rotates: rotation is done by the Node writers only (IC-015, DEC-019). It is
31
+ # a no-op when no failure home can be resolved (HOME unset, or XDG_CONFIG_HOME relative) and while
32
+ # capture is off (the `off` sentinel file wins; DOFLOW_FAILURE_CAPTURE=off|0|false|no also turns it
33
+ # off). The line carries only names from DoFlow's own tables and the working directory: never an
34
+ # argument, stdin or the environment.
35
+ # capture_failure <command> <kind> <exit status>
36
+ CAPTURE_VERB=""
37
+
38
+ capture_failure_write() {
39
+ local command="${1:-}" kind="${2:-}" status="${3:-}"
40
+ local home="" setting="" version="" candidate="" project="" harness="" at="" line="" cwd="" hp=""
41
+ export LC_ALL=C
42
+
43
+ if [ -n "${XDG_CONFIG_HOME:-}" ]; then
44
+ case "$XDG_CONFIG_HOME" in
45
+ /*) home="$XDG_CONFIG_HOME/doflow/failures" ;;
46
+ *) return 0 ;;
47
+ esac
48
+ else
49
+ case "${HOME:-}" in
50
+ /*) home="$HOME/.config/doflow/failures" ;;
51
+ *) return 0 ;;
52
+ esac
53
+ fi
54
+
55
+ # Case-insensitive, whitespace trimmed at the ends only: the same reading the Node writer has.
56
+ setting="$(printf '%s' "${DOFLOW_FAILURE_CAPTURE:-}" | tr '[:upper:]' '[:lower:]')" || return 0
57
+ setting="${setting#"${setting%%[![:space:]]*}"}"
58
+ setting="${setting%"${setting##*[![:space:]]}"}"
59
+ case "$setting" in
60
+ off|0|false|no) return 0 ;;
61
+ esac
62
+ [ -f "$home/off" ] && return 0
63
+
64
+ # The command is a verb the dispatcher has already matched against its own tables, or `dispatcher`.
65
+ [[ "$command" =~ ^[a-z][a-z0-9-]{0,39}$ ]] || command="dispatcher"
66
+ [[ "$kind" =~ ^[A-Za-z][A-Za-z0-9._:-]{0,39}$ ]] || return 0
67
+ [[ "$status" =~ ^[0-9]{1,3}$ ]] || status="null"
68
+
69
+ harness="${DOFLOW_AGENT:-}"
70
+ [[ "$harness" =~ ^[A-Za-z0-9._-]{1,40}$ ]] || harness="none"
71
+
72
+ # script_version of the nearest install manifest: the project install first, then the global one.
73
+ for candidate in "${CONFIG_DIR:-}" "${HOME:-}/.doflow"; do
74
+ [ -n "$candidate" ] && [ -f "$candidate/.install-manifest.json" ] || continue
75
+ version="$(sed -n 's/^[[:space:]]*"script_version"[[:space:]]*:[[:space:]]*"\([^"]*\)".*/\1/p' "$candidate/.install-manifest.json" | head -n 1)" || version=""
76
+ [ -n "$version" ] && break
77
+ done
78
+ [[ "$version" =~ ^[A-Za-z0-9._+-]{1,40}$ ]] || version="unknown"
79
+
80
+ # The working directory, home prefix written as `~`, cut to 200 bytes, control characters turned
81
+ # into spaces and every quote and backslash escaped, so the line stays one valid JSON string.
82
+ cwd="$(pwd 2>/dev/null)" || cwd=""
83
+ hp="${HOME:-}"
84
+ hp="${hp%/}"
85
+ if [ -n "$hp" ]; then
86
+ case "$cwd" in
87
+ "$hp") cwd="~" ;;
88
+ "$hp"/*) cwd="~${cwd#"$hp"}" ;;
89
+ esac
90
+ fi
91
+ project="$(printf '%s' "${cwd:0:200}" | tr '\001-\037\177' ' ')" || project=""
92
+ project="${project//\\/\\\\}"
93
+ project="${project//\"/\\\"}"
94
+
95
+ at="$(date -u +%Y-%m-%dT%H:%M:%S.000Z)" || return 0
96
+ line="{\"v\":1,\"at\":\"$at\",\"source\":\"dispatcher\",\"command\":\"$command\",\"harness\":\"$harness\",\"version\":\"$version\",\"project\":\"$project\",\"kind\":\"$kind\",\"message\":\"\",\"frame\":null,\"exit\":$status}"
97
+ if [ "${#line}" -gt 999 ]; then
98
+ line="{\"v\":1,\"at\":\"$at\",\"source\":\"dispatcher\",\"command\":\"$command\",\"harness\":\"$harness\",\"version\":\"$version\",\"project\":\"\",\"kind\":\"$kind\",\"message\":\"\",\"frame\":null,\"exit\":$status}"
99
+ fi
100
+
101
+ umask 077
102
+ mkdir -p "$home" || return 0
103
+ # Only ever append to a regular file: opening a FIFO for append would block forever.
104
+ [ ! -e "$home/events.jsonl" ] || [ -f "$home/events.jsonl" ] || return 0
105
+ printf '%s\n' "$line" >>"$home/events.jsonl" || return 0
106
+ }
107
+
108
+ capture_failure() {
109
+ ( capture_failure_write "$@" ) >/dev/null 2>&1 || true
110
+ return 0
111
+ }
112
+
113
+ # After a verb ran: a status outside {0, 1, 2} is a crash worth recording (a signal, a runtime that
114
+ # died), minus what is not DoFlow's fault (DEC-031): 127 (command not found), 130, 141 and 143
115
+ # (interrupted, broken pipe, terminated) and the task-not-found status 3 of `task-brief`. A Node
116
+ # crash exits 1 and is recorded by the CLI itself, so it is never counted twice.
117
+ capture_exit_status() {
118
+ local verb="${1:-}" status="${2:-0}"
119
+ case "$status" in
120
+ 0|1|2|127|130|141|143) return 0 ;;
121
+ 3) [ "$verb" = "task-brief" ] && return 0 ;;
122
+ esac
123
+ capture_failure "$verb" "exit-$status" "$status"
124
+ return 0
125
+ }
126
+
127
+ # ---------------------------------------------------------------------------- self-resolution
128
+
129
+ # `readlink -f` is GNU-only and arrived late on BSD; resolve the chain by hand so the dispatcher
130
+ # keeps working on the oldest shell we support (macOS bash 3.2). Bounded, because a symlink loop
131
+ # must produce a message rather than hang.
132
+ resolve_real_dir() {
133
+ local src="$1" dir hops=0
134
+ while [ -L "$src" ]; do
135
+ hops=$((hops + 1))
136
+ if [ "$hops" -gt 40 ]; then
137
+ capture_failure "dispatcher" "symlink-loop" 2
138
+ printf 'doflow-run: symlink loop resolving %s\n' "$1" >&2
139
+ exit 2
140
+ fi
141
+ dir="$(cd -P "$(dirname "$src")" >/dev/null 2>&1 && pwd)"
142
+ src="$(readlink "$src")"
143
+ case "$src" in
144
+ /*) ;;
145
+ *) src="$dir/$src" ;;
146
+ esac
147
+ done
148
+ cd -P "$(dirname "$src")" >/dev/null 2>&1 && pwd
149
+ }
150
+
151
+ SCRIPT_DIR="$(resolve_real_dir "${BASH_SOURCE[0]}")"
152
+
153
+ # The install root that owns state. Mirrors the locator's resolution order (design.md §4.1) so a
154
+ # verb dispatched inside a project records against that project, not against wherever the
155
+ # dispatcher itself happens to live.
156
+ resolve_config_dir() {
157
+ local dir
158
+ if [ -n "${DOFLOW_CONFIG_DIR:-}" ]; then
159
+ printf '%s' "$DOFLOW_CONFIG_DIR"
160
+ return 0
161
+ fi
162
+ dir="$(pwd -P 2>/dev/null || pwd)"
163
+ while [ -n "$dir" ] && [ "$dir" != "/" ]; do
164
+ if [ -d "$dir/.doflow" ]; then
165
+ printf '%s' "$dir/.doflow"
166
+ return 0
167
+ fi
168
+ dir="$(dirname "$dir")"
169
+ done
170
+ # No project install above the caller: fall back to the install this dispatcher was copied
171
+ # into, and only then to the global one.
172
+ case "$SCRIPT_DIR" in
173
+ */.doflow/*) printf '%s' "${SCRIPT_DIR%%/.doflow/*}/.doflow"; return 0 ;;
174
+ esac
175
+ printf '%s' "${HOME:-.}/.doflow"
176
+ }
177
+
178
+ CONFIG_DIR="$(resolve_config_dir)"
179
+
180
+ # Shell helpers sit beside this file in every shape shipped today (`.../doflow/bin` next to
181
+ # `.../doflow/bash`); the third candidate covers the dispatcher being relocated to `<config>/bin`
182
+ # without the helpers moving with it.
183
+ resolve_bash_dir() {
184
+ local candidate
185
+ for candidate in \
186
+ "$SCRIPT_DIR/../bash" \
187
+ "$SCRIPT_DIR/bash" \
188
+ "$CONFIG_DIR/scripts/doflow/bash"
189
+ do
190
+ if [ -d "$candidate" ]; then
191
+ (cd -P "$candidate" >/dev/null 2>&1 && pwd)
192
+ return 0
193
+ fi
194
+ done
195
+ return 1
196
+ }
197
+
198
+ # A directory is the package root when it holds the CLI this dispatcher would exec AND a
199
+ # package.json claiming the doflow name — `bin/doflow.js` alone would happily match an unrelated
200
+ # project the install happens to sit inside.
201
+ is_package_root() {
202
+ [ -f "$1/bin/doflow.js" ] &&
203
+ [ -f "$1/package.json" ] &&
204
+ grep -q '"name"[[:space:]]*:[[:space:]]*"[^"]*doflow"' "$1/package.json" 2>/dev/null
205
+ }
206
+
207
+ # Deliberately looser than is_package_root — no package.json check at all. Answers only "does a
208
+ # file literally named bin/doflow.js exist above $PWD or $SCRIPT_DIR", used exclusively to shape
209
+ # the exhaustion-time diagnostic in dispatch_node once every real resolution path in
210
+ # resolve_node_cli has already failed (design.md R3). A strict check here would rarely fire in
211
+ # that situation — after resolve_node_cli's own $PWD/$SCRIPT_DIR walk-ups, a directory that passes
212
+ # the strict check would usually have already resolved successfully — so a false positive here
213
+ # costs a slightly-off suggestion, never a wrong program behavior; the message is phrased as a
214
+ # hedge for exactly that reason.
215
+ has_doflow_marker_nearby() {
216
+ local dir start
217
+ for start in "$(pwd -P 2>/dev/null || pwd)" "$SCRIPT_DIR"; do
218
+ dir="$start"
219
+ while [ -n "$dir" ] && [ "$dir" != "/" ]; do
220
+ if [ -f "$dir/bin/doflow.js" ]; then
221
+ printf '%s' "$dir/bin/doflow.js"
222
+ return 0
223
+ fi
224
+ dir="$(dirname "$dir")"
225
+ done
226
+ done
227
+ return 1
228
+ }
229
+
230
+ # Order is most-specific-first: an explicit override, then the checkout this file lives in, then
231
+ # the checkout the caller is standing in, then a project- or global-local projected runtime, then
232
+ # a dependency pinned by the project, then whatever is on PATH. Answers through globals rather
233
+ # than stdout, so a path containing whitespace needs no field separator to survive.
234
+ NODE_CLI_KIND="" # "script" = run with node, "bin" = an executable that runs itself
235
+ NODE_CLI_PATH=""
236
+ NODE_CLI_SOURCE="" # which branch below resolved: override / checkout-script-dir /
237
+ # checkout-pwd / project-runtime / global-runtime / node_modules / path
238
+ resolve_node_cli() {
239
+ local dir project_root global_runtime_cli
240
+ if [ -n "${DOFLOW_CLI:-}" ] && [ -f "$DOFLOW_CLI" ]; then
241
+ NODE_CLI_KIND="script"; NODE_CLI_PATH="$DOFLOW_CLI"; NODE_CLI_SOURCE="override"
242
+ return 0
243
+ fi
244
+ dir="$SCRIPT_DIR"
245
+ while [ -n "$dir" ] && [ "$dir" != "/" ]; do
246
+ if is_package_root "$dir"; then
247
+ NODE_CLI_KIND="script"; NODE_CLI_PATH="$dir/bin/doflow.js"; NODE_CLI_SOURCE="checkout-script-dir"
248
+ return 0
249
+ fi
250
+ dir="$(dirname "$dir")"
251
+ done
252
+ # Same walk-up, started from where the caller is standing rather than where this dispatcher
253
+ # lives — lets a verb resolve correctly when the dispatcher being run is the global one but the
254
+ # caller is standing inside the actual checkout (e.g. dogfooding without `npm link`).
255
+ dir="$(pwd -P 2>/dev/null || pwd)"
256
+ while [ -n "$dir" ] && [ "$dir" != "/" ]; do
257
+ if is_package_root "$dir"; then
258
+ NODE_CLI_KIND="script"; NODE_CLI_PATH="$dir/bin/doflow.js"; NODE_CLI_SOURCE="checkout-pwd"
259
+ return 0
260
+ fi
261
+ dir="$(dirname "$dir")"
262
+ done
263
+ # The runtime projected alongside this dispatcher. This is the step that makes Node-backed verbs
264
+ # work for someone who ran `npx @khoavu882/doflow install` and nothing else: npx leaves no package
265
+ # behind, the install directory is not inside a checkout, and nothing lands on PATH — so before
266
+ # the `runtime.*` assets shipped, every Node-backed verb answered `cli-not-found` in every real
267
+ # install while passing in every test, because tests run inside a checkout. Layout under
268
+ # runtime/ mirrors the repo (bin/, src/, core/registry/) so the modules' own
269
+ # `path.resolve(__dirname, '..', '..')` finds the registries without any path rewriting.
270
+ if [ -f "$CONFIG_DIR/runtime/bin/doflow.js" ]; then
271
+ NODE_CLI_KIND="script"; NODE_CLI_PATH="$CONFIG_DIR/runtime/bin/doflow.js"; NODE_CLI_SOURCE="project-runtime"
272
+ return 0
273
+ fi
274
+ # Same runtime layout, but under the global install — covers a project-local `.doflow/` that
275
+ # exists but is only partial (e.g. `state/`/`worktrees/` with no `runtime/` of its own), where
276
+ # CONFIG_DIR resolved to that project rather than to $HOME/.doflow. Skipped when it's the exact
277
+ # same path already tried above (CONFIG_DIR already IS $HOME/.doflow), to avoid a redundant stat.
278
+ global_runtime_cli="${HOME:-}/.doflow/runtime/bin/doflow.js"
279
+ if [ -n "${HOME:-}" ] && [ "$global_runtime_cli" != "$CONFIG_DIR/runtime/bin/doflow.js" ] && [ -f "$global_runtime_cli" ]; then
280
+ NODE_CLI_KIND="script"; NODE_CLI_PATH="$global_runtime_cli"; NODE_CLI_SOURCE="global-runtime"
281
+ return 0
282
+ fi
283
+ project_root="$(dirname "$CONFIG_DIR")"
284
+ if [ -f "$project_root/node_modules/@khoavu882/doflow/bin/doflow.js" ]; then
285
+ NODE_CLI_KIND="script"; NODE_CLI_PATH="$project_root/node_modules/@khoavu882/doflow/bin/doflow.js"; NODE_CLI_SOURCE="node_modules"
286
+ return 0
287
+ fi
288
+ if command -v doflow >/dev/null 2>&1; then
289
+ NODE_CLI_KIND="bin"; NODE_CLI_PATH="$(command -v doflow)"; NODE_CLI_SOURCE="path"
290
+ return 0
291
+ fi
292
+ return 1
293
+ }
294
+
295
+ # ---------------------------------------------------------------------------------- reporting
296
+
297
+ wants_json=false
298
+ for _arg in "$@"; do
299
+ [ "$_arg" = "--json" ] && wants_json=true
300
+ done
301
+
302
+ # Dispatcher-level failures answer in the caller's requested shape; a caller that asked for JSON
303
+ # and got a bare English sentence has to special-case the dispatcher, which defeats the uniform
304
+ # contract.
305
+ fail() {
306
+ local code="$1" reason="$2" message="$3" escaped
307
+ # A broken DoFlow install is worth recording; the other reasons are the caller's mistake or the
308
+ # user's environment (DEC-031) and are not.
309
+ case "$reason" in
310
+ helper-missing|helpers-not-found) capture_failure "${CAPTURE_VERB:-dispatcher}" "$reason" "$code" ;;
311
+ esac
312
+ if [ "$wants_json" = true ]; then
313
+ # Messages quote resolved paths, and a path is allowed to contain a quote or a backslash;
314
+ # unescaped, one such path turns an error report into unparseable JSON.
315
+ escaped="${message//\\/\\\\}"
316
+ escaped="${escaped//\"/\\\"}"
317
+ printf '{"ok":false,"error":"%s","message":"%s"}\n' "$reason" "$escaped" >&2
318
+ else
319
+ printf 'doflow-run: %s\n' "$message" >&2
320
+ fi
321
+ exit "$code"
322
+ }
323
+
324
+ usage() {
325
+ cat <<'EOF'
326
+ doflow-run <verb> [args...] — the DoFlow runtime seam
327
+
328
+ Every verb accepts --json and reports on stdout. Exit 0 = success,
329
+ 1 = an actionable finding, 2 = a usage or resolution error. sync-context is the
330
+ one verb whose result is a file write rather than a report, so it acknowledges
331
+ in plain text and --json changes nothing.
332
+
333
+ Artifact and repository state:
334
+ paths resolve repo root, branch, feature slug, artifact paths
335
+ validate artifact index/detail consistency check
336
+ render-audit regenerate audit.md from the orchestration journal
337
+ render-diagrams render a chain artifact's mermaid blocks to image files
338
+ render-puml render authored PlantUML sources and project them inline
339
+ git-state branch class and derived branch names
340
+ prereqs stage prerequisite checks
341
+ parallel-check dispatch groups and write-set collisions for one plan phase
342
+ task-brief task brief extraction for execution
343
+ brief-tools tier, tools and report-format block for a brief (called by task-brief)
344
+ advise local decision-model routing, outcomes and configuration
345
+ review-package assemble a review payload
346
+ sync-context write a marker-delimited block (stdin) into an agent context file
347
+
348
+ Workflow and evidence:
349
+ classify validate a proposed task class, return its workflow
350
+ workflow resolve stages, dependencies and gates for a class
351
+ orchestrate start/resume a run: complete stages, skip optional ones, decide gates
352
+ research-request open, list or resolve a feature-stage research question
353
+ task-attempt claim, finish, release or read the attempts on a plan's tasks
354
+ retrieve BM25 search over the installed guidance tree (auto-refreshing index)
355
+ model-role resolve an abstract model role to ranked, availability-annotated providers
356
+ route resolve an information need to a healthy provider
357
+ evidence record a stage's evidence batch, or query the ledger
358
+ claim record or update a claim and its support state
359
+ readiness evaluate readiness; return state and missing items
360
+ context-pack emit the compiled context pack for a stage
361
+ retrieval-plan declare the needs a stage will resolve, then report every declared item
362
+ outcome record a task's terminal state with its basis, or show what was recorded
363
+ scaffold emit the code scaffold the active feature's artifacts imply
364
+ decision register, list or compact the active feature's decisions
365
+ followup record, list, take, settle, promote or report what a feature left unfinished
366
+ lifecycle overview, init, status, release or merged: follow-ups and feature tracking for the project
367
+ goal add, check, link, list or close a goal and its checklist
368
+ failure list, settle or switch off the failures DoFlow captured on this machine
369
+
370
+ Verification and recovery:
371
+ verify compile the contract, run checks, emit the report
372
+ recover classify a failure, return the targeted action
373
+ leak-scan report DoFlow-internal identifiers in shipped files
374
+
375
+ Observability:
376
+ trace current run trajectory
377
+ stats aggregate run usage
378
+ indicators per-stage and per-gate timings from the orchestration record
379
+ discover missed opportunities in recorded runs
380
+ inventory both scopes at once: shadowed assets, drift, unmanaged contenders
381
+ capabilities provider resolution
382
+ doctor installation and provider health
383
+ storage report stored data and its retention bounds
384
+ EOF
385
+ }
386
+
387
+ # ------------------------------------------------------------------------------------- clocks
388
+
389
+ # Millisecond clocks are not portable: EPOCHREALTIME is bash 5+, `date +%N` exists on GNU and on
390
+ # recent BSD but the GNU width modifier `%3N` does not, and older BSD has neither. Probe once and
391
+ # keep the answer. The perl path pays its own interpreter startup inside the measured span, so
392
+ # durations recorded through it read a few milliseconds high — accepted, because the alternative
393
+ # on such a host is whole-second granularity.
394
+ detect_clock() {
395
+ local nanos
396
+ if [ -n "${EPOCHREALTIME:-}" ]; then printf 'bash'; return 0; fi
397
+ # Require exactly nine digits: `%s%N` is only safe to read as one number when %N is
398
+ # zero-padded, and a date that prints a literal "N" fails this test rather than poisoning
399
+ # every duration with a non-numeric suffix.
400
+ nanos="$(date -u +%N 2>/dev/null || true)"
401
+ case "$nanos" in
402
+ [0-9][0-9][0-9][0-9][0-9][0-9][0-9][0-9][0-9]) printf 'nanos'; return 0 ;;
403
+ esac
404
+ if command -v perl >/dev/null 2>&1; then printf 'perl'; return 0; fi
405
+ printf 'seconds'
406
+ }
407
+
408
+ CLOCK="$(detect_clock)"
409
+
410
+ now_ms() {
411
+ local raw
412
+ case "$CLOCK" in
413
+ bash)
414
+ raw="${EPOCHREALTIME/./}"
415
+ printf '%s' "${raw:0:13}"
416
+ ;;
417
+ nanos)
418
+ # One call, not %s then %N, so the reading cannot straddle a second boundary.
419
+ printf '%s' "$(( $(date -u +%s%N) / 1000000 ))"
420
+ ;;
421
+ perl)
422
+ perl -MTime::HiRes -e 'printf "%d", Time::HiRes::time() * 1000'
423
+ ;;
424
+ *)
425
+ printf '%s' "$(( $(date -u +%s) * 1000 ))"
426
+ ;;
427
+ esac
428
+ }
429
+
430
+ # --------------------------------------------------------------------------------- run ledger
431
+
432
+ # One metadata record per dispatched verb (FR-011). Metadata ONLY — the verb name comes from the
433
+ # dispatcher's own table and the argument count is a count, so no argument value, no command
434
+ # output and no file content can reach the ledger (NFR-004).
435
+ #
436
+ # Tracing never changes what a verb returned. Every step is failure-tolerant and the function
437
+ # always succeeds: an unwritable state directory degrades observability, not the run.
438
+ trace_run() {
439
+ local verb="$1" code="$2" duration="$3" argc="$4" started_at="$5"
440
+ local runs_dir="$CONFIG_DIR/state/runs"
441
+ mkdir -p "$runs_dir" 2>/dev/null || return 0
442
+ printf '{"timestamp":"%s","verb":"%s","exit_code":%s,"duration_ms":%s,"arg_count":%s}\n' \
443
+ "$started_at" "$verb" "$code" "$duration" "$argc" \
444
+ >>"$runs_dir/$(date -u +%Y-%m-%d).jsonl" 2>/dev/null || return 0
445
+ return 0
446
+ }
447
+
448
+ # ----------------------------------------------------------------------------------- dispatch
449
+
450
+ # The two arms of the verb table (design.md §4.2). Together they also answer "is this a verb at
451
+ # all", so there is no third list to keep in step.
452
+ #
453
+ # Every helper a *skill* names has to appear here, or that skill has no way to reach it except by
454
+ # inlining its own resolver — the exact pattern C.4 removes. `do-parallel-check.sh` and
455
+ # `sync-context.sh` are here for that reason and no other. `do-exec-paths.sh` deliberately is not:
456
+ # it is called by do-task-brief.sh and do-review-package.sh, never by a skill, so exposing it would
457
+ # widen the public surface without removing a single resolver.
458
+ shell_helper_for() {
459
+ case "$1" in
460
+ paths) printf 'do-paths.sh' ;;
461
+ validate) printf 'validate-artifacts.sh' ;;
462
+ render-audit) printf 'render-audit.sh' ;;
463
+ render-diagrams) printf 'render-diagrams.sh' ;;
464
+ render-puml) printf 'render-puml.sh' ;;
465
+ git-state) printf 'do-git-state.sh' ;;
466
+ prereqs) printf 'do-prereqs.sh' ;;
467
+ parallel-check) printf 'do-parallel-check.sh' ;;
468
+ task-brief) printf 'do-task-brief.sh' ;;
469
+ review-package) printf 'do-review-package.sh' ;;
470
+ sync-context) printf 'sync-context.sh' ;;
471
+ *) return 1 ;;
472
+ esac
473
+ }
474
+
475
+ # The whole Node namespace, including the verbs later phases still have to build. Tracking which
476
+ # of them the CLI implements *today* would mean a second inventory drifting against the CLI's own
477
+ # command list; an unbuilt verb is dispatched and the CLI answers for itself.
478
+ is_node_verb() {
479
+ case "$1" in
480
+ classify|workflow|route|evidence|claim|readiness|context-pack|retrieval-plan|outcome|scaffold|decision|followup|lifecycle|goal|failure|verify|recover|leak-scan|\
481
+ trace|stats|indicators|discover|inventory|capabilities|doctor|orchestrate|research-request|task-attempt|retrieve|model-role|storage|brief-tools|advise) return 0 ;;
482
+ *) return 1 ;;
483
+ esac
484
+ }
485
+
486
+ dispatch_shell() {
487
+ local verb="$1"; shift
488
+ local helper bash_dir script
489
+ helper="$(shell_helper_for "$verb")"
490
+ if ! bash_dir="$(resolve_bash_dir)"; then
491
+ fail 2 "helpers-not-found" \
492
+ "cannot locate the shell helpers; searched $SCRIPT_DIR/../bash, $SCRIPT_DIR/bash and $CONFIG_DIR/scripts/doflow/bash"
493
+ fi
494
+ script="$bash_dir/$helper"
495
+ [ -f "$script" ] || fail 2 "helper-missing" "verb '$verb' needs $script, which does not exist"
496
+ bash "$script" "$@"
497
+ }
498
+
499
+ dispatch_node() {
500
+ local verb="$1"; shift
501
+ local marker tmpfile rc first_line
502
+ if ! resolve_node_cli; then
503
+ if marker="$(has_doflow_marker_nearby)"; then
504
+ fail 2 "unlinked-checkout" \
505
+ "verb '$verb' is served by the Node CLI, which could not be located; a file named bin/doflow.js was found near here ($marker) — if this is a doflow checkout, running \`npm link\` may resolve this"
506
+ fi
507
+ fail 2 "cli-not-found" \
508
+ "verb '$verb' is served by the Node CLI, which could not be located; set DOFLOW_CLI to a doflow.js path, install the package (npm i -g @khoavu882/doflow), or run from a checkout"
509
+ fi
510
+ if [ "$NODE_CLI_KIND" = "script" ]; then
511
+ command -v node >/dev/null 2>&1 || fail 2 "node-not-found" \
512
+ "verb '$verb' needs node on PATH to run $NODE_CLI_PATH"
513
+ case "$NODE_CLI_SOURCE" in
514
+ project-runtime|global-runtime)
515
+ # These two sources are a *projected copy* of the runtime, not the checkout itself, so
516
+ # they can drift out of sync with the working tree's registry. Stdout still streams
517
+ # directly; only stderr is captured, so a version-drift crash can be told apart from a
518
+ # verb legitimately reporting a finding (e.g. readiness's NEEDS_EVIDENCE) before either
519
+ # reaches the caller.
520
+ tmpfile="$(mktemp)"
521
+ trap 'rm -f "$tmpfile" 2>/dev/null || true' EXIT
522
+ rc=0
523
+ node "$NODE_CLI_PATH" "$verb" "$@" 2>"$tmpfile" || rc=$?
524
+ if [ "$rc" -ne 0 ]; then
525
+ first_line=""
526
+ IFS= read -r first_line <"$tmpfile" || true
527
+ # Matched loosely (not anchored to position 0): bin/doflow.js's own top-level catch
528
+ # prepends "[ERROR] " to every thrown message before it ever reaches stderr, so an
529
+ # anchored match against the registry loader's raw prefix never fires in practice.
530
+ case "$first_line" in
531
+ *"Invalid DoFlow registry:"*)
532
+ fail 2 "stale-runtime" \
533
+ "verb '$verb' failed against $NODE_CLI_PATH, which appears out of date relative to the working checkout; reinstall or re-run the doflow installer to refresh it"
534
+ ;;
535
+ esac
536
+ fi
537
+ cat "$tmpfile" >&2
538
+ rm -f "$tmpfile"
539
+ trap - EXIT
540
+ return "$rc"
541
+ ;;
542
+ *)
543
+ node "$NODE_CLI_PATH" "$verb" "$@"
544
+ ;;
545
+ esac
546
+ else
547
+ "$NODE_CLI_PATH" "$verb" "$@"
548
+ fi
549
+ }
550
+
551
+ main() {
552
+ local verb rc started_ms started_at ended_ms argc
553
+
554
+ verb="${1:-}"
555
+ case "$verb" in
556
+ "")
557
+ usage >&2
558
+ fail 2 "no-verb" "no verb given"
559
+ ;;
560
+ -h|--help|help)
561
+ usage
562
+ exit 0
563
+ ;;
564
+ esac
565
+ shift
566
+
567
+ if ! shell_helper_for "$verb" >/dev/null 2>&1 && ! is_node_verb "$verb"; then
568
+ fail 2 "unknown-verb" "unknown verb '$verb' — run 'doflow-run --help' for the verb list"
569
+ fi
570
+
571
+ CAPTURE_VERB="$verb"
572
+ argc=$#
573
+ started_at="$(date -u +%Y-%m-%dT%H:%M:%SZ)"
574
+ started_ms="$(now_ms)"
575
+
576
+ # `|| rc=$?` rather than a bare call: the verb's exit code is the dispatcher's exit code, and
577
+ # under `set -e` a failing verb would otherwise abort before the run is ever recorded.
578
+ rc=0
579
+ if shell_helper_for "$verb" >/dev/null 2>&1; then
580
+ dispatch_shell "$verb" "$@" || rc=$?
581
+ else
582
+ dispatch_node "$verb" "$@" || rc=$?
583
+ fi
584
+
585
+ ended_ms="$(now_ms)"
586
+ trace_run "$verb" "$rc" "$(( ended_ms - started_ms ))" "$argc" "$started_at" || true
587
+ capture_exit_status "$verb" "$rc"
588
+
589
+ exit "$rc"
590
+ }
591
+
592
+ main "$@"