muonroi-cli 1.8.3 → 1.8.5

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 (477) hide show
  1. package/LICENSE +21 -21
  2. package/README.md +133 -122
  3. package/dist/packages/agent-harness-core/src/driver.d.ts +27 -1
  4. package/dist/packages/agent-harness-core/src/driver.js +46 -0
  5. package/dist/packages/agent-harness-core/src/event-tee.d.ts +48 -0
  6. package/dist/packages/agent-harness-core/src/event-tee.js +77 -0
  7. package/dist/packages/agent-harness-core/src/mcp-server.d.ts +11 -0
  8. package/dist/packages/agent-harness-core/src/mcp-server.js +87 -15
  9. package/dist/packages/agent-harness-core/src/protocol.d.ts +66 -2
  10. package/dist/packages/agent-harness-core/src/protocol.js +15 -0
  11. package/dist/packages/agent-harness-core/src/visual-quality.d.ts +58 -0
  12. package/dist/packages/agent-harness-core/src/visual-quality.js +141 -0
  13. package/dist/packages/agent-harness-opentui/src/agent-mode.d.ts +6 -0
  14. package/dist/packages/agent-harness-opentui/src/agent-mode.js +14 -1
  15. package/dist/packages/agent-harness-opentui/src/input-bridge.d.ts +2 -10
  16. package/dist/packages/agent-harness-opentui/src/input-bridge.js +103 -16
  17. package/dist/packages/agent-harness-opentui/src/install.d.ts +8 -0
  18. package/dist/packages/agent-harness-opentui/src/install.js +10 -0
  19. package/dist/packages/agent-harness-opentui/src/semantic.js +12 -10
  20. package/dist/packages/agent-harness-opentui/src/visual-capture.d.ts +56 -0
  21. package/dist/packages/agent-harness-opentui/src/visual-capture.js +103 -0
  22. package/dist/src/agent-harness/mock-model.d.ts +28 -0
  23. package/dist/src/agent-harness/mock-model.js +63 -1
  24. package/dist/src/agent-harness/test-spawn.js +31 -0
  25. package/dist/src/cli/config/screen-providers.js +1 -1
  26. package/dist/src/cli/cost-forensics.d.ts +10 -0
  27. package/dist/src/cli/cost-forensics.js +30 -15
  28. package/dist/src/cli/keys-bundle.d.ts +1 -1
  29. package/dist/src/cli/keys-bundle.js +1 -1
  30. package/dist/src/cli/keys.d.ts +2 -2
  31. package/dist/src/cli/keys.js +19 -81
  32. package/dist/src/council/clarifier.d.ts +28 -2
  33. package/dist/src/council/clarifier.js +81 -15
  34. package/dist/src/council/context.js +49 -15
  35. package/dist/src/council/debate-checkpoint.d.ts +129 -0
  36. package/dist/src/council/debate-checkpoint.js +176 -0
  37. package/dist/src/council/debate-planner.js +51 -3
  38. package/dist/src/council/debate-summary.d.ts +25 -0
  39. package/dist/src/council/debate-summary.js +85 -0
  40. package/dist/src/council/debate.d.ts +169 -2
  41. package/dist/src/council/debate.js +1210 -134
  42. package/dist/src/council/index.d.ts +85 -1
  43. package/dist/src/council/index.js +634 -196
  44. package/dist/src/council/leader.d.ts +26 -0
  45. package/dist/src/council/leader.js +150 -9
  46. package/dist/src/council/llm.d.ts +32 -0
  47. package/dist/src/council/llm.js +231 -38
  48. package/dist/src/council/panel-select.d.ts +30 -0
  49. package/dist/src/council/panel-select.js +72 -0
  50. package/dist/src/council/planner.js +23 -0
  51. package/dist/src/council/preflight.d.ts +7 -0
  52. package/dist/src/council/preflight.js +14 -2
  53. package/dist/src/council/prompts.d.ts +30 -3
  54. package/dist/src/council/prompts.js +254 -84
  55. package/dist/src/council/stance-recall.d.ts +42 -0
  56. package/dist/src/council/stance-recall.js +57 -0
  57. package/dist/src/council/strip-think.d.ts +17 -0
  58. package/dist/src/council/strip-think.js +33 -0
  59. package/dist/src/council/types.d.ts +128 -0
  60. package/dist/src/ee/artifact-cache.d.ts +16 -0
  61. package/dist/src/ee/artifact-cache.js +32 -0
  62. package/dist/src/ee/auth.d.ts +1 -0
  63. package/dist/src/ee/auth.js +15 -2
  64. package/dist/src/ee/bridge.d.ts +10 -0
  65. package/dist/src/ee/bridge.js +58 -0
  66. package/dist/src/ee/client.js +81 -18
  67. package/dist/src/ee/export-transcripts.d.ts +1 -0
  68. package/dist/src/ee/export-transcripts.js +8 -10
  69. package/dist/src/ee/extract-session.js +29 -0
  70. package/dist/src/ee/extract-style.d.ts +58 -0
  71. package/dist/src/ee/extract-style.js +270 -0
  72. package/dist/src/ee/recall-ledger.d.ts +9 -0
  73. package/dist/src/ee/recall-ledger.js +3 -0
  74. package/dist/src/ee/scope.d.ts +1 -0
  75. package/dist/src/ee/scope.js +26 -1
  76. package/dist/src/ee/search.d.ts +7 -0
  77. package/dist/src/ee/search.js +24 -0
  78. package/dist/src/ee/transcript-emit.js +2 -0
  79. package/dist/src/ee/types.d.ts +22 -0
  80. package/dist/src/ee/who-am-i-brain.d.ts +35 -0
  81. package/dist/src/ee/who-am-i-brain.js +220 -0
  82. package/dist/src/ee/who-am-i.d.ts +10 -3
  83. package/dist/src/ee/who-am-i.js +12 -0
  84. package/dist/src/ee/workflow-event.d.ts +48 -0
  85. package/dist/src/ee/workflow-event.js +81 -0
  86. package/dist/src/flow/compaction/compress.d.ts +3 -3
  87. package/dist/src/flow/compaction/compress.js +45 -8
  88. package/dist/src/flow/compaction/extract.d.ts +4 -7
  89. package/dist/src/flow/compaction/extract.js +50 -10
  90. package/dist/src/flow/compaction/index.d.ts +13 -1
  91. package/dist/src/flow/compaction/index.js +70 -3
  92. package/dist/src/flow/compaction/input-guard.d.ts +24 -0
  93. package/dist/src/flow/compaction/input-guard.js +43 -0
  94. package/dist/src/flow/fold-planning.d.ts +36 -0
  95. package/dist/src/flow/fold-planning.js +83 -0
  96. package/dist/src/flow/hierarchy.d.ts +146 -0
  97. package/dist/src/flow/hierarchy.js +427 -0
  98. package/dist/src/flow/index.d.ts +1 -0
  99. package/dist/src/flow/index.js +2 -0
  100. package/dist/src/flow/run-artifacts.d.ts +102 -0
  101. package/dist/src/flow/run-artifacts.js +208 -0
  102. package/dist/src/generated/version.d.ts +1 -1
  103. package/dist/src/generated/version.js +1 -1
  104. package/dist/src/gsd/assessment-schema.d.ts +44 -0
  105. package/dist/src/gsd/assessment-schema.js +134 -0
  106. package/dist/src/gsd/capability-registry.d.ts +45 -0
  107. package/dist/src/gsd/capability-registry.js +337 -0
  108. package/dist/src/gsd/complexity-assessor.d.ts +39 -0
  109. package/dist/src/gsd/complexity-assessor.js +152 -0
  110. package/dist/src/gsd/config-bridge.d.ts +7 -0
  111. package/dist/src/gsd/config-bridge.js +114 -0
  112. package/dist/src/gsd/config-loader.d.ts +27 -0
  113. package/dist/src/gsd/config-loader.js +50 -0
  114. package/dist/src/gsd/council-context.d.ts +44 -0
  115. package/dist/src/gsd/council-context.js +114 -0
  116. package/dist/src/gsd/ee-closure.d.ts +28 -0
  117. package/dist/src/gsd/ee-closure.js +49 -0
  118. package/dist/src/gsd/flags.d.ts +55 -0
  119. package/dist/src/gsd/flags.js +83 -0
  120. package/dist/src/gsd/gsd-dispatch.d.ts +58 -0
  121. package/dist/src/gsd/gsd-dispatch.js +131 -0
  122. package/dist/src/gsd/gsd-runtime.d.ts +22 -0
  123. package/dist/src/gsd/gsd-runtime.js +37 -0
  124. package/dist/src/gsd/host-adapter.d.ts +11 -0
  125. package/dist/src/gsd/host-adapter.js +29 -0
  126. package/dist/src/gsd/index.d.ts +24 -1
  127. package/dist/src/gsd/index.js +27 -0
  128. package/dist/src/gsd/loop-host-contract.d.ts +21 -0
  129. package/dist/src/gsd/loop-host-contract.js +39 -0
  130. package/dist/src/gsd/loop-host.d.ts +69 -0
  131. package/dist/src/gsd/loop-host.js +245 -0
  132. package/dist/src/gsd/loop-resolver.d.ts +36 -0
  133. package/dist/src/gsd/loop-resolver.js +79 -0
  134. package/dist/src/gsd/model-tier.d.ts +13 -0
  135. package/dist/src/gsd/model-tier.js +45 -0
  136. package/dist/src/gsd/mutation-gate.d.ts +16 -0
  137. package/dist/src/gsd/mutation-gate.js +41 -0
  138. package/dist/src/gsd/native-roadmap.d.ts +89 -0
  139. package/dist/src/gsd/native-roadmap.js +343 -0
  140. package/dist/src/gsd/native-state.d.ts +47 -0
  141. package/dist/src/gsd/native-state.js +220 -0
  142. package/dist/src/gsd/paths.d.ts +23 -0
  143. package/dist/src/gsd/paths.js +66 -0
  144. package/dist/src/gsd/phase-dag.d.ts +12 -0
  145. package/dist/src/gsd/phase-dag.js +94 -0
  146. package/dist/src/gsd/phase-sync.d.ts +42 -0
  147. package/dist/src/gsd/phase-sync.js +321 -0
  148. package/dist/src/gsd/pil-gate-context.d.ts +13 -0
  149. package/dist/src/gsd/pil-gate-context.js +64 -0
  150. package/dist/src/gsd/pil-gate-critic.d.ts +19 -0
  151. package/dist/src/gsd/pil-gate-critic.js +74 -0
  152. package/dist/src/gsd/plan-council-prompts.d.ts +25 -0
  153. package/dist/src/gsd/plan-council-prompts.js +79 -0
  154. package/dist/src/gsd/plan-council.d.ts +44 -0
  155. package/dist/src/gsd/plan-council.js +251 -0
  156. package/dist/src/gsd/plan-gate-vocabulary.d.ts +40 -0
  157. package/dist/src/gsd/plan-gate-vocabulary.js +64 -0
  158. package/dist/src/gsd/product-workspace.d.ts +13 -0
  159. package/dist/src/gsd/product-workspace.js +124 -0
  160. package/dist/src/gsd/ship-bridge.d.ts +25 -0
  161. package/dist/src/gsd/ship-bridge.js +65 -0
  162. package/dist/src/gsd/state-document.d.ts +40 -0
  163. package/dist/src/gsd/state-document.js +163 -0
  164. package/dist/src/gsd/verdict-schema.d.ts +39 -0
  165. package/dist/src/gsd/verdict-schema.js +144 -0
  166. package/dist/src/gsd/verify-context.d.ts +22 -0
  167. package/dist/src/gsd/verify-context.js +27 -0
  168. package/dist/src/gsd/verify-council-prompts.d.ts +19 -0
  169. package/dist/src/gsd/verify-council-prompts.js +85 -0
  170. package/dist/src/gsd/verify-council.d.ts +25 -0
  171. package/dist/src/gsd/verify-council.js +119 -0
  172. package/dist/src/gsd/verify-gate-vocabulary.d.ts +25 -0
  173. package/dist/src/gsd/verify-gate-vocabulary.js +46 -0
  174. package/dist/src/gsd/workflow-engine.d.ts +60 -0
  175. package/dist/src/gsd/workflow-engine.js +207 -0
  176. package/dist/src/gsd/workflow-tools.d.ts +13 -0
  177. package/dist/src/gsd/workflow-tools.js +277 -0
  178. package/dist/src/hooks/index.js +1 -1
  179. package/dist/src/index.js +44 -11
  180. package/dist/src/maintain/pr-builder.js +23 -13
  181. package/dist/src/mcp/auto-setup.js +57 -32
  182. package/dist/src/mcp/client-pool.js +1 -1
  183. package/dist/src/mcp/ee-tools.js +1 -0
  184. package/dist/src/mcp/oauth-callback.js +2 -2
  185. package/dist/src/mcp/research-onboarding.js +8 -7
  186. package/dist/src/mcp/runtime.js +34 -2
  187. package/dist/src/mcp/setup-guide-text.d.ts +1 -1
  188. package/dist/src/mcp/setup-guide-text.js +77 -76
  189. package/dist/src/models/catalog-client.d.ts +87 -0
  190. package/dist/src/models/catalog-client.js +105 -38
  191. package/dist/src/models/catalog.json +528 -265
  192. package/dist/src/models/registry.d.ts +22 -7
  193. package/dist/src/models/registry.js +73 -10
  194. package/dist/src/ops/doctor.js +8 -8
  195. package/dist/src/orchestrator/auto-commit.js +1 -1
  196. package/dist/src/orchestrator/batch-turn-runner.js +2 -2
  197. package/dist/src/orchestrator/cache-prefix.d.ts +67 -0
  198. package/dist/src/orchestrator/cache-prefix.js +83 -0
  199. package/dist/src/orchestrator/compact-request.d.ts +32 -0
  200. package/dist/src/orchestrator/compact-request.js +41 -0
  201. package/dist/src/orchestrator/compaction.d.ts +10 -0
  202. package/dist/src/orchestrator/compaction.js +27 -7
  203. package/dist/src/orchestrator/council-manager.d.ts +12 -3
  204. package/dist/src/orchestrator/council-manager.js +65 -24
  205. package/dist/src/orchestrator/cross-turn-dedup.d.ts +6 -0
  206. package/dist/src/orchestrator/cross-turn-dedup.js +22 -1
  207. package/dist/src/orchestrator/error-utils.d.ts +29 -0
  208. package/dist/src/orchestrator/error-utils.js +132 -24
  209. package/dist/src/orchestrator/grounding-check.js +39 -1
  210. package/dist/src/orchestrator/message-processor.js +242 -33
  211. package/dist/src/orchestrator/orchestrator.d.ts +39 -3
  212. package/dist/src/orchestrator/orchestrator.js +651 -102
  213. package/dist/src/orchestrator/preprocessor.js +1 -1
  214. package/dist/src/orchestrator/proactive-compact-detector.d.ts +26 -0
  215. package/dist/src/orchestrator/proactive-compact-detector.js +36 -0
  216. package/dist/src/orchestrator/prompts.js +159 -159
  217. package/dist/src/orchestrator/reactive-delegation.d.ts +39 -0
  218. package/dist/src/orchestrator/reactive-delegation.js +59 -0
  219. package/dist/src/orchestrator/retry-classifier.d.ts +2 -1
  220. package/dist/src/orchestrator/retry-classifier.js +46 -2
  221. package/dist/src/orchestrator/safety-intercept.d.ts +45 -0
  222. package/dist/src/orchestrator/safety-intercept.js +55 -0
  223. package/dist/src/orchestrator/scope-reminder.js +1 -1
  224. package/dist/src/orchestrator/session-experience.d.ts +2 -1
  225. package/dist/src/orchestrator/session-experience.js +2 -1
  226. package/dist/src/orchestrator/should-run-gate.d.ts +5 -0
  227. package/dist/src/orchestrator/should-run-gate.js +18 -0
  228. package/dist/src/orchestrator/stall-watchdog.d.ts +24 -3
  229. package/dist/src/orchestrator/stall-watchdog.js +47 -13
  230. package/dist/src/orchestrator/stream-runner.js +62 -29
  231. package/dist/src/orchestrator/sub-agent-cap.d.ts +13 -1
  232. package/dist/src/orchestrator/sub-agent-cap.js +16 -1
  233. package/dist/src/orchestrator/sub-agent-model-tier.d.ts +13 -1
  234. package/dist/src/orchestrator/sub-agent-model-tier.js +16 -2
  235. package/dist/src/orchestrator/subagent-compactor.d.ts +53 -1
  236. package/dist/src/orchestrator/subagent-compactor.js +126 -15
  237. package/dist/src/orchestrator/tool-engine.d.ts +26 -0
  238. package/dist/src/orchestrator/tool-engine.js +669 -56
  239. package/dist/src/orchestrator/tool-limit-auto-recover.d.ts +22 -0
  240. package/dist/src/orchestrator/tool-limit-auto-recover.js +30 -0
  241. package/dist/src/orchestrator/turn-runner-deps.d.ts +19 -0
  242. package/dist/src/orchestrator/turn-watchdog.d.ts +37 -0
  243. package/dist/src/orchestrator/turn-watchdog.js +55 -0
  244. package/dist/src/pil/agent-operating-contract.d.ts +1 -1
  245. package/dist/src/pil/agent-operating-contract.js +1 -1
  246. package/dist/src/pil/cheap-model-playbook.d.ts +1 -1
  247. package/dist/src/pil/cheap-model-playbook.js +5 -1
  248. package/dist/src/pil/cheap-model-workbooks.d.ts +1 -1
  249. package/dist/src/pil/cheap-model-workbooks.js +1 -1
  250. package/dist/src/pil/discovery-types.d.ts +1 -0
  251. package/dist/src/pil/discovery.js +16 -11
  252. package/dist/src/pil/layer1-intent.d.ts +18 -6
  253. package/dist/src/pil/layer1-intent.js +66 -757
  254. package/dist/src/pil/layer15-context-scan.js +15 -1
  255. package/dist/src/pil/layer2_5-ponytail.js +8 -8
  256. package/dist/src/pil/layer3-ee-injection.js +23 -8
  257. package/dist/src/pil/layer4-gsd.js +69 -16
  258. package/dist/src/pil/layer5-context.js +7 -3
  259. package/dist/src/pil/layer6-output.d.ts +23 -0
  260. package/dist/src/pil/layer6-output.js +5 -1
  261. package/dist/src/pil/llm-classify.d.ts +33 -2
  262. package/dist/src/pil/llm-classify.js +123 -131
  263. package/dist/src/pil/native-capabilities-workbook.d.ts +1 -1
  264. package/dist/src/pil/native-capabilities-workbook.js +1 -0
  265. package/dist/src/pil/pipeline.js +34 -2
  266. package/dist/src/pil/response-tools.js +5 -3
  267. package/dist/src/pil/schema.d.ts +1 -0
  268. package/dist/src/pil/schema.js +2 -0
  269. package/dist/src/pil/types.d.ts +18 -0
  270. package/dist/src/playbook/directives.d.ts +4 -0
  271. package/dist/src/playbook/directives.js +17 -5
  272. package/dist/src/product-loop/backlog-builder.d.ts +14 -1
  273. package/dist/src/product-loop/backlog-builder.js +30 -6
  274. package/dist/src/product-loop/discovery-context-format.js +3 -1
  275. package/dist/src/product-loop/discovery-ecosystem.js +4 -1
  276. package/dist/src/product-loop/discovery-interview.js +32 -3
  277. package/dist/src/product-loop/discovery-schema.js +5 -1
  278. package/dist/src/product-loop/done-gate.js +3 -3
  279. package/dist/src/product-loop/ideal-trace.d.ts +7 -0
  280. package/dist/src/product-loop/ideal-trace.js +64 -0
  281. package/dist/src/product-loop/index.d.ts +13 -1
  282. package/dist/src/product-loop/index.js +333 -52
  283. package/dist/src/product-loop/loop-driver.d.ts +7 -0
  284. package/dist/src/product-loop/loop-driver.js +327 -116
  285. package/dist/src/product-loop/phase-plan.d.ts +5 -0
  286. package/dist/src/product-loop/phase-plan.js +39 -2
  287. package/dist/src/product-loop/phase-runner.js +9 -1
  288. package/dist/src/product-loop/progress-snapshot.js +4 -4
  289. package/dist/src/product-loop/sprint-runner.d.ts +111 -0
  290. package/dist/src/product-loop/sprint-runner.js +559 -16
  291. package/dist/src/product-loop/types.d.ts +36 -5
  292. package/dist/src/providers/adapter.d.ts +1 -1
  293. package/dist/src/providers/adapter.js +3 -4
  294. package/dist/src/providers/auth/browser-flow.d.ts +1 -1
  295. package/dist/src/providers/auth/browser-flow.js +1 -1
  296. package/dist/src/providers/auth/openai-oauth.js +1 -1
  297. package/dist/src/providers/auth/registry.js +0 -34
  298. package/dist/src/providers/auth/token-store.js +4 -1
  299. package/dist/src/providers/auth/types.d.ts +1 -1
  300. package/dist/src/providers/auth/types.js +1 -1
  301. package/dist/src/providers/capabilities.d.ts +24 -5
  302. package/dist/src/providers/capabilities.js +42 -24
  303. package/dist/src/providers/endpoints.d.ts +2 -2
  304. package/dist/src/providers/endpoints.js +11 -10
  305. package/dist/src/providers/keychain.d.ts +1 -1
  306. package/dist/src/providers/keychain.js +7 -9
  307. package/dist/src/providers/mcp-vision-bridge.js +82 -172
  308. package/dist/src/providers/openai-compatible.js +8 -1
  309. package/dist/src/providers/pricing.d.ts +2 -2
  310. package/dist/src/providers/pricing.js +3 -13
  311. package/dist/src/providers/runtime.d.ts +27 -2
  312. package/dist/src/providers/runtime.js +78 -15
  313. package/dist/src/providers/strategies/base.strategy.d.ts +16 -0
  314. package/dist/src/providers/strategies/base.strategy.js +24 -1
  315. package/dist/src/providers/strategies/{siliconflow.strategy.d.ts → opencode-go.strategy.d.ts} +3 -3
  316. package/dist/src/providers/strategies/opencode-go.strategy.js +83 -0
  317. package/dist/src/providers/strategies/registry.js +4 -4
  318. package/dist/src/providers/strategies/thinking-mode.d.ts +109 -0
  319. package/dist/src/providers/strategies/thinking-mode.js +280 -1
  320. package/dist/src/providers/strategies/zai.strategy.d.ts +14 -0
  321. package/dist/src/providers/strategies/zai.strategy.js +44 -0
  322. package/dist/src/providers/types.d.ts +5 -6
  323. package/dist/src/providers/types.js +2 -2
  324. package/dist/src/providers/vision-backend.d.ts +47 -0
  325. package/dist/src/providers/vision-backend.js +258 -0
  326. package/dist/src/providers/vision-proxy.d.ts +22 -9
  327. package/dist/src/providers/vision-proxy.js +63 -132
  328. package/dist/src/providers/wire-debug.js +95 -0
  329. package/dist/src/reporter/index.js +1 -1
  330. package/dist/src/router/decide.d.ts +13 -0
  331. package/dist/src/router/decide.js +138 -36
  332. package/dist/src/router/peak-hour.d.ts +38 -0
  333. package/dist/src/router/peak-hour.js +107 -0
  334. package/dist/src/router/step-router.js +3 -2
  335. package/dist/src/router/warm.js +4 -5
  336. package/dist/src/scaffold/bb-ecosystem-apply.js +47 -47
  337. package/dist/src/scaffold/bb-quality-gate.js +5 -5
  338. package/dist/src/scaffold/continuation-prompt.d.ts +11 -0
  339. package/dist/src/scaffold/continuation-prompt.js +86 -60
  340. package/dist/src/scaffold/init-new.js +453 -453
  341. package/dist/src/scaffold/point-to-existing.d.ts +21 -0
  342. package/dist/src/scaffold/point-to-existing.js +25 -0
  343. package/dist/src/self-qa/agentic-loop.js +22 -22
  344. package/dist/src/{ui/state → state}/active-run.d.ts +19 -0
  345. package/dist/src/{ui/state → state}/active-run.js +21 -0
  346. package/dist/src/{ui/status-bar/store.d.ts → state/status-bar-store.d.ts} +4 -1
  347. package/dist/src/{ui/status-bar/store.js → state/status-bar-store.js} +12 -9
  348. package/dist/src/state/turn-trace.d.ts +43 -0
  349. package/dist/src/state/turn-trace.js +32 -0
  350. package/dist/src/storage/db.js +2 -1
  351. package/dist/src/storage/index.d.ts +1 -1
  352. package/dist/src/storage/index.js +1 -1
  353. package/dist/src/storage/interaction-log.d.ts +1 -1
  354. package/dist/src/storage/interaction-log.js +5 -5
  355. package/dist/src/storage/migrations.js +196 -126
  356. package/dist/src/storage/session-experience-store.js +4 -4
  357. package/dist/src/storage/sessions.d.ts +28 -10
  358. package/dist/src/storage/sessions.js +112 -55
  359. package/dist/src/storage/transcript-view.js +1 -1
  360. package/dist/src/storage/transcript.d.ts +51 -0
  361. package/dist/src/storage/transcript.js +383 -112
  362. package/dist/src/storage/usage.js +14 -14
  363. package/dist/src/storage/workspaces.js +12 -12
  364. package/dist/src/tools/file.d.ts +15 -0
  365. package/dist/src/tools/file.js +32 -0
  366. package/dist/src/tools/native-tools.js +5 -0
  367. package/dist/src/tools/registry.d.ts +3 -0
  368. package/dist/src/tools/registry.js +460 -22
  369. package/dist/src/tools/research.d.ts +29 -0
  370. package/dist/src/tools/research.js +233 -0
  371. package/dist/src/types/index.d.ts +118 -3
  372. package/dist/src/ui/app.js +0 -0
  373. package/dist/src/ui/cards/product-status-card.js +1 -1
  374. package/dist/src/ui/components/bubble-body-guard.d.ts +27 -0
  375. package/dist/src/ui/components/bubble-body-guard.js +50 -0
  376. package/dist/src/ui/components/context-rail.d.ts +26 -0
  377. package/dist/src/ui/components/context-rail.js +33 -0
  378. package/dist/src/ui/components/council-conclusion-card.d.ts +73 -0
  379. package/dist/src/ui/components/council-conclusion-card.js +420 -0
  380. package/dist/src/ui/components/council-debate-pill.d.ts +36 -0
  381. package/dist/src/ui/components/council-debate-pill.js +34 -0
  382. package/dist/src/ui/components/council-info-card.js +2 -2
  383. package/dist/src/ui/components/council-leader-bubble.d.ts +10 -3
  384. package/dist/src/ui/components/council-leader-bubble.js +21 -11
  385. package/dist/src/ui/components/council-message-bubble.d.ts +15 -2
  386. package/dist/src/ui/components/council-message-bubble.js +16 -15
  387. package/dist/src/ui/components/council-phase-timeline.d.ts +9 -1
  388. package/dist/src/ui/components/council-phase-timeline.js +49 -15
  389. package/dist/src/ui/components/council-placeholder-bubble.d.ts +16 -9
  390. package/dist/src/ui/components/council-placeholder-bubble.js +32 -29
  391. package/dist/src/ui/components/council-question-card.js +12 -12
  392. package/dist/src/ui/components/council-rail-rounds.d.ts +26 -0
  393. package/dist/src/ui/components/council-rail-rounds.js +57 -0
  394. package/dist/src/ui/components/council-round-group.d.ts +38 -0
  395. package/dist/src/ui/components/council-round-group.js +88 -0
  396. package/dist/src/ui/components/council-status-list.d.ts +3 -1
  397. package/dist/src/ui/components/council-status-list.js +36 -24
  398. package/dist/src/ui/components/council-synthesis-banner.d.ts +7 -2
  399. package/dist/src/ui/components/council-synthesis-banner.js +20 -5
  400. package/dist/src/ui/components/halt-recovery-card.js +9 -5
  401. package/dist/src/ui/components/jump-to-latest-pill.d.ts +11 -0
  402. package/dist/src/ui/components/jump-to-latest-pill.js +14 -0
  403. package/dist/src/ui/components/prompt-box.js +18 -16
  404. package/dist/src/ui/components/session-tree-card.d.ts +14 -0
  405. package/dist/src/ui/components/session-tree-card.js +46 -0
  406. package/dist/src/ui/components/slash-inline-menu.d.ts +12 -0
  407. package/dist/src/ui/components/slash-inline-menu.js +26 -5
  408. package/dist/src/ui/components/task-list-panel.d.ts +14 -1
  409. package/dist/src/ui/components/task-list-panel.js +22 -2
  410. package/dist/src/ui/containers/modals-layer.d.ts +2 -1
  411. package/dist/src/ui/hooks/use-session-picker.d.ts +3 -3
  412. package/dist/src/ui/mcp-modal.js +2 -4
  413. package/dist/src/ui/modals/api-key-modal.js +1 -1
  414. package/dist/src/ui/modals/connect-modal.js +4 -3
  415. package/dist/src/ui/modals/session-picker-modal.d.ts +2 -2
  416. package/dist/src/ui/modals/session-picker-modal.js +3 -5
  417. package/dist/src/ui/picker-providers.d.ts +1 -1
  418. package/dist/src/ui/picker-providers.js +1 -1
  419. package/dist/src/ui/primitives/index.d.ts +1 -0
  420. package/dist/src/ui/primitives/index.js +2 -0
  421. package/dist/src/ui/primitives/semantic-primitives.d.ts +76 -0
  422. package/dist/src/ui/primitives/semantic-primitives.js +81 -0
  423. package/dist/src/ui/slash/compact.js +5 -7
  424. package/dist/src/ui/slash/cost.js +1 -1
  425. package/dist/src/ui/slash/council-inspect.js +4 -4
  426. package/dist/src/ui/slash/council.js +19 -1
  427. package/dist/src/ui/slash/debug.d.ts +3 -31
  428. package/dist/src/ui/slash/debug.js +9 -20
  429. package/dist/src/ui/slash/ideal.d.ts +6 -2
  430. package/dist/src/ui/slash/ideal.js +97 -7
  431. package/dist/src/ui/slash/menu-items.d.ts +7 -0
  432. package/dist/src/ui/slash/menu-items.js +12 -18
  433. package/dist/src/ui/slash/registry.d.ts +2 -0
  434. package/dist/src/ui/slash/registry.js +4 -0
  435. package/dist/src/ui/status-bar/cache-hit.d.ts +6 -0
  436. package/dist/src/ui/status-bar/cache-hit.js +9 -0
  437. package/dist/src/ui/status-bar/index.d.ts +1 -1
  438. package/dist/src/ui/status-bar/index.js +7 -3
  439. package/dist/src/ui/status-bar/usd-meter.d.ts +5 -4
  440. package/dist/src/ui/status-bar/usd-meter.js +6 -4
  441. package/dist/src/ui/theme.d.ts +1 -0
  442. package/dist/src/ui/theme.js +2 -0
  443. package/dist/src/ui/types.d.ts +7 -0
  444. package/dist/src/ui/use-app-logic.js +0 -0
  445. package/dist/src/ui/utils/format.d.ts +14 -0
  446. package/dist/src/ui/utils/format.js +23 -3
  447. package/dist/src/usage/downgrade.js +2 -2
  448. package/dist/src/usage/product-ledger.js +2 -2
  449. package/dist/src/utils/clipboard-image.js +23 -23
  450. package/dist/src/utils/install-manager.js +14 -11
  451. package/dist/src/utils/logger.js +2 -2
  452. package/dist/src/utils/permission-mode.js +5 -3
  453. package/dist/src/utils/redactor.js +1 -1
  454. package/dist/src/utils/settings.d.ts +153 -5
  455. package/dist/src/utils/settings.js +233 -29
  456. package/dist/src/utils/side-question.js +2 -2
  457. package/dist/src/utils/skills.js +3 -3
  458. package/dist/src/utils/visible-retry.d.ts +11 -0
  459. package/dist/src/utils/visible-retry.js +10 -1
  460. package/dist/src/verify/entrypoint.d.ts +1 -1
  461. package/dist/src/verify/entrypoint.js +1 -1
  462. package/dist/src/verify/recipes.d.ts +13 -0
  463. package/dist/src/verify/recipes.js +15 -0
  464. package/package.json +135 -132
  465. package/dist/src/providers/auth/gcloud.d.ts +0 -28
  466. package/dist/src/providers/auth/gcloud.js +0 -102
  467. package/dist/src/providers/auth/gemini-oauth.d.ts +0 -82
  468. package/dist/src/providers/auth/gemini-oauth.js +0 -472
  469. package/dist/src/providers/gemini.d.ts +0 -11
  470. package/dist/src/providers/gemini.js +0 -45
  471. package/dist/src/providers/siliconflow-sse-repair.d.ts +0 -58
  472. package/dist/src/providers/siliconflow-sse-repair.js +0 -177
  473. package/dist/src/providers/strategies/google.strategy.d.ts +0 -22
  474. package/dist/src/providers/strategies/google.strategy.js +0 -174
  475. package/dist/src/providers/strategies/siliconflow.strategy.js +0 -29
  476. package/dist/src/ui/containers/chat-feed.d.ts +0 -40
  477. package/dist/src/ui/containers/chat-feed.js +0 -66
@@ -4,7 +4,11 @@
4
4
  * Serializes messages, extracts preserved blocks, compresses if over budget,
5
5
  * then restores preserved blocks into the output.
6
6
  */
7
+ import { generateText } from "ai";
7
8
  import { serializeConversation } from "../../orchestrator/compaction.js";
9
+ import { resolveModelRuntime, resolveTemperatureParam, } from "../../providers/runtime.js";
10
+ import { logger } from "../../utils/logger.js";
11
+ import { capCompactionInput } from "./input-guard.js";
8
12
  import { extractPreservedBlocks, restorePreservedBlocks } from "./preserve.js";
9
13
  /**
10
14
  * Compress chat messages within a token budget.
@@ -12,9 +16,9 @@ import { extractPreservedBlocks, restorePreservedBlocks } from "./preserve.js";
12
16
  * 1. Serialize messages via serializeConversation().
13
17
  * 2. Extract preserved blocks.
14
18
  * 3. If under budget, return as-is (with preserved blocks restored).
15
- * 4. If over budget, truncate/compress and restore preserved blocks.
19
+ * 4. If over budget, compress via LLM (if provider given) or truncate, and restore blocks.
16
20
  */
17
- export async function compressChat(messages, _systemPrompt, tokenBudget, _provider, _modelId) {
21
+ export async function compressChat(messages, _systemPrompt, tokenBudget, provider, modelId, customInstructions) {
18
22
  const serialized = serializeConversation(messages);
19
23
  const { cleaned, blocks } = extractPreservedBlocks(serialized);
20
24
  // Estimate tokens of cleaned text
@@ -28,16 +32,49 @@ export async function compressChat(messages, _systemPrompt, tokenBudget, _provid
28
32
  tokensAfter: Math.ceil(restored.length / 4),
29
33
  };
30
34
  }
31
- // Over budget — truncate to fit budget while keeping preserved blocks
32
35
  // Calculate space taken by preserved blocks
33
36
  const preservedTokens = blocks.reduce((sum, b) => sum + Math.ceil(b.content.length / 4), 0);
34
37
  const availableTokens = Math.max(0, tokenBudget - preservedTokens);
35
38
  const availableChars = availableTokens * 4;
36
- // Truncate the cleaned text to fit
37
- const truncated = cleaned.length > availableChars
38
- ? `${cleaned.slice(0, availableChars)}\n\n[... ${cleaned.length - availableChars} characters truncated]`
39
- : cleaned;
40
- const restored = restorePreservedBlocks(truncated, blocks);
39
+ let compressedContent = cleaned;
40
+ let usedLLM = false;
41
+ if (provider && modelId) {
42
+ try {
43
+ const runtime = resolveModelRuntime(provider, modelId);
44
+ const extraPrompt = customInstructions ? `\n\nUSER FOCUS/INSTRUCTIONS:\n${customInstructions}\n` : "";
45
+ // Guard the compaction INPUT against the model's own context window —
46
+ // compaction fires when history is large, which is exactly when the full
47
+ // serialized text can overflow the summarizer. Keep head + tail.
48
+ const guardedInput = capCompactionInput(cleaned, runtime.modelInfo?.contextWindow ?? 0);
49
+ const result = await generateText({
50
+ model: runtime.model,
51
+ system: "You are an AI context compaction agent. Your job is to heavily summarize a chat history. Keep the core outcomes, the final state, and the technical context. Remove verbose pleasantries, step-by-step thinking, and irrelevant intermediate steps. Do NOT wrap in markdown unless it's code.",
52
+ prompt: `The following conversation exceeds the token budget. Please summarize it concisely, maintaining the essence of what was discussed, what code was written, and what decisions were reached:${extraPrompt}\n\n${guardedInput}`,
53
+ ...resolveTemperatureParam(runtime, 0.1),
54
+ });
55
+ compressedContent = result.text.trim();
56
+ usedLLM = true;
57
+ }
58
+ catch (e) {
59
+ // Fall back to deterministic truncation below, but do NOT swallow the
60
+ // reason — a hidden compaction-LLM failure (auth, overflow, provider
61
+ // 400) is exactly what makes "why did compaction do nothing" undebuggable.
62
+ logger.error("orchestrator", "compressChat LLM summarize failed — falling back to truncation", {
63
+ modelId,
64
+ inputChars: cleaned.length,
65
+ message: e?.message,
66
+ stack: e?.stack?.split("\n").slice(0, 3),
67
+ });
68
+ }
69
+ }
70
+ if (!usedLLM) {
71
+ // Over budget — truncate to fit budget while keeping preserved blocks
72
+ compressedContent =
73
+ cleaned.length > availableChars
74
+ ? `${cleaned.slice(0, availableChars)}\n\n[... ${cleaned.length - availableChars} characters truncated]`
75
+ : cleaned;
76
+ }
77
+ const restored = restorePreservedBlocks(compressedContent, blocks);
41
78
  return {
42
79
  summary: restored,
43
80
  preservedBlocks: blocks,
@@ -5,7 +5,7 @@
5
5
  * Scans for "Decision:", "Decided:", "Fact:", "Constraint:" patterns
6
6
  * and content inside <!-- preserve --> blocks.
7
7
  */
8
- import type { ModelMessage } from "ai";
8
+ import { type ModelMessage } from "ai";
9
9
  export interface ExtractedDecisions {
10
10
  decisions: string[];
11
11
  facts: string[];
@@ -14,10 +14,7 @@ export interface ExtractedDecisions {
14
14
  /**
15
15
  * Extract decisions, facts, and constraints from messages.
16
16
  *
17
- * Scans serialized conversation text for:
18
- * - Lines matching "Decision:" or "Decided:" -> decisions
19
- * - Lines matching "Fact:" -> facts
20
- * - Lines matching "Constraint:" -> constraints
21
- * - All content inside <!-- preserve --> blocks -> decisions (verbatim)
17
+ * Scans serialized conversation text for explicit markers, but if provider
18
+ * and modelId are given, it asks the LLM to intelligently extract them.
22
19
  */
23
- export declare function extractDecisions(messages: ModelMessage[]): ExtractedDecisions;
20
+ export declare function extractDecisions(messages: ModelMessage[], provider?: unknown, modelId?: string, customInstructions?: string): Promise<ExtractedDecisions>;
@@ -5,7 +5,11 @@
5
5
  * Scans for "Decision:", "Decided:", "Fact:", "Constraint:" patterns
6
6
  * and content inside <!-- preserve --> blocks.
7
7
  */
8
+ import { generateText } from "ai";
8
9
  import { serializeConversation } from "../../orchestrator/compaction.js";
10
+ import { resolveModelRuntime, resolveTemperatureParam, } from "../../providers/runtime.js";
11
+ import { logger } from "../../utils/logger.js";
12
+ import { capCompactionInput } from "./input-guard.js";
9
13
  import { extractPreservedBlocks } from "./preserve.js";
10
14
  const DECISION_RE = /(?:Decision|Decided):\s*(.+)/gi;
11
15
  const FACT_RE = /Fact:\s*(.+)/gi;
@@ -23,13 +27,10 @@ function matchAll(text, re) {
23
27
  /**
24
28
  * Extract decisions, facts, and constraints from messages.
25
29
  *
26
- * Scans serialized conversation text for:
27
- * - Lines matching "Decision:" or "Decided:" -> decisions
28
- * - Lines matching "Fact:" -> facts
29
- * - Lines matching "Constraint:" -> constraints
30
- * - All content inside <!-- preserve --> blocks -> decisions (verbatim)
30
+ * Scans serialized conversation text for explicit markers, but if provider
31
+ * and modelId are given, it asks the LLM to intelligently extract them.
31
32
  */
32
- export function extractDecisions(messages) {
33
+ export async function extractDecisions(messages, provider, modelId, customInstructions) {
33
34
  if (messages.length === 0) {
34
35
  return { decisions: [], facts: [], constraints: [] };
35
36
  }
@@ -37,10 +38,49 @@ export function extractDecisions(messages) {
37
38
  // Extract preserved blocks as decisions
38
39
  const { blocks } = extractPreservedBlocks(serialized);
39
40
  const preservedDecisions = blocks.map((b) => b.content);
40
- // Pattern-match for explicit markers
41
- const decisions = [...matchAll(serialized, DECISION_RE), ...preservedDecisions];
42
- const facts = matchAll(serialized, FACT_RE);
43
- const constraints = matchAll(serialized, CONSTRAINT_RE);
41
+ const decisions = [];
42
+ const facts = [];
43
+ const constraints = [];
44
+ let usedLLM = false;
45
+ if (provider && modelId) {
46
+ try {
47
+ const runtime = resolveModelRuntime(provider, modelId);
48
+ const extraPrompt = customInstructions ? `\n\nUSER FOCUS/INSTRUCTIONS:\n${customInstructions}\n` : "";
49
+ // Guard input against the summarizer's context window (see input-guard).
50
+ const guardedInput = capCompactionInput(serialized, runtime.modelInfo?.contextWindow ?? 0);
51
+ const result = await generateText({
52
+ model: runtime.model,
53
+ system: 'You are an AI context compaction agent. Extract all core decisions, technical facts, and project constraints from this conversation. Return strict JSON with { "decisions": string[], "facts": string[], "constraints": string[] }.',
54
+ prompt: `Current conversation messages:\n\n${guardedInput}\n\nExtract decisions, facts, and constraints.${extraPrompt} Return strict JSON ONLY.`,
55
+ ...resolveTemperatureParam(runtime, 0.1),
56
+ });
57
+ const match = result.text.match(/\{[\s\S]*\}/);
58
+ if (match) {
59
+ const parsed = JSON.parse(match[0]);
60
+ if (Array.isArray(parsed.decisions))
61
+ decisions.push(...parsed.decisions);
62
+ if (Array.isArray(parsed.facts))
63
+ facts.push(...parsed.facts);
64
+ if (Array.isArray(parsed.constraints))
65
+ constraints.push(...parsed.constraints);
66
+ usedLLM = true;
67
+ }
68
+ }
69
+ catch (e) {
70
+ // Fall back to regex extraction, but log the reason — a swallowed failure
71
+ // here silently degrades /compact to marker-only extraction.
72
+ logger.error("orchestrator", "extractDecisions LLM failed — falling back to regex", {
73
+ modelId,
74
+ message: e?.message,
75
+ });
76
+ }
77
+ }
78
+ if (!usedLLM) {
79
+ decisions.push(...matchAll(serialized, DECISION_RE));
80
+ facts.push(...matchAll(serialized, FACT_RE));
81
+ constraints.push(...matchAll(serialized, CONSTRAINT_RE));
82
+ }
83
+ decisions.push(...preservedDecisions);
44
84
  return { decisions, facts, constraints };
45
85
  }
46
86
  //# sourceMappingURL=extract.js.map
@@ -6,6 +6,18 @@
6
6
  * Snapshot full chat to history/<timestamp>.md before compressing.
7
7
  */
8
8
  import type { ModelMessage } from "ai";
9
+ /**
10
+ * Anti-mù for the deliberate (/compact) path — parity with the auto/tool-loop
11
+ * compaction which persists every elided tool output via persistArtifact.
12
+ *
13
+ * deliberateCompact rewrites the whole history into a prose summary, so without
14
+ * this the model loses the ability to `ee_query "tool-artifact id=<id>"` a
15
+ * specific tool result after /compact. We record each tool result into the
16
+ * in-process + disk artifact cache (the tier ee_query reads FIRST, before EE),
17
+ * and fire a best-effort EE extract so cross-session rehydrate also survives.
18
+ * Fail-open: a cache/EE hiccup never blocks the compaction.
19
+ */
20
+ export declare function recordToolArtifactsForRehydrate(messages: ModelMessage[], projectPath: string): number;
9
21
  export interface CompactionResult {
10
22
  decisionsExtracted: number;
11
23
  tokensBeforeCompress: number;
@@ -21,4 +33,4 @@ export interface CompactionResult {
21
33
  * 3. Pass 2: compressChat -> compressed output
22
34
  * 4. Return metrics
23
35
  */
24
- export declare function deliberateCompact(flowDir: string, messages: ModelMessage[], systemPrompt: string, tokenBudget: number, provider?: unknown, modelId?: string): Promise<CompactionResult>;
36
+ export declare function deliberateCompact(flowDir: string, messages: ModelMessage[], systemPrompt: string, tokenBudget: number, provider?: unknown, modelId?: string, customInstructions?: string): Promise<CompactionResult>;
@@ -7,11 +7,74 @@
7
7
  */
8
8
  import { promises as fs } from "node:fs";
9
9
  import * as path from "node:path";
10
+ import { recordArtifact } from "../../ee/artifact-cache.js";
11
+ import { getDefaultEEClient } from "../../ee/intercept.js";
10
12
  import { estimateConversationTokens, serializeConversation } from "../../orchestrator/compaction.js";
11
13
  import { atomicWriteText } from "../../storage/atomic-io.js";
14
+ import { logger } from "../../utils/logger.js";
12
15
  import { readArtifact, writeArtifact } from "../artifact-io.js";
13
16
  import { compressChat } from "./compress.js";
14
17
  import { extractDecisions } from "./extract.js";
18
+ /**
19
+ * Anti-mù for the deliberate (/compact) path — parity with the auto/tool-loop
20
+ * compaction which persists every elided tool output via persistArtifact.
21
+ *
22
+ * deliberateCompact rewrites the whole history into a prose summary, so without
23
+ * this the model loses the ability to `ee_query "tool-artifact id=<id>"` a
24
+ * specific tool result after /compact. We record each tool result into the
25
+ * in-process + disk artifact cache (the tier ee_query reads FIRST, before EE),
26
+ * and fire a best-effort EE extract so cross-session rehydrate also survives.
27
+ * Fail-open: a cache/EE hiccup never blocks the compaction.
28
+ */
29
+ export function recordToolArtifactsForRehydrate(messages, projectPath) {
30
+ let recorded = 0;
31
+ for (const msg of messages) {
32
+ if (msg.role !== "tool" || !Array.isArray(msg.content))
33
+ continue;
34
+ for (const part of msg.content) {
35
+ if (part?.type !== "tool-result")
36
+ continue;
37
+ const toolCallId = typeof part.toolCallId === "string" ? part.toolCallId : "";
38
+ if (!toolCallId)
39
+ continue;
40
+ const toolName = typeof part.toolName === "string" ? part.toolName : "";
41
+ // AI SDK v5 tool-result payloads live under `output` (typed) or `result`.
42
+ const payload = part.output ?? part.result;
43
+ const content = typeof payload === "string"
44
+ ? payload
45
+ : payload == null
46
+ ? ""
47
+ : (() => {
48
+ try {
49
+ return JSON.stringify(payload);
50
+ }
51
+ catch {
52
+ return String(payload);
53
+ }
54
+ })();
55
+ if (!content)
56
+ continue;
57
+ try {
58
+ recordArtifact(toolCallId, toolName, content);
59
+ recorded++;
60
+ getDefaultEEClient()
61
+ .extract({
62
+ transcript: content.slice(0, 8000),
63
+ projectPath,
64
+ meta: { source: "tool-artifact", toolCallId, toolName, reason: "deliberate-compact" },
65
+ }, AbortSignal.timeout(700))
66
+ .catch(() => { });
67
+ }
68
+ catch (err) {
69
+ logger.error("orchestrator", "deliberate-compact artifact record failed", {
70
+ toolCallId,
71
+ message: err?.message,
72
+ });
73
+ }
74
+ }
75
+ }
76
+ return recorded;
77
+ }
15
78
  /**
16
79
  * Orchestrate two-pass deliberate compaction.
17
80
  *
@@ -20,9 +83,13 @@ import { extractDecisions } from "./extract.js";
20
83
  * 3. Pass 2: compressChat -> compressed output
21
84
  * 4. Return metrics
22
85
  */
23
- export async function deliberateCompact(flowDir, messages, systemPrompt, tokenBudget, provider, modelId) {
86
+ export async function deliberateCompact(flowDir, messages, systemPrompt, tokenBudget, provider, modelId, customInstructions) {
87
+ // Anti-mù parity: persist every tool result to the artifact cache (+ EE)
88
+ // BEFORE we summarize the history away, so the model can still rehydrate a
89
+ // specific tool output via ee_query "tool-artifact id=<id>" after /compact.
90
+ recordToolArtifactsForRehydrate(messages, flowDir);
24
91
  // Pass 1: Extract decisions/facts/constraints
25
- const extracted = extractDecisions(messages);
92
+ const extracted = await extractDecisions(messages, provider, modelId, customInstructions);
26
93
  const totalExtracted = extracted.decisions.length + extracted.facts.length + extracted.constraints.length;
27
94
  // Append to decisions.md
28
95
  if (totalExtracted > 0) {
@@ -55,7 +122,7 @@ export async function deliberateCompact(flowDir, messages, systemPrompt, tokenBu
55
122
  // Token estimation before
56
123
  const tokensBefore = estimateConversationTokens(systemPrompt, messages);
57
124
  // Pass 2: Compress
58
- const compressed = await compressChat(messages, systemPrompt, tokenBudget, provider, modelId);
125
+ const compressed = await compressChat(messages, systemPrompt, tokenBudget, provider, modelId, customInstructions);
59
126
  return {
60
127
  decisionsExtracted: totalExtracted,
61
128
  tokensBeforeCompress: tokensBefore,
@@ -0,0 +1,24 @@
1
+ /**
2
+ * src/flow/compaction/input-guard.ts
3
+ *
4
+ * Guard the INPUT of the deliberate-compaction LLM calls (extractDecisions +
5
+ * compressChat) against context-window overflow.
6
+ *
7
+ * Compaction fires precisely when a conversation has grown large — which is
8
+ * exactly when the full serialized history can EXCEED the compaction model's
9
+ * own context window. Both passes previously sent the whole serialized text as
10
+ * a single prompt with no bound, so on a very long session the summarizing call
11
+ * would fail (or the provider would hard-truncate the tail, dropping the most
12
+ * recent — most relevant — context) and fall back to a dumb truncation.
13
+ *
14
+ * This keeps the HEAD (task setup / early decisions) and the TAIL (most recent
15
+ * work) and elides the middle, so the summarizer always gets a coherent,
16
+ * in-window view of both ends. Pure + dependency-free.
17
+ */
18
+ /**
19
+ * Cap `text` to a safe char budget derived from the compaction model's context
20
+ * window. Returns the text unchanged when it already fits (or the window is
21
+ * unknown and the text is under the floor). Otherwise keeps head+tail and marks
22
+ * the elided middle.
23
+ */
24
+ export declare function capCompactionInput(text: string, contextWindowTokens: number): string;
@@ -0,0 +1,43 @@
1
+ /**
2
+ * src/flow/compaction/input-guard.ts
3
+ *
4
+ * Guard the INPUT of the deliberate-compaction LLM calls (extractDecisions +
5
+ * compressChat) against context-window overflow.
6
+ *
7
+ * Compaction fires precisely when a conversation has grown large — which is
8
+ * exactly when the full serialized history can EXCEED the compaction model's
9
+ * own context window. Both passes previously sent the whole serialized text as
10
+ * a single prompt with no bound, so on a very long session the summarizing call
11
+ * would fail (or the provider would hard-truncate the tail, dropping the most
12
+ * recent — most relevant — context) and fall back to a dumb truncation.
13
+ *
14
+ * This keeps the HEAD (task setup / early decisions) and the TAIL (most recent
15
+ * work) and elides the middle, so the summarizer always gets a coherent,
16
+ * in-window view of both ends. Pure + dependency-free.
17
+ */
18
+ /** Fraction of the model window we allow the compaction INPUT to occupy. */
19
+ const INPUT_WINDOW_FRACTION = 0.55;
20
+ /** Chars-per-token estimate (matches the rest of the compaction code). */
21
+ const CHARS_PER_TOKEN = 4;
22
+ /** Absolute floor so a tiny/unknown window never collapses the input to nothing. */
23
+ const MIN_INPUT_CHARS = 24_000;
24
+ /**
25
+ * Cap `text` to a safe char budget derived from the compaction model's context
26
+ * window. Returns the text unchanged when it already fits (or the window is
27
+ * unknown and the text is under the floor). Otherwise keeps head+tail and marks
28
+ * the elided middle.
29
+ */
30
+ export function capCompactionInput(text, contextWindowTokens) {
31
+ const windowBudget = contextWindowTokens > 0 ? Math.floor(contextWindowTokens * CHARS_PER_TOKEN * INPUT_WINDOW_FRACTION) : 0;
32
+ const budget = Math.max(MIN_INPUT_CHARS, windowBudget);
33
+ if (text.length <= budget)
34
+ return text;
35
+ // Split the budget between head and tail, reserving room for the marker.
36
+ const headChars = Math.floor(budget * 0.5);
37
+ const tailChars = budget - headChars;
38
+ const head = text.slice(0, headChars);
39
+ const tail = text.slice(text.length - tailChars);
40
+ const elided = text.length - headChars - tailChars;
41
+ return `${head}\n\n[... ${elided} characters of the middle of the conversation elided to fit the compaction model's context window; the head (task setup) and tail (most recent work) are preserved ...]\n\n${tail}`;
42
+ }
43
+ //# sourceMappingURL=input-guard.js.map
@@ -0,0 +1,36 @@
1
+ /**
2
+ * Fold `.planning/` into `.muonroi-flow/planning/` — net-new, non-destructive
3
+ * consolidation migration (Sprint-2 Part A, staged per REV-3 Kill B).
4
+ *
5
+ * WHY staged / copy-only:
6
+ * GSD phases are still CREATED by the external `gsd-tools.cjs` subprocess,
7
+ * which writes to `.planning/` (hardcoded). Until that writer is removed
8
+ * (Part B — deferred), `.planning/` must remain the live tree. So this
9
+ * migration COPIES `.planning/` into the consolidated location and NEVER
10
+ * deletes the original — the read layer (`paths.ts::planningRoot`) keeps
11
+ * preferring `.planning/` while it exists, so there is zero desync risk.
12
+ * Once Part B stops writing `.planning/`, the folded tree becomes the live
13
+ * source transparently via the same read fallback.
14
+ *
15
+ * Guarantees:
16
+ * - Idempotent: guarded by a `.migrated` marker (NOT by directory existence —
17
+ * an empty `.muonroi-flow/planning/` must not make the fold skip forever;
18
+ * see REV-2 Kill #2).
19
+ * - Non-destructive: source `.planning/` is left untouched.
20
+ * - Byte-preserving: every copied file is asserted equal in size to its source.
21
+ */
22
+ export interface FoldResult {
23
+ /** True when a fold copy was performed this call. */
24
+ migrated: boolean;
25
+ /** Reason a fold was skipped (marker present / no source). */
26
+ skipReason?: "already-migrated" | "no-source";
27
+ /** Number of files copied. */
28
+ filesCopied: number;
29
+ /** Absolute path to the folded planning root. */
30
+ foldedRoot: string;
31
+ }
32
+ /**
33
+ * Perform the fold. Safe to call repeatedly; returns `{migrated:false}` when the
34
+ * marker is already present or there is no `.planning/` to fold.
35
+ */
36
+ export declare function foldPlanningIntoFlow(cwd: string): Promise<FoldResult>;
@@ -0,0 +1,83 @@
1
+ /**
2
+ * Fold `.planning/` into `.muonroi-flow/planning/` — net-new, non-destructive
3
+ * consolidation migration (Sprint-2 Part A, staged per REV-3 Kill B).
4
+ *
5
+ * WHY staged / copy-only:
6
+ * GSD phases are still CREATED by the external `gsd-tools.cjs` subprocess,
7
+ * which writes to `.planning/` (hardcoded). Until that writer is removed
8
+ * (Part B — deferred), `.planning/` must remain the live tree. So this
9
+ * migration COPIES `.planning/` into the consolidated location and NEVER
10
+ * deletes the original — the read layer (`paths.ts::planningRoot`) keeps
11
+ * preferring `.planning/` while it exists, so there is zero desync risk.
12
+ * Once Part B stops writing `.planning/`, the folded tree becomes the live
13
+ * source transparently via the same read fallback.
14
+ *
15
+ * Guarantees:
16
+ * - Idempotent: guarded by a `.migrated` marker (NOT by directory existence —
17
+ * an empty `.muonroi-flow/planning/` must not make the fold skip forever;
18
+ * see REV-2 Kill #2).
19
+ * - Non-destructive: source `.planning/` is left untouched.
20
+ * - Byte-preserving: every copied file is asserted equal in size to its source.
21
+ */
22
+ import { promises as fs } from "node:fs";
23
+ import * as path from "node:path";
24
+ const FLOW_DIR = ".muonroi-flow";
25
+ const PLANNING_DIR = ".planning";
26
+ const FOLDED_SUBDIR = "planning";
27
+ const MARKER = ".migrated";
28
+ /** Recursively copy a directory, asserting byte-size preservation per file. */
29
+ async function copyTreePreserving(src, dest) {
30
+ let copied = 0;
31
+ const entries = await fs.readdir(src, { withFileTypes: true });
32
+ await fs.mkdir(dest, { recursive: true });
33
+ for (const entry of entries) {
34
+ const from = path.join(src, entry.name);
35
+ const to = path.join(dest, entry.name);
36
+ if (entry.isDirectory()) {
37
+ copied += await copyTreePreserving(from, to);
38
+ }
39
+ else if (entry.isFile()) {
40
+ await fs.copyFile(from, to);
41
+ const [srcStat, destStat] = await Promise.all([fs.stat(from), fs.stat(to)]);
42
+ if (srcStat.size !== destStat.size) {
43
+ throw new Error(`fold-planning: byte mismatch copying ${from} (${srcStat.size} != ${destStat.size})`);
44
+ }
45
+ copied += 1;
46
+ }
47
+ // Symlinks / other node types are intentionally skipped — .planning holds
48
+ // only regular files and dirs; a stray symlink is not worth following.
49
+ }
50
+ return copied;
51
+ }
52
+ /**
53
+ * Perform the fold. Safe to call repeatedly; returns `{migrated:false}` when the
54
+ * marker is already present or there is no `.planning/` to fold.
55
+ */
56
+ export async function foldPlanningIntoFlow(cwd) {
57
+ const foldedRoot = path.join(cwd, FLOW_DIR, FOLDED_SUBDIR);
58
+ const markerPath = path.join(foldedRoot, MARKER);
59
+ // Marker guard — idempotent regardless of whether the folded dir is empty.
60
+ try {
61
+ await fs.access(markerPath);
62
+ return { migrated: false, skipReason: "already-migrated", filesCopied: 0, foldedRoot };
63
+ }
64
+ catch {
65
+ /* marker absent → proceed */
66
+ }
67
+ const source = path.join(cwd, PLANNING_DIR);
68
+ try {
69
+ const st = await fs.stat(source);
70
+ if (!st.isDirectory()) {
71
+ return { migrated: false, skipReason: "no-source", filesCopied: 0, foldedRoot };
72
+ }
73
+ }
74
+ catch {
75
+ return { migrated: false, skipReason: "no-source", filesCopied: 0, foldedRoot };
76
+ }
77
+ const filesCopied = await copyTreePreserving(source, foldedRoot);
78
+ // Stamp the marker LAST so a crash mid-copy leaves no false "migrated" flag —
79
+ // the next call re-copies (copyFile overwrites, byte-assert still holds).
80
+ await fs.writeFile(markerPath, JSON.stringify({ migratedFrom: PLANNING_DIR, filesCopied, note: "copy-only; original left in place" }, null, 2), "utf8");
81
+ return { migrated: true, filesCopied, foldedRoot };
82
+ }
83
+ //# sourceMappingURL=fold-planning.js.map
@@ -0,0 +1,146 @@
1
+ /**
2
+ * Milestone → Phase → Run hierarchy for the Product Ideal Loop.
3
+ *
4
+ * Sprint-2 Part A (full plan, item 2 of the deferred list). Built as an ADDITIVE
5
+ * INDEX LAYER on top of `runs/<runId>/` (per REV-3 Kill B / REV-2 Kill #7): it
6
+ * groups runs under phases under milestones for navigation and cross-run memory,
7
+ * but does NOT reroute the numeric ROADMAP phases that phase-sync depends on. A
8
+ * phase here simply *references* the run IDs executed under it; the run
9
+ * artifacts remain the source of truth for sprint/verify state.
10
+ *
11
+ * .muonroi-flow/milestones/<mid>/milestone.json ← canonical record (read)
12
+ * .muonroi-flow/milestones/<mid>/milestone.md ← human-reviewable render
13
+ * .muonroi-flow/milestones/<mid>/phases/<pid>/phase.json
14
+ * .muonroi-flow/milestones/<mid>/phases/<pid>/phase.md
15
+ *
16
+ * The active milestone/phase pointers live in the top-level `state.md`
17
+ * ("Active Milestone" / "Active Phase" sections), alongside "Active Run".
18
+ *
19
+ * Records are JSON for reliable machine reads; the paired `.md` is a rendered
20
+ * summary only (never parsed back). Writes are atomic. Reads are tolerant: a
21
+ * missing/corrupt record returns null, never throws.
22
+ */
23
+ export interface MilestoneRecord {
24
+ /** Sortable slug id, e.g. "m01-native-state". */
25
+ id: string;
26
+ /** Human title. */
27
+ title: string;
28
+ /** One-line goal / outcome the milestone delivers. */
29
+ goal: string;
30
+ /** Ordinal (1-based) — mirrors the numeric prefix in the id for stable sort. */
31
+ ordinal: number;
32
+ /** lifecycle status. */
33
+ status: "active" | "done" | "archived";
34
+ /** ISO creation timestamp. */
35
+ createdAt: string;
36
+ /** ISO last-update timestamp. */
37
+ updatedAt: string;
38
+ }
39
+ export interface PhaseRecord {
40
+ /** Sortable slug id, e.g. "p01-scoping". */
41
+ id: string;
42
+ /** Parent milestone id. */
43
+ milestoneId: string;
44
+ /** Human title. */
45
+ title: string;
46
+ /** One-line goal. */
47
+ goal: string;
48
+ /** Ordinal (1-based) within the milestone. */
49
+ ordinal: number;
50
+ /** lifecycle status. */
51
+ status: "active" | "done" | "archived";
52
+ /** Run IDs executed under this phase (the index link; runs stay canonical). */
53
+ runIds: string[];
54
+ /** ISO creation timestamp. */
55
+ createdAt: string;
56
+ /** ISO last-update timestamp. */
57
+ updatedAt: string;
58
+ }
59
+ export declare const MILESTONES_DIR = "milestones";
60
+ /** List all milestones, sorted by ordinal ascending. */
61
+ export declare function listMilestones(flowDir: string): Promise<MilestoneRecord[]>;
62
+ export declare function loadMilestone(flowDir: string, milestoneId: string): Promise<MilestoneRecord | null>;
63
+ /**
64
+ * Create a milestone. `nowIso` is injected (never Date.now here) so callers
65
+ * control the clock and tests stay deterministic. Ordinal is next-highest+1.
66
+ */
67
+ export declare function createMilestone(flowDir: string, input: {
68
+ title: string;
69
+ goal?: string;
70
+ }, nowIso: string): Promise<MilestoneRecord>;
71
+ export declare function updateMilestone(flowDir: string, milestoneId: string, patch: Partial<Pick<MilestoneRecord, "title" | "goal" | "status">>, nowIso: string): Promise<MilestoneRecord | null>;
72
+ /** List phases under a milestone, sorted by ordinal ascending. */
73
+ export declare function listPhases(flowDir: string, milestoneId: string): Promise<PhaseRecord[]>;
74
+ export declare function loadPhase(flowDir: string, milestoneId: string, phaseId: string): Promise<PhaseRecord | null>;
75
+ export declare function createPhase(flowDir: string, milestoneId: string, input: {
76
+ title: string;
77
+ goal?: string;
78
+ runId?: string;
79
+ }, nowIso: string): Promise<PhaseRecord>;
80
+ export declare function updatePhase(flowDir: string, milestoneId: string, phaseId: string, patch: Partial<Pick<PhaseRecord, "title" | "goal" | "status">>, nowIso: string): Promise<PhaseRecord | null>;
81
+ /** Link a run to a phase (idempotent — no duplicate run ids). */
82
+ export declare function attachRunToPhase(flowDir: string, milestoneId: string, phaseId: string, runId: string, nowIso: string): Promise<PhaseRecord | null>;
83
+ /**
84
+ * Find the milestone+phase a run is already indexed under, scanning every
85
+ * milestone. Returns null when the run is not yet linked anywhere. Used to keep
86
+ * scoping wiring idempotent across `/ideal resume` (the scoping stage re-runs).
87
+ */
88
+ export declare function findPhaseForRun(flowDir: string, runId: string): Promise<{
89
+ milestoneId: string;
90
+ phaseId: string;
91
+ } | null>;
92
+ /**
93
+ * Idempotently place a run in the hierarchy and mark it active. First call for a
94
+ * run creates (or reuses the active) milestone, opens a phase for the run, links
95
+ * it, and points the active-milestone/active-phase pointers at it. Subsequent
96
+ * calls (resume) are no-ops that just re-assert the pointers.
97
+ *
98
+ * The milestone groups an idea/product; the phase is one scoped iteration under
99
+ * it. This is purely an INDEX over `runs/<runId>/` — it never moves or rewrites
100
+ * run artifacts, and the numeric ROADMAP phases that phase-sync reads are
101
+ * untouched.
102
+ */
103
+ export declare function ensureRunScoped(flowDir: string, input: {
104
+ runId: string;
105
+ milestoneTitle: string;
106
+ milestoneGoal?: string;
107
+ phaseTitle: string;
108
+ phaseGoal?: string;
109
+ }, nowIso: string): Promise<{
110
+ milestoneId: string;
111
+ phaseId: string;
112
+ }>;
113
+ /**
114
+ * One-time backfill: index any `runs/<id>/` not yet linked to a phase under a
115
+ * synthetic `m00-legacy` milestone (one phase per orphan run). Idempotent — runs
116
+ * already indexed are skipped, and re-running adds only newly-orphaned runs.
117
+ * Returns the number of runs newly indexed.
118
+ *
119
+ * `m00` (ordinal 0) sorts before any real milestone so legacy work stays visible
120
+ * but out of the way. The clock is injected for deterministic tests.
121
+ */
122
+ export declare function migrateLegacyRuns(flowDir: string, nowIso: string): Promise<number>;
123
+ export interface ActivePointer {
124
+ milestoneId: string | null;
125
+ phaseId: string | null;
126
+ }
127
+ /**
128
+ * F8 — the active milestone/phase are DERIVED from the single canonical focus,
129
+ * the active run, via the hierarchy index; they are NOT separately persisted.
130
+ *
131
+ * Previously `state.md` carried independent `Active Run` (set for chat-runs) and
132
+ * `Active Milestone`/`Active Phase` (set by `ensureRunScoped` for product-runs)
133
+ * pointers that routinely drifted out of sync — `/ideal` never updated `Active
134
+ * Run`, so it pointed at a stale skeleton run while the milestone/phase pointed
135
+ * at the product run. Council decision (5/5): collapse to one truth. Whatever run
136
+ * is active, its phase (and that phase's milestone) is the active one; a
137
+ * chat/skeleton run that was never indexed resolves to nulls.
138
+ */
139
+ export declare function getActivePointer(flowDir: string): Promise<ActivePointer>;
140
+ /**
141
+ * Blank the legacy `Active Milestone`/`Active Phase` sections if an old
142
+ * `state.md` still carries them, so a stale value can never be mistaken for the
143
+ * (now derived) truth. One-time, idempotent; no-op when the sections are absent
144
+ * or already empty. Legacy files are otherwise read-as-junk — never migrated.
145
+ */
146
+ export declare function clearLegacyActivePointerSections(flowDir: string): Promise<void>;