muonroi-cli 1.8.4 → 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 (458) hide show
  1. package/LICENSE +17 -5
  2. package/dist/packages/agent-harness-core/src/driver.d.ts +27 -1
  3. package/dist/packages/agent-harness-core/src/driver.js +46 -0
  4. package/dist/packages/agent-harness-core/src/event-tee.d.ts +48 -0
  5. package/dist/packages/agent-harness-core/src/event-tee.js +77 -0
  6. package/dist/packages/agent-harness-core/src/mcp-server.d.ts +11 -0
  7. package/dist/packages/agent-harness-core/src/mcp-server.js +87 -15
  8. package/dist/packages/agent-harness-core/src/protocol.d.ts +66 -2
  9. package/dist/packages/agent-harness-core/src/protocol.js +15 -0
  10. package/dist/packages/agent-harness-core/src/visual-quality.d.ts +58 -0
  11. package/dist/packages/agent-harness-core/src/visual-quality.js +141 -0
  12. package/dist/packages/agent-harness-opentui/src/agent-mode.d.ts +6 -0
  13. package/dist/packages/agent-harness-opentui/src/agent-mode.js +14 -1
  14. package/dist/packages/agent-harness-opentui/src/input-bridge.d.ts +2 -10
  15. package/dist/packages/agent-harness-opentui/src/input-bridge.js +103 -16
  16. package/dist/packages/agent-harness-opentui/src/install.d.ts +8 -0
  17. package/dist/packages/agent-harness-opentui/src/install.js +10 -0
  18. package/dist/packages/agent-harness-opentui/src/semantic.js +12 -10
  19. package/dist/packages/agent-harness-opentui/src/visual-capture.d.ts +56 -0
  20. package/dist/packages/agent-harness-opentui/src/visual-capture.js +103 -0
  21. package/dist/src/agent-harness/mock-model.d.ts +28 -0
  22. package/dist/src/agent-harness/mock-model.js +63 -1
  23. package/dist/src/agent-harness/test-spawn.js +31 -0
  24. package/dist/src/cli/config/screen-providers.js +1 -1
  25. package/dist/src/cli/cost-forensics.d.ts +10 -0
  26. package/dist/src/cli/cost-forensics.js +18 -3
  27. package/dist/src/cli/keys-bundle.d.ts +1 -1
  28. package/dist/src/cli/keys-bundle.js +1 -1
  29. package/dist/src/cli/keys.d.ts +2 -2
  30. package/dist/src/cli/keys.js +19 -81
  31. package/dist/src/council/clarifier.d.ts +28 -2
  32. package/dist/src/council/clarifier.js +81 -15
  33. package/dist/src/council/context.js +49 -15
  34. package/dist/src/council/debate-checkpoint.d.ts +129 -0
  35. package/dist/src/council/debate-checkpoint.js +176 -0
  36. package/dist/src/council/debate-planner.js +51 -3
  37. package/dist/src/council/debate-summary.d.ts +25 -0
  38. package/dist/src/council/debate-summary.js +85 -0
  39. package/dist/src/council/debate.d.ts +169 -2
  40. package/dist/src/council/debate.js +1210 -134
  41. package/dist/src/council/index.d.ts +85 -1
  42. package/dist/src/council/index.js +634 -196
  43. package/dist/src/council/leader.d.ts +26 -0
  44. package/dist/src/council/leader.js +150 -9
  45. package/dist/src/council/llm.d.ts +32 -0
  46. package/dist/src/council/llm.js +231 -38
  47. package/dist/src/council/panel-select.d.ts +30 -0
  48. package/dist/src/council/panel-select.js +72 -0
  49. package/dist/src/council/planner.js +23 -0
  50. package/dist/src/council/preflight.d.ts +7 -0
  51. package/dist/src/council/preflight.js +14 -2
  52. package/dist/src/council/prompts.d.ts +30 -3
  53. package/dist/src/council/prompts.js +234 -64
  54. package/dist/src/council/stance-recall.d.ts +42 -0
  55. package/dist/src/council/stance-recall.js +57 -0
  56. package/dist/src/council/strip-think.d.ts +17 -0
  57. package/dist/src/council/strip-think.js +33 -0
  58. package/dist/src/council/types.d.ts +128 -0
  59. package/dist/src/ee/artifact-cache.d.ts +16 -0
  60. package/dist/src/ee/artifact-cache.js +32 -0
  61. package/dist/src/ee/auth.d.ts +1 -0
  62. package/dist/src/ee/auth.js +15 -2
  63. package/dist/src/ee/bridge.d.ts +10 -0
  64. package/dist/src/ee/bridge.js +58 -0
  65. package/dist/src/ee/client.js +81 -18
  66. package/dist/src/ee/export-transcripts.d.ts +1 -0
  67. package/dist/src/ee/export-transcripts.js +8 -10
  68. package/dist/src/ee/extract-session.js +29 -0
  69. package/dist/src/ee/extract-style.d.ts +58 -0
  70. package/dist/src/ee/extract-style.js +270 -0
  71. package/dist/src/ee/recall-ledger.d.ts +9 -0
  72. package/dist/src/ee/recall-ledger.js +3 -0
  73. package/dist/src/ee/scope.d.ts +1 -0
  74. package/dist/src/ee/scope.js +26 -1
  75. package/dist/src/ee/search.d.ts +7 -0
  76. package/dist/src/ee/search.js +24 -0
  77. package/dist/src/ee/transcript-emit.js +2 -0
  78. package/dist/src/ee/types.d.ts +22 -0
  79. package/dist/src/ee/who-am-i-brain.d.ts +35 -0
  80. package/dist/src/ee/who-am-i-brain.js +220 -0
  81. package/dist/src/ee/who-am-i.d.ts +10 -3
  82. package/dist/src/ee/who-am-i.js +12 -0
  83. package/dist/src/ee/workflow-event.d.ts +48 -0
  84. package/dist/src/ee/workflow-event.js +81 -0
  85. package/dist/src/flow/compaction/compress.d.ts +3 -3
  86. package/dist/src/flow/compaction/compress.js +45 -8
  87. package/dist/src/flow/compaction/extract.d.ts +4 -7
  88. package/dist/src/flow/compaction/extract.js +50 -10
  89. package/dist/src/flow/compaction/index.d.ts +13 -1
  90. package/dist/src/flow/compaction/index.js +70 -3
  91. package/dist/src/flow/compaction/input-guard.d.ts +24 -0
  92. package/dist/src/flow/compaction/input-guard.js +43 -0
  93. package/dist/src/flow/fold-planning.d.ts +36 -0
  94. package/dist/src/flow/fold-planning.js +83 -0
  95. package/dist/src/flow/hierarchy.d.ts +146 -0
  96. package/dist/src/flow/hierarchy.js +427 -0
  97. package/dist/src/flow/index.d.ts +1 -0
  98. package/dist/src/flow/index.js +2 -0
  99. package/dist/src/flow/run-artifacts.d.ts +102 -0
  100. package/dist/src/flow/run-artifacts.js +208 -0
  101. package/dist/src/generated/version.d.ts +1 -1
  102. package/dist/src/generated/version.js +1 -1
  103. package/dist/src/gsd/assessment-schema.d.ts +44 -0
  104. package/dist/src/gsd/assessment-schema.js +134 -0
  105. package/dist/src/gsd/capability-registry.d.ts +45 -0
  106. package/dist/src/gsd/capability-registry.js +337 -0
  107. package/dist/src/gsd/complexity-assessor.d.ts +39 -0
  108. package/dist/src/gsd/complexity-assessor.js +152 -0
  109. package/dist/src/gsd/config-bridge.d.ts +7 -0
  110. package/dist/src/gsd/config-bridge.js +114 -0
  111. package/dist/src/gsd/config-loader.d.ts +27 -0
  112. package/dist/src/gsd/config-loader.js +50 -0
  113. package/dist/src/gsd/council-context.d.ts +44 -0
  114. package/dist/src/gsd/council-context.js +114 -0
  115. package/dist/src/gsd/ee-closure.d.ts +28 -0
  116. package/dist/src/gsd/ee-closure.js +49 -0
  117. package/dist/src/gsd/flags.d.ts +55 -0
  118. package/dist/src/gsd/flags.js +83 -0
  119. package/dist/src/gsd/gsd-dispatch.d.ts +58 -0
  120. package/dist/src/gsd/gsd-dispatch.js +131 -0
  121. package/dist/src/gsd/gsd-runtime.d.ts +22 -0
  122. package/dist/src/gsd/gsd-runtime.js +37 -0
  123. package/dist/src/gsd/host-adapter.d.ts +11 -0
  124. package/dist/src/gsd/host-adapter.js +29 -0
  125. package/dist/src/gsd/index.d.ts +24 -1
  126. package/dist/src/gsd/index.js +27 -0
  127. package/dist/src/gsd/loop-host-contract.d.ts +21 -0
  128. package/dist/src/gsd/loop-host-contract.js +39 -0
  129. package/dist/src/gsd/loop-host.d.ts +69 -0
  130. package/dist/src/gsd/loop-host.js +245 -0
  131. package/dist/src/gsd/loop-resolver.d.ts +36 -0
  132. package/dist/src/gsd/loop-resolver.js +79 -0
  133. package/dist/src/gsd/model-tier.d.ts +13 -0
  134. package/dist/src/gsd/model-tier.js +45 -0
  135. package/dist/src/gsd/mutation-gate.d.ts +16 -0
  136. package/dist/src/gsd/mutation-gate.js +41 -0
  137. package/dist/src/gsd/native-roadmap.d.ts +89 -0
  138. package/dist/src/gsd/native-roadmap.js +343 -0
  139. package/dist/src/gsd/native-state.d.ts +47 -0
  140. package/dist/src/gsd/native-state.js +220 -0
  141. package/dist/src/gsd/paths.d.ts +23 -0
  142. package/dist/src/gsd/paths.js +66 -0
  143. package/dist/src/gsd/phase-dag.d.ts +12 -0
  144. package/dist/src/gsd/phase-dag.js +94 -0
  145. package/dist/src/gsd/phase-sync.d.ts +42 -0
  146. package/dist/src/gsd/phase-sync.js +321 -0
  147. package/dist/src/gsd/pil-gate-context.d.ts +13 -0
  148. package/dist/src/gsd/pil-gate-context.js +64 -0
  149. package/dist/src/gsd/pil-gate-critic.d.ts +19 -0
  150. package/dist/src/gsd/pil-gate-critic.js +74 -0
  151. package/dist/src/gsd/plan-council-prompts.d.ts +25 -0
  152. package/dist/src/gsd/plan-council-prompts.js +79 -0
  153. package/dist/src/gsd/plan-council.d.ts +44 -0
  154. package/dist/src/gsd/plan-council.js +251 -0
  155. package/dist/src/gsd/plan-gate-vocabulary.d.ts +40 -0
  156. package/dist/src/gsd/plan-gate-vocabulary.js +64 -0
  157. package/dist/src/gsd/product-workspace.d.ts +13 -0
  158. package/dist/src/gsd/product-workspace.js +124 -0
  159. package/dist/src/gsd/ship-bridge.d.ts +25 -0
  160. package/dist/src/gsd/ship-bridge.js +65 -0
  161. package/dist/src/gsd/state-document.d.ts +40 -0
  162. package/dist/src/gsd/state-document.js +163 -0
  163. package/dist/src/gsd/verdict-schema.d.ts +39 -0
  164. package/dist/src/gsd/verdict-schema.js +144 -0
  165. package/dist/src/gsd/verify-context.d.ts +22 -0
  166. package/dist/src/gsd/verify-context.js +27 -0
  167. package/dist/src/gsd/verify-council-prompts.d.ts +19 -0
  168. package/dist/src/gsd/verify-council-prompts.js +85 -0
  169. package/dist/src/gsd/verify-council.d.ts +25 -0
  170. package/dist/src/gsd/verify-council.js +119 -0
  171. package/dist/src/gsd/verify-gate-vocabulary.d.ts +25 -0
  172. package/dist/src/gsd/verify-gate-vocabulary.js +46 -0
  173. package/dist/src/gsd/workflow-engine.d.ts +60 -0
  174. package/dist/src/gsd/workflow-engine.js +207 -0
  175. package/dist/src/gsd/workflow-tools.d.ts +13 -0
  176. package/dist/src/gsd/workflow-tools.js +277 -0
  177. package/dist/src/hooks/index.js +1 -1
  178. package/dist/src/index.js +44 -11
  179. package/dist/src/maintain/pr-builder.js +23 -13
  180. package/dist/src/mcp/auto-setup.js +57 -32
  181. package/dist/src/mcp/client-pool.js +1 -1
  182. package/dist/src/mcp/ee-tools.js +1 -0
  183. package/dist/src/mcp/research-onboarding.js +8 -7
  184. package/dist/src/mcp/runtime.js +34 -2
  185. package/dist/src/models/catalog-client.d.ts +87 -0
  186. package/dist/src/models/catalog-client.js +105 -38
  187. package/dist/src/models/catalog.json +528 -265
  188. package/dist/src/models/registry.d.ts +22 -7
  189. package/dist/src/models/registry.js +73 -10
  190. package/dist/src/ops/doctor.js +1 -1
  191. package/dist/src/orchestrator/auto-commit.js +1 -1
  192. package/dist/src/orchestrator/batch-turn-runner.js +2 -2
  193. package/dist/src/orchestrator/cache-prefix.d.ts +67 -0
  194. package/dist/src/orchestrator/cache-prefix.js +83 -0
  195. package/dist/src/orchestrator/compact-request.d.ts +32 -0
  196. package/dist/src/orchestrator/compact-request.js +41 -0
  197. package/dist/src/orchestrator/compaction.d.ts +10 -0
  198. package/dist/src/orchestrator/compaction.js +27 -7
  199. package/dist/src/orchestrator/council-manager.d.ts +12 -3
  200. package/dist/src/orchestrator/council-manager.js +65 -24
  201. package/dist/src/orchestrator/cross-turn-dedup.d.ts +6 -0
  202. package/dist/src/orchestrator/cross-turn-dedup.js +22 -1
  203. package/dist/src/orchestrator/error-utils.d.ts +29 -0
  204. package/dist/src/orchestrator/error-utils.js +132 -24
  205. package/dist/src/orchestrator/grounding-check.js +39 -1
  206. package/dist/src/orchestrator/message-processor.js +242 -33
  207. package/dist/src/orchestrator/orchestrator.d.ts +39 -3
  208. package/dist/src/orchestrator/orchestrator.js +651 -102
  209. package/dist/src/orchestrator/preprocessor.js +1 -1
  210. package/dist/src/orchestrator/proactive-compact-detector.d.ts +26 -0
  211. package/dist/src/orchestrator/proactive-compact-detector.js +36 -0
  212. package/dist/src/orchestrator/prompts.js +17 -17
  213. package/dist/src/orchestrator/reactive-delegation.d.ts +39 -0
  214. package/dist/src/orchestrator/reactive-delegation.js +59 -0
  215. package/dist/src/orchestrator/retry-classifier.d.ts +2 -1
  216. package/dist/src/orchestrator/retry-classifier.js +46 -2
  217. package/dist/src/orchestrator/safety-intercept.d.ts +45 -0
  218. package/dist/src/orchestrator/safety-intercept.js +55 -0
  219. package/dist/src/orchestrator/scope-reminder.js +1 -1
  220. package/dist/src/orchestrator/session-experience.d.ts +2 -1
  221. package/dist/src/orchestrator/session-experience.js +2 -1
  222. package/dist/src/orchestrator/should-run-gate.d.ts +5 -0
  223. package/dist/src/orchestrator/should-run-gate.js +18 -0
  224. package/dist/src/orchestrator/stall-watchdog.d.ts +24 -3
  225. package/dist/src/orchestrator/stall-watchdog.js +47 -13
  226. package/dist/src/orchestrator/stream-runner.js +62 -29
  227. package/dist/src/orchestrator/sub-agent-cap.d.ts +13 -1
  228. package/dist/src/orchestrator/sub-agent-cap.js +16 -1
  229. package/dist/src/orchestrator/sub-agent-model-tier.d.ts +13 -1
  230. package/dist/src/orchestrator/sub-agent-model-tier.js +16 -2
  231. package/dist/src/orchestrator/subagent-compactor.d.ts +53 -1
  232. package/dist/src/orchestrator/subagent-compactor.js +126 -15
  233. package/dist/src/orchestrator/tool-engine.d.ts +22 -0
  234. package/dist/src/orchestrator/tool-engine.js +620 -56
  235. package/dist/src/orchestrator/tool-limit-auto-recover.d.ts +22 -0
  236. package/dist/src/orchestrator/tool-limit-auto-recover.js +30 -0
  237. package/dist/src/orchestrator/turn-runner-deps.d.ts +19 -0
  238. package/dist/src/orchestrator/turn-watchdog.d.ts +37 -0
  239. package/dist/src/orchestrator/turn-watchdog.js +55 -0
  240. package/dist/src/pil/agent-operating-contract.d.ts +1 -1
  241. package/dist/src/pil/agent-operating-contract.js +1 -1
  242. package/dist/src/pil/cheap-model-playbook.d.ts +1 -1
  243. package/dist/src/pil/cheap-model-playbook.js +5 -1
  244. package/dist/src/pil/cheap-model-workbooks.d.ts +1 -1
  245. package/dist/src/pil/cheap-model-workbooks.js +1 -1
  246. package/dist/src/pil/discovery-types.d.ts +1 -0
  247. package/dist/src/pil/discovery.js +16 -11
  248. package/dist/src/pil/layer1-intent.d.ts +18 -6
  249. package/dist/src/pil/layer1-intent.js +66 -757
  250. package/dist/src/pil/layer15-context-scan.js +15 -1
  251. package/dist/src/pil/layer3-ee-injection.js +23 -8
  252. package/dist/src/pil/layer4-gsd.js +69 -16
  253. package/dist/src/pil/layer5-context.js +7 -3
  254. package/dist/src/pil/layer6-output.d.ts +23 -0
  255. package/dist/src/pil/layer6-output.js +5 -1
  256. package/dist/src/pil/llm-classify.d.ts +33 -2
  257. package/dist/src/pil/llm-classify.js +123 -131
  258. package/dist/src/pil/native-capabilities-workbook.d.ts +1 -1
  259. package/dist/src/pil/native-capabilities-workbook.js +1 -0
  260. package/dist/src/pil/pipeline.js +34 -2
  261. package/dist/src/pil/response-tools.js +5 -3
  262. package/dist/src/pil/schema.d.ts +1 -0
  263. package/dist/src/pil/schema.js +2 -0
  264. package/dist/src/pil/types.d.ts +18 -0
  265. package/dist/src/playbook/directives.d.ts +4 -0
  266. package/dist/src/playbook/directives.js +17 -5
  267. package/dist/src/product-loop/backlog-builder.d.ts +14 -1
  268. package/dist/src/product-loop/backlog-builder.js +30 -6
  269. package/dist/src/product-loop/discovery-context-format.js +3 -1
  270. package/dist/src/product-loop/discovery-ecosystem.js +4 -1
  271. package/dist/src/product-loop/discovery-interview.js +32 -3
  272. package/dist/src/product-loop/discovery-schema.js +5 -1
  273. package/dist/src/product-loop/ideal-trace.d.ts +7 -0
  274. package/dist/src/product-loop/ideal-trace.js +64 -0
  275. package/dist/src/product-loop/index.d.ts +13 -1
  276. package/dist/src/product-loop/index.js +333 -52
  277. package/dist/src/product-loop/loop-driver.d.ts +7 -0
  278. package/dist/src/product-loop/loop-driver.js +310 -99
  279. package/dist/src/product-loop/phase-plan.d.ts +5 -0
  280. package/dist/src/product-loop/phase-plan.js +39 -2
  281. package/dist/src/product-loop/phase-runner.js +9 -1
  282. package/dist/src/product-loop/sprint-runner.d.ts +111 -0
  283. package/dist/src/product-loop/sprint-runner.js +559 -16
  284. package/dist/src/product-loop/types.d.ts +36 -5
  285. package/dist/src/providers/adapter.d.ts +1 -1
  286. package/dist/src/providers/adapter.js +3 -4
  287. package/dist/src/providers/auth/browser-flow.d.ts +1 -1
  288. package/dist/src/providers/auth/browser-flow.js +1 -1
  289. package/dist/src/providers/auth/openai-oauth.js +1 -1
  290. package/dist/src/providers/auth/registry.js +0 -34
  291. package/dist/src/providers/auth/token-store.js +4 -1
  292. package/dist/src/providers/auth/types.d.ts +1 -1
  293. package/dist/src/providers/auth/types.js +1 -1
  294. package/dist/src/providers/capabilities.d.ts +24 -5
  295. package/dist/src/providers/capabilities.js +42 -24
  296. package/dist/src/providers/endpoints.d.ts +2 -2
  297. package/dist/src/providers/endpoints.js +11 -10
  298. package/dist/src/providers/keychain.d.ts +1 -1
  299. package/dist/src/providers/keychain.js +7 -9
  300. package/dist/src/providers/mcp-vision-bridge.js +56 -146
  301. package/dist/src/providers/openai-compatible.js +8 -1
  302. package/dist/src/providers/pricing.d.ts +2 -2
  303. package/dist/src/providers/pricing.js +3 -13
  304. package/dist/src/providers/runtime.d.ts +27 -2
  305. package/dist/src/providers/runtime.js +78 -15
  306. package/dist/src/providers/strategies/base.strategy.d.ts +16 -0
  307. package/dist/src/providers/strategies/base.strategy.js +24 -1
  308. package/dist/src/providers/strategies/{siliconflow.strategy.d.ts → opencode-go.strategy.d.ts} +3 -3
  309. package/dist/src/providers/strategies/opencode-go.strategy.js +83 -0
  310. package/dist/src/providers/strategies/registry.js +4 -4
  311. package/dist/src/providers/strategies/thinking-mode.d.ts +109 -0
  312. package/dist/src/providers/strategies/thinking-mode.js +280 -1
  313. package/dist/src/providers/strategies/zai.strategy.d.ts +14 -0
  314. package/dist/src/providers/strategies/zai.strategy.js +44 -0
  315. package/dist/src/providers/types.d.ts +5 -6
  316. package/dist/src/providers/types.js +2 -2
  317. package/dist/src/providers/vision-backend.d.ts +47 -0
  318. package/dist/src/providers/vision-backend.js +258 -0
  319. package/dist/src/providers/vision-proxy.d.ts +22 -9
  320. package/dist/src/providers/vision-proxy.js +63 -132
  321. package/dist/src/providers/wire-debug.js +95 -0
  322. package/dist/src/router/decide.d.ts +13 -0
  323. package/dist/src/router/decide.js +138 -36
  324. package/dist/src/router/peak-hour.d.ts +38 -0
  325. package/dist/src/router/peak-hour.js +107 -0
  326. package/dist/src/router/step-router.js +3 -2
  327. package/dist/src/router/warm.js +4 -5
  328. package/dist/src/scaffold/continuation-prompt.d.ts +11 -0
  329. package/dist/src/scaffold/continuation-prompt.js +26 -0
  330. package/dist/src/scaffold/point-to-existing.d.ts +21 -0
  331. package/dist/src/scaffold/point-to-existing.js +25 -0
  332. package/dist/src/self-qa/agentic-loop.js +3 -3
  333. package/dist/src/{ui/state → state}/active-run.d.ts +19 -0
  334. package/dist/src/{ui/state → state}/active-run.js +21 -0
  335. package/dist/src/{ui/status-bar/store.d.ts → state/status-bar-store.d.ts} +4 -1
  336. package/dist/src/{ui/status-bar/store.js → state/status-bar-store.js} +12 -9
  337. package/dist/src/state/turn-trace.d.ts +43 -0
  338. package/dist/src/state/turn-trace.js +32 -0
  339. package/dist/src/storage/db.js +2 -1
  340. package/dist/src/storage/index.d.ts +1 -1
  341. package/dist/src/storage/index.js +1 -1
  342. package/dist/src/storage/interaction-log.d.ts +1 -1
  343. package/dist/src/storage/migrations.js +71 -1
  344. package/dist/src/storage/sessions.d.ts +28 -10
  345. package/dist/src/storage/sessions.js +78 -21
  346. package/dist/src/storage/transcript-view.js +1 -1
  347. package/dist/src/storage/transcript.d.ts +51 -0
  348. package/dist/src/storage/transcript.js +284 -13
  349. package/dist/src/tools/file.d.ts +15 -0
  350. package/dist/src/tools/file.js +32 -0
  351. package/dist/src/tools/native-tools.js +5 -0
  352. package/dist/src/tools/registry.d.ts +3 -0
  353. package/dist/src/tools/registry.js +460 -22
  354. package/dist/src/tools/research.d.ts +29 -0
  355. package/dist/src/tools/research.js +233 -0
  356. package/dist/src/types/index.d.ts +118 -3
  357. package/dist/src/ui/app.js +0 -0
  358. package/dist/src/ui/cards/product-status-card.js +1 -1
  359. package/dist/src/ui/components/bubble-body-guard.d.ts +27 -0
  360. package/dist/src/ui/components/bubble-body-guard.js +50 -0
  361. package/dist/src/ui/components/context-rail.d.ts +26 -0
  362. package/dist/src/ui/components/context-rail.js +33 -0
  363. package/dist/src/ui/components/council-conclusion-card.d.ts +73 -0
  364. package/dist/src/ui/components/council-conclusion-card.js +420 -0
  365. package/dist/src/ui/components/council-debate-pill.d.ts +36 -0
  366. package/dist/src/ui/components/council-debate-pill.js +34 -0
  367. package/dist/src/ui/components/council-info-card.js +2 -2
  368. package/dist/src/ui/components/council-leader-bubble.d.ts +10 -3
  369. package/dist/src/ui/components/council-leader-bubble.js +21 -11
  370. package/dist/src/ui/components/council-message-bubble.d.ts +15 -2
  371. package/dist/src/ui/components/council-message-bubble.js +16 -15
  372. package/dist/src/ui/components/council-phase-timeline.d.ts +9 -1
  373. package/dist/src/ui/components/council-phase-timeline.js +49 -15
  374. package/dist/src/ui/components/council-placeholder-bubble.d.ts +16 -9
  375. package/dist/src/ui/components/council-placeholder-bubble.js +32 -29
  376. package/dist/src/ui/components/council-question-card.js +12 -12
  377. package/dist/src/ui/components/council-rail-rounds.d.ts +26 -0
  378. package/dist/src/ui/components/council-rail-rounds.js +57 -0
  379. package/dist/src/ui/components/council-round-group.d.ts +38 -0
  380. package/dist/src/ui/components/council-round-group.js +88 -0
  381. package/dist/src/ui/components/council-status-list.d.ts +3 -1
  382. package/dist/src/ui/components/council-status-list.js +36 -24
  383. package/dist/src/ui/components/council-synthesis-banner.d.ts +7 -2
  384. package/dist/src/ui/components/council-synthesis-banner.js +20 -5
  385. package/dist/src/ui/components/halt-recovery-card.js +9 -5
  386. package/dist/src/ui/components/jump-to-latest-pill.d.ts +11 -0
  387. package/dist/src/ui/components/jump-to-latest-pill.js +14 -0
  388. package/dist/src/ui/components/prompt-box.js +18 -16
  389. package/dist/src/ui/components/session-tree-card.d.ts +14 -0
  390. package/dist/src/ui/components/session-tree-card.js +46 -0
  391. package/dist/src/ui/components/slash-inline-menu.d.ts +12 -0
  392. package/dist/src/ui/components/slash-inline-menu.js +26 -5
  393. package/dist/src/ui/components/task-list-panel.d.ts +14 -1
  394. package/dist/src/ui/components/task-list-panel.js +22 -2
  395. package/dist/src/ui/containers/modals-layer.d.ts +2 -1
  396. package/dist/src/ui/hooks/use-session-picker.d.ts +3 -3
  397. package/dist/src/ui/mcp-modal.js +2 -4
  398. package/dist/src/ui/modals/api-key-modal.js +1 -1
  399. package/dist/src/ui/modals/connect-modal.js +4 -3
  400. package/dist/src/ui/modals/session-picker-modal.d.ts +2 -2
  401. package/dist/src/ui/modals/session-picker-modal.js +3 -5
  402. package/dist/src/ui/picker-providers.d.ts +1 -1
  403. package/dist/src/ui/picker-providers.js +1 -1
  404. package/dist/src/ui/primitives/index.d.ts +1 -0
  405. package/dist/src/ui/primitives/index.js +2 -0
  406. package/dist/src/ui/primitives/semantic-primitives.d.ts +76 -0
  407. package/dist/src/ui/primitives/semantic-primitives.js +81 -0
  408. package/dist/src/ui/slash/compact.js +5 -7
  409. package/dist/src/ui/slash/cost.js +1 -1
  410. package/dist/src/ui/slash/council.js +19 -1
  411. package/dist/src/ui/slash/debug.d.ts +3 -31
  412. package/dist/src/ui/slash/debug.js +9 -20
  413. package/dist/src/ui/slash/ideal.d.ts +6 -2
  414. package/dist/src/ui/slash/ideal.js +97 -7
  415. package/dist/src/ui/slash/menu-items.d.ts +7 -0
  416. package/dist/src/ui/slash/menu-items.js +12 -18
  417. package/dist/src/ui/slash/registry.d.ts +2 -0
  418. package/dist/src/ui/slash/registry.js +4 -0
  419. package/dist/src/ui/status-bar/cache-hit.d.ts +6 -0
  420. package/dist/src/ui/status-bar/cache-hit.js +9 -0
  421. package/dist/src/ui/status-bar/index.d.ts +1 -1
  422. package/dist/src/ui/status-bar/index.js +7 -3
  423. package/dist/src/ui/status-bar/usd-meter.d.ts +5 -4
  424. package/dist/src/ui/status-bar/usd-meter.js +6 -4
  425. package/dist/src/ui/theme.d.ts +1 -0
  426. package/dist/src/ui/theme.js +2 -0
  427. package/dist/src/ui/types.d.ts +7 -0
  428. package/dist/src/ui/use-app-logic.js +0 -0
  429. package/dist/src/ui/utils/format.d.ts +14 -0
  430. package/dist/src/ui/utils/format.js +23 -3
  431. package/dist/src/usage/downgrade.js +2 -2
  432. package/dist/src/usage/product-ledger.js +2 -2
  433. package/dist/src/utils/install-manager.js +2 -1
  434. package/dist/src/utils/logger.js +2 -2
  435. package/dist/src/utils/permission-mode.js +5 -3
  436. package/dist/src/utils/redactor.js +1 -1
  437. package/dist/src/utils/settings.d.ts +153 -5
  438. package/dist/src/utils/settings.js +233 -29
  439. package/dist/src/utils/visible-retry.d.ts +11 -0
  440. package/dist/src/utils/visible-retry.js +10 -1
  441. package/dist/src/verify/entrypoint.d.ts +1 -1
  442. package/dist/src/verify/entrypoint.js +1 -1
  443. package/dist/src/verify/recipes.d.ts +13 -0
  444. package/dist/src/verify/recipes.js +15 -0
  445. package/package.json +135 -132
  446. package/dist/src/providers/auth/gcloud.d.ts +0 -28
  447. package/dist/src/providers/auth/gcloud.js +0 -102
  448. package/dist/src/providers/auth/gemini-oauth.d.ts +0 -82
  449. package/dist/src/providers/auth/gemini-oauth.js +0 -472
  450. package/dist/src/providers/gemini.d.ts +0 -11
  451. package/dist/src/providers/gemini.js +0 -45
  452. package/dist/src/providers/siliconflow-sse-repair.d.ts +0 -58
  453. package/dist/src/providers/siliconflow-sse-repair.js +0 -177
  454. package/dist/src/providers/strategies/google.strategy.d.ts +0 -22
  455. package/dist/src/providers/strategies/google.strategy.js +0 -174
  456. package/dist/src/providers/strategies/siliconflow.strategy.js +0 -29
  457. package/dist/src/ui/containers/chat-feed.d.ts +0 -40
  458. package/dist/src/ui/containers/chat-feed.js +0 -66
@@ -48,7 +48,7 @@
48
48
  // - A4 (tool_call write-ahead) — persistToolCallWriteAhead
49
49
  // - A5 (message_seq write-ahead) — persistMessageWriteAhead
50
50
  // - O1 (providerOptions shape forensics) — extractProviderOptionsShape
51
- // - siliconflow reasoning-strip — turnCaps.sanitizeHistory
51
+ // - reasoning-strip (provider quirk) — turnCaps.sanitizeHistory
52
52
  import { getCachedAuthToken, getCachedServerBaseUrl } from "../ee/auth.js";
53
53
  import { routeModel } from "../ee/bridge.js";
54
54
  import { getMistakeDetector } from "../ee/mistake-detector.js";
@@ -57,20 +57,26 @@ import * as phaseTracker from "../ee/phase-tracker.js";
57
57
  import { buildScope as buildScopeForVeto } from "../ee/scope.js";
58
58
  import { fireTrajectoryEvent } from "../ee/session-trajectory.js";
59
59
  import { getTenantId as getTenantIdForVeto } from "../ee/tenant.js";
60
+ import { assessComplexity } from "../gsd/complexity-assessor.js";
61
+ import { isComplexityAssessorEnabled, isGsdNativeEnabled, isPilGateEnrichEnabled } from "../gsd/flags.js";
62
+ import { getGsdLoopHost } from "../gsd/loop-host.js";
63
+ import { readState, syncWorkflowContext } from "../gsd/workflow-engine.js";
60
64
  import { applyPilSuffix, getResponseToolSet, } from "../pil/index.js";
65
+ import { isContinuationPhrase } from "../pil/layer1-intent.js";
61
66
  import { loadKeyForProvider } from "../providers/keychain.js";
62
67
  import { getVisionGuidanceForTextOnly, } from "../providers/mcp-vision-bridge.js";
63
68
  import { detectProviderForModel, resolveModelRuntime, } from "../providers/runtime.js";
64
- import { needsVisionProxy, proxyVision } from "../providers/vision-proxy.js";
69
+ import { canHandleImagesForTextOnlyModel, needsVisionProxy, planImageHandlingForTextOnlyModel, proxyVision, } from "../providers/vision-proxy.js";
65
70
  import { decideStepRouting, eeSamrGuidance, getStepRouterConfig } from "../router/step-router.js";
66
71
  import { routerStore } from "../router/store.js";
67
- import { getNextMessageSequence, logInteraction, persistMessageWriteAhead, } from "../storage/index.js";
68
- import { isDebugEnabled } from "../ui/slash/debug.js";
69
- import { statusBarStore } from "../ui/status-bar/store.js";
72
+ import { statusBarStore } from "../state/status-bar-store.js";
73
+ import { isDebugEnabled } from "../state/turn-trace.js";
74
+ import { getLastApprovedPlan, getNextMessageSequence, logInteraction, persistMessageWriteAhead, } from "../storage/index.js";
70
75
  import { isProviderDisabled, loadValidSubAgents, } from "../utils/settings.js";
71
76
  import { prepareTurnContext } from "./preprocessor.js";
72
77
  import { applyModelConstraints, buildSystemPromptParts } from "./prompts.js";
73
78
  import { parseBudgetOverride, resetSessionStep, } from "./scope-ceiling.js";
79
+ import { shouldRunGate } from "./should-run-gate.js";
74
80
  import { executeToolEngine } from "./tool-engine.js";
75
81
  /**
76
82
  * F2 — approximate the char cost of the FIXED prompt envelope (system +
@@ -107,6 +113,50 @@ function computeEnvelopeChars(system, tools) {
107
113
  * guidance entries it stays informed until new entries arrive.
108
114
  */
109
115
  const _injectedGuidanceSha = new Map();
116
+ /**
117
+ * Single-shot leader-tier LLM runner for the GSD complexity assessor
118
+ * (Task 4 `assessComplexity`). Mirrors the orchestrator's own council LLM
119
+ * construction (`createCouncilLLM` — see `runCouncil` / `runProductLoop` in
120
+ * orchestrator.ts) so the assessor call auto-records usage as
121
+ * `source=council` (no cost-leak) instead of a bespoke unaccounted call.
122
+ * Leader model resolution goes ONLY through `resolvePlanCouncilLeader` —
123
+ * Zero Hardcode Rule, no literal model/provider IDs here.
124
+ */
125
+ function buildLeaderAssessorRunner(deps, sessionModel) {
126
+ return async (prompt) => {
127
+ const { createCouncilLLM } = await import("../council/llm.js");
128
+ const { resolvePlanCouncilLeader } = await import("../council/leader.js");
129
+ const leader = await resolvePlanCouncilLeader(sessionModel);
130
+ const stats = { calls: 0, startMs: Date.now(), phases: [] };
131
+ const llm = createCouncilLLM(deps.bash, deps.mode, deps.session?.id, stats);
132
+ // Small budget — this is a single classification, not a synthesis.
133
+ return llm.generate(leader.modelId, "You are a task complexity assessor.", prompt, 512, undefined, AbortSignal.timeout(PIL_GATE_DEADLINE_MS));
134
+ };
135
+ }
136
+ /**
137
+ * Turn-start PIL gate budget: the assessor + heavy-tier critics run BEFORE the
138
+ * model message is assembled, so they must be short — a slow gate call would
139
+ * delay every turn, not just heavy ones. `createCouncilLLM.generate` has no
140
+ * per-call timeout of its own (`llm.ts:331` defaults to 5 minutes), so this
141
+ * deadline is threaded explicitly as the `signal` arg on every gate call.
142
+ */
143
+ const PIL_GATE_DEADLINE_MS = 2500;
144
+ /**
145
+ * Heavy-tier gate critic runner (Task 4 `runGateCritics`). Reuses the council
146
+ * LLM (billed `source=council`, no cost leak) with the same tight deadline as
147
+ * the assessor — three critics run in parallel via `Promise.all` inside
148
+ * `runGateCritics`, each individually bounded by this signal.
149
+ */
150
+ function buildGateCriticRunner(deps, sessionModel) {
151
+ return async (prompt) => {
152
+ const { createCouncilLLM } = await import("../council/llm.js");
153
+ const { resolvePlanCouncilLeader } = await import("../council/leader.js");
154
+ const leader = await resolvePlanCouncilLeader(sessionModel);
155
+ const stats = { calls: 0, startMs: Date.now(), phases: [] };
156
+ const llm = createCouncilLLM(deps.bash, deps.mode, deps.session?.id, stats);
157
+ return llm.generate(leader.modelId, "You are a prompt-enrichment critic.", prompt, 512, undefined, AbortSignal.timeout(PIL_GATE_DEADLINE_MS));
158
+ };
159
+ }
110
160
  /**
111
161
  * MessageProcessor — extracted streaming turn loop.
112
162
  *
@@ -316,6 +366,89 @@ export class MessageProcessor {
316
366
  yield res.value;
317
367
  }
318
368
  const { pilCtx, _stepCeiling, _pilStart, _naturalCeiling, _ceilingTaskType, _ceilingSize } = prepResult;
369
+ const cwd = deps.bash.getCwd();
370
+ if (isGsdNativeEnabled() &&
371
+ shouldRunGate(pilCtx, () => {
372
+ try {
373
+ return readState(cwd).phase;
374
+ }
375
+ catch (err) {
376
+ // Missing/corrupt .planning state is the normal "no active run" case, not an error.
377
+ console.error(`[pil-gate] readState failed while checking resume phase (treating as no active run): ${err.message}`);
378
+ return null;
379
+ }
380
+ })) {
381
+ try {
382
+ const sessionModel = deps.session?.model ?? "unknown";
383
+ let depth = pilCtx.modelDepthTier ?? pilCtx.complexityTier ?? "standard";
384
+ // Leader-tier assessor enrichment: OVERRIDES the fast-classifier depth
385
+ // before it's written to SDK STATE.md. `assessComplexity` itself never
386
+ // throws (every internal step is caught, degrading to `priorDepth`),
387
+ // but this inner try/catch is defensive fail-open insurance so even an
388
+ // unexpected throw here keeps `depth` at its fast-classifier value —
389
+ // syncWorkflowContext below is never skipped because of the assessor.
390
+ let brief = "";
391
+ if (isComplexityAssessorEnabled()) {
392
+ try {
393
+ const { buildGateContextBundle } = await import("../gsd/pil-gate-context.js");
394
+ const bundle = buildGateContextBundle({
395
+ cwd,
396
+ conversationDigest: deps.buildRecentTurnsSummary(),
397
+ brainData: pilCtx._brainData,
398
+ });
399
+ const assessed = await assessComplexity({
400
+ cwd,
401
+ raw: pilCtx.raw,
402
+ priorDepth: depth,
403
+ confidence: pilCtx.confidence,
404
+ bundle,
405
+ sessionModelId: sessionModel,
406
+ runAssessor: buildLeaderAssessorRunner(deps, sessionModel), // single-shot leader call
407
+ });
408
+ depth = assessed.depth;
409
+ // Keep the native depth slot authoritative: write the assessed depth
410
+ // back to pilCtx.modelDepthTier so every downstream consumer that reads
411
+ // it (tool-engine depthTier -> gsd tool registration + gsd_verify depth
412
+ // + layer-derived tiering) sees the SAME value the mutation gate reads
413
+ // from STATE.md. Without this, the gate (readState().depth) and gsd_verify
414
+ // (pilCtx.modelDepthTier) diverge on any assessor override. Same pilCtx
415
+ // ref, and this block runs before executeToolEngine in the same turn.
416
+ pilCtx.modelDepthTier = depth;
417
+ if (assessed.assessed)
418
+ pilCtx.gsdAutoCouncil = assessed.autoCouncil;
419
+ if (isPilGateEnrichEnabled() && assessed.enrichedPrompt) {
420
+ let verdict = assessed.quality?.verdict ?? "enriched";
421
+ brief = assessed.enrichedPrompt;
422
+ if (depth === "heavy") {
423
+ const { runGateCritics } = await import("../gsd/pil-gate-critic.js");
424
+ const critiqued = await runGateCritics({
425
+ draftBrief: brief,
426
+ draftVerdict: verdict,
427
+ bundle,
428
+ runCritic: buildGateCriticRunner(deps, sessionModel),
429
+ });
430
+ verdict = critiqued.verdict;
431
+ brief = critiqued.brief;
432
+ }
433
+ if (verdict === "adequate")
434
+ brief = "";
435
+ }
436
+ }
437
+ catch (assessErr) {
438
+ brief = "";
439
+ console.error(`[pil-gate] enrichment failed, using raw prompt: ${assessErr.message}`);
440
+ }
441
+ }
442
+ if (brief) {
443
+ pilCtx.enriched = `[PIL Gate brief]\n${brief.slice(0, 1500)}\n\n${pilCtx.enriched}`;
444
+ }
445
+ getGsdLoopHost().ensureHost(cwd, sessionModel);
446
+ syncWorkflowContext(cwd, sessionModel, depth);
447
+ }
448
+ catch (err) {
449
+ console.error(`[gsd-loop-host] turn sync failed: ${err.message}`);
450
+ }
451
+ }
319
452
  // Track whether forced-finalize is needed (set by stopWhen when the
320
453
  // ceiling fires). Read AFTER the streamText fullStream finishes.
321
454
  const _ceilingHit = false;
@@ -332,8 +465,8 @@ export class MessageProcessor {
332
465
  enrichedMessage = `[PIL fallback: ${pilCtx.fallbackReason} — classification/routing may be inaccurate or layers skipped; using raw input.]\n\n${enrichedMessage}`;
333
466
  }
334
467
  deps.setPilActive(pilCtx.taskType !== null);
335
- deps.setPilEnrichmentDelta(pilCtx.metrics?.suffixInstructionTokens ?? Math.round((enrichedMessage.length - userMessage.length) / 4));
336
- const _pilEnrichmentDeltaSnapshot = pilCtx.metrics?.suffixInstructionTokens ?? Math.round((enrichedMessage.length - userMessage.length) / 4);
468
+ deps.setPilEnrichmentDelta(pilCtx.metrics?.suffixInstructionTokens ?? Math.round(((enrichedMessage ?? "").length - userMessage.length) / 4));
469
+ const _pilEnrichmentDeltaSnapshot = pilCtx.metrics?.suffixInstructionTokens ?? Math.round(((enrichedMessage ?? "").length - userMessage.length) / 4);
337
470
  // P1 Item 3 wiring: phase-boundary detection. setPhase returns a snapshot
338
471
  // of the prior phase iff the phase NAME just changed. We classify the
339
472
  // outcome (pass/fail/abandoned/null) and fire phase-outcome to the EE
@@ -423,9 +556,17 @@ export class MessageProcessor {
423
556
  const turnStartMs = Date.now();
424
557
  let turnModelId = deps.modelId;
425
558
  let taskHash = null;
559
+ let routeReason = null;
560
+ const historyHasImages = deps.messages.some((m) => Array.isArray(m.content) && m.content.some((p) => p.type === "image"));
561
+ const turnHasImages = (images?.length ?? 0) > 0;
562
+ let visionUnavailableNotice = null;
426
563
  const _routeStart = Date.now();
427
564
  try {
428
565
  const { decide } = await import("../router/decide.js");
566
+ const compactionMsg = deps.messages.find((m) => typeof m.content === "string" && m.content.startsWith("[Context checkpoint summary]"));
567
+ const compactionSummary = compactionMsg && typeof compactionMsg.content === "string"
568
+ ? compactionMsg.content.slice("[Context checkpoint summary]".length).trim()
569
+ : null;
429
570
  const routeDecision = await decide(userMessage, {
430
571
  tenantId: "local",
431
572
  cwd: deps.bash.getCwd(),
@@ -441,6 +582,11 @@ export class MessageProcessor {
441
582
  projectSize: deps.estimateProjectSize(),
442
583
  filesTouched: deps.countFilesTouched(),
443
584
  mode: deps.mode,
585
+ turnIndex: deps.messages.filter((m) => m.role === "user").length,
586
+ messageCount: deps.messages.length,
587
+ compactionCount: deps.getCompactionStats().count,
588
+ totalSavedTokens: deps.getCompactionStats().totalSaved,
589
+ compactionSummary,
444
590
  },
445
591
  });
446
592
  if (routeDecision.model && routeDecision.model !== "HALT") {
@@ -449,14 +595,15 @@ export class MessageProcessor {
449
595
  // images to text, so there's no need to switch to a vision-capable
450
596
  // (and usually pricier / rate-limited) model.
451
597
  const defaultHasVisionProxy = needsVisionProxy(deps.modelId);
452
- const historyHasImages = deps.messages.some((m) => Array.isArray(m.content) && m.content.some((p) => p.type === "image"));
453
- const turnHasImages = (images?.length ?? 0) > 0;
454
- const skipVisionRoute = defaultHasVisionProxy && (turnHasImages || historyHasImages);
598
+ const imagesOnTurn = turnHasImages || historyHasImages;
599
+ const canHandleImages = !defaultHasVisionProxy || !imagesOnTurn || (await canHandleImagesForTextOnlyModel(deps.modelId));
600
+ const skipVisionRoute = defaultHasVisionProxy && imagesOnTurn && canHandleImages;
455
601
  if (!skipVisionRoute) {
456
602
  turnModelId = routeDecision.model;
457
603
  }
458
604
  }
459
605
  taskHash = routeDecision.taskHash ?? null;
606
+ routeReason = routeDecision.reason ?? null;
460
607
  // Update status bar with router switch info. Also reset back to the
461
608
  // session default when the router does NOT switch on this turn —
462
609
  // otherwise the bar stays "stuck" showing the previously-routed model
@@ -487,14 +634,39 @@ export class MessageProcessor {
487
634
  taskHash = eeRoute?.taskHash ?? null;
488
635
  }
489
636
  }
637
+ if (needsVisionProxy(turnModelId) && (turnHasImages || historyHasImages)) {
638
+ const imageCount = turnHasImages ? images.length : 1;
639
+ const plan = await planImageHandlingForTextOnlyModel({
640
+ primaryModelId: turnModelId,
641
+ imageCount,
642
+ });
643
+ if (plan.strategy === "native_model") {
644
+ turnModelId = plan.fallback.modelId;
645
+ routeReason = routeReason ? `${routeReason}; vision-native-fallback` : "vision-native-fallback";
646
+ yield {
647
+ type: "content",
648
+ content: `[Vision: routed to ${plan.fallback.modelId} — no proxy backend; using native image support]\n`,
649
+ };
650
+ }
651
+ else if (plan.strategy === "unavailable") {
652
+ visionUnavailableNotice = plan.notice;
653
+ }
654
+ }
490
655
  // Interaction log: model routing
491
656
  try {
492
657
  if (deps.session) {
658
+ const promoted = turnModelId !== deps.modelId;
493
659
  logInteraction(deps.session.id, "routing", {
494
660
  model: turnModelId,
661
+ eventSubtype: promoted ? "promoted" : "default",
495
662
  data: {
496
663
  defaultModel: deps.modelId,
497
664
  routedModel: turnModelId,
665
+ promoted,
666
+ // promo-cap(...) tag appears here when the promotion ceiling clamped
667
+ // an EE premium pick down to balanced — queryable via event_subtype +
668
+ // data.reason to audit cost-leak prevention (session 89b34ce9a4e8 class).
669
+ reason: routeReason,
498
670
  taskHash,
499
671
  pilTaskType: pilCtx.taskType ?? null,
500
672
  pilIntentKind: pilCtx.intentKind ?? null,
@@ -566,10 +738,38 @@ export class MessageProcessor {
566
738
  // still carry image parts — otherwise sending the conversation back to a
567
739
  // text-only provider (e.g. DeepSeek) fails with "unknown variant
568
740
  // `image_url`" once history contains an image from a prior turn.
569
- if (needsVisionProxy(turnModelId)) {
570
- const historyHasImages = deps.messages.some((m) => Array.isArray(m.content) && m.content.some((p) => p.type === "image"));
571
- const turnHasImages = (images?.length ?? 0) > 0;
572
- if (turnHasImages || historyHasImages) {
741
+ if (needsVisionProxy(turnModelId) && (turnHasImages || historyHasImages)) {
742
+ const stripImagesFromMessages = (msgs) => msgs.map((m) => {
743
+ if (!Array.isArray(m.content))
744
+ return m;
745
+ const textParts = m.content.filter((p) => p.type === "text");
746
+ const joined = textParts.map((p) => p.text ?? "").join("\n");
747
+ return { ...m, content: joined || "[image removed — vision unavailable]" };
748
+ });
749
+ if (visionUnavailableNotice) {
750
+ yield {
751
+ type: "content",
752
+ content: "[Vision: cannot analyze images — no vision API key or vision model available]\n",
753
+ };
754
+ if (historyHasImages) {
755
+ deps.setMessages(stripImagesFromMessages(deps.messages).map((m) => {
756
+ if (m.role !== "user" || typeof m.content !== "string")
757
+ return m;
758
+ return { ...m, content: `${m.content}\n\n${visionUnavailableNotice}` };
759
+ }));
760
+ }
761
+ if (turnHasImages) {
762
+ userModelMessage = {
763
+ role: "user",
764
+ content: `${messageForDb}\n\n${visionUnavailableNotice}`,
765
+ };
766
+ userEnrichedMessage = {
767
+ role: "user",
768
+ content: `${messageForModel}\n\n${visionUnavailableNotice}`,
769
+ };
770
+ }
771
+ }
772
+ else {
573
773
  try {
574
774
  if (historyHasImages) {
575
775
  const historyResult = await proxyVision(deps.messages, turnModelId, signal);
@@ -588,25 +788,23 @@ export class MessageProcessor {
588
788
  userEnrichedMessage = proxyResult.messages[1];
589
789
  yield {
590
790
  type: "content",
591
- content: `[Vision proxy: ${proxyResult.imageCount} image(s) ${turnModelId} via SiliconFlow]\n`,
791
+ content: `[Vision proxy: ${proxyResult.imageCount} image(s) analyzed for ${turnModelId}]\n`,
592
792
  };
593
793
  }
594
794
  }
595
795
  }
596
- catch {
597
- yield { type: "content", content: "[Vision proxy: failed, images dropped]\n" };
796
+ catch (err) {
797
+ const errMsg = err instanceof Error ? err.message : String(err);
798
+ console.warn(`[vision-proxy] message path failed: ${errMsg}`);
799
+ const notice = visionUnavailableNotice ?? `[vision unavailable: ${errMsg}]`;
800
+ yield { type: "content", content: "[Vision proxy: failed — images not sent to model]\n" };
801
+ if (historyHasImages) {
802
+ deps.setMessages(stripImagesFromMessages(deps.messages));
803
+ }
598
804
  if (turnHasImages) {
599
- userModelMessage = { role: "user", content: messageForDb };
600
- userEnrichedMessage = { role: "user", content: messageForModel };
805
+ userModelMessage = { role: "user", content: `${messageForDb}\n\n${notice}` };
806
+ userEnrichedMessage = { role: "user", content: `${messageForModel}\n\n${notice}` };
601
807
  }
602
- // Strip image parts from history as a last-resort fallback so the
603
- // request doesn't blow up at the provider serialization layer.
604
- deps.setMessages(deps.messages.map((m) => {
605
- if (!Array.isArray(m.content))
606
- return m;
607
- const filtered = m.content.filter((p) => p.type !== "image");
608
- return { ...m, content: filtered };
609
- }));
610
808
  }
611
809
  }
612
810
  }
@@ -666,12 +864,13 @@ export class MessageProcessor {
666
864
  .slice(0, 10)
667
865
  .map((p) => ` - ee_feedback(id="${p.id}", collection="${p.collection ?? "?"}", verdict=followed|ignored|noise)`);
668
866
  const more = pending.length > 10 ? `\n ...and ${pending.length - 10} more` : "";
669
- const recallContent = `⚠️ MANDATORY: Rate ${pending.length} unrated EE hint(s) before proceeding.\n` +
670
- `You MUST call ee_feedback for each hint below BEFORE doing anything else this turn.\n` +
671
- `This is not optional the Experience Engine brain learns from these ratings.\n` +
672
- `Verdict: followed (you used the hint) | ignored (not relevant) | noise (wrong/stale).\n` +
867
+ const recallContent = `↳ ${pending.length} earlier EE hint(s) still unrated. Rate the one(s) you actually ` +
868
+ `acted on so the brain keeps what helped this does NOT block the task; batch the ` +
869
+ `ee_feedback call(s) alongside your work, don't stall the user's request on it.\n` +
870
+ `Verdict: followed (you used it) | ignored (topical, didn't apply) | noise (wrong — needs reason).\n` +
673
871
  `${hintLines.join("\n")}${more}\n` +
674
- `First output MUST be the ee_feedback call(s) then proceed with the task.`;
872
+ `Rate once and move on a hint you can't judge yet, leave for later; re-rating the same ` +
873
+ `id does not help. If the brain is unreachable the verdict is queued, so never retry-loop on it.`;
675
874
  const sid = deps.session?.id ?? "_anon";
676
875
  const { createHash: _recallHash } = await import("node:crypto");
677
876
  const recallSha = _recallHash("sha256").update(recallContent).digest("hex").slice(0, 16);
@@ -749,7 +948,17 @@ export class MessageProcessor {
749
948
  output_summary: stepRouterDecision.reason,
750
949
  });
751
950
  }
752
- deps.setPlanContext(null);
951
+ // Phase 5 continuation fix: do not clear planContext on bare "tiếp tục"/"continue".
952
+ // Re-hydrate from persisted approved plan if needed (cross-process or after abort).
953
+ const _isCont = isContinuationPhrase(userMessage);
954
+ if (!_isCont) {
955
+ deps.setPlanContext(null);
956
+ }
957
+ else if (!deps.getPlanContext()) {
958
+ const _p = getLastApprovedPlan(deps.session?.id ?? "");
959
+ if (_p)
960
+ deps.setPlanContext(_p);
961
+ }
753
962
  const attemptedOverflowRecovery = false;
754
963
  // Stream-retry state: track how many transient retries have been attempted
755
964
  // for the current turn. Reset to 0 on each new user turn (we're in processMessage).
@@ -4,9 +4,13 @@ import { type ScheduleDaemonStatus, type StoredSchedule } from "../tools/schedul
4
4
  import type { AgentMode, ChatEntry, SessionInfo, SessionSnapshot, StreamChunk, SubagentStatus, TaskListSnapshot, TaskRequest, ToolResult, VerifyRecipe } from "../types/index.js";
5
5
  import { type SandboxMode, type SandboxSettings } from "../utils/settings.js";
6
6
  import { type SideQuestionResult } from "../utils/side-question.js";
7
- import { type AgentOptions, type ProcessMessageObserver } from "./agent-options.js";
7
+ import { type AgentOptions, type LegacyProvider, type ProcessMessageObserver } from "./agent-options.js";
8
8
  import type { SafetyOverrideAskInfo, SafetyOverrideVerdict } from "./safety-askcard.js";
9
9
  import type { ToolLoopCapAsk } from "./tool-loop-cap.js";
10
+ /** Deterministic fallback title: truncated first user message, or "" when the
11
+ * message is empty or a JSON-ish payload (so the caller leaves title = NULL
12
+ * and the picker renders a clean "(untitled)" instead of a literal "{}"). */
13
+ export declare function fallbackTitle(userMessage: string): string;
10
14
  export declare class Agent {
11
15
  private provider;
12
16
  private providerId;
@@ -25,6 +29,8 @@ export declare class Agent {
25
29
  private steerDrain;
26
30
  private maxToolRounds;
27
31
  private hardMaxToolRounds;
32
+ /** Original hard ceiling at construction — bounds auto-compaction extension. */
33
+ private _initialHardMaxToolRounds;
28
34
  private mode;
29
35
  private modelId;
30
36
  private maxTokens;
@@ -83,6 +89,9 @@ export declare class Agent {
83
89
  private _turnUserGoalExcerpt;
84
90
  /** Compaction statistics tracking count and total tokens saved. */
85
91
  private _compactionStats;
92
+ /** Token count immediately after the last successful compaction (or null if none yet this
93
+ * session). Used by the cross-turn anti-thrash guard in postTurnCompact. */
94
+ private _lastCompactionTokensAfter;
86
95
  /**
87
96
  * Pinned message sequences. A pinned user message is preserved verbatim across
88
97
  * compaction — it is re-injected as a system note immediately after the
@@ -93,6 +102,8 @@ export declare class Agent {
93
102
  /** One-shot cwd note injected at the start of the next processMessage turn after setCwd(). Cleared after injection. */
94
103
  private _pendingCwdNote;
95
104
  private _crossTurnDedup;
105
+ private _lastTurnToolChars;
106
+ private _turnLoadOrdinal;
96
107
  private _readBudget;
97
108
  constructor(apiKey: string | undefined, baseURL?: string, model?: string, maxToolRounds?: number, options?: AgentOptions);
98
109
  /**
@@ -123,6 +134,12 @@ export declare class Agent {
123
134
  setApiKey(apiKey: string, baseURL?: string): void;
124
135
  setProviderAndKey(providerId: ProviderId, apiKey: string, baseURL?: string): void;
125
136
  getProviderId(): ProviderId;
137
+ /**
138
+ * Expose the provider factory for external callers (e.g., /compact slash command,
139
+ * sub-agent spawning) that need to make LLM calls outside the normal processMessage flow.
140
+ * Throws if no provider is configured.
141
+ */
142
+ getProvider(): LegacyProvider;
126
143
  getCwd(): string;
127
144
  setCwd(dir: string): void;
128
145
  getMessages(): ModelMessage[];
@@ -143,6 +160,18 @@ export declare class Agent {
143
160
  cleanup(): Promise<void>;
144
161
  private _toolLoopCapHandler;
145
162
  setToolLoopCapHandler(fn: ToolLoopCapAsk | null): void;
163
+ /**
164
+ * Extend the absolute hard-cap ceiling when the turn is being sustained by
165
+ * AUTO-COMPACTION (a productive long task, not a runaway). Rationale: each
166
+ * auto-compacted round resets context to O(N) input, so it is cheap — the
167
+ * hard cap's cost-runaway purpose is already served by the compaction. We
168
+ * grant `maxToolRounds/2` more headroom per compaction, bounded to at most
169
+ * one extra auto-recover budget's worth above the ORIGINAL ceiling so a
170
+ * genuinely wedged turn (which trips the pattern guard, not this path) can
171
+ * never grow the cap without limit. Called from the tool-engine auto-recover
172
+ * branch after a successful compaction.
173
+ */
174
+ extendHardCeilingForAutoCompaction(): void;
146
175
  private _safetyOverrideHandler;
147
176
  setSafetyOverrideHandler(fn: ((block: SafetyOverrideAskInfo) => Promise<SafetyOverrideVerdict>) | null): void;
148
177
  respondToToolApproval(approvalId: string, approved: boolean): void;
@@ -166,6 +195,13 @@ export declare class Agent {
166
195
  unpinMessageBySeq(seq: number): boolean;
167
196
  getPinnedSeqs(): number[];
168
197
  getChatEntries(): ChatEntry[];
198
+ /**
199
+ * The session tree this TUI currently hosts: the root conversation plus every
200
+ * rotation / sub-agent descendant, with per-session metadata. Content from
201
+ * these sessions is already merged into the transcript on resume; this exposes
202
+ * WHICH sessions produced it so the rail can show the multi-session structure.
203
+ */
204
+ getSessionTree(): import("../storage/transcript.js").SessionChainNode[];
169
205
  getLastTodoSnapshot(): TaskListSnapshot | null;
170
206
  getSessionSnapshot(): SessionSnapshot | null;
171
207
  onSubagentStatus(listener: (status: SubagentStatus | null) => void): () => void;
@@ -195,7 +231,7 @@ export declare class Agent {
195
231
  private _resolveModelForTask;
196
232
  private compactForContext;
197
233
  private postTurnCompact;
198
- respondToCouncilQuestion(questionId: string, answer: string): void;
234
+ respondToCouncilQuestion(questionId: string, answer: string, questionText?: string): void;
199
235
  respondToCouncilPreflight(preflightId: string, approved: boolean): void;
200
236
  runCouncilV2(topic: string, options?: {
201
237
  skipClarification?: boolean;
@@ -203,7 +239,7 @@ export declare class Agent {
203
239
  userModelMessage?: ModelMessage;
204
240
  }): AsyncGenerator<StreamChunk, void, unknown>;
205
241
  runProductLoopV1(payload: {
206
- subcommand: "start" | "status" | "resume" | "abort" | "ship";
242
+ subcommand: "start" | "status" | "resume" | "abort" | "ship" | "review";
207
243
  idea?: string;
208
244
  runId?: string;
209
245
  flags: {