@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,698 @@
1
+ #!/usr/bin/env bash
2
+ # do-task-brief.sh — compose one task's brief or a group's brief into files the implementer reads.
3
+ #
4
+ # A doflow task is a single checklist line, and plan.md has no "global constraints"
5
+ # section, so a brief cannot be sliced out of one place the way it can when tasks are
6
+ # prose sections. It is COMPOSED from six sources (design §5.2), plus specs.md when the
7
+ # feature has one:
8
+ #
9
+ # where this fits plan.md §1 Approach + the task's own "### Phase X" heading
10
+ # requirements requirement.md §3 FR detail for the FRs the task's [US#] traces
11
+ # why requirement.md §2 story text for that [US#]
12
+ # global constraints requirement.md §4 — ALL NFR detail; NFRs bind every task
13
+ # component boundary design.md §3 detail for components serving those FRs
14
+ # verification bar plan.md §7 rows for those FRs + the phase's Checkpoints line
15
+ # interface contracts specs.md §1 in full — only when the resolver reports has_specs
16
+ #
17
+ # The brief becomes the single source of the task's exact values, so no subagent needs
18
+ # to open the plan — which is what keeps the context discipline real rather than
19
+ # aspirational.
20
+ #
21
+ # Sections are located by HEADING TEXT, never by ordinal, so inserting a section does
22
+ # not silently shift the parse. Anything that could not be resolved is reported in
23
+ # `missing[]` rather than yielding a quietly thin brief the implementer cannot tell
24
+ # is incomplete.
25
+ #
26
+ # Every brief also closes with a tier, tools and report-format block (IC-017) that the
27
+ # `brief-tools` verb composes from the registries and this machine's probes; this script reads the
28
+ # task line's `owner:` and `tier:`, calls the dispatcher once per brief and writes the block plus
29
+ # the `*-brief.json` record (IC-018) beside the brief. It names no tool, provider, server or tier.
30
+ # It fails open (IC-019): a missing dispatcher, a non-zero exit or output that is not the expected
31
+ # JSON gives a "Not generated" line and a static report-format block, a `missing[]` note, no
32
+ # record, and the exit status the brief would otherwise have had.
33
+ #
34
+ # Usage:
35
+ # do-task-brief.sh --task=<id> [--harness=<id>] [--slug=<slug>] [--json]
36
+ # do-task-brief.sh --group=<phase>:<owner> --tasks=<id,id,...> [--harness=<id>] [--slug=<slug>] [--json]
37
+ #
38
+ # Emits for task mode: {path, lines, record, traced:{story, frs[], nfrs[], components[]}, missing[]}
39
+ # Emits for group mode: {path, lines, record, tasks[], traced:{frs[], nfrs[], components[]}, missing[]}
40
+
41
+ set -uo pipefail
42
+
43
+ task_id=""
44
+ group_id=""
45
+ tasks_csv=""
46
+ slug_override=""
47
+ harness=""
48
+ mode=""
49
+
50
+ for arg in "$@"; do
51
+ case "$arg" in
52
+ --task=*)
53
+ task_id="${arg#--task=}"
54
+ mode="task"
55
+ ;;
56
+ --group=*)
57
+ group_id="${arg#--group=}"
58
+ mode="group"
59
+ ;;
60
+ --tasks=*)
61
+ tasks_csv="${arg#--tasks=}"
62
+ ;;
63
+ --slug=*)
64
+ slug_override="${arg#--slug=}"
65
+ ;;
66
+ --harness=*)
67
+ harness="${arg#--harness=}"
68
+ ;;
69
+ --json) ;;
70
+ *) ;;
71
+ esac
72
+ done
73
+
74
+ if ! command -v jq >/dev/null 2>&1; then
75
+ printf '{"error":"jq-not-found","path":null}\n'
76
+ exit 0
77
+ fi
78
+
79
+ validate_id() {
80
+ local id="$1"
81
+ case "$id" in
82
+ */*|*\\*|..*|*..|"") return 1 ;;
83
+ *) return 0 ;;
84
+ esac
85
+ }
86
+
87
+ if [ "$mode" = "group" ]; then
88
+ if [ -z "$group_id" ] || [ -z "$tasks_csv" ]; then
89
+ jq -n '{error:"missing-group-args", hint:"pass --group=<phase>:<owner> and --tasks=<id,id,...>"}'
90
+ exit 2
91
+ fi
92
+ if ! validate_id "$group_id"; then
93
+ jq -n --arg id "$group_id" '{error:"invalid-group", group_id:$id, hint:"a group id must be phase-dotted with a safe owner name"}'
94
+ exit 2
95
+ fi
96
+ elif [ "$mode" = "task" ]; then
97
+ if [ -z "$task_id" ]; then
98
+ jq -n '{error:"missing-task", hint:"pass --task=<id>, e.g. --task=A.1"}'
99
+ exit 2
100
+ fi
101
+ if ! validate_id "$task_id"; then
102
+ jq -n --arg id "$task_id" '{error:"invalid-task", task_id:$id, hint:"a task id is phase-dotted, e.g. A.1 — no path separators"}'
103
+ exit 2
104
+ fi
105
+ else
106
+ jq -n '{error:"missing-task", hint:"pass --task=<id>, e.g. --task=A.1"}'
107
+ exit 2
108
+ fi
109
+
110
+ script_dir="$(cd "$(dirname "$0")" && pwd)"
111
+ paths=""
112
+ if [ "$mode" = "group" ]; then
113
+ paths="$(bash "$script_dir/do-exec-paths.sh" --group="$group_id" --tasks="$tasks_csv" ${slug_override:+--slug="$slug_override"} 2>/dev/null)"
114
+ brief_rel="$(printf '%s' "$paths" | jq -r '.group_brief // empty')"
115
+ else
116
+ paths="$(bash "$script_dir/do-exec-paths.sh" --task="$task_id" ${slug_override:+--slug="$slug_override"} 2>/dev/null)"
117
+ brief_rel="$(printf '%s' "$paths" | jq -r '.brief // empty')"
118
+ fi
119
+
120
+ if [ -z "$brief_rel" ]; then
121
+ # Not "${paths:-{...}}": bash ends the expansion at the first unescaped `}`, so the default word
122
+ # is `{"error":"paths-unresolved"` and the final `}` is emitted *outside* it — appending a stray
123
+ # brace to $paths whenever $paths is non-empty. Every error passthrough here (a rejected task id,
124
+ # or simply running with no active feature) therefore produced JSON that `jq` refuses to parse.
125
+ if [ -n "$paths" ]; then
126
+ printf '%s\n' "$paths"
127
+ else
128
+ printf '%s\n' '{"error":"paths-unresolved"}'
129
+ fi
130
+ exit 2
131
+ fi
132
+
133
+ resolved="$(bash "$script_dir/do-paths.sh" --json ${slug_override:+--slug="$slug_override"} 2>/dev/null)"
134
+ repo_root="$(printf '%s' "$resolved" | jq -r '.repo_root // empty')"
135
+ plan_abs="$repo_root/$(printf '%s' "$resolved" | jq -r '.plan // empty')"
136
+ req_abs="$repo_root/$(printf '%s' "$resolved" | jq -r '.requirement // empty')"
137
+ des_abs="$repo_root/$(printf '%s' "$resolved" | jq -r '.design // empty')"
138
+ specs_abs="$repo_root/$(printf '%s' "$resolved" | jq -r '.specs // empty')"
139
+ has_specs="$(printf '%s' "$resolved" | jq -r '.has_specs // false')"
140
+ brief_abs="$repo_root/$brief_rel"
141
+ record_rel="$(printf '%s' "$paths" | jq -r '.brief_record // empty')"
142
+ feature_slug="$(printf '%s' "$resolved" | jq -r '.feature_slug // empty')"
143
+
144
+ # The preamble names specs.md only when this feature actually has one: a legacy-layout brief
145
+ # stays byte-identical to what it was before specs.md existed, rather than advertising a source
146
+ # the reader will not find a section for.
147
+ composed_from="plan.md, requirement.md and design.md"
148
+ if [ "$has_specs" = "true" ] && [ -f "$specs_abs" ]; then
149
+ composed_from="plan.md, requirement.md, design.md and specs.md"
150
+ fi
151
+
152
+ missing=()
153
+ [ -f "$plan_abs" ] || missing+=("plan.md not readable")
154
+ [ -f "$req_abs" ] || missing+=("requirement.md not readable")
155
+ [ -f "$des_abs" ] || missing+=("design.md not readable")
156
+
157
+ if [ ! -f "$plan_abs" ]; then
158
+ jq -n --arg p "$brief_rel" '{error:"no-plan", path:$p, hint:"a brief is composed from plan.md; there is nothing to compose"}'
159
+ exit 2
160
+ fi
161
+
162
+ # ── section extractor: by heading TEXT, stopping at the next same-level heading ─
163
+ section() { # section <file> <heading-regex>
164
+ awk -v want="$2" '
165
+ $0 ~ want { inside = 1; next }
166
+ inside && /^## / { exit }
167
+ inside { print }
168
+ ' "$1"
169
+ }
170
+
171
+ detail_for() { # detail_for <file> <section-regex> <id>
172
+ section "$1" "$2" | awk -v id="$3" '
173
+ $0 ~ "^- \\*\\*" id "([^A-Za-z0-9]|$)" { inside = 1; print; next }
174
+ inside && /^- \*\*/ { exit }
175
+ inside { print }
176
+ '
177
+ }
178
+
179
+ to_json_array() {
180
+ local input="${1:-}"
181
+ if [ -z "$input" ]; then
182
+ echo '[]'
183
+ else
184
+ printf '%s\n' "$input" | sed '/^$/d' | jq -R . | jq -s 'if length == 0 then [] else . end'
185
+ fi
186
+ }
187
+
188
+ # ── tier, tools and report format (IC-017 to IC-019) ─────────────────────────
189
+ # A task line field is "; <name>: <value>" or "— <name>: <value>"; the value is one safe word.
190
+ task_field() { # task_field <task line> <name>
191
+ printf '%s' "$1" | sed -nE "s/.*(; |— )$2: *([A-Za-z0-9_-]+).*/\\2/p"
192
+ }
193
+
194
+ # Sets bt_md and bt_record on success, bt_reason on every failure; never exits.
195
+ bt_call() { # bt_call <owner> <tier> <heading level> <task ids>
196
+ bt_md=""; bt_record=""; bt_reason=""
197
+ local dispatcher="$script_dir/../bin/doflow-run" out rc
198
+ if [ -z "$1" ]; then bt_reason="the task line names no owner"; return 0; fi
199
+ if [ ! -f "$dispatcher" ]; then bt_reason="the dispatcher was not found"; return 0; fi
200
+ out="$(cd "${repo_root:-.}" 2>/dev/null && bash "$dispatcher" brief-tools --json --owner "$1" \
201
+ ${2:+--tier "$2"} ${harness:+--harness "$harness"} ${feature_slug:+--slug "$feature_slug"} \
202
+ --heading-level "$3" ${4:+--tasks "$4"} </dev/null 2>/dev/null)"
203
+ rc=$?
204
+ if [ "$rc" -ne 0 ]; then bt_reason="brief-tools exited $rc"; return 0; fi
205
+ if ! printf '%s' "$out" | jq -e '(.markdown | type == "string" and length > 0) and (.record | type == "object")' >/dev/null 2>&1; then
206
+ bt_reason="brief-tools printed unparseable output"; return 0
207
+ fi
208
+ bt_md="$(printf '%s' "$out" | jq -r '.markdown')"
209
+ bt_record="$(printf '%s' "$out" | jq -c '.record')"
210
+ return 0
211
+ }
212
+
213
+ # The block for the brief: the verb's markdown, or the static fallback (no tool names).
214
+ bt_emit() { # bt_emit <heading level>
215
+ local h="##" who="your report"
216
+ if [ "$1" = "3" ]; then h="###"; who="each task's report"; fi
217
+ if [ -n "$bt_md" ]; then
218
+ printf '%s\n' "$bt_md"
219
+ return 0
220
+ fi
221
+ printf '%s Tier and tools\n\nNot generated: %s. Name the tier and tools in the dispatch.\n\n' "$h" "$bt_reason"
222
+ printf '%s Report format\n\nEnd %s with one line naming every tool and MCP server you used:\n' "$h" "$who"
223
+ printf '%s\n' '`Tools used: <name>[=used|nothing-usable|unavailable|skipped:<reason>], ...`'
224
+ }
225
+
226
+ # Writes the record beside the brief with its tasks filled in; sets record_out to its path, or to ""
227
+ # when there is nothing to write or the write failed.
228
+ record_out=""
229
+ bt_write_record() { # bt_write_record <tasks json>
230
+ record_out=""
231
+ [ -n "$bt_record" ] || return 0
232
+ [ -n "$record_rel" ] || { missing+=("brief-tools: no record path from do-exec-paths.sh"); return 0; }
233
+ if printf '%s' "$bt_record" | jq --argjson tasks "$1" '. + {tasks: $tasks}' > "$repo_root/$record_rel" 2>/dev/null; then
234
+ record_out="$record_rel"
235
+ else
236
+ rm -f "$repo_root/$record_rel" 2>/dev/null
237
+ missing+=("brief-tools: the record could not be written")
238
+ fi
239
+ }
240
+
241
+ nfrs=""
242
+ if [ -f "$req_abs" ]; then
243
+ nfrs="$(section "$req_abs" '^## 4[.]' | grep -o '^| *NFR-[0-9]*' | tr -d '| ')"
244
+ fi
245
+
246
+ # Parse task list
247
+ task_ids=()
248
+ if [ "$mode" = "group" ]; then
249
+ IFS=',' read -ra raw_task_ids <<< "$tasks_csv"
250
+ for tid in "${raw_task_ids[@]}"; do
251
+ tid="$(echo "$tid" | tr -d ' ')"
252
+ [ -n "$tid" ] && task_ids+=("$tid")
253
+ done
254
+ else
255
+ task_ids=("$task_id")
256
+ fi
257
+
258
+ # In single task mode: check if task exists
259
+ if [ "$mode" = "task" ]; then
260
+ task_line="$(awk -v id="$task_id" '
261
+ $0 ~ "^- \\[[ x]\\] " id "([^0-9]|$)" { print; exit }' "$plan_abs")"
262
+ if [ -z "$task_line" ]; then
263
+ jq -n --arg id "$task_id" '{error:"task-not-found", task_id:$id, hint:"no \"- [ ] <id>\" line in plan.md section 8"}'
264
+ exit 3
265
+ fi
266
+ phase_heading="$(awk -v id="$task_id" '
267
+ /^### Phase / { h = $0 }
268
+ $0 ~ "^- \\[[ x]\\] " id "([^0-9]|$)" { print h; exit }' "$plan_abs")"
269
+ phase_letter="$(printf '%s' "$phase_heading" | awk '{print $3}')"
270
+
271
+ story="$(printf '%s' "$task_line" | grep -o '\[US[0-9]\+\]' | head -1 | tr -d '[]')"
272
+ files_field="$(printf '%s' "$task_line" | sed -n 's/.*files: \([^;]*\).*/\1/p')"
273
+ [ -n "$story" ] || missing+=("task line carries no [US#] trace")
274
+
275
+ frs=""
276
+ if [ -n "$story" ] && [ -f "$req_abs" ]; then
277
+ frs="$(section "$req_abs" '^## 3[.]' | awk -F'|' -v s="$story" '
278
+ /^\| *FR-/ {
279
+ id = $2; sto = $4
280
+ gsub(/^[ \t]+|[ \t]+$/, "", id); gsub(/^[ \t]+|[ \t]+$/, "", sto)
281
+ if (sto == s) print id
282
+ }')"
283
+ fi
284
+ [ -n "$frs" ] || missing+=("no FR in requirement.md section 3 traces to ${story:-this task}")
285
+
286
+ components=""
287
+ if [ -n "$frs" ] && [ -f "$des_abs" ]; then
288
+ components="$(for fr in $frs; do
289
+ section "$des_abs" '^## 3[.]' | awk -F'|' -v fr="$fr" '
290
+ /^\| *CMP/ { if ($5 ~ fr) { id = $2; gsub(/^[ \t]+|[ \t]+$/, "", id); print id } }'
291
+ done | sort -u)"
292
+ fi
293
+
294
+ bt_call "$(task_field "$task_line" owner)" "$(task_field "$task_line" tier)" 2 "$task_id"
295
+ [ -z "$bt_reason" ] || missing+=("brief-tools: $bt_reason")
296
+
297
+ # Compose brief
298
+ write_ok=1
299
+ {
300
+ echo "# Task brief: $task_id"
301
+ echo
302
+ echo "> Composed from $composed_from. This brief is your requirements —"
303
+ echo "> use the exact values it gives, verbatim. You do not need to open the plan."
304
+ echo
305
+ echo "## The task"
306
+ echo
307
+ echo "${task_line#- \[ \] }"
308
+ echo
309
+ [ -n "$phase_heading" ] && { echo "Phase: ${phase_heading#\#\#\# }"; echo; }
310
+ [ -n "$files_field" ] && { echo "Files you own: $files_field"; echo; }
311
+
312
+ echo "## Where this fits"
313
+ echo
314
+ section "$plan_abs" '^## 1[.]' | sed '/^$/d' | head -8
315
+ echo
316
+
317
+ if [ -n "$story" ] && [ -f "$req_abs" ]; then
318
+ echo "## Why (user story)"
319
+ echo
320
+ section "$req_abs" '^## 2[.]' | awk -v s="$story" '
321
+ $0 ~ ("^- \\*\\*" s "([^0-9]|$)") { inside = 1; sub(/^- /, ""); print; next }
322
+ inside && /^- \*\*/ { exit }
323
+ inside { print }' || true
324
+ echo
325
+ fi
326
+
327
+ if [ -n "$frs" ]; then
328
+ echo "## Requirements — build exactly these"
329
+ echo
330
+ for fr in $frs; do detail_for "$req_abs" '^## 3[.]' "$fr"; done
331
+ echo
332
+ fi
333
+
334
+ if [ -f "$req_abs" ]; then
335
+ echo "## Global constraints — these bind every task"
336
+ echo
337
+ section "$req_abs" '^## 4[.]' | awk '/^- \*\*NFR-/ { p = 1 } p' | sed '/^$/d'
338
+ echo
339
+ fi
340
+
341
+ if [ -n "$components" ]; then
342
+ echo "## Component boundary"
343
+ echo
344
+ printf '%s\n' "$components" | while read -r cmp; do
345
+ [ -n "$cmp" ] && detail_for "$des_abs" '^## 3[.]' "$cmp"
346
+ done
347
+ echo
348
+ fi
349
+
350
+ if [ "$has_specs" = "true" ] && [ -f "$specs_abs" ]; then
351
+ echo "## Interface contracts"
352
+ echo
353
+ # §1 IN FULL, deliberately unfiltered: an IC-### entry carries no FR or component
354
+ # linkage field, so there is nothing to filter it by the way "component boundary"
355
+ # above filters design.md §3 rows on the FRs they name.
356
+ section "$specs_abs" '^## 1[.]' | awk 'NF { p = 1 } p'
357
+ echo
358
+ fi
359
+
360
+ echo "## Verification bar"
361
+ echo
362
+ for fr in $frs; do
363
+ section "$plan_abs" '^## 7[.]' | grep -F "| $fr |" || true
364
+ done
365
+ [ -n "$phase_letter" ] && grep -F "After Phase $phase_letter:" "$plan_abs" || true
366
+ echo
367
+ bt_emit 2
368
+ } > "$brief_abs" || write_ok=0
369
+
370
+ if [ "${write_ok:-1}" -eq 0 ] || [ ! -s "$brief_abs" ]; then
371
+ jq -n --arg path "$brief_rel" \
372
+ '{error:"write-failed", path:$path, hint:"the task brief could not be written — check the workspace is writable"}'
373
+ exit 2
374
+ fi
375
+
376
+ lines="$(wc -l < "$brief_abs" | tr -d ' ')"
377
+
378
+ bt_write_record "$(jq -nc --arg id "$task_id" --arg report "$(printf '%s' "$paths" | jq -r '.report // empty')" '[{id:$id, report:$report}]')"
379
+
380
+ jq -n \
381
+ --arg path "$brief_rel" \
382
+ --arg record "$record_out" \
383
+ --argjson lines "${lines:-0}" \
384
+ --arg story "$story" \
385
+ --argjson frs "$(to_json_array "$frs")" \
386
+ --argjson nfrs "$(to_json_array "$nfrs")" \
387
+ --argjson components "$(to_json_array "$components")" \
388
+ --argjson missing "$(to_json_array "$(printf '%s\n' "${missing[@]+"${missing[@]}"}" | sed '/^$/d')")" \
389
+ '{path:$path, lines:$lines, record:(if $record=="" then null else $record end),
390
+ traced:{story:(if $story=="" then null else $story end), frs:$frs, nfrs:$nfrs, components:$components},
391
+ missing:$missing}'
392
+ exit 0
393
+
394
+ else
395
+ # Group mode
396
+ num_tasks="${#task_ids[@]}"
397
+
398
+ # For each task in group, collect details into arrays
399
+ declare -a task_lines=()
400
+ declare -a task_phases=()
401
+ declare -a task_phase_letters=()
402
+ declare -a task_stories=()
403
+ declare -a task_files=()
404
+ declare -a task_fr_lists=()
405
+ all_frs_raw=""
406
+ all_comps_raw=""
407
+
408
+ for tid in "${task_ids[@]}"; do
409
+ t_line="$(awk -v id="$tid" '
410
+ $0 ~ "^- \\[[ x]\\] " id "([^0-9]|$)" { print; exit }' "$plan_abs")"
411
+ if [ -z "$t_line" ]; then
412
+ missing+=("$tid: task line not found in plan.md")
413
+ task_lines+=("")
414
+ task_phases+=("")
415
+ task_phase_letters+=("")
416
+ task_stories+=("")
417
+ task_files+=("")
418
+ task_fr_lists+=("")
419
+ continue
420
+ fi
421
+
422
+ t_phase="$(awk -v id="$tid" '
423
+ /^### Phase / { h = $0 }
424
+ $0 ~ "^- \\[[ x]\\] " id "([^0-9]|$)" { print h; exit }' "$plan_abs")"
425
+ t_phase_let="$(printf '%s' "$t_phase" | awk '{print $3}')"
426
+ t_files="$(printf '%s' "$t_line" | sed -n 's/.*files: \([^;]*\).*/\1/p')"
427
+ t_story="$(printf '%s' "$t_line" | grep -o '\[US[0-9]\+\]' | head -1 | tr -d '[]')"
428
+
429
+ [ -n "$t_story" ] || missing+=("$tid: task line carries no [US#] trace")
430
+
431
+ t_frs=""
432
+ if [ -n "$t_story" ] && [ -f "$req_abs" ]; then
433
+ t_frs="$(section "$req_abs" '^## 3[.]' | awk -F'|' -v s="$t_story" '
434
+ /^\| *FR-/ {
435
+ id = $2; sto = $4
436
+ gsub(/^[ \t]+|[ \t]+$/, "", id); gsub(/^[ \t]+|[ \t]+$/, "", sto)
437
+ if (sto == s) print id
438
+ }')"
439
+ fi
440
+ [ -n "$t_frs" ] || missing+=("$tid: no FR in requirement.md section 3 traces to ${t_story:-this task}")
441
+
442
+ for f in $t_frs; do
443
+ all_frs_raw="${all_frs_raw}${f}"$'\n'
444
+ done
445
+
446
+ task_lines+=("$t_line")
447
+ task_phases+=("$t_phase")
448
+ task_phase_letters+=("$t_phase_let")
449
+ task_stories+=("$t_story")
450
+ task_files+=("$t_files")
451
+ task_fr_lists+=("$t_frs")
452
+ done
453
+
454
+ # Union of FRs
455
+ all_frs="$(printf '%s' "$all_frs_raw" | sed '/^$/d' | sort -u)"
456
+
457
+ # Union of components serving those FRs
458
+ if [ -n "$all_frs" ] && [ -f "$des_abs" ]; then
459
+ all_comps_raw="$(for fr in $all_frs; do
460
+ section "$des_abs" '^## 3[.]' | awk -F'|' -v fr="$fr" '
461
+ /^\| *CMP/ { if ($5 ~ fr) { id = $2; gsub(/^[ \t]+|[ \t]+$/, "", id); print id } }'
462
+ done | sort -u)"
463
+ fi
464
+
465
+ # The group's owner is the part of --group after the phase; its tier is the tasks' shared tier.
466
+ group_owner=""
467
+ case "$group_id" in *:*) group_owner="${group_id#*:}" ;; esac
468
+ group_tier=""
469
+ for idx in "${!task_ids[@]}"; do
470
+ t_tier="$(task_field "${task_lines[$idx]}" tier)"
471
+ if [ "$idx" -eq 0 ]; then group_tier="$t_tier"
472
+ elif [ "$t_tier" != "$group_tier" ]; then group_tier=""; break; fi
473
+ done
474
+ bt_level=3
475
+ [ "$num_tasks" -eq 1 ] && bt_level=2
476
+ bt_call "$group_owner" "$group_tier" "$bt_level" "$(IFS=,; printf '%s' "${task_ids[*]}")"
477
+ [ -z "$bt_reason" ] || missing+=("brief-tools: $bt_reason")
478
+
479
+ write_ok=1
480
+ if [ "$num_tasks" -eq 1 ]; then
481
+ # Single-task group: byte-identical output to --task=
482
+ t_id="${task_ids[0]}"
483
+ t_line="${task_lines[0]}"
484
+ t_phase="${task_phases[0]}"
485
+ t_phase_let="${task_phase_letters[0]}"
486
+ t_story="${task_stories[0]}"
487
+ t_files="${task_files[0]}"
488
+ t_frs="${task_fr_lists[0]}"
489
+
490
+ t_comps=""
491
+ if [ -n "$t_frs" ] && [ -f "$des_abs" ]; then
492
+ t_comps="$(for fr in $t_frs; do
493
+ section "$des_abs" '^## 3[.]' | awk -F'|' -v fr="$fr" '
494
+ /^\| *CMP/ { if ($5 ~ fr) { id = $2; gsub(/^[ \t]+|[ \t]+$/, "", id); print id } }'
495
+ done | sort -u)"
496
+ fi
497
+
498
+ {
499
+ echo "# Task brief: $t_id"
500
+ echo
501
+ echo "> Composed from $composed_from. This brief is your requirements —"
502
+ echo "> use the exact values it gives, verbatim. You do not need to open the plan."
503
+ echo
504
+ echo "## The task"
505
+ echo
506
+ echo "${t_line#- \[ \] }"
507
+ echo
508
+ [ -n "$t_phase" ] && { echo "Phase: ${t_phase#\#\#\# }"; echo; }
509
+ [ -n "$t_files" ] && { echo "Files you own: $t_files"; echo; }
510
+
511
+ echo "## Where this fits"
512
+ echo
513
+ section "$plan_abs" '^## 1[.]' | sed '/^$/d' | head -8
514
+ echo
515
+
516
+ if [ -n "$t_story" ] && [ -f "$req_abs" ]; then
517
+ echo "## Why (user story)"
518
+ echo
519
+ section "$req_abs" '^## 2[.]' | awk -v s="$t_story" '
520
+ $0 ~ ("^- \\*\\*" s "([^0-9]|$)") { inside = 1; sub(/^- /, ""); print; next }
521
+ inside && /^- \*\*/ { exit }
522
+ inside { print }' || true
523
+ echo
524
+ fi
525
+
526
+ if [ -n "$t_frs" ]; then
527
+ echo "## Requirements — build exactly these"
528
+ echo
529
+ for fr in $t_frs; do detail_for "$req_abs" '^## 3[.]' "$fr"; done
530
+ echo
531
+ fi
532
+
533
+ if [ -f "$req_abs" ]; then
534
+ echo "## Global constraints — these bind every task"
535
+ echo
536
+ section "$req_abs" '^## 4[.]' | awk '/^- \*\*NFR-/ { p = 1 } p' | sed '/^$/d'
537
+ echo
538
+ fi
539
+
540
+ if [ -n "$t_comps" ]; then
541
+ echo "## Component boundary"
542
+ echo
543
+ printf '%s\n' "$t_comps" | while read -r cmp; do
544
+ [ -n "$cmp" ] && detail_for "$des_abs" '^## 3[.]' "$cmp"
545
+ done
546
+ echo
547
+ fi
548
+
549
+ if [ "$has_specs" = "true" ] && [ -f "$specs_abs" ]; then
550
+ echo "## Interface contracts"
551
+ echo
552
+ # §1 IN FULL, deliberately unfiltered — see the --task= path above: an IC-### entry
553
+ # carries no FR or component linkage field to filter it by.
554
+ section "$specs_abs" '^## 1[.]' | awk 'NF { p = 1 } p'
555
+ echo
556
+ fi
557
+
558
+ echo "## Verification bar"
559
+ echo
560
+ for fr in $t_frs; do
561
+ section "$plan_abs" '^## 7[.]' | grep -F "| $fr |" || true
562
+ done
563
+ [ -n "$t_phase_let" ] && grep -F "After Phase $t_phase_let:" "$plan_abs" || true
564
+ echo
565
+ bt_emit 2
566
+ } > "$brief_abs" || write_ok=0
567
+
568
+ else
569
+ # Multi-task group: shared preamble once + one block per task
570
+ {
571
+ echo "# Group brief: $group_id"
572
+ echo
573
+ echo "> Composed from $composed_from. This brief covers multiple tasks that share an owner."
574
+ echo
575
+ echo "## Shared context"
576
+ echo
577
+ echo "### Where this fits"
578
+ echo
579
+ section "$plan_abs" '^## 1[.]' | sed '/^$/d' | head -8
580
+ echo
581
+
582
+ if [ -f "$req_abs" ]; then
583
+ echo "### Global constraints — these bind every task"
584
+ echo
585
+ section "$req_abs" '^## 4[.]' | awk '/^- \*\*NFR-/ { p = 1 } p' | sed '/^$/d'
586
+ echo
587
+ fi
588
+
589
+ if [ -n "$all_comps_raw" ]; then
590
+ echo "### Component boundary"
591
+ echo
592
+ printf '%s\n' "$all_comps_raw" | while read -r cmp; do
593
+ [ -n "$cmp" ] && detail_for "$des_abs" '^## 3[.]' "$cmp"
594
+ done
595
+ echo
596
+ fi
597
+
598
+ if [ "$has_specs" = "true" ] && [ -f "$specs_abs" ]; then
599
+ echo "### Interface contracts"
600
+ echo
601
+ # §1 IN FULL, deliberately unfiltered — see the --task= path above: an IC-### entry
602
+ # carries no FR or component linkage field to filter it by. Shared context, since
603
+ # every task in the group is bound by the same contracts.
604
+ section "$specs_abs" '^## 1[.]' | awk 'NF { p = 1 } p'
605
+ echo
606
+ fi
607
+
608
+ bt_emit 3
609
+ echo
610
+
611
+ echo "## Task order"
612
+ echo
613
+ task_order=""
614
+ for tid in "${task_ids[@]}"; do
615
+ if [ -n "$task_order" ]; then
616
+ task_order="$task_order → $tid"
617
+ else
618
+ task_order="$tid"
619
+ fi
620
+ done
621
+ echo "$task_order (write each task's report before starting the next)"
622
+ echo
623
+
624
+ for idx in "${!task_ids[@]}"; do
625
+ tid="${task_ids[$idx]}"
626
+ t_line="${task_lines[$idx]}"
627
+ t_phase="${task_phases[$idx]}"
628
+ t_phase_let="${task_phase_letters[$idx]}"
629
+ t_story="${task_stories[$idx]}"
630
+ t_files="${task_files[$idx]}"
631
+ t_frs="${task_fr_lists[$idx]}"
632
+
633
+ echo "## Task $tid"
634
+ echo
635
+ echo "${t_line#- \[ \] }"
636
+ echo
637
+
638
+ if [ -n "$t_story" ] && [ -f "$req_abs" ]; then
639
+ echo "### Why (user story)"
640
+ echo
641
+ section "$req_abs" '^## 2[.]' | awk -v s="$t_story" '
642
+ $0 ~ ("^- \\*\\*" s "([^0-9]|$)") { inside = 1; sub(/^- /, ""); print; next }
643
+ inside && /^- \*\*/ { exit }
644
+ inside { print }' || true
645
+ echo
646
+ fi
647
+
648
+ if [ -n "$t_frs" ]; then
649
+ echo "### Requirements — build exactly these"
650
+ echo
651
+ for fr in $t_frs; do detail_for "$req_abs" '^## 3[.]' "$fr"; done
652
+ echo
653
+ fi
654
+
655
+ if [ -n "$t_files" ]; then
656
+ echo "### Files you own"
657
+ echo
658
+ echo "$t_files"
659
+ echo
660
+ fi
661
+
662
+ echo "### Verification bar"
663
+ echo
664
+ for fr in $t_frs; do
665
+ section "$plan_abs" '^## 7[.]' | grep -F "| $fr |" || true
666
+ done
667
+ [ -n "$t_phase_let" ] && grep -F "After Phase $t_phase_let:" "$plan_abs" || true
668
+ echo
669
+ done
670
+ } > "$brief_abs" || write_ok=0
671
+ fi
672
+
673
+ if [ "${write_ok:-1}" -eq 0 ] || [ ! -s "$brief_abs" ]; then
674
+ jq -n --arg path "$brief_rel" \
675
+ '{error:"write-failed", path:$path, hint:"the task brief could not be written — check the workspace is writable"}'
676
+ exit 2
677
+ fi
678
+
679
+ lines="$(wc -l < "$brief_abs" | tr -d ' ')"
680
+
681
+ bt_write_record "$(jq -nc --argjson reports "$(printf '%s' "$paths" | jq -c '.reports // []')" \
682
+ '$ARGS.positional as $ids | [range(0; $ids | length) | {id: $ids[.], report: ($reports[.] // null)}]' \
683
+ --args "${task_ids[@]}")"
684
+
685
+ jq -n \
686
+ --arg path "$brief_rel" \
687
+ --arg record "$record_out" \
688
+ --argjson lines "${lines:-0}" \
689
+ --argjson frs "$(to_json_array "$all_frs")" \
690
+ --argjson nfrs "$(to_json_array "$nfrs")" \
691
+ --argjson components "$(to_json_array "$all_comps_raw")" \
692
+ --argjson missing "$(to_json_array "$(printf '%s\n' "${missing[@]+"${missing[@]}"}" | sed '/^$/d')")" \
693
+ '{path:$path, lines:$lines, record:(if $record=="" then null else $record end), tasks:$ARGS.positional,
694
+ traced:{frs:$frs, nfrs:$nfrs, components:$components},
695
+ missing:$missing}' \
696
+ --args "${task_ids[@]}"
697
+ exit 0
698
+ fi