mixdog 0.9.151 → 0.9.153

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 (307) hide show
  1. package/LICENSES/browser-import-NOTICE.txt +11 -0
  2. package/NOTICE.md +11 -0
  3. package/README.md +108 -68
  4. package/package.json +17 -4
  5. package/scripts/computer-task-cost-report.mjs +144 -0
  6. package/scripts/run-office-live-tests.mjs +32 -0
  7. package/scripts/tool-stress.mjs +0 -2
  8. package/src/agents/front-worker/AGENT.md +13 -0
  9. package/src/agents/front-worker/agent.json +6 -0
  10. package/src/agents/heavy-worker/AGENT.md +10 -11
  11. package/src/agents/heavy-worker/agent.json +1 -1
  12. package/src/agents/maintainer/AGENT.md +0 -2
  13. package/src/agents/reviewer/AGENT.md +9 -13
  14. package/src/agents/reviewer/agent.json +1 -1
  15. package/src/agents/security/AGENT.md +14 -0
  16. package/src/agents/security/agent.json +6 -0
  17. package/src/agents/worker/AGENT.md +8 -8
  18. package/src/agents/worker/agent.json +1 -1
  19. package/src/agents/writer/AGENT.md +14 -0
  20. package/src/agents/writer/agent.json +6 -0
  21. package/src/defaults/skills/setup/SKILL.md +18 -27
  22. package/src/headless-exec.mjs +3 -10
  23. package/src/headless-exec.test.mjs +2 -7
  24. package/src/rules/agent/00-common.md +4 -7
  25. package/src/rules/lead/01-general.md +0 -3
  26. package/src/rules/shared/10-tool-workflow.md +10 -2
  27. package/src/runtime/agent/orchestrator/agent-runtime/agent-dispatch.mjs +183 -26
  28. package/src/runtime/agent/orchestrator/agent-runtime/agent-dispatch.test.mjs +378 -0
  29. package/src/runtime/agent/orchestrator/agent-runtime/session-builder.mjs +4 -0
  30. package/src/runtime/agent/orchestrator/cache-break-trace.mjs +109 -0
  31. package/src/runtime/agent/orchestrator/cache-break-trace.test.mjs +115 -0
  32. package/src/runtime/agent/orchestrator/config.mjs +13 -68
  33. package/src/runtime/agent/orchestrator/context/collect-skills.test.mjs +153 -0
  34. package/src/runtime/agent/orchestrator/context/collect.mjs +49 -45
  35. package/src/runtime/agent/orchestrator/mcp/client.mjs +242 -15
  36. package/src/runtime/agent/orchestrator/mcp/features.test.mjs +66 -0
  37. package/src/runtime/agent/orchestrator/mcp/security.test.mjs +36 -20
  38. package/src/runtime/agent/orchestrator/providers/admission-scheduler-metrics.test.mjs +47 -0
  39. package/src/runtime/agent/orchestrator/providers/admission-scheduler.mjs +16 -3
  40. package/src/runtime/agent/orchestrator/providers/anthropic-sse.mjs +54 -33
  41. package/src/runtime/agent/orchestrator/providers/anthropic.mjs +1 -0
  42. package/src/runtime/agent/orchestrator/providers/antigravity-oauth.mjs +7 -0
  43. package/src/runtime/agent/orchestrator/providers/gemini-schema.mjs +7 -0
  44. package/src/runtime/agent/orchestrator/providers/gemini-stream.mjs +3 -8
  45. package/src/runtime/agent/orchestrator/providers/gemini.mjs +7 -0
  46. package/src/runtime/agent/orchestrator/providers/lib/anthropic-request-utils.mjs +19 -3
  47. package/src/runtime/agent/orchestrator/providers/lib/provider-replay.mjs +50 -0
  48. package/src/runtime/agent/orchestrator/providers/lib/sse-framing.mjs +93 -0
  49. package/src/runtime/agent/orchestrator/providers/media-normalization.mjs +30 -9
  50. package/src/runtime/agent/orchestrator/providers/media-parity.test.mjs +59 -0
  51. package/src/runtime/agent/orchestrator/providers/model-list-sanitize.mjs +3 -3
  52. package/src/runtime/agent/orchestrator/providers/openai-codex-identity.test.mjs +71 -0
  53. package/src/runtime/agent/orchestrator/providers/openai-codex-metadata.mjs +18 -26
  54. package/src/runtime/agent/orchestrator/providers/openai-compat-presets.mjs +8 -0
  55. package/src/runtime/agent/orchestrator/providers/openai-compat-stream.mjs +7 -0
  56. package/src/runtime/agent/orchestrator/providers/openai-compat-wire.mjs +25 -2
  57. package/src/runtime/agent/orchestrator/providers/openai-compat.mjs +35 -4
  58. package/src/runtime/agent/orchestrator/providers/openai-oauth-http-sse.mjs +47 -2
  59. package/src/runtime/agent/orchestrator/providers/openai-oauth-ws.mjs +103 -12
  60. package/src/runtime/agent/orchestrator/providers/openai-responses-payload.mjs +13 -0
  61. package/src/runtime/agent/orchestrator/providers/openai-turn-state.mjs +68 -0
  62. package/src/runtime/agent/orchestrator/providers/openai-ws-delta-parity.test.mjs +122 -6
  63. package/src/runtime/agent/orchestrator/providers/openai-ws-delta.mjs +36 -11
  64. package/src/runtime/agent/orchestrator/providers/openai-ws-pool.mjs +144 -93
  65. package/src/runtime/agent/orchestrator/providers/openai-ws-stream.mjs +18 -13
  66. package/src/runtime/agent/orchestrator/providers/provider-replay.test.mjs +288 -0
  67. package/src/runtime/agent/orchestrator/providers/sse-framing.test.mjs +719 -0
  68. package/src/runtime/agent/orchestrator/providers/stream-json-pool.mjs +399 -39
  69. package/src/runtime/agent/orchestrator/providers/stream-json-worker.mjs +26 -0
  70. package/src/runtime/agent/orchestrator/session/agent-loop.mjs +86 -7
  71. package/src/runtime/agent/orchestrator/session/agent-loop.test.mjs +222 -0
  72. package/src/runtime/agent/orchestrator/session/browser-snapshot-supersession.mjs +61 -0
  73. package/src/runtime/agent/orchestrator/session/browser-snapshot-supersession.test.mjs +83 -0
  74. package/src/runtime/agent/orchestrator/session/cache/read-cache.mjs +13 -0
  75. package/src/runtime/agent/orchestrator/session/compact/runner.mjs +26 -2
  76. package/src/runtime/agent/orchestrator/session/compact-policy.test.mjs +112 -0
  77. package/src/runtime/agent/orchestrator/session/compaction-read-reset.test.mjs +192 -0
  78. package/src/runtime/agent/orchestrator/session/context-usage-restart.test.mjs +72 -0
  79. package/src/runtime/agent/orchestrator/session/context-utils.mjs +100 -15
  80. package/src/runtime/agent/orchestrator/session/eager-dispatch.mjs +17 -1
  81. package/src/runtime/agent/orchestrator/session/eager-dispatch.test.mjs +74 -0
  82. package/src/runtime/agent/orchestrator/session/image-strip-recovery.mjs +12 -8
  83. package/src/runtime/agent/orchestrator/session/image-strip-recovery.test.mjs +20 -1
  84. package/src/runtime/agent/orchestrator/session/loop/compact-policy.mjs +110 -2
  85. package/src/runtime/agent/orchestrator/session/loop/pre-dispatch-deny.mjs +3 -16
  86. package/src/runtime/agent/orchestrator/session/loop/pre-dispatch-deny.test.mjs +28 -0
  87. package/src/runtime/agent/orchestrator/session/loop/recall-fasttrack.mjs +2 -2
  88. package/src/runtime/agent/orchestrator/session/loop/steering.mjs +6 -0
  89. package/src/runtime/agent/orchestrator/session/loop/tool-exec.mjs +15 -1
  90. package/src/runtime/agent/orchestrator/session/loop/tool-helpers.mjs +6 -0
  91. package/src/runtime/agent/orchestrator/session/manager/ask-session.mjs +111 -39
  92. package/src/runtime/agent/orchestrator/session/manager/ask-session.test.mjs +46 -0
  93. package/src/runtime/agent/orchestrator/session/manager/compaction-runner.mjs +30 -6
  94. package/src/runtime/agent/orchestrator/session/manager/message-sanitize.mjs +3 -0
  95. package/src/runtime/agent/orchestrator/session/manager/session-crud.mjs +27 -3
  96. package/src/runtime/agent/orchestrator/session/manager/session-lifecycle.mjs +26 -54
  97. package/src/runtime/agent/orchestrator/session/manager/session-lifecycle.test.mjs +63 -1
  98. package/src/runtime/agent/orchestrator/session/manager/status-telemetry.mjs +3 -0
  99. package/src/runtime/agent/orchestrator/session/manager/tool-resolution.mjs +4 -110
  100. package/src/runtime/agent/orchestrator/session/manager/turn-checkpoint-journal.mjs +580 -0
  101. package/src/runtime/agent/orchestrator/session/manager/turn-checkpoint-journal.test.mjs +593 -0
  102. package/src/runtime/agent/orchestrator/session/manager/turn-checkpoint.mjs +119 -190
  103. package/src/runtime/agent/orchestrator/session/manager/turn-interruption.mjs +115 -0
  104. package/src/runtime/agent/orchestrator/session/pre-send-compact.mjs +43 -8
  105. package/src/runtime/agent/orchestrator/session/provider-prefix-guard.mjs +129 -12
  106. package/src/runtime/agent/orchestrator/session/send-with-recovery.mjs +9 -2
  107. package/src/runtime/agent/orchestrator/session/store/listing.mjs +8 -1
  108. package/src/runtime/agent/orchestrator/session/store/save-worker.mjs +15 -1
  109. package/src/runtime/agent/orchestrator/session/store-live-publication.test.mjs +83 -0
  110. package/src/runtime/agent/orchestrator/session/store-summary-index.mjs +36 -2
  111. package/src/runtime/agent/orchestrator/session/store-summary-reader.mjs +157 -30
  112. package/src/runtime/agent/orchestrator/session/store-summary-reader.test.mjs +64 -0
  113. package/src/runtime/agent/orchestrator/session/store-summary-visibility.mjs +57 -0
  114. package/src/runtime/agent/orchestrator/session/store-summary-visibility.test.mjs +219 -0
  115. package/src/runtime/agent/orchestrator/session/store.mjs +26 -2
  116. package/src/runtime/agent/orchestrator/session/tool-batch.mjs +22 -0
  117. package/src/runtime/agent/orchestrator/tools/builtin/bash-tool-cwd-env.test.mjs +14 -0
  118. package/src/runtime/agent/orchestrator/tools/builtin/bash-tool.mjs +19 -10
  119. package/src/runtime/agent/orchestrator/tools/builtin/find-search-budget.test.mjs +30 -14
  120. package/src/runtime/agent/orchestrator/tools/builtin/git-command-policy.mjs +15 -4
  121. package/src/runtime/agent/orchestrator/tools/builtin/git-command-tool.mjs +73 -15
  122. package/src/runtime/agent/orchestrator/tools/builtin/git-command-tool.test.mjs +76 -2
  123. package/src/runtime/agent/orchestrator/tools/builtin/list-tool.mjs +24 -683
  124. package/src/runtime/agent/orchestrator/tools/builtin/native-search-client.mjs +64 -72
  125. package/src/runtime/agent/orchestrator/tools/builtin/native-search-runner.mjs +2 -5
  126. package/src/runtime/agent/orchestrator/tools/builtin/native-search-transport.mjs +75 -0
  127. package/src/runtime/agent/orchestrator/tools/builtin/native-search-transport.test.mjs +24 -0
  128. package/src/runtime/agent/orchestrator/tools/builtin/read-special-files.mjs +6 -6
  129. package/src/runtime/agent/orchestrator/tools/code-graph/build.mjs +12 -0
  130. package/src/runtime/agent/orchestrator/tools/code-graph/constants.mjs +4 -1
  131. package/src/runtime/agent/orchestrator/tools/code-graph/dispatch.mjs +24 -5
  132. package/src/runtime/agent/orchestrator/tools/code-graph/dispatch.test.mjs +44 -0
  133. package/src/runtime/agent/orchestrator/tools/code-graph/graph-binary.mjs +12 -2
  134. package/src/runtime/agent/orchestrator/tools/code-graph/graph-model.mjs +35 -21
  135. package/src/runtime/agent/orchestrator/tools/code-graph/memory-cache.mjs +28 -13
  136. package/src/runtime/agent/orchestrator/tools/code-graph/memory-cache.test.mjs +54 -0
  137. package/src/runtime/agent/orchestrator/tools/graph-manifest.json +11 -11
  138. package/src/runtime/agent/orchestrator/tools/patch-manifest.json +11 -11
  139. package/src/runtime/agent/orchestrator/tools/progress-message.mjs +12 -0
  140. package/src/runtime/agent/orchestrator/tools/spawn-manifest.json +11 -11
  141. package/src/runtime/attachments/pdf-extract.mjs +3 -0
  142. package/src/runtime/attachments/pdfjs-runtime.mjs +13 -0
  143. package/src/runtime/bridge-clients.test.mjs +827 -0
  144. package/src/runtime/browser-bridge/action-schema.mjs +251 -0
  145. package/src/runtime/browser-bridge/client.mjs +152 -0
  146. package/src/runtime/browser-bridge/tool-defs.mjs +159 -0
  147. package/src/runtime/computer-bridge/action-schema.mjs +653 -0
  148. package/src/runtime/computer-bridge/client.mjs +231 -0
  149. package/src/runtime/computer-bridge/tool-defs.mjs +33 -0
  150. package/src/runtime/media/store.mjs +18 -8
  151. package/src/runtime/media/store.test.mjs +14 -0
  152. package/src/runtime/memory/index.mjs +1 -1
  153. package/src/runtime/memory/lib/transcript-ingest.mjs +8 -6
  154. package/src/runtime/memory/lib/transcript-ingest.test.mjs +52 -0
  155. package/src/runtime/office/assurance-benchmark.mjs +358 -0
  156. package/src/runtime/office/assurance.mjs +833 -0
  157. package/src/runtime/office/benchmark.mjs +496 -0
  158. package/src/runtime/office/capabilities.mjs +551 -0
  159. package/src/runtime/office/com-adapter.mjs +283 -0
  160. package/src/runtime/office/content-model.mjs +183 -0
  161. package/src/runtime/office/contract-benchmark.mjs +105 -0
  162. package/src/runtime/office/design-library.mjs +1562 -0
  163. package/src/runtime/office/design-system.mjs +1966 -0
  164. package/src/runtime/office/index.mjs +2413 -0
  165. package/src/runtime/office/journal.mjs +82 -0
  166. package/src/runtime/office/office-assurance.test.mjs +371 -0
  167. package/src/runtime/office/office-com-host.ps1 +3781 -0
  168. package/src/runtime/office/office-com-session-host.ps1 +855 -0
  169. package/src/runtime/office/office-live-runtime.test.mjs +819 -0
  170. package/src/runtime/office/office-runtime.test.mjs +2070 -0
  171. package/src/runtime/office/ooxml-validator.mjs +271 -0
  172. package/src/runtime/office/pagination.mjs +132 -0
  173. package/src/runtime/office/pdf-adapter.mjs +591 -0
  174. package/src/runtime/office/pdf-analysis.mjs +372 -0
  175. package/src/runtime/office/pdf-render.mjs +167 -0
  176. package/src/runtime/office/pdf-security.mjs +63 -0
  177. package/src/runtime/office/polish-benchmark.mjs +190 -0
  178. package/src/runtime/office/portable-ooxml.mjs +1867 -0
  179. package/src/runtime/office/quality-live-benchmark.mjs +486 -0
  180. package/src/runtime/office/quality-pipeline.mjs +136 -0
  181. package/src/runtime/office/tabular.mjs +302 -0
  182. package/src/runtime/office/templates/mixdog-executive.pptx +0 -0
  183. package/src/runtime/office/templates/mixdog-executive.pptx.mixdog.json +190 -0
  184. package/src/runtime/office/tool-defs.mjs +113 -0
  185. package/src/runtime/office/visual-diff.mjs +89 -0
  186. package/src/runtime/office/xlsx-assertions.mjs +172 -0
  187. package/src/runtime/office/xlsx-contract.mjs +147 -0
  188. package/src/runtime/shared/agent-route-config.mjs +9 -0
  189. package/src/runtime/shared/child-spawn-gate.mjs +17 -0
  190. package/src/runtime/shared/child-spawn-remote.mjs +69 -7
  191. package/src/runtime/shared/child-spawn-remote.test.mjs +124 -0
  192. package/src/runtime/shared/pristine-execution-contract.json +2 -1
  193. package/src/runtime/shared/provider-api-key.mjs +1 -0
  194. package/src/runtime/shared/session-runtime-health.mjs +91 -0
  195. package/src/runtime/shared/session-runtime-health.test.mjs +53 -0
  196. package/src/runtime/shared/skill-document.mjs +86 -0
  197. package/src/runtime/shared/skill-document.test.mjs +81 -0
  198. package/src/runtime/shared/tool-execution-contract.mjs +16 -0
  199. package/src/runtime/shared/tool-surface.mjs +27 -0
  200. package/src/runtime/shared/turn-snapshot-store.mjs +1 -0
  201. package/src/runtime/shared/turn-snapshot.mjs +32 -9
  202. package/src/runtime/shared/user-cwd.mjs +33 -14
  203. package/src/runtime/shared/user-cwd.test.mjs +43 -0
  204. package/src/session-runtime/agent-disable.test.mjs +20 -1
  205. package/src/session-runtime/context-status.mjs +9 -3
  206. package/src/session-runtime/cwd-plugins.mjs +26 -26
  207. package/src/session-runtime/cwd-plugins.test.mjs +75 -0
  208. package/src/session-runtime/cwd-tool-routing.test.mjs +5 -0
  209. package/src/session-runtime/deferred-tool-delta.mjs +104 -0
  210. package/src/session-runtime/deferred-tool-delta.test.mjs +40 -0
  211. package/src/session-runtime/global-extensions.mjs +26 -0
  212. package/src/session-runtime/global-extensions.test.mjs +28 -0
  213. package/src/session-runtime/global-settings-session-identity.test.mjs +76 -0
  214. package/src/session-runtime/goal-runtime.mjs +1141 -0
  215. package/src/session-runtime/goal-runtime.test.mjs +645 -0
  216. package/src/session-runtime/lifecycle-api.mjs +58 -11
  217. package/src/session-runtime/lifecycle-api.test.mjs +183 -0
  218. package/src/session-runtime/mcp-glue.mjs +49 -47
  219. package/src/session-runtime/plugin-mcp-standard.test.mjs +177 -0
  220. package/src/session-runtime/plugin-mcp.mjs +96 -22
  221. package/src/session-runtime/prewarm.mjs +1 -10
  222. package/src/session-runtime/provider-request-snapshot.mjs +33 -9
  223. package/src/session-runtime/provider-request-snapshot.test.mjs +27 -5
  224. package/src/session-runtime/resource-api-global.test.mjs +109 -0
  225. package/src/session-runtime/resource-api.mjs +168 -116
  226. package/src/session-runtime/runtime-core.mjs +208 -29
  227. package/src/session-runtime/runtime-tunables.mjs +6 -8
  228. package/src/session-runtime/session-lifecycle.mjs +34 -12
  229. package/src/session-runtime/session-title.mjs +2 -2
  230. package/src/session-runtime/session-turn-api.mjs +37 -25
  231. package/src/session-runtime/skills-api.mjs +79 -25
  232. package/src/session-runtime/skills-api.test.mjs +99 -0
  233. package/src/session-runtime/tool-catalog-data.mjs +1 -1
  234. package/src/session-runtime/tool-catalog-schema.mjs +0 -5
  235. package/src/session-runtime/tool-catalog.mjs +42 -112
  236. package/src/session-runtime/tool-defs.mjs +6 -1
  237. package/src/session-runtime/tool-policy-surface.test.mjs +93 -17
  238. package/src/session-runtime/tool-surface.mjs +30 -8
  239. package/src/session-runtime/workflow-agents-api.mjs +8 -25
  240. package/src/session-runtime/workflow.mjs +8 -6
  241. package/src/standalone/agent-dispatch-broker.mjs +5 -9
  242. package/src/standalone/agent-tool/helpers.mjs +2 -2
  243. package/src/standalone/agent-tool/job-views.mjs +3 -1
  244. package/src/standalone/agent-tool/notify.mjs +11 -9
  245. package/src/standalone/agent-tool/notify.test.mjs +37 -0
  246. package/src/standalone/agent-tool/render.mjs +3 -0
  247. package/src/standalone/agent-tool/spawn-flow.mjs +61 -16
  248. package/src/standalone/agent-tool/spawn-flow.test.mjs +41 -0
  249. package/src/standalone/agent-tool/tool-def.mjs +1 -1
  250. package/src/standalone/agent-tool/worker-index.mjs +123 -0
  251. package/src/standalone/agent-tool/worker-index.test.mjs +132 -0
  252. package/src/standalone/agent-tool/worker-rows.mjs +2 -1
  253. package/src/standalone/agent-tool.mjs +57 -10
  254. package/src/standalone/daemon.mjs +113 -15
  255. package/src/standalone/hook-bus/config.mjs +1 -0
  256. package/src/standalone/plugin-admin.mjs +17 -0
  257. package/src/standalone/plugin-admin.test.mjs +7 -0
  258. package/src/standalone/provider-admin.mjs +1 -0
  259. package/src/standalone/session-protocol.mjs +5 -0
  260. package/src/standalone/session-runtime-agent-control-client.mjs +133 -0
  261. package/src/standalone/session-runtime-agent-control-client.test.mjs +71 -0
  262. package/src/standalone/session-runtime-dispatch-cancel.test.mjs +139 -0
  263. package/src/standalone/session-runtime-host-factory.mjs +17 -0
  264. package/src/standalone/session-runtime-host-factory.test.mjs +31 -0
  265. package/src/standalone/session-runtime-host-health.test.mjs +5 -0
  266. package/src/standalone/session-runtime-host.mjs +709 -58
  267. package/src/standalone/session-runtime-inline-host.mjs +258 -0
  268. package/src/standalone/session-runtime-inline-host.test.mjs +385 -0
  269. package/src/standalone/session-runtime-provider-cooldown.mjs +78 -0
  270. package/src/standalone/session-runtime-provider-cooldown.test.mjs +80 -0
  271. package/src/standalone/session-runtime-shard-host.test.mjs +642 -0
  272. package/src/standalone/session-runtime-shard-router.mjs +149 -0
  273. package/src/standalone/session-runtime-shard-router.test.mjs +101 -0
  274. package/src/standalone/session-runtime-worker.mjs +302 -26
  275. package/src/standalone/session-service-agent-tree.test.mjs +984 -0
  276. package/src/standalone/session-service-goal-recovery.test.mjs +177 -0
  277. package/src/standalone/session-service.mjs +711 -11
  278. package/src/tui/app/app-view.jsx +1 -0
  279. package/src/tui/app/core-memory-picker.mjs +2 -0
  280. package/src/tui/app/extension-pickers.mjs +1 -1
  281. package/src/tui/app/maintenance-pickers.mjs +3 -3
  282. package/src/tui/app/model-options.mjs +2 -0
  283. package/src/tui/app/model-picker.mjs +14 -4
  284. package/src/tui/app/panel-handoff.test.mjs +311 -0
  285. package/src/tui/app/project-picker.mjs +1 -0
  286. package/src/tui/app/route-pickers.mjs +21 -6
  287. package/src/tui/app/settings-picker.mjs +26 -3
  288. package/src/tui/app/slash-commands.mjs +1 -0
  289. package/src/tui/app/slash-dispatch.mjs +73 -22
  290. package/src/tui/app/theme-effort-pickers.mjs +7 -2
  291. package/src/tui/components/Picker.jsx +10 -1
  292. package/src/tui/dist/index.mjs +187 -45
  293. package/src/tui/lib/voice-setup.mjs +4 -1
  294. package/src/tui/session/agent-message-source.test.mjs +37 -0
  295. package/src/tui/session/completion-card-restore.test.mjs +50 -0
  296. package/src/tui/session/context-state.mjs +3 -13
  297. package/src/tui/session/goal-continuation.mjs +141 -0
  298. package/src/tui/session/goal-continuation.test.mjs +203 -0
  299. package/src/tui/session/queue-helpers.mjs +5 -2
  300. package/src/tui/session/session-action-surface.test.mjs +190 -0
  301. package/src/tui/session/session-api-ext.mjs +48 -8
  302. package/src/tui/session/session-api.mjs +73 -1
  303. package/src/tui/session/session-flow.mjs +31 -1
  304. package/src/tui/session/turn.mjs +88 -15
  305. package/src/tui/session-local.mjs +39 -3
  306. package/src/vendor/statusline/src/gateway/route-meta.mjs +31 -0
  307. package/src/runtime/agent/orchestrator/tools/builtin/fuzzy-match.mjs +0 -301
@@ -669,7 +669,8 @@ var init_provider_api_key = __esm({
669
669
  gemini: "GEMINI_API_KEY",
670
670
  deepseek: "DEEPSEEK_API_KEY",
671
671
  xai: "XAI_API_KEY",
672
- "opencode-go": "OPENCODE_API_KEY"
672
+ "opencode-go": "OPENCODE_API_KEY",
673
+ openrouter: "OPENROUTER_API_KEY"
673
674
  });
674
675
  AGENT_PROVIDER_ENV_ALIASES = Object.freeze({
675
676
  xai: ["GROK_API_KEY"]
@@ -3873,6 +3874,12 @@ function displayToolName(name, args = {}) {
3873
3874
  case "web_fetch":
3874
3875
  case "fetch":
3875
3876
  return "Fetch";
3877
+ case "browser":
3878
+ return "Browser";
3879
+ case "computer":
3880
+ return "Computer";
3881
+ case "office":
3882
+ return "Office";
3876
3883
  case "list_mcp_resources":
3877
3884
  case "list_mcp_resource_templates":
3878
3885
  case "cwd":
@@ -3993,6 +4000,21 @@ function summarizeToolArgs(name, args, { max = DEFAULT_SUMMARY_MAX } = {}) {
3993
4000
  return formatCountedUnit(collectionCount(a.url, a.uri), "URL", "URLs");
3994
4001
  }
3995
4002
  return truncateToolText(a.url || a.uri || "", max);
4003
+ case "browser":
4004
+ return compactParts([
4005
+ String(a.action || ""),
4006
+ a.url ? truncateToolText(a.url, max) : a.ref ? String(a.ref) : ""
4007
+ ]);
4008
+ case "computer":
4009
+ return compactParts([
4010
+ String(a.action || ""),
4011
+ a.window ? truncateToolText(a.window, max) : a.ref ? String(a.ref) : a.app ? truncateToolText(a.app, max) : ""
4012
+ ]);
4013
+ case "office":
4014
+ return compactParts([
4015
+ String(a.action || ""),
4016
+ a.path ? truncateToolText(a.path, max) : a.session ? String(a.session) : ""
4017
+ ]);
3996
4018
  case "read_mcp_resource":
3997
4019
  return truncateToolText(a.uri || "", max);
3998
4020
  case "list_mcp_resources":
@@ -4257,6 +4279,12 @@ function toolWorkUnit(name, args = {}, category = "") {
4257
4279
  return unitDescriptor("Web Research", { count: queryCount(a, "query", "queries", "keywords") || 1, noun: "query", pluralNoun: "queries" });
4258
4280
  case "web_fetch":
4259
4281
  return unitDescriptor("Web Research", { count: queryCount(a, "url", "urls", "uri", "uris") || 1, active: "Fetching", done: "Fetched", noun: "URL", pluralNoun: "URLs" });
4282
+ case "browser":
4283
+ return unitDescriptor("Browser", { count: 1, active: "Browsing", done: "Browsed", noun: "action" });
4284
+ case "computer":
4285
+ return unitDescriptor("Computer", { count: 1, active: "Operating", done: "Operated", noun: "action" });
4286
+ case "office":
4287
+ return unitDescriptor("Office", { count: 1, active: "Editing", done: "Edited", noun: "document action" });
4260
4288
  case "fetch": {
4261
4289
  const fetchLimit = Number(a.limit ?? a.messages);
4262
4290
  const fetchCount = Number.isFinite(fetchLimit) && fetchLimit > 0 ? Math.floor(fetchLimit) : queryCount(a, "messages") || 1;
@@ -5275,6 +5303,16 @@ import { join as join7 } from "node:path";
5275
5303
  init_plugin_paths();
5276
5304
  init_config();
5277
5305
 
5306
+ // src/runtime/shared/agent-route-config.mjs
5307
+ var DEFAULT_DISABLED_AGENT_IDS = Object.freeze([
5308
+ "worker",
5309
+ "heavy-worker",
5310
+ "reviewer",
5311
+ "security",
5312
+ "front-worker",
5313
+ "writer"
5314
+ ]);
5315
+
5278
5316
  // src/runtime/agent/orchestrator/providers/oauth-credential-probes.mjs
5279
5317
  init_plugin_paths();
5280
5318
  import { join as join6 } from "node:path";
@@ -7464,6 +7502,10 @@ function Picker({
7464
7502
  indexMode = "auto",
7465
7503
  fillHeight = false,
7466
7504
  visibleCount = MAX_VISIBLE,
7505
+ // Loading panels reserve the same content-row geometry as the real list.
7506
+ // This prevents an `(empty)` row from being replaced by a multi-row menu in
7507
+ // one commit, which reads as the option items jumping into place.
7508
+ loading = false,
7467
7509
  // Onboarding confirm bar: { buttons:[{value,label}], onConfirm(button,index) }.
7468
7510
  // When present, ←/→ and Tab drive button focus (mutually exclusive with
7469
7511
  // onLeft/onRight), and Enter fires onConfirm while a button is focused.
@@ -7644,6 +7686,7 @@ function Picker({
7644
7686
  );
7645
7687
  if (items.length === 0) {
7646
7688
  const emptyLine = truncateText(String(description || "").replace(/\s+/g, " ").trim(), Math.max(0, columns - 4));
7689
+ const loadingRows = loading ? Array.from({ length: visibleLimit }, (_, index) => /* @__PURE__ */ jsx6(Text6, { color: theme.inactive, children: " " }, `loading-${index}`)) : null;
7647
7690
  return /* @__PURE__ */ jsx6(Box6, { flexDirection: "column", flexShrink: 0, height: fillHeight ? "100%" : void 0, children: /* @__PURE__ */ jsxs4(
7648
7691
  Box6,
7649
7692
  {
@@ -7661,7 +7704,7 @@ function Picker({
7661
7704
  /* @__PURE__ */ jsx6(Text6, { children: " " }),
7662
7705
  /* @__PURE__ */ jsx6(Text6, { color: theme.text, children: emptyLine || " " }),
7663
7706
  /* @__PURE__ */ jsx6(Text6, { children: " " }),
7664
- /* @__PURE__ */ jsx6(Text6, { color: theme.inactive, children: "(empty)" }),
7707
+ loading ? loadingRows : /* @__PURE__ */ jsx6(Text6, { color: theme.inactive, children: "(empty)" }),
7665
7708
  hasConfirm ? /* @__PURE__ */ jsxs4(Fragment3, { children: [
7666
7709
  /* @__PURE__ */ jsx6(Box6, { flexGrow: 1 }),
7667
7710
  /* @__PURE__ */ jsx6(Text6, { children: " " }),
@@ -9372,6 +9415,7 @@ var SLASH_COMMANDS = [
9372
9415
  { name: "clear", usage: "/clear", aliases: ["new"], aliasUsage: ["new"], description: "Start a fresh chat" },
9373
9416
  { name: "project", usage: "/project", aliases: ["projects"], aliasUsage: ["projects"], showAliasUsage: false, params: "[path]", description: "Switch working directory (project)" },
9374
9417
  { name: "compact", usage: "/compact", description: "Compact older conversation context" },
9418
+ { name: "goal", usage: "/goal", params: "[objective --time 1h|status|pause|resume|edit|complete|clear]", description: "Run and manage a durable session Goal" },
9375
9419
  { name: "autoclear", usage: "/autoclear", params: "[on|off|duration]", description: "Reduce cache-miss cost after long idle gaps" },
9376
9420
  { name: "resume", usage: "/resume", params: "[id]", description: "Resume a saved chat" },
9377
9421
  { name: "context", usage: "/context", description: "Show current context surface" },
@@ -17166,6 +17210,7 @@ function renderAppView(ctx) {
17166
17210
  indexMode: picker.indexMode,
17167
17211
  visibleCount: pickerVisibleRows,
17168
17212
  fillHeight: expandedOptionPanel,
17213
+ loading: picker.loading === true,
17169
17214
  themeEpoch: state.themeEpoch || 0,
17170
17215
  confirmBar: picker.confirmBar
17171
17216
  },
@@ -17543,6 +17588,7 @@ function createThemeEffortPickers({
17543
17588
  const openThemePicker = (options = {}) => {
17544
17589
  const returnTo = typeof options.returnTo === "function" ? options.returnTo : null;
17545
17590
  const onboarding = options.onboarding || null;
17591
+ const handoffPanel = options.handoffPanel && typeof options.handoffPanel === "object" ? options.handoffPanel : null;
17546
17592
  const own = surface.claim();
17547
17593
  let themes = [];
17548
17594
  try {
@@ -17577,7 +17623,8 @@ function createThemeEffortPickers({
17577
17623
  }
17578
17624
  };
17579
17625
  const saveTheme = (id, { advance = false } = {}) => {
17580
- own.close();
17626
+ if (handoffPanel) own.paint(handoffPanel);
17627
+ else own.close();
17581
17628
  const applied = applyTheme(id, { persist: true });
17582
17629
  store.pushNotice(themeNotice(applied || { id }), "info");
17583
17630
  if (advance && onboarding) onboarding.onAdvance?.();
@@ -17618,7 +17665,8 @@ function createThemeEffortPickers({
17618
17665
  saveTheme(entry.id, { advance: Boolean(onboarding) });
17619
17666
  },
17620
17667
  onCancel: () => {
17621
- own.close();
17668
+ if (handoffPanel) own.paint(handoffPanel);
17669
+ else own.close();
17622
17670
  if (currentId) applyTheme(currentId, { persist: false });
17623
17671
  if (onboarding) onboarding.onCancel?.();
17624
17672
  else if (returnTo) returnTo();
@@ -17730,6 +17778,7 @@ function createCoreMemoryPicker({
17730
17778
  // Loading state lives in the header description row, not as a fake
17731
17779
  // selectable menu item.
17732
17780
  description: "Loading memories\u2026",
17781
+ loading: true,
17733
17782
  items: [],
17734
17783
  onSelect: () => {
17735
17784
  },
@@ -17793,6 +17842,7 @@ function createCoreMemoryPicker({
17793
17842
  paintPanel({
17794
17843
  title: "Memory \xB7 List",
17795
17844
  description: "Loading memories\u2026",
17845
+ loading: true,
17796
17846
  items: [],
17797
17847
  onSelect: () => {
17798
17848
  },
@@ -17956,7 +18006,7 @@ function createExtensionPickers({
17956
18006
  mcpActive = true;
17957
18007
  };
17958
18008
  const openMcpPicker = () => {
17959
- openMcpServersPicker();
18009
+ return openMcpServersPicker();
17960
18010
  };
17961
18011
  const skillsStatus = async () => {
17962
18012
  let status;
@@ -18488,7 +18538,7 @@ function createMaintenancePickers({
18488
18538
  settled();
18489
18539
  });
18490
18540
  };
18491
- void Promise.resolve(render2({ checking: true })).catch((e) => {
18541
+ return Promise.resolve(render2({ checking: true })).catch((e) => {
18492
18542
  store.pushNotice(`update panel failed: ${e?.message || e}`, "error");
18493
18543
  return false;
18494
18544
  }).then((painted) => {
@@ -18621,8 +18671,7 @@ function createMaintenancePickers({
18621
18671
  setSettingsPrompt(null);
18622
18672
  own.context(null);
18623
18673
  closeUsagePanel();
18624
- if (options.advanced === true) renderAdvanced();
18625
- else render2();
18674
+ return Promise.resolve(options.advanced === true ? renderAdvanced() : render2()).catch((e) => store.pushNotice(`auto-clear panel failed: ${e?.message || e}`, "error"));
18626
18675
  };
18627
18676
  const openProfilePicker = async (options = {}) => {
18628
18677
  const returnTo = typeof options.returnTo === "function" ? options.returnTo : null;
@@ -18867,6 +18916,7 @@ var providerDisplayName = (provider) => {
18867
18916
  if (key === "xai" || key === "xai-api") return "xAI API";
18868
18917
  if (key === "deepseek" || key === "deepseek-api") return "DeepSeek API";
18869
18918
  if (key === "opencode-go") return "OpenCode Go API";
18919
+ if (key === "openrouter") return "OpenRouter";
18870
18920
  if (key === "ollama") return "Ollama";
18871
18921
  if (key === "lmstudio") return "LM Studio";
18872
18922
  if (key === "default") return "Default";
@@ -18882,6 +18932,7 @@ var providerDisplayRank = (provider) => {
18882
18932
  "antigravity-oauth": 31,
18883
18933
  "cursor-oauth": 32,
18884
18934
  "opencode-go": 35,
18935
+ openrouter: 36,
18885
18936
  openai: 40,
18886
18937
  "openai-api": 40,
18887
18938
  anthropic: 50,
@@ -19877,6 +19928,7 @@ function createModelPicker({
19877
19928
  const returnTo = typeof options.returnTo === "function" ? options.returnTo : null;
19878
19929
  const returnLabel = String(options.returnLabel || "Agents");
19879
19930
  const returnOnNestedCancel = options.returnOnNestedCancel === true;
19931
+ const handoffPanel = options.handoffPanel && typeof options.handoffPanel === "object" ? options.handoffPanel : null;
19880
19932
  const cancelModelPicker = () => {
19881
19933
  modelPickerClosed = true;
19882
19934
  if (returnTo) returnTo();
@@ -19893,6 +19945,7 @@ function createModelPicker({
19893
19945
  title: options.title || "Model",
19894
19946
  description: options.loadingDescription || "Loading models...",
19895
19947
  help: returnTo ? `\u2191/\u2193 Select \xB7 Enter Open \xB7 Esc ${returnLabel}` : "\u2191/\u2193 Select \xB7 Enter Open \xB7 Esc Back",
19948
+ loading: true,
19896
19949
  items: [],
19897
19950
  onCancel: cancelModelPicker
19898
19951
  });
@@ -20162,7 +20215,7 @@ ${model?.id || ""}`;
20162
20215
  if (typeof options.onImmediateSelect === "function") {
20163
20216
  options.onImmediateSelect(routeInput, selected, effort);
20164
20217
  } else {
20165
- own.paint(null);
20218
+ own.paint(handoffPanel);
20166
20219
  }
20167
20220
  const afterSelect2 = own.defer(() => {
20168
20221
  if (typeof options.onAfterSelect === "function") options.onAfterSelect();
@@ -20171,10 +20224,13 @@ ${model?.id || ""}`;
20171
20224
  if (result) clearModelCaches("all");
20172
20225
  afterSelect2();
20173
20226
  return result;
20174
- }).catch((e) => store.pushNotice(`Couldn\u2019t save model: ${e?.message || e}`, "error"));
20227
+ }).catch((e) => {
20228
+ store.pushNotice(`Couldn\u2019t save model: ${e?.message || e}`, "error");
20229
+ if (handoffPanel) afterSelect2();
20230
+ });
20175
20231
  return;
20176
20232
  }
20177
- own.paint(null);
20233
+ own.paint(handoffPanel);
20178
20234
  const afterSelect = own.defer(() => {
20179
20235
  if (typeof options.onAfterSelect === "function") options.onAfterSelect();
20180
20236
  });
@@ -20185,7 +20241,10 @@ ${model?.id || ""}`;
20185
20241
  ok ? "info" : "warn"
20186
20242
  );
20187
20243
  if (ok) afterSelect();
20188
- }).catch((e) => store.pushNotice(`Couldn\u2019t switch model: ${e?.message || e}`, "error"));
20244
+ }).catch((e) => {
20245
+ store.pushNotice(`Couldn\u2019t switch model: ${e?.message || e}`, "error");
20246
+ if (handoffPanel) afterSelect();
20247
+ });
20189
20248
  };
20190
20249
  const renderProviderModels = () => {
20191
20250
  const providerModelItems = buildProviderModelItems(models, provider, activeRoute);
@@ -20448,6 +20507,7 @@ function createRoutePickers({
20448
20507
  };
20449
20508
  const openWorkflowPicker = async (options = {}) => {
20450
20509
  const returnTo = typeof options.returnTo === "function" ? options.returnTo : null;
20510
+ const handoffPanel = options.handoffPanel && typeof options.handoffPanel === "object" ? options.handoffPanel : null;
20451
20511
  const own = surface.claim();
20452
20512
  let workflows = [];
20453
20513
  try {
@@ -20482,27 +20542,33 @@ function createRoutePickers({
20482
20542
  onSelect: (_value, item) => {
20483
20543
  const workflow = item?._workflow;
20484
20544
  if (!workflow) return;
20485
- own.paint(null);
20545
+ own.paint(handoffPanel);
20486
20546
  const returnAfterSwitch = own.defer(() => {
20487
20547
  if (returnTo) returnTo();
20488
20548
  });
20489
20549
  void store.setWorkflow?.(workflow.id).then((result) => {
20490
20550
  if (!result) {
20491
20551
  store.pushNotice("Workflow switch is already running.", "warn");
20552
+ if (handoffPanel) returnAfterSwitch();
20492
20553
  return;
20493
20554
  }
20494
20555
  store.pushNotice(workflowSwitchNotice2(result), "info");
20495
20556
  returnAfterSwitch();
20496
- }).catch((e) => store.pushNotice(`Couldn\u2019t switch workflow: ${e?.message || e}`, "error"));
20557
+ }).catch((e) => {
20558
+ store.pushNotice(`Couldn\u2019t switch workflow: ${e?.message || e}`, "error");
20559
+ if (handoffPanel) returnAfterSwitch();
20560
+ });
20497
20561
  },
20498
20562
  onCancel: () => {
20499
- own.close();
20563
+ if (handoffPanel) own.paint(handoffPanel);
20564
+ else own.close();
20500
20565
  if (returnTo) returnTo();
20501
20566
  }
20502
20567
  });
20503
20568
  };
20504
20569
  const openOutputStylePicker = async (options = {}) => {
20505
20570
  const returnTo = typeof options.returnTo === "function" ? options.returnTo : null;
20571
+ const handoffPanel = options.handoffPanel && typeof options.handoffPanel === "object" ? options.handoffPanel : null;
20506
20572
  const onboarding = options.onboarding || null;
20507
20573
  const own = surface.claim();
20508
20574
  let status = null;
@@ -20534,7 +20600,7 @@ function createRoutePickers({
20534
20600
  closeUsagePanel();
20535
20601
  const saveStyle = (styleId, { advance = false } = {}) => {
20536
20602
  if (!styleId) return;
20537
- if (!(advance && onboarding)) own.paint(null);
20603
+ if (!(advance && onboarding)) own.paint(handoffPanel);
20538
20604
  const advanceAfterSave = own.defer(() => {
20539
20605
  if (advance && onboarding) onboarding.onAdvance?.();
20540
20606
  else if (returnTo) returnTo();
@@ -20546,7 +20612,10 @@ function createRoutePickers({
20546
20612
  store.pushNotice(outputStyleNotice(result), "info");
20547
20613
  }
20548
20614
  advanceAfterSave();
20549
- }).catch((e) => store.pushNotice(`Couldn\u2019t switch output style: ${e?.message || e}`, "error"));
20615
+ }).catch((e) => {
20616
+ store.pushNotice(`Couldn\u2019t switch output style: ${e?.message || e}`, "error");
20617
+ if (handoffPanel) advanceAfterSave();
20618
+ });
20550
20619
  };
20551
20620
  own.paint({
20552
20621
  title: "Output Style",
@@ -20579,7 +20648,8 @@ function createRoutePickers({
20579
20648
  saveStyle(style.id, { advance: Boolean(onboarding) });
20580
20649
  },
20581
20650
  onCancel: () => {
20582
- own.close();
20651
+ if (handoffPanel) own.paint(handoffPanel);
20652
+ else own.close();
20583
20653
  if (onboarding) onboarding.onCancel?.();
20584
20654
  else if (returnTo) returnTo();
20585
20655
  }
@@ -20657,8 +20727,9 @@ function makeThrottledProgressNotice({ pushNotice, setProgressHint } = {}, inter
20657
20727
  const total = Number(progress.total) || 0;
20658
20728
  const downloaded = Number(progress.downloaded) || 0;
20659
20729
  const text = renderProgressBarText(progress.phase, downloaded, total);
20730
+ const percent2 = total > 0 ? Math.max(0, Math.min(100, Math.round(downloaded / total * 100))) : void 0;
20660
20731
  if (typeof setProgressHint === "function") {
20661
- setProgressHint(text, "info");
20732
+ setProgressHint(text, "info", percent2);
20662
20733
  return;
20663
20734
  }
20664
20735
  if (typeof pushNotice === "function") pushNotice(text, "info");
@@ -20749,6 +20820,15 @@ function createSettingsPicker({
20749
20820
  openMemoryCorePicker,
20750
20821
  openUpdatePicker
20751
20822
  }) {
20823
+ const settingsHandoffPanel = (description = "Loading settings...") => ({
20824
+ title: "Settings",
20825
+ description,
20826
+ help: "Esc Close",
20827
+ indexMode: "never",
20828
+ pickerKey: "settings-handoff",
20829
+ loading: true,
20830
+ items: []
20831
+ });
20752
20832
  const nextSettingsRequest = () => {
20753
20833
  if (!settingsRequestRef) return 0;
20754
20834
  settingsRequestRef.current = (Number(settingsRequestRef.current) || 0) + 1;
@@ -20758,6 +20838,7 @@ function createSettingsPicker({
20758
20838
  const buildSettingsPicker = async (opts = {}, requestId = 0) => {
20759
20839
  const own = surface.claim();
20760
20840
  const light = opts.light === true;
20841
+ if (!light && !own.paint(settingsHandoffPanel())) return;
20761
20842
  const overrides = opts.overrides || null;
20762
20843
  const heavyCache = light ? settingsHeavyCacheRef.current : null;
20763
20844
  const snapshot = await store.getSettingsSnapshot?.({ heavy: !heavyCache }) || {};
@@ -21100,14 +21181,24 @@ function createSettingsPicker({
21100
21181
  else if (item._action === "memory-enabled") toggleMemory();
21101
21182
  else if (item._action === "memory-cycles") toggleMemoryCycles();
21102
21183
  else if (item._action === "voice") applyVoice();
21103
- else if (item._action === "output-style") openOutputStylePicker({ returnTo: openSettingsPicker });
21104
- else if (item._action === "theme") openThemePicker({ returnTo: openSettingsPicker });
21105
- else if (item._action === "workflow") openWorkflowPicker({ returnTo: openSettingsPicker });
21184
+ else if (item._action === "output-style") openOutputStylePicker({
21185
+ returnTo: openSettingsPicker,
21186
+ handoffPanel: settingsHandoffPanel("Applying output style...")
21187
+ });
21188
+ else if (item._action === "theme") openThemePicker({
21189
+ returnTo: openSettingsPicker,
21190
+ handoffPanel: settingsHandoffPanel("Applying theme...")
21191
+ });
21192
+ else if (item._action === "workflow") openWorkflowPicker({
21193
+ returnTo: openSettingsPicker,
21194
+ handoffPanel: settingsHandoffPanel("Switching workflow...")
21195
+ });
21106
21196
  else if (item._action === "model") openModelPicker({
21107
21197
  returnTo: openSettingsPicker,
21108
21198
  returnLabel: "Settings",
21109
21199
  returnOnNestedCancel: true,
21110
- onAfterSelect: openSettingsPicker
21200
+ onAfterSelect: openSettingsPicker,
21201
+ handoffPanel: settingsHandoffPanel("Switching model...")
21111
21202
  });
21112
21203
  else if (item._action === "websearch") openWebSearchPicker({
21113
21204
  returnTo: openSettingsPicker,
@@ -21199,6 +21290,42 @@ function createSlashDispatch({
21199
21290
  runDoctor,
21200
21291
  requestExit
21201
21292
  }) {
21293
+ const openSlashPanel = (command, title, open) => {
21294
+ const own = surface.claim();
21295
+ if (!own.paint({
21296
+ _kind: `slash-loading:${command}`,
21297
+ title,
21298
+ description: `Loading ${title.toLowerCase()}...`,
21299
+ help: "Esc Close",
21300
+ indexMode: "never",
21301
+ pickerKey: `slash-loading:${command}`,
21302
+ loading: true,
21303
+ items: [],
21304
+ onSelect: () => {
21305
+ },
21306
+ onCancel: () => own.close()
21307
+ })) return;
21308
+ const finishUnclaimedLoading = () => {
21309
+ if (own.owns()) own.close();
21310
+ };
21311
+ try {
21312
+ const opening = open();
21313
+ if (opening && typeof opening.then === "function") {
21314
+ void Promise.resolve(opening).then(
21315
+ finishUnclaimedLoading,
21316
+ (error) => {
21317
+ finishUnclaimedLoading();
21318
+ store.pushNotice(`${title} panel failed: ${error?.message || error}`, "error");
21319
+ }
21320
+ );
21321
+ } else {
21322
+ finishUnclaimedLoading();
21323
+ }
21324
+ } catch (error) {
21325
+ finishUnclaimedLoading();
21326
+ store.pushNotice(`${title} panel failed: ${error?.message || error}`, "error");
21327
+ }
21328
+ };
21202
21329
  const runSlashCommand = (cmd, arg = "") => {
21203
21330
  const rawName = String(cmd || "").toLowerCase();
21204
21331
  cmd = normalizeSlashCommandName2(cmd);
@@ -21225,25 +21352,27 @@ function createSlashDispatch({
21225
21352
  return true;
21226
21353
  case "model":
21227
21354
  if (!arg) {
21228
- openModelPicker();
21355
+ openSlashPanel("model", "Model", () => openModelPicker());
21229
21356
  return true;
21230
21357
  }
21231
21358
  if (arg.trim().toLowerCase() === "refresh") {
21232
- openModelPicker({ refreshModels: true });
21359
+ openSlashPanel("model", "Model", () => openModelPicker({ refreshModels: true }));
21233
21360
  return true;
21234
21361
  }
21235
21362
  void store.setModel(arg).then((ok) => store.pushNotice(ok ? modelSwitchNotice2() : "Model switch is already running.", ok ? "info" : "warn")).catch((e) => store.pushNotice(`Couldn\u2019t switch model: ${e?.message || e}`, "error"));
21236
21363
  return true;
21237
21364
  case "websearch":
21238
21365
  if (arg) store.pushNotice("/websearch sets the web-search provider/model; the web_search tool uses that model when called.", "warn");
21239
- openWebSearchPicker();
21366
+ openSlashPanel("websearch", "Web Search Model", () => openWebSearchPicker());
21240
21367
  return true;
21241
21368
  case "agents":
21242
- openAgentsPicker(arg.trim().toLowerCase() === "refresh" ? { refreshModels: true } : {});
21369
+ openSlashPanel("agents", "Agents", () => openAgentsPicker(
21370
+ arg.trim().toLowerCase() === "refresh" ? { refreshModels: true } : {}
21371
+ ));
21243
21372
  return true;
21244
21373
  case "workflow":
21245
21374
  if (!arg) {
21246
- openWorkflowPicker();
21375
+ openSlashPanel("workflow", "Workflow", () => openWorkflowPicker());
21247
21376
  return true;
21248
21377
  }
21249
21378
  void store.setWorkflow?.(arg.trim()).then((result) => {
@@ -21262,7 +21391,7 @@ function createSlashDispatch({
21262
21391
  const value = arg.trim();
21263
21392
  const lower = value.toLowerCase();
21264
21393
  if (!value) {
21265
- openOutputStylePicker();
21394
+ openSlashPanel("outputstyle", "Output Style", () => openOutputStylePicker());
21266
21395
  return true;
21267
21396
  }
21268
21397
  if (lower === "status" || lower === "current" || lower === "show") {
@@ -21285,7 +21414,7 @@ function createSlashDispatch({
21285
21414
  const value = arg.trim();
21286
21415
  const lower = value.toLowerCase();
21287
21416
  if (!value) {
21288
- openThemePicker();
21417
+ openSlashPanel("theme", "Theme", () => openThemePicker());
21289
21418
  return true;
21290
21419
  }
21291
21420
  let themes = [];
@@ -21318,7 +21447,7 @@ function createSlashDispatch({
21318
21447
  case "effort": {
21319
21448
  const pendingTurn = state.busy ? " (applies from the next turn)" : "";
21320
21449
  if (!arg) {
21321
- openEffortPicker();
21450
+ openSlashPanel("effort", "Effort", () => openEffortPicker());
21322
21451
  return true;
21323
21452
  }
21324
21453
  void store.setEffort(arg).then((result) => store.pushNotice(result ? `Effort set to ${result}${pendingTurn}` : "Effort switch is already running.", result ? "info" : "warn")).catch((e) => store.pushNotice(`Couldn\u2019t switch effort: ${e?.message || e}`, "error"));
@@ -21350,23 +21479,23 @@ function createSlashDispatch({
21350
21479
  enterProject(target);
21351
21480
  return true;
21352
21481
  }
21353
- openProjectPicker();
21482
+ openSlashPanel("project", "Projects", () => openProjectPicker());
21354
21483
  return true;
21355
21484
  }
21356
21485
  case "mcp":
21357
- openMcpPicker();
21486
+ openSlashPanel("mcp", "MCP Servers", () => openMcpPicker());
21358
21487
  return true;
21359
21488
  case "skills":
21360
- openSkillsPicker();
21489
+ openSlashPanel("skills", "Skills", () => openSkillsPicker());
21361
21490
  return true;
21362
21491
  case "plugins":
21363
- openPluginsPicker();
21492
+ openSlashPanel("plugins", "Plugins", () => openPluginsPicker());
21364
21493
  return true;
21365
21494
  case "hooks":
21366
- openHooksPicker();
21495
+ openSlashPanel("hooks", "Hooks", () => openHooksPicker());
21367
21496
  return true;
21368
21497
  case "providers":
21369
- void openProviderSetupPicker();
21498
+ openSlashPanel("providers", "Providers", () => openProviderSetupPicker());
21370
21499
  return true;
21371
21500
  case "schedules":
21372
21501
  case "webhooks":
@@ -21374,7 +21503,7 @@ function createSlashDispatch({
21374
21503
  return true;
21375
21504
  case "memory": {
21376
21505
  if (!arg.trim()) {
21377
- openMemoryCorePicker({ returnTo: null });
21506
+ openSlashPanel("memory", "Memory", () => openMemoryCorePicker({ returnTo: null }));
21378
21507
  return true;
21379
21508
  }
21380
21509
  void store.memoryControl?.(parseMemoryCommand2(arg)).catch((e) => store.pushNotice(`memory failed: ${e?.message || e}`, "error"));
@@ -21383,7 +21512,7 @@ function createSlashDispatch({
21383
21512
  case "autoclear": {
21384
21513
  const value = arg.trim().toLowerCase();
21385
21514
  if (!value) {
21386
- openAutoClearPicker();
21515
+ openSlashPanel("autoclear", "Auto-clear", () => openAutoClearPicker());
21387
21516
  return true;
21388
21517
  }
21389
21518
  void Promise.resolve(
@@ -21422,6 +21551,15 @@ function createSlashDispatch({
21422
21551
  store.pushNotice("Compact done.", "info");
21423
21552
  }).catch((error) => store.pushNotice(compactFailureNotice(error), "error"));
21424
21553
  return true;
21554
+ case "goal":
21555
+ void Promise.resolve(store.goalControl?.({ command: arg })).then((result) => {
21556
+ if (!result) {
21557
+ store.pushNotice("Goal is unavailable.", "warn");
21558
+ return;
21559
+ }
21560
+ store.pushNotice(result.message || "Goal updated.", "info");
21561
+ }).catch((error) => store.pushNotice(`Goal failed: ${error?.message || error}`, "error"));
21562
+ return true;
21425
21563
  case "resume":
21426
21564
  if (state.busy) {
21427
21565
  store.pushNotice("wait for the current turn to finish before /resume", "warn");
@@ -21430,14 +21568,14 @@ function createSlashDispatch({
21430
21568
  if (arg) {
21431
21569
  void store.resume(arg).then((ok) => store.pushNotice(ok ? `Resumed ${arg}` : "Couldn\u2019t resume chat.", ok ? "info" : "warn")).catch((e) => store.pushNotice(`Couldn\u2019t resume chat: ${e?.message || e}`, "error"));
21432
21570
  } else {
21433
- openResumePicker();
21571
+ openSlashPanel("resume", "Resume", () => openResumePicker());
21434
21572
  }
21435
21573
  return true;
21436
21574
  case "usage":
21437
- openUsagePanel(arg);
21575
+ openSlashPanel("usage", "Provider Quotas", () => openUsagePanel(arg));
21438
21576
  return true;
21439
21577
  case "context":
21440
- openContextPicker();
21578
+ openSlashPanel("context", "Context Usage", () => openContextPicker());
21441
21579
  return true;
21442
21580
  case "inherit":
21443
21581
  if (state.busy) {
@@ -21457,13 +21595,13 @@ function createSlashDispatch({
21457
21595
  return true;
21458
21596
  case "settings":
21459
21597
  case "config":
21460
- openSettingsPicker();
21598
+ openSlashPanel("settings", "Settings", () => openSettingsPicker());
21461
21599
  return true;
21462
21600
  case "profile":
21463
- openProfilePicker();
21601
+ openSlashPanel("profile", "Profile", () => openProfilePicker());
21464
21602
  return true;
21465
21603
  case "update":
21466
- openUpdatePicker();
21604
+ openSlashPanel("update", "Update", () => openUpdatePicker());
21467
21605
  return true;
21468
21606
  case "doctor":
21469
21607
  if (state.commandBusy) {
@@ -22648,6 +22786,7 @@ function createProjectPicker({
22648
22786
  description: "Opening folder picker\u2026 choose a folder in the dialog window.",
22649
22787
  help: "Waiting for the system folder dialog\u2026",
22650
22788
  indexMode: "never",
22789
+ loading: true,
22651
22790
  items: [],
22652
22791
  onSelect: () => {
22653
22792
  },
@@ -23994,6 +24133,9 @@ import {
23994
24133
  } from "node:fs/promises";
23995
24134
  import { join as join9 } from "node:path";
23996
24135
 
24136
+ // src/runtime/attachments/pdfjs-runtime.mjs
24137
+ import { definePDFJSModule } from "unpdf";
24138
+
23997
24139
  // src/runtime/attachments/pdf-extract.mjs
23998
24140
  var DEFAULT_MAX_OUTPUT_BYTES = 1024 * 1024;
23999
24141
 
@@ -98,8 +98,11 @@ function makeThrottledProgressNotice({ pushNotice, setProgressHint } = {}, inter
98
98
  const total = Number(progress.total) || 0;
99
99
  const downloaded = Number(progress.downloaded) || 0;
100
100
  const text = renderProgressBarText(progress.phase, downloaded, total);
101
+ const percent = total > 0
102
+ ? Math.max(0, Math.min(100, Math.round((downloaded / total) * 100)))
103
+ : undefined;
101
104
  if (typeof setProgressHint === 'function') {
102
- setProgressHint(text, 'info');
105
+ setProgressHint(text, 'info', percent);
103
106
  return;
104
107
  }
105
108
  if (typeof pushNotice === 'function') pushNotice(text, 'info');
@@ -0,0 +1,37 @@
1
+ import assert from 'node:assert/strict';
2
+ import test from 'node:test';
3
+
4
+ import { mergeSteeringEntries } from '../../runtime/agent/orchestrator/session/loop/steering.mjs';
5
+ import { restoreTranscriptItems } from './session-api-ext.mjs';
6
+
7
+ test('restored Agent transcript preserves Lead message attribution', () => {
8
+ const items = restoreTranscriptItems([
9
+ {
10
+ role: 'user',
11
+ content: 'Review this change.',
12
+ meta: { transcript: { at: 1, sender: 'lead' } },
13
+ },
14
+ {
15
+ role: 'user',
16
+ content: 'Please explain the result.',
17
+ meta: { transcript: { at: 2, sender: 'user' } },
18
+ },
19
+ ], { sessionId: 'sess_agent' });
20
+
21
+ assert.equal(items.length, 2);
22
+ assert.equal(items[0].kind, 'user');
23
+ assert.equal(items[0].sender, 'lead');
24
+ assert.equal(items[0].text, 'Review this change.');
25
+ assert.equal(items[1].kind, 'user');
26
+ assert.equal(items[1].sender, 'user');
27
+ assert.equal(items[1].text, 'Please explain the result.');
28
+ });
29
+
30
+ test('busy Agent steering keeps User attribution metadata', () => {
31
+ const merged = mergeSteeringEntries([{
32
+ id: 'desktop-message',
33
+ content: 'Can you clarify?',
34
+ transcriptMeta: { sender: 'user' },
35
+ }]);
36
+ assert.deepEqual(merged.transcriptMeta, { sender: 'user' });
37
+ });