@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
@@ -2,13 +2,19 @@
2
2
  // `doflow reconcile` — converge observed state onto the doflow.lock pin: report drift, then heal
3
3
  // it on confirmation. Never re-prompts for MCP; selections ride exactly as pinned.
4
4
  // TypeScript migration (agent-docs/BRIEF_GOAL_DOFLOW.md): run directly by Node native type-stripping.
5
+ const path = require('node:path');
5
6
  const { toolDirs } = require('../../install/targets.js');
6
7
  const { resolveContext, printContext } = require('../../install/context.js');
7
8
  const { writeManifest } = require('../../install/manifest.js');
9
+ const { DEFAULT_BACKUP_RETENTION, createFileBackup } = require('../../install/backup.js');
10
+ const { backupSetFromPlan, backupSetFromPaths } = require('../../install/backup-set.js');
11
+ const { ledgerPath } = require('../../state/index.js');
12
+ const { backupStep, reportBackup, applyBackupRetention } = require('./install.js');
8
13
  const { confirm } = require('../../helper/prompt.js');
9
14
  const { sourceCommit } = require('../../helper/git.js');
10
- const { loadRegistry } = require('../../registry/index.js');
15
+ const { loadRegistry, retiredFor } = require('../../registry/index.js');
11
16
  const { applyLifecycle, recordMcpOwnership } = require('../../lifecycle/index.js');
17
+ const { formatRetiredPlans, retiredReleaseKeys } = require('../../lifecycle/retired-harnesses.js');
12
18
  const {
13
19
  registryLifecycleView, assertSafeRegistryPlan,
14
20
  } = require('../../lifecycle/view.js');
@@ -33,6 +39,10 @@ function reconcileReport(view ) {
33
39
  }
34
40
  perHarness.set(target.harness, entry);
35
41
  }
42
+ // A retired harness's rows (row 127 IC-003) are drift too: converging means releasing them.
43
+ for (const change of (view.plan.retiredHarnesses ?? []).flatMap((item ) => item.changes)) {
44
+ drifts.push({ harness: change.harness, operation: change.operation, assetId: change.assetId, target: change.target, retired: true });
45
+ }
36
46
  return {
37
47
  drifts,
38
48
  conflicts: view.plan.conflicts,
@@ -42,17 +52,29 @@ function reconcileReport(view ) {
42
52
  };
43
53
  }
44
54
 
45
- function printReconcileReport(report , lock ) {
55
+ function printReconcileReport(report , lock , retiredLines = []) {
46
56
  console.log(`[INFO] Reconciling against doflow.lock (sourceVersion ${lock.sourceVersion ?? 'unknown'})`);
47
57
  for (const [harness, counts] of Object.entries (report.perHarness)) {
48
58
  const total = counts.create + counts.update + counts.remove;
49
59
  console.log(`[INFO] ${harness}: ${total === 0 ? 'clean' : `${total} drift(s) (${counts.create} create, ${counts.update} update, ${counts.remove} remove)`}`);
50
60
  }
61
+ for (const line of retiredLines) console.log(line);
51
62
  for (const conflict of report.conflicts) console.log(`[CONFLICT] ${conflict.harness}: ${conflict.reason}`);
52
63
  for (const prerequisite of report.prerequisites) console.log(`[PENDING-TRUST] ${prerequisite.harness}: ${prerequisite.prerequisite}`);
53
64
  if (report.clean) console.log('[OK] Observed state matches doflow.lock.');
54
65
  }
55
66
 
67
+ /** The backup a retirement sweep takes (row 127 FR-4): the set install and update take, files and
68
+ * ledger. A sweep that only gives up rows (release, drop, keep) touches no file, so that set is empty;
69
+ * the ledger alone is then what a rollback needs to bring the rows and the target entry back. */
70
+ function retirementBackupSet(view , paths , scope ) {
71
+ const ledger = ledgerPath(view.stateRoot);
72
+ const args = { scope: scope.global ? 'global' : 'project', scopeRoot: paths.scopeRoot, records: [ledger],
73
+ exclude: [paths.backupRoot, view.stateRoot, paths.manifestPath, path.join(paths.doflowRoot, 'doflow.lock')] };
74
+ const set = backupSetFromPlan({ plan: view.plan, ...args });
75
+ return set.count ? set : backupSetFromPaths({ items: [{ path: ledger, harnesses: [] }], ...args });
76
+ }
77
+
56
78
  function cmdReconcile(o ) {
57
79
  refuseHomeRootedProject(o, 'reconcile');
58
80
  const scope = scopeOf(o);
@@ -61,23 +83,33 @@ function cmdReconcile(o ) {
61
83
  const dirs = toolDirs(scope);
62
84
  const lifecyclePaths = installPaths(scope);
63
85
  const { lock, ledger, manifestServers } = scopeSelectionState(scope);
86
+ // Read only when there is a pin or a row to classify, as before this check existed.
87
+ const registry = lock?.targets?.length || ledger?.resources?.length ? loadRegistry({ repoRoot: REPO_ROOT }) : null;
88
+ const retired = (harness ) => (registry ? retiredFor(registry, harness) : null);
89
+ // A retired pin (row 127 IC-004) names a harness with no adapter: dropped, said, and the rest
90
+ // converge. Its ledger rows are released by this run's plan, like install's and update's.
91
+ for (const entry of lock?.targets ?? []) {
92
+ const record = retired(entry.harness);
93
+ if (record) console.log(`[WARN] ${entry.harness}: retired (use ${record.replacement}); dropped from the pinned targets`);
94
+ }
95
+ const livePins = (lock?.targets ?? []).filter((entry ) => !retired(entry.harness));
64
96
  // A harness the ledger holds but the lock does not pin is installed and outside reconcile's reach.
65
97
  // Said, not converged: the lock records choices, and reconcile has no choice to record for it.
66
- const pinned = new Set((lock?.targets ?? []).map((entry ) => entry.harness));
67
- const unpinned = [...new Set((ledger?.resources ?? []).map((resource ) => resource.harness))].filter((harness) => !pinned.has(harness)).sort();
98
+ const pinned = new Set(livePins.map((entry ) => entry.harness));
99
+ const unpinned = [...new Set((ledger?.resources ?? []).map((resource ) => resource.harness))]
100
+ .filter((harness ) => !pinned.has(harness) && !retired(harness)).sort();
68
101
  for (const harness of unpinned) {
69
102
  const count = ledger.resources.filter((resource ) => resource.harness === harness).length;
70
103
  console.log(`[WARN] ${harness}: installed (ledger holds ${count} resource(s)) but absent from doflow.lock; reconcile does not converge it.`);
71
104
  }
72
- if (!lock || !lock.targets.length) {
105
+ if (!lock || !livePins.length) {
73
106
  // Reconcile converges onto what install pinned; with no pin there is no desired state to
74
107
  // converge to, and guessing one from the registry would silently adopt targets the user
75
108
  // never chose.
76
109
  console.log('[INFO] No doflow.lock in this scope — nothing pinned to reconcile against. Run `doflow install` first.');
77
110
  return;
78
111
  }
79
- const targets = lock.targets.map((entry ) => entry.harness);
80
- const registry = loadRegistry({ repoRoot: REPO_ROOT });
112
+ const targets = livePins.map((entry ) => entry.harness);
81
113
  printContext(resolveContext({ repoRoot: REPO_ROOT, targets, dirs, sourceCommit: sourceCommit(SCRIPT_DIR), ...scope }));
82
114
  // Each harness converges onto its own pinned selection — reconcile never re-prompts and never
83
115
  // lends one harness's servers to another.
@@ -87,7 +119,7 @@ function cmdReconcile(o ) {
87
119
  if (!lifecycleView.plan.safe) { assertSafeRegistryPlan(lifecycleView); return; }
88
120
 
89
121
  const report = reconcileReport(lifecycleView);
90
- printReconcileReport(report, lock);
122
+ printReconcileReport(report, lock, formatRetiredPlans(lifecycleView.plan.retiredHarnesses ?? []));
91
123
  if (o.json) console.log(JSON.stringify({ scope: lock.scope, sourceVersion: lock.sourceVersion, targets, unpinned, ...report }, null, 2));
92
124
  if (o.dryRun) {
93
125
  console.log('[DRY] Reconcile plan complete — no changes written');
@@ -107,10 +139,22 @@ function cmdReconcile(o ) {
107
139
  process.exit(1);
108
140
  }
109
141
  checkpointRunLock(hold);
142
+ // A run that changes a retired harness's rows backs the retirement up first, as install and
143
+ // update do, so `doflow rollback` restores it (row 127 FR-4). Any other reconcile takes none.
144
+ let bid = '';
145
+ const retiring = retiredReleaseKeys(lifecycleView.plan.retiredHarnesses ?? []).size > 0;
146
+ if (retiring && o.noBackup) {
147
+ console.error('[WARN] Skipping backup (--no-backup)');
148
+ } else if (retiring) {
149
+ const commit = sourceCommit(SCRIPT_DIR);
150
+ bid = reportBackup(backupStep(() => createFileBackup({ operation: 'reconcile', set: retirementBackupSet(lifecycleView, lifecyclePaths, scope),
151
+ backupRoot: lifecyclePaths.backupRoot, repoRoot: SCRIPT_DIR, sourceCommit: commit, version: pkg.version, date: new Date() })));
152
+ }
110
153
  applyLifecycle({ plan: lifecycleView.plan, registry: lifecycleView.registry,
111
154
  adapters: buildAdapterRegistry(),
112
155
  stateRoot: lifecycleView.stateRoot, ledger: lifecycleView.ledger });
113
- writeManifest({ scopeRoot: lifecyclePaths.scopeRoot, scriptVersion: pkg.version, operation: 'update', repoRoot: SCRIPT_DIR, sourceCommit: sourceCommit(SCRIPT_DIR), backupId: '', tools: targets, date: new Date() });
156
+ writeManifest({ scopeRoot: lifecyclePaths.scopeRoot, scriptVersion: pkg.version, operation: 'update', repoRoot: SCRIPT_DIR, sourceCommit: sourceCommit(SCRIPT_DIR), backupId: bid, tools: targets, date: new Date() });
157
+ if (bid) applyBackupRetention({ backupRoot: lifecyclePaths.backupRoot, prune: o.prune, keep: o.prune ?? DEFAULT_BACKUP_RETENTION, bid });
114
158
  console.log('[OK] Reconciliation complete — state converged onto doflow.lock.');
115
159
  } finally {
116
160
  hold?.release();
@@ -59,8 +59,8 @@ function cmdRemove(o ) {
59
59
  scope: codexScope(scope), scopeRoot: scope.global ? os.homedir() : path.resolve(scope.projectRoot),
60
60
  targets: lifecycleTargets, mcpAdoptable, retainedMcpIds, stateRoot: view.stateRoot, ledger: view.ledger,
61
61
  context: view.plan.targets[0].adapterInput.context });
62
- // Shared destinations (one .doflow/scripts tree for claude/codex/gemini, one .agents for
63
- // gemini/copilot) mean a removal can legitimately leave files standing. Saying only "removed"
62
+ // Shared destinations (one .doflow/scripts tree for claude/codex, one .agents for
63
+ // antigravity/copilot) mean a removal can legitimately leave files standing. Saying only "removed"
64
64
  // would be half the truth, so what was kept and who still claims it is printed, not implied.
65
65
  for (const line of retentionSummary(result.retained)) console.log(`[INFO] ${line}`);
66
66
  console.log(`[OK] Removed ${result.ledger.resources.length === 0 ? 'all' : 'eligible'} native resource(s) for ${lifecycleTargets.join(', ')}; ${result.ledger.resources.length} owned record(s) remain.`);
@@ -6,7 +6,7 @@
6
6
  // restores per tool, as it always did.
7
7
  // TypeScript migration (agent-docs/BRIEF_GOAL_DOFLOW.md): run directly by Node native type-stripping.
8
8
  const path = require('node:path');
9
- const { resolveTargets, toolDirs } = require('../../install/targets.js');
9
+ const { VALID, resolveTargets, toolDirs } = require('../../install/targets.js');
10
10
  const { resolveContext, printContext } = require('../../install/context.js');
11
11
  const {
12
12
  BackupError, createFileBackup, planRestore, executeRestore, listBackups, formatBytes,
@@ -59,9 +59,12 @@ function cmdRollback(o ) {
59
59
  fail(error);
60
60
  }
61
61
  // A per-file backup restores the harnesses it holds (only those in --target when given), so the
62
- // banner and the install manifest name those, not the default target.
62
+ // banner and the install manifest name those, not the default target. A backup taken by a run
63
+ // that swept a retired harness (127 IC-003) holds that harness's files and rows too: they are
64
+ // restored like any other, but a retired id is no target, so the banner and manifest skip it.
63
65
  const restoredTools = plan.format === 2
64
- ? [...new Set(plan.restore.flatMap((item ) => item.harnesses))].filter((h) => !explicitTargets || targets.includes(h)).sort()
66
+ ? [...new Set(plan.restore.flatMap((item ) => item.harnesses))]
67
+ .filter((h ) => VALID.includes(h) && (!explicitTargets || targets.includes(h))).sort()
65
68
  : targets;
66
69
  printContext(resolveContext({ repoRoot: REPO_ROOT, targets: restoredTools, dirs, sourceCommit: commit, global: o.global, projectRoot: '.' }));
67
70
 
@@ -2,32 +2,41 @@
2
2
  // `doflow self-update` — git fetch/pull the checkout, then re-run the install path so the
3
3
  // installed trees match the freshly pulled source.
4
4
  // TypeScript migration (agent-docs/BRIEF_GOAL_DOFLOW.md): run directly by Node native type-stripping.
5
+ const fs = require('node:fs');
6
+ const path = require('node:path');
5
7
  const { execFileSync } = require('node:child_process');
6
8
  const { REPO_ROOT } = require('../shared.js');
7
9
  const cmdInstall = require('./install.js');
8
10
 
9
- function cmdSelfUpdate(o ) {
11
+ /** The second argument is for tests: the checkout to update and the install it re-runs. */
12
+ function cmdSelfUpdate(o , { repoRoot = REPO_ROOT, install = cmdInstall } = {}) {
10
13
  console.log('[INFO] Self-update: checking for upstream changes...');
11
14
  let pulled = false;
12
15
  let fetchOk = false;
13
- try {
14
- execFileSync('git', ['-C', REPO_ROOT, 'fetch', '--depth=1', 'origin'], { stdio: ['ignore', 'ignore', 'pipe'], timeout: 10000 });
15
- fetchOk = true;
16
- } catch {
17
- console.error('[WARN] git fetch failed (offline or no remote configured) — installing from current HEAD');
16
+ // An npm install is not a git checkout: `git -C` there would act on whatever repository holds
17
+ // node_modules (or fail), never on DoFlow's source.
18
+ const isCheckout = fs.existsSync(path.join(repoRoot, '.git'));
19
+ if (!isCheckout) console.log('[INFO] This install is not a git checkout; to upgrade DoFlow run: npm install -g @khoavu882/doflow');
20
+ if (isCheckout) {
21
+ try {
22
+ execFileSync('git', ['-C', repoRoot, 'fetch', '--depth=1', 'origin'], { stdio: ['ignore', 'ignore', 'pipe'], timeout: 10000 });
23
+ fetchOk = true;
24
+ } catch {
25
+ console.error('[WARN] git fetch failed (offline or no remote configured) — installing from current HEAD');
26
+ }
18
27
  }
19
28
  if (fetchOk) {
20
29
  try {
21
- execFileSync('git', ['-C', REPO_ROOT, 'pull', '--ff-only'], { stdio: ['ignore', 'ignore', 'pipe'], timeout: 10000 });
30
+ execFileSync('git', ['-C', repoRoot, 'pull', '--ff-only'], { stdio: ['ignore', 'ignore', 'pipe'], timeout: 10000 });
22
31
  pulled = true;
23
- const commit = execFileSync('git', ['-C', REPO_ROOT, 'rev-parse', '--short', 'HEAD']).toString().trim();
32
+ const commit = execFileSync('git', ['-C', repoRoot, 'rev-parse', '--short', 'HEAD']).toString().trim();
24
33
  console.log(`[INFO] Updated to commit: ${commit}`);
25
34
  } catch {
26
35
  console.error('[WARN] Fast-forward not possible — using current local state');
27
36
  }
28
37
  }
29
38
  console.log(`[INFO] Running install (after ${pulled ? 'a git pull' : 'checking for updates'})...`);
30
- cmdInstall(o);
39
+ install(o);
31
40
  }
32
41
 
33
42
  module.exports = cmdSelfUpdate;
@@ -42,6 +42,10 @@ function cmdStatus(o ) {
42
42
  ledgerPresent: Boolean(readLedger(registryView.stateRoot)),
43
43
  plan: { changes: registryView.plan.changes.length, conflicts: registryView.plan.conflicts, prerequisites: registryView.plan.prerequisites },
44
44
  };
45
+ // Row 127: a retired harness the ledger still holds rows of, which the next install or update
46
+ // releases. Absent when there is none, so the report is unchanged for every other ledger.
47
+ const retired = (registryView.plan.retiredHarnesses ?? []).map((item ) => ({ harness: item.harness, replacement: item.replacement, rows: item.changes.length }));
48
+ if (retired.length) ctx.registry.retired = retired;
45
49
  // Per-harness status must derive from that harness's own plan target, not the flattened
46
50
  // registryView.plan.changes/conflicts across every target — otherwise, e.g., Codex having
47
51
  // pending changes when it isn't installed yet would make Claude's line falsely report
@@ -50,7 +54,7 @@ function cmdStatus(o ) {
50
54
  // Hook-wiring status needs the same general per-harness verification every install/update run
51
55
  // already flows through (src/lifecycle's verifyLifecycle) rather than a Codex-only hardcode:
52
56
  // it is the one place that can tell 'installed and active' apart from 'installed but pending a
53
- // prerequisite' (Codex's unreviewed trust, Gemini's live hook-trust check) from 'absent'.
57
+ // prerequisite' (Codex's unreviewed trust) from 'absent'.
54
58
  const verification = verifyLifecycle({ plan: registryView.plan, adapters: registryView.adapters, context: { registry } });
55
59
  const hooksFor = (harness ) => verification.verifications.find((item ) => item.harness === harness)?.hookWiring ?? null;
56
60
  const harnessStatus = (harness ) => {
@@ -80,8 +84,19 @@ function cmdStatus(o ) {
80
84
  ctx.registry = { status: 'invalid', error: error.message };
81
85
  }
82
86
 
87
+ // The primary is read on use only (row 120 A.4): a fault in resolving it never breaks status.
88
+ let primary = null;
89
+ let primaryText ;
90
+ try {
91
+ const { primarySummary, resolveForReport } = require('../../runtime/context/primary-command.js');
92
+ primary = resolveForReport({ env: process.env, projectRoot: path.resolve(scope.projectRoot) }).primary;
93
+ primaryText = primarySummary(primary);
94
+ } catch (error ) {
95
+ primaryText = `unavailable (${error?.message || String(error)})`;
96
+ }
97
+
83
98
  if (o.json) {
84
- console.log(JSON.stringify({ context: ctx, manifest, codex: ctx.codex ?? null, mcpSelections }, null, 2));
99
+ console.log(JSON.stringify({ context: ctx, manifest, codex: ctx.codex ?? null, mcpSelections, primary }, null, 2));
85
100
  return;
86
101
  }
87
102
 
@@ -92,6 +107,7 @@ function cmdStatus(o ) {
92
107
  };
93
108
 
94
109
  printContext(ctx);
110
+ console.log(`primary: ${primaryText}`);
95
111
  if (!manifest) {
96
112
  console.log("[WARN] No install manifest found — run 'doflow install' to get started");
97
113
  return;
@@ -126,6 +142,9 @@ function cmdStatus(o ) {
126
142
  if (ctx.registry) {
127
143
  console.log(` Registry lifecycle: ${ctx.registry.status === 'invalid' ? ctx.registry.error : `${ctx.registry.plan.changes} pending, ${ctx.registry.plan.conflicts.length} conflict(s)`}`);
128
144
  if (ctx.registry.status !== 'invalid') console.log(` Neutral state: ${ctx.registry.stateRoot}${ctx.registry.ledgerPresent ? ' (ledger present)' : ' (not yet created)'}`);
145
+ for (const item of ctx.registry.retired ?? []) {
146
+ console.log(` Retired harness: ${item.harness} (use ${item.replacement}): ${item.rows} ledger row(s); the next 'doflow install' or 'doflow update' in this scope releases them`);
147
+ }
129
148
  }
130
149
  console.log('\n TOOL STATUS LAST UPDATED');
131
150
  for (const tool of LIFECYCLE_HARNESSES) {
@@ -0,0 +1,99 @@
1
+ 'use strict';
2
+ // `doflow ui [<project>] [--port N] [private TLS flags]` — run the DoFlow Console, a separately installed package
3
+ // (092 IC-008). The package is found by file existence and never loaded into the core: this module
4
+ // loads only node:fs, node:path and node:child_process (test/runtime/ui-launcher.test.ts). It never
5
+ // listens, reads DoFlow state, installs anything, or adds a variable to the Console's environment.
6
+ // TypeScript migration (agent-docs/BRIEF_GOAL_DOFLOW.md): run directly by Node native type-stripping.
7
+ const fs = require('node:fs');
8
+ const path = require('node:path');
9
+ const { spawn } = require('node:child_process');
10
+
11
+ /** The package's entry, fixed by its own contract (093 IC-002). */
12
+ const CONSOLE_BIN = path.join('bin', 'doflow-ui.js');
13
+ const USAGE = 'doflow ui: usage: doflow ui [<project>] [--port N] [--listen-address <private IP> --tls-cert <absolute path> --tls-key <absolute path>]';
14
+ const NOT_INSTALLED = 'doflow ui: the Console is not installed. Install it with: npm install -g @khoavu882/doflow-ui';
15
+
16
+ /** The Console bin when `dir` holds both the package's package.json and its bin, else null. */
17
+ function consoleBinIn(dir ) {
18
+ const bin = path.join(dir, CONSOLE_BIN);
19
+ return fs.existsSync(path.join(dir, 'package.json')) && fs.existsSync(bin) ? bin : null;
20
+ }
21
+
22
+ /**
23
+ * IC-008 order. First the core's sibling: npm puts both packages in the same
24
+ * `node_modules/@khoavu882/`, global or project, so that copy was installed next to this very core.
25
+ * Then a walk up from the project for `node_modules/@khoavu882/doflow-ui`.
26
+ */
27
+ function findConsole(coreRoot , project ) {
28
+ const sibling = consoleBinIn(path.join(coreRoot, '..', 'doflow-ui'));
29
+ if (sibling) return sibling;
30
+ for (let dir = project; ; dir = path.dirname(dir)) {
31
+ const bin = consoleBinIn(path.join(dir, 'node_modules', '@khoavu882', 'doflow-ui'));
32
+ if (bin) return bin;
33
+ if (path.dirname(dir) === dir) return null;
34
+ }
35
+ }
36
+
37
+ /** `coreRoot` is this core's package root, passed in by the COMMANDS table (src/helper/repo-root.js owns it). */
38
+ function cmdUi(o , coreRoot ) {
39
+ const port = o.port;
40
+ const uiFlags = new Set(['--listen-address', '--tls-cert', '--tls-key']);
41
+ const otherFlags = o.flagsGiven.filter((flag ) => {
42
+ const name = flag.split('=', 1)[0];
43
+ return name !== '--port' && !uiFlags.has(name);
44
+ });
45
+ const remoteValues = [o.listenAddress, o.tlsCert, o.tlsKey];
46
+ const remoteCount = remoteValues.filter((value ) => value !== undefined).length;
47
+ if (o.positional.length > 1 || otherFlags.length > 0
48
+ || (remoteCount !== 0 && remoteCount !== remoteValues.length)
49
+ || (port !== undefined && !(/^[0-9]{1,5}$/.test(port) && Number(port) <= 65535))) {
50
+ console.error(USAGE);
51
+ process.exitCode = 2;
52
+ return;
53
+ }
54
+ const project = path.resolve(o.positional[0] ?? '.');
55
+ const bin = findConsole(coreRoot, project);
56
+ if (!bin) {
57
+ console.error(NOT_INSTALLED);
58
+ process.exitCode = 2;
59
+ return;
60
+ }
61
+ // stderr, so stdout carries only the Console's own one line (093 IC-002).
62
+ console.error(`doflow ui: using ${bin}`);
63
+ const args = [bin, '--core', path.join(coreRoot, 'bin', 'doflow.js')];
64
+ if (o.positional.length > 0) args.push('--project', project);
65
+ if (port !== undefined) args.push('--port', port);
66
+ if (o.listenAddress !== undefined) args.push('--listen-address', o.listenAddress);
67
+ if (o.tlsCert !== undefined) args.push('--tls-cert', o.tlsCert);
68
+ if (o.tlsKey !== undefined) args.push('--tls-key', o.tlsKey);
69
+ const child = spawn(process.execPath, args, { stdio: 'inherit' });
70
+
71
+ // Stay up until the Console exits, so its exit code is ours. A terminal Ctrl-C already reaches the
72
+ // Console through the process group; it is forwarded as SIGTERM, which the Console handles once
73
+ // separately from SIGINT, so the second delivery does not cut its 2 s shutdown short.
74
+ const forward = () => { child.kill('SIGTERM'); };
75
+ process.on('SIGINT', forward);
76
+ process.on('SIGTERM', forward);
77
+ return new Promise((resolve) => {
78
+ let settled = false;
79
+ const settle = (finish ) => {
80
+ if (settled) return;
81
+ settled = true;
82
+ process.off('SIGINT', forward);
83
+ process.off('SIGTERM', forward);
84
+ finish();
85
+ resolve();
86
+ };
87
+ child.on('error', (error ) => settle(() => {
88
+ console.error(`doflow ui: cannot start ${bin}: ${error.message}`);
89
+ process.exitCode = 1;
90
+ }));
91
+ // Killed by a signal: die by the same signal, the shell's own way of forwarding it.
92
+ child.on('exit', (code , signal ) => settle(() => {
93
+ if (signal) process.kill(process.pid, signal);
94
+ else process.exitCode = code ?? 1;
95
+ }));
96
+ });
97
+ }
98
+
99
+ module.exports = cmdUi;
@@ -19,7 +19,7 @@ const { loadRegistry } = require('../../registry/index.js');
19
19
  const { storageAfterInstall } = require('../../runtime/storage/upkeep.js');
20
20
  const { applyLifecycle, recordMcpOwnership, retentionSummary } = require('../../lifecycle/index.js');
21
21
  const {
22
- codexScope, registryLifecycleView, printRegistryLifecycle, printPlanNotices, assertSafeRegistryPlan,
22
+ codexScope, registryLifecycleView, printRegistryLifecycle, printRetiredPlans, printPlanNotices, assertSafeRegistryPlan,
23
23
  lockDocument, lockDelta, recordLock,
24
24
  } = require('../../lifecycle/view.js');
25
25
  const {
@@ -51,7 +51,7 @@ function cmdUpdate(o ) {
51
51
  // One lifecycle view across every requested target — computed unconditionally (not only under
52
52
  // --dry-run) so its safety gate and its plan are the exact same object the real apply below uses.
53
53
  const lifecycleView = registryLifecycleView({ registry, repoRoot: REPO_ROOT, scope, dirs, targets,
54
- mcpSelections: selection.selections, mcpAdoptable: selection.adoptable, retainedMcpIds: selection.retainedMcpIds,
54
+ mcpSelections: selection.selections, mcpAdoptable: selection.adoptable, retainedMcpIds: selection.retainedMcpIds, operation: 'update',
55
55
  force: o.force, permissions: o.permissions === true, statusline: o.statusline === true });
56
56
  if (!lifecycleView.plan.safe) { assertSafeRegistryPlan(lifecycleView); return; }
57
57
  printMcpSelection(lifecycleView, selection.sources, { requested: o.mcp, prefix: o.dryRun ? '[DRY]' : '[INFO]' });
@@ -139,6 +139,7 @@ function cmdUpdate(o ) {
139
139
  const owned = result.ledger.resources.filter((resource ) => resource.harness === target.harness).length;
140
140
  console.log(`[INFO] ${target.harness}: lifecycle verified (${owned} owned resource(s))`);
141
141
  }
142
+ printRetiredPlans(lifecycleView);
142
143
  printPlanNotices(lifecycleView);
143
144
  // As remove does: a file this update leaves standing because a harness outside the run still
144
145
  // claims it is said, not implied. The per-file prune and keep lines are the plan notices above.