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
@@ -1,5 +1,6 @@
1
1
  import { jsx as _jsx, jsxs as _jsxs } from "@opentui/react/jsx-runtime";
2
2
  import { useEffect, useRef } from "react";
3
+ import { Dialog } from "../primitives/index.js";
3
4
  import { bottomAlignedModalTop } from "../utils/modal.js";
4
5
  const TEXTAREA_KEYBINDINGS = [
5
6
  { name: "return", action: "submit" },
@@ -15,20 +16,20 @@ export function ConnectModal({ t, width, height, selectedIndex, channels, }) {
15
16
  const panelHeight = Math.min(channels.length + 9, Math.floor(height * 0.5));
16
17
  const top = bottomAlignedModalTop(height, panelHeight);
17
18
  const overlayBg = "#000000cc";
18
- return (_jsx("box", { position: "absolute", left: 0, top: 0, width: width, height: height, alignItems: "center", paddingTop: top, backgroundColor: overlayBg, children: _jsxs("box", { width: Math.min(56, width - 6), height: panelHeight, backgroundColor: t.backgroundPanel, paddingTop: 1, paddingBottom: 1, flexDirection: "column", children: [_jsxs("box", { flexShrink: 0, flexDirection: "row", justifyContent: "space-between", paddingLeft: 2, paddingRight: 2, children: [_jsx("text", { fg: t.primary, children: _jsx("b", { children: "Connect" }) }), _jsx("text", { fg: t.textMuted, children: "esc" })] }), _jsx("box", { flexShrink: 0, paddingLeft: 2, paddingRight: 2, paddingTop: 1, paddingBottom: 1, children: _jsx("text", { fg: t.textMuted, children: "Choose a channel" }) }), _jsx("scrollbox", { ref: listRef, flexGrow: 1, minHeight: 0, children: channels.map((ch, idx) => (_jsx("box", { id: `connect-${ch.id}`, backgroundColor: idx === selectedIndex ? t.selectedBg : undefined, paddingLeft: 2, paddingRight: 2, children: _jsxs("box", { flexDirection: "row", justifyContent: "space-between", children: [_jsx("text", { fg: idx === selectedIndex ? t.selected : t.text, children: ch.label }), _jsx("text", { fg: t.textMuted, children: ch.description })] }) }, ch.id))) }), _jsx("box", { flexShrink: 0, paddingLeft: 2, paddingRight: 2, paddingTop: 2, paddingBottom: 1, children: _jsxs("text", { children: [_jsx("span", { style: { fg: t.primary }, children: "enter " }), _jsx("span", { style: { fg: t.textMuted }, children: "select · " }), _jsx("span", { style: { fg: t.primary }, children: "↑↓ " }), _jsx("span", { style: { fg: t.textMuted }, children: "navigate · " }), _jsx("span", { style: { fg: t.primary }, children: "esc " }), _jsx("span", { style: { fg: t.textMuted }, children: "close" })] }) })] }) }));
19
+ return (_jsx(Dialog, { id: "connect-modal", name: "Connect", children: _jsx("box", { position: "absolute", left: 0, top: 0, width: width, height: height, alignItems: "center", paddingTop: top, backgroundColor: overlayBg, children: _jsxs("box", { width: Math.min(56, width - 6), height: panelHeight, backgroundColor: t.backgroundPanel, paddingTop: 1, paddingBottom: 1, flexDirection: "column", children: [_jsxs("box", { flexShrink: 0, flexDirection: "row", justifyContent: "space-between", paddingLeft: 2, paddingRight: 2, children: [_jsx("text", { fg: t.primary, children: _jsx("b", { children: "Connect" }) }), _jsx("text", { fg: t.textMuted, children: "esc" })] }), _jsx("box", { flexShrink: 0, paddingLeft: 2, paddingRight: 2, paddingTop: 1, paddingBottom: 1, children: _jsx("text", { fg: t.textMuted, children: "Choose a channel" }) }), _jsx("scrollbox", { ref: listRef, flexGrow: 1, minHeight: 0, children: channels.map((ch, idx) => (_jsx("box", { id: `connect-${ch.id}`, backgroundColor: idx === selectedIndex ? t.selectedBg : undefined, paddingLeft: 2, paddingRight: 2, children: _jsxs("box", { flexDirection: "row", justifyContent: "space-between", children: [_jsx("text", { fg: idx === selectedIndex ? t.selected : t.text, children: ch.label }), _jsx("text", { fg: t.textMuted, children: ch.description })] }) }, ch.id))) }), _jsx("box", { flexShrink: 0, paddingLeft: 2, paddingRight: 2, paddingTop: 2, paddingBottom: 1, children: _jsxs("text", { children: [_jsx("span", { style: { fg: t.primary }, children: "enter " }), _jsx("span", { style: { fg: t.textMuted }, children: "select · " }), _jsx("span", { style: { fg: t.primary }, children: "↑↓ " }), _jsx("span", { style: { fg: t.textMuted }, children: "navigate · " }), _jsx("span", { style: { fg: t.primary }, children: "esc " }), _jsx("span", { style: { fg: t.textMuted }, children: "close" })] }) })] }) }) }));
19
20
  }
20
21
  export function TelegramTokenModal({ t, width, height, inputRef, error, onSubmit, }) {
21
22
  const overlayBg = "#000000cc";
22
23
  const panelWidth = Math.min(68, width - 6);
23
24
  const panelHeight = 14;
24
25
  const top = bottomAlignedModalTop(height, panelHeight);
25
- return (_jsx("box", { position: "absolute", left: 0, top: 0, width: width, height: height, alignItems: "center", paddingTop: top, backgroundColor: overlayBg, children: _jsxs("box", { width: panelWidth, height: panelHeight, backgroundColor: t.backgroundPanel, paddingTop: 1, paddingBottom: 1, flexDirection: "column", children: [_jsxs("box", { flexShrink: 0, flexDirection: "row", justifyContent: "space-between", paddingLeft: 2, paddingRight: 2, children: [_jsx("text", { fg: t.primary, children: _jsx("b", { children: "Telegram bot token" }) }), _jsx("text", { fg: t.textMuted, children: "esc" })] }), _jsx("box", { paddingLeft: 2, paddingRight: 2, paddingTop: 1, children: _jsx("text", { fg: t.text, children: "From @BotFather: /newbot, then paste the token here. Stored in ~/.muonroi-cli/user-settings.json." }) }), _jsx("box", { paddingLeft: 2, paddingRight: 2, paddingTop: 1, children: _jsx("box", { backgroundColor: t.backgroundElement, paddingLeft: 1, paddingRight: 1, width: "100%", children: _jsx("textarea", { ref: inputRef, focused: true, placeholder: "123456:ABC...", textColor: t.text, backgroundColor: t.backgroundElement, placeholderColor: t.textMuted, minHeight: 1, maxHeight: 3, wrapMode: "word", keyBindings: TEXTAREA_KEYBINDINGS, onSubmit: onSubmit }) }) }), _jsx("box", { flexGrow: 1, minHeight: 0 }), _jsx("box", { paddingLeft: 2, paddingRight: 2, paddingTop: 2, paddingBottom: 1, children: error ? (_jsx("text", { fg: t.diffRemovedFg, children: error })) : (_jsxs("text", { children: [_jsx("span", { style: { fg: t.primary }, children: "enter " }), _jsx("span", { style: { fg: t.textMuted }, children: "save token · " }), _jsx("span", { style: { fg: t.primary }, children: "esc " }), _jsx("span", { style: { fg: t.textMuted }, children: "close" })] })) })] }) }));
26
+ return (_jsx(Dialog, { id: "telegram-token-modal", name: "Telegram bot token", children: _jsx("box", { position: "absolute", left: 0, top: 0, width: width, height: height, alignItems: "center", paddingTop: top, backgroundColor: overlayBg, children: _jsxs("box", { width: panelWidth, height: panelHeight, backgroundColor: t.backgroundPanel, paddingTop: 1, paddingBottom: 1, flexDirection: "column", children: [_jsxs("box", { flexShrink: 0, flexDirection: "row", justifyContent: "space-between", paddingLeft: 2, paddingRight: 2, children: [_jsx("text", { fg: t.primary, children: _jsx("b", { children: "Telegram bot token" }) }), _jsx("text", { fg: t.textMuted, children: "esc" })] }), _jsx("box", { paddingLeft: 2, paddingRight: 2, paddingTop: 1, children: _jsx("text", { fg: t.text, children: "From @BotFather: /newbot, then paste the token here. Stored in ~/.muonroi-cli/user-settings.json." }) }), _jsx("box", { paddingLeft: 2, paddingRight: 2, paddingTop: 1, children: _jsx("box", { backgroundColor: t.backgroundElement, paddingLeft: 1, paddingRight: 1, width: "100%", children: _jsx("textarea", { ref: inputRef, focused: true, placeholder: "123456:ABC...", textColor: t.text, backgroundColor: t.backgroundElement, placeholderColor: t.textMuted, minHeight: 1, maxHeight: 3, wrapMode: "word", keyBindings: TEXTAREA_KEYBINDINGS, onSubmit: onSubmit }) }) }), _jsx("box", { flexGrow: 1, minHeight: 0 }), _jsx("box", { paddingLeft: 2, paddingRight: 2, paddingTop: 2, paddingBottom: 1, children: error ? (_jsx("text", { fg: t.diffRemovedFg, children: error })) : (_jsxs("text", { children: [_jsx("span", { style: { fg: t.primary }, children: "enter " }), _jsx("span", { style: { fg: t.textMuted }, children: "save token · " }), _jsx("span", { style: { fg: t.primary }, children: "esc " }), _jsx("span", { style: { fg: t.textMuted }, children: "close" })] })) })] }) }) }));
26
27
  }
27
28
  export function TelegramPairModal({ t, width, height, inputRef, error, onSubmit, }) {
28
29
  const overlayBg = "#000000cc";
29
30
  const panelWidth = Math.min(68, width - 6);
30
31
  const panelHeight = 13;
31
32
  const top = bottomAlignedModalTop(height, panelHeight);
32
- return (_jsx("box", { position: "absolute", left: 0, top: 0, width: width, height: height, alignItems: "center", paddingTop: top, backgroundColor: overlayBg, children: _jsxs("box", { width: panelWidth, height: panelHeight, backgroundColor: t.backgroundPanel, paddingTop: 1, paddingBottom: 1, flexDirection: "column", children: [_jsxs("box", { flexShrink: 0, flexDirection: "row", justifyContent: "space-between", paddingLeft: 2, paddingRight: 2, children: [_jsx("text", { fg: t.primary, children: _jsx("b", { children: "Pairing code" }) }), _jsx("text", { fg: t.textMuted, children: "esc" })] }), _jsx("box", { paddingLeft: 2, paddingRight: 2, paddingTop: 1, children: _jsx("text", { fg: t.text, children: "DM your bot with /pair, then paste the 6-character code." }) }), _jsx("box", { paddingLeft: 2, paddingRight: 2, paddingTop: 1, children: _jsx("box", { backgroundColor: t.backgroundElement, paddingLeft: 1, paddingRight: 1, width: "100%", children: _jsx("textarea", { ref: inputRef, focused: true, placeholder: "ABC123", textColor: t.text, backgroundColor: t.backgroundElement, placeholderColor: t.textMuted, minHeight: 1, maxHeight: 2, wrapMode: "word", keyBindings: TEXTAREA_KEYBINDINGS, onSubmit: onSubmit }) }) }), _jsx("box", { flexGrow: 1, minHeight: 0 }), _jsx("box", { paddingLeft: 2, paddingRight: 2, paddingTop: 2, paddingBottom: 1, children: error ? (_jsx("text", { fg: t.diffRemovedFg, children: error })) : (_jsxs("text", { children: [_jsx("span", { style: { fg: t.primary }, children: "enter " }), _jsx("span", { style: { fg: t.textMuted }, children: "approve pairing · " }), _jsx("span", { style: { fg: t.primary }, children: "esc " }), _jsx("span", { style: { fg: t.textMuted }, children: "close" })] })) })] }) }));
33
+ return (_jsx(Dialog, { id: "telegram-pair-modal", name: "Pairing code", children: _jsx("box", { position: "absolute", left: 0, top: 0, width: width, height: height, alignItems: "center", paddingTop: top, backgroundColor: overlayBg, children: _jsxs("box", { width: panelWidth, height: panelHeight, backgroundColor: t.backgroundPanel, paddingTop: 1, paddingBottom: 1, flexDirection: "column", children: [_jsxs("box", { flexShrink: 0, flexDirection: "row", justifyContent: "space-between", paddingLeft: 2, paddingRight: 2, children: [_jsx("text", { fg: t.primary, children: _jsx("b", { children: "Pairing code" }) }), _jsx("text", { fg: t.textMuted, children: "esc" })] }), _jsx("box", { paddingLeft: 2, paddingRight: 2, paddingTop: 1, children: _jsx("text", { fg: t.text, children: "DM your bot with /pair, then paste the 6-character code." }) }), _jsx("box", { paddingLeft: 2, paddingRight: 2, paddingTop: 1, children: _jsx("box", { backgroundColor: t.backgroundElement, paddingLeft: 1, paddingRight: 1, width: "100%", children: _jsx("textarea", { ref: inputRef, focused: true, placeholder: "ABC123", textColor: t.text, backgroundColor: t.backgroundElement, placeholderColor: t.textMuted, minHeight: 1, maxHeight: 2, wrapMode: "word", keyBindings: TEXTAREA_KEYBINDINGS, onSubmit: onSubmit }) }) }), _jsx("box", { flexGrow: 1, minHeight: 0 }), _jsx("box", { paddingLeft: 2, paddingRight: 2, paddingTop: 2, paddingBottom: 1, children: error ? (_jsx("text", { fg: t.diffRemovedFg, children: error })) : (_jsxs("text", { children: [_jsx("span", { style: { fg: t.primary }, children: "enter " }), _jsx("span", { style: { fg: t.textMuted }, children: "approve pairing · " }), _jsx("span", { style: { fg: t.primary }, children: "esc " }), _jsx("span", { style: { fg: t.textMuted }, children: "close" })] })) })] }) }) }));
33
34
  }
34
35
  //# sourceMappingURL=connect-modal.js.map
@@ -1,4 +1,4 @@
1
- import type { SessionInfo } from "../../types/index.js";
1
+ import type { ResumeEntry } from "../../types/index.js";
2
2
  import type { Theme } from "../theme.js";
3
3
  /**
4
4
  * Recent-sessions picker. Opened by `/sessions` or `/session`. Selecting a
@@ -7,7 +7,7 @@ import type { Theme } from "../theme.js";
7
7
  */
8
8
  export declare function SessionPickerModal({ t, sessions, focusIndex, width, height, }: {
9
9
  t: Theme;
10
- sessions: SessionInfo[];
10
+ sessions: ResumeEntry[];
11
11
  focusIndex: number;
12
12
  width: number;
13
13
  height: number;
@@ -21,11 +21,9 @@ export function SessionPickerModal({ t, sessions, focusIndex, width, height, })
21
21
  const titleRaw = s.title?.trim() || "(untitled)";
22
22
  const titleMax = Math.max(8, panelWidth - 38);
23
23
  const title = titleRaw.length > titleMax ? `${titleRaw.slice(0, titleMax - 1)}…` : titleRaw;
24
- // Show the FULL session id (not slice(-8)). The resumed-session
25
- // header displays the full id, so a truncated id here made users
26
- // think they had resumed a "different" session when it was the
27
- // same one shown in two formats.
28
- const idLabel = s.id;
24
+ // Short 8-char id — the tree's root id, enough to disambiguate
25
+ // rows without crowding the model column.
26
+ const idLabel = s.id.slice(0, 8);
29
27
  return (_jsx(Semantic, { id: `session-item-${idx}`, role: "listitem", name: `${title} ${idLabel}`, value: s.id, selected: focused || undefined, children: _jsxs("box", { backgroundColor: focused ? t.selectedBg : undefined, paddingLeft: 2, paddingRight: 2, width: "100%", flexDirection: "row", justifyContent: "space-between", children: [_jsx("text", { fg: focused ? t.selected : t.text, children: `${ts} ${title}` }), _jsx("text", { fg: focused ? t.primary : t.textMuted, children: `${s.model} ${idLabel}` })] }) }, s.id));
30
28
  })) }), _jsx("box", { flexShrink: 0, paddingLeft: 2, paddingRight: 2, paddingTop: 1, children: _jsx("text", { fg: t.textMuted, children: "↑↓ navigate · enter resume (restarts CLI) · esc cancel" }) })] }) }) }));
31
29
  }
@@ -9,7 +9,7 @@ import type { ProviderId } from "../providers/types.js";
9
9
  * previously hidden because `configuredProviders` stayed pinned to the splash
10
10
  * list (app.tsx never re-applied the async `getConfiguredProviders()` result).
11
11
  *
12
- * Providers with no catalog models (anthropic/ollama/google in the default
12
+ * Providers with no catalog models (anthropic/ollama in the default
13
13
  * catalog) are excluded — they cannot be routed to and would render as dead
14
14
  * chips with an empty model list. (xai now ships catalog models, so a
15
15
  * configured/OAuth-logged-in xai surfaces here.)
@@ -8,7 +8,7 @@
8
8
  * previously hidden because `configuredProviders` stayed pinned to the splash
9
9
  * list (app.tsx never re-applied the async `getConfiguredProviders()` result).
10
10
  *
11
- * Providers with no catalog models (anthropic/ollama/google in the default
11
+ * Providers with no catalog models (anthropic/ollama in the default
12
12
  * catalog) are excluded — they cannot be routed to and would render as dead
13
13
  * chips with an empty model list. (xai now ships catalog models, so a
14
14
  * configured/OAuth-logged-in xai surfaces here.)
@@ -0,0 +1 @@
1
+ export * from "./semantic-primitives.js";
@@ -0,0 +1,2 @@
1
+ export * from "./semantic-primitives.js";
2
+ //# sourceMappingURL=index.js.map
@@ -0,0 +1,76 @@
1
+ /**
2
+ * src/ui/primitives/semantic-primitives.tsx
3
+ *
4
+ * Role-fixed semantic primitives. Compose these instead of hand-writing
5
+ * `<Semantic role="...">` in feature code. Two things they buy you:
6
+ *
7
+ * 1. The `role` is fixed per component, so it can't be typo'd or drift, and
8
+ * TypeScript enforces the right props per role.
9
+ * 2. Interactive state is passed as plain booleans (`focused`, `selected`,
10
+ * `disabled`, `hidden`) and mirrored to the Semantic node's `true|undefined`
11
+ * flags automatically — no more `focus={cond ? true : undefined}` written
12
+ * by hand at every call site (the #1 source of harness/state drift).
13
+ *
14
+ * Feature authors should reach for these first; a raw `<Semantic>` is only for
15
+ * genuinely bespoke roles not covered here (or a namespaced `x-*` role).
16
+ *
17
+ * These are invisible wrappers (like `<Semantic>` itself): zero OpenTUI element,
18
+ * zero runtime cost when the agent runtime is unset.
19
+ */
20
+ import type * as React from "react";
21
+ /**
22
+ * Common props shared by every primitive. `focused`/`selected`/`disabled`/
23
+ * `hidden` are plain booleans here (not `true`-literal) and are mirrored to the
24
+ * underlying Semantic flags.
25
+ */
26
+ export interface BlockProps {
27
+ id: string;
28
+ name?: string;
29
+ value?: string;
30
+ state?: string;
31
+ focused?: boolean;
32
+ selected?: boolean;
33
+ disabled?: boolean;
34
+ hidden?: boolean;
35
+ props?: Record<string, unknown>;
36
+ children?: React.ReactNode;
37
+ }
38
+ /** A modal dialog. `isModal` defaults to true (pass `isModal={false}` to opt out). */
39
+ export declare function Dialog({ isModal, ...rest }: BlockProps & {
40
+ isModal?: boolean;
41
+ }): React.ReactNode;
42
+ /** A generic grouping region / panel. */
43
+ export declare function Region(props: BlockProps): React.ReactNode;
44
+ /** A titled content panel (IDE-style). */
45
+ export declare function Panel(props: BlockProps): React.ReactNode;
46
+ /** A single-line or multi-line text input. Pass `value` + `focused`. */
47
+ export declare function TextBox(props: BlockProps): React.ReactNode;
48
+ /** A pressable button. Pass `disabled`/`focused` as booleans. */
49
+ export declare function Button(props: BlockProps): React.ReactNode;
50
+ /** A toggle. Reflect checked state via `selected`. */
51
+ export declare function Checkbox(props: BlockProps): React.ReactNode;
52
+ /** A scrollable list container. */
53
+ export declare function ListBox(props: BlockProps): React.ReactNode;
54
+ /** A single list row. Reflect highlight via `selected`. */
55
+ export declare function ListItem(props: BlockProps): React.ReactNode;
56
+ /** A command / context menu. `isModal` defaults to true. */
57
+ export declare function Menu({ isModal, ...rest }: BlockProps & {
58
+ isModal?: boolean;
59
+ }): React.ReactNode;
60
+ /** A single menu entry. */
61
+ export declare function MenuItem(props: BlockProps): React.ReactNode;
62
+ /** A transient notification. */
63
+ export declare function Toast(props: BlockProps): React.ReactNode;
64
+ /** The persistent status bar. */
65
+ export declare function StatusBar(props: BlockProps): React.ReactNode;
66
+ /** A determinate/indeterminate progress indicator. Put `0..1` in `value`. */
67
+ export declare function ProgressBar(props: BlockProps): React.ReactNode;
68
+ /** A scrollback / message log. */
69
+ export declare function Log(props: BlockProps): React.ReactNode;
70
+ /**
71
+ * Escape hatch for a namespaced custom role not covered above. `role` MUST start
72
+ * with `x-` (enforced by the `Role` type). Prefer a named primitive when one fits.
73
+ */
74
+ export declare function CustomBlock({ role, ...rest }: BlockProps & {
75
+ role: `x-${string}`;
76
+ }): React.ReactNode;
@@ -0,0 +1,81 @@
1
+ import { jsx as _jsx } from "@opentui/react/jsx-runtime";
2
+ import { Semantic } from "@muonroi/agent-harness-opentui";
3
+ /** Coerce a boolean into the Semantic flag shape (`true` present, else absent). */
4
+ function flag(value) {
5
+ return value ? true : undefined;
6
+ }
7
+ /**
8
+ * Internal base. Renders a `<Semantic>` with a fixed `role`, mapping the plain
9
+ * boolean props to the flag shape. `isModal` is passed through for the roles
10
+ * that support it (dialog/menu).
11
+ */
12
+ function Block({ role, isModal, id, name, value, state, focused, selected, disabled, hidden, props, children, }) {
13
+ return (_jsx(Semantic, { id: id, role: role, name: name, value: value, state: state, focus: flag(focused), selected: flag(selected), disabled: flag(disabled), hidden: flag(hidden), isModal: flag(isModal), props: props, children: children }));
14
+ }
15
+ // ---------------------------------------------------------------------------
16
+ // Role-fixed primitives
17
+ // ---------------------------------------------------------------------------
18
+ /** A modal dialog. `isModal` defaults to true (pass `isModal={false}` to opt out). */
19
+ export function Dialog({ isModal = true, ...rest }) {
20
+ return _jsx(Block, { role: "dialog", isModal: isModal, ...rest });
21
+ }
22
+ /** A generic grouping region / panel. */
23
+ export function Region(props) {
24
+ return _jsx(Block, { role: "region", ...props });
25
+ }
26
+ /** A titled content panel (IDE-style). */
27
+ export function Panel(props) {
28
+ return _jsx(Block, { role: "panel", ...props });
29
+ }
30
+ /** A single-line or multi-line text input. Pass `value` + `focused`. */
31
+ export function TextBox(props) {
32
+ return _jsx(Block, { role: "textbox", ...props });
33
+ }
34
+ /** A pressable button. Pass `disabled`/`focused` as booleans. */
35
+ export function Button(props) {
36
+ return _jsx(Block, { role: "button", ...props });
37
+ }
38
+ /** A toggle. Reflect checked state via `selected`. */
39
+ export function Checkbox(props) {
40
+ return _jsx(Block, { role: "checkbox", ...props });
41
+ }
42
+ /** A scrollable list container. */
43
+ export function ListBox(props) {
44
+ return _jsx(Block, { role: "listbox", ...props });
45
+ }
46
+ /** A single list row. Reflect highlight via `selected`. */
47
+ export function ListItem(props) {
48
+ return _jsx(Block, { role: "listitem", ...props });
49
+ }
50
+ /** A command / context menu. `isModal` defaults to true. */
51
+ export function Menu({ isModal = true, ...rest }) {
52
+ return _jsx(Block, { role: "menu", isModal: isModal, ...rest });
53
+ }
54
+ /** A single menu entry. */
55
+ export function MenuItem(props) {
56
+ return _jsx(Block, { role: "menuitem", ...props });
57
+ }
58
+ /** A transient notification. */
59
+ export function Toast(props) {
60
+ return _jsx(Block, { role: "toast", ...props });
61
+ }
62
+ /** The persistent status bar. */
63
+ export function StatusBar(props) {
64
+ return _jsx(Block, { role: "statusbar", ...props });
65
+ }
66
+ /** A determinate/indeterminate progress indicator. Put `0..1` in `value`. */
67
+ export function ProgressBar(props) {
68
+ return _jsx(Block, { role: "progressbar", ...props });
69
+ }
70
+ /** A scrollback / message log. */
71
+ export function Log(props) {
72
+ return _jsx(Block, { role: "log", ...props });
73
+ }
74
+ /**
75
+ * Escape hatch for a namespaced custom role not covered above. `role` MUST start
76
+ * with `x-` (enforced by the `Role` type). Prefer a named primitive when one fits.
77
+ */
78
+ export function CustomBlock({ role, ...rest }) {
79
+ return _jsx(Block, { role: role, ...rest });
80
+ }
81
+ //# sourceMappingURL=semantic-primitives.js.map
@@ -15,11 +15,9 @@ import { FLOW_DIR_NAME } from "../../flow/scaffold.js";
15
15
  import { registerSlash } from "./registry.js";
16
16
  export const handleCompactSlash = async (_args, ctx) => {
17
17
  const flowDir = path.join(ctx.cwd, FLOW_DIR_NAME);
18
- // Check for active run
18
+ // Check for active run (informational only). /compact should work on any
19
+ // session, not only inside a product-loop run, so we no longer block here.
19
20
  const runId = await getActiveRunId(flowDir);
20
- if (!runId) {
21
- return "No active run. Nothing to compact. Start with /discuss to create a run.";
22
- }
23
21
  // Fire-and-forget: notify EE that surfaced suggestions are going stale due to compact
24
22
  const { surfacedIds, timestamp } = getLastSurfacedState();
25
23
  if (surfacedIds.length > 0) {
@@ -31,9 +29,9 @@ export const handleCompactSlash = async (_args, ctx) => {
31
29
  .catch(() => { });
32
30
  }
33
31
  // Return signal for orchestrator to perform compaction
34
- // The orchestrator intercepts __COMPACT__ and calls deliberateCompact()
35
- // with its own this.messages and this.systemPrompt
36
- return `__COMPACT__\nRun: ${runId}\nReady for two-pass compaction.`;
32
+ const instructions = _args.length > 0 ? `\nInstructions: ${_args.join(" ")}` : "";
33
+ const runLine = runId ? `Run: ${runId}` : "No active run — compacting chat history only.";
34
+ return `__COMPACT__\n${runLine}${instructions}\nReady for two-pass compaction.`;
37
35
  };
38
36
  // Self-register on module import
39
37
  registerSlash("compact", handleCompactSlash);
@@ -9,7 +9,7 @@
9
9
  */
10
10
  import { healthDetailed } from "../../ee/health.js";
11
11
  import { getDefaultEEClient } from "../../ee/intercept.js";
12
- import { statusBarStore } from "../status-bar/store.js";
12
+ import { statusBarStore } from "../../state/status-bar-store.js";
13
13
  import { registerSlash } from "./registry.js";
14
14
  export const handleCostSlash = async (_args, _ctx) => {
15
15
  const s = statusBarStore.getState();
@@ -1,3 +1,4 @@
1
+ import { getCouncilLanguage, normalizeCouncilLanguage, saveUserSettings } from "../../utils/settings.js";
1
2
  import { handleCouncilInspectSlash } from "./council-inspect.js";
2
3
  import { registerSlash } from "./registry.js";
3
4
  export const handleCouncilSlash = async (args, ctx) => {
@@ -5,6 +6,22 @@ export const handleCouncilSlash = async (args, ctx) => {
5
6
  if (args[0] === "inspect") {
6
7
  return handleCouncilInspectSlash(args.slice(1), ctx);
7
8
  }
9
+ // Feature B — /council lang [value] : read or set the debate language.
10
+ // The chosen language IS the debate language (no translate pass).
11
+ if (args[0] === "lang" || args[0] === "language") {
12
+ const value = args.slice(1).join(" ").trim();
13
+ if (!value) {
14
+ const current = getCouncilLanguage();
15
+ return (`Council debate language: ${current}\n` +
16
+ `- "auto" (default): debate + conclusion follow the language of your prompt.\n` +
17
+ `- "english": force the historical English-only debate.\n` +
18
+ `- <locale> (e.g. "vietnamese", "日本語"): pin the debate to that language.\n` +
19
+ `Set with: /council lang <value>`);
20
+ }
21
+ const normalized = normalizeCouncilLanguage(value);
22
+ saveUserSettings({ councilLanguage: normalized });
23
+ return `Council debate language set to: ${normalized}`;
24
+ }
8
25
  let rounds;
9
26
  const firstArg = args[0];
10
27
  if (firstArg && /^\d+$/.test(firstArg)) {
@@ -14,7 +31,8 @@ export const handleCouncilSlash = async (args, ctx) => {
14
31
  const topic = args.join(" ") || ctx.lastPrompt || "";
15
32
  if (!topic) {
16
33
  return ("/council [rounds] <topic> — multi-model discussion\n" +
17
- "Default: uses models from the same provider. Set councilPreferMultiProvider + roleModels for cross-provider.\n" +
34
+ "Default: multi-provider lineup from catalog (implement/verify/research across providers).\n" +
35
+ "Override via roleModels in settings, or councilPreferMultiProvider: false for same-provider.\n" +
18
36
  "Example: /council 3 REST vs gRPC for our microservices");
19
37
  }
20
38
  return `__COUNCIL__\n${rounds ?? ""}\n${topic}`;
@@ -10,36 +10,8 @@
10
10
  * /debug off — disable
11
11
  * /debug status — show current pipeline state without toggling
12
12
  */
13
+ import { isDebugEnabled, recordTurnTrace } from "../../state/turn-trace.js";
13
14
  import type { SlashHandler } from "./registry.js";
14
- export interface PipelineStep {
15
- name: string;
16
- duration_ms: number;
17
- input_summary: string;
18
- output_summary: string;
19
- tokens_saved?: number;
20
- }
21
- export interface TurnTrace {
22
- turn_id: number;
23
- timestamp: number;
24
- raw_prompt: string;
25
- steps: PipelineStep[];
26
- model_requested: string;
27
- model_used: string;
28
- routed: boolean;
29
- input_tokens: number;
30
- output_tokens: number;
31
- cache_read_tokens: number;
32
- cost_usd: number;
33
- estimated_savings: SavingsEstimate;
34
- }
35
- export interface SavingsEstimate {
36
- pil_tokens_saved: number;
37
- cache_tokens_saved: number;
38
- router_cost_saved_usd: number;
39
- total_tokens_saved: number;
40
- total_cost_saved_usd: number;
41
- }
42
- export declare function isDebugEnabled(): boolean;
43
- export declare function recordTurnTrace(trace: TurnTrace): void;
44
- export declare function getLastTrace(): TurnTrace | null;
15
+ export type { PipelineStep, SavingsEstimate, TurnTrace } from "../../state/turn-trace.js";
16
+ export { isDebugEnabled, recordTurnTrace };
45
17
  export declare const handleDebugSlash: SlashHandler;
@@ -10,23 +10,10 @@
10
10
  * /debug off — disable
11
11
  * /debug status — show current pipeline state without toggling
12
12
  */
13
- import { statusBarStore } from "../status-bar/store.js";
13
+ import { statusBarStore } from "../../state/status-bar-store.js";
14
+ import { getAllTraces, getLastTrace, isDebugEnabled, recordTurnTrace, setDebugEnabled, } from "../../state/turn-trace.js";
14
15
  import { registerSlash } from "./registry.js";
15
- let debugEnabled = false;
16
- const turnTraces = [];
17
- export function isDebugEnabled() {
18
- return debugEnabled;
19
- }
20
- export function recordTurnTrace(trace) {
21
- if (!debugEnabled)
22
- return;
23
- turnTraces.push(trace);
24
- if (turnTraces.length > 50)
25
- turnTraces.shift();
26
- }
27
- export function getLastTrace() {
28
- return turnTraces[turnTraces.length - 1] ?? null;
29
- }
16
+ export { isDebugEnabled, recordTurnTrace };
30
17
  function formatTrace(trace) {
31
18
  const lines = [];
32
19
  lines.push(`┌─ Turn #${trace.turn_id} ─────────────────────────────────`);
@@ -62,6 +49,7 @@ function formatTrace(trace) {
62
49
  }
63
50
  function formatSessionSummary() {
64
51
  const s = statusBarStore.getState();
52
+ const turnTraces = getAllTraces();
65
53
  const totalSavings = turnTraces.reduce((acc, t) => ({
66
54
  tokens: acc.tokens + t.estimated_savings.total_tokens_saved,
67
55
  cost: acc.cost + t.estimated_savings.total_cost_saved_usd,
@@ -82,11 +70,11 @@ function formatSessionSummary() {
82
70
  export const handleDebugSlash = async (args, _ctx) => {
83
71
  const cmd = args[0]?.toLowerCase();
84
72
  if (cmd === "on") {
85
- debugEnabled = true;
73
+ setDebugEnabled(true);
86
74
  return "Pipeline debug tracing: ON\nEach turn will show: PIL → Router → EE hooks → Model → Savings";
87
75
  }
88
76
  if (cmd === "off") {
89
- debugEnabled = false;
77
+ setDebugEnabled(false);
90
78
  return "Pipeline debug tracing: OFF";
91
79
  }
92
80
  if (cmd === "status") {
@@ -99,8 +87,9 @@ export const handleDebugSlash = async (args, _ctx) => {
99
87
  return formatTrace(last);
100
88
  }
101
89
  // Toggle
102
- debugEnabled = !debugEnabled;
103
- if (debugEnabled) {
90
+ const next = !isDebugEnabled();
91
+ setDebugEnabled(next);
92
+ if (next) {
104
93
  return "Pipeline debug tracing: ON\nEach turn will show: PIL → Router → EE hooks → Model → Savings\n\nCommands: /debug off | /debug status | /debug last";
105
94
  }
106
95
  return "Pipeline debug tracing: OFF";
@@ -7,7 +7,7 @@
7
7
  * /ideal "<idea>" start a new product run (default)
8
8
  * /ideal status list active runs
9
9
  * /ideal status <runId> detail of one run
10
- * /ideal resume <runId> resume halted/crashed run
10
+ * /ideal resume [runId] resume halted/crashed run (no id = newest incomplete)
11
11
  * /ideal abort <runId> hard kill
12
12
  * /ideal ship <runId> force user-approval gate (skip if Cond #1-#4 pass)
13
13
  *
@@ -47,7 +47,7 @@ export interface IdealFlags {
47
47
  /** Mode C only — opt-in: run `gh pr create` after PR is built. Default false. */
48
48
  ghPr?: boolean;
49
49
  }
50
- export type IdealSubcommand = "start" | "status" | "resume" | "abort" | "ship" | "help";
50
+ export type IdealSubcommand = "start" | "status" | "resume" | "abort" | "ship" | "review" | "milestones" | "phases" | "help";
51
51
  export interface IdealParseResult {
52
52
  subcommand: IdealSubcommand;
53
53
  idea?: string;
@@ -60,6 +60,10 @@ export interface IdealParseResult {
60
60
  * SlashHandler signature (which depends on a SlashContext).
61
61
  */
62
62
  export declare function parseIdealArgs(args: string[]): IdealParseResult;
63
+ /** Render `/ideal milestones` — every milestone with its phases + linked runs. */
64
+ export declare function renderMilestones(cwd: string): Promise<string>;
65
+ /** Render `/ideal phases [milestoneId]` — phases under one milestone. */
66
+ export declare function renderPhases(cwd: string, milestoneId?: string): Promise<string>;
63
67
  /**
64
68
  * Slash handler. Returns a sentinel string parseable by app.tsx, OR a help/error
65
69
  * string when no orchestrator dispatch is appropriate.
@@ -7,7 +7,7 @@
7
7
  * /ideal "<idea>" start a new product run (default)
8
8
  * /ideal status list active runs
9
9
  * /ideal status <runId> detail of one run
10
- * /ideal resume <runId> resume halted/crashed run
10
+ * /ideal resume [runId] resume halted/crashed run (no id = newest incomplete)
11
11
  * /ideal abort <runId> hard kill
12
12
  * /ideal ship <runId> force user-approval gate (skip if Cond #1-#4 pass)
13
13
  *
@@ -25,7 +25,9 @@
25
25
  * app.tsx parses and dispatches to orchestrator.runProductLoopV1, mirroring
26
26
  * the existing __COUNCIL__ pattern in src/ui/slash/council.ts.
27
27
  */
28
+ import * as path from "node:path";
28
29
  import { Command, InvalidArgumentError } from "commander";
30
+ import { getActivePointer, listMilestones, listPhases, migrateLegacyRuns } from "../../flow/hierarchy.js";
29
31
  import { registerSlash } from "./registry.js";
30
32
  const DEFAULTS = {
31
33
  maxCost: 50,
@@ -38,8 +40,11 @@ const HELP_TEXT = [
38
40
  "Subcommands:",
39
41
  ' /ideal "<idea>" Start a new product run',
40
42
  " /ideal status [runId] List active runs (or detail one)",
41
- " /ideal resume <runId> Resume a halted / crashed run",
42
- " /ideal abort <runId> Hard-kill a run",
43
+ " /ideal resume [runId] Resume a run (no id = newest incomplete run)",
44
+ " /ideal review [runId] Render a run's transcript + sprint scores (no id = newest run)",
45
+ " /ideal milestones List milestones (idea/product groups) and their phases",
46
+ " /ideal phases [mId] List phases under a milestone (no id = active milestone)",
47
+ " /ideal abort [runId] Hard-kill a run (no id = newest incomplete run)",
43
48
  " /ideal ship <runId> Force user-approval gate (skip Cond #1-#4 if passing)",
44
49
  "",
45
50
  "Flags (start only):",
@@ -85,7 +90,18 @@ export function parseIdealArgs(args) {
85
90
  return { subcommand: "help", flags: { ...DEFAULTS, noCustomerDebate }, warnings };
86
91
  }
87
92
  // Detect non-start subcommands by first token (subcommand keywords are reserved).
88
- const RESERVED = new Set(["status", "resume", "abort", "ship", "help", "--help", "-h"]);
93
+ const RESERVED = new Set([
94
+ "status",
95
+ "resume",
96
+ "abort",
97
+ "ship",
98
+ "review",
99
+ "milestones",
100
+ "phases",
101
+ "help",
102
+ "--help",
103
+ "-h",
104
+ ]);
89
105
  const head = args[0];
90
106
  if (RESERVED.has(head)) {
91
107
  if (head === "help" || head === "--help" || head === "-h") {
@@ -193,18 +209,92 @@ export function parseIdealArgs(args) {
193
209
  warnings,
194
210
  };
195
211
  }
212
+ function flowDirOf(cwd) {
213
+ return path.join(cwd, ".muonroi-flow");
214
+ }
215
+ /** Render `/ideal milestones` — every milestone with its phases + linked runs. */
216
+ export async function renderMilestones(cwd) {
217
+ const flowDir = flowDirOf(cwd);
218
+ // Lazily backfill pre-hierarchy runs so old work is visible. Idempotent.
219
+ await migrateLegacyRuns(flowDir, new Date().toISOString()).catch(() => 0);
220
+ const milestones = await listMilestones(flowDir);
221
+ if (milestones.length === 0) {
222
+ return 'No milestones yet. Start one with `/ideal "<idea>"`.';
223
+ }
224
+ const { milestoneId: activeM, phaseId: activeP } = await getActivePointer(flowDir);
225
+ const lines = ["# Milestones", ""];
226
+ for (const m of milestones) {
227
+ const active = m.id === activeM ? " ← active" : "";
228
+ lines.push(`## ${m.id}: ${m.title} [${m.status}]${active}`);
229
+ if (m.goal)
230
+ lines.push(` goal: ${m.goal}`);
231
+ const phases = await listPhases(flowDir, m.id);
232
+ if (phases.length === 0) {
233
+ lines.push(" (no phases yet)");
234
+ }
235
+ else {
236
+ for (const p of phases) {
237
+ const runs = p.runIds.length > 0 ? ` — runs: ${p.runIds.join(", ")}` : "";
238
+ const pActive = m.id === activeM && p.id === activeP ? " ←" : "";
239
+ lines.push(` - [${p.status === "done" ? "x" : " "}] ${p.id}: ${p.title} [${p.status}]${runs}${pActive}`);
240
+ }
241
+ }
242
+ lines.push("");
243
+ }
244
+ return lines.join("\n").trimEnd();
245
+ }
246
+ /** Render `/ideal phases [milestoneId]` — phases under one milestone. */
247
+ export async function renderPhases(cwd, milestoneId) {
248
+ const flowDir = flowDirOf(cwd);
249
+ let mId = milestoneId;
250
+ if (!mId) {
251
+ mId = (await getActivePointer(flowDir)).milestoneId ?? undefined;
252
+ }
253
+ if (!mId) {
254
+ return "No active milestone. Run `/ideal milestones` to list, or pass a milestone id.";
255
+ }
256
+ const phases = await listPhases(flowDir, mId);
257
+ if (phases.length === 0) {
258
+ return `No phases under ${mId}.`;
259
+ }
260
+ const { phaseId: activeP } = await getActivePointer(flowDir);
261
+ const lines = [`# Phases of ${mId}`, ""];
262
+ for (const p of phases) {
263
+ const runs = p.runIds.length > 0 ? ` — runs: ${p.runIds.join(", ")}` : "";
264
+ const pActive = p.id === activeP ? " ← active" : "";
265
+ lines.push(`- [${p.status === "done" ? "x" : " "}] ${p.id}: ${p.title} [${p.status}]${runs}${pActive}`);
266
+ if (p.goal)
267
+ lines.push(` goal: ${p.goal}`);
268
+ }
269
+ return lines.join("\n");
270
+ }
196
271
  /**
197
272
  * Slash handler. Returns a sentinel string parseable by app.tsx, OR a help/error
198
273
  * string when no orchestrator dispatch is appropriate.
199
274
  */
200
- export const handleIdealSlash = async (args) => {
275
+ export const handleIdealSlash = async (args, ctx) => {
201
276
  const result = parseIdealArgs(args);
202
277
  if (result.subcommand === "help") {
203
278
  const warnings = result.warnings.length ? `\n\n${result.warnings.join("\n")}` : "";
204
279
  return `${HELP_TEXT}${warnings}`;
205
280
  }
206
- // Status/abort/resume/ship without a runId: status is allowed (lists), the rest are not.
207
- if (result.subcommand !== "start" && result.subcommand !== "status" && !result.runId) {
281
+ // Milestones/phases are read-only index views render inline (no orchestrator
282
+ // dispatch). `runId` carries the optional milestone id for `phases`.
283
+ if (result.subcommand === "milestones") {
284
+ return renderMilestones(ctx.cwd);
285
+ }
286
+ if (result.subcommand === "phases") {
287
+ return renderPhases(ctx.cwd, result.runId);
288
+ }
289
+ // Status/resume/abort without a runId are allowed: status lists all runs,
290
+ // resume + abort auto-detect the newest incomplete run (A/B). ship still
291
+ // requires an explicit runId.
292
+ if (result.subcommand !== "start" &&
293
+ result.subcommand !== "status" &&
294
+ result.subcommand !== "resume" &&
295
+ result.subcommand !== "abort" &&
296
+ result.subcommand !== "review" &&
297
+ !result.runId) {
208
298
  return `error: /ideal ${result.subcommand} requires a runId\n\n${HELP_TEXT}`;
209
299
  }
210
300
  const payload = {
@@ -40,3 +40,10 @@ export interface SlashMenuItem {
40
40
  export declare const SLASH_MENU_ITEMS: SlashMenuItem[];
41
41
  /** Items shown in the splash autocomplete + /help listing. */
42
42
  export declare const VISIBLE_SLASH_MENU_ITEMS: SlashMenuItem[];
43
+ /**
44
+ * Arrow-navigation order for the empty-query ("just /") dropdown: primary
45
+ * surface first, then the hidden commands. The dropdown renders a scrolling
46
+ * viewport, so listing the full set here makes every command reachable by
47
+ * arrow keys without cluttering the top of the list (primary stays on top).
48
+ */
49
+ export declare const SLASH_MENU_ITEMS_ARROW_ORDER: SlashMenuItem[];