@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,468 @@
1
+ 'use strict';
2
+
3
+ // TypeScript migration (agent-docs/BRIEF_GOAL_DOFLOW.md): run directly by Node native type-stripping.
4
+
5
+ const fs = require('node:fs');
6
+ const path = require('node:path');
7
+ const crypto = require('node:crypto');
8
+ // Shared with EvidenceLedger so both stores enforce one definition of a safe task id.
9
+ const { assertSafeTaskId, EvidenceLedger } = require('./evidence-ledger.ts');
10
+ const { updateTaskState, readTaskState, mergeRecords } = require('./task-state.ts');
11
+ const { taskStoreDir } = require('./task-scope.ts');
12
+ const { finishRuntime, usageError } = require('./cli-result.ts');
13
+ const { REPO_ROOT } = require('../helper/repo-root.ts');
14
+
15
+ const CLAIM_STATUSES = new Set([
16
+ 'hypothesis',
17
+ 'supported',
18
+ 'conflicted',
19
+ // Contradicted with nothing on the other side — a disproven claim, not a disputed one. Ported
20
+ // from `evidence/claim_builder.py`'s REJECTED (plan task B.3): the Python distinguished these
21
+ // and this file did not, folding both into 'conflicted'.
22
+ 'rejected',
23
+ 'invalidated',
24
+ 'unknown',
25
+ // Terminal states (FR-001, FR-002). A human decided this claim no longer stands; that decision
26
+ // outranks any later mechanical re-reading of its evidence, which is why `evaluateClaim` returns
27
+ // early for them rather than recomputing.
28
+ 'retracted',
29
+ 'superseded',
30
+ ]);
31
+
32
+ /**
33
+ * States no evidence walk may leave. `evaluateAll()` runs on every `list`/`status`, and
34
+ * `evaluateClaim` otherwise rewrites `status` from the evidence links — so without this set a
35
+ * retraction would be undone by the very next read and the verb would appear to work while doing
36
+ * nothing (design R1).
37
+ */
38
+ const TERMINAL_CLAIM_STATUSES = new Set(['retracted', 'superseded']);
39
+
40
+ class ClaimsManager {
41
+ declare fsImpl: any;
42
+ declare evidenceLedger: any;
43
+ declare repoRoot: any;
44
+ declare fixedStateDir: any;
45
+ declare slug: any;
46
+ declare stateDir: any;
47
+ declare claimsMap: Map<any, any>;
48
+ declare baseline: Map<any, any>;
49
+ declare seq: number;
50
+ /**
51
+ * @param {Object} [options]
52
+ * @param {Object} [options.evidenceLedger]
53
+ * @param {string} [options.repoRoot]
54
+ * @param {string} [options.stateDir] a fixed directory; when given, no feature namespace applies
55
+ * @param {string} [options.slug] feature whose namespace the records live under (see task-scope.js)
56
+ * @param {Object} [options.fsImpl]
57
+ */
58
+ constructor(options: any = {}) {
59
+ this.fsImpl = options.fsImpl || fs;
60
+ this.evidenceLedger = options.evidenceLedger || null;
61
+ this.repoRoot = options.repoRoot || REPO_ROOT;
62
+ this.fixedStateDir = options.stateDir || null;
63
+ this.slug = options.slug || null;
64
+ this.stateDir = this.fixedStateDir || path.join(this.repoRoot, '.doflow', 'state', 'evidence');
65
+ this.claimsMap = new Map();
66
+ this.baseline = new Map();
67
+ this.seq = 0;
68
+ }
69
+
70
+ /** Where this task's claims file lives: beside its evidence, in the feature's namespace when it has one. */
71
+ fileFor(taskId: any) {
72
+ const dir = this.fixedStateDir
73
+ || taskStoreDir({ projectRoot: this.repoRoot, store: 'evidence', taskId, slug: this.slug });
74
+ return path.join(dir, `${assertSafeTaskId(taskId)}_claims.json`);
75
+ }
76
+
77
+ generateId() {
78
+ // Cross-instance unique, same reasoning as EvidenceLedger.generateId: ids key the merge in
79
+ // save(), so a same-millisecond collision between two sessions silently merges two claims.
80
+ this.seq += 1;
81
+ return `claim_${Date.now().toString(36)}_${crypto.randomBytes(4).toString('hex')}_${this.seq.toString(36)}`;
82
+ }
83
+
84
+ /**
85
+ * Registers a new proposition as a claim.
86
+ * Agent inferences start strictly in 'hypothesis' status.
87
+ * @param {Object} item - { statement, taskId, status, id, role }
88
+ * @returns {string} claimId
89
+ */
90
+ addClaim(item: any): string {
91
+ if (!item || typeof item !== 'object') {
92
+ throw new Error('Claim item must be an object');
93
+ }
94
+ if (!item.statement || typeof item.statement !== 'string') {
95
+ throw new Error('Claim requires a non-empty statement');
96
+ }
97
+ // The claim's relationship to the task, e.g. 'root-cause'. A readiness template can require a
98
+ // role, so a supported-but-unrelated claim cannot satisfy a requirement it never addressed.
99
+ if (item.role !== undefined && !/^[a-z][a-z0-9-]*$/.test(String(item.role))) {
100
+ throw new Error(`Claim role '${item.role}' must be a lowercase-kebab token, e.g. 'root-cause'`);
101
+ }
102
+
103
+ const id = item.id || this.generateId();
104
+ const taskId = item.taskId || 'default';
105
+ const status = item.status && CLAIM_STATUSES.has(item.status) ? item.status : 'hypothesis';
106
+
107
+ const claimRecord = {
108
+ id,
109
+ taskId,
110
+ statement: item.statement,
111
+ role: item.role || null,
112
+ status,
113
+ supportingEvidence: Array.isArray(item.supportingEvidence) ? [...item.supportingEvidence] : [],
114
+ contradictingEvidence: Array.isArray(item.contradictingEvidence) ? [...item.contradictingEvidence] : [],
115
+ createdAt: item.createdAt || new Date().toISOString(),
116
+ updatedAt: new Date().toISOString(),
117
+ };
118
+
119
+ this.claimsMap.set(id, claimRecord);
120
+ return id;
121
+ }
122
+
123
+ /**
124
+ * Retrieves a claim by ID.
125
+ * @param {string} id
126
+ * @returns {Object|null}
127
+ */
128
+ getClaim(id: string) {
129
+ return this.claimsMap.get(id) || null;
130
+ }
131
+
132
+ /**
133
+ * Links an evidence item to a claim.
134
+ * @param {string} claimId
135
+ * @param {string} evidenceId
136
+ * @param {'supports'|'contradicts'} [relation='supports']
137
+ */
138
+ linkEvidence(claimId: string, evidenceId: string, relation = 'supports') {
139
+ const claim = this.claimsMap.get(claimId);
140
+ if (!claim) {
141
+ throw new Error(`Unknown claim '${claimId}'`);
142
+ }
143
+
144
+ if (relation === 'supports') {
145
+ if (!claim.supportingEvidence.includes(evidenceId)) {
146
+ claim.supportingEvidence.push(evidenceId);
147
+ }
148
+ } else if (relation === 'contradicts') {
149
+ if (!claim.contradictingEvidence.includes(evidenceId)) {
150
+ claim.contradictingEvidence.push(evidenceId);
151
+ }
152
+ } else {
153
+ throw new Error(`Invalid evidence relation '${relation}'. Allowed: supports, contradicts`);
154
+ }
155
+
156
+ // Bidirectionally update evidence if ledger attached
157
+ if (this.evidenceLedger) {
158
+ const evidence = this.evidenceLedger.getEvidence(evidenceId);
159
+ if (evidence) {
160
+ if (relation === 'supports' && !evidence.supports.includes(claimId)) {
161
+ evidence.supports.push(claimId);
162
+ } else if (relation === 'contradicts' && !evidence.contradicts.includes(claimId)) {
163
+ evidence.contradicts.push(claimId);
164
+ }
165
+ }
166
+ }
167
+
168
+ claim.updatedAt = new Date().toISOString();
169
+ return this.evaluateClaim(claimId);
170
+ }
171
+
172
+ /**
173
+ * Evaluates the epistemic state of a claim based on evidence availability and freshness.
174
+ * @param {string} claimId
175
+ * @returns {'hypothesis'|'supported'|'conflicted'|'invalidated'|'unknown'}
176
+ */
177
+ evaluateClaim(claimId: string) {
178
+ const claim = this.claimsMap.get(claimId);
179
+ if (!claim) {
180
+ throw new Error(`Unknown claim '${claimId}'`);
181
+ }
182
+
183
+ // A terminal state is a recorded human decision, not a reading of evidence. Recomputing it here
184
+ // would silently resurrect a retracted claim on the next list (design R1).
185
+ if (TERMINAL_CLAIM_STATUSES.has(claim.status)) {
186
+ return claim.status;
187
+ }
188
+
189
+ // If no evidence attached, remains a hypothesis
190
+ if (claim.supportingEvidence.length === 0 && claim.contradictingEvidence.length === 0) {
191
+ claim.status = 'hypothesis';
192
+ return claim.status;
193
+ }
194
+
195
+ let hasFreshSupport = false;
196
+ let hasFreshContradiction = false;
197
+ let hasStaleSupport = false;
198
+
199
+ for (const evId of claim.supportingEvidence) {
200
+ const ev = this.evidenceLedger ? this.evidenceLedger.getEvidence(evId) : null;
201
+ if (!ev || ev.freshness?.status === 'STALE') {
202
+ hasStaleSupport = true;
203
+ } else {
204
+ hasFreshSupport = true;
205
+ }
206
+ }
207
+
208
+ for (const evId of claim.contradictingEvidence) {
209
+ const ev = this.evidenceLedger ? this.evidenceLedger.getEvidence(evId) : null;
210
+ if (ev && ev.freshness?.status !== 'STALE') {
211
+ hasFreshContradiction = true;
212
+ }
213
+ }
214
+
215
+ if (hasFreshContradiction) {
216
+ // 'conflicted' means evidence disagrees and a human must reconcile it; 'rejected' means the
217
+ // evidence agrees and the claim is false. Collapsing the second into the first reported a
218
+ // dispute where none existed, and made the readiness gate block on a question already
219
+ // settled. Support that has merely gone stale still counts as support, so a claim that once
220
+ // had backing stays 'conflicted' rather than being declared false on a technicality.
221
+ claim.status = claim.supportingEvidence.length === 0 ? 'rejected' : 'conflicted';
222
+ } else if (hasFreshSupport) {
223
+ claim.status = 'supported';
224
+ } else if (hasStaleSupport && !hasFreshSupport) {
225
+ claim.status = 'invalidated';
226
+ } else {
227
+ claim.status = 'hypothesis';
228
+ }
229
+
230
+ claim.updatedAt = new Date().toISOString();
231
+ return claim.status;
232
+ }
233
+
234
+ /**
235
+ * Moves a claim to a terminal state, leaving the record and its evidence links untouched.
236
+ * Shared by retract and supersede so the two cannot drift on what "terminal" means.
237
+ * @param {string} claimId
238
+ * @param {'retracted'|'superseded'} status
239
+ * @param {string} [supersededBy]
240
+ * @returns {string} the new status
241
+ */
242
+ finalizeClaim(claimId: string, status: any, supersededBy?: string): string {
243
+ const claim = this.claimsMap.get(claimId);
244
+ if (!claim) {
245
+ throw new Error(`Unknown claim '${claimId}'`);
246
+ }
247
+ if (TERMINAL_CLAIM_STATUSES.has(claim.status)) {
248
+ throw new Error(`Claim '${claimId}' is already '${claim.status}' and cannot be changed again`);
249
+ }
250
+ claim.status = status;
251
+ claim.terminalAt = new Date().toISOString();
252
+ if (supersededBy) claim.supersededBy = supersededBy;
253
+ claim.updatedAt = claim.terminalAt;
254
+ return claim.status;
255
+ }
256
+
257
+ /**
258
+ * Records that a claim no longer holds. Nothing is deleted (NFR-003): retraction records that a
259
+ * conclusion was withdrawn, not that it was never drawn.
260
+ * @param {string} claimId
261
+ * @returns {string} the new status
262
+ */
263
+ retractClaim(claimId: string): string {
264
+ return this.finalizeClaim(claimId, 'retracted');
265
+ }
266
+
267
+ /**
268
+ * Records that a claim was replaced by another, with a forward pointer to it.
269
+ *
270
+ * The replacement must already exist. A pointer to an unrecorded id is worse than no pointer, and
271
+ * this refusal mirrors the one `link` already makes for unrecorded evidence.
272
+ * @param {string} claimId
273
+ * @param {string} replacedBy
274
+ * @returns {string} the new status
275
+ */
276
+ supersedeClaim(claimId: string, replacedBy: string): string {
277
+ // The target is checked first: validating the replacement before the claim being superseded
278
+ // reported a missing replacement when the caller had actually mistyped the target, sending them
279
+ // to fix the wrong id.
280
+ if (!this.claimsMap.has(claimId)) {
281
+ throw new Error(`Unknown claim '${claimId}'`);
282
+ }
283
+ if (!replacedBy) {
284
+ throw new Error('supersede requires the id of the claim that replaces this one');
285
+ }
286
+ if (replacedBy === claimId) {
287
+ throw new Error(`Claim '${claimId}' cannot supersede itself`);
288
+ }
289
+ if (!this.claimsMap.has(replacedBy)) {
290
+ throw new Error(`No claim '${replacedBy}' is recorded — a forward pointer to nothing is worse `
291
+ + 'than no pointer. Record the replacing claim first: doflow claim --action add --statement ...');
292
+ }
293
+ return this.finalizeClaim(claimId, 'superseded', replacedBy);
294
+ }
295
+
296
+ /**
297
+ * Evaluates all claims in memory.
298
+ */
299
+ evaluateAll() {
300
+ for (const claimId of this.claimsMap.keys()) {
301
+ this.evaluateClaim(claimId);
302
+ }
303
+ }
304
+
305
+ /**
306
+ * Queries claims for a specific task.
307
+ * @param {string} [taskId]
308
+ * @returns {Array<Object>}
309
+ */
310
+ getClaims(taskId: string) {
311
+ const results = [];
312
+ for (const claim of this.claimsMap.values()) {
313
+ if (!taskId || claim.taskId === taskId) {
314
+ results.push(claim);
315
+ }
316
+ }
317
+ return results;
318
+ }
319
+
320
+ /**
321
+ * Persists claims to disk.
322
+ * @param {string} [taskId='default']
323
+ * @returns {string} filePath
324
+ */
325
+ save(taskId = 'default'): string {
326
+ const targetFile = this.fileFor(taskId);
327
+ let merged: any;
328
+ const file = updateTaskState({
329
+ fsImpl: this.fsImpl,
330
+ file: targetFile,
331
+ build: (disk: any) => {
332
+ merged = mergeRecords(this.getClaims(taskId), disk?.claims || [], this.baseline);
333
+ return { taskId, updatedAt: new Date().toISOString(), claimsCount: merged.length, claims: merged };
334
+ },
335
+ });
336
+ for (const item of merged) {
337
+ this.claimsMap.set(item.id, item);
338
+ this.baseline.set(item.id, JSON.parse(JSON.stringify(item)));
339
+ }
340
+ return file;
341
+ }
342
+
343
+ /**
344
+ * Loads claims from disk.
345
+ * @param {string} [taskId='default']
346
+ * @returns {number}
347
+ */
348
+ load(taskId = 'default'): number {
349
+ const targetFile = this.fileFor(taskId);
350
+ const data = readTaskState(this.fsImpl, targetFile);
351
+ if (data && Array.isArray(data.claims)) {
352
+ for (const item of data.claims) {
353
+ this.claimsMap.set(item.id, item);
354
+ this.baseline.set(item.id, JSON.parse(JSON.stringify(item)));
355
+ }
356
+ return data.claims.length;
357
+ }
358
+ return 0;
359
+ }
360
+
361
+ clear() {
362
+ this.claimsMap.clear();
363
+ this.baseline.clear();
364
+ this.seq = 0;
365
+ }
366
+ }
367
+
368
+ /**
369
+ * Handles `doflow claim` — record a proposition, link evidence to it, or list what is recorded.
370
+ *
371
+ * A claim added here starts as a hypothesis and can only become `supported` through linked
372
+ * evidence (FR-007); this handler exposes no way to declare one supported directly, because a
373
+ * conclusion that becomes fact by assertion is the thing the claims ledger exists to prevent.
374
+ *
375
+ * @param {Object} options
376
+ * @param {string} options.taskId
377
+ * @param {'list'|'add'|'link'|'retract'|'supersede'} [options.action='list']
378
+ * @param {string} [options.statement] `add`
379
+ * @param {string} [options.claimId] `link`
380
+ * @param {string} [options.evidenceId] `link`
381
+ * @param {string} [options.replacedBy] `supersede`: the claim that replaces this one
382
+ * @param {string} [options.relation='supports'] `link`
383
+ * @param {boolean} [options.json=false]
384
+ * @param {string} [options.stateRoot]
385
+ * @param {string} [options.slug] feature the task belongs to, when not the branch's
386
+ * @returns {number} exit code
387
+ */
388
+ function handleClaimCommand({ taskId, action = 'list', statement, claimId, evidenceId, replacedBy, relation = 'supports', role, json = false, stateRoot, slug }: any = {}): number {
389
+ const root = stateRoot || process.cwd();
390
+ const ledger = new EvidenceLedger({ repoRoot: root, slug });
391
+ ledger.load(taskId);
392
+ const claims = new ClaimsManager({ evidenceLedger: ledger, repoRoot: root, slug });
393
+ claims.load(taskId);
394
+
395
+ let result;
396
+ try {
397
+ if (action === 'add') {
398
+ if (typeof statement !== 'string' || statement.trim() === '') {
399
+ return usageError('claim', '--statement is required for --action add', json);
400
+ }
401
+ const id = claims.addClaim({ statement, taskId, role });
402
+ claims.save(taskId);
403
+ result = { action, taskId, claim: claims.getClaim(id) };
404
+ } else if (action === 'link') {
405
+ if (!claimId || !evidenceId) {
406
+ return usageError('claim', '--claim-id and --evidence-id are both required for --action link', json);
407
+ }
408
+ // Linking an id the ledger does not hold used to succeed. `evaluateClaim` reads a missing
409
+ // evidence item as *stale* support and returns `invalidated` — a verdict about evidence
410
+ // that was never recorded, and the reading that made C.5 conclude `conflicted` (and so
411
+ // `BLOCKED`) was unreachable through the seam. Refuse instead of grading.
412
+ if (!ledger.getEvidence(evidenceId)) {
413
+ return usageError('claim', `no evidence '${evidenceId}' is recorded for task '${taskId}' — linking it would `
414
+ + 'mark the claim `invalidated` on the strength of an item that does not exist. Record it first: '
415
+ + `doflow evidence --task-id ${taskId} --action add ...`, json);
416
+ }
417
+ const status = claims.linkEvidence(claimId, evidenceId, relation);
418
+ claims.save(taskId);
419
+ result = { action, taskId, claim: claims.getClaim(claimId), status };
420
+ } else if (action === 'retract') {
421
+ if (!claimId) {
422
+ return usageError('claim', '--claim-id is required for --action retract', json);
423
+ }
424
+ const status = claims.retractClaim(claimId);
425
+ claims.save(taskId);
426
+ result = { action, taskId, claim: claims.getClaim(claimId), status };
427
+ } else if (action === 'supersede') {
428
+ if (!claimId || !replacedBy) {
429
+ return usageError('claim', '--claim-id and --replaced-by are both required for --action supersede', json);
430
+ }
431
+ const status = claims.supersedeClaim(claimId, replacedBy);
432
+ claims.save(taskId);
433
+ result = { action, taskId, claim: claims.getClaim(claimId), status };
434
+ } else if (action === 'list' || action === 'status') {
435
+ claims.evaluateAll();
436
+ result = { action: 'list', taskId, claims: claims.getClaims(taskId) };
437
+ } else {
438
+ return usageError('claim', `unknown --action '${action}'. Valid: list, add, link, retract, supersede`, json);
439
+ }
440
+ } catch (error: any) {
441
+ return usageError('claim', error.message, json, error);
442
+ }
443
+
444
+ if (json) { console.log(JSON.stringify(result, null, 2)); }
445
+ else {
446
+ const rows = result.claims || [result.claim];
447
+ console.log(`\nDoFlow Claims [Task: ${taskId}]:`);
448
+ console.log('═'.repeat(78));
449
+ if (rows.length === 0) console.log('No claims recorded for this task.');
450
+ else {
451
+ console.log('ID'.padEnd(24) + 'Status'.padEnd(14) + 'Statement');
452
+ console.log('─'.repeat(78));
453
+ for (const claim of rows) {
454
+ const suffix = claim.supersededBy ? ` → ${claim.supersededBy}` : '';
455
+ console.log(claim.id.padEnd(24) + (claim.status + suffix).padEnd(14) + claim.statement);
456
+ }
457
+ }
458
+ console.log('═'.repeat(78) + '\n');
459
+ }
460
+ return finishRuntime(0);
461
+ }
462
+
463
+ module.exports = {
464
+ ClaimsManager,
465
+ CLAIM_STATUSES,
466
+ TERMINAL_CLAIM_STATUSES,
467
+ handleClaimCommand,
468
+ };
@@ -0,0 +1,55 @@
1
+ 'use strict';
2
+
3
+ // TypeScript migration (agent-docs/BRIEF_GOAL_DOFLOW.md): run directly by Node native type-stripping.
4
+
5
+ /**
6
+ * CLI exit and error reporting for runtime verb handlers. These presentation helpers are being
7
+ * factored out as verb handlers move from bin/doflow.js into engine modules. Homed here rather
8
+ * than in cli.js to avoid import cycles, since cli.js already requires claims.js and claims.js
9
+ * is gaining handleClaimCommand. This module requires nothing from src/runtime/ at load time — that
10
+ * is its defining constraint; the failure writer is required lazily, inside the one call that uses
11
+ * it, and requires only the mask module.
12
+ */
13
+
14
+ /**
15
+ * Sets the process exit code.
16
+ * @param {number} code
17
+ * @returns {number} the code, for chaining
18
+ */
19
+ function finishRuntime(code: number): number {
20
+ process.exitCode = code;
21
+ return code;
22
+ }
23
+
24
+ /**
25
+ * Records a caught error in the failure store when it is a programming error (IC-010), silently and
26
+ * without changing anything the caller prints or exits with. For a handler that catches an error and
27
+ * reports it itself, so a bug in DoFlow is not swallowed by its own `[ERROR]` line.
28
+ * @param {*} error
29
+ * @param {string} command the verb or installer command name
30
+ * @param {number} exit the exit status the caller is about to produce
31
+ */
32
+ function captureCaught(error: any, command: string, exit: number): void {
33
+ try { require('./failure/capture.ts').captureError(error, { command, exit }); } catch { /* capture is best-effort */ }
34
+ }
35
+
36
+ /**
37
+ * Reports an argument the CLI cannot proceed without, in the caller's requested shape.
38
+ *
39
+ * `error` is the thrown error a catch site is turning into this usage result. When it is a
40
+ * programming error (IC-010) it is also recorded in the failure store, silently; the output and
41
+ * the exit status are the same either way (IC-016).
42
+ * @param {string} verb
43
+ * @param {string} message
44
+ * @param {boolean} [json]
45
+ * @param {Error} [error]
46
+ * @returns {number} 2 (USAGE error exit code)
47
+ */
48
+ function usageError(verb: string, message: string, json?: boolean, error?: Error): number {
49
+ if (error !== undefined) captureCaught(error, verb, 2);
50
+ if (json) console.log(JSON.stringify({ ok: false, status: 'USAGE', exitCode: 2, error: 'usage', summary: message }, null, 2));
51
+ else console.error(`doflow ${verb}: ${message}`);
52
+ return finishRuntime(2);
53
+ }
54
+
55
+ module.exports = { finishRuntime, usageError, captureCaught };