@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,568 @@
1
+ 'use strict';
2
+ // doflow CLI — argument parsing, the installer command table, and dispatch.
3
+ //
4
+ // bin/doflow.js is only a forwarder into main() here. This module owns: parseArgs (verbatim from
5
+ // the pre-extraction monolith), the ONE table mapping the nine installer command names to their
6
+ // handlers under commands/, and the runtime verbs' forwarding via ./runtime-commands — whose
7
+ // implementations stay one-per-module in src/runtime/. Adding an installer command means a new
8
+ // file in src/cli/commands/, an entry in COMMANDS, and an edit to test/guards/cli-boundary.test.js,
9
+ // which ratchets this surface.
10
+ // TypeScript migration (agent-docs/BRIEF_GOAL_DOFLOW.md): run directly by Node native type-stripping.
11
+ const {
12
+ handleCapabilitiesCommand, handleReadinessCommand, handleEvidenceCommand,
13
+ EVIDENCE_SCORE_FIELDS, scoreFieldRefusal,
14
+ } = require('../runtime/cli.js');
15
+ const { pkg } = require('./shared.js');
16
+ const { VALID: VALID_TARGETS, DEFAULT_TARGETS } = require('../install/targets.js');
17
+ const { dispatchRuntimeCommand } = require('./runtime-commands.js');
18
+ const { usageError } = require('../runtime/cli-result.js');
19
+
20
+ const cmdInstall = require('./commands/install.js');
21
+ const cmdUpdate = require('./commands/update.js');
22
+ const cmdReconcile = require('./commands/reconcile.js');
23
+ const cmdRemove = require('./commands/remove.js');
24
+ const cmdStatus = require('./commands/status.js');
25
+ const cmdTools = require('./commands/tools.js');
26
+ const cmdListBackups = require('./commands/list-backups.js');
27
+ const cmdRollback = require('./commands/rollback.js');
28
+ const cmdSelfUpdate = require('./commands/self-update.js');
29
+
30
+ /** The installer command surface, written down once. The runtime verbs are dispatched separately
31
+ * (see ./runtime-commands) because their namespace is owned by the doflow-run verb table. */
32
+ const COMMANDS = {
33
+ install: cmdInstall,
34
+ update: cmdUpdate,
35
+ reconcile: cmdReconcile,
36
+ remove: cmdRemove,
37
+ status: cmdStatus,
38
+ tools: cmdTools,
39
+ 'list-backups': cmdListBackups,
40
+ rollback: cmdRollback,
41
+ 'self-update': cmdSelfUpdate,
42
+ };
43
+
44
+ /** "skip all backup protection" must be an explicit, deliberate choice, never a default combo. */
45
+ function assertNoBackupRequiresForce(o ) {
46
+ if (o.noBackup && !o.force) {
47
+ console.error('doflow: --no-backup skips all backup protection and requires --force');
48
+ process.exit(1);
49
+ }
50
+ }
51
+
52
+ function parseArgs(argv ) {
53
+ const o = { cmd: null, positional: [], targets: [], mcp: null, dryRun: false, force: false, adopt: false,
54
+ noBackup: false, prune: null, global: false, json: false, help: false, version: false,
55
+ tools: null, action: 'status', days: null, slug: null,
56
+ // Explicitly null, not absent. `handleReadinessCommand` declares defaults of `'feature'` and
57
+ // `'default'`, and a JavaScript default parameter fires on `undefined` — so an *absent* key
58
+ // silently reinstated exactly the identity defect readiness.ts fixed by failing closed.
59
+ taskClass: null, taskId: null };
60
+ for (let i = 0; i < argv.length; i++) {
61
+ const a = argv[i];
62
+ switch (a) {
63
+ case '-h': case '--help': o.help = true; break;
64
+ case '-v': case '--version': o.version = true; break;
65
+ case '-n': case '--dry-run': o.dryRun = true; break;
66
+ case '-f': case '--force': o.force = true; break;
67
+ case '--adopt': o.adopt = true; break;
68
+ case '-g': case '--global': o.global = true; break;
69
+ case '--no-backup': o.noBackup = true; break;
70
+ case '--permissions': o.permissions = true; break;
71
+ case '--statusline': o.statusline = true; break;
72
+ case '--json': o.json = true; break;
73
+ case '--check': o.check = true; break;
74
+ // decision --action list: every decision by id, not just the live ones.
75
+ case '--all': o.all = true; break;
76
+ // lifecycle --action overview: the /do maintain view, with a larger list and a pending count.
77
+ case '--maintain': o.maintain = true; break;
78
+ // lifecycle --action release: record the previewed release instead of only previewing it.
79
+ case '--confirm': o.confirm = true; break;
80
+ // followup --action report: the report body comes from stdin instead of --file or --text.
81
+ case '--stdin': o.stdin = true; break;
82
+ // advise --action configure: these are deliberately presence-only switches.
83
+ case '--off': o.off = true; break;
84
+ case '--project': o.project = true; break;
85
+ // goal --action check: record the item as not met (evidence is still required, as the reason).
86
+ case '--unmet': o.unmet = true; break;
87
+ // goal --action link: move a feature that already serves another goal.
88
+ case '--replace': o.replace = true; break;
89
+ // readiness: the caller declares a decision is owed by the user. A flag rather than an
90
+ // inference, because nothing the runtime can see distinguishes "a decision is pending"
91
+ // from "nobody has looked yet", and guessing would be the gate answering unasked.
92
+ case '--user-decision-pending': o.userDecisionPending = true; break;
93
+ case '-t': case '--target': {
94
+ const val = argv[i + 1];
95
+ if (val === undefined || val.startsWith('-')) { console.error(`doflow: ${a} requires a value`); process.exit(1); }
96
+ o.targets = val.split(',').map((s) => s.trim()).filter(Boolean); i++; break;
97
+ }
98
+ case '--mcp': {
99
+ const val = argv[i + 1];
100
+ if (val === undefined || val.startsWith('-')) { console.error(`doflow: ${a} requires a value`); process.exit(1); }
101
+ o.mcp = val.split(',').map((s) => s.trim()).filter(Boolean); i++; break;
102
+ }
103
+ case '--tool': {
104
+ const val = argv[i + 1];
105
+ if (val === undefined || val.startsWith('-')) { console.error(`doflow: ${a} requires a value`); process.exit(1); }
106
+ o.tools = val.split(',').map((s) => s.trim()).filter(Boolean); i++; break;
107
+ }
108
+ case '--action': {
109
+ const val = argv[i + 1];
110
+ if (val === undefined || val.startsWith('-')) { console.error(`doflow: ${a} requires a value`); process.exit(1); }
111
+ o.action = val; o.actionGiven = true; i++; break;
112
+ }
113
+ case '--task-class': {
114
+ const val = argv[i + 1];
115
+ if (val === undefined || val.startsWith('-')) { console.error(`doflow: ${a} requires a value`); process.exit(1); }
116
+ o.taskClass = val; i++; break;
117
+ }
118
+ case '--task-id': {
119
+ const val = argv[i + 1];
120
+ if (val === undefined || val.startsWith('-')) { console.error(`doflow: ${a} requires a value`); process.exit(1); }
121
+ o.taskId = val; i++; break;
122
+ }
123
+ case '--stage': {
124
+ const val = argv[i + 1];
125
+ if (val === undefined || val.startsWith('-')) { console.error(`doflow: ${a} requires a value`); process.exit(1); }
126
+ o.stage = val; i++; break;
127
+ }
128
+ case '--gate': {
129
+ const val = argv[i + 1];
130
+ if (val === undefined || val.startsWith('-')) { console.error(`doflow: ${a} requires a value`); process.exit(1); }
131
+ o.gate = val; i++; break;
132
+ }
133
+ case '--node': {
134
+ const val = argv[i + 1];
135
+ if (val === undefined || val.startsWith('-')) { console.error(`doflow: ${a} requires a value`); process.exit(1); }
136
+ o.node = val; i++; break;
137
+ }
138
+ case '--forced': o.forced = true; break;
139
+ case '--decision': {
140
+ const val = argv[i + 1];
141
+ if (val === undefined || val.startsWith('-')) { console.error(`doflow: ${a} requires a value`); process.exit(1); }
142
+ o.decision = val; i++; break;
143
+ }
144
+ case '--note': {
145
+ const val = argv[i + 1];
146
+ if (val === undefined) { console.error(`doflow: ${a} requires a value`); process.exit(1); }
147
+ o.note = val; i++; break;
148
+ }
149
+ case '--reason': {
150
+ const val = argv[i + 1];
151
+ if (val === undefined) { console.error(`doflow: ${a} requires a value`); process.exit(1); }
152
+ o.reason = val; i++; break;
153
+ }
154
+ case '--query': {
155
+ const val = argv[i + 1];
156
+ if (val === undefined || val.startsWith('-')) { console.error(`doflow: ${a} requires a value`); process.exit(1); }
157
+ o.query = val; i++; break;
158
+ }
159
+ case '-k': case '--top': {
160
+ const val = argv[i + 1];
161
+ const parsed = parseInt(val, 10);
162
+ if (!Number.isFinite(parsed) || parsed < 1) { console.error(`doflow: ${a} expects a positive number`); process.exit(2); }
163
+ o.top = parsed; i++; break;
164
+ }
165
+ case '--role': {
166
+ const val = argv[i + 1];
167
+ if (val === undefined || val.startsWith('-')) { console.error(`doflow: ${a} requires a value`); process.exit(1); }
168
+ o.role = val; i++; break;
169
+ }
170
+ case '--days': {
171
+ const val = argv[i + 1];
172
+ if (val === undefined || val.startsWith('-')) { console.error(`doflow: ${a} requires a number`); process.exit(2); }
173
+ const parsed = parseInt(val, 10);
174
+ // Run-ledger windows are calendar days; a zero or negative window is a typo, not "all
175
+ // history", and silently reading everything would answer a question nobody asked.
176
+ if (!Number.isFinite(parsed) || parsed < 1) { console.error(`doflow: ${a} expects a positive number of days, got '${val}'`); process.exit(2); }
177
+ o.days = parsed; i++; break;
178
+ }
179
+ case '--prune': {
180
+ const val = argv[i + 1];
181
+ if (val === undefined || val.startsWith('-')) { console.error(`doflow: ${a} requires a number`); process.exit(1); }
182
+ // Digits only: parseInt accepted `5abc` and `1.5`, and 0 is valid (keep every backup).
183
+ if (!/^[0-9]+$/.test(val) || Number(val) > Number.MAX_SAFE_INTEGER) { console.error(`doflow: ${a} requires a non-negative whole number, got '${val}'`); process.exit(2); }
184
+ o.prune = Number(val); i++; break;
185
+ }
186
+ default: {
187
+ // Value-taking arguments of the runtime verbs. Table-driven rather than fifteen more
188
+ // near-identical `case` blocks: the blocks above differ from one another only in the key
189
+ // they write, and copying that shape once per new verb is how one of them eventually gets
190
+ // its validation subtly wrong.
191
+ const runtime = parseRuntimeFlag(a, argv, i, o);
192
+ if (runtime !== null) { i = runtime; break; }
193
+ if (a.startsWith('-')) { console.error(`doflow: unknown flag '${a}'`); process.exit(1); }
194
+ else if (!o.cmd) o.cmd = a;
195
+ else o.positional.push(a);
196
+ }
197
+ }
198
+ }
199
+ return o;
200
+ }
201
+
202
+ /** Single-value arguments of the runtime verbs → the option key each one writes. */
203
+ const RUNTIME_STRING_FLAGS = new Map([
204
+ // `scaffold`. The resolver's own ambiguous-feature error tells the caller to "re-run with
205
+ // --slug=<chosen>"; without this flag that hint would name an argument this CLI rejects.
206
+ ['--slug', 'slug'],
207
+ ['--rationale', 'rationale'], // classify: why this class was proposed · decision --action add: why it was decided
208
+ ['--request', 'request'], // classify: request text for an advisory second opinion
209
+ ['--request-file', 'requestFile'], // classify: request text read from a file
210
+ // decision --action add. `--statement`, `--stage`, `--slug` and `--batch` above are shared.
211
+ ['--topic', 'topic'], // the subject key a decision is live on
212
+ ['--channel', 'channel'], // question | gate | prompt | default | resolution
213
+ ['--supersedes', 'supersedes'], // comma-separated DEC-### ids this decision replaces
214
+ ['--refs', 'refs'], // comma-separated ids the decision touches, e.g. FR-001,IC-002
215
+ ['--source', 'source'], // where the decision was stated, e.g. design/design-02-question.md#question-1
216
+ // followup and lifecycle (feature 046). `--statement`, `--stage`, `--slug`, `--batch`, `--reason`,
217
+ // `--channel`, `--state`, `--source`, `--intent`, `--task-class` and `--task-id` above are shared.
218
+ ['--ids', 'ids'], // followup: comma-separated FU-xxxxxx ids to take, settle or promote
219
+ ['--as', 'as'], // followup --action settle: kept | dismissed | fix | done
220
+ ['--evidence', 'evidence'], // followup --action settle --as done: what shows it was done
221
+ ['--title', 'title'], // followup --action promote: the new intent's title
222
+ ['--release', 'release'], // followup --action add --source release: the release tag
223
+ ['--take', 'take'], // lifecycle --action init: comma-separated FU ids the feature takes
224
+ ['--goal', 'goal'], // lifecycle --action init: the goal the feature serves
225
+ ['--since', 'since'], // lifecycle --action overview --maintain: ISO time the pass started
226
+ ['--file', 'file'], // followup --action report: the report body, read as text (at most 16 MiB)
227
+ ['--text', 'text'], // followup --action report: the report body inline (a value starting with - needs --text=...) · goal --action item: the checklist item
228
+ ['--tag', 'tag'], // lifecycle --action release: the version tag (`--version` is the CLI's own flag)
229
+ ['--fp', 'fp'], // failure --action settle: the 16 hex characters of an entry
230
+ ['--set', 'set'], // failure --action capture: on | off
231
+ ['--proposed-by', 'proposedBy'], // classify: which worker proposed it
232
+ ['--calling-skill', 'callingSkill'], // classify: which skill is asking, for the fit check
233
+ ['--intent', 'intent'], // route: the information need being resolved
234
+ ['--query', 'query'], // route: what the resolved provider would be asked
235
+ ['--statement', 'statement'], // claim --action add
236
+ ['--claim-id', 'claimId'], // claim --action link
237
+ ['--evidence-id', 'evidenceId'], // claim --action link · evidence --action supersede
238
+ ['--relation', 'relation'], // claim --action link: supports | contradicts
239
+ ['--role', 'role'], // claim --action add: the claim's relationship to the task, e.g. root-cause
240
+ ['--replaced-by', 'replacedBy'], // claim --action supersede: the claim replacing this one ·
241
+ // evidence --action supersede: the evidence replacing this one
242
+ ['--kind', 'kind'], // evidence --action add: one of VALID_EVIDENCE_KINDS · advise --action ask
243
+ ['--server', 'server'], // advise: MCP server for the mcp-need kind
244
+ ['--state-file', 'stateFile'], // advise: request state from a UTF-8 file
245
+ ['--questions-file', 'questionsFile'], // advise: ad hoc question set JSON
246
+ ['--static', 'staticAnswer'], // advise: explicit caller answer for comparison
247
+ ['--provenance', 'provenance'], // evidence --action add: extracted | inferred | asserted
248
+ ['--provider', 'provider'], // evidence --action add: source.provider
249
+ ['--capability', 'capability'], // evidence --action add: source.capability
250
+ ['--locator', 'locator'], // evidence --action add: 'path/file[:line]' or a URI
251
+ ['--content', 'content'], // evidence --action add: the fact or the analysis itself
252
+ ['--establishes', 'establishes'], // evidence --action add: requirement id(s) this item proves, comma-separated
253
+ ['--observed-command', 'observedCommand'], // evidence --action add: the command a test-result/runtime-observation ran
254
+ ['--batch', 'batchPath'], // evidence --action add: a stage's batch file, or '-'
255
+ ['--verification-plan', 'verificationPlan'], // readiness: how success will be established
256
+ ['--mode', 'mode'], // readiness: execution mode, workflow (default) | standalone
257
+ ['--scope', 'scope'], // readiness: the stated scope boundary; verify: the declared
258
+ // change scope, <path>[,<path>...], unioned with the plan's bound
259
+ ['--invariants', 'invariants'], // readiness: the invariants a refactor must preserve
260
+ ['--objective', 'objective'], // context-pack
261
+ ['--stage-id', 'stageId'], // research-request: active feature stage
262
+ ['--question', 'question'], // research-request: external question
263
+ ['--blocking', 'blocking'], // research-request: true | false
264
+ ['--request-id', 'requestId'], // research-request: request to resolve
265
+ ['--outcome', 'researchOutcome'], // research-request: answered | unresolved
266
+ ['--gap', 'gap'], // research-request: unresolved reason
267
+ ['--stage', 'stage'], // retrieval-plan: the stage id declaring the plan;
268
+ // outcome: the stage writing it, refused unless terminal
269
+ ['--state', 'state'], // outcome: the terminal state being recorded
270
+ ['--result', 'result'], // orchestrate complete-stage: the stage's own outcome, passed | failed (omit → unverified)
271
+ // outcome: the verdicts the run saw, stated by it and validated against the vocabulary the
272
+ // owning module exports. Recording an outcome never re-evaluates readiness and never re-runs
273
+ // verification, so these arrive as statements rather than as measurements taken here.
274
+ ['--readiness', 'readiness'],
275
+ ['--verification', 'verification'],
276
+ ['--risk', 'risk'], // verify: risk level selecting the required tiers
277
+ ['--pick-id', 'pickId'], // advise --action outcome: retained pick to label
278
+ ['--actual', 'actual'], // advise --action outcome: observed outcome
279
+ ['--model', 'model'], // advise --action configure: installed decision-capable model
280
+ ['--endpoint', 'endpoint'], // advise --action configure: loopback Ollama endpoint
281
+ ['--owner', 'owner'], // brief-tools: the agent type the brief is for
282
+ ['--tier', 'tier'], // brief-tools: the task line's tier (light | standard | frontier)
283
+ ['--harness', 'harness'], // brief-tools: the harness the brief is for
284
+ ['--heading-level', 'headingLevel'], // brief-tools: 2 (default) or 3
285
+ ['--tasks', 'tasks'], // brief-tools: comma-separated plan task ids for tier advice
286
+ ['--plan-path', 'planPath'], // verify: a feature plan.md whose doflow-verification
287
+ // block overrides manifest detection. Without this the
288
+ // override was implemented but unreachable (FR-011).
289
+ ['--verification-input', 'verificationInput'], // verify: manifest JSON file for explicit structuralChecks/requirements (IC-022)
290
+ ['--verification-phase', 'verificationPhase'], // verify: postimplementation (IC-022)
291
+ ['--baseline-ref', 'baselineRef'], // verify: explicit ancestor commit or ref to measure change against (IC-022)
292
+ ['--error', 'errorMessage'], // recover: the failure text to classify
293
+ ['--agent', 'agent'], // recover: which agent produced the failure
294
+ ['--task', 'task'], // task-attempt: the plan task id, e.g. A.1
295
+ ['--token', 'token'], // task-attempt finish|release: the fencing token claim returned
296
+ ]);
297
+
298
+ /** Repeatable arguments — each occurrence appends rather than replaces. */
299
+ const RUNTIME_LIST_FLAGS = new Map([
300
+ ['--mcp-outcome', 'mcpOutcome'], // orchestrate handoff: <server>=<outcome>, one per MCP server the step names
301
+ ['--failed-check', 'failedChecks'], // recover: check names outrank the error prose (see recovery.js)
302
+ // retrieval-plan: the intents a stage declares, or (on report) the ones it states it reached.
303
+ // Repeatable as well as comma-separated, because a plan assembled a need at a time should not
304
+ // have to be re-spelled as one string to be declared.
305
+ ['--need', 'need'],
306
+ ['--path', 'paths'], // leak-scan: the files to scan, one per occurrence
307
+ ['--exclude', 'exclude'], // leak-scan: extra path segments to skip · lifecycle --action release: slugs left out
308
+ ['--feature', 'feature'], // lifecycle --action release: a feature slug to add, one per occurrence
309
+ ['--item', 'item'], // goal --action add: a checklist item, one per occurrence · goal --action check: the one item id (C3)
310
+ ]);
311
+
312
+ /** Non-negative integer arguments. */
313
+ const RUNTIME_INT_FLAGS = new Map([
314
+ ['--iteration', 'iteration'], // recover: retries already spent, bounding the retry budget
315
+ ['--observed-exit', 'observedExit'], // evidence --action add: exit status of the observed command (0 is meaningful)
316
+ ]);
317
+
318
+ /**
319
+ * Reads one runtime-verb argument, in either `--flag value` or `--flag=value` spelling.
320
+ *
321
+ * Both spellings are accepted because the messages users copy from are not consistent about it:
322
+ * `do-paths.sh`'s own hint says `--slug=<chosen>` while the rest of this CLI is space-separated,
323
+ * and rejecting either would punish following the instructions.
324
+ *
325
+ * Returns the new loop index, or null when `arg` is not a runtime flag.
326
+ */
327
+ function parseRuntimeFlag(arg , argv , i , o ) {
328
+ const eq = arg.indexOf('=');
329
+ const name = eq === -1 ? arg : arg.slice(0, eq);
330
+ // A score-shaped flag is refused by name rather than falling through to "unknown flag", which
331
+ // reads as "not built yet" and invites someone to build it. The name set and the reason both
332
+ // come from the evidence write boundary (src/runtime/cli.js), so argv and a --batch JSON file
333
+ // are refused by one rule with two enforcement points rather than two rules.
334
+ const camel = name.replace(/^--/, '').replace(/-([a-z])/g, (_, c) => c.toUpperCase());
335
+ if (EVIDENCE_SCORE_FIELDS.has(camel)) { console.error(`doflow: ${scoreFieldRefusal(name)}`); process.exit(2); }
336
+ const inline = eq === -1 ? null : arg.slice(eq + 1);
337
+ const key = RUNTIME_STRING_FLAGS.get(name) || RUNTIME_LIST_FLAGS.get(name) || RUNTIME_INT_FLAGS.get(name);
338
+ if (!key) return null;
339
+
340
+ let value = inline;
341
+ let next = i;
342
+ if (value === null) {
343
+ value = argv[i + 1];
344
+ // A value that itself starts with `-` is far more likely the next flag than a deliberate
345
+ // argument, and consuming it would silently drop that flag.
346
+ // A bare `-` is the conventional name for stdin, not a flag, and the help advertises
347
+ // `--batch <file|->`. Rejecting it made the documented spelling exit 2 while only `--batch=-`
348
+ // worked — a help text endorsing a form the parser refuses.
349
+ const isStdin = value === '-';
350
+ if (value === undefined || (value.startsWith('-') && !isStdin)) { console.error(`doflow: ${name} requires a value`); process.exit(2); }
351
+ next = i + 1;
352
+ }
353
+ if (value === '') { console.error(`doflow: ${name} requires a value`); process.exit(2); }
354
+
355
+ if (RUNTIME_INT_FLAGS.has(name)) {
356
+ const parsed = parseInt(value, 10);
357
+ if (!Number.isFinite(parsed) || parsed < 0) { console.error(`doflow: ${name} expects a non-negative integer, got '${value}'`); process.exit(2); }
358
+ o[key] = parsed;
359
+ } else if (RUNTIME_LIST_FLAGS.has(name)) {
360
+ // --exclude alone also accepts a comma-joined value (`--exclude bin,src,core`), not just the
361
+ // repeatable form (`--exclude bin --exclude src`) every other list flag uses — the two used to
362
+ // be parsed by two separate code paths (a dedicated switch case handling only the space
363
+ // spelling's comma-splitting, this generic path handling both spellings but never splitting),
364
+ // so `--exclude=bin,src` silently excluded nothing while `--exclude bin,src` worked. One path,
365
+ // both spellings, same behavior now.
366
+ const parts = name === '--exclude' ? value.split(',').map((s ) => s.trim()).filter(Boolean) : [value];
367
+ (o[key] = o[key] || []).push(...parts);
368
+ } else if (name === '--evidence-id' && o.cmd === 'research-request') {
369
+ (o.evidenceIds = o.evidenceIds || []).push(value);
370
+ } else {
371
+ o[key] = value;
372
+ }
373
+ return next;
374
+ }
375
+
376
+ const HELP = `doflow — DoFlow config installer
377
+
378
+ Usage: doflow <command> [path] [options]
379
+
380
+ Commands:
381
+ install [path] Install configs to target tools (use --dry-run to preview)
382
+ update Incremental update of changed files only
383
+ reconcile Converge observed state onto the doflow.lock pin (drift report + heal)
384
+ status Show resolved context + installed state from manifest (--json for scripting)
385
+ rollback [id] Restore from a backup (interactive pick if id omitted)
386
+ remove [path] Remove only lifecycle-owned native resources
387
+ list-backups List available backups
388
+ self-update git pull + reinstall
389
+ tools Inspect or manage registered external tools
390
+ capabilities Show registered abstract capabilities and resolved providers
391
+ doctor System health and capability smoke check diagnostics
392
+ readiness Evaluate task readiness contract (--task-class, --task-id, both required)
393
+ evidence Record a stage's evidence batch, or inspect what is recorded (--task-id)
394
+ claim Record a claim, link evidence to it, or list them (--task-id, --action)
395
+ context-pack Compile a task's evidence and claims into a context block (--task-id)
396
+ retrieval-plan Declare a stage's information needs, then report every declared item
397
+ outcome Record a task's terminal state with its basis, or show it (--task-id)
398
+ classify Validate a proposed task class and return its workflow (--task-class)
399
+ workflow Resolve a task class to its stages, gates and readiness templates
400
+ orchestrate Start or resume a run: complete stages, decide gates (--action)
401
+ research-request Open, list or resolve a feature-stage research question (--task-id)
402
+ task-attempt Claim, finish, release or read the attempts on a plan's tasks (--action, --slug)
403
+ retrieve BM25 search over the installed guidance tree (--query)
404
+ model-role Resolve a model role to ranked provider candidates (--role)
405
+ advise Route decision questions to the configured local model (--action)
406
+ brief-tools Tier, tools and report-format block for a dispatch brief (--owner)
407
+ route Resolve an information need to a healthy provider (--intent)
408
+ verify Compile the verification contract and report against it (--task-id)
409
+ recover Classify a verification failure and plan the bounded retry (--error)
410
+ trace Trajectory of the current or most recent workflow (run ledger)
411
+ stats Aggregate local run-ledger usage
412
+ indicators Per-stage and per-gate timings from the orchestration record
413
+ discover Missed capability opportunities in recorded runs
414
+ inventory Shadowed copies, drift and unmanaged files across both install scopes
415
+ storage Report stored data and retention bounds (--action report|prune|upkeep)
416
+ scaffold Emit the reviewable code scaffold the active feature's artifacts imply
417
+ decision Register, list or compact the active feature's decisions (--action init|add|list|compact)
418
+ followup Record, list, take, settle, promote or report what a feature left unfinished (--action add|list|take|settle|promote|report)
419
+ lifecycle Open follow-ups, feature tracking, releases and status for the project (--action overview|init|release|status|merged)
420
+ goal Add, check, link, list or close a goal and its checklist (--action add|item|check|link|list|done)
421
+ failure List, settle or switch off the failures DoFlow captured on this machine (--action list|settle|capture)
422
+ (a value beginning with '-' must be written --flag=value)
423
+ leak-scan Report DoFlow-internal identifiers in shipped files (--path, repeatable)
424
+
425
+ Scope (mutually exclusive — global wins if both given):
426
+ -g, --global Install to each target's user-level directory under \$HOME (e.g. \$HOME/.claude),
427
+ and the shared runtime to \$HOME/.doflow
428
+ [path] Project-scoped install root (default: '.', i.e. cwd); e.g.
429
+ 'doflow install ../my-app' -> each target's project files, plus
430
+ ../my-app/.doflow
431
+ (rollback's one positional slot is the backup id instead — its scope is
432
+ always -g or cwd, no custom project path)
433
+
434
+ Options:
435
+ -t, --target <list> Comma-separated: ${VALID_TARGETS.join(',')} (default: ${DEFAULT_TARGETS.join(',')})
436
+ --mcp <list> Comma-separated MCP server names, or all or none, for every targeted
437
+ harness that takes MCP servers (all but gemini). Default: none, or the
438
+ selection a harness has recorded in doflow.lock, or the servers an
439
+ installed harness already has; a real terminal prompts on install.
440
+ Recorded per harness.
441
+ -n, --dry-run Preview without writing
442
+ -f, --force Skip confirmation prompts
443
+ --adopt Record ownership of resources that exist with no ledger record, instead
444
+ of refusing them. Not --force: a resource whose record disagrees with
445
+ the file is still a conflict. For a tree installed before the neutral
446
+ ledger existed, which nothing else can re-adopt
447
+ --no-backup Skip backup (requires --force; ignored by rollback's safety snapshot)
448
+ --prune <N> Keep the N newest backups after install or update (default 3; 0 keeps all)
449
+ --days <N> Run-ledger window in calendar days (trace, stats, discover)
450
+ --slug <name> Scaffold this feature instead of the branch-resolved active one
451
+
452
+ Runtime verb arguments (accept --flag value or --flag=value):
453
+ --task-class classify, workflow, readiness, context-pack, outcome --action record
454
+ --task-id readiness, evidence, claim, context-pack, retrieval-plan, outcome, verify, advise
455
+ --action claim: list|add|link|retract|supersede · evidence: list|add|supersede
456
+ verify: report|contract · retrieval-plan: declare|report
457
+ outcome: record|show · advise: ask|outcome|configure · tools: see above
458
+ followup: add|list|take|settle|promote|report
459
+ task-attempt: claim|finish|release|status
460
+ lifecycle: overview|init|release|status|merged
461
+ goal: add|item|check|link|list|done
462
+ failure: list|settle|capture
463
+ --task, --token, --owner, --mode,
464
+ --result, --evidence-id, --reason task-attempt (claim: --task --owner --mode manual|sequential|subagent;
465
+ finish: --task --token --result COMPLETED|BLOCKED|ABANDONED|INCONCLUSIVE
466
+ [--evidence-id]; release: --task --token --reason)
467
+ --rationale, --proposed-by, --calling-skill classify
468
+ --request <text>, --request-file <file> classify (mutually exclusive; optional second opinion)
469
+ --intent, --query, --check route
470
+ --statement, --claim-id,
471
+ --evidence-id, --relation claim
472
+ --kind, --provenance, --provider,
473
+ --capability, --locator, --content evidence --action add (one item)
474
+ --batch <file|-> evidence --action add (a stage's JSON batch)
475
+ --evidence-id, --replaced-by evidence --action supersede (retire one item, point
476
+ forward to the item that replaces it)
477
+ --verification-plan, --scope,
478
+ --invariants,
479
+ --user-decision-pending readiness: inputs the caller states rather than
480
+ evidence establishes; reported back as such
481
+ --objective context-pack
482
+ --need <intent[,intent]>,
483
+ --stage retrieval-plan (--need is repeatable), outcome
484
+ --mcp-outcome <server>=<outcome> orchestrate --action handoff, repeatable: used | nothing-usable |
485
+ skipped:<reason> | unavailable (a server left out only warns)
486
+ --state <COMPLETED|BLOCKED|
487
+ ABANDONED|INCONCLUSIVE>,
488
+ --readiness, --verification outcome --action record
489
+ --risk, --plan-path, --scope,
490
+ --verification-input,
491
+ --verification-phase,
492
+ --baseline-ref verify
493
+ --owner, --tier, --harness, --tasks <id,...>,
494
+ --heading-level 2|3 brief-tools (--slug names the feature whose run gives the stage)
495
+ --kind, --state, --state-file,
496
+ --questions-file, --server,
497
+ --static advise --action ask
498
+ --pick-id, --actual advise --action outcome
499
+ --model, --endpoint, --project,
500
+ --off advise --action configure
501
+ --path, --exclude (repeatable) leak-scan
502
+ --ids, --as, --evidence, --title,
503
+ --release, --source, --channel followup (add, list, take, settle, promote)
504
+ --file <path|->, --stdin, --text,
505
+ --feature followup --action report (the body comes from exactly one; - is stdin)
506
+ --take, --goal, --intent, --since,
507
+ --maintain lifecycle (overview, init)
508
+ --goal, --statement, --item (repeatable),
509
+ --text, --evidence, --unmet, --slug,
510
+ --replace, --reason, --channel goal (add, item, check, link, list, done)
511
+ --tag, --confirm, --feature,
512
+ --exclude (repeatable), --reason lifecycle (release, merged)
513
+ --fp, --as, --reason, --set, --all failure (list, settle, capture)
514
+ --error, --failed-check,
515
+ --iteration, --agent recover
516
+ --json Machine-readable output (status)
517
+
518
+ External tools:
519
+ --tool <list> Comma-separated: rtk,graphify (required outside an interactive terminal)
520
+ --action <name> status (default), install, update, or uninstall
521
+ --force is intentionally unavailable: every mutation is separately confirmed
522
+ -h, --help Show help
523
+ -v, --version Show version`;
524
+
525
+ // The names a failure may be recorded under (IC-011): the installer table and the verbs HELP lists,
526
+ // so a record can only ever carry a name from DoFlow's own tables and never an argument value.
527
+ const COMMAND_NAMES = new Set([...Object.keys(COMMANDS), ...[...HELP.matchAll(/^ ([a-z][a-z-]*) {2,}\S/gm)].map((m) => m[1])]);
528
+
529
+ /** `name` when it is one of DoFlow's own command names, else `unknown`. */
530
+ function commandName(name ) { return typeof name === 'string' && COMMAND_NAMES.has(name) ? name : 'unknown'; }
531
+
532
+ /**
533
+ * Run one CLI invocation. Same behavior as the pre-extraction monolith's main(): --version and
534
+ * --help answer first, --no-backup-without-force is refused, then the command resolves either
535
+ * through the installer table above or through the runtime-verb dispatcher.
536
+ */
537
+ async function main(argv ) {
538
+ const o = parseArgs(argv);
539
+ if (o.version) { console.log(pkg.version); return; }
540
+ if (o.help || !o.cmd) { console.log(HELP); return; }
541
+ assertNoBackupRequiresForce(o);
542
+ if (o.cmd === 'classify' && o.request !== undefined && o.requestFile !== undefined) {
543
+ return usageError('classify', '--request and --request-file are mutually exclusive; provide only one.', o.json);
544
+ }
545
+ try {
546
+ const handler = COMMANDS[o.cmd];
547
+ if (handler) return handler(o);
548
+ return await dispatchRuntimeCommand(o);
549
+ } catch (error ) {
550
+ // Recorded silently when it is a programming error (IC-016); the output and exit status below
551
+ // are the same whether or not anything was written.
552
+ // Required here, not at load, so a CLI whose failure modules cannot be loaded still runs as today.
553
+ try { require('../runtime/failure/capture.js').captureError(error, { command: commandName(o.cmd), exit: 1 }); } catch { /* best-effort */ }
554
+ // A lifecycle apply/remove can throw mid-mutation (fs error, TOCTOU ownership mismatch on a
555
+ // multi-harness run) — surface a clean, actionable message instead of a raw stack trace, and
556
+ // point at the recovery record applyLifecycle already wrote before rethrowing.
557
+ console.error(`[ERROR] ${error.message}`);
558
+ // Only the commands that actually mutate native resources can leave a partial application.
559
+ // Printing this after a rejected `readiness --task-id` or any other read-only query told the
560
+ // user to go inspect recovery records for a run that never wrote anything.
561
+ if (['install', 'update', 'remove', 'rollback', 'self-update', 'tools'].includes(o.cmd)) {
562
+ console.error('[ERROR] Some native resources may be partially applied — check .doflow/state/recovery/ (or ~/.doflow/state/recovery/ for -g) for the latest record before retrying.');
563
+ }
564
+ process.exit(1);
565
+ }
566
+ }
567
+
568
+ module.exports = { main, COMMANDS, commandName };