@khoavu882/doflow 2.0.0-beta.5 → 2.0.0

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 (471) hide show
  1. package/README.md +12 -11
  2. package/bin/doflow.js +21 -11
  3. package/core/.antigravity-plugin/plugin.json +1 -2
  4. package/core/.claude-plugin/plugin.json +1 -1
  5. package/core/.codex-plugin/plugin.json +1 -1
  6. package/core/.plugin/plugin.json +1 -1
  7. package/core/harnesses/claude/hooks/lib.sh +43 -24
  8. package/core/harnesses/claude/hooks/permission-audit.sh +3 -0
  9. package/core/harnesses/claude/hooks/post-compact.sh +35 -32
  10. package/core/harnesses/claude/hooks/post-edit-lint.sh +2 -0
  11. package/core/harnesses/claude/hooks/post-shell-observe.sh +48 -0
  12. package/core/harnesses/claude/hooks/post-tool-failure.sh +3 -0
  13. package/core/harnesses/claude/hooks/pre-compact.sh +23 -27
  14. package/core/harnesses/claude/hooks/session-end.sh +23 -10
  15. package/core/harnesses/claude/hooks/skill-config-audit.sh +3 -0
  16. package/core/harnesses/claude/settings/settings.json +18 -0
  17. package/core/harnesses/claude/statusline/doflow-statusline.sh +1 -0
  18. package/core/harnesses/codex/agents/core-implementer.toml +1 -0
  19. package/core/harnesses/codex/agents/delivery-lead.toml +10 -0
  20. package/core/harnesses/codex/agents/quality-guardian.toml +1 -1
  21. package/core/harnesses/codex/agents/research-writer.toml +1 -1
  22. package/core/harnesses/codex/agents/reviewer.toml +10 -0
  23. package/core/harnesses/codex/agents/spec-analyst.toml +1 -1
  24. package/core/harnesses/codex/agents/system-architect.toml +1 -1
  25. package/core/harnesses/codex/hooks/lib.sh +44 -25
  26. package/core/harnesses/codex/hooks/post-edit-lint.impl.sh +3 -1
  27. package/core/harnesses/codex/hooks/pre-compact.impl.sh +29 -26
  28. package/core/harnesses/codex/hooks/session-end.impl.sh +23 -10
  29. package/core/harnesses/codex/hooks/subagent-audit.sh +1 -0
  30. package/core/harnesses/copilot/hooks/doflow-lib.sh +93 -0
  31. package/core/harnesses/copilot/hooks/doflow-mcp-tool-guard.sh +9 -0
  32. package/core/harnesses/copilot/hooks/doflow-pre-bash-guard.sh +9 -0
  33. package/core/harnesses/copilot/hooks/doflow-pre-implement-gate.sh +9 -0
  34. package/core/harnesses/copilot/hooks/doflow-session-start.sh +9 -0
  35. package/core/harnesses/copilot/hooks/doflow-stop-check.sh +9 -0
  36. package/core/harnesses/copilot/hooks/doflow-subagent-start.sh +9 -0
  37. package/core/harnesses/copilot/hooks/doflow-subagent-stop.sh +9 -0
  38. package/core/harnesses/copilot/hooks/doflow.json +57 -0
  39. package/core/harnesses/kiro/agents/doflow.json +1 -1
  40. package/core/harnesses/kiro/hooks/lib.sh +26 -6
  41. package/core/harnesses/kiro/hooks/mcp-tool-guard.sh +1 -0
  42. package/core/harnesses/kiro/hooks/pre-bash-guard.sh +1 -0
  43. package/core/harnesses/kiro/hooks/pre-implement-gate.sh +1 -0
  44. package/core/harnesses/kiro/hooks/session-start.sh +1 -0
  45. package/core/harnesses/kiro/hooks/stop-check.sh +1 -0
  46. package/core/harnesses/pi/extensions/doflow-guard.js +8 -0
  47. package/core/harnesses/shared/hooks/ENVELOPE_MIGRATION.md +0 -1
  48. package/core/harnesses/shared/hooks/bridge/bridge.sh +102 -9
  49. package/core/harnesses/shared/hooks/bridge/envelope.jq +87 -18
  50. package/core/harnesses/shared/hooks/bridge/observe-model.sh +75 -0
  51. package/core/harnesses/shared/hooks/bridge/respond.sh +10 -2
  52. package/core/harnesses/shared/hooks/policies/blocked-patterns.conf +28 -14
  53. package/core/harnesses/shared/hooks/policies/capture-failure.sh +48 -15
  54. package/core/harnesses/shared/hooks/policies/compact-text.sh +46 -0
  55. package/core/harnesses/shared/hooks/policies/contract.sh +3 -0
  56. package/core/harnesses/shared/hooks/policies/deny-json.sh +2 -11
  57. package/core/harnesses/shared/hooks/policies/emission-rules.sh +37 -0
  58. package/core/harnesses/shared/hooks/policies/emission.jq +209 -0
  59. package/core/harnesses/shared/hooks/policies/emission.sh +383 -0
  60. package/core/harnesses/shared/hooks/policies/identity.sh +177 -0
  61. package/core/harnesses/shared/hooks/policies/lib.sh +63 -40
  62. package/core/harnesses/shared/hooks/policies/mcp-tool-guard.sh +3 -2
  63. package/core/harnesses/shared/hooks/policies/pre-bash-guard.sh +213 -12
  64. package/core/harnesses/shared/hooks/policies/pre-implementation-gate.sh +114 -38
  65. package/core/harnesses/shared/hooks/policies/session-context.sh +30 -1
  66. package/core/harnesses/shared/hooks/policies/stop-check.sh +20 -9
  67. package/core/harnesses/shared/hooks/policies/subagent-audit.sh +5 -2
  68. package/core/harnesses/shared/hooks/policies/summary-store.sh +347 -0
  69. package/core/harnesses/shared/hooks/policies/user-prompt-submit.sh +60 -155
  70. package/core/harnesses/shared/hooks/stream-hook-runner.js +47 -8
  71. package/core/harnesses/shared/locator/doflow-run +2 -3
  72. package/core/registry/advice.json +3 -3
  73. package/core/registry/assets.json +55 -82
  74. package/core/registry/capabilities.json +12 -0
  75. package/core/registry/contracts.json +58 -31
  76. package/core/registry/contribution-points.json +32 -0
  77. package/core/registry/gates.json +32 -0
  78. package/core/registry/guidance-caps.json +40 -0
  79. package/core/registry/harnesses.json +1442 -363
  80. package/core/registry/lifecycle.json +485 -304
  81. package/core/registry/mcp.json +5 -1
  82. package/core/registry/models.json +7 -1
  83. package/core/registry/package-templates/README.md +19 -0
  84. package/core/registry/package-templates/agent/files/agent.md +9 -0
  85. package/core/registry/package-templates/agent/template.json +4 -0
  86. package/core/registry/package-templates/capability-provider/files/provider.json +9 -0
  87. package/core/registry/package-templates/capability-provider/template.json +11 -0
  88. package/core/registry/package-templates/debate-preset/files/preset.json +26 -0
  89. package/core/registry/package-templates/debate-preset/template.json +4 -0
  90. package/core/registry/package-templates/review-preset/files/preset.json +30 -0
  91. package/core/registry/package-templates/review-preset/template.json +4 -0
  92. package/core/registry/package-templates/skill/files/SKILL.md +8 -0
  93. package/core/registry/package-templates/skill/template.json +4 -0
  94. package/core/registry/package-templates/worker/files/worker.json +92 -0
  95. package/core/registry/package-templates/worker/template.json +11 -0
  96. package/core/registry/packages/doflow/doflow-package.json +15 -0
  97. package/core/registry/packages/doflow/presets/debate-3.json +26 -0
  98. package/core/registry/protocols.json +61 -0
  99. package/core/registry/routes.json +17 -0
  100. package/core/registry/rules.json +431 -0
  101. package/core/registry/settings.json +276 -0
  102. package/core/registry/storage.json +679 -31
  103. package/core/registry/telemetry.json +236 -0
  104. package/core/registry/transcripts.json +142 -0
  105. package/core/registry/verification.json +76 -1
  106. package/core/registry/workflows.json +55 -0
  107. package/core/shared/agent-specs/core-implementer.md +3 -0
  108. package/core/shared/agent-specs/delivery-lead.md +68 -0
  109. package/core/shared/agent-specs/quality-guardian.md +5 -1
  110. package/core/shared/agent-specs/research-writer.md +10 -3
  111. package/core/shared/agent-specs/reviewer.md +53 -0
  112. package/core/shared/agent-specs/spec-analyst.md +5 -6
  113. package/core/shared/agent-specs/system-architect.md +5 -1
  114. package/core/shared/guidance/DOFLOW_CORE.md +1 -5
  115. package/core/shared/guidance/modes/MODE_DeepResearch.md +1 -1
  116. package/core/shared/guidance/modes/MODE_Orchestration.md +4 -3
  117. package/core/shared/guidance/modes/MODE_Task_Management.md +14 -14
  118. package/core/shared/guidance/pointers/codex.md +1 -4
  119. package/core/shared/guidance/references/ARTIFACT_FORMAT.md +30 -16
  120. package/core/shared/guidance/references/ARTIFACT_VOICE.md +3 -2
  121. package/core/shared/guidance/references/CONSTITUTION_BASE.md +17 -15
  122. package/core/shared/guidance/references/DIAGRAM_GUIDE.md +1 -1
  123. package/core/shared/guidance/references/DOFLOW_CHAIN.md +17 -19
  124. package/core/shared/guidance/references/EVIDENCE_LEDGER.md +7 -8
  125. package/core/shared/guidance/references/MODEL_SELECTION.md +5 -3
  126. package/core/shared/guidance/references/ORCHESTRATION.md +1 -2
  127. package/core/shared/guidance/rules/RULES.md +45 -0
  128. package/core/shared/scripts/doflow/bash/do-args.sh +37 -0
  129. package/core/shared/scripts/doflow/bash/do-exec-paths.sh +4 -0
  130. package/core/shared/scripts/doflow/bash/do-git-state.sh +15 -4
  131. package/core/shared/scripts/doflow/bash/do-parallel-check.sh +4 -0
  132. package/core/shared/scripts/doflow/bash/do-paths.sh +40 -2
  133. package/core/shared/scripts/doflow/bash/do-prereqs.sh +2 -1
  134. package/core/shared/scripts/doflow/bash/do-review-package.sh +4 -0
  135. package/core/shared/scripts/doflow/bash/do-task-brief.sh +58 -16
  136. package/core/shared/scripts/doflow/bash/render-audit.sh +26 -2
  137. package/core/shared/scripts/doflow/bash/render-diagrams.sh +1 -0
  138. package/core/shared/scripts/doflow/bash/render-puml.sh +2 -1
  139. package/core/shared/scripts/doflow/bash/validate-artifacts.sh +48 -4
  140. package/core/shared/scripts/doflow/bin/doflow-run +149 -34
  141. package/core/shared/skills/do/SKILL.md +12 -10
  142. package/core/shared/skills/do/references/advice_calls.md +26 -0
  143. package/core/shared/skills/do/references/pm_routing.md +1 -2
  144. package/core/shared/skills/do/references/program_mode.md +31 -0
  145. package/core/shared/skills/do-brainstorm/SKILL.md +20 -74
  146. package/core/shared/skills/do-brainstorm/references/handoff_branches.md +35 -0
  147. package/core/shared/skills/do-brainstorm/references/intent_seed.md +21 -0
  148. package/core/shared/skills/do-brainstorm/references/round_log.md +17 -0
  149. package/core/shared/skills/do-code-review/SKILL.md +41 -144
  150. package/core/shared/skills/do-code-review/content-types/markdown.md +24 -2
  151. package/core/shared/skills/do-code-review/references/tools.md +90 -0
  152. package/core/shared/skills/do-code-review/scripts/doc_quality_checker.py +549 -7
  153. package/core/shared/skills/do-design/SKILL.md +18 -17
  154. package/core/shared/skills/do-diagnose/SKILL.md +14 -4
  155. package/core/shared/skills/do-document/SKILL.md +11 -1
  156. package/core/shared/skills/do-document/references/deep_research.md +1 -2
  157. package/core/shared/skills/do-document/references/embedded-research.md +18 -6
  158. package/core/shared/skills/do-document/references/implementation-flow.md +5 -6
  159. package/core/shared/skills/do-execute-plan/SKILL.md +15 -58
  160. package/core/shared/skills/do-execute-plan/references/handoff_record.md +7 -2
  161. package/core/shared/skills/do-execute-plan/references/parallel_dispatch.md +13 -0
  162. package/core/shared/skills/do-execute-plan/references/readiness_gate.md +26 -1
  163. package/core/shared/skills/do-execute-plan/references/run_position.md +13 -1
  164. package/core/shared/skills/do-execute-plan/references/scaffold.md +17 -9
  165. package/core/shared/skills/do-execute-plan/references/state_checkpoint.md +11 -0
  166. package/core/shared/skills/do-execute-plan/references/task_attempts.md +78 -24
  167. package/core/shared/skills/do-flow/SKILL.md +8 -9
  168. package/core/shared/skills/do-flow/references/task_classes.md +2 -2
  169. package/core/shared/skills/do-git/SKILL.md +4 -0
  170. package/core/shared/skills/do-implement/SKILL.md +4 -7
  171. package/core/shared/skills/do-plan/SKILL.md +26 -15
  172. package/core/shared/skills/do-test/SKILL.md +7 -4
  173. package/core/shared/templates/doflow/constitution-template.md +9 -3
  174. package/core/shared/templates/doflow/data-model-template.md +1 -1
  175. package/core/shared/templates/doflow/design-template.md +113 -16
  176. package/core/shared/templates/doflow/plan-template.md +11 -10
  177. package/core/shared/templates/doflow/question-log-template.md +14 -2
  178. package/core/shared/templates/doflow/requirement-template.md +1 -1
  179. package/core/worker-evidence/antigravity/checks.json +14 -0
  180. package/core/worker-evidence/codex/2026-10-18-cli-check.json +107 -0
  181. package/core/worker-evidence/codex/2026-10-18-live-run-edit.json +73 -0
  182. package/core/worker-evidence/codex/2026-10-18-live-run-read-only.json +62 -0
  183. package/core/worker-evidence/codex/2026-10-24-cli-check.json +126 -0
  184. package/core/worker-evidence/codex/checks.json +38 -0
  185. package/package.json +10 -6
  186. package/src/adapters/antigravity/index.js +143 -66
  187. package/src/adapters/claude/index.js +24 -4
  188. package/src/adapters/codex/agents.js +25 -15
  189. package/src/adapters/codex/index.js +48 -13
  190. package/src/adapters/codex/native-projection.js +6 -2
  191. package/src/adapters/copilot/index.js +58 -23
  192. package/src/adapters/copy-tree.js +290 -44
  193. package/src/adapters/guidance-manifest.js +71 -0
  194. package/src/adapters/guidance-pointer.js +19 -0
  195. package/src/adapters/hook-commands.js +6 -10
  196. package/src/adapters/index.js +1 -0
  197. package/src/adapters/kiro/index.js +23 -12
  198. package/src/adapters/opencode/index.js +8 -8
  199. package/src/adapters/pi/hooks.js +2 -1
  200. package/src/adapters/pi/index.js +14 -7
  201. package/src/adapters/resolve-source.js +26 -2
  202. package/src/cli/commands/install.js +2 -1
  203. package/src/cli/commands/reconcile.js +53 -9
  204. package/src/cli/commands/remove.js +2 -2
  205. package/src/cli/commands/rollback.js +6 -3
  206. package/src/cli/commands/self-update.js +18 -9
  207. package/src/cli/commands/status.js +21 -2
  208. package/src/cli/commands/ui.js +99 -0
  209. package/src/cli/commands/update.js +2 -1
  210. package/src/cli/index.js +322 -29
  211. package/src/cli/runtime-commands.js +209 -57
  212. package/src/cli/shared.js +0 -2
  213. package/src/helper/git.js +1 -1
  214. package/src/helper/guardrails.js +1 -1
  215. package/src/helper/marker-merge.js +31 -13
  216. package/src/helper/package-ids.js +37 -0
  217. package/src/helper/semver.js +94 -0
  218. package/src/install/backup.js +105 -15
  219. package/src/install/context.js +1 -1
  220. package/src/install/targets.js +31 -16
  221. package/src/lifecycle/coverage.js +20 -3
  222. package/src/lifecycle/hook-tier.js +160 -0
  223. package/src/lifecycle/index.js +412 -78
  224. package/src/lifecycle/retired-harnesses.js +318 -0
  225. package/src/lifecycle/view.js +35 -15
  226. package/src/registry/index.js +551 -26
  227. package/src/registry/worker-ids.js +45 -0
  228. package/src/release/build-package.js +0 -3
  229. package/src/release/docs-blocks.js +492 -0
  230. package/src/release/preflight.js +425 -0
  231. package/src/release/rehearse.js +401 -0
  232. package/src/release/release-workflow.js +733 -0
  233. package/src/release/sync-plugin-versions.js +43 -7
  234. package/src/runtime/advice/bench-gate.js +25 -0
  235. package/src/runtime/advice/cli.js +59 -16
  236. package/src/runtime/advice/client.js +32 -9
  237. package/src/runtime/advice/config.js +98 -133
  238. package/src/runtime/advice/doctor.js +1 -1
  239. package/src/runtime/advice/elevation.js +97 -0
  240. package/src/runtime/advice/endpoint-guard.js +9 -3
  241. package/src/runtime/advice/mode.js +37 -0
  242. package/src/runtime/advice/record.js +18 -5
  243. package/src/runtime/advice/registry.js +4 -1
  244. package/src/runtime/advice/shadow-config.js +229 -0
  245. package/src/runtime/advice/shadow-dispatcher.js +276 -0
  246. package/src/runtime/brief-rules.js +81 -0
  247. package/src/runtime/brief-tools.js +111 -34
  248. package/src/runtime/candidate.js +20 -11
  249. package/src/runtime/capabilities/executor.js +450 -0
  250. package/src/runtime/capabilities/loopback.js +41 -0
  251. package/src/runtime/capabilities/sanitizer.js +88 -0
  252. package/src/runtime/capability-router.js +135 -3
  253. package/src/runtime/checkouts.js +73 -11
  254. package/src/runtime/claims.js +13 -7
  255. package/src/runtime/cli.js +196 -19
  256. package/src/runtime/config-home.js +42 -0
  257. package/src/runtime/context/arbitrate.js +767 -0
  258. package/src/runtime/context/delivery-store.js +4 -6
  259. package/src/runtime/context/emission-rules.js +118 -0
  260. package/src/runtime/context/identity.js +227 -0
  261. package/src/runtime/context/primary-command.js +117 -0
  262. package/src/runtime/context/primary.js +344 -0
  263. package/src/runtime/context/summary-store.js +655 -0
  264. package/src/runtime/context-pack.js +154 -78
  265. package/src/runtime/decision-register.js +13 -4
  266. package/src/runtime/dispatch/admission.js +392 -0
  267. package/src/runtime/dispatch/attempt-end.js +274 -0
  268. package/src/runtime/dispatch/command.js +628 -0
  269. package/src/runtime/dispatch/controls.js +904 -0
  270. package/src/runtime/dispatch/envelope.js +276 -0
  271. package/src/runtime/dispatch/grants.js +310 -0
  272. package/src/runtime/dispatch/integrate.js +617 -0
  273. package/src/runtime/dispatch/loop.js +1835 -0
  274. package/src/runtime/dispatch/store.js +352 -0
  275. package/src/runtime/dispatch/verify-run.js +201 -0
  276. package/src/runtime/evidence-ledger.js +34 -7
  277. package/src/runtime/failure/capture.js +3 -1
  278. package/src/runtime/failure/cli.js +25 -9
  279. package/src/runtime/failure/home.js +57 -30
  280. package/src/runtime/failure/store.js +7 -2
  281. package/src/runtime/feature-pointer.js +174 -0
  282. package/src/runtime/feature-resolve.js +13 -2
  283. package/src/runtime/fleet/command.js +77 -0
  284. package/src/runtime/fleet/projects.js +178 -0
  285. package/src/runtime/fleet/tree.js +383 -0
  286. package/src/runtime/freshness.js +33 -3
  287. package/src/runtime/git-memo.js +46 -0
  288. package/src/runtime/guidance/ablation.js +427 -0
  289. package/src/runtime/health.js +565 -17
  290. package/src/runtime/history-compactor.js +13 -3
  291. package/src/runtime/implementation-gate.js +277 -22
  292. package/src/runtime/inventory/coverage.js +1 -1
  293. package/src/runtime/inventory/index.js +1 -1
  294. package/src/runtime/inventory/precedence.js +2 -2
  295. package/src/runtime/inventory/siblings.js +6 -4
  296. package/src/runtime/knowledge/code-corpus.js +277 -0
  297. package/src/runtime/knowledge/code-lexical.js +130 -0
  298. package/src/runtime/knowledge/code-retrieval.js +307 -0
  299. package/src/runtime/knowledge/code-validation.js +106 -0
  300. package/src/runtime/knowledge/gp3-gate.js +74 -0
  301. package/src/runtime/knowledge/graph-adapter.js +288 -0
  302. package/src/runtime/knowledge/graph-fallback.js +394 -0
  303. package/src/runtime/knowledge/hybrid.js +136 -8
  304. package/src/runtime/knowledge/retrieval.js +34 -1
  305. package/src/runtime/knowledge/rtk-compress.js +77 -0
  306. package/src/runtime/knowledge/semble-bridge.py +106 -0
  307. package/src/runtime/knowledge/semble-lifecycle.js +114 -0
  308. package/src/runtime/knowledge/semble-provider.js +365 -0
  309. package/src/runtime/lifecycle/cli.js +16 -6
  310. package/src/runtime/lifecycle/event-store.js +8 -6
  311. package/src/runtime/lifecycle/followup.js +6 -1
  312. package/src/runtime/lifecycle/overview.js +24 -1
  313. package/src/runtime/lifecycle/report-store.js +8 -10
  314. package/src/runtime/lifecycle/retention.js +95 -31
  315. package/src/runtime/lifecycle/root.js +9 -1
  316. package/src/runtime/lifecycle/status.js +34 -17
  317. package/src/runtime/lifecycle/store-upkeep.js +56 -7
  318. package/src/runtime/mask.js +134 -7
  319. package/src/runtime/mcp-consultations.js +40 -6
  320. package/src/runtime/model-router.js +79 -7
  321. package/src/runtime/models/catalogue.js +191 -0
  322. package/src/runtime/models/command.js +153 -0
  323. package/src/runtime/off-words.js +12 -0
  324. package/src/runtime/outcome.js +2 -2
  325. package/src/runtime/packages/command.js +1009 -0
  326. package/src/runtime/packages/contributions.js +116 -0
  327. package/src/runtime/packages/digest.js +132 -0
  328. package/src/runtime/packages/fetch.js +182 -0
  329. package/src/runtime/packages/grants.js +192 -0
  330. package/src/runtime/packages/index-file.js +134 -0
  331. package/src/runtime/packages/instruction.js +90 -0
  332. package/src/runtime/packages/manifest.js +331 -0
  333. package/src/runtime/packages/points.js +477 -0
  334. package/src/runtime/packages/programs.js +216 -0
  335. package/src/runtime/packages/scaffold.js +277 -0
  336. package/src/runtime/packages/source.js +90 -0
  337. package/src/runtime/packages/state.js +164 -0
  338. package/src/runtime/packages/store.js +449 -0
  339. package/src/runtime/packages/tar.js +106 -0
  340. package/src/runtime/packages/view.js +406 -0
  341. package/src/runtime/plan-check.js +59 -0
  342. package/src/runtime/plan-content.js +324 -0
  343. package/src/runtime/policy-init.js +118 -0
  344. package/src/runtime/profiles/doctor.js +96 -0
  345. package/src/runtime/profiles/resolve.js +244 -0
  346. package/src/runtime/profiles/rollback.js +254 -0
  347. package/src/runtime/profiles/sampler.js +41 -0
  348. package/src/runtime/readiness-record.js +16 -11
  349. package/src/runtime/readiness.js +46 -5
  350. package/src/runtime/research-request.js +50 -25
  351. package/src/runtime/retrieval-plan.js +10 -30
  352. package/src/runtime/retrieval-record.js +75 -5
  353. package/src/runtime/review/command.js +246 -0
  354. package/src/runtime/review/dominance.js +68 -0
  355. package/src/runtime/review/findings.js +434 -0
  356. package/src/runtime/review/identity.js +255 -0
  357. package/src/runtime/review/protocol-command.js +109 -0
  358. package/src/runtime/review/protocols.js +405 -0
  359. package/src/runtime/review/resolve-protocol.js +302 -0
  360. package/src/runtime/review/start.js +530 -0
  361. package/src/runtime/roadmap/facts.js +479 -0
  362. package/src/runtime/roadmap/gates.js +270 -0
  363. package/src/runtime/roadmap/loop.js +1636 -0
  364. package/src/runtime/roadmap/merge.js +381 -0
  365. package/src/runtime/roadmap/rows.js +1113 -0
  366. package/src/runtime/roadmap/seed.js +951 -0
  367. package/src/runtime/rules-report.js +336 -0
  368. package/src/runtime/scaffold/artifacts.js +60 -9
  369. package/src/runtime/scaffold/generate.js +21 -9
  370. package/src/runtime/settings/autopilot.js +106 -0
  371. package/src/runtime/settings/cli.js +280 -0
  372. package/src/runtime/settings/config-write.js +314 -0
  373. package/src/runtime/settings/files.js +271 -0
  374. package/src/runtime/settings/legacy.js +154 -0
  375. package/src/runtime/settings/lexical.js +56 -0
  376. package/src/runtime/settings/prepared-run.js +269 -0
  377. package/src/runtime/settings/project-layers.js +118 -0
  378. package/src/runtime/settings/refs.js +288 -0
  379. package/src/runtime/settings/registry.js +553 -0
  380. package/src/runtime/settings/resolve.js +713 -0
  381. package/src/runtime/settings/shared.js +37 -0
  382. package/src/runtime/settings/worker-billing.js +107 -0
  383. package/src/runtime/settings/write.js +269 -0
  384. package/src/runtime/slot-command.js +78 -0
  385. package/src/runtime/slots.js +671 -0
  386. package/src/runtime/source-version.js +1 -0
  387. package/src/runtime/state-root.js +217 -0
  388. package/src/runtime/storage/cli.js +12 -5
  389. package/src/runtime/storage/engine.js +9 -2
  390. package/src/runtime/storage/registry.js +14 -1
  391. package/src/runtime/storage/roots.js +66 -16
  392. package/src/runtime/storage/rules.js +82 -10
  393. package/src/runtime/storage/upkeep.js +10 -2
  394. package/src/runtime/storage/work-status.js +245 -26
  395. package/src/runtime/task-attempts.js +589 -69
  396. package/src/runtime/task-classifier.js +47 -11
  397. package/src/runtime/task-graph.js +373 -0
  398. package/src/runtime/task-run.js +778 -0
  399. package/src/runtime/task-scope.js +176 -55
  400. package/src/runtime/task-sources.js +147 -0
  401. package/src/runtime/task-state.js +374 -64
  402. package/src/runtime/team/admission.js +301 -0
  403. package/src/runtime/team/envelope.js +324 -0
  404. package/src/runtime/team/review-guard.js +156 -0
  405. package/src/runtime/trace/analyze.js +427 -0
  406. package/src/runtime/trace/baseline.js +770 -0
  407. package/src/runtime/trace/ledger.js +63 -140
  408. package/src/runtime/trace/otlp-export.js +568 -0
  409. package/src/runtime/trace/otlp-map.js +481 -0
  410. package/src/runtime/trace/spans.js +745 -0
  411. package/src/runtime/trace/telemetry.js +225 -0
  412. package/src/runtime/trace/views.js +1 -0
  413. package/src/runtime/transcripts/command.js +98 -0
  414. package/src/runtime/transcripts/cursor.js +326 -0
  415. package/src/runtime/transcripts/read.js +126 -0
  416. package/src/runtime/transcripts/readers/claude-jsonl.js +74 -0
  417. package/src/runtime/transcripts/readers/codex-rollout.js +70 -0
  418. package/src/runtime/transcripts/readers/copilot-events.js +90 -0
  419. package/src/runtime/transcripts/readers/kiro-jsonl.js +77 -0
  420. package/src/runtime/transcripts/readers/pi-jsonl.js +59 -0
  421. package/src/runtime/transcripts/registry.js +161 -0
  422. package/src/runtime/transcripts/stats.js +161 -0
  423. package/src/runtime/verification/check-key.js +628 -0
  424. package/src/runtime/verification/contract-runner.js +546 -11
  425. package/src/runtime/verification/engine.js +499 -9
  426. package/src/runtime/verification/impact.js +617 -0
  427. package/src/runtime/verification/inflight.js +205 -0
  428. package/src/runtime/verification/registry.js +176 -0
  429. package/src/runtime/verification/reuse.js +184 -0
  430. package/src/runtime/verification/telemetry-emit.js +254 -0
  431. package/src/runtime/verification/test-selection.js +67 -7
  432. package/src/runtime/worker/active.js +90 -0
  433. package/src/runtime/worker/cancel.js +222 -0
  434. package/src/runtime/worker/catalogue.js +122 -0
  435. package/src/runtime/worker/command.js +677 -0
  436. package/src/runtime/worker/evidence.js +288 -0
  437. package/src/runtime/worker/launch.js +288 -0
  438. package/src/runtime/worker/models.js +137 -0
  439. package/src/runtime/worker/parsers.js +218 -0
  440. package/src/runtime/worker/probes/index.js +706 -0
  441. package/src/runtime/worker/process-tree.js +415 -0
  442. package/src/runtime/worker/quota.js +43 -0
  443. package/src/runtime/worker/readiness.js +713 -0
  444. package/src/runtime/worker/run-store.js +166 -0
  445. package/src/runtime/worker/supervisor.js +541 -0
  446. package/src/runtime/worker/worktree-check.js +252 -0
  447. package/src/runtime/workflow-engine.js +5 -1
  448. package/src/runtime/workflow-orchestrator.js +578 -63
  449. package/src/runtime/worktree.js +149 -22
  450. package/src/state/index.js +1 -1
  451. package/src/state/lockfile.js +64 -10
  452. package/src/state/run-lock.js +1 -1
  453. package/types/node-commonjs.d.ts +106 -7
  454. package/core/harnesses/gemini/hooks/hooks.json +0 -77
  455. package/core/harnesses/gemini/hooks/lib.sh +0 -302
  456. package/core/harnesses/gemini/hooks/mcp-tool-guard.sh +0 -10
  457. package/core/harnesses/gemini/hooks/post-edit-lint.sh +0 -39
  458. package/core/harnesses/gemini/hooks/pre-bash-guard.sh +0 -10
  459. package/core/harnesses/gemini/hooks/pre-compact.sh +0 -38
  460. package/core/harnesses/gemini/hooks/pre-implement-gate.sh +0 -10
  461. package/core/harnesses/gemini/hooks/session-end.impl.sh +0 -89
  462. package/core/harnesses/gemini/hooks/session-end.sh +0 -5
  463. package/core/harnesses/gemini/hooks/session-start.sh +0 -7
  464. package/core/harnesses/gemini/settings/adapter-defaults.json +0 -4
  465. package/core/shared/guidance/FLAGS.md +0 -25
  466. package/core/shared/guidance/rules/RULE_01_SAFETY.md +0 -25
  467. package/core/shared/guidance/rules/RULE_02_WORKFLOW.md +0 -23
  468. package/core/shared/guidance/rules/RULE_03_QUALITY.md +0 -14
  469. package/core/shared/guidance/rules/RULE_04_QUESTIONS.md +0 -46
  470. package/src/adapters/gemini/hooks.js +0 -251
  471. package/src/adapters/gemini/index.js +0 -429
@@ -0,0 +1,347 @@
1
+ #!/usr/bin/env bash
2
+ # summary-store.sh — Canonical Policy Library: scoped compact summaries, grants and the legacy
3
+ # adopter (feature 078, IC-010, IC-011 store write, IC-012, IC-014; DEC-003, DEC-012, DEC-014).
4
+ #
5
+ # Layout under STATE_DIR (lib.sh: <config home>/doflow/session-env; empty with no config home, and
6
+ # then there is no store: peeks find nothing, writes, claims and adopts return 1):
7
+ # summaries/<worktreeKey>/<run>/<lineage>/summary.md one pending summary per scope
8
+ # summaries/<worktreeKey>/<run>/<lineage>/.summary.XXXXXX write temporary
9
+ # summaries/<worktreeKey>/<run>/<lineage>/.claimed.<unitId> claim temporary
10
+ # grants/<run>/<lineage>/<summaryId>.md grant addressed to a recipient
11
+ # grants/<run>/<lineage>/.claimed.<unitId>.<summaryId> claim temporary
12
+ # worktreeKey is cwd_hash of the identity worktree (DEC-027), so the caller must have sourced
13
+ # lib.sh, which defines cwd_hash, STATE_DIR and PROJECTS_DIR.
14
+ #
15
+ # Sourcing this file defines functions only: no option, no variable, no trap, no output. bash 3.2
16
+ # safe and safe under the caller's `set -euo pipefail`. Peek functions always return 0; write,
17
+ # claim and adopt return 0 when they did their work and 1 otherwise, so call them from `if` or
18
+ # with `||`. Results are DF_SUMMARY_* and DF_GRANT_* variables. A claimed file is left in place for
19
+ # the caller to pass to emission.jq (--rawfile summary or grant) and to remove after rendering.
20
+
21
+ # The id pattern of IC-007 (DEC-024) and the summary id pattern of IC-010.
22
+ _doflow_ss_id_ok() { [[ ${1:-} =~ ^[A-Za-z0-9][A-Za-z0-9_-]{0,55}$ ]]; }
23
+ _doflow_ss_summary_id_ok() { [[ ${1:-} =~ ^s-[0-9]{8}T[0-9]{6}Z-[A-Za-z0-9]{6}$ ]]; }
24
+ # A unit id (L.<run>.<lineage>.<attempt> or a harness session id) is one path segment.
25
+ _doflow_ss_unit_ok() { [[ ${1:-} =~ ^[A-Za-z0-9][A-Za-z0-9._-]{0,127}$ ]]; }
26
+
27
+ # _doflow_ss_root: _DF_SS_ROOT = lib.sh's STATE_DIR; returns 1 when it is empty (no config home).
28
+ _doflow_ss_root() {
29
+ _DF_SS_ROOT="${STATE_DIR:-}"
30
+ [ -n "$_DF_SS_ROOT" ]
31
+ }
32
+
33
+ # _doflow_ss_key <dir>: _DF_SS_KEY = cwd_hash <dir>, remembered for the last directory asked.
34
+ _doflow_ss_key() {
35
+ if [ -n "${_DF_SS_KEY_FOR:-}" ] && [ "$_DF_SS_KEY_FOR" = "$1" ] && [ -n "${_DF_SS_KEY:-}" ]; then
36
+ return 0
37
+ fi
38
+ _DF_SS_KEY=""
39
+ _DF_SS_KEY_FOR=""
40
+ [ -n "$1" ] || return 1
41
+ declare -F cwd_hash >/dev/null 2>&1 || return 1
42
+ _DF_SS_KEY=$(cwd_hash "$1" 2>/dev/null) || _DF_SS_KEY=""
43
+ [[ $_DF_SS_KEY =~ ^[0-9a-f]{16}$ ]] || { _DF_SS_KEY=""; return 1; }
44
+ _DF_SS_KEY_FOR=$1
45
+ return 0
46
+ }
47
+
48
+ # doflow_summary_scope <worktree> <run> <lineage>
49
+ # DF_SUMMARY_SCOPE = summaries/<worktreeKey>/<run>/<lineage>, or empty (return 1) when run or
50
+ # lineage is not an id, or the lineage is `solo`, which has no scope directory.
51
+ doflow_summary_scope() {
52
+ DF_SUMMARY_SCOPE=""
53
+ _doflow_ss_id_ok "${2:-}" && _doflow_ss_id_ok "${3:-}" && [ "$3" != solo ] || return 1
54
+ _doflow_ss_key "${1:-}" || return 1
55
+ _doflow_ss_root || return 1
56
+ DF_SUMMARY_SCOPE="$_DF_SS_ROOT/summaries/$_DF_SS_KEY/$2/$3"
57
+ return 0
58
+ }
59
+
60
+ # _doflow_ss_head <file>: reads the frontmatter the way emission.jq's parse_record does (\r removed,
61
+ # fields between the first two `---` lines, first match wins, leading spaces of a value dropped),
62
+ # never more than 65536 bytes. Sets _DF_SS_SESSION, _DF_SS_SID, and for the grant header
63
+ # _DF_SS_FROM (from_lineage), _DF_SS_AT (compacted_at) and _DF_SS_BRANCH (branch).
64
+ _doflow_ss_head() {
65
+ local LC_ALL=C line="" left=65536 fences=0 key value seen=" "
66
+ _DF_SS_SESSION=""
67
+ _DF_SS_SID=""
68
+ _DF_SS_FROM=""
69
+ _DF_SS_AT=""
70
+ _DF_SS_BRANCH=""
71
+ {
72
+ while [ "$left" -gt 0 ] && [ "$fences" -lt 2 ]; do
73
+ IFS= read -r -n "$left" line || [ -n "$line" ] || break
74
+ left=$((left - ${#line} - 1))
75
+ line=${line//$'\r'/}
76
+ if [ "$line" = "---" ]; then
77
+ fences=$((fences + 1))
78
+ elif [ "$fences" = 1 ] && [[ $line == ?*:* ]]; then
79
+ key=${line%%:*}
80
+ value=${line#*:}
81
+ while [ "${value# }" != "$value" ]; do value=${value# }; done
82
+ # The first match of a key wins: a wanted key is recorded in $seen once it is read.
83
+ case "$key" in
84
+ session_id | summary_id | from_lineage | compacted_at | branch)
85
+ case "$seen" in *" $key "*) key="" ;; esac ;;
86
+ *) key="" ;;
87
+ esac
88
+ case "$key" in
89
+ session_id) _DF_SS_SESSION=$value ;;
90
+ summary_id) _DF_SS_SID=$value ;;
91
+ from_lineage) _DF_SS_FROM=$value ;;
92
+ compacted_at) _DF_SS_AT=$value ;;
93
+ branch) _DF_SS_BRANCH=$value ;;
94
+ esac
95
+ [ -z "$key" ] || seen="$seen$key "
96
+ fi
97
+ line=""
98
+ done
99
+ } 2>/dev/null <"$1" || true
100
+ return 0
101
+ }
102
+
103
+ # _doflow_ss_body_bytes <file>: _DF_SS_BODY = the UTF-8 byte length of the record body exactly as
104
+ # parse_record yields it (\r removed, from the first non-empty line after the second `---`,
105
+ # trailing newlines dropped). The caller has bounded the file's size.
106
+ _doflow_ss_body_bytes() {
107
+ local LC_ALL=C line="" fences=0 started=0 gap=0
108
+ _DF_SS_BODY=0
109
+ {
110
+ while IFS= read -r line || [ -n "$line" ]; do
111
+ line=${line//$'\r'/}
112
+ if [ "$fences" -lt 2 ]; then
113
+ [ "$line" != "---" ] || fences=$((fences + 1))
114
+ elif [ -z "$line" ]; then
115
+ [ "$started" = 0 ] || gap=$((gap + 1))
116
+ elif [ "$started" = 0 ]; then
117
+ started=1
118
+ _DF_SS_BODY=${#line}
119
+ else
120
+ _DF_SS_BODY=$((_DF_SS_BODY + gap + 1 + ${#line}))
121
+ gap=0
122
+ fi
123
+ line=""
124
+ done
125
+ } 2>/dev/null <"$1" || true
126
+ return 0
127
+ }
128
+
129
+ # _doflow_ss_size <file>: _DF_SS_SIZE = the file's size in bytes, or empty.
130
+ _doflow_ss_size() {
131
+ _DF_SS_SIZE=$(wc -c 2>/dev/null <"$1") || _DF_SS_SIZE=""
132
+ _DF_SS_SIZE=${_DF_SS_SIZE//[!0-9]/}
133
+ return 0
134
+ }
135
+
136
+ # doflow_summary_write <worktree> <run> <lineage> <attempt> <compacted_at> <session_id> <trigger>
137
+ # <branch> <role> <body>
138
+ # IC-011 step 3: mkdir -p the scope, mktemp .summary.XXXXXX in it, write the IC-010 record, mv it to
139
+ # summary.md (a newer compaction replaces the pending one). compacted_at is UTC ISO-8601 to the
140
+ # second (YYYY-MM-DDTHH:MM:SSZ). Sets DF_SUMMARY_ID and DF_SUMMARY_PATH. Returns 1 with nothing left
141
+ # behind on an invalid argument, an empty body or a failed step.
142
+ doflow_summary_write() {
143
+ local worktree="${1:-}" run="${2:-}" lineage="${3:-}" attempt="${4:-}" at="${5:-}"
144
+ local session="${6:-}" trigger="${7:-}" branch="${8:-}" role="${9:-}" body="${10:-}"
145
+ local tmp="" stamp suffix nl=$'\n' cr=$'\r'
146
+ DF_SUMMARY_ID=""
147
+ DF_SUMMARY_PATH=""
148
+ [ -n "$body" ] || return 1
149
+ [[ $at =~ ^[0-9]{4}-[0-9]{2}-[0-9]{2}T[0-9]{2}:[0-9]{2}:[0-9]{2}Z$ ]] || return 1
150
+ [ -z "$attempt" ] || [[ $attempt =~ ^[1-9][0-9]{0,3}$ ]] || return 1
151
+ doflow_summary_scope "$worktree" "$run" "$lineage" || return 1
152
+ # A frontmatter value is one line: an embedded line break would forge a key.
153
+ session=${session//[$nl$cr]/ }; trigger=${trigger//[$nl$cr]/ }; branch=${branch//[$nl$cr]/ }
154
+ role=${role//[$nl$cr]/ }; worktree=${worktree//[$nl$cr]/ }
155
+ mkdir -p "$DF_SUMMARY_SCOPE" 2>/dev/null || return 1
156
+ tmp=$(mktemp "$DF_SUMMARY_SCOPE/.summary.XXXXXX" 2>/dev/null) || return 1
157
+ suffix=${tmp##*.summary.}
158
+ stamp=${at//[-:]/}
159
+ DF_SUMMARY_ID="s-$stamp-$suffix"
160
+ if ! _doflow_ss_summary_id_ok "$DF_SUMMARY_ID" \
161
+ || ! printf -- '---\ncompacted_at: %s\nsession_id: %s\ntrigger: %s\nbranch: %s\nrole: %s\nsummary_id: %s\nrun: %s\nlineage: %s\nattempt:%s\nworktree: %s\n---\n\n%s\n' \
162
+ "$at" "${session:-unknown}" "${trigger:-unknown}" "${branch:-unknown}" "${role:-main}" \
163
+ "$DF_SUMMARY_ID" "$run" "$lineage" "${attempt:+ $attempt}" "$worktree" "$body" >"$tmp" 2>/dev/null \
164
+ || ! mv -f "$tmp" "$DF_SUMMARY_SCOPE/summary.md" 2>/dev/null; then
165
+ rm -f "$tmp" 2>/dev/null || true
166
+ DF_SUMMARY_ID=""
167
+ return 1
168
+ fi
169
+ DF_SUMMARY_PATH="$DF_SUMMARY_SCOPE/summary.md"
170
+ return 0
171
+ }
172
+
173
+ # doflow_summary_peek <worktree> <run> <lineage> <session_id>
174
+ # IC-012 owner steps 1 and 2, for the state vector: DF_SUMMARY_OWN is `none` (no regular,
175
+ # non-symlink summary.md in the scope), `own-write` (its frontmatter session_id is this session's)
176
+ # or `pending`; DF_SUMMARY_FILE is its path and DF_SUMMARY_SID its frontmatter summary_id (possibly
177
+ # empty) when not `none`. Always returns 0.
178
+ doflow_summary_peek() {
179
+ local f
180
+ DF_SUMMARY_OWN=none
181
+ DF_SUMMARY_FILE=""
182
+ DF_SUMMARY_SID=""
183
+ doflow_summary_scope "${1:-}" "${2:-}" "${3:-}" || return 0
184
+ f="$DF_SUMMARY_SCOPE/summary.md"
185
+ [ -f "$f" ] && [ ! -L "$f" ] || return 0
186
+ _doflow_ss_head "$f"
187
+ DF_SUMMARY_FILE=$f
188
+ DF_SUMMARY_SID=$_DF_SS_SID
189
+ if [ -n "${4:-}" ] && [ "$_DF_SS_SESSION" = "$4" ]; then DF_SUMMARY_OWN=own-write; else DF_SUMMARY_OWN=pending; fi
190
+ return 0
191
+ }
192
+
193
+ # doflow_summary_claim <worktree> <run> <lineage> <unit_id> <session_id>
194
+ # IC-012 owner steps 1 to 3: peek, then rename summary.md to .claimed.<unitId>; a summary written
195
+ # after the rename is a new summary.md and survives. The claimed copy is cut to its first 65536
196
+ # bytes. Sets DF_SUMMARY_OWN (as peek, `none` after a lost rename), DF_SUMMARY_CLAIMED (the claimed
197
+ # path, for --rawfile summary) and DF_SUMMARY_BYTES (its full size before the cut, for
198
+ # plan.summaryBytes). Returns 0 when this caller claimed it; the caller removes the claimed file.
199
+ doflow_summary_claim() {
200
+ local unit="${4:-}" claimed
201
+ DF_SUMMARY_CLAIMED=""
202
+ DF_SUMMARY_BYTES=0
203
+ doflow_summary_peek "${1:-}" "${2:-}" "${3:-}" "${5:-}"
204
+ [ "$DF_SUMMARY_OWN" = pending ] || return 1
205
+ _doflow_ss_unit_ok "$unit" || return 1
206
+ claimed="$DF_SUMMARY_SCOPE/.claimed.$unit"
207
+ if ! mv "$DF_SUMMARY_FILE" "$claimed" 2>/dev/null; then
208
+ DF_SUMMARY_OWN=none
209
+ return 1
210
+ fi
211
+ _doflow_ss_size "$claimed"
212
+ DF_SUMMARY_BYTES=${_DF_SS_SIZE:-0}
213
+ if [ "$DF_SUMMARY_BYTES" -gt 65536 ]; then
214
+ # The cut copy is private to this user, as the record it replaces (L1-11).
215
+ if ! { (umask 077; head -c 65536 "$claimed" >"$claimed.read") 2>/dev/null && mv -f "$claimed.read" "$claimed" 2>/dev/null; }; then
216
+ rm -f "$claimed" "$claimed.read" 2>/dev/null || true
217
+ return 1
218
+ fi
219
+ fi
220
+ DF_SUMMARY_CLAIMED=$claimed
221
+ return 0
222
+ }
223
+
224
+ # _doflow_ss_known <value>: _DF_SS_KNOWN = emission.jq's `known`: `]` removed, then empty when it
225
+ # is "unknown".
226
+ _doflow_ss_known() {
227
+ _DF_SS_KNOWN=${1//]/}
228
+ [ "$_DF_SS_KNOWN" != unknown ] || _DF_SS_KNOWN=""
229
+ return 0
230
+ }
231
+
232
+ # doflow_grant_peek <run> <lineage> <max_bytes>
233
+ # IC-012 grant steps 1 and 2: the oldest grants/<run>/<lineage>/<summaryId>.md by name among regular,
234
+ # non-symlink files whose name matches the summary id pattern. DF_GRANT is `none`, `fits` or `over`.
235
+ # It fits exactly when emission.jq would render it whole: the UTF-8 bytes of render_grant's segment
236
+ # "[Granted summary from lineage <from_lineage><header_tail>]\n<body>" are at most max_bytes, so a
237
+ # body that fits under a header that does not is `over` and is never claimed. DF_GRANT_FILE,
238
+ # DF_GRANT_ID and DF_GRANT_BYTES (the body's bytes, for the pointer; empty when the file is too large
239
+ # to be worth reading) describe it. Always returns 0.
240
+ doflow_grant_peek() {
241
+ local LC_ALL=C run="${1:-}" lineage="${2:-}" max="${3:-}" dir f name header tail=""
242
+ DF_GRANT=none
243
+ DF_GRANT_FILE=""
244
+ DF_GRANT_ID=""
245
+ DF_GRANT_BYTES=""
246
+ _doflow_ss_id_ok "$run" && _doflow_ss_id_ok "$lineage" || return 0
247
+ [[ $max =~ ^[1-9][0-9]{0,9}$ ]] || return 0
248
+ _doflow_ss_root || return 0
249
+ dir="$_DF_SS_ROOT/grants/$run/$lineage"
250
+ [ -d "$dir" ] && [ ! -L "$dir" ] || return 0
251
+ # Glob expansion is sorted (C collation here), and summary ids sort by time.
252
+ for f in "$dir"/s-*.md; do
253
+ name=${f##*/}
254
+ name=${name%.md}
255
+ _doflow_ss_summary_id_ok "$name" || continue
256
+ [ -f "$f" ] && [ ! -L "$f" ] || continue
257
+ DF_GRANT_FILE=$f
258
+ DF_GRANT_ID=$name
259
+ break
260
+ done
261
+ [ -n "$DF_GRANT_FILE" ] || return 0
262
+ _doflow_ss_size "$DF_GRANT_FILE"
263
+ # A frontmatter needs far less than 65536 bytes: anything larger than that plus the budget is over.
264
+ if [ -n "$_DF_SS_SIZE" ] && [ "$_DF_SS_SIZE" -le $((max + 65536)) ]; then
265
+ _doflow_ss_body_bytes "$DF_GRANT_FILE"
266
+ DF_GRANT_BYTES=$_DF_SS_BODY
267
+ # render_grant's header, from the same bounded head pass parse_record's fields come from.
268
+ _doflow_ss_head "$DF_GRANT_FILE"
269
+ _doflow_ss_known "$_DF_SS_AT"
270
+ [ -z "$_DF_SS_KNOWN" ] || tail=", compacted $_DF_SS_KNOWN"
271
+ _doflow_ss_known "$_DF_SS_BRANCH"
272
+ [ -z "$_DF_SS_KNOWN" ] || tail="$tail on branch $_DF_SS_KNOWN"
273
+ header="[Granted summary from lineage $_DF_SS_FROM$tail]"
274
+ if [ $((${#header} + 1 + DF_GRANT_BYTES)) -le "$max" ]; then DF_GRANT=fits; else DF_GRANT=over; fi
275
+ else
276
+ DF_GRANT=over
277
+ fi
278
+ return 0
279
+ }
280
+
281
+ # doflow_grant_claim <run> <lineage> <unit_id> <max_bytes>
282
+ # IC-012 grant step 3: peek; when the oldest grant fits, rename it to
283
+ # .claimed.<unitId>.<summaryId> and set DF_GRANT_CLAIMED (for --rawfile grant); the caller removes
284
+ # it after rendering. An `over` grant stays in place (DF_GRANT_FILE renders the pointer). One grant
285
+ # per event. Returns 0 only when this caller claimed a grant.
286
+ doflow_grant_claim() {
287
+ local unit="${3:-}" claimed
288
+ DF_GRANT_CLAIMED=""
289
+ doflow_grant_peek "${1:-}" "${2:-}" "${4:-}"
290
+ [ "$DF_GRANT" = fits ] || return 1
291
+ _doflow_ss_unit_ok "$unit" || return 1
292
+ claimed="${DF_GRANT_FILE%/*}/.claimed.$unit.$DF_GRANT_ID"
293
+ if ! mv "$DF_GRANT_FILE" "$claimed" 2>/dev/null; then
294
+ DF_GRANT=none
295
+ return 1
296
+ fi
297
+ DF_GRANT_CLAIMED=$claimed
298
+ return 0
299
+ }
300
+
301
+ # doflow_summary_adopt_legacy <cwd> <worktree> [check]
302
+ # IC-014, on action `adopt` only: the pre-078 project summary under projects/<cwd_hash cwd>/, a
303
+ # regular file and not a symlink, moves once into summaries/<worktreeKey>/local/main/summary.md
304
+ # with its frontmatter kept. When a summary is already pending there it is newer by construction
305
+ # and the old file is removed instead. The legacy file is first renamed to <old>.adopting.<pid>, so
306
+ # only one adopter proceeds (a lost rename means another adopter won and returns 0, DEC-043); then
307
+ # a hard link that refuses to replace, and the .adopting file is unlinked last, so a summary written
308
+ # meanwhile is never overwritten. Without hard links, `mv -n` is the fallback, taken only when the
309
+ # target is absent and verified afterwards. Nothing writes the old path. Returns 0 when a legacy
310
+ # file was adopted or retired, or another adopter took it. With a third argument `check` it only tests that the
311
+ # legacy file exists and changes nothing (doflow_summary_legacy_present). This function is the one
312
+ # place that names the legacy file (G38.4).
313
+ doflow_summary_adopt_legacy() {
314
+ local cwd="${1:-}" worktree="${2:-}" projects old new taken
315
+ [ -n "$cwd" ] || return 1
316
+ [ -n "$worktree" ] || worktree=$cwd
317
+ _doflow_ss_key "$cwd" || return 1
318
+ _doflow_ss_root || return 1
319
+ projects="${PROJECTS_DIR:-$_DF_SS_ROOT/projects}"
320
+ old="$projects/$_DF_SS_KEY/last-compact-summary.md"
321
+ [ -f "$old" ] && [ ! -L "$old" ] || return 1
322
+ [ "${3:-}" != check ] || return 0
323
+ doflow_summary_scope "$worktree" local main || return 1
324
+ new="$DF_SUMMARY_SCOPE/summary.md"
325
+ mkdir -p "$DF_SUMMARY_SCOPE" 2>/dev/null || return 1
326
+ taken="$old.adopting.$$"
327
+ mv "$old" "$taken" 2>/dev/null || return 0
328
+ # A link that refuses to replace; it fails when a summary is pending, which retires the legacy one.
329
+ if ! ln "$taken" "$new" 2>/dev/null && [ ! -e "$new" ] && [ ! -L "$new" ]; then
330
+ # No hard links on this filesystem: a rename that refuses to replace, then a check that $new is
331
+ # the adopted file (mv -n leaves the source in place when the target appeared meanwhile).
332
+ # The old path is never written again, so a failed rename leaves the .adopting file in place.
333
+ mv -n "$taken" "$new" 2>/dev/null || true
334
+ if [ -e "$taken" ] && [ ! -e "$new" ] && [ ! -L "$new" ]; then return 1; fi
335
+ fi
336
+ rm -f "$taken" 2>/dev/null || true
337
+ return 0
338
+ }
339
+
340
+ # doflow_summary_legacy_present <cwd>
341
+ # Returns 0 when the pre-078 project summary under projects/<cwd_hash cwd>/ exists as a regular file
342
+ # and not a symlink, and 1 otherwise. Runs adopt_legacy's check mode in a subshell, so it sets no
343
+ # variable, prints nothing and changes nothing.
344
+ doflow_summary_legacy_present() {
345
+ [ -n "${1:-}" ] || return 1
346
+ (doflow_summary_adopt_legacy "$1" "" check)
347
+ }
@@ -1,18 +1,18 @@
1
1
  #!/usr/bin/env bash
2
- case $0 in */*) _DOFLOW_POLDIR=${0%/*} ;; *) _DOFLOW_POLDIR=. ;; esac
2
+ case "${OSTYPE:-}" in msys*|cygwin*|win32*) if command -v jq >/dev/null 2>&1; then jq() { command jq -b "$@"; }; fi ;; esac # native jq.exe ends lines with CRLF unless -b
3
+ _DOFLOW_SRC=${0//\\//}; case $_DOFLOW_SRC in */*) _DOFLOW_POLDIR=${_DOFLOW_SRC%/*} ;; *) _DOFLOW_POLDIR=. ;; esac
3
4
  # user-prompt-submit.sh — Canonical Policy Library: UserPromptSubmit hook
4
5
  #
5
6
  # 022-hooks-remaining-duplication: claude and codex's UserPromptSubmit policies share the same
6
- # context-gathering behavior. Gemini has no UserPromptSubmit-equivalent event in its native hook set.
7
+ # context-gathering behavior.
7
8
  #
8
- # On the FIRST prompt of a session: injects lightweight git context into the harness's LLM
9
- # context. Claude and Codex receive one nested envelope,
9
+ # Emission (078 IC-004): this policy reads the payload, records its decisions and runs the nudge
10
+ # classifier; doflow_emit_prompt (emission.sh) decides and renders the response. On the first
11
+ # prompt of a bootstrap unit that is git context, the scoped prior summary and the prior warning
12
+ # in one nested envelope,
10
13
  # {"hookSpecificOutput":{"hookEventName":"UserPromptSubmit","additionalContext":...}}
11
- # because Claude Code ignores a top-level additionalContext. Claude's object also carries
12
- # sessionTitle for window identification, unless the payload's session_title shows the user
13
- # already titled the session; Codex rejects unknown fields, so its object never does.
14
- #
15
- # On subsequent prompts: prints {} (clean, no token waste), unless the nudge below is earned.
14
+ # with sessionTitle on every harness but Codex unless the payload already carries session_title
15
+ # (DEC-030). Later prompts print {} unless the nudge below is earned.
16
16
  #
17
17
  # Once per session, the first prompt that reads as a plain code-change request (decided by
18
18
  # prompt-nudge.jq against the rules in the workflow registry's `promptNudge` key) also carries a
@@ -22,7 +22,7 @@ case $0 in */*) _DOFLOW_POLDIR=${0%/*} ;; *) _DOFLOW_POLDIR=. ;; esac
22
22
  # opt-out file, a subagent prompt, a /do-flow already in progress) resolves to silence; see the
23
23
  # once-per-session marker in lib.sh. The nudge starts no node or doflow-run process.
24
24
  #
25
- # Multi-session safe: uses session_id-scoped `injected` flag — no shared state.
25
+ # Multi-session safe: the adapter's one-shot slot is per bootstrap unit (DEC-007).
26
26
  # Must complete in <100ms. Must NEVER output "decision: block".
27
27
 
28
28
  set -euo pipefail
@@ -46,6 +46,16 @@ if ! command -v jq >/dev/null 2>&1; then
46
46
  ( . "$POLICY_DIR/capture-failure.sh"; doflow_capture_failure user-prompt-submit dependency-missing:jq ) >/dev/null 2>&1 || true
47
47
  fi
48
48
  require_jq
49
+ # The emission authority (feature 078): the scoped summary store, the compiled rule table and the
50
+ # adapter. A missing file leaves its functions
51
+ # undefined, which the adapter (or the check below) answers with the silent response and an
52
+ # emission-deps capture.
53
+ # shellcheck source=summary-store.sh
54
+ [ ! -f "$_DOFLOW_POLDIR/summary-store.sh" ] || . "$_DOFLOW_POLDIR/summary-store.sh"
55
+ # shellcheck source=emission-rules.sh
56
+ [ ! -f "$_DOFLOW_POLDIR/emission-rules.sh" ] || . "$_DOFLOW_POLDIR/emission-rules.sh"
57
+ # shellcheck source=emission.sh
58
+ [ ! -f "$_DOFLOW_POLDIR/emission.sh" ] || . "$_DOFLOW_POLDIR/emission.sh"
49
59
  # One jq pass over the payload for every field this hook reads (each pass costs about 8 ms on a
50
60
  # 20 KB prompt, and the budget is 100 ms), NUL-separated: session_id, cwd and session_title, null
51
61
  # and false read as empty as json_field does, with any NUL inside a value dropped so no field can
@@ -77,7 +87,6 @@ fi
77
87
  [[ -z "$SESSION_ID" ]] && exit 0
78
88
 
79
89
  SESSION_PATH="$SESSION_DIR/$SESSION_ID"
80
- INJECTED_FLAG="$SESSION_PATH/injected"
81
90
 
82
91
  # ── Prompt nudge (IC-004 N1-N8) ───────────────────────────────────────────────
83
92
 
@@ -86,13 +95,22 @@ INJECTED_FLAG="$SESSION_PATH/injected"
86
95
  # here can change the exit status or the first-prompt output. The prompt only ever travels to jq
87
96
  # on stdin, with stderr discarded, and is never copied out of INPUT.
88
97
  nudge_message() {
89
- local root policy_dir here registry decision message
98
+ local root policy_dir here registry decision message role
90
99
  [[ "${DOFLOW_AGENT:-}" == "claude" || "${DOFLOW_AGENT:-}" == "codex" ]] || return 0 # N1
91
- [[ "$(doflow_session_role 2>/dev/null || echo main)" != "worker" ]] || return 0 # a worker is never nudged
100
+ # The role gate is the rule table's: a role whose prompt.nudge action is skip (a worker) is never
101
+ # nudged, and returning here keeps the classifier from running or marking it (L2-15).
102
+ role=$(doflow_session_role 2>/dev/null) || role=main
103
+ DF_ACTION=skip
104
+ declare -F doflow_emission_rule >/dev/null 2>&1 && doflow_emission_rule prompt.nudge "$role:nudge" 2>/dev/null || DF_ACTION=skip
105
+ [[ "$DF_ACTION" != "skip" ]] || return 0
92
106
  nudge_safe_id "$SESSION_ID" || return 0 # N2
93
107
  root=$(nudge_repo_root "$CWD") || return 0
94
108
  [[ "$(nudge_setting "$root")" == "on" ]] || return 0 # N3
95
109
  [[ ! -e "$STATE_DIR/nudge/$SESSION_ID" ]] || return 0 # N4 (IC-008's path, no process)
110
+ # The marker is written after the render (DEC-041), so a folder it cannot be written to would
111
+ # nudge every prompt: an unwritable marker folder (or state folder, before it exists) is silent.
112
+ if [[ -e "$STATE_DIR/nudge" ]]; then [[ -d "$STATE_DIR/nudge" && -w "$STATE_DIR/nudge" ]] || return 0
113
+ elif [[ -e "$STATE_DIR" ]]; then [[ -w "$STATE_DIR" ]] || return 0; fi
96
114
  # N5: a subagent prompt carries agent_id or agent_type (read with the other fields above).
97
115
  [[ -z "$SUBAGENT" ]] || return 0
98
116
  # N6: the policy script's physical directory, found with built-ins (a subshell costs about 4 ms).
@@ -112,157 +130,44 @@ nudge_message() {
112
130
  nudge_mark "$SESSION_ID" suppressed || true
113
131
  return 0
114
132
  fi
115
- # N8: the message is read and checked before the marker is created, so a registry without a
116
- # usable message leaves no marker; a failed create (unwritable folder, a racing prompt) is silent.
133
+ # N8: a registry without a usable message leaves no marker. The `nudged` marker is written by
134
+ # doflow_emit_prompt once the nudge rendered, so a nudge the budget dropped stays unmarked (DEC-041).
117
135
  message=$(jq -r '.promptNudge.message | strings' "$registry" 2>/dev/null) || return 0
118
136
  [[ -n "$message" ]] || return 0
119
- nudge_mark "$SESSION_ID" nudged || return 0
120
137
  printf '%s' "$message"
121
138
  return 0
122
139
  }
123
140
 
124
- # One nested envelope for both harnesses (IC-002): $1 is the additionalContext; $2 the session
125
- # title, omitted when empty.
126
- emit_envelope() {
127
- jq -n --arg ctx "$1" --arg title "$2" \
128
- '{"hookSpecificOutput": ({"hookEventName": "UserPromptSubmit", "additionalContext": $ctx}
129
- + (if $title != "" then {"sessionTitle": $title} else {} end))}'
141
+ # ── Emission: every prompt, handed to the authority (IC-004) ──────────────────
142
+ # The classifier runs first, where its gates allow, and returns the message unmarked.
143
+ # doflow_emit_prompt decides everything else (the bootstrap slot, git context, the
144
+ # scoped summary, the warning, a grant, the nudge's place in the budget), prints the response and
145
+ # marks the session nudged and records `advisory prompt-nudge` itself when the nudge was rendered.
146
+
147
+ # Rider R1 (091): the emission metadata for the bridge's hook line, as one record on the decision
148
+ # fd after the decision records: the reason, the byte count and the digest, never a response byte. The
149
+ # bridge validates each value before it writes it. Telemetry off or no fd writes nothing.
150
+ doflow_emit_record() {
151
+ local fd="${DOFLOW_DECISION_FD:-}" digest=null
152
+ [ "${DOFLOW_TELEMETRY:-}" != off ] && [ -n "${DF_EMIT_REASON:-}" ] || return 0
153
+ [ -z "${DF_EMIT_DIGEST:-}" ] || digest="\"$DF_EMIT_DIGEST\""
154
+ case "$fd" in
155
+ 3|4|5|6|7|8|9)
156
+ { printf '\036{"v":1,"emit":{"reason":"%s","bytes":%s,"digest":%s}}\n' "$DF_EMIT_REASON" "${DF_EMIT_BYTES:-0}" "$digest" >&"$fd"; } 2>/dev/null || :
157
+ ;;
158
+ esac
159
+ return 0
130
160
  }
131
161
 
132
- # ── Subsequent prompts: no injection, unless the nudge is earned ──────────────
133
-
134
- if [[ -f "$INJECTED_FLAG" ]]; then
135
- NUDGE=$(nudge_message 2>/dev/null) || NUDGE=""
136
- if [[ -n "$NUDGE" ]]; then
137
- doflow_decide advisory prompt-nudge
138
- emit_envelope "$NUDGE" ""
139
- else
140
- echo "{}"
141
- fi
142
- exit 0
143
- fi
144
-
145
- # ── Worker session: no bootstrap, nothing claimed ─────────────────────────────
146
- # A worker never receives the git context, the prior compact summary or the prior warning, and
147
- # leaves both files for the main session. It is marked injected so later prompts stay silent.
148
-
149
- if [[ "$(doflow_session_role || echo main)" == "worker" ]]; then
150
- ensure_session_dir "$SESSION_ID" >/dev/null || true
151
- touch "$INJECTED_FLAG" 2>/dev/null || true
152
- echo "{}"
153
- exit 0
154
- fi
155
-
156
- # ── First prompt: build context ───────────────────────────────────────────────
157
-
158
- GIT_CONTEXT_FILE="$SESSION_PATH/git-context.json"
159
-
160
- # Fallback if session-start.sh didn't run or failed
161
- if [[ ! -f "$GIT_CONTEXT_FILE" ]]; then
162
- ensure_session_dir "$SESSION_ID" >/dev/null
163
- touch "$INJECTED_FLAG"
164
- CONTEXT="Git context unavailable for this session."
165
- SESSION_TITLE=""
166
- else
167
- GIT_JSON=$(cat "$GIT_CONTEXT_FILE")
168
- IS_GIT=$(json_field "$GIT_JSON" ".is_git_repo")
169
-
170
- if [[ "$IS_GIT" == "true" ]]; then
171
- BRANCH=$(json_field "$GIT_JSON" ".branch")
172
- SHA=$(json_field "$GIT_JSON" ".sha")
173
- UNCOMMITTED=$(json_field "$GIT_JSON" ".uncommitted_count")
174
- STASH=$(json_field "$GIT_JSON" ".stash_count")
175
-
176
- # Build commit list as a single line (· separated)
177
- COMMITS=$(echo "$GIT_JSON" | jq -r '.commits[]? // empty' | head -5 | paste -sd ' · ' -)
178
-
179
- CONTEXT="Git context — branch: ${BRANCH:-unknown} | ${SHA:-unknown}"$'\n'
180
- CONTEXT+="Last commits: ${COMMITS:-none}"$'\n'
181
- CONTEXT+="Uncommitted files: ${UNCOMMITTED:-0}"
182
- [[ "${STASH:-0}" -gt 0 ]] && CONTEXT+=" | Stashed: ${STASH}"
183
-
184
- SESSION_TITLE="${BRANCH:-unknown} — ${SHA:-unknown}"
185
- else
186
- CONTEXT="Not a git repository."
187
- SESSION_TITLE="no-git"
188
- fi
189
-
190
- # ── Prior compact summary: injected once into the next session, then consumed ─
191
- # post-compact.sh writes this file for the session that follows a compaction. The session
192
- # that compacted already holds the summary, so it skips the file and leaves it in place.
193
- # Any other session claims the file with an atomic rename first (a summary written meanwhile
194
- # is a new file and survives), reads a bounded prefix of the claimed copy and removes it. No
195
- # step here may fail the hook: on any error the summary is simply not injected.
196
-
197
- PROJECT_DIR=$(ensure_project_dir "$CWD")
198
- COMPACT_FILE="$PROJECT_DIR/last-compact-summary.md"
199
- COMPACT_CLAIM="$PROJECT_DIR/.last-compact-summary.claimed.$SESSION_ID"
200
- COMPACT_CAP=4000
201
- COMPACT_READ=65536 # bytes: enough for the cap even at four bytes per character
202
- compact_field() {
203
- printf '%s\n' "$COMPACT_HEAD" | awk -v k="$1:" '/^---$/{n++; if (n == 2) exit; next} n == 1 && index($0, k) == 1 {sub(/^[^:]*:[ ]*/, ""); print; exit}' || true
204
- }
205
- # A native subagent payload (agent_id or agent_type) never claims the summary or the warning.
206
- if [[ -z "$SUBAGENT" && -f "$COMPACT_FILE" && ! -L "$COMPACT_FILE" ]]; then
207
- COMPACT_HEAD=$(head -c "$COMPACT_READ" "$COMPACT_FILE" 2>/dev/null | tr -d '\r') || COMPACT_HEAD=''
208
- if [[ "$(compact_field session_id)" != "$SESSION_ID" ]] && mv "$COMPACT_FILE" "$COMPACT_CLAIM" 2>/dev/null; then
209
- COMPACT_SIZE=$(wc -c < "$COMPACT_CLAIM" 2>/dev/null) || COMPACT_SIZE=0
210
- COMPACT_HEAD=$(head -c "$COMPACT_READ" "$COMPACT_CLAIM" 2>/dev/null | tr -d '\r') || COMPACT_HEAD=''
211
- rm -f "$COMPACT_CLAIM"
212
- # Strip the YAML frontmatter (between the first two `---` lines) and the blank line after it;
213
- # keep the summary body only.
214
- COMPACT_BODY=$(printf '%s\n' "$COMPACT_HEAD" | awk '/^---$/ && n < 2 {n++; next} n >= 2 && (started || $0 != "") {started = 1; print}') || COMPACT_BODY=''
215
- COMPACT_LEN=''
216
- if [[ -n "$COMPACT_BODY" ]]; then
217
- # --rawfile, not stdin or --arg: jq 1.7's raw stdin reader miscounts multibyte text across
218
- # buffer boundaries, and --arg would hit the per-argument size limit on a large summary.
219
- COMPACT_LEN=$(jq -n --rawfile b <(printf '%s' "$COMPACT_BODY") '$b | length' 2>/dev/null) || COMPACT_BODY=''
220
- fi
221
- if [[ -n "$COMPACT_BODY" && "$COMPACT_LEN" -gt "$COMPACT_CAP" ]]; then
222
- COMPACT_BODY=$(jq -nr --rawfile b <(printf '%s' "$COMPACT_BODY") "\$b[0:$COMPACT_CAP]" 2>/dev/null) || COMPACT_BODY=''
223
- COMPACT_MORE=''
224
- [[ "$COMPACT_SIZE" -gt "$COMPACT_READ" ]] && COMPACT_MORE='at least '
225
- [[ -n "$COMPACT_BODY" ]] && COMPACT_BODY+=$'\n'"[summary truncated: first ${COMPACT_CAP} of ${COMPACT_MORE}${COMPACT_LEN} characters]"
226
- fi
227
- if [[ -n "$COMPACT_BODY" ]]; then
228
- COMPACT_AT=$(compact_field compacted_at); COMPACT_AT=${COMPACT_AT//]/}
229
- COMPACT_BRANCH=$(compact_field branch); COMPACT_BRANCH=${COMPACT_BRANCH//]/}
230
- COMPACT_HEADER="Prior session summary"
231
- [[ -n "$COMPACT_AT" && "$COMPACT_AT" != "unknown" ]] && COMPACT_HEADER+=", compacted ${COMPACT_AT}"
232
- [[ -n "$COMPACT_BRANCH" && "$COMPACT_BRANCH" != "unknown" ]] && COMPACT_HEADER+=" on branch ${COMPACT_BRANCH}"
233
- CONTEXT+=$'\n\n'"[${COMPACT_HEADER}]"$'\n'"$COMPACT_BODY"
234
- fi
235
- fi
236
- fi
237
-
238
- # Check for uncommitted warning from prior session (one-time: delete after read —
239
- # nothing else in the framework reassigns this cleanup, so it happens here)
240
- if [[ -z "$SUBAGENT" && -f "$PROJECT_DIR/uncommitted-warning.txt" ]]; then
241
- WARNING=$(cat "$PROJECT_DIR/uncommitted-warning.txt")
242
- CONTEXT+=$'\n'"[Prior session warning: ${WARNING}]"
243
- rm -f "$PROJECT_DIR/uncommitted-warning.txt"
244
- fi
245
- fi
246
-
247
- # ── Write injected flag ────────────────────────────────────────────────────────
248
-
249
- touch "$INJECTED_FLAG"
250
-
251
- # ── Output JSON ───────────────────────────────────────────────────────────────
252
-
253
- # The nudge, when earned, follows the context after a blank line.
254
162
  NUDGE=$(nudge_message 2>/dev/null) || NUDGE=""
255
- if [[ -n "$NUDGE" ]]; then
256
- doflow_decide advisory prompt-nudge
257
- CONTEXT+=$'\n\n'"$NUDGE"
258
- fi
259
-
260
- # sessionTitle: not on Codex, only when a title was built, and only when the user has not already
261
- # titled the session.
262
- TITLE_ARG=""
263
- if [[ "${DOFLOW_AGENT:-}" != "codex" && -n "${SESSION_TITLE:-}" && -z "$PAYLOAD_TITLE" ]]; then
264
- TITLE_ARG="$SESSION_TITLE"
163
+ if ! declare -F doflow_emit_prompt >/dev/null 2>&1; then
164
+ ( . "$POLICY_DIR/capture-failure.sh"; doflow_capture_failure user-prompt-submit emission-deps ) >/dev/null 2>&1 || true
165
+ printf '{}\n'
166
+ DF_EMIT_REASON=fault:deps DF_EMIT_BYTES=0 DF_EMIT_DIGEST=""
167
+ doflow_emit_record
168
+ exit 0
265
169
  fi
266
- emit_envelope "$CONTEXT" "$TITLE_ARG"
170
+ doflow_emit_prompt "$SESSION_ID" "$CWD" "$PAYLOAD_TITLE" "$SUBAGENT" "$NUDGE"
171
+ doflow_emit_record
267
172
 
268
173
  exit 0