@khoavu882/doflow 2.0.0-beta.4 → 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 (497) hide show
  1. package/README.md +12 -11
  2. package/bin/doflow.js +21 -11
  3. package/core/.antigravity-plugin/plugin.json +1 -3
  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/mcp-tool-guard.sh +7 -17
  9. package/core/harnesses/claude/hooks/permission-audit.sh +3 -0
  10. package/core/harnesses/claude/hooks/post-compact.sh +35 -32
  11. package/core/harnesses/claude/hooks/post-edit-lint.sh +2 -0
  12. package/core/harnesses/claude/hooks/post-shell-observe.sh +48 -0
  13. package/core/harnesses/claude/hooks/post-tool-failure.sh +3 -0
  14. package/core/harnesses/claude/hooks/pre-bash-guard.sh +7 -17
  15. package/core/harnesses/claude/hooks/pre-compact.sh +23 -27
  16. package/core/harnesses/claude/hooks/pre-implement-gate.sh +7 -18
  17. package/core/harnesses/claude/hooks/session-end.sh +23 -10
  18. package/core/harnesses/claude/hooks/session-start.sh +5 -3
  19. package/core/harnesses/claude/hooks/skill-config-audit.sh +3 -0
  20. package/core/harnesses/claude/hooks/stop-check.sh +5 -3
  21. package/core/harnesses/claude/hooks/subagent-audit.sh +5 -5
  22. package/core/harnesses/claude/hooks/user-prompt-submit.sh +5 -3
  23. package/core/harnesses/claude/settings/settings.json +18 -0
  24. package/core/harnesses/claude/statusline/doflow-statusline.sh +1 -0
  25. package/core/harnesses/codex/agents/core-implementer.toml +1 -0
  26. package/core/harnesses/codex/agents/delivery-lead.toml +10 -0
  27. package/core/harnesses/codex/agents/quality-guardian.toml +1 -1
  28. package/core/harnesses/codex/agents/research-writer.toml +1 -1
  29. package/core/harnesses/codex/agents/reviewer.toml +10 -0
  30. package/core/harnesses/codex/agents/spec-analyst.toml +1 -1
  31. package/core/harnesses/codex/agents/system-architect.toml +1 -1
  32. package/core/harnesses/codex/hooks/lib.sh +44 -25
  33. package/core/harnesses/codex/hooks/mcp-tool-guard.sh +7 -15
  34. package/core/harnesses/codex/hooks/post-edit-lint.impl.sh +3 -1
  35. package/core/harnesses/codex/hooks/pre-bash-guard.sh +7 -15
  36. package/core/harnesses/codex/hooks/pre-compact.impl.sh +29 -26
  37. package/core/harnesses/codex/hooks/pre-implement-gate.sh +7 -16
  38. package/core/harnesses/codex/hooks/session-end.impl.sh +23 -10
  39. package/core/harnesses/codex/hooks/session-start.sh +5 -3
  40. package/core/harnesses/codex/hooks/stop-check.sh +6 -5
  41. package/core/harnesses/codex/hooks/subagent-audit.sh +18 -6
  42. package/core/harnesses/codex/hooks/user-prompt-submit.sh +5 -4
  43. package/core/harnesses/copilot/hooks/doflow-lib.sh +93 -0
  44. package/core/harnesses/copilot/hooks/doflow-mcp-tool-guard.sh +9 -0
  45. package/core/harnesses/copilot/hooks/doflow-pre-bash-guard.sh +9 -0
  46. package/core/harnesses/copilot/hooks/doflow-pre-implement-gate.sh +9 -0
  47. package/core/harnesses/copilot/hooks/doflow-session-start.sh +9 -0
  48. package/core/harnesses/copilot/hooks/doflow-stop-check.sh +9 -0
  49. package/core/harnesses/copilot/hooks/doflow-subagent-start.sh +9 -0
  50. package/core/harnesses/copilot/hooks/doflow-subagent-stop.sh +9 -0
  51. package/core/harnesses/copilot/hooks/doflow.json +57 -0
  52. package/core/harnesses/kiro/agents/doflow.json +1 -1
  53. package/core/harnesses/kiro/hooks/lib.sh +26 -6
  54. package/core/harnesses/kiro/hooks/mcp-tool-guard.sh +21 -5
  55. package/core/harnesses/kiro/hooks/pre-bash-guard.sh +21 -5
  56. package/core/harnesses/kiro/hooks/pre-implement-gate.sh +21 -5
  57. package/core/harnesses/kiro/hooks/session-start.sh +12 -5
  58. package/core/harnesses/kiro/hooks/stop-check.sh +22 -30
  59. package/core/harnesses/pi/extensions/doflow-guard.js +167 -0
  60. package/core/harnesses/shared/hooks/ENVELOPE_MIGRATION.md +27 -12
  61. package/core/harnesses/shared/hooks/adapters/antigravity.js +14 -57
  62. package/core/harnesses/shared/hooks/bridge/bridge.sh +277 -0
  63. package/core/harnesses/shared/hooks/bridge/envelope.jq +129 -0
  64. package/core/harnesses/shared/hooks/bridge/observe-model.sh +75 -0
  65. package/core/harnesses/shared/hooks/bridge/respond.sh +70 -0
  66. package/core/harnesses/shared/hooks/policies/blocked-patterns.conf +28 -14
  67. package/core/harnesses/shared/hooks/policies/capture-failure.sh +51 -16
  68. package/core/harnesses/shared/hooks/policies/compact-text.sh +46 -0
  69. package/core/harnesses/shared/hooks/policies/contract.sh +78 -0
  70. package/core/harnesses/shared/hooks/policies/deny-json.sh +35 -9
  71. package/core/harnesses/shared/hooks/policies/emission-rules.sh +37 -0
  72. package/core/harnesses/shared/hooks/policies/emission.jq +209 -0
  73. package/core/harnesses/shared/hooks/policies/emission.sh +383 -0
  74. package/core/harnesses/shared/hooks/policies/identity.sh +177 -0
  75. package/core/harnesses/shared/hooks/policies/lib.sh +65 -40
  76. package/core/harnesses/shared/hooks/policies/mcp-tool-guard.sh +48 -35
  77. package/core/harnesses/shared/hooks/policies/pre-bash-guard.sh +284 -33
  78. package/core/harnesses/shared/hooks/policies/pre-implementation-gate.sh +180 -110
  79. package/core/harnesses/shared/hooks/policies/session-context.sh +66 -7
  80. package/core/harnesses/shared/hooks/policies/stop-check.sh +61 -23
  81. package/core/harnesses/shared/hooks/policies/subagent-audit.sh +39 -6
  82. package/core/harnesses/shared/hooks/policies/summary-store.sh +347 -0
  83. package/core/harnesses/shared/hooks/policies/user-prompt-submit.sh +97 -159
  84. package/core/harnesses/shared/hooks/stream-hook-runner.js +114 -187
  85. package/core/harnesses/shared/locator/doflow-run +2 -3
  86. package/core/registry/advice.json +3 -3
  87. package/core/registry/assets.json +72 -80
  88. package/core/registry/capabilities.json +12 -0
  89. package/core/registry/contracts.json +60 -33
  90. package/core/registry/contribution-points.json +32 -0
  91. package/core/registry/gates.json +32 -0
  92. package/core/registry/guidance-caps.json +40 -0
  93. package/core/registry/harnesses.json +1542 -277
  94. package/core/registry/lifecycle.json +2837 -37
  95. package/core/registry/mcp.json +5 -1
  96. package/core/registry/models.json +7 -1
  97. package/core/registry/package-templates/README.md +19 -0
  98. package/core/registry/package-templates/agent/files/agent.md +9 -0
  99. package/core/registry/package-templates/agent/template.json +4 -0
  100. package/core/registry/package-templates/capability-provider/files/provider.json +9 -0
  101. package/core/registry/package-templates/capability-provider/template.json +11 -0
  102. package/core/registry/package-templates/debate-preset/files/preset.json +26 -0
  103. package/core/registry/package-templates/debate-preset/template.json +4 -0
  104. package/core/registry/package-templates/review-preset/files/preset.json +30 -0
  105. package/core/registry/package-templates/review-preset/template.json +4 -0
  106. package/core/registry/package-templates/skill/files/SKILL.md +8 -0
  107. package/core/registry/package-templates/skill/template.json +4 -0
  108. package/core/registry/package-templates/worker/files/worker.json +92 -0
  109. package/core/registry/package-templates/worker/template.json +11 -0
  110. package/core/registry/packages/doflow/doflow-package.json +15 -0
  111. package/core/registry/packages/doflow/presets/debate-3.json +26 -0
  112. package/core/registry/protocols.json +61 -0
  113. package/core/registry/routes.json +17 -0
  114. package/core/registry/rules.json +431 -0
  115. package/core/registry/settings.json +276 -0
  116. package/core/registry/storage.json +701 -30
  117. package/core/registry/telemetry.json +236 -0
  118. package/core/registry/transcripts.json +142 -0
  119. package/core/registry/verification.json +76 -1
  120. package/core/registry/workflows.json +55 -0
  121. package/core/shared/agent-specs/core-implementer.md +3 -0
  122. package/core/shared/agent-specs/delivery-lead.md +68 -0
  123. package/core/shared/agent-specs/quality-guardian.md +5 -1
  124. package/core/shared/agent-specs/research-writer.md +10 -3
  125. package/core/shared/agent-specs/reviewer.md +53 -0
  126. package/core/shared/agent-specs/spec-analyst.md +5 -6
  127. package/core/shared/agent-specs/system-architect.md +5 -1
  128. package/core/shared/guidance/DOFLOW_CORE.md +1 -5
  129. package/core/shared/guidance/modes/MODE_DeepResearch.md +1 -1
  130. package/core/shared/guidance/modes/MODE_Orchestration.md +4 -3
  131. package/core/shared/guidance/modes/MODE_Task_Management.md +14 -14
  132. package/core/shared/guidance/pointers/codex.md +1 -4
  133. package/core/shared/guidance/references/ARTIFACT_FORMAT.md +30 -16
  134. package/core/shared/guidance/references/ARTIFACT_VOICE.md +3 -2
  135. package/core/shared/guidance/references/CONSTITUTION_BASE.md +17 -15
  136. package/core/shared/guidance/references/DIAGRAM_GUIDE.md +1 -1
  137. package/core/shared/guidance/references/DOFLOW_CHAIN.md +17 -19
  138. package/core/shared/guidance/references/EVIDENCE_LEDGER.md +7 -8
  139. package/core/shared/guidance/references/MODEL_SELECTION.md +5 -3
  140. package/core/shared/guidance/references/ORCHESTRATION.md +1 -2
  141. package/core/shared/guidance/rules/RULES.md +45 -0
  142. package/core/shared/scripts/doflow/bash/do-args.sh +37 -0
  143. package/core/shared/scripts/doflow/bash/do-exec-paths.sh +4 -0
  144. package/core/shared/scripts/doflow/bash/do-git-state.sh +15 -4
  145. package/core/shared/scripts/doflow/bash/do-parallel-check.sh +4 -0
  146. package/core/shared/scripts/doflow/bash/do-paths.sh +40 -2
  147. package/core/shared/scripts/doflow/bash/do-prereqs.sh +2 -1
  148. package/core/shared/scripts/doflow/bash/do-review-package.sh +4 -0
  149. package/core/shared/scripts/doflow/bash/do-task-brief.sh +58 -16
  150. package/core/shared/scripts/doflow/bash/render-audit.sh +26 -2
  151. package/core/shared/scripts/doflow/bash/render-diagrams.sh +1 -0
  152. package/core/shared/scripts/doflow/bash/render-puml.sh +2 -1
  153. package/core/shared/scripts/doflow/bash/validate-artifacts.sh +48 -4
  154. package/core/shared/scripts/doflow/bin/doflow-run +154 -35
  155. package/core/shared/skills/do/SKILL.md +12 -10
  156. package/core/shared/skills/do/references/advice_calls.md +26 -0
  157. package/core/shared/skills/do/references/pm_routing.md +1 -2
  158. package/core/shared/skills/do/references/program_mode.md +31 -0
  159. package/core/shared/skills/do-brainstorm/SKILL.md +20 -74
  160. package/core/shared/skills/do-brainstorm/references/handoff_branches.md +35 -0
  161. package/core/shared/skills/do-brainstorm/references/intent_seed.md +21 -0
  162. package/core/shared/skills/do-brainstorm/references/round_log.md +17 -0
  163. package/core/shared/skills/do-code-review/SKILL.md +41 -144
  164. package/core/shared/skills/do-code-review/content-types/markdown.md +24 -2
  165. package/core/shared/skills/do-code-review/references/tools.md +90 -0
  166. package/core/shared/skills/do-code-review/scripts/doc_quality_checker.py +549 -7
  167. package/core/shared/skills/do-design/SKILL.md +24 -23
  168. package/core/shared/skills/do-diagnose/SKILL.md +14 -4
  169. package/core/shared/skills/do-document/SKILL.md +11 -1
  170. package/core/shared/skills/do-document/references/deep_research.md +1 -2
  171. package/core/shared/skills/do-document/references/embedded-research.md +18 -6
  172. package/core/shared/skills/do-document/references/implementation-flow.md +5 -6
  173. package/core/shared/skills/do-execute-plan/SKILL.md +17 -59
  174. package/core/shared/skills/do-execute-plan/references/handoff_record.md +7 -2
  175. package/core/shared/skills/do-execute-plan/references/parallel_dispatch.md +13 -0
  176. package/core/shared/skills/do-execute-plan/references/readiness_gate.md +28 -1
  177. package/core/shared/skills/do-execute-plan/references/run_position.md +13 -1
  178. package/core/shared/skills/do-execute-plan/references/scaffold.md +17 -9
  179. package/core/shared/skills/do-execute-plan/references/state_checkpoint.md +11 -0
  180. package/core/shared/skills/do-execute-plan/references/task_attempts.md +78 -24
  181. package/core/shared/skills/do-flow/SKILL.md +8 -9
  182. package/core/shared/skills/do-flow/references/task_classes.md +2 -2
  183. package/core/shared/skills/do-git/SKILL.md +4 -0
  184. package/core/shared/skills/do-implement/SKILL.md +7 -9
  185. package/core/shared/skills/do-plan/SKILL.md +29 -19
  186. package/core/shared/skills/do-test/SKILL.md +7 -4
  187. package/core/shared/templates/doflow/constitution-template.md +9 -3
  188. package/core/shared/templates/doflow/data-model-template.md +1 -1
  189. package/core/shared/templates/doflow/design-template.md +113 -16
  190. package/core/shared/templates/doflow/plan-template.md +11 -10
  191. package/core/shared/templates/doflow/question-log-template.md +14 -2
  192. package/core/shared/templates/doflow/requirement-template.md +1 -1
  193. package/core/worker-evidence/antigravity/checks.json +14 -0
  194. package/core/worker-evidence/codex/2026-10-18-cli-check.json +107 -0
  195. package/core/worker-evidence/codex/2026-10-18-live-run-edit.json +73 -0
  196. package/core/worker-evidence/codex/2026-10-18-live-run-read-only.json +62 -0
  197. package/core/worker-evidence/codex/2026-10-24-cli-check.json +126 -0
  198. package/core/worker-evidence/codex/checks.json +38 -0
  199. package/package.json +10 -6
  200. package/src/adapters/antigravity/index.js +226 -113
  201. package/src/adapters/claude/index.js +39 -5
  202. package/src/adapters/codex/agents.js +25 -15
  203. package/src/adapters/codex/hooks.js +40 -5
  204. package/src/adapters/codex/index.js +100 -22
  205. package/src/adapters/codex/native-projection.js +6 -2
  206. package/src/adapters/copilot/index.js +58 -23
  207. package/src/adapters/copy-tree.js +294 -48
  208. package/src/adapters/guidance-manifest.js +71 -0
  209. package/src/adapters/guidance-pointer.js +19 -0
  210. package/src/adapters/hook-commands.js +6 -10
  211. package/src/adapters/index.js +1 -0
  212. package/src/adapters/kiro/index.js +38 -13
  213. package/src/adapters/opencode/index.js +8 -8
  214. package/src/adapters/pi/hooks.js +120 -0
  215. package/src/adapters/pi/index.js +48 -16
  216. package/src/adapters/resolve-source.js +26 -2
  217. package/src/cli/commands/install.js +3 -2
  218. package/src/cli/commands/reconcile.js +53 -9
  219. package/src/cli/commands/remove.js +2 -2
  220. package/src/cli/commands/rollback.js +6 -3
  221. package/src/cli/commands/self-update.js +18 -9
  222. package/src/cli/commands/status.js +21 -2
  223. package/src/cli/commands/ui.js +99 -0
  224. package/src/cli/commands/update.js +3 -2
  225. package/src/cli/index.js +338 -33
  226. package/src/cli/runtime-commands.js +243 -52
  227. package/src/cli/shared.js +0 -2
  228. package/src/helper/git.js +1 -1
  229. package/src/helper/guardrails.js +1 -1
  230. package/src/helper/marker-merge.js +31 -13
  231. package/src/helper/package-ids.js +37 -0
  232. package/src/helper/semver.js +94 -0
  233. package/src/install/backup.js +105 -15
  234. package/src/install/context.js +1 -1
  235. package/src/install/targets.js +31 -16
  236. package/src/lifecycle/coverage.js +74 -0
  237. package/src/lifecycle/hook-step.js +61 -0
  238. package/src/lifecycle/hook-tier.js +160 -0
  239. package/src/lifecycle/index.js +434 -86
  240. package/src/lifecycle/retired-harnesses.js +318 -0
  241. package/src/lifecycle/view.js +35 -15
  242. package/src/registry/index.js +686 -32
  243. package/src/registry/worker-ids.js +45 -0
  244. package/src/release/build-package.js +0 -3
  245. package/src/release/docs-blocks.js +492 -0
  246. package/src/release/preflight.js +425 -0
  247. package/src/release/rehearse.js +401 -0
  248. package/src/release/release-workflow.js +733 -0
  249. package/src/release/sync-plugin-versions.js +43 -7
  250. package/src/runtime/advice/bench-gate.js +25 -0
  251. package/src/runtime/advice/cli.js +59 -16
  252. package/src/runtime/advice/client.js +32 -9
  253. package/src/runtime/advice/config.js +98 -133
  254. package/src/runtime/advice/doctor.js +1 -1
  255. package/src/runtime/advice/elevation.js +97 -0
  256. package/src/runtime/advice/endpoint-guard.js +9 -3
  257. package/src/runtime/advice/mode.js +37 -0
  258. package/src/runtime/advice/record.js +18 -5
  259. package/src/runtime/advice/registry.js +4 -1
  260. package/src/runtime/advice/shadow-config.js +229 -0
  261. package/src/runtime/advice/shadow-dispatcher.js +276 -0
  262. package/src/runtime/brief-rules.js +81 -0
  263. package/src/runtime/brief-tools.js +111 -34
  264. package/src/runtime/candidate.js +514 -0
  265. package/src/runtime/capabilities/executor.js +450 -0
  266. package/src/runtime/capabilities/loopback.js +41 -0
  267. package/src/runtime/capabilities/sanitizer.js +88 -0
  268. package/src/runtime/capability-router.js +135 -3
  269. package/src/runtime/checkouts.js +73 -11
  270. package/src/runtime/claims.js +27 -12
  271. package/src/runtime/cli-result.js +11 -4
  272. package/src/runtime/cli.js +221 -277
  273. package/src/runtime/config-home.js +42 -0
  274. package/src/runtime/context/arbitrate.js +767 -0
  275. package/src/runtime/context/budget.js +203 -0
  276. package/src/runtime/context/compose.js +1367 -0
  277. package/src/runtime/context/delivery-store.js +100 -0
  278. package/src/runtime/context/emission-rules.js +118 -0
  279. package/src/runtime/context/identity.js +227 -0
  280. package/src/runtime/context/mandatory.js +594 -0
  281. package/src/runtime/context/pointer.js +142 -0
  282. package/src/runtime/context/primary-command.js +117 -0
  283. package/src/runtime/context/primary.js +344 -0
  284. package/src/runtime/context/summary-store.js +655 -0
  285. package/src/runtime/context-pack.js +1106 -245
  286. package/src/runtime/decision-register.js +13 -4
  287. package/src/runtime/dispatch/admission.js +392 -0
  288. package/src/runtime/dispatch/attempt-end.js +274 -0
  289. package/src/runtime/dispatch/command.js +628 -0
  290. package/src/runtime/dispatch/controls.js +904 -0
  291. package/src/runtime/dispatch/envelope.js +276 -0
  292. package/src/runtime/dispatch/grants.js +310 -0
  293. package/src/runtime/dispatch/integrate.js +617 -0
  294. package/src/runtime/dispatch/loop.js +1835 -0
  295. package/src/runtime/dispatch/store.js +352 -0
  296. package/src/runtime/dispatch/verify-run.js +201 -0
  297. package/src/runtime/evidence-fields.js +39 -0
  298. package/src/runtime/evidence-ledger.js +41 -7
  299. package/src/runtime/failure/capture.js +3 -1
  300. package/src/runtime/failure/cli.js +25 -9
  301. package/src/runtime/failure/home.js +57 -30
  302. package/src/runtime/failure/store.js +7 -2
  303. package/src/runtime/feature-pointer.js +174 -0
  304. package/src/runtime/feature-resolve.js +13 -2
  305. package/src/runtime/fleet/command.js +77 -0
  306. package/src/runtime/fleet/projects.js +178 -0
  307. package/src/runtime/fleet/tree.js +383 -0
  308. package/src/runtime/freshness.js +77 -10
  309. package/src/runtime/git-memo.js +46 -0
  310. package/src/runtime/guidance/ablation.js +427 -0
  311. package/src/runtime/health.js +565 -17
  312. package/src/runtime/history-compactor.js +13 -3
  313. package/src/runtime/implementation-gate.js +277 -22
  314. package/src/runtime/inventory/coverage.js +1 -1
  315. package/src/runtime/inventory/index.js +1 -1
  316. package/src/runtime/inventory/precedence.js +2 -2
  317. package/src/runtime/inventory/siblings.js +6 -4
  318. package/src/runtime/knowledge/code-corpus.js +277 -0
  319. package/src/runtime/knowledge/code-lexical.js +130 -0
  320. package/src/runtime/knowledge/code-retrieval.js +307 -0
  321. package/src/runtime/knowledge/code-validation.js +106 -0
  322. package/src/runtime/knowledge/gp3-gate.js +74 -0
  323. package/src/runtime/knowledge/graph-adapter.js +288 -0
  324. package/src/runtime/knowledge/graph-fallback.js +394 -0
  325. package/src/runtime/knowledge/hybrid.js +136 -8
  326. package/src/runtime/knowledge/retrieval.js +34 -1
  327. package/src/runtime/knowledge/rtk-compress.js +77 -0
  328. package/src/runtime/knowledge/semble-bridge.py +106 -0
  329. package/src/runtime/knowledge/semble-lifecycle.js +114 -0
  330. package/src/runtime/knowledge/semble-provider.js +365 -0
  331. package/src/runtime/lifecycle/cli.js +16 -6
  332. package/src/runtime/lifecycle/event-store.js +8 -6
  333. package/src/runtime/lifecycle/followup.js +6 -1
  334. package/src/runtime/lifecycle/overview.js +24 -1
  335. package/src/runtime/lifecycle/report-store.js +8 -10
  336. package/src/runtime/lifecycle/retention.js +95 -31
  337. package/src/runtime/lifecycle/root.js +9 -1
  338. package/src/runtime/lifecycle/status.js +34 -17
  339. package/src/runtime/lifecycle/store-upkeep.js +56 -7
  340. package/src/runtime/mask.js +134 -7
  341. package/src/runtime/mcp-consultations.js +40 -6
  342. package/src/runtime/model-router.js +79 -7
  343. package/src/runtime/models/catalogue.js +191 -0
  344. package/src/runtime/models/command.js +153 -0
  345. package/src/runtime/off-words.js +12 -0
  346. package/src/runtime/outcome.js +3 -3
  347. package/src/runtime/packages/command.js +1009 -0
  348. package/src/runtime/packages/contributions.js +116 -0
  349. package/src/runtime/packages/digest.js +132 -0
  350. package/src/runtime/packages/fetch.js +182 -0
  351. package/src/runtime/packages/grants.js +192 -0
  352. package/src/runtime/packages/index-file.js +134 -0
  353. package/src/runtime/packages/instruction.js +90 -0
  354. package/src/runtime/packages/manifest.js +331 -0
  355. package/src/runtime/packages/points.js +477 -0
  356. package/src/runtime/packages/programs.js +216 -0
  357. package/src/runtime/packages/scaffold.js +277 -0
  358. package/src/runtime/packages/source.js +90 -0
  359. package/src/runtime/packages/state.js +164 -0
  360. package/src/runtime/packages/store.js +449 -0
  361. package/src/runtime/packages/tar.js +106 -0
  362. package/src/runtime/packages/view.js +406 -0
  363. package/src/runtime/plan-check.js +59 -0
  364. package/src/runtime/plan-content.js +324 -0
  365. package/src/runtime/policy-init.js +118 -0
  366. package/src/runtime/profiles/doctor.js +96 -0
  367. package/src/runtime/profiles/resolve.js +244 -0
  368. package/src/runtime/profiles/rollback.js +254 -0
  369. package/src/runtime/profiles/sampler.js +41 -0
  370. package/src/runtime/readiness-record.js +16 -11
  371. package/src/runtime/readiness.js +127 -16
  372. package/src/runtime/research-request.js +50 -25
  373. package/src/runtime/retrieval-plan.js +402 -73
  374. package/src/runtime/retrieval-record.js +293 -0
  375. package/src/runtime/review/command.js +246 -0
  376. package/src/runtime/review/dominance.js +68 -0
  377. package/src/runtime/review/findings.js +434 -0
  378. package/src/runtime/review/identity.js +255 -0
  379. package/src/runtime/review/protocol-command.js +109 -0
  380. package/src/runtime/review/protocols.js +405 -0
  381. package/src/runtime/review/resolve-protocol.js +302 -0
  382. package/src/runtime/review/start.js +530 -0
  383. package/src/runtime/roadmap/facts.js +479 -0
  384. package/src/runtime/roadmap/gates.js +270 -0
  385. package/src/runtime/roadmap/loop.js +1636 -0
  386. package/src/runtime/roadmap/merge.js +381 -0
  387. package/src/runtime/roadmap/rows.js +1113 -0
  388. package/src/runtime/roadmap/seed.js +951 -0
  389. package/src/runtime/rules-report.js +336 -0
  390. package/src/runtime/scaffold/artifacts.js +63 -9
  391. package/src/runtime/scaffold/generate.js +21 -9
  392. package/src/runtime/settings/autopilot.js +106 -0
  393. package/src/runtime/settings/cli.js +280 -0
  394. package/src/runtime/settings/config-write.js +314 -0
  395. package/src/runtime/settings/files.js +271 -0
  396. package/src/runtime/settings/legacy.js +154 -0
  397. package/src/runtime/settings/lexical.js +56 -0
  398. package/src/runtime/settings/prepared-run.js +269 -0
  399. package/src/runtime/settings/project-layers.js +118 -0
  400. package/src/runtime/settings/refs.js +288 -0
  401. package/src/runtime/settings/registry.js +553 -0
  402. package/src/runtime/settings/resolve.js +713 -0
  403. package/src/runtime/settings/shared.js +37 -0
  404. package/src/runtime/settings/worker-billing.js +107 -0
  405. package/src/runtime/settings/write.js +269 -0
  406. package/src/runtime/slot-command.js +78 -0
  407. package/src/runtime/slots.js +671 -0
  408. package/src/runtime/source-version.js +290 -0
  409. package/src/runtime/state-root.js +217 -0
  410. package/src/runtime/storage/cli.js +12 -5
  411. package/src/runtime/storage/engine.js +9 -2
  412. package/src/runtime/storage/registry.js +14 -1
  413. package/src/runtime/storage/roots.js +66 -16
  414. package/src/runtime/storage/rules.js +82 -10
  415. package/src/runtime/storage/upkeep.js +10 -2
  416. package/src/runtime/storage/work-status.js +245 -26
  417. package/src/runtime/task-attempts.js +589 -69
  418. package/src/runtime/task-classifier.js +47 -11
  419. package/src/runtime/task-graph.js +373 -0
  420. package/src/runtime/task-run.js +778 -0
  421. package/src/runtime/task-scope.js +202 -56
  422. package/src/runtime/task-sources.js +147 -0
  423. package/src/runtime/task-state.js +440 -65
  424. package/src/runtime/team/admission.js +301 -0
  425. package/src/runtime/team/envelope.js +324 -0
  426. package/src/runtime/team/review-guard.js +156 -0
  427. package/src/runtime/trace/analyze.js +427 -0
  428. package/src/runtime/trace/baseline.js +770 -0
  429. package/src/runtime/trace/ledger.js +63 -140
  430. package/src/runtime/trace/otlp-export.js +568 -0
  431. package/src/runtime/trace/otlp-map.js +481 -0
  432. package/src/runtime/trace/spans.js +745 -0
  433. package/src/runtime/trace/telemetry.js +225 -0
  434. package/src/runtime/trace/views.js +1 -0
  435. package/src/runtime/transcripts/command.js +98 -0
  436. package/src/runtime/transcripts/cursor.js +326 -0
  437. package/src/runtime/transcripts/read.js +126 -0
  438. package/src/runtime/transcripts/readers/claude-jsonl.js +74 -0
  439. package/src/runtime/transcripts/readers/codex-rollout.js +70 -0
  440. package/src/runtime/transcripts/readers/copilot-events.js +90 -0
  441. package/src/runtime/transcripts/readers/kiro-jsonl.js +77 -0
  442. package/src/runtime/transcripts/readers/pi-jsonl.js +59 -0
  443. package/src/runtime/transcripts/registry.js +161 -0
  444. package/src/runtime/transcripts/stats.js +161 -0
  445. package/src/runtime/verification/check-key.js +628 -0
  446. package/src/runtime/verification/contract-runner.js +546 -11
  447. package/src/runtime/verification/engine.js +499 -9
  448. package/src/runtime/verification/impact.js +617 -0
  449. package/src/runtime/verification/inflight.js +205 -0
  450. package/src/runtime/verification/registry.js +176 -0
  451. package/src/runtime/verification/reuse.js +184 -0
  452. package/src/runtime/verification/telemetry-emit.js +254 -0
  453. package/src/runtime/verification/test-selection.js +67 -7
  454. package/src/runtime/worker/active.js +90 -0
  455. package/src/runtime/worker/cancel.js +222 -0
  456. package/src/runtime/worker/catalogue.js +122 -0
  457. package/src/runtime/worker/command.js +677 -0
  458. package/src/runtime/worker/evidence.js +288 -0
  459. package/src/runtime/worker/launch.js +288 -0
  460. package/src/runtime/worker/models.js +137 -0
  461. package/src/runtime/worker/parsers.js +218 -0
  462. package/src/runtime/worker/probes/index.js +706 -0
  463. package/src/runtime/worker/process-tree.js +415 -0
  464. package/src/runtime/worker/quota.js +43 -0
  465. package/src/runtime/worker/readiness.js +713 -0
  466. package/src/runtime/worker/run-store.js +166 -0
  467. package/src/runtime/worker/supervisor.js +541 -0
  468. package/src/runtime/worker/worktree-check.js +252 -0
  469. package/src/runtime/workflow-engine.js +5 -1
  470. package/src/runtime/workflow-orchestrator.js +578 -63
  471. package/src/runtime/worktree.js +149 -22
  472. package/src/state/index.js +1 -1
  473. package/src/state/lockfile.js +64 -10
  474. package/src/state/run-lock.js +1 -1
  475. package/types/node-commonjs.d.ts +106 -7
  476. package/core/.antigravity-plugin/hooks.json +0 -39
  477. package/core/harnesses/gemini/hooks/hooks.json +0 -77
  478. package/core/harnesses/gemini/hooks/lib.sh +0 -302
  479. package/core/harnesses/gemini/hooks/mcp-tool-guard.sh +0 -21
  480. package/core/harnesses/gemini/hooks/post-edit-lint.sh +0 -39
  481. package/core/harnesses/gemini/hooks/pre-bash-guard.sh +0 -21
  482. package/core/harnesses/gemini/hooks/pre-compact.sh +0 -38
  483. package/core/harnesses/gemini/hooks/pre-implement-gate.sh +0 -22
  484. package/core/harnesses/gemini/hooks/session-end.impl.sh +0 -89
  485. package/core/harnesses/gemini/hooks/session-end.sh +0 -5
  486. package/core/harnesses/gemini/hooks/session-start.sh +0 -5
  487. package/core/harnesses/gemini/settings/adapter-defaults.json +0 -4
  488. package/core/harnesses/shared/hooks/adapters/arg-fields.js +0 -19
  489. package/core/harnesses/shared/hooks/adapters/gemini.js +0 -114
  490. package/core/harnesses/shared/hooks/hooks.json +0 -47
  491. package/core/shared/guidance/FLAGS.md +0 -25
  492. package/core/shared/guidance/rules/RULE_01_SAFETY.md +0 -25
  493. package/core/shared/guidance/rules/RULE_02_WORKFLOW.md +0 -23
  494. package/core/shared/guidance/rules/RULE_03_QUALITY.md +0 -14
  495. package/core/shared/guidance/rules/RULE_04_QUESTIONS.md +0 -46
  496. package/src/adapters/gemini/hooks.js +0 -210
  497. package/src/adapters/gemini/index.js +0 -390
@@ -0,0 +1,383 @@
1
+ #!/usr/bin/env bash
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
+ # emission.sh — Canonical Policy Library: the hook emission adapter and the emission ledger
4
+ # (feature 078, IC-004, IC-015; DEC-015, DEC-016, DEC-017).
5
+ #
6
+ # The prompt path's emission, from the state bits to the response bytes. arbitrate() in
7
+ # src/runtime/context/arbitrate.js is the reference for the rules; this file reads the compiled
8
+ # table (emission-rules.sh), claims through summary-store.sh and renders with one jq process running
9
+ # emission.jq. It starts no Node or doflow-run process.
10
+ #
11
+ # Sourcing this file defines functions only: no option, no variable, no trap, no output. bash 3.2
12
+ # safe and safe under the caller's `set -euo pipefail`. The caller has sourced lib.sh (which sources
13
+ # identity.sh), summary-store.sh and emission-rules.sh; a missing one is a fault.
14
+ #
15
+ # Store, under SESSION_DIR (lib.sh; session-env/sessions; empty with no config home, which prints
16
+ # the silent response with reason silent:no-home):
17
+ # <unitId>/injected one-shot bootstrap slot, created exclusively (set -C) by the first caller
18
+ # <unitId>/emitted the IC-015 ledger: <ISO-8601 UTC>\t<kind>\t<key>\t<outcome>\t<caller>, one
19
+ # line per (kind, key, outcome), appended only when that triple is absent
20
+ #
21
+ # Faults: any claim or render failure prints the silent response ({} and a newline) and records
22
+ # `doflow_capture_failure user-prompt-submit emission-<point>`, point one of deps, unit, slot,
23
+ # summary, grant, warning, render; a failed ledger append records emission-ledger and keeps the
24
+ # rendered response. A fault after the slot claim releases the slot this call created, so the next
25
+ # prompt bootstraps again (DEC-038); a fault in a later claim renames the summary, grant and warning
26
+ # already claimed back into place (`mv -n`, never over a newer file). A claim that fails because its
27
+ # source vanished (another caller won it) is no fault: that segment counts as absent and the
28
+ # bootstrap continues. A claimed summary or grant whose render fails is not restored.
29
+ #
30
+ # Ledger outcomes besides refused:mandatory-over-budget: `optional-dropped <key> over-budget`, one
31
+ # per optional segment the budget dropped (key: the summary id for summary, else the segment name;
32
+ # DEC-041). A dropped nudge leaves the session unmarked, so a later prompt can nudge.
33
+
34
+ # _doflow_em_capture <point>: one failure-capture line, never on stdout or stderr.
35
+ _doflow_em_capture() {
36
+ local dir
37
+ _DOFLOW_SRC=${BASH_SOURCE[0]//\\//}; case $_DOFLOW_SRC in */*) dir=${_DOFLOW_SRC%/*} ;; *) dir=. ;; esac
38
+ if declare -F doflow_capture_failure >/dev/null 2>&1; then
39
+ ( doflow_capture_failure user-prompt-submit "emission-$1" ) >/dev/null 2>&1 || true
40
+ else
41
+ ( . "$dir/capture-failure.sh" && doflow_capture_failure user-prompt-submit "emission-$1" ) >/dev/null 2>&1 || true
42
+ fi
43
+ return 0
44
+ }
45
+
46
+ # _doflow_em_restore <claimed> <original>: rename a claimed file back unless a newer one took its
47
+ # place, in which case the claimed copy is the older and is removed.
48
+ _doflow_em_restore() {
49
+ [ -n "$1" ] && [ -e "$1" ] || return 0
50
+ mv -n "$1" "$2" 2>/dev/null || true
51
+ [ ! -e "$1" ] || rm -f "$1" 2>/dev/null || true
52
+ return 0
53
+ }
54
+
55
+ # _doflow_em_release: undo this call's claims before a fault response, from the caller's locals
56
+ # (made, dir, sumfile, sumsrc, claimed_grant, grantsrc, warnclaimed, warnfile). The slot goes last.
57
+ _doflow_em_release() {
58
+ [ "$sumfile" = /dev/null ] || _doflow_em_restore "$sumfile" "$sumsrc"
59
+ [ -z "$claimed_grant" ] || _doflow_em_restore "$claimed_grant" "$grantsrc"
60
+ [ -z "$warnclaimed" ] || _doflow_em_restore "$warnclaimed" "$warnfile"
61
+ sumfile=/dev/null claimed_grant="" warnclaimed=""
62
+ if [ "$made" = 1 ]; then rm -f "$dir/injected" 2>/dev/null || true; made=0; fi
63
+ return 0
64
+ }
65
+
66
+ # _doflow_em_measure <response> <digest>: for the response printed as `printf '%s\n'`, DF_EMIT_BYTES
67
+ # (its byte length under LC_ALL=C, newline included) and DF_EMIT_DIGEST (the renderer's digest
68
+ # header line when it is 8 lowercase hex, else empty). Rider R1 (091): metadata for the hook line
69
+ # only; builtins only, no response byte leaves this function, and nothing reaches stdout.
70
+ _doflow_em_measure() {
71
+ local LC_ALL=C
72
+ DF_EMIT_BYTES=$(( ${#1} + 1 ))
73
+ DF_EMIT_DIGEST=""
74
+ case "${2:-}" in
75
+ [0123456789abcdef][0123456789abcdef][0123456789abcdef][0123456789abcdef][0123456789abcdef][0123456789abcdef][0123456789abcdef][0123456789abcdef]) DF_EMIT_DIGEST=$2 ;;
76
+ esac
77
+ return 0
78
+ }
79
+
80
+ # _doflow_em_silent <point>: the fault response.
81
+ _doflow_em_silent() {
82
+ _doflow_em_capture "$1"
83
+ DF_EMIT_REASON="fault:$1"
84
+ printf '{}\n'
85
+ return 0
86
+ }
87
+
88
+ # _doflow_em_seen <ledger file> <kind> <key> <outcome>: 0 when the triple is already recorded.
89
+ _doflow_em_seen() {
90
+ local ts kind key outcome caller
91
+ [ -f "$1" ] || return 1
92
+ {
93
+ while IFS=$'\t' read -r ts kind key outcome caller || [ -n "$ts" ]; do
94
+ if [ "$kind" = "$2" ] && [ "$key" = "$3" ] && [ "$outcome" = "$4" ]; then return 0; fi
95
+ ts=""
96
+ done
97
+ } 2>/dev/null <"$1"
98
+ return 1
99
+ }
100
+
101
+ # _doflow_em_ledger_add <unit dir> <kind> <key> <outcome> <caller>: append one IC-015 line unless
102
+ # (kind, key, outcome) is already recorded. Returns 1 when the line could not be written.
103
+ _doflow_em_ledger_add() {
104
+ local file="$1/emitted" ts
105
+ if _doflow_em_seen "$file" "$2" "$3" "$4"; then return 0; fi
106
+ mkdir -p "$1" 2>/dev/null || return 1
107
+ ts=$(date -u +%Y-%m-%dT%H:%M:%SZ 2>/dev/null) || return 1
108
+ printf '%s\t%s\t%s\t%s\t%s\n' "$ts" "$2" "$3" "$4" "$5" >>"$file" 2>/dev/null || return 1
109
+ return 0
110
+ }
111
+
112
+ # _doflow_em_rule <event.segment> <vector>: prints nothing; sets DF_ACTION (skip on any failure).
113
+ _doflow_em_rule() {
114
+ DF_ACTION=skip
115
+ doflow_emission_rule "$1" "$2" || DF_ACTION=skip
116
+ return 0
117
+ }
118
+
119
+ # _doflow_em_actions: the prompt segments' actions from the caller's state locals (role, kind,
120
+ # bootstrapped, subagent, own, grant, refused, warning, nudge_state), vectors in IC-002 order.
121
+ _doflow_em_actions() {
122
+ _doflow_em_rule prompt.slot "$bootstrapped"; a_slot=$DF_ACTION
123
+ _doflow_em_rule prompt.git "$role:$bootstrapped"; a_git=$DF_ACTION
124
+ _doflow_em_rule prompt.summary "$role:$kind:$subagent:$bootstrapped:$own"; a_summary=$DF_ACTION
125
+ _doflow_em_rule prompt.warning "$role:$subagent:$bootstrapped:$warning"; a_warning=$DF_ACTION
126
+ _doflow_em_rule prompt.grant "$subagent:$grant:$refused"; a_grant=$DF_ACTION
127
+ _doflow_em_rule prompt.nudge "$role:$nudge_state"; a_nudge=$DF_ACTION
128
+ return 0
129
+ }
130
+
131
+ # doflow_emit_prompt <session_id> <cwd> <payload_title> <subagent> <nudge_text>
132
+ # IC-004 steps 2 to 8 for one UserPromptSubmit event; prints the response on stdout and returns 0.
133
+ # session_id the payload session_id; empty prints nothing (the 0fcd973 early exit)
134
+ # cwd the payload cwd
135
+ # payload_title the payload session_title; non-empty suppresses sessionTitle
136
+ # subagent non-empty when the payload is a native subagent prompt (agent_id or agent_type)
137
+ # nudge_text the nudge message when the classifier earned it, else empty; the session is
138
+ # marked nudged here, only once the nudge rendered (DEC-041)
139
+ # Reads DOFLOW_AGENT (harness; sessionTitle on every harness but codex, DEC-030),
140
+ # DOFLOW_CONTEXT_MAX_BYTES (budget, default DF_RULES_MAX_BYTES_DEFAULT or 16384), SESSION_DIR and the
141
+ # launcher variables through doflow_identity. Sets DF_ID_* (doflow_identity), DF_EMIT_REASON (emit,
142
+ # refused:mandatory-over-budget, silent:already-bootstrapped, silent:unchanged, silent:no-home or
143
+ # fault:<point>), DF_EMIT_BYTES and DF_EMIT_DIGEST (_doflow_em_measure for emit and refused:*, else 0
144
+ # and empty) and DF_EMIT_NUDGE (rendered or empty); when the nudge was rendered it calls
145
+ # `nudge_mark <session> nudged` and, when contract.sh is loaded, `doflow_decide advisory prompt-nudge`.
146
+ doflow_emit_prompt() {
147
+ local session="${1:-}" cwd="${2:-}" payload_title="${3:-}" nudge="${5:-}"
148
+ local subagent=false nudge_state=none role kind bootstrapped=false own=none grant=none refused=false
149
+ local warning=false legacy=false a_slot a_git a_summary a_warning a_grant a_nudge
150
+ local sessions dir unit max harness here renderer project="" warnfile="" warntext="" had_c=0 made=0
151
+ local gitfile sumfile=/dev/null grantfile=/dev/null claimed_grant="" absent="" plan out
152
+ local refusal=refused:mandatory-over-budget title=false sumsrc="" sumid="" grantsrc="" warnclaimed=""
153
+ local dropped rest seg key digest=false
154
+ DF_EMIT_REASON=""
155
+ DF_EMIT_BYTES=0
156
+ DF_EMIT_DIGEST=""
157
+ DF_EMIT_NUDGE=""
158
+ [ -n "$session" ] || return 0
159
+ [ -z "${4:-}" ] || subagent=true
160
+ [ -z "$nudge" ] || nudge_state=nudge
161
+ if ! declare -F doflow_identity doflow_emission_rule doflow_summary_peek doflow_summary_claim \
162
+ doflow_grant_peek doflow_grant_claim doflow_summary_adopt_legacy doflow_summary_legacy_present ensure_project_dir >/dev/null 2>&1; then
163
+ _doflow_em_silent deps
164
+ return 0
165
+ fi
166
+ _DOFLOW_SRC=${BASH_SOURCE[0]//\\//}; case $_DOFLOW_SRC in */*) here=${_DOFLOW_SRC%/*} ;; *) here=. ;; esac
167
+ # The renderer beside the entry policy when it set _DOFLOW_POLDIR, else beside this file.
168
+ renderer=$here/emission.jq
169
+ [ -z "${_DOFLOW_POLDIR:-}" ] || [ ! -f "$_DOFLOW_POLDIR/emission.jq" ] || renderer=$_DOFLOW_POLDIR/emission.jq
170
+
171
+ # Step 2: identity, and the unit whose slot and ledger this event uses. The session id names
172
+ # git-context.json's directory for every lineage kind, so it is a path segment or a fault (DEC-042).
173
+ if ! [[ $session =~ ^[A-Za-z0-9][A-Za-z0-9._-]{0,127}$ ]]; then
174
+ _doflow_em_silent unit
175
+ return 0
176
+ fi
177
+ doflow_identity "$session" "$cwd"
178
+ role=$DF_ID_ROLE
179
+ kind=$DF_ID_KIND
180
+ unit=$DF_ID_UNIT
181
+ if ! [[ $unit =~ ^[A-Za-z0-9][A-Za-z0-9._-]{0,127}$ ]]; then
182
+ _doflow_em_silent unit
183
+ return 0
184
+ fi
185
+ # IC-010: lib.sh's SESSION_DIR is empty with no config home; there is no store, so nothing is
186
+ # claimed, rendered or recorded (src/runtime/context/arbitrate.js answers silent:no-home too).
187
+ sessions="${SESSION_DIR:-}"
188
+ if [ -z "$sessions" ]; then
189
+ DF_EMIT_REASON=silent:no-home
190
+ printf '{}\n'
191
+ return 0
192
+ fi
193
+ dir="$sessions/$unit"
194
+ max="${DOFLOW_CONTEXT_MAX_BYTES:-}"
195
+ [[ $max =~ ^[1-9][0-9]{0,9}$ ]] || max="${DF_RULES_MAX_BYTES_DEFAULT:-16384}"
196
+ harness="${DOFLOW_AGENT:-}"
197
+ [[ $harness =~ ^[A-Za-z0-9._-]{0,40}$ ]] || harness=unknown
198
+
199
+ # Step 3: state bits. The project directory, the legacy file, the warning and the owner summary
200
+ # only matter before the bootstrap, so a later prompt reads none of them.
201
+ if [ -e "$dir/injected" ] || [ -L "$dir/injected" ]; then bootstrapped=true; fi
202
+ if [ "$bootstrapped" = false ]; then
203
+ if [ -n "$cwd" ]; then project=$(ensure_project_dir "$cwd" 2>/dev/null) || project=""; fi
204
+ if [ -n "$project" ]; then
205
+ if doflow_summary_legacy_present "$cwd"; then legacy=true; fi
206
+ warnfile="$project/uncommitted-warning.txt"
207
+ if [ -f "$warnfile" ]; then warning=true; fi
208
+ fi
209
+ doflow_summary_peek "$DF_ID_WORKTREE" "$DF_ID_RUN" "$DF_ID_LINEAGE" "$session"
210
+ own=$DF_SUMMARY_OWN
211
+ fi
212
+ # Grants are addressed to launched units only: local, solo and main lineages are shared by
213
+ # unrelated sessions (DEC-039).
214
+ if [ "$kind" = launched ]; then
215
+ doflow_grant_peek "$DF_ID_RUN" "$DF_ID_LINEAGE" "$max"
216
+ grant=$DF_GRANT
217
+ fi
218
+ if [ "$grant" = over ] && _doflow_em_seen "$dir/emitted" grant "$DF_GRANT_ID" "$refusal"; then refused=true; fi
219
+
220
+ # Step 4: the legacy adoption, then the owner summary bit again.
221
+ _doflow_em_rule legacy-adopt.legacy "$role:$kind:$subagent:$bootstrapped:$legacy"
222
+ if [ "$DF_ACTION" = adopt ]; then
223
+ doflow_summary_adopt_legacy "$cwd" "$DF_ID_WORKTREE" || true
224
+ doflow_summary_peek "$DF_ID_WORKTREE" "$DF_ID_RUN" "$DF_ID_LINEAGE" "$session"
225
+ own=$DF_SUMMARY_OWN
226
+ fi
227
+
228
+ # Step 5: one lookup per segment.
229
+ _doflow_em_actions
230
+
231
+ # Step 6: claims in the order slot, summary, grant, warning. EEXIST on the slot means another
232
+ # caller bootstrapped this unit: the segments are looked up again as bootstrapped, which makes
233
+ # every bootstrap-only one skip.
234
+ if [ "$a_slot" = claim ]; then
235
+ if ! mkdir -p "$dir" 2>/dev/null; then
236
+ _doflow_em_silent slot
237
+ return 0
238
+ fi
239
+ case $- in *C*) had_c=1 ;; esac
240
+ set -C
241
+ { : >"$dir/injected"; } 2>/dev/null && made=1
242
+ [ "$had_c" = 1 ] || set +C
243
+ if [ "$made" = 0 ]; then
244
+ if [ -e "$dir/injected" ] || [ -L "$dir/injected" ]; then
245
+ bootstrapped=true
246
+ _doflow_em_actions
247
+ else
248
+ _doflow_em_silent slot
249
+ return 0
250
+ fi
251
+ fi
252
+ fi
253
+ # A lost claim (the source gone, or no longer a pending summary) makes that segment absent and the
254
+ # segments are looked up again; only a failure with the source still in place is a fault.
255
+ if [ "$a_summary" = truncate ]; then
256
+ if doflow_summary_claim "$DF_ID_WORKTREE" "$DF_ID_RUN" "$DF_ID_LINEAGE" "$unit" "$session"; then
257
+ sumfile=$DF_SUMMARY_CLAIMED
258
+ sumsrc=$DF_SUMMARY_SCOPE/summary.md
259
+ sumid=$DF_SUMMARY_SID
260
+ else
261
+ doflow_summary_peek "$DF_ID_WORKTREE" "$DF_ID_RUN" "$DF_ID_LINEAGE" "$session"
262
+ if [ "$DF_SUMMARY_OWN" = pending ]; then
263
+ _doflow_em_release
264
+ _doflow_em_silent summary
265
+ return 0
266
+ fi
267
+ own=none
268
+ _doflow_em_actions
269
+ fi
270
+ fi
271
+ if [ "$a_grant" = whole ]; then
272
+ grantsrc=$DF_GRANT_FILE
273
+ if doflow_grant_claim "$DF_ID_RUN" "$DF_ID_LINEAGE" "$unit" "$max"; then
274
+ grantfile=$DF_GRANT_CLAIMED
275
+ claimed_grant=$grantfile
276
+ grantsrc=$DF_GRANT_FILE
277
+ elif [ -n "$grantsrc" ] && [ -f "$grantsrc" ]; then
278
+ _doflow_em_release
279
+ _doflow_em_silent grant
280
+ return 0
281
+ else
282
+ grant=none
283
+ _doflow_em_actions
284
+ fi
285
+ elif [ "$a_grant" = pointer ]; then
286
+ # An over-budget grant is never claimed: it renders as its pointer from where it lies.
287
+ grantfile=$DF_GRANT_FILE
288
+ fi
289
+ # The warning is claimed by rename, so two first prompts deliver it once (DEC-040); read -d ''
290
+ # returns non-zero at EOF, which is accepted only once the claimed file is known to be readable.
291
+ if [ "$a_warning" = include ]; then
292
+ if mv "$warnfile" "$warnfile.claimed.$unit" 2>/dev/null; then
293
+ warnclaimed=$warnfile.claimed.$unit
294
+ if [ -r "$warnclaimed" ] && [ -f "$warnclaimed" ]; then
295
+ IFS= read -r -d '' warntext 2>/dev/null <"$warnclaimed" || true
296
+ else
297
+ _doflow_em_release
298
+ _doflow_em_silent warning
299
+ return 0
300
+ fi
301
+ elif [ -e "$warnfile" ] || [ -L "$warnfile" ]; then
302
+ _doflow_em_release
303
+ _doflow_em_silent warning
304
+ return 0
305
+ else
306
+ warning=false
307
+ _doflow_em_actions
308
+ fi
309
+ fi
310
+
311
+ # Nothing that renders: silence without a jq process.
312
+ case "$a_git $a_summary $a_warning $a_grant $a_nudge" in
313
+ *include* | *truncate* | *whole* | *pointer*) ;;
314
+ *)
315
+ if [ "$bootstrapped" = true ]; then DF_EMIT_REASON=silent:already-bootstrapped; else DF_EMIT_REASON=silent:unchanged; fi
316
+ printf '{}\n'
317
+ return 0
318
+ ;;
319
+ esac
320
+
321
+ # Step 7: one jq process. A missing file is /dev/null and named in plan.absent.
322
+ gitfile="$sessions/$session/git-context.json"
323
+ if [ ! -f "$gitfile" ]; then gitfile=/dev/null; absent='"git"'; fi
324
+ [ "$sumfile" != /dev/null ] || absent="${absent:+$absent,}\"summary\""
325
+ [ "$grantfile" != /dev/null ] || absent="${absent:+$absent,}\"grant\""
326
+ [ "$a_warning" = include ] || absent="${absent:+$absent,}\"warning\""
327
+ [ -n "$payload_title" ] || title=true
328
+ plan="{\"actions\":{\"git\":\"$a_git\",\"summary\":\"$a_summary\",\"warning\":\"$a_warning\",\"grant\":\"$a_grant\",\"nudge\":\"$a_nudge\"},\"maxBytes\":$max,\"harness\":\"$harness\",\"title\":$title,\"absent\":[$absent]"
329
+ [ "$sumfile" = /dev/null ] || plan="$plan,\"summaryBytes\":${DF_SUMMARY_BYTES:-0}"
330
+ # Rider R1: the renderer hashes the response only when the bridge will write it (telemetry on, fd set).
331
+ [ "${DOFLOW_TELEMETRY:-}" = off ] || [ -z "${DOFLOW_DECISION_FD:-}" ] || digest=true
332
+ plan="$plan,\"digest\":$digest,\"mode\":\"hook\"}"
333
+ # Hook mode: the first line is the dropped segment names, tab-joined (possibly empty); the second
334
+ # is the response digest (empty unless plan.digest).
335
+ out=$(jq -n -r -f "$renderer" --argjson plan "$plan" --rawfile git "$gitfile" \
336
+ --rawfile summary "$sumfile" --rawfile grant "$grantfile" --arg warning "$warntext" \
337
+ --arg nudge "$nudge" 2>/dev/null) || out=""
338
+ [ "$sumfile" = /dev/null ] || rm -f "$sumfile" 2>/dev/null || true
339
+ [ -z "$claimed_grant" ] || rm -f "$claimed_grant" 2>/dev/null || true
340
+ [ -z "$warnclaimed" ] || rm -f "$warnclaimed" 2>/dev/null || true
341
+ sumfile=/dev/null claimed_grant="" warnclaimed=""
342
+ case "$out" in *$'\n'*$'\n'?*) ;; *) out="" ;; esac
343
+ if [ -z "$out" ]; then
344
+ _doflow_em_release
345
+ _doflow_em_silent render
346
+ return 0
347
+ fi
348
+ dropped=${out%%$'\n'*}
349
+ out=${out#*$'\n'}
350
+ digest=${out%%$'\n'*}
351
+ out=${out#*$'\n'}
352
+
353
+ # Step 8: the refusal ledger line (key: the grant's summary id), one optional-dropped line per
354
+ # dropped segment, then the nudge record.
355
+ DF_EMIT_REASON=emit
356
+ if [ "$a_grant" = pointer ]; then
357
+ DF_EMIT_REASON=$refusal
358
+ _doflow_em_ledger_add "$dir" grant "$DF_GRANT_ID" "$refusal" hook || _doflow_em_capture ledger
359
+ fi
360
+ rest=$dropped
361
+ while [ -n "$rest" ]; do
362
+ seg=${rest%%$'\t'*}
363
+ case "$rest" in *$'\t'*) rest=${rest#*$'\t'} ;; *) rest="" ;; esac
364
+ [ -n "$seg" ] || continue
365
+ key=$seg
366
+ [ "$seg" != summary ] || [ -z "$sumid" ] || key=$sumid
367
+ [ "$seg" != grant ] || [ -z "${DF_GRANT_ID:-}" ] || key=$DF_GRANT_ID
368
+ _doflow_em_ledger_add "$dir" optional-dropped "$key" over-budget hook || _doflow_em_capture ledger
369
+ done
370
+ if [ "$a_nudge" = include ]; then
371
+ case $'\t'"$dropped"$'\t' in
372
+ *$'\t'nudge$'\t'*) ;;
373
+ *)
374
+ DF_EMIT_NUDGE=rendered
375
+ if declare -F nudge_mark >/dev/null 2>&1; then nudge_mark "$session" nudged || true; fi
376
+ if declare -F doflow_decide >/dev/null 2>&1; then doflow_decide advisory prompt-nudge || true; fi
377
+ ;;
378
+ esac
379
+ fi
380
+ _doflow_em_measure "$out" "$digest"
381
+ printf '%s\n' "$out"
382
+ return 0
383
+ }
@@ -0,0 +1,177 @@
1
+ #!/usr/bin/env bash
2
+ # identity.sh — Canonical Policy Library: session role and identity (feature 078, IC-007, IC-009)
3
+ #
4
+ # The only definition of doflow_session_role and doflow_identity (DEC-011). policies/lib.sh sources
5
+ # it from its own directory; the Claude and Codex hooks/lib.sh copies source it through
6
+ # ../../.doflow/shared/hooks/policies/identity.sh.
7
+ #
8
+ # Sourcing this file defines functions only: it sets no shell option, no variable and no trap, and
9
+ # prints nothing. Every function is bash 3.2 safe (no ${var,,}, no associative arrays) and safe
10
+ # under the caller's `set -euo pipefail`.
11
+
12
+ # Sets _DF_ROLE to `main` or `worker` from DOFLOW_SESSION_ROLE, matched case-insensitively, without
13
+ # a subshell. Unset or empty is `main`; any other value is `worker` and writes one stderr line, once
14
+ # per process (a call inside $(...) cannot mark the parent, so each such call still warns).
15
+ _doflow_role_resolve() {
16
+ case "${DOFLOW_SESSION_ROLE:-}" in
17
+ ""|[Mm][Aa][Ii][Nn]) _DF_ROLE=main ;;
18
+ [Ww][Oo][Rr][Kk][Ee][Rr]) _DF_ROLE=worker ;;
19
+ *)
20
+ _DF_ROLE=worker
21
+ if [ -z "${_DF_ROLE_WARNED:-}" ]; then
22
+ echo "[doflow] unknown DOFLOW_SESSION_ROLE; treating session as worker" >&2
23
+ _DF_ROLE_WARNED=1
24
+ fi
25
+ ;;
26
+ esac
27
+ return 0
28
+ }
29
+
30
+ # Print `main` or `worker` for this session, read from DOFLOW_SESSION_ROLE (matched
31
+ # case-insensitively). Unset or empty is `main`; a value that is neither `main` nor
32
+ # `worker` is `worker` and writes one line to stderr. A worker never writes or claims the
33
+ # project's compact summary or warning. Always returns 0. bash 3.2 safe (no ${var,,}).
34
+ doflow_session_role() {
35
+ _doflow_role_resolve
36
+ printf '%s\n' "$_DF_ROLE"
37
+ return 0
38
+ }
39
+
40
+ # Record one failure-capture point for the calling policy, never on stdout or stderr. The policy
41
+ # name is the running script's name without `.sh` or `.impl.sh`; capture-failure.sh replaces a name
42
+ # outside its pattern with `unknown`.
43
+ _doflow_identity_capture() {
44
+ local point="$1" policy="${0##*/}" dir
45
+ policy="${policy%.sh}"
46
+ policy="${policy%.impl}"
47
+ # Inside a function, BASH_SOURCE[0] is the file that defined it: this file's directory.
48
+ _DOFLOW_SRC=${BASH_SOURCE[0]//\\//}; case $_DOFLOW_SRC in */*) dir=${_DOFLOW_SRC%/*} ;; *) dir=. ;; esac
49
+ if declare -F doflow_capture_failure >/dev/null 2>&1; then
50
+ ( doflow_capture_failure "$policy" "$point" ) >/dev/null 2>&1 || true
51
+ else
52
+ ( . "$dir/capture-failure.sh" && doflow_capture_failure "$policy" "$point" ) >/dev/null 2>&1 || true
53
+ fi
54
+ return 0
55
+ }
56
+
57
+ # doflow_identity <session_id> <cwd>
58
+ # Sets DF_ID_RUN, DF_ID_ATTEMPT, DF_ID_LINEAGE, DF_ID_ROLE, DF_ID_WORKTREE, DF_ID_KIND and
59
+ # DF_ID_UNIT per IC-007. Reads only the launcher variables, the payload session_id and cwd; never
60
+ # git or the harness's idea of a main session. Built-ins only, except `pwd -P` in a `cd` subshell
61
+ # when DOFLOW_WORKTREE is set and `mkdir -p` when a launched unit binds. An invalid run or lineage
62
+ # is captured as `identity-invalid` and never reaches a path. Always returns 0.
63
+ doflow_identity() {
64
+ local session_id="${1:-}" cwd="${2:-}" LC_ALL=C
65
+ local run="${DOFLOW_RUN_ID:-}" attempt="${DOFLOW_ATTEMPT:-}" lineage="${DOFLOW_LINEAGE_ID:-}"
66
+ local worktree="${DOFLOW_WORKTREE:-}" invalid=0 run_ok=0 lineage_ok=0 attempt_ok=0
67
+ local sessions dir bound="" had_c=0 mine=0 tries
68
+
69
+ _doflow_role_resolve
70
+ DF_ID_ROLE=$_DF_ROLE
71
+
72
+ # run: id pattern and not `local`; unset is `local`; invalid is unlaunched with lineage solo.
73
+ if [ -z "$run" ]; then
74
+ DF_ID_RUN=local
75
+ elif [ "$run" != local ] && [[ $run =~ ^[A-Za-z0-9][A-Za-z0-9_-]{0,55}$ ]]; then
76
+ DF_ID_RUN=$run
77
+ run_ok=1
78
+ else
79
+ DF_ID_RUN=local
80
+ invalid=1
81
+ fi
82
+
83
+ # attempt: integer 1 to 9999; invalid is as unset.
84
+ DF_ID_ATTEMPT=""
85
+ if [[ $attempt =~ ^[1-9][0-9]{0,3}$ ]]; then
86
+ DF_ID_ATTEMPT=$attempt
87
+ attempt_ok=1
88
+ fi
89
+
90
+ # lineage: id pattern; unset is `main` for main and `solo` for worker; invalid is `solo`.
91
+ if [ -z "$lineage" ]; then
92
+ if [ "$DF_ID_ROLE" = main ]; then DF_ID_LINEAGE=main; else DF_ID_LINEAGE=solo; fi
93
+ elif [[ $lineage =~ ^[A-Za-z0-9][A-Za-z0-9_-]{0,55}$ ]]; then
94
+ DF_ID_LINEAGE=$lineage
95
+ lineage_ok=1
96
+ else
97
+ DF_ID_LINEAGE=solo
98
+ invalid=1
99
+ fi
100
+ if [ -n "$run" ] && [ "$run_ok" = 0 ]; then
101
+ DF_ID_LINEAGE=solo
102
+ lineage_ok=0
103
+ fi
104
+ [ "$invalid" = 0 ] || _doflow_identity_capture identity-invalid
105
+
106
+ # worktree: an absolute path to an existing directory, canonicalised; otherwise the payload cwd.
107
+ DF_ID_WORKTREE=$cwd
108
+ case "$worktree" in
109
+ /*)
110
+ if [ -d "$worktree" ]; then
111
+ worktree=$(CDPATH= cd -P -- "$worktree" 2>/dev/null && pwd -P) || worktree=""
112
+ [ -z "$worktree" ] || DF_ID_WORKTREE=$worktree
113
+ fi
114
+ ;;
115
+ esac
116
+
117
+ if [ "$run_ok" = 1 ] && [ "$lineage_ok" = 1 ] && [ "$attempt_ok" = 1 ]; then
118
+ DF_ID_KIND=launched
119
+ DF_ID_UNIT="L.$DF_ID_RUN.$DF_ID_LINEAGE.$DF_ID_ATTEMPT"
120
+ elif [ "$DF_ID_RUN" = local ] && [ "$DF_ID_LINEAGE" = main ]; then
121
+ # default-main: run unset and lineage main, whether main was defaulted or set explicitly.
122
+ DF_ID_KIND=default-main
123
+ DF_ID_UNIT=$session_id
124
+ else
125
+ DF_ID_KIND=solo
126
+ DF_ID_UNIT=$session_id
127
+ fi
128
+
129
+ # Binding (DEC-008, DEC-044): the first session to present a launched unit creates `bound`
130
+ # exclusively; a session whose id differs from the bound one is inherited and gets its own solo
131
+ # unit. A unit that cannot be bound with a session id (store unwritable, `bound` a symlink, which is
132
+ # never followed, or `bound` still empty after one retry) is inherited too. With no session id the
133
+ # unit is solo with an empty unit id and no capture.
134
+ if [ "$DF_ID_KIND" = launched ]; then
135
+ # The store is lib.sh's SESSION_DIR. Sourced without lib.sh, the config-home rule of
136
+ # src/runtime/config-home.js is applied inline (an absolute XDG_CONFIG_HOME, else an absolute
137
+ # HOME + /.config); with no config home there is no store and the unit is not bound (086 IC-010).
138
+ sessions="${SESSION_DIR:-}"
139
+ # doflow-config-home v1 inline copy: no marked block here, identity.sh defines only its four functions (086 B.2).
140
+ if [ -z "$sessions" ]; then
141
+ case "${XDG_CONFIG_HOME:-}" in
142
+ /*) sessions="$XDG_CONFIG_HOME/doflow/session-env/sessions" ;;
143
+ [A-Za-z]:[\\/]*) case "${OSTYPE:-}" in msys*|cygwin*|win32*) sessions="$XDG_CONFIG_HOME/doflow/session-env/sessions" ;; esac ;;
144
+ esac
145
+ case "${HOME:-}" in
146
+ /*) [ -n "$sessions" ] || sessions="$HOME/.config/doflow/session-env/sessions" ;;
147
+ [A-Za-z]:[\\/]*) case "${OSTYPE:-}" in msys*|cygwin*|win32*) [ -n "$sessions" ] || sessions="$HOME/.config/doflow/session-env/sessions" ;; esac ;;
148
+ esac
149
+ fi
150
+ dir="${sessions:+$sessions/$DF_ID_UNIT}"
151
+ if [ -n "$session_id" ] && [ -n "$dir" ] && mkdir -p "$dir" 2>/dev/null; then
152
+ case $- in *C*) had_c=1 ;; esac
153
+ set -C
154
+ { printf '%s\n' "$session_id" >"$dir/bound"; } 2>/dev/null && mine=1
155
+ [ "$had_c" = 1 ] || set +C
156
+ if [ "$mine" = 0 ]; then
157
+ # An empty first line may be a concurrent binder between its create and its write.
158
+ for tries in 1 2; do
159
+ [ -f "$dir/bound" ] && [ ! -L "$dir/bound" ] || break
160
+ IFS= read -r bound 2>/dev/null <"$dir/bound" || true
161
+ [ -z "$bound" ] || break
162
+ done
163
+ [ -z "$bound" ] || [ "$bound" != "$session_id" ] || mine=1
164
+ fi
165
+ fi
166
+ if [ "$mine" = 0 ]; then
167
+ DF_ID_KIND=solo
168
+ DF_ID_LINEAGE=solo
169
+ DF_ID_UNIT=$session_id
170
+ if [ -n "$session_id" ] && [ -z "${_DF_ID_INHERITED_CAPTURED:-}" ]; then
171
+ _doflow_identity_capture identity-inherited
172
+ _DF_ID_INHERITED_CAPTURED=1
173
+ fi
174
+ fi
175
+ fi
176
+ return 0
177
+ }