mixdog 1.2.0 → 1.2.2

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 (386) hide show
  1. package/README.md +7 -5
  2. package/package.json +1 -1
  3. package/scripts/gate-local.mjs +19 -3
  4. package/scripts/model-catalog-audit.mjs +1 -15
  5. package/src/agents/reviewer/AGENT.md +3 -3
  6. package/src/agents/reviewer/agent.json +1 -1
  7. package/src/defaults/shipped-history.json +5 -0
  8. package/src/defaults/skills/pptx/SKILL.md +6 -6
  9. package/src/defaults/skills/pptx/references/review.md +6 -4
  10. package/src/defaults/skills/pptx/scripts/source-extract.mjs +1 -1
  11. package/src/defaults/skills/setup/references/actions.md +13 -3
  12. package/src/defaults/skills/visualize/SKILL.md +12 -9
  13. package/src/repl/slash-commands.mjs +16 -1
  14. package/src/rules/shared/60-verification.md +3 -1
  15. package/src/rules/shared/70-delivery.md +4 -2
  16. package/src/runtime/agent/orchestrator/agent-runtime/agent-progress-watchdog.mjs +29 -4
  17. package/src/runtime/agent/orchestrator/agent-runtime/cache-strategy.mjs +10 -0
  18. package/src/runtime/agent/orchestrator/cache-mtime.mjs +26 -5
  19. package/src/runtime/agent/orchestrator/config.mjs +10 -4
  20. package/src/runtime/agent/orchestrator/context/collect.mjs +2 -1
  21. package/src/runtime/agent/orchestrator/context/deferred-tools.mjs +11 -5
  22. package/src/runtime/agent/orchestrator/context/skill-catalog.mjs +74 -21
  23. package/src/runtime/agent/orchestrator/mcp/client-config.mjs +122 -15
  24. package/src/runtime/agent/orchestrator/mcp/client-handshake.mjs +54 -11
  25. package/src/runtime/agent/orchestrator/mcp/client-transport.mjs +104 -9
  26. package/src/runtime/agent/orchestrator/mcp/client.mjs +358 -140
  27. package/src/runtime/agent/orchestrator/mcp/lazy-output-validator.mjs +25 -0
  28. package/src/runtime/agent/orchestrator/mcp/oauth-callback.mjs +103 -0
  29. package/src/runtime/agent/orchestrator/mcp/oauth-credentials.mjs +150 -0
  30. package/src/runtime/agent/orchestrator/mcp/oauth-login.mjs +111 -0
  31. package/src/runtime/agent/orchestrator/mcp/oauth-probe.mjs +87 -0
  32. package/src/runtime/agent/orchestrator/mcp/oauth-provider.mjs +95 -0
  33. package/src/runtime/agent/orchestrator/mcp/oauth-request.mjs +122 -0
  34. package/src/runtime/agent/orchestrator/mcp/oauth-shared.mjs +9 -0
  35. package/src/runtime/agent/orchestrator/mcp/oauth.mjs +229 -0
  36. package/src/runtime/agent/orchestrator/mcp/plugin-placeholders.mjs +54 -0
  37. package/src/runtime/agent/orchestrator/providers/account-pool.mjs +294 -44
  38. package/src/runtime/agent/orchestrator/providers/anthropic-api-recovery.mjs +2 -1
  39. package/src/runtime/agent/orchestrator/providers/anthropic-api-transport.mjs +94 -31
  40. package/src/runtime/agent/orchestrator/providers/anthropic-error-contract.mjs +96 -0
  41. package/src/runtime/agent/orchestrator/providers/anthropic-fast-mode.mjs +39 -18
  42. package/src/runtime/agent/orchestrator/providers/anthropic-max-tokens-recovery.mjs +55 -0
  43. package/src/runtime/agent/orchestrator/providers/anthropic-max-tokens.mjs +25 -21
  44. package/src/runtime/agent/orchestrator/providers/anthropic-messages.mjs +3 -1
  45. package/src/runtime/agent/orchestrator/providers/anthropic-midstream-recovery.mjs +18 -4
  46. package/src/runtime/agent/orchestrator/providers/anthropic-model-resolve.mjs +13 -1
  47. package/src/runtime/agent/orchestrator/providers/anthropic-oauth-client-version.mjs +1 -1
  48. package/src/runtime/agent/orchestrator/providers/anthropic-oauth-midstream.mjs +10 -1
  49. package/src/runtime/agent/orchestrator/providers/anthropic-oauth-recovery.mjs +23 -9
  50. package/src/runtime/agent/orchestrator/providers/anthropic-oauth-request/initial-status.mjs +46 -20
  51. package/src/runtime/agent/orchestrator/providers/anthropic-oauth-request.mjs +14 -9
  52. package/src/runtime/agent/orchestrator/providers/anthropic-oauth.mjs +73 -35
  53. package/src/runtime/agent/orchestrator/providers/anthropic-overload-fallback.mjs +69 -0
  54. package/src/runtime/agent/orchestrator/providers/anthropic-server-fallback.mjs +4 -0
  55. package/src/runtime/agent/orchestrator/providers/anthropic-sse.mjs +8 -1
  56. package/src/runtime/agent/orchestrator/providers/anthropic.mjs +53 -18
  57. package/src/runtime/agent/orchestrator/providers/antigravity-oauth-catalog.mjs +30 -9
  58. package/src/runtime/agent/orchestrator/providers/antigravity-oauth.mjs +7 -0
  59. package/src/runtime/agent/orchestrator/providers/antigravity-request.mjs +30 -14
  60. package/src/runtime/agent/orchestrator/providers/antigravity-response.mjs +2 -1
  61. package/src/runtime/agent/orchestrator/providers/antigravity-retry-policy.mjs +93 -0
  62. package/src/runtime/agent/orchestrator/providers/antigravity-transport.mjs +82 -9
  63. package/src/runtime/agent/orchestrator/providers/auto-effort.mjs +9 -0
  64. package/src/runtime/agent/orchestrator/providers/command-code-oauth-login.mjs +337 -0
  65. package/src/runtime/agent/orchestrator/providers/command-code-oauth-tokens.mjs +159 -0
  66. package/src/runtime/agent/orchestrator/providers/command-code-oauth.mjs +447 -0
  67. package/src/runtime/agent/orchestrator/providers/cursor-auth.mjs +38 -5
  68. package/src/runtime/agent/orchestrator/providers/cursor-client-version.mjs +1 -1
  69. package/src/runtime/agent/orchestrator/providers/cursor-wire-guards.mjs +97 -2
  70. package/src/runtime/agent/orchestrator/providers/cursor-wire-stream-bridge.mjs +102 -23
  71. package/src/runtime/agent/orchestrator/providers/cursor-wire-transport.mjs +103 -33
  72. package/src/runtime/agent/orchestrator/providers/cursor-wire.mjs +29 -6
  73. package/src/runtime/agent/orchestrator/providers/cursor.mjs +18 -1
  74. package/src/runtime/agent/orchestrator/providers/custom-provider.mjs +7 -4
  75. package/src/runtime/agent/orchestrator/providers/effort-configuration.mjs +86 -19
  76. package/src/runtime/agent/orchestrator/providers/gemini-cache-policy.mjs +1 -1
  77. package/src/runtime/agent/orchestrator/providers/gemini-cache.mjs +29 -8
  78. package/src/runtime/agent/orchestrator/providers/gemini-error-contract.mjs +191 -0
  79. package/src/runtime/agent/orchestrator/providers/gemini-family.mjs +9 -0
  80. package/src/runtime/agent/orchestrator/providers/gemini-history-signatures.mjs +9 -4
  81. package/src/runtime/agent/orchestrator/providers/gemini-response.mjs +3 -1
  82. package/src/runtime/agent/orchestrator/providers/gemini-retry-policy.mjs +180 -0
  83. package/src/runtime/agent/orchestrator/providers/gemini-schema.mjs +21 -82
  84. package/src/runtime/agent/orchestrator/providers/gemini-sdk-request.mjs +4 -1
  85. package/src/runtime/agent/orchestrator/providers/gemini-stream.mjs +71 -12
  86. package/src/runtime/agent/orchestrator/providers/gemini-thinking.mjs +21 -20
  87. package/src/runtime/agent/orchestrator/providers/gemini.mjs +97 -51
  88. package/src/runtime/agent/orchestrator/providers/grok-oauth-tokens.mjs +3 -0
  89. package/src/runtime/agent/orchestrator/providers/grok-oauth.mjs +68 -19
  90. package/src/runtime/agent/orchestrator/providers/lib/gemini-model-catalog.mjs +7 -1
  91. package/src/runtime/agent/orchestrator/providers/mimo-oauth.mjs +3 -0
  92. package/src/runtime/agent/orchestrator/providers/model-list-sanitize.mjs +2 -1
  93. package/src/runtime/agent/orchestrator/providers/model-proxy-bridge.mjs +1080 -0
  94. package/src/runtime/agent/orchestrator/providers/model-proxy-channel.d.mts +15 -0
  95. package/src/runtime/agent/orchestrator/providers/model-proxy-channel.mjs +35 -0
  96. package/src/runtime/agent/orchestrator/providers/muse-code-oauth.mjs +4 -9
  97. package/src/runtime/agent/orchestrator/providers/oauth-credential-probes.mjs +12 -0
  98. package/src/runtime/agent/orchestrator/providers/oauth-usage.mjs +6 -5
  99. package/src/runtime/agent/orchestrator/providers/openai-compat-chat-send.mjs +5 -3
  100. package/src/runtime/agent/orchestrator/providers/openai-compat-chat-stream/stream-result.mjs +22 -0
  101. package/src/runtime/agent/orchestrator/providers/openai-compat-chat-stream.mjs +1 -0
  102. package/src/runtime/agent/orchestrator/providers/openai-compat-error-contract.mjs +50 -0
  103. package/src/runtime/agent/orchestrator/providers/openai-compat-models.mjs +6 -2
  104. package/src/runtime/agent/orchestrator/providers/openai-compat-options.mjs +11 -0
  105. package/src/runtime/agent/orchestrator/providers/openai-compat-response-normalization.mjs +23 -0
  106. package/src/runtime/agent/orchestrator/providers/openai-compat-responses-events.mjs +16 -8
  107. package/src/runtime/agent/orchestrator/providers/openai-compat-responses-state.mjs +3 -2
  108. package/src/runtime/agent/orchestrator/providers/openai-compat-responses.mjs +94 -13
  109. package/src/runtime/agent/orchestrator/providers/openai-compat-retry-profile.mjs +193 -0
  110. package/src/runtime/agent/orchestrator/providers/openai-compat-stream-common.mjs +66 -2
  111. package/src/runtime/agent/orchestrator/providers/openai-compat-stream.mjs +2 -1
  112. package/src/runtime/agent/orchestrator/providers/openai-compat-wire.mjs +6 -0
  113. package/src/runtime/agent/orchestrator/providers/openai-compat-xai-send.mjs +6 -3
  114. package/src/runtime/agent/orchestrator/providers/openai-compat-xai.mjs +23 -14
  115. package/src/runtime/agent/orchestrator/providers/openai-compat.mjs +26 -6
  116. package/src/runtime/agent/orchestrator/providers/openai-direct-request.mjs +42 -25
  117. package/src/runtime/agent/orchestrator/providers/openai-error-contract.mjs +274 -0
  118. package/src/runtime/agent/orchestrator/providers/openai-http-sse-request.mjs +72 -32
  119. package/src/runtime/agent/orchestrator/providers/openai-http-sse-response-state/response-events/terminal-frames.mjs +18 -11
  120. package/src/runtime/agent/orchestrator/providers/openai-http-sse-response-state/response-outcome.mjs +1 -2
  121. package/src/runtime/agent/orchestrator/providers/openai-http-sse-response-state/response-stamps.mjs +2 -2
  122. package/src/runtime/agent/orchestrator/providers/openai-http-sse-response-state/response-state.mjs +2 -3
  123. package/src/runtime/agent/orchestrator/providers/openai-http-sse-response-state.mjs +2 -2
  124. package/src/runtime/agent/orchestrator/providers/openai-http-sse-watchdogs.mjs +1 -3
  125. package/src/runtime/agent/orchestrator/providers/openai-oauth-dispatch.mjs +34 -3
  126. package/src/runtime/agent/orchestrator/providers/openai-oauth-http-sse.mjs +5 -1
  127. package/src/runtime/agent/orchestrator/providers/openai-oauth-tokens.mjs +22 -2
  128. package/src/runtime/agent/orchestrator/providers/openai-oauth.mjs +5 -0
  129. package/src/runtime/agent/orchestrator/providers/openai-responses-input.mjs +5 -9
  130. package/src/runtime/agent/orchestrator/providers/openai-retry-policy.mjs +9 -0
  131. package/src/runtime/agent/orchestrator/providers/openai-ws-handshake.mjs +16 -8
  132. package/src/runtime/agent/orchestrator/providers/openai-ws-send-attempts/attempt-context.mjs +1 -2
  133. package/src/runtime/agent/orchestrator/providers/openai-ws-send-attempts/policy.mjs +25 -14
  134. package/src/runtime/agent/orchestrator/providers/openai-ws-terminal.mjs +18 -11
  135. package/src/runtime/agent/orchestrator/providers/openai-ws.mjs +35 -24
  136. package/src/runtime/agent/orchestrator/providers/provider-error-kind.mjs +581 -0
  137. package/src/runtime/agent/orchestrator/providers/registry.mjs +35 -9
  138. package/src/runtime/agent/orchestrator/providers/retry-backoff.mjs +46 -7
  139. package/src/runtime/agent/orchestrator/providers/retry-classification.mjs +118 -219
  140. package/src/runtime/agent/orchestrator/providers/retry-classifier.mjs +2 -0
  141. package/src/runtime/agent/orchestrator/providers/retry-executor.mjs +148 -45
  142. package/src/runtime/agent/orchestrator/providers/retry-midstream.mjs +81 -16
  143. package/src/runtime/agent/orchestrator/runtime-core/config-helpers.mjs +3 -0
  144. package/src/runtime/agent/orchestrator/runtime-core/effort.mjs +3 -0
  145. package/src/runtime/agent/orchestrator/runtime-core/extension-scopes.mjs +15 -55
  146. package/src/runtime/agent/orchestrator/runtime-core/goal-control.mjs +15 -2
  147. package/src/runtime/agent/orchestrator/runtime-core/goal-reminder.mjs +0 -18
  148. package/src/runtime/agent/orchestrator/runtime-core/model-capabilities.mjs +57 -28
  149. package/src/runtime/agent/orchestrator/runtime-core/orchestration.mjs +19 -16
  150. package/src/runtime/agent/orchestrator/runtime-core/plugin-mcp.mjs +268 -181
  151. package/src/runtime/agent/orchestrator/runtime-core/skill-tool-loading.mjs +4 -1
  152. package/src/runtime/agent/orchestrator/runtime-core/tool-catalog-schema.mjs +21 -0
  153. package/src/runtime/agent/orchestrator/runtime-core/tool-catalog.mjs +54 -3
  154. package/src/runtime/agent/orchestrator/session/catalog-db/index.mjs +284 -0
  155. package/src/runtime/agent/orchestrator/session/catalog-db/schema.mjs +270 -0
  156. package/src/runtime/agent/orchestrator/session/catalog-db/sqlite-gate.mjs +27 -0
  157. package/src/runtime/agent/orchestrator/session/catalog-db/worker.mjs +628 -0
  158. package/src/runtime/agent/orchestrator/session/compact/messages.mjs +6 -2
  159. package/src/runtime/agent/orchestrator/session/conversation-import/claude.mjs +184 -0
  160. package/src/runtime/agent/orchestrator/session/conversation-import/codex.mjs +136 -0
  161. package/src/runtime/agent/orchestrator/session/conversation-import/convert.mjs +128 -0
  162. package/src/runtime/agent/orchestrator/session/conversation-import/imported-session.mjs +127 -0
  163. package/src/runtime/agent/orchestrator/session/conversation-import/turns.mjs +101 -0
  164. package/src/runtime/agent/orchestrator/session/explicit-skills.mjs +83 -5
  165. package/src/runtime/agent/orchestrator/session/imported-message.mjs +11 -0
  166. package/src/runtime/agent/orchestrator/session/loop/completion-guards.mjs +2 -1
  167. package/src/runtime/agent/orchestrator/session/loop/loop-state.mjs +1 -1
  168. package/src/runtime/agent/orchestrator/session/loop/no-tool-turn.mjs +3 -2
  169. package/src/runtime/agent/orchestrator/session/loop/send-phase.mjs +10 -4
  170. package/src/runtime/agent/orchestrator/session/loop/steering.mjs +4 -3
  171. package/src/runtime/agent/orchestrator/session/loop/step-auto-effort.mjs +102 -18
  172. package/src/runtime/agent/orchestrator/session/loop/tool-helpers.mjs +3 -0
  173. package/src/runtime/agent/orchestrator/session/loop/tool-phase.mjs +3 -1
  174. package/src/runtime/agent/orchestrator/session/manager/ask-queue.mjs +42 -5
  175. package/src/runtime/agent/orchestrator/session/manager/ask-session.mjs +14 -3
  176. package/src/runtime/agent/orchestrator/session/manager/ask-turn-auto-effort.mjs +20 -12
  177. package/src/runtime/agent/orchestrator/session/manager/ask-turn-execute.mjs +50 -23
  178. package/src/runtime/agent/orchestrator/session/manager/ask-turn-loop-options.mjs +4 -0
  179. package/src/runtime/agent/orchestrator/session/manager/pending-message-entry.mjs +22 -14
  180. package/src/runtime/agent/orchestrator/session/manager/session-close.mjs +1 -1
  181. package/src/runtime/agent/orchestrator/session/manager/turn-interruption.mjs +18 -7
  182. package/src/runtime/agent/orchestrator/session/manager.mjs +0 -1
  183. package/src/runtime/agent/orchestrator/session/pre-send-compact.mjs +4 -3
  184. package/src/runtime/agent/orchestrator/session/send-with-recovery.mjs +155 -29
  185. package/src/runtime/agent/orchestrator/session/store/listing.mjs +6 -2
  186. package/src/runtime/agent/orchestrator/session/store/save-worker.mjs +6 -3
  187. package/src/runtime/agent/orchestrator/session/store/summary-cache.mjs +6 -0
  188. package/src/runtime/agent/orchestrator/session/store/write-guards.mjs +16 -0
  189. package/src/runtime/agent/orchestrator/session/store-agent-worker-rows.mjs +22 -10
  190. package/src/runtime/agent/orchestrator/session/store-summary-catalog.mjs +819 -0
  191. package/src/runtime/agent/orchestrator/session/store-summary-fields.mjs +12 -0
  192. package/src/runtime/agent/orchestrator/session/store-summary-index.mjs +22 -12
  193. package/src/runtime/agent/orchestrator/session/store-summary-reader-catalog-fixture.mjs +158 -0
  194. package/src/runtime/agent/orchestrator/session/store-summary-reader.mjs +183 -374
  195. package/src/runtime/agent/orchestrator/session/synthetic-user-envelope.mjs +3 -1
  196. package/src/runtime/agent/orchestrator/session/tool-batch/pre-dispatch.mjs +1 -1
  197. package/src/runtime/agent/orchestrator/session/transcript-restore/restore.mjs +41 -3
  198. package/src/runtime/agent/orchestrator/session/transcript-restore/user-text.mjs +38 -17
  199. package/src/runtime/agent/orchestrator/tools/builtin/arg-guard.mjs +2 -2
  200. package/src/runtime/agent/orchestrator/tools/builtin/bash-tool/deadline-plan.mjs +12 -15
  201. package/src/runtime/agent/orchestrator/tools/builtin/bash-tool/invocation-plan.mjs +17 -1
  202. package/src/runtime/agent/orchestrator/tools/builtin/bash-tool/spawn-env.mjs +4 -0
  203. package/src/runtime/agent/orchestrator/tools/builtin/builtin-tools.mjs +5 -5
  204. package/src/runtime/agent/orchestrator/tools/builtin/lib/list-helpers.mjs +2 -2
  205. package/src/runtime/agent/orchestrator/tools/builtin/path-diagnostics.mjs +6 -6
  206. package/src/runtime/agent/orchestrator/tools/builtin/read-range-index.mjs +173 -22
  207. package/src/runtime/agent/orchestrator/tools/builtin/read-single-guards.mjs +8 -4
  208. package/src/runtime/agent/orchestrator/tools/builtin/read-single-tool.mjs +5 -4
  209. package/src/runtime/agent/orchestrator/tools/builtin/read-source-windows.mjs +15 -2
  210. package/src/runtime/agent/orchestrator/tools/builtin/search-glob-tool.mjs +13 -10
  211. package/src/runtime/agent/orchestrator/tools/builtin/search-grep-tool.mjs +1 -1
  212. package/src/runtime/agent/orchestrator/tools/builtin/search-path-diagnostics.mjs +17 -12
  213. package/src/runtime/agent/orchestrator/tools/code-graph/dispatch/root-resolution.mjs +2 -2
  214. package/src/runtime/agent/orchestrator/tools/code-graph/dispatch.mjs +1 -1
  215. package/src/runtime/agent/orchestrator/tools/patch/apply-patch/codex-batch.mjs +4 -4
  216. package/src/runtime/agent/orchestrator/tools/patch/apply-patch/route.mjs +2 -2
  217. package/src/runtime/agent/orchestrator/tools/patch/orchestrator.mjs +1 -1
  218. package/src/runtime/agent/orchestrator/tools/patch/read-redirects.mjs +34 -30
  219. package/src/runtime/agent/orchestrator/tools/patch/sequence/units.mjs +7 -7
  220. package/src/runtime/agent/orchestrator/tools/patch/sequence.mjs +1 -1
  221. package/src/runtime/agent/orchestrator/tools/shell-snapshot.mjs +4 -0
  222. package/src/runtime/attachments/store.d.mts +3 -0
  223. package/src/runtime/channels/lib/owned-runtime/owned-start.mjs +1 -1
  224. package/src/runtime/channels/lib/webhook/session-dispatch.mjs +16 -4
  225. package/src/runtime/channels/lib/worker-main.mjs +17 -14
  226. package/src/runtime/computer-bridge/linux-readiness.mjs +0 -2
  227. package/src/runtime/effort-judge/judge-client.mjs +56 -18
  228. package/src/runtime/memory/lib/memory.mjs +1 -1
  229. package/src/runtime/memory/lib/pg/process.mjs +34 -24
  230. package/src/runtime/memory/lib/pg/supervisor.mjs +16 -13
  231. package/src/runtime/memory/lib/session-ingest.mjs +2 -2
  232. package/src/runtime/office/README.md +1 -1
  233. package/src/runtime/office/shared/values.mjs +0 -5
  234. package/src/runtime/shared/atomic-file.mjs +25 -4
  235. package/src/runtime/shared/background-tasks.mjs +92 -14
  236. package/src/runtime/shared/err-text.mjs +25 -0
  237. package/src/runtime/shared/error-presentation.mjs +159 -19
  238. package/src/runtime/shared/extension-scopes.mjs +5 -3
  239. package/src/runtime/shared/file-lock.mjs +37 -11
  240. package/src/runtime/shared/llm/anthropic-betas.mjs +4 -3
  241. package/src/runtime/shared/llm/anthropic-effort.mjs +134 -131
  242. package/src/runtime/shared/llm/anthropic-thinking-contract.mjs +50 -14
  243. package/src/runtime/shared/llm/model-catalog.mjs +53 -52
  244. package/src/runtime/shared/llm/openai-daybreak.mjs +4 -16
  245. package/src/runtime/shared/llm/provider-catalog-registry.mjs +17 -0
  246. package/src/runtime/shared/llm/provider-model-identities.mjs +13 -4
  247. package/src/runtime/shared/llm/usage-rollup.mjs +0 -1
  248. package/src/runtime/shared/model-display.mjs +13 -0
  249. package/src/runtime/shared/plugin-manifest.mjs +18 -9
  250. package/src/runtime/shared/pristine-execution-contract.json +9 -2
  251. package/src/runtime/shared/pristine-execution.mjs +28 -4
  252. package/src/runtime/shared/provider-accounts.mjs +124 -20
  253. package/src/runtime/shared/provider-api-key.mjs +12 -0
  254. package/src/runtime/shared/quota-resume-store.mjs +11 -0
  255. package/src/runtime/shared/session-baseline-store.mjs +960 -0
  256. package/src/runtime/shared/shell-display.mjs +9 -3
  257. package/src/runtime/shared/skill-mentions.d.mts +10 -0
  258. package/src/runtime/shared/skill-mentions.mjs +133 -0
  259. package/src/runtime/shared/skill-script-runtime.mjs +264 -0
  260. package/src/runtime/shared/statusline/statusline-format.mjs +4 -4
  261. package/src/runtime/shared/task-notification-envelope.mjs +2 -2
  262. package/src/runtime/shared/tool-primitives.mjs +35 -2
  263. package/src/runtime/shared/turn-changes.mjs +447 -219
  264. package/src/runtime/shared/turn-snapshot-store.mjs +182 -1
  265. package/src/runtime/shared/turn-snapshot.mjs +170 -48
  266. package/src/runtime/shared/turn-worktree-snapshot.mjs +160 -51
  267. package/src/runtime/shared/worker-requests.mjs +15 -2
  268. package/src/runtime/shared/worktrees/contract.mjs +0 -24
  269. package/src/runtime/shared/worktrees/test-support.mjs +19 -4
  270. package/src/session-runtime/automation-agents.mjs +8 -2
  271. package/src/session-runtime/boot/apis.mjs +61 -0
  272. package/src/session-runtime/boot/config.mjs +5 -2
  273. package/src/session-runtime/boot/facade.mjs +1 -0
  274. package/src/session-runtime/boot/infrastructure.mjs +35 -18
  275. package/src/session-runtime/conversation-import/discovery.mjs +698 -0
  276. package/src/session-runtime/conversation-import/service.mjs +369 -0
  277. package/src/session-runtime/cwd-plugins/cwd-apply.mjs +10 -5
  278. package/src/session-runtime/cwd-plugins/plugin-status.mjs +47 -42
  279. package/src/session-runtime/lifecycle/session-catalog.mjs +2 -0
  280. package/src/session-runtime/lifecycle/teardown.mjs +1 -1
  281. package/src/session-runtime/mcp-glue/connect.mjs +83 -16
  282. package/src/session-runtime/mcp-glue/plugin-servers.mjs +499 -0
  283. package/src/session-runtime/mcp-glue/server-catalog.mjs +135 -33
  284. package/src/session-runtime/mcp-glue.mjs +25 -2
  285. package/src/session-runtime/mcp-oauth-login.mjs +174 -0
  286. package/src/session-runtime/model-route/model-switch-target.mjs +34 -0
  287. package/src/session-runtime/model-route/set-route.mjs +83 -15
  288. package/src/session-runtime/model-route/web-search-route.mjs +1 -1
  289. package/src/session-runtime/native-web-search/routes.mjs +22 -3
  290. package/src/session-runtime/new-session-config.mjs +3 -2
  291. package/src/session-runtime/notification-bus.mjs +9 -2
  292. package/src/session-runtime/provider-auth/accounts.mjs +33 -15
  293. package/src/session-runtime/provider-models/model-meta.mjs +12 -3
  294. package/src/session-runtime/provider-models/web-search-catalog.mjs +5 -1
  295. package/src/session-runtime/provider-readiness.mjs +16 -10
  296. package/src/session-runtime/quick-model-rows/web-search-rows.mjs +13 -8
  297. package/src/session-runtime/quick-web-search-models.mjs +13 -38
  298. package/src/session-runtime/resource-extension-sync.mjs +24 -5
  299. package/src/session-runtime/resource-mcp-api.mjs +198 -78
  300. package/src/session-runtime/resource-plugins-api.mjs +29 -41
  301. package/src/session-runtime/resource-scope-decorate.mjs +6 -8
  302. package/src/session-runtime/resource-skills-api.mjs +23 -2
  303. package/src/session-runtime/runtime-review-api.mjs +13 -0
  304. package/src/session-runtime/schedule-session-run.mjs +1 -1
  305. package/src/session-runtime/services/agent-tool/job-task-reconcile.mjs +13 -1
  306. package/src/session-runtime/services/agent-tool/job-views/agent-list.mjs +7 -2
  307. package/src/session-runtime/services/agent-tool/send-flow.mjs +22 -4
  308. package/src/session-runtime/services/agent-tool/spawn-flow/job-start.mjs +2 -0
  309. package/src/session-runtime/services/agent-tool/spawn-flow/spawn-run.mjs +22 -5
  310. package/src/session-runtime/services/agent-tool/worker-index/row-liveness.mjs +8 -1
  311. package/src/session-runtime/services/agent-tool/worker-index/row-shape.mjs +2 -2
  312. package/src/session-runtime/services/agent-tool/worker-rows.mjs +17 -0
  313. package/src/session-runtime/services/channel-session-router.mjs +4 -1
  314. package/src/session-runtime/services/hook-bus/command-handler.mjs +4 -1
  315. package/src/session-runtime/services/hook-bus/handlers.mjs +7 -3
  316. package/src/session-runtime/services/provider-admin.mjs +64 -18
  317. package/src/session-runtime/services/usage-dashboard-model.mjs +3 -0
  318. package/src/session-runtime/settings-compaction-api.mjs +1 -0
  319. package/src/session-runtime/setup-tool/executor.mjs +12 -1
  320. package/src/session-runtime/setup-tool/extended-actions.mjs +1 -0
  321. package/src/session-runtime/setup-tool/settings-contract.mjs +1 -0
  322. package/src/session-runtime/setup-tool/tool-defs.mjs +7 -1
  323. package/src/session-runtime/skills-api.mjs +7 -3
  324. package/src/session-runtime/turn/turn-run/ask-callbacks.mjs +1 -0
  325. package/src/session-runtime/webhook-session-run.mjs +16 -4
  326. package/src/skill-script-entry.mjs +36 -0
  327. package/src/standalone/daemon-drain-policy.mjs +8 -0
  328. package/src/standalone/daemon-stored-session-views.mjs +11 -3
  329. package/src/standalone/daemon-telemetry.mjs +55 -0
  330. package/src/standalone/daemon.mjs +44 -11
  331. package/src/standalone/session-protocol.mjs +12 -0
  332. package/src/standalone/session-service/agent-tree/agent-cancel.mjs +33 -2
  333. package/src/standalone/session-service/agent-tree/agent-turns.mjs +26 -10
  334. package/src/standalone/session-service/agent-tree.mjs +12 -0
  335. package/src/standalone/session-service/quota-resume.mjs +8 -0
  336. package/src/standalone/session-service/retention/busy.mjs +15 -1
  337. package/src/standalone/session-service/session-calls/session-action.mjs +6 -1
  338. package/src/standalone/session-service-api.mjs +5 -0
  339. package/src/standalone/session-service.mjs +1 -0
  340. package/src/tui/App.jsx +9 -1
  341. package/src/tui/app/app-view/floating-panel.jsx +9 -1
  342. package/src/tui/app/app-view.jsx +7 -0
  343. package/src/tui/app/create-app-pickers.mjs +4 -0
  344. package/src/tui/app/extension-pickers/mcp-login.mjs +107 -0
  345. package/src/tui/app/extension-pickers/mcp-servers-picker.mjs +2 -1
  346. package/src/tui/app/extension-pickers/plugins-pickers.mjs +35 -16
  347. package/src/tui/app/extension-pickers.mjs +2 -1
  348. package/src/tui/app/model-options.mjs +13 -16
  349. package/src/tui/app/skill-mention-palette.mjs +88 -0
  350. package/src/tui/app/slash-commands.mjs +7 -2
  351. package/src/tui/app/slash-dispatch/panel-commands.mjs +16 -1
  352. package/src/tui/app/slash-palette.mjs +23 -7
  353. package/src/tui/app/transcript-row-estimate.mjs +11 -3
  354. package/src/tui/app/use-prompt-draft-flow.mjs +7 -2
  355. package/src/tui/app/use-prompt-state.mjs +5 -0
  356. package/src/tui/components/Message.jsx +22 -1
  357. package/src/tui/components/PromptInput.jsx +21 -3
  358. package/src/tui/components/SlashCommandPalette.jsx +12 -3
  359. package/src/tui/components/StatusLine.jsx +2 -0
  360. package/src/tui/components/TranscriptItem.jsx +9 -1
  361. package/src/tui/components/prompt-input/key-handler.mjs +21 -8
  362. package/src/tui/components/status-line/local-line.mjs +5 -2
  363. package/src/tui/components/status-line/use-statusline-text.mjs +7 -1
  364. package/src/tui/components/user-message-skills.mjs +38 -0
  365. package/src/tui/dist/index.mjs +1323 -214
  366. package/src/tui/session/queue-helpers.mjs +7 -2
  367. package/src/tui/session/quota-resume.mjs +46 -14
  368. package/src/tui/session/session-api/commands.mjs +33 -24
  369. package/src/tui/session/session-api/extensions.mjs +26 -2
  370. package/src/tui/session/session-api/integrations.mjs +7 -0
  371. package/src/tui/session/session-api/lifecycle.mjs +5 -1
  372. package/src/tui/session/session-api/routes.mjs +71 -7
  373. package/src/tui/session/session-api/settings.mjs +12 -14
  374. package/src/tui/session/session-flow/drain.mjs +21 -5
  375. package/src/tui/session/session-flow/failed-turn-rewind.mjs +10 -4
  376. package/src/tui/session/tui-steering-persist.mjs +25 -9
  377. package/src/tui/session/turn.mjs +55 -15
  378. package/src/tui/statusline-ansi-bridge.mjs +1 -1
  379. package/src/ui/statusline-agents.mjs +15 -4
  380. package/src/ui/statusline.mjs +7 -3
  381. package/src/ui/streaming-markdown-heal.mjs +34 -3
  382. package/src/vendor/statusline/src/gateway/claude-current.mjs +14 -4
  383. package/src/runtime/effort-judge/previous-human-request.mjs +0 -162
  384. package/src/runtime/effort-judge/verified-context-input.mjs +0 -10
  385. package/src/runtime/memory/lib/memory-session-merge.mjs +0 -32
  386. package/src/runtime/shared/llm/usage-session-history.mjs +0 -266
@@ -23394,15 +23394,30 @@ function warnLockRateLimited(warnedAt, lockPath, line) {
23394
23394
  } catch {
23395
23395
  }
23396
23396
  }
23397
- function reportLockWait(lockPath, waitedMs, mode) {
23397
+ function formatLockTiming(timing) {
23398
+ return Object.entries(timing || {}).filter(([, ms]) => Number.isFinite(ms)).map(([name, ms]) => ` ${name}=${ms}ms`).join("");
23399
+ }
23400
+ function recordLockTiming(lockPath, fields) {
23401
+ const lease = heldLockPaths.getStore()?.get(lockPath);
23402
+ if (lease?.active) Object.assign(lease.timing, fields);
23403
+ }
23404
+ function reportLockWait(lockPath, waitedMs, mode, timing) {
23398
23405
  if (waitedMs < LOCK_WAIT_WARN_MS) return;
23399
- warnLockRateLimited(lockWaitWarnedAt, lockPath, `[atomic-file] ${mode} lock wait ${waitedMs}ms: ${lockPath}
23400
- `);
23406
+ warnLockRateLimited(
23407
+ lockWaitWarnedAt,
23408
+ lockPath,
23409
+ `[atomic-file] ${mode} lock wait ${waitedMs}ms:${formatLockTiming(timing)} ${lockPath}
23410
+ `
23411
+ );
23401
23412
  }
23402
- function reportLockHeld(lockPath, heldMs, mode) {
23413
+ function reportLockHeld(lockPath, heldMs, mode, timing) {
23403
23414
  if (heldMs < LOCK_HELD_WARN_MS) return;
23404
- warnLockRateLimited(lockHeldWarnedAt, lockPath, `[atomic-file] ${mode} lock held ${heldMs}ms: ${lockPath}
23405
- `);
23415
+ warnLockRateLimited(
23416
+ lockHeldWarnedAt,
23417
+ lockPath,
23418
+ `[atomic-file] ${mode} lock held ${heldMs}ms:${formatLockTiming(timing)} ${lockPath}
23419
+ `
23420
+ );
23406
23421
  }
23407
23422
  function* tryAcquireReclaimGuard(lockPath) {
23408
23423
  const guardPath = `${lockPath}.reclaim`;
@@ -23572,7 +23587,7 @@ function sweepStagedLockFiles(lockPath, now = Date.now()) {
23572
23587
  }
23573
23588
  return removed;
23574
23589
  }
23575
- function* acquireLock(lockPath, opts, mode, markHeld) {
23590
+ function* acquireLock(lockPath, opts, mode, markHeld, timing = null) {
23576
23591
  const timeoutMs = lockTimeoutMs(opts);
23577
23592
  const staleMs = lockStaleMs(opts);
23578
23593
  const deadline = Date.now() + timeoutMs;
@@ -23599,7 +23614,9 @@ function* acquireLock(lockPath, opts, mode, markHeld) {
23599
23614
  attempt += 1;
23600
23615
  continue;
23601
23616
  }
23602
- reportLockWait(lockPath, Date.now() - waitStartedAt, mode);
23617
+ const osMs = Date.now() - waitStartedAt;
23618
+ if (timing) timing.osAcquireMs = osMs;
23619
+ reportLockWait(lockPath, osMs, mode, timing);
23603
23620
  return;
23604
23621
  }
23605
23622
  throw timeoutError(lockPath, timeoutMs, lastError, yield* describeLockHolder(lockPath));
@@ -23625,12 +23642,14 @@ function withFileLockSync(lockPath, fn, opts = {}) {
23625
23642
  async function withFileLock(lockPath, fn, opts = {}) {
23626
23643
  if (heldLockPaths.getStore()?.get(lockPath)?.active) return fn();
23627
23644
  if (lockTimeoutMs(opts) <= 0) return withOsFileLock(lockPath, fn, opts);
23628
- return lockQueue(lockPath, () => withOsFileLock(lockPath, fn, opts));
23645
+ const enqueuedAt = Date.now();
23646
+ return lockQueue(lockPath, () => withOsFileLock(lockPath, fn, opts, Date.now() - enqueuedAt));
23629
23647
  }
23630
- async function withOsFileLock(lockPath, fn, opts = {}) {
23631
- await runAsync(acquireLock(lockPath, opts, "async", true));
23648
+ async function withOsFileLock(lockPath, fn, opts = {}, queueWaitMs = 0) {
23649
+ const timing = { queueWaitMs };
23650
+ await runAsync(acquireLock(lockPath, opts, "async", true, timing));
23632
23651
  const heldSince = Date.now();
23633
- const lease = { active: false };
23652
+ const lease = { active: false, timing };
23634
23653
  try {
23635
23654
  if (opts.secret === true) await enforceOwnerOnlyAclWin32Async(lockPath, { fresh: true });
23636
23655
  const held = new Map(heldLockPaths.getStore() || []);
@@ -23642,7 +23661,7 @@ async function withOsFileLock(lockPath, fn, opts = {}) {
23642
23661
  try {
23643
23662
  await runAsync(releaseLock(lockPath));
23644
23663
  } finally {
23645
- reportLockHeld(lockPath, Date.now() - heldSince, "async");
23664
+ reportLockHeld(lockPath, Date.now() - heldSince, "async", timing);
23646
23665
  unmarkOsHeld(lockPath);
23647
23666
  }
23648
23667
  }
@@ -23919,7 +23938,28 @@ async function writeFileAtomicAsync(filePath, data, opts = {}) {
23919
23938
  throw err;
23920
23939
  }
23921
23940
  };
23922
- return opts.lock === true ? withFileLock(`${filePath}.lock`, () => _runAdaptiveFileIo(run), opts) : _runAdaptiveFileIo(run);
23941
+ if (opts.lock !== true) return _runAdaptiveFileIo(run);
23942
+ const lockPath = `${filePath}.lock`;
23943
+ return withFileLock(
23944
+ lockPath,
23945
+ async () => {
23946
+ const queuedAt = Date.now();
23947
+ let startedAt = 0;
23948
+ try {
23949
+ return await _runAdaptiveFileIo(() => {
23950
+ startedAt = Date.now();
23951
+ return run();
23952
+ });
23953
+ } finally {
23954
+ const now = Date.now();
23955
+ recordLockTiming(lockPath, {
23956
+ ioGateWaitMs: (startedAt || now) - queuedAt,
23957
+ writeMs: startedAt ? now - startedAt : 0
23958
+ });
23959
+ }
23960
+ },
23961
+ opts
23962
+ );
23923
23963
  }
23924
23964
  function writeJsonAtomicAsync(filePath, value, opts = {}) {
23925
23965
  return writeFileAtomicAsync(filePath, `${JSON.stringify(value, null, opts.compact ? 0 : 2)}
@@ -35075,7 +35115,7 @@ import { performance as performance2 } from "node:perf_hooks";
35075
35115
  import { format } from "node:util";
35076
35116
 
35077
35117
  // src/tui/App.jsx
35078
- import { useState as useState19, useCallback as useCallback29, useEffect as useEffect30, useLayoutEffect as useLayoutEffect9, useMemo as useMemo9, useRef as useRef29 } from "react";
35118
+ import { useState as useState20, useCallback as useCallback29, useEffect as useEffect31, useLayoutEffect as useLayoutEffect9, useMemo as useMemo9, useRef as useRef29 } from "react";
35079
35119
 
35080
35120
  // src/tui/hooks/useSession.mjs
35081
35121
  import { useSyncExternalStore } from "react";
@@ -35416,8 +35456,13 @@ var SLASH_COMMANDS = [
35416
35456
  { name: "theme", usage: "/theme", params: "[id]", description: "Change the TUI color theme" },
35417
35457
  { name: "agents", usage: "/agents", params: "[refresh]", description: "Show available workflow agents" },
35418
35458
  { name: "effort", usage: "/effort", params: "[level]", description: "Set reasoning effort for the current model" },
35419
- { name: "fast", usage: "/fast", params: "[on|off|ultra]", description: "Set Fast or Ultrafast mode for the current model" },
35420
- { name: "mcp", usage: "/mcp", description: "Manage MCP servers and tools" },
35459
+ {
35460
+ name: "fast",
35461
+ usage: "/fast",
35462
+ params: "[on|off|ultra]",
35463
+ description: "Set Fast or Ultrafast mode for the current model"
35464
+ },
35465
+ { name: "mcp", usage: "/mcp", params: "[login|logout <name>]", description: "Manage MCP servers and tools" },
35421
35466
  { name: "skills", usage: "/skills", description: "Choose a skill for the next request" },
35422
35467
  { name: "memory", usage: "/memory", params: "[status|core ...]", description: "List and edit core memories" },
35423
35468
  { name: "plugins", usage: "/plugins", description: "Manage local plugin integrations" },
@@ -35489,6 +35534,154 @@ function slashArgumentHint(value) {
35489
35534
  return command?.params ? `${command.usage} ${command.params}` : "";
35490
35535
  }
35491
35536
 
35537
+ // src/tui/app/skill-mention-palette.mjs
35538
+ import { useEffect as useEffect7, useState as useState6 } from "react";
35539
+
35540
+ // src/runtime/shared/skill-mentions.mjs
35541
+ var MENTION = /(^|[\s([{"'`])\$([a-z0-9][a-z0-9-]{0,63})(?![A-Za-z0-9_-])/g;
35542
+ var RESERVED_NAMES = /* @__PURE__ */ new Set([
35543
+ "path",
35544
+ "home",
35545
+ "user",
35546
+ "shell",
35547
+ "pwd",
35548
+ "tmpdir",
35549
+ "temp",
35550
+ "tmp",
35551
+ "lang",
35552
+ "term",
35553
+ "xdg_config_home",
35554
+ "userprofile",
35555
+ "appdata",
35556
+ "localappdata",
35557
+ "programfiles",
35558
+ "systemroot",
35559
+ "windir",
35560
+ "comspec"
35561
+ ]);
35562
+ function isReservedMentionName(name) {
35563
+ const value = String(name ?? "");
35564
+ return /^[0-9]+$/.test(value) || RESERVED_NAMES.has(value.toLowerCase());
35565
+ }
35566
+ var FENCE_OPEN = /^ {0,3}(`{3,}|~{3,})(.*)$/;
35567
+ var FENCE_CLOSE = /^ {0,3}(`{3,}|~{3,})[ \t]*$/;
35568
+ function inlineCodeRanges(source, from, to, ranges) {
35569
+ const runs = [];
35570
+ const re = /`+/g;
35571
+ re.lastIndex = from;
35572
+ for (let match = re.exec(source); match && match.index < to; match = re.exec(source)) {
35573
+ runs.push({ start: match.index, end: Math.min(to, match.index + match[0].length) });
35574
+ }
35575
+ for (let index = 0; index < runs.length; index += 1) {
35576
+ const length = runs[index].end - runs[index].start;
35577
+ const close = runs.findIndex((run, at) => at > index && run.end - run.start === length);
35578
+ if (close < 0) continue;
35579
+ ranges.push([runs[index].start, runs[close].end]);
35580
+ index = close;
35581
+ }
35582
+ }
35583
+ function codeRanges(source) {
35584
+ const ranges = [];
35585
+ let open = null;
35586
+ let proseStart = 0;
35587
+ for (let at = 0; at <= source.length; ) {
35588
+ const newline = source.indexOf("\n", at);
35589
+ const end = newline < 0 ? source.length : newline;
35590
+ const next = newline < 0 ? source.length + 1 : newline + 1;
35591
+ const line = source.slice(at, end).replace(/\r$/, "");
35592
+ if (!open) {
35593
+ const fence = FENCE_OPEN.exec(line);
35594
+ if (fence && !(fence[1][0] === "`" && fence[2].includes("`"))) {
35595
+ inlineCodeRanges(source, proseStart, at, ranges);
35596
+ open = { char: fence[1][0], length: fence[1].length, start: at };
35597
+ }
35598
+ } else {
35599
+ const fence = FENCE_CLOSE.exec(line);
35600
+ if (fence && fence[1][0] === open.char && fence[1].length >= open.length) {
35601
+ ranges.push([open.start, Math.min(next, source.length)]);
35602
+ proseStart = Math.min(next, source.length);
35603
+ open = null;
35604
+ }
35605
+ }
35606
+ at = next;
35607
+ }
35608
+ if (open) ranges.push([open.start, source.length]);
35609
+ else inlineCodeRanges(source, proseStart, source.length, ranges);
35610
+ return ranges;
35611
+ }
35612
+ function isInMarkdownCode(text, offset) {
35613
+ const source = typeof text === "string" ? text : "";
35614
+ if (!Number.isInteger(offset) || !source.includes("`") && !source.includes("~~~")) return false;
35615
+ return codeRanges(source).some(([from, to]) => offset >= from && offset < to);
35616
+ }
35617
+ function skillMentionCandidates(text) {
35618
+ const source = typeof text === "string" ? text : "";
35619
+ const found = [];
35620
+ let code = null;
35621
+ for (const match of source.matchAll(MENTION)) {
35622
+ if (isReservedMentionName(match[2])) continue;
35623
+ const start = match.index + match[1].length;
35624
+ code ??= source.includes("`") || source.includes("~~~") ? codeRanges(source) : [];
35625
+ if (code.some(([from, to]) => start >= from && start < to)) continue;
35626
+ found.push({ name: match[2], start, end: start + 1 + match[2].length });
35627
+ }
35628
+ return found;
35629
+ }
35630
+ function skillMentions(text, isSkill) {
35631
+ return skillMentionCandidates(text).filter((mention) => isSkill(mention.name));
35632
+ }
35633
+
35634
+ // src/tui/app/skill-mention-palette.mjs
35635
+ var MENTION_TAIL = /(^|[\s([{"'`])\$([a-z0-9][a-z0-9-]{0,63})?$/;
35636
+ var caretIn = (text, caret) => Number.isInteger(caret) ? Math.max(0, Math.min(text.length, caret)) : text.length;
35637
+ function skillMentionQuery(value, caret) {
35638
+ const text = String(value ?? "");
35639
+ const end = caretIn(text, caret);
35640
+ const match = MENTION_TAIL.exec(text.slice(0, end));
35641
+ if (!match) return null;
35642
+ const start = match.index + match[1].length;
35643
+ if (isInMarkdownCode(text, start)) return null;
35644
+ return { query: match[2] || "", start, end };
35645
+ }
35646
+ var byName = (a, b) => a.name.localeCompare(b.name, "en");
35647
+ function skillMentionItems(skills, query) {
35648
+ const needle = String(query || "").toLowerCase();
35649
+ const usable = (Array.isArray(skills) ? skills : []).filter(
35650
+ (skill) => typeof skill?.name === "string" && skill.name && skill.enabled !== false && skill.activeHere !== false && skill.source !== "builtin" && // `$path`/`$300` are never mentions, so offering them would insert prose.
35651
+ !isReservedMentionName(skill.name)
35652
+ );
35653
+ const prefix = usable.filter((skill) => skill.name.startsWith(needle)).sort(byName);
35654
+ const contains = needle ? usable.filter((skill) => !skill.name.startsWith(needle) && skill.name.includes(needle)).sort(byName) : [];
35655
+ return [...prefix, ...contains].map((skill) => ({
35656
+ kind: "skill",
35657
+ name: skill.name,
35658
+ label: `$${skill.name}`,
35659
+ description: skill.description || ""
35660
+ }));
35661
+ }
35662
+ function completeSkillMention(value, name, caret) {
35663
+ const text = String(value ?? "");
35664
+ const mention = skillMentionQuery(text, caret);
35665
+ if (!mention || !name) return void 0;
35666
+ const head = `${text.slice(0, mention.start)}$${name} `;
35667
+ return { value: head + text.slice(mention.end), cursor: head.length };
35668
+ }
35669
+ function useSkillMentionSkills(store, active) {
35670
+ const [skills, setSkills] = useState6([]);
35671
+ useEffect7(() => {
35672
+ if (!active) return void 0;
35673
+ let live = true;
35674
+ Promise.resolve().then(() => store.skillsStatus?.()).then((status) => {
35675
+ if (live) setSkills(Array.isArray(status?.skills) ? status.skills : []);
35676
+ }).catch(() => {
35677
+ });
35678
+ return () => {
35679
+ live = false;
35680
+ };
35681
+ }, [store, active]);
35682
+ return skills;
35683
+ }
35684
+
35492
35685
  // src/tui/app/slash-palette.mjs
35493
35686
  function deriveSlashPalette({
35494
35687
  providerPrompt,
@@ -35500,13 +35693,28 @@ function deriveSlashPalette({
35500
35693
  exiting,
35501
35694
  commandBusy,
35502
35695
  promptDraft,
35503
- slashDismissedFor
35696
+ slashDismissedFor,
35697
+ skills = [],
35698
+ promptCaret = null
35504
35699
  }) {
35505
35700
  const activeSlashQuery = providerPrompt || settingsPrompt || toolApproval || contextPanel || usagePanel ? null : slashQuery(promptDraft);
35506
- const slashModeLive = activeSlashQuery !== null && !picker && !toolApproval && !contextPanel && !usagePanel && !exiting && !commandBusy;
35507
- const slashCommands = !slashModeLive ? [] : SLASH_COMMANDS.filter((command) => slashCommandMatches(command, activeSlashQuery)).sort(compareSlashCommands);
35508
- const slashPaletteOpen = slashModeLive && slashDismissedFor !== promptDraft;
35509
- return { activeSlashQuery, slashCommands, slashPaletteOpen };
35701
+ const surfaceFree = !picker && !toolApproval && !contextPanel && !usagePanel && !exiting && !commandBusy;
35702
+ const slashModeLive = activeSlashQuery !== null && surfaceFree;
35703
+ if (!slashModeLive) {
35704
+ const mention = surfaceFree && !providerPrompt && !settingsPrompt ? skillMentionQuery(promptDraft, promptCaret) : null;
35705
+ const slashCommands2 = mention ? skillMentionItems(skills, mention.query) : [];
35706
+ return {
35707
+ activeSlashQuery: mention ? mention.query : null,
35708
+ slashCommands: slashCommands2,
35709
+ slashPaletteOpen: slashCommands2.length > 0 && slashDismissedFor !== promptDraft,
35710
+ paletteKind: mention ? "skills" : "commands"
35711
+ };
35712
+ }
35713
+ const slashCommands = SLASH_COMMANDS.filter((command) => slashCommandMatches(command, activeSlashQuery)).sort(
35714
+ compareSlashCommands
35715
+ );
35716
+ const slashPaletteOpen = slashDismissedFor !== promptDraft;
35717
+ return { activeSlashQuery, slashCommands, slashPaletteOpen, paletteKind: "commands" };
35510
35718
  }
35511
35719
 
35512
35720
  // src/tui/app/panel-epoch.mjs
@@ -35611,7 +35819,7 @@ function resolvePickerState(prev, resolved, { pickerOpenedFromEnterRef, pickerOp
35611
35819
  }
35612
35820
 
35613
35821
  // src/tui/app/use-prompt-layout-rows.mjs
35614
- import { useCallback as useCallback5, useEffect as useEffect7 } from "react";
35822
+ import { useCallback as useCallback5, useEffect as useEffect8 } from "react";
35615
35823
  import stringWidth3 from "string-width";
35616
35824
 
35617
35825
  // src/tui/display-width.mjs
@@ -35796,10 +36004,10 @@ function usePromptLayoutRows({
35796
36004
  },
35797
36005
  [promptContentColumns]
35798
36006
  );
35799
- useEffect7(() => {
36007
+ useEffect8(() => {
35800
36008
  syncPromptLayoutRows(promptLayoutValueRef.current);
35801
36009
  }, [syncPromptLayoutRows]);
35802
- useEffect7(() => {
36010
+ useEffect8(() => {
35803
36011
  const kind = String(settingsPrompt?.kind || "");
35804
36012
  if (!CORE_MULTILINE_TEXT_ENTRY_KINDS.has(kind)) {
35805
36013
  setTextEntryLayoutRows(1);
@@ -35812,7 +36020,7 @@ function usePromptLayoutRows({
35812
36020
  }
35813
36021
 
35814
36022
  // src/tui/app/use-panel-transition.mjs
35815
- import { useEffect as useEffect8 } from "react";
36023
+ import { useEffect as useEffect9 } from "react";
35816
36024
  function usePanelTransition({
35817
36025
  panelTransitionRef,
35818
36026
  panelCloseInkMaskRowsRef,
@@ -35824,7 +36032,7 @@ function usePanelTransition({
35824
36032
  setPanelInkMaskEpoch,
35825
36033
  setPanelTransitionEpoch
35826
36034
  }) {
35827
- useEffect8(() => {
36035
+ useEffect9(() => {
35828
36036
  const transition = panelTransitionRef.current;
35829
36037
  const pendingInkMask = panelCloseInkMaskRowsRef.current;
35830
36038
  const hadTransitionClearance = panelTransitionClearRows > 0 || panelTransitionGuardRows > 0;
@@ -35841,13 +36049,13 @@ function usePanelTransition({
35841
36049
  const timer2 = setTimeout(() => setPanelTransitionEpoch((epoch) => epoch + 1), 0);
35842
36050
  return () => clearTimeout(timer2);
35843
36051
  }, [panelLayoutSignature, bottomClusterRows, panelTransitionClearRows, panelTransitionGuardRows]);
35844
- useEffect8(() => {
36052
+ useEffect9(() => {
35845
36053
  panelTransitionRef.current.tailId = latestTranscriptItem?.id ?? null;
35846
36054
  });
35847
36055
  }
35848
36056
 
35849
36057
  // src/tui/app/use-ui-open-request.mjs
35850
- import { useEffect as useEffect9, useRef as useRef4 } from "react";
36058
+ import { useEffect as useEffect10, useRef as useRef4 } from "react";
35851
36059
  var SETUP_SECTION_TARGETS = Object.freeze({
35852
36060
  developer: ({ openDeveloperPicker }) => openDeveloperPicker(),
35853
36061
  voice: ({ openSettingsPicker }) => openSettingsPicker(),
@@ -35855,7 +36063,7 @@ var SETUP_SECTION_TARGETS = Object.freeze({
35855
36063
  });
35856
36064
  function useUiOpenRequest({ uiOpenRequest, runSlashCommand, sections }) {
35857
36065
  const seenRef = useRef4(0);
35858
- useEffect9(() => {
36066
+ useEffect10(() => {
35859
36067
  const request = uiOpenRequest;
35860
36068
  const seq = Number(request?.seq) || 0;
35861
36069
  if (!request?.command || seq <= seenRef.current) return;
@@ -35867,7 +36075,7 @@ function useUiOpenRequest({ uiOpenRequest, runSlashCommand, sections }) {
35867
36075
  }
35868
36076
 
35869
36077
  // src/tui/app/use-mouse-input.mjs
35870
- import { useCallback as useCallback6, useEffect as useEffect10, useRef as useRef5 } from "react";
36078
+ import { useCallback as useCallback6, useEffect as useEffect11, useRef as useRef5 } from "react";
35871
36079
 
35872
36080
  // src/tui/markdown/streaming-markdown.mjs
35873
36081
  import { marked as marked2 } from "marked";
@@ -38593,12 +38801,35 @@ function healIncompleteLink(text, isPendingLocalPath) {
38593
38801
  if (label < 0 && isPendingLocalPath?.(caption)) return prefix;
38594
38802
  return `${prefix}[${closeEmphasis(caption)}${"]".repeat(Math.max(0, depth - 1))}]()`;
38595
38803
  }
38804
+ var PIPE_ROW = /^ {0,3}\|/;
38805
+ var DELIMITER_ROW = /^ {0,3}\|?\s*:?-+:?\s*(?:\|\s*:?-+:?\s*)*\|?\s*$/;
38806
+ var PARTIAL_DELIMITER_ROW = /^ {0,3}\|?[\s:|-]*$/;
38807
+ function tableCells(line) {
38808
+ const cells = line.trim().split(/(?<!\\)\|/);
38809
+ if (cells[0].trim() === "") cells.shift();
38810
+ if (cells.length && cells[cells.length - 1].trim() === "") cells.pop();
38811
+ return cells.length;
38812
+ }
38813
+ function trimPendingTableHead(text) {
38814
+ let offset = 0;
38815
+ for (const blank of text.matchAll(/\n[ \t]*\r?\n/g)) offset = blank.index + blank[0].length;
38816
+ const block = text.slice(offset);
38817
+ const lines = block.split("\n").map((line) => line.replace(/\r$/, ""));
38818
+ if (lines.length === 0 || lines.length > 2 || !PIPE_ROW.test(lines[0])) return text;
38819
+ if (lines.length === 2) {
38820
+ const delimiter2 = lines[1];
38821
+ if (!PARTIAL_DELIMITER_ROW.test(delimiter2)) return text;
38822
+ if (DELIMITER_ROW.test(delimiter2) && tableCells(delimiter2) === tableCells(lines[0])) return text;
38823
+ }
38824
+ return text.slice(0, offset);
38825
+ }
38596
38826
  function healStreamingMarkdownTail(text, isPendingLocalPath) {
38597
- const value = String(text ?? "");
38827
+ const source = String(text ?? "");
38828
+ const fence = source.includes("`") || source.includes("~") ? openFence(source) : null;
38829
+ if (fence) return trimPartialClosingFence(source, fence);
38830
+ const value = source.includes("|") ? trimPendingTableHead(source) : source;
38598
38831
  const hasSyntax = HEALABLE_MARKDOWN_SYNTAX.test(value);
38599
38832
  if (!value || !hasSyntax && !isPendingLocalPath) return value;
38600
- const fence = openFence(value);
38601
- if (fence) return trimPartialClosingFence(value, fence);
38602
38833
  const healed = hasSyntax ? closeEmphasis(healIncompleteLink(closeInlineCode(value, isPendingLocalPath), isPendingLocalPath)) : value;
38603
38834
  const tail = isPendingLocalPath ? /\S+$/.exec(maskCode(healed)) : null;
38604
38835
  return tail && isPendingLocalPath(tail[0]) ? healed.slice(0, tail.index) : healed;
@@ -38794,6 +39025,13 @@ function resolveStreamingMarkdownParts(text, streamKey) {
38794
39025
  }
38795
39026
 
38796
39027
  // src/runtime/shared/model-display.mjs
39028
+ var titleCaseOption = (value) => String(value || "").split(/([\s_-]+)/).map((part) => /^[\s_-]+$/.test(part) ? part : `${part.charAt(0).toUpperCase()}${part.slice(1).toLowerCase()}`).join("");
39029
+ var effortDisplayLabel = (value) => {
39030
+ const text = String(value || "").trim();
39031
+ if (!text) return "";
39032
+ if (text.toLowerCase() === "xhigh") return "XHigh";
39033
+ return titleCaseOption(text);
39034
+ };
38797
39035
  function titleModelPart(part) {
38798
39036
  const text = String(part || "").trim();
38799
39037
  if (!text) return "";
@@ -38936,8 +39174,21 @@ function stripToolPrefix(name) {
38936
39174
  function rawToolName(name) {
38937
39175
  return String(name || "tool").replace(/^functions\./, "");
38938
39176
  }
38939
- function parseMcpToolName(name) {
38940
- const text = rawToolName(name);
39177
+ var mcpToolIdentities = /* @__PURE__ */ new Map();
39178
+ function knownMcpToolIdentity(name) {
39179
+ const known = mcpToolIdentities.get(rawToolName(name));
39180
+ return known ? { ...known } : null;
39181
+ }
39182
+ function parseMcpToolName(nameOrTool) {
39183
+ if (nameOrTool && typeof nameOrTool === "object") {
39184
+ const server = String(nameOrTool.mcpServerName || "").trim();
39185
+ const parsed = parseMcpToolName(nameOrTool.name);
39186
+ if (!server) return parsed;
39187
+ return { server, tool: String(nameOrTool.mcpToolName || "") || parsed?.tool || "" };
39188
+ }
39189
+ const text = rawToolName(nameOrTool);
39190
+ const known = mcpToolIdentities.get(text);
39191
+ if (known) return { ...known };
38941
39192
  const match = /^mcp__(.+?)__(.+)$/.exec(text);
38942
39193
  if (!match) return null;
38943
39194
  return { server: match[1], tool: match[2] };
@@ -39041,6 +39292,8 @@ function toolSearchDisplayLabel(args = {}) {
39041
39292
  function displayToolSearchTarget(value) {
39042
39293
  const text = String(value || "").trim();
39043
39294
  if (/^skill:/i.test(text)) return text.slice("skill:".length);
39295
+ const known = knownMcpToolIdentity(text);
39296
+ if (known) return `${known.server}.${known.tool}`;
39044
39297
  const mcp = /^mcp__(.*?)__(.+)$/.exec(text);
39045
39298
  if (mcp) return `${mcp[1]}.${mcp[2]}`;
39046
39299
  return stripToolPrefix(text);
@@ -41479,6 +41732,479 @@ function transportErrorText(error) {
41479
41732
  return `${TRANSPORT_SENTENCES[verdict.kind]}${detail ? ` (${detail})` : ""}.`;
41480
41733
  }
41481
41734
 
41735
+ // src/runtime/agent/orchestrator/providers/provider-error-kind.mjs
41736
+ var PROVIDER_ERROR_KINDS = Object.freeze([
41737
+ "overloaded",
41738
+ "rate_limited",
41739
+ "quota_exhausted",
41740
+ "entitlement",
41741
+ "billing",
41742
+ "auth",
41743
+ "permission",
41744
+ "context_overflow",
41745
+ "request_too_large",
41746
+ "policy",
41747
+ "service_tier_unavailable",
41748
+ "invalid_request",
41749
+ "transient",
41750
+ "unknown"
41751
+ ]);
41752
+ var MAX_CAUSE_CHAIN_DEPTH = 8;
41753
+ function boundedCauseChain(err) {
41754
+ const chain = [];
41755
+ const seen = /* @__PURE__ */ new Set();
41756
+ let cursor = err;
41757
+ while (cursor && chain.length < MAX_CAUSE_CHAIN_DEPTH && !seen.has(cursor)) {
41758
+ chain.push(cursor);
41759
+ seen.add(cursor);
41760
+ cursor = cursor?.cause;
41761
+ }
41762
+ return chain;
41763
+ }
41764
+ function headerValue(headers, name) {
41765
+ if (!headers) return null;
41766
+ const lower = name.toLowerCase();
41767
+ if (typeof headers.get === "function") return headers.get(name) ?? headers.get(lower);
41768
+ for (const [key, value] of Object.entries(headers)) {
41769
+ if (String(key).toLowerCase() === lower) return Array.isArray(value) ? value[0] : value;
41770
+ }
41771
+ return null;
41772
+ }
41773
+ function wireDetail(err) {
41774
+ const failed = err?.responseFailed;
41775
+ return failed?.response?.error || failed?.error || err?.providerError || failed || null;
41776
+ }
41777
+ function headerSources(err) {
41778
+ const detail = wireDetail(err);
41779
+ return [
41780
+ err?.headers,
41781
+ err?.response?.headers,
41782
+ err?.data?.responseHeaders,
41783
+ err?.error?.headers,
41784
+ detail?.headers,
41785
+ err?.providerError?.headers,
41786
+ err?.payload?.error?.headers
41787
+ ].filter((headers) => headers && typeof headers === "object");
41788
+ }
41789
+ function errorHeaderValue(err, name) {
41790
+ for (const headers of headerSources(err)) {
41791
+ const value = headerValue(headers, name);
41792
+ if (value != null && value !== "") return value;
41793
+ }
41794
+ return null;
41795
+ }
41796
+ function typedErrorCode(err) {
41797
+ const detail = wireDetail(err);
41798
+ for (const field of [detail?.code, detail?.type, err?.providerErrorCode, err?.code, err?.error?.code]) {
41799
+ if (typeof field === "string" && field.trim()) return field.trim().toLowerCase();
41800
+ }
41801
+ return "";
41802
+ }
41803
+ var MESSAGE_DELAY_CODES = /* @__PURE__ */ new Set(["rate_limit_exceeded", "slow_down"]);
41804
+ var MESSAGE_DELAY_RE = /(?:try again in|retry (?:again )?(?:in|after)|wait(?: for)?)\s*(\d+(?:\.\d+)?)\s*(ms|milliseconds?|s|secs?|seconds?|m|mins?|minutes?)\b/i;
41805
+ function finitePositive(value) {
41806
+ if (value == null || value === "") return null;
41807
+ const n = Number(value);
41808
+ return Number.isFinite(n) && n > 0 ? n : null;
41809
+ }
41810
+ function retryInfoDelayMs(details) {
41811
+ if (!Array.isArray(details)) return null;
41812
+ for (const detail of details) {
41813
+ const delay = detail?.retryDelay;
41814
+ let ms = null;
41815
+ if (typeof delay === "string") {
41816
+ const match = delay.trim().match(/^(\d+(?:\.\d+)?)s$/);
41817
+ if (match) ms = Number(match[1]) * 1e3;
41818
+ } else if (delay && typeof delay === "object") {
41819
+ ms = Number(delay.seconds || 0) * 1e3 + Number(delay.nanos || 0) / 1e6;
41820
+ }
41821
+ if (finitePositive(ms) != null) return Math.ceil(ms);
41822
+ }
41823
+ return null;
41824
+ }
41825
+ function messageDelayMs(err) {
41826
+ const detail = wireDetail(err) || err?.error || null;
41827
+ for (const message of [detail?.message, err?.error?.message, err?.message]) {
41828
+ if (typeof message !== "string" || !message) continue;
41829
+ const match = message.match(MESSAGE_DELAY_RE);
41830
+ if (!match) continue;
41831
+ const value = finitePositive(match[1]);
41832
+ if (value == null) continue;
41833
+ const unit = String(match[2] || "").toLowerCase();
41834
+ if (unit === "ms" || unit.startsWith("millisecond")) return Math.ceil(value);
41835
+ if (unit === "m" || unit.startsWith("min")) return Math.ceil(value * 6e4);
41836
+ return Math.ceil(value * 1e3);
41837
+ }
41838
+ return null;
41839
+ }
41840
+ function retryAfterMsFromError(err) {
41841
+ if (!err || typeof err !== "object") return null;
41842
+ for (const item of boundedCauseChain(err).slice(0, 2)) {
41843
+ const at = Number(item?.retryAfterAt);
41844
+ if (Number.isFinite(at) && at > 0) return Math.max(0, at - Date.now());
41845
+ }
41846
+ for (const item of boundedCauseChain(err).slice(0, 2)) {
41847
+ const stamped = finitePositive(item?.retryAfterMs);
41848
+ if (stamped != null) return stamped;
41849
+ }
41850
+ const retryAfterMs = finitePositive(errorHeaderValue(err, "retry-after-ms"));
41851
+ if (retryAfterMs != null) return retryAfterMs;
41852
+ const retryAfter = errorHeaderValue(err, "retry-after");
41853
+ if (retryAfter != null) {
41854
+ const seconds = finitePositive(retryAfter);
41855
+ if (seconds != null) return Math.ceil(seconds * 1e3);
41856
+ const untilDate = finitePositive(Date.parse(String(retryAfter)) - Date.now());
41857
+ if (untilDate != null) return untilDate;
41858
+ }
41859
+ const detail = wireDetail(err);
41860
+ for (const details of [
41861
+ err.details,
41862
+ err.error?.details,
41863
+ err.data?.error?.details,
41864
+ err.errorDetails,
41865
+ err.error?.errorDetails,
41866
+ detail?.details
41867
+ ]) {
41868
+ const delay = retryInfoDelayMs(details);
41869
+ if (delay != null) return delay;
41870
+ }
41871
+ if (MESSAGE_DELAY_CODES.has(typedErrorCode(err))) return messageDelayMs(err);
41872
+ return null;
41873
+ }
41874
+ var TRANSIENT_SDK_NAMES = /* @__PURE__ */ new Set([
41875
+ "APIConnectionError",
41876
+ "APIConnectionTimeoutError",
41877
+ "ConnectTimeoutError",
41878
+ "HeadersTimeoutError",
41879
+ "BodyTimeoutError"
41880
+ ]);
41881
+ var STALL_NAMES = /* @__PURE__ */ new Set(["StreamStalledError", "StreamStalledAbortError", "AgentStallAbortError"]);
41882
+ var BARE_FETCH_TRANSPORT_MESSAGE_RE = /^(?:fetch failed|failed to fetch|couldn'?t fetch\.?|load failed|network error|terminated|other side closed|socket hang up)$/i;
41883
+ var TRANSIENT_ERROR_CODES = /* @__PURE__ */ new Set([
41884
+ "ECONNRESET",
41885
+ "ETIMEDOUT",
41886
+ "ESOCKETTIMEDOUT",
41887
+ "EAI_AGAIN",
41888
+ "ENOTFOUND",
41889
+ "EAI_NODATA",
41890
+ "ECONNREFUSED",
41891
+ "ENETUNREACH",
41892
+ "EHOSTUNREACH",
41893
+ "EPIPE",
41894
+ "EPROVIDERTIMEOUT",
41895
+ "EGEMINITIMEOUT",
41896
+ "ESTREAMSTALL",
41897
+ "EWSACQUIRETIMEOUT",
41898
+ "UND_ERR_SOCKET",
41899
+ "UND_ERR_CONNECT_TIMEOUT",
41900
+ "UND_ERR_HEADERS_TIMEOUT",
41901
+ "UND_ERR_BODY_TIMEOUT",
41902
+ "UND_ERR_CONNECT",
41903
+ "EPROTO",
41904
+ "UND_ERR_DESTROYED",
41905
+ "UND_ERR_CLOSED",
41906
+ "ECONNABORTED",
41907
+ "ENETRESET",
41908
+ "ERR_STREAM_DESTROYED",
41909
+ "ERR_HTTP2_STREAM_ERROR",
41910
+ "ERR_HTTP2_SESSION_ERROR",
41911
+ "ERR_HTTP2_INVALID_SESSION",
41912
+ "ERR_SOCKET_CONNECTION_TIMEOUT",
41913
+ "ERR_SSL_WRONG_VERSION_NUMBER",
41914
+ "ERR_STREAM_PREMATURE_CLOSE"
41915
+ ]);
41916
+ var TLS_RECORD_FAILURE_RE = /^ERR_SSL_[A-Z0-9_/]*BAD_RECORD_MAC$/i;
41917
+ function isTransientErrorCode(code) {
41918
+ const value = String(code || "");
41919
+ return TRANSIENT_ERROR_CODES.has(value) || TLS_RECORD_FAILURE_RE.test(value);
41920
+ }
41921
+ var TRANSIENT_WS_CLOSE_CODES = /* @__PURE__ */ new Set([1e3, 1001, 1005, 1006, 1011, 1012]);
41922
+ function transportEvidence(err, chain, status) {
41923
+ if (err.truncatedStream === true || err.code === "TRUNCATED_STREAM" || err.streamStalled === true) return true;
41924
+ if (TRANSIENT_WS_CLOSE_CODES.has(Number(err.wsCloseCode ?? err.streamCloseCode ?? 0))) return true;
41925
+ if (chain.some((item) => isTransientErrorCode(item?.code))) return true;
41926
+ const names = chain.map((item) => String(item?.name || ""));
41927
+ if (names.some((name) => TRANSIENT_SDK_NAMES.has(name) || STALL_NAMES.has(name))) return true;
41928
+ return !status && chain.some((item) => BARE_FETCH_TRANSPORT_MESSAGE_RE.test(String(item?.message || "").trim()));
41929
+ }
41930
+ var TOKEN_CONTEXT_OVERFLOW_PATTERNS = [
41931
+ /input (?:length|tokens?) exceeds? the context window/i,
41932
+ /exceeds? the (?:maximum )?context (?:window|length)/i,
41933
+ /maximum context length/i,
41934
+ /context[_ ]length[_ ]exceeded/i,
41935
+ /prompt is too long/i,
41936
+ /reduce the length of (?:the )?(?:messages|input|prompt)/i,
41937
+ // Wordings other backends use for the same refusal, each tied to a context
41938
+ // or input-length noun so a tokens-per-minute rate limit never matches.
41939
+ /prompt too long/i,
41940
+ // z.ai, Ollama
41941
+ /prompt exceeds max length/i,
41942
+ // z.ai CN endpoint
41943
+ /input is too long for requested model/i,
41944
+ // Amazon Bedrock
41945
+ /input token count.*exceeds the maximum/i,
41946
+ // Google
41947
+ /maximum prompt length is \d+/i,
41948
+ // xAI
41949
+ /exceeds (?:the )?maximum allowed input length/i,
41950
+ // OpenRouter relays
41951
+ /is longer than the model'?s context length/i,
41952
+ // Together AI
41953
+ /exceeds the available context size/i,
41954
+ // llama.cpp server
41955
+ /greater than the context length/i,
41956
+ // LM Studio
41957
+ /context window exceeds limit/i,
41958
+ // MiniMax
41959
+ /exceeded model token limit/i,
41960
+ // Kimi
41961
+ /too large for model with \d+ maximum context length/i,
41962
+ // Mistral
41963
+ /range of input length should be/i,
41964
+ // DashScope / Qwen
41965
+ /model_context_window_exceeded/i
41966
+ // z.ai finish reason surfaced as text
41967
+ ];
41968
+ var REQUEST_SIZE_PATTERNS = [
41969
+ /request payload size exceeds the limit/i,
41970
+ // Google (400, byte-size limit)
41971
+ // A 413 re-wrapped by a proxy or aggregator without its status.
41972
+ /request entity too large/i,
41973
+ /request exceeds the maximum size/i
41974
+ ];
41975
+ var CAPACITY_MESSAGE_RE = /\bat capacity\b|\boverloaded\b|\bserver is busy\b/i;
41976
+ var LEGACY_BILLING_MESSAGE_RE = /\binsufficient_quota\b|exceeded your (?:current )?quota/i;
41977
+ var LEGACY_QUOTA_MESSAGE_RE = /\bquota_exceeded\b|\busage_limit_reached\b|hit your usage limit/i;
41978
+ var CODE_KINDS = new Map(
41979
+ Object.entries({
41980
+ policy: [
41981
+ "cyber_policy",
41982
+ "bio_policy",
41983
+ "cyber_policy_violation",
41984
+ "bio_policy_violation",
41985
+ "misalignment_policy_violation",
41986
+ "content_policy_violation",
41987
+ "content_filter",
41988
+ "safety",
41989
+ "recitation",
41990
+ "invalid_prompt"
41991
+ ],
41992
+ billing: [
41993
+ "insufficient_quota",
41994
+ "credit_balance_exhausted",
41995
+ "organization_spend_limit_exceeded",
41996
+ "project_spend_limit_exceeded",
41997
+ "organization_usage_limit_exceeded",
41998
+ "billing_not_active",
41999
+ "billing_hard_limit_reached",
42000
+ "payment_required",
42001
+ "insufficient_g1_credits_balance"
42002
+ ],
42003
+ entitlement: ["usage_not_included"],
42004
+ quota_exhausted: ["quota_exceeded", "quota_exhausted", "usage_limit_reached", "provider_accounts_exhausted"],
42005
+ context_overflow: ["context_length_exceeded", "context_window_exceeded", "model_context_window_exceeded"],
42006
+ request_too_large: ["request_too_large", "payload_too_large", "request_entity_too_large"],
42007
+ auth: ["invalid_api_key", "authentication_error", "unauthenticated", "unauthorized", "invalid_authentication"],
42008
+ permission: ["permission_error", "permission_denied", "forbidden"],
42009
+ overloaded: [
42010
+ "server_is_overloaded",
42011
+ "overloaded_error",
42012
+ "overloaded",
42013
+ "server_overloaded",
42014
+ "model_capacity_exhausted",
42015
+ "model_capacity_exceeded"
42016
+ ],
42017
+ // The requested service tier has no capacity: the same request at the
42018
+ // same tier is refused again, so it is final rather than an overload.
42019
+ service_tier_unavailable: ["flex_unavailable"],
42020
+ rate_limited: ["rate_limit_exceeded", "rate_limit_error", "rate_limited", "slow_down", "too_many_requests"],
42021
+ transient: [
42022
+ "server_error",
42023
+ "api_error",
42024
+ "internal",
42025
+ "internal_error",
42026
+ "unavailable",
42027
+ "service_unavailable",
42028
+ "deadline_exceeded",
42029
+ "timeout",
42030
+ "previous_response_not_found",
42031
+ "websocket_connection_limit_reached",
42032
+ "stream_disconnected",
42033
+ "network_error",
42034
+ // Replay safety is still the stream-outcome gate's call (classifyError).
42035
+ "malformed_stream"
42036
+ ],
42037
+ invalid_request: [
42038
+ "invalid_request",
42039
+ "invalid_request_error",
42040
+ "invalid_argument",
42041
+ "failed_precondition",
42042
+ "bad_request",
42043
+ "not_found",
42044
+ "not_found_error",
42045
+ "model_not_found",
42046
+ "unsupported_parameter"
42047
+ ]
42048
+ }).flatMap(([kind, codes]) => codes.map((code) => [code, kind]))
42049
+ );
42050
+ var RESOURCE_EXHAUSTED = "resource_exhausted";
42051
+ var KIND_RANK = [
42052
+ "policy",
42053
+ "billing",
42054
+ "entitlement",
42055
+ "quota_exhausted",
42056
+ "context_overflow",
42057
+ "request_too_large",
42058
+ "auth",
42059
+ "permission",
42060
+ "service_tier_unavailable",
42061
+ "overloaded",
42062
+ "rate_limited",
42063
+ "transient",
42064
+ "invalid_request"
42065
+ ];
42066
+ function codeFields(item) {
42067
+ const detail = wireDetail(item);
42068
+ return [
42069
+ detail?.code,
42070
+ detail?.type,
42071
+ detail?.status,
42072
+ item?.providerErrorCode,
42073
+ item?.code,
42074
+ item?.type,
42075
+ item?.error?.code,
42076
+ item?.error?.type,
42077
+ item?.error?.status,
42078
+ item?.error?.error?.code,
42079
+ item?.error?.error?.type,
42080
+ item?.payload?.code,
42081
+ item?.payload?.type,
42082
+ item?.payload?.error?.code,
42083
+ item?.payload?.error?.type,
42084
+ item?.geminiStatus,
42085
+ item?.status
42086
+ ];
42087
+ }
42088
+ function typedCodes(chain) {
42089
+ const codes = [];
42090
+ for (const item of chain) {
42091
+ if (!item || typeof item !== "object") continue;
42092
+ for (const field of codeFields(item)) {
42093
+ if (typeof field !== "string") continue;
42094
+ const code = field.trim().toLowerCase();
42095
+ if (code && !codes.includes(code)) codes.push(code);
42096
+ }
42097
+ }
42098
+ return codes;
42099
+ }
42100
+ var VALID_STATUS = (n) => Number.isFinite(n) && n >= 100 && n <= 599;
42101
+ function statusOf(err) {
42102
+ for (const value of [err?.httpStatus, err?.status, err?.statusCode, err?.response?.status]) {
42103
+ const n = Number(value);
42104
+ if (VALID_STATUS(n)) return Math.floor(n);
42105
+ }
42106
+ return 0;
42107
+ }
42108
+ function kindFromStatus(status) {
42109
+ if (status === 401) return "auth";
42110
+ if (status === 402) return "billing";
42111
+ if (status === 403) return "permission";
42112
+ if (status === 413) return "request_too_large";
42113
+ if (status === 429) return "rate_limited";
42114
+ if (status === 529) return "overloaded";
42115
+ if (status === 408 || status === 409 || status === 425) return "transient";
42116
+ if (status === 525 || status === 526) return null;
42117
+ if (status >= 400 && status < 500) return "invalid_request";
42118
+ if (status >= 500 && status < 600) return "transient";
42119
+ return null;
42120
+ }
42121
+ function firstOf(chain, read) {
42122
+ for (const item of chain) {
42123
+ const value = item && typeof item === "object" ? read(item) : void 0;
42124
+ if (value !== void 0 && value !== null) return value;
42125
+ }
42126
+ return null;
42127
+ }
42128
+ function resetAtOf(err, chain) {
42129
+ const stamped = firstOf(chain, (item) => {
42130
+ const n = Number(item.resetAt);
42131
+ return Number.isFinite(n) && n > 0 ? n : null;
42132
+ });
42133
+ if (stamped != null) return stamped;
42134
+ const exhausted = Number(err?.quotaExhausted?.resetAt);
42135
+ return Number.isFinite(exhausted) && exhausted > 0 ? exhausted : null;
42136
+ }
42137
+ function quotaScopeOf(chain) {
42138
+ return firstOf(chain, (item) => {
42139
+ const scope = typeof item.quotaScope === "string" ? item.quotaScope.trim().toLowerCase() : "";
42140
+ return scope === "minute" || scope === "day" || scope === "plan" ? scope : null;
42141
+ });
42142
+ }
42143
+ function kindFromCodes(codes, scope) {
42144
+ let kind = null;
42145
+ let code = "";
42146
+ for (const candidate of codes) {
42147
+ let candidateKind = CODE_KINDS.get(candidate) || null;
42148
+ if (candidate === RESOURCE_EXHAUSTED) {
42149
+ candidateKind = scope === "day" || scope === "plan" ? "quota_exhausted" : "rate_limited";
42150
+ }
42151
+ if (candidateKind && (kind === null || KIND_RANK.indexOf(candidateKind) < KIND_RANK.indexOf(kind))) {
42152
+ kind = candidateKind;
42153
+ code = candidate;
42154
+ }
42155
+ }
42156
+ return { kind, code };
42157
+ }
42158
+ function messageOf2(err, chain) {
42159
+ const detail = wireDetail(err);
42160
+ return [detail?.message, err?.error?.message, ...chain.map((item) => item?.message)].filter((message) => typeof message === "string" && message).join("\n");
42161
+ }
42162
+ function providerErrorKind(err, options = {}) {
42163
+ if (!err || typeof err !== "object" && typeof err !== "function") {
42164
+ return { kind: "unknown", code: "", status: 0, retryAfterMs: null, resetAt: null };
42165
+ }
42166
+ const chain = boundedCauseChain(err);
42167
+ const status = statusOf(err);
42168
+ const retryAfterMs = retryAfterMsFromError(err);
42169
+ const resetAt = resetAtOf(err, chain);
42170
+ const scope = quotaScopeOf(chain);
42171
+ const codes = typedCodes(chain);
42172
+ const describe = (kind2, code2 = typedErrorCode(err)) => ({ kind: kind2, code: code2 || "", status, retryAfterMs, resetAt });
42173
+ if (err.quotaExhausted && typeof err.quotaExhausted === "object") return describe("quota_exhausted");
42174
+ if (chain.some((item) => item?.reauthRequired === true)) return describe("auth");
42175
+ let { kind, code } = kindFromCodes(codes, scope);
42176
+ const quotaFlagged = options.quotaFlags !== false && chain.some((item) => item?.providerQuota === true || item?.quotaExceeded === true);
42177
+ if (quotaFlagged && (!kind || kind === "rate_limited")) kind = "quota_exhausted";
42178
+ const text = options.text !== false && (!kind || kind === "invalid_request") ? messageOf2(err, chain) : "";
42179
+ if (!kind && !codes.length && text && status === 429 && CAPACITY_MESSAGE_RE.test(text)) kind = "overloaded";
42180
+ if (options.legacyQuotaWording === true && !kind && !codes.length && !status && retryAfterMs == null && !scope && text) {
42181
+ if (LEGACY_BILLING_MESSAGE_RE.test(text)) kind = "billing";
42182
+ else if (LEGACY_QUOTA_MESSAGE_RE.test(text)) kind = "quota_exhausted";
42183
+ }
42184
+ if (!kind) kind = kindFromStatus(status);
42185
+ if ((!kind || kind === "invalid_request") && text) {
42186
+ if (TOKEN_CONTEXT_OVERFLOW_PATTERNS.some((re) => re.test(text))) kind = "context_overflow";
42187
+ else if (REQUEST_SIZE_PATTERNS.some((re) => re.test(text))) kind = "request_too_large";
42188
+ }
42189
+ if (!kind && transportEvidence(err, chain, status)) kind = "transient";
42190
+ if (!kind && (err.responseFailed != null || err.providerWireError === true)) kind = "transient";
42191
+ kind = kind || "unknown";
42192
+ if (scope === "minute" && kind === "quota_exhausted") kind = "rate_limited";
42193
+ if (kind === "rate_limited" && (scope === "day" || scope === "plan")) kind = "quota_exhausted";
42194
+ return describe(kind, code || void 0);
42195
+ }
42196
+ var QUOTA_KINDS = /* @__PURE__ */ new Set(["quota_exhausted", "entitlement", "billing"]);
42197
+ var DETERMINISTIC_KINDS = /* @__PURE__ */ new Set([
42198
+ ...QUOTA_KINDS,
42199
+ "policy",
42200
+ "auth",
42201
+ "permission",
42202
+ "context_overflow",
42203
+ "request_too_large",
42204
+ "service_tier_unavailable",
42205
+ "invalid_request"
42206
+ ]);
42207
+
41482
42208
  // src/runtime/shared/error-presentation.mjs
41483
42209
  var DETAILS_LIMIT = 12e3;
41484
42210
  var SUMMARY_LIMIT = 180;
@@ -41494,7 +42220,7 @@ function safeErrorDetails(value) {
41494
42220
  \u2026`;
41495
42221
  return text;
41496
42222
  }
41497
- function messageOf2(value) {
42223
+ function messageOf3(value) {
41498
42224
  if (typeof value === "string") return value;
41499
42225
  if (value && typeof value === "object") {
41500
42226
  if (typeof value.message === "string") return value.message;
@@ -41508,7 +42234,7 @@ function messageOf2(value) {
41508
42234
  return value == null ? "" : String(value);
41509
42235
  }
41510
42236
  function unwrap(value) {
41511
- const raw = messageOf2(value).trim();
42237
+ const raw = messageOf3(value).trim();
41512
42238
  const start = raw.indexOf("{");
41513
42239
  let parsed;
41514
42240
  if (start >= 0) {
@@ -41528,39 +42254,147 @@ function unwrap(value) {
41528
42254
  return { raw, message, status, code };
41529
42255
  }
41530
42256
  function isRejected429(value) {
41531
- return /\bAPI 429 request rejected\b/.test(messageOf2(value));
42257
+ return /\bAPI 429 request rejected\b/.test(messageOf3(value));
42258
+ }
42259
+ var KIND_COPY = {
42260
+ overloaded: ["overloaded", "The provider is busy right now.", "Try again later or choose another model."],
42261
+ rate_limited: ["rate-limit", "The provider is temporarily rate-limiting requests.", "Try again shortly."],
42262
+ quota_exhausted: [
42263
+ "quota",
42264
+ "The provider usage limit was reached.",
42265
+ "Wait for the limit to reset or choose another account."
42266
+ ],
42267
+ entitlement: [
42268
+ "entitlement",
42269
+ "This model isn't included in your plan.",
42270
+ "Upgrade your plan, or choose another model or provider."
42271
+ ],
42272
+ billing: [
42273
+ "billing",
42274
+ "The provider account is out of credits or at its spend limit.",
42275
+ "Check your billing with the provider, then try again."
42276
+ ],
42277
+ permission: [
42278
+ "permission",
42279
+ "You don't have access to this resource.",
42280
+ "Check your account permissions, or choose another model."
42281
+ ],
42282
+ context_overflow: [
42283
+ "context-overflow",
42284
+ "The conversation is too long for this model.",
42285
+ "Compact the conversation or start a new one."
42286
+ ],
42287
+ request_too_large: [
42288
+ "payload-size",
42289
+ "The request exceeds the size limit.",
42290
+ "Reduce the attachments or request size, then try again."
42291
+ ],
42292
+ policy: [
42293
+ "policy",
42294
+ "The provider refused this request under its safety policy.",
42295
+ "Rephrase the request or choose another model."
42296
+ ],
42297
+ service_tier_unavailable: [
42298
+ "service-tier",
42299
+ "The requested service tier is unavailable right now.",
42300
+ "Switch to the standard tier or try again later."
42301
+ ]
42302
+ };
42303
+ var SUMMARY_KINDS = new Map(Object.entries(KIND_COPY).map(([providerKind, [, summary]]) => [summary, providerKind]));
42304
+ function waitLabel(ms) {
42305
+ const seconds = Math.max(1, Math.ceil(ms / 1e3));
42306
+ if (seconds < 60) return `${seconds}s`;
42307
+ const minutes = Math.ceil(seconds / 60);
42308
+ if (minutes < 60) return `${minutes}m`;
42309
+ const hours = Math.floor(minutes / 60);
42310
+ return minutes % 60 ? `${hours}h ${minutes % 60}m` : `${hours}h`;
42311
+ }
42312
+ function resetLabel(resetAt) {
42313
+ const reset = new Date(resetAt);
42314
+ const pad = (n) => String(n).padStart(2, "0");
42315
+ const time = `${pad(reset.getHours())}:${pad(reset.getMinutes())}`;
42316
+ return reset.toDateString() === (/* @__PURE__ */ new Date()).toDateString() ? time : `${reset.getMonth() + 1}/${reset.getDate()} ${time}`;
42317
+ }
42318
+ var LEGACY_TEXT_KINDS = [
42319
+ [/The provider usage limit was reached|quota.*(?:hit|exceed)|usage limit/i, "quota_exhausted"],
42320
+ [/rate[_ -]?limit|too many requests/i, "rate_limited"]
42321
+ ];
42322
+ function classify(value, raw, clean3, status, code) {
42323
+ const persisted = value?.errorKind;
42324
+ if (persisted && PROVIDER_ERROR_KINDS.includes(persisted.kind)) {
42325
+ return { descriptor: persisted, typed: persisted.kind !== "unknown" };
42326
+ }
42327
+ const hasTypedFields = value && typeof value === "object" && Boolean(value.status || value.httpStatus || value.response?.status || value.code || value.retryAfterMs);
42328
+ if (!hasTypedFields) {
42329
+ const legacy = SUMMARY_KINDS.get(clean3) ?? LEGACY_TEXT_KINDS.find(([re]) => re.test(clean3))?.[1];
42330
+ if (legacy) {
42331
+ const wait = /retryAfter=(\d+)(ms|s|m)\b/i.exec(raw);
42332
+ const retryAfterMs = wait ? Number(wait[1]) * { ms: 1, s: 1e3, m: 6e4 }[wait[2].toLowerCase()] : void 0;
42333
+ return { descriptor: { kind: legacy, ...retryAfterMs ? { retryAfterMs } : {} }, typed: false };
42334
+ }
42335
+ }
42336
+ let descriptor = value && typeof value === "object" ? providerErrorKind(value) : null;
42337
+ const typed = Boolean(descriptor) && descriptor.kind !== "unknown";
42338
+ if (!descriptor || descriptor.kind === "unknown") {
42339
+ descriptor = providerErrorKind(
42340
+ Object.assign(new Error(raw), { ...status ? { status } : {}, ...code ? { code } : {} })
42341
+ );
42342
+ }
42343
+ if (descriptor.kind === "unknown") {
42344
+ const known = SUMMARY_KINDS.get(clean3);
42345
+ const legacy = known ?? LEGACY_TEXT_KINDS.find(([re]) => re.test(clean3))?.[1];
42346
+ if (legacy) return { descriptor: { ...descriptor, kind: legacy }, typed: false };
42347
+ }
42348
+ return { descriptor, typed };
41532
42349
  }
41533
42350
  function describeError(value) {
41534
- const { raw, message, status, code } = unwrap(value);
41535
- const rejected429 = isRejected429(value);
42351
+ const { raw, message, status: textStatus, code: textCode } = unwrap(value);
41536
42352
  const details = safeErrorDetails(raw);
41537
42353
  const clean3 = safeErrorDetails(message).replace(/^(?:Error invoking remote method ['"][^'"]+['"]:\s*)?(?:Error:\s*)?/i, "").trim();
42354
+ const { descriptor, typed } = classify(value, raw, clean3, textStatus, textCode);
42355
+ const status = typed ? Number(descriptor.status) || 0 : textStatus;
42356
+ const code = typed ? String(descriptor.code || "") : textCode;
42357
+ const rejected429 = isRejected429(value) && (!typed || descriptor.kind === "rate_limited");
42358
+ const copy = KIND_COPY[descriptor.kind];
42359
+ const retryAfterMs = Number(descriptor.retryAfterMs) > 0 ? Number(descriptor.retryAfterMs) : null;
42360
+ const resetAt = Number(descriptor.resetAt) > 0 ? Number(descriptor.resetAt) : null;
41538
42361
  let kind = "unknown";
41539
42362
  let summary = "";
41540
42363
  let recovery = "";
41541
- const transport = transportErrorText(value) || transportErrorText(raw);
41542
- if (value?.reauthRequired === true || /invalid_grant|refresh token (?:expired|revoked|not available)|sign in again|sign-in expired|Reauth Required/i.test(raw)) {
42364
+ let recoveryTemplate = "";
42365
+ let params = null;
42366
+ const transport = transportErrorText(value) || typed && transportErrorText({ code: code.toUpperCase(), status }) || (!typed || descriptor.kind === "transient" ? transportErrorText(raw) : null);
42367
+ if (value?.reauthRequired === true || !typed && /invalid_grant|refresh token (?:expired|revoked|not available)|sign in again|sign-in expired|Reauth Required/i.test(raw)) {
41543
42368
  kind = "reauth";
41544
42369
  summary = "Sign-in expired.";
41545
42370
  recovery = "Sign in again from Providers.";
41546
- } else if (status === 401 || status === 403 || /\b(?:invalid|expired)\s+(?:api[ _-]?key|access token|credentials?)\b|Provider authentication failed/i.test(clean3)) {
42371
+ } else if (descriptor.kind === "auth" || descriptor.kind === "unknown" && /\b(?:invalid|expired)\s+(?:api[ _-]?key|access token|credentials?)\b|Provider authentication failed/i.test(clean3)) {
41547
42372
  kind = "authentication";
41548
42373
  summary = "Provider authentication failed";
41549
42374
  recovery = "Check your sign-in or API key, then try again.";
41550
- } else if (/image.*dimensions.*exceed|image.*(?:too large|maximum.*(?:size|dimension))|many-image requests|An attached image exceeds the provider limit/i.test(
42375
+ } else if (rejected429) {
42376
+ kind = "request";
42377
+ summary = "The provider rejected this request.";
42378
+ recovery = "Review the request details before trying again.";
42379
+ } else if (["invalid_request", "unknown", "request_too_large"].includes(descriptor.kind) && /image.*dimensions.*exceed|image.*(?:too large|maximum.*(?:size|dimension))|many-image requests|An attached image exceeds the provider limit/i.test(
41551
42380
  clean3
41552
42381
  )) {
41553
42382
  kind = "image-size";
41554
42383
  summary = "An attached image exceeds the provider limit.";
41555
42384
  recovery = "Reduce the image dimensions or number of images, then try again.";
41556
- } else if (status === 413 || /payload too large|request (?:body )?too large|The request exceeds the size limit/i.test(clean3)) {
41557
- kind = "payload-size";
41558
- summary = "The request exceeds the size limit.";
41559
- recovery = "Reduce the attachments or request size, then try again.";
41560
- } else if (!rejected429 && (status === 429 || /rate[_ -]?limit|quota.*(?:hit|exceed)|too many requests|The provider usage limit was reached/i.test(clean3))) {
41561
- kind = "rate-limit";
41562
- summary = "The provider usage limit was reached.";
41563
- recovery = "Wait for the limit to reset or choose another account.";
42385
+ } else if (descriptor.kind === "unknown" && /payload too large|request (?:body )?too large|The request exceeds the size limit/i.test(clean3)) {
42386
+ [kind, summary, recovery] = KIND_COPY.request_too_large;
42387
+ } else if (copy) {
42388
+ [kind, summary, recovery] = copy;
42389
+ if (descriptor.kind === "rate_limited" && retryAfterMs) {
42390
+ recovery = `Try again in ${waitLabel(retryAfterMs)}.`;
42391
+ recoveryTemplate = "Try again in {{wait}}.";
42392
+ params = { wait: waitLabel(retryAfterMs) };
42393
+ } else if (descriptor.kind === "quota_exhausted" && resetAt) {
42394
+ recovery = `It resets at ${resetLabel(resetAt)}. Switch accounts or providers to continue now.`;
42395
+ recoveryTemplate = "It resets at {{time}}. Switch accounts or providers to continue now.";
42396
+ params = { time: resetLabel(resetAt) };
42397
+ }
41564
42398
  } else if (transport) {
41565
42399
  kind = "connection";
41566
42400
  summary = transport.replace(/\.$/, "");
@@ -41580,6 +42414,11 @@ function describeError(value) {
41580
42414
  kind,
41581
42415
  summary,
41582
42416
  recovery,
42417
+ recoveryTemplate,
42418
+ params,
42419
+ providerKind: descriptor.kind,
42420
+ resetAt,
42421
+ retryAfterMs,
41583
42422
  details,
41584
42423
  // Known structured failures ignore volatile indexes; unknown failures
41585
42424
  // retain their diagnostic identity rather than merging unrelated work.
@@ -41730,9 +42569,27 @@ function isCancelLikeError(error) {
41730
42569
  const text = errText(error);
41731
42570
  return /aborted by session close/i.test(text) || /withRetry:\s*(?:sleep )?aborted/i.test(text) || /^sleep aborted$/i.test(text);
41732
42571
  }
42572
+ var KIND_LINES = {
42573
+ overloaded: "Provider is busy at capacity.",
42574
+ rate_limited: ({ retryAfterMs }) => retryAfterMs ? `Provider is rate-limited (retry in ${formatDurationMs(retryAfterMs)}).` : "Provider is rate-limited.",
42575
+ quota_exhausted: "Provider usage limit reached.",
42576
+ entitlement: "Not included in your plan.",
42577
+ billing: "Out of credits or at spend limit.",
42578
+ permission: "Access denied by the provider.",
42579
+ policy: "Refused by the provider safety policy.",
42580
+ auth: "Provider authentication failed."
42581
+ };
42582
+ function hasTypedEvidence(error) {
42583
+ if (!error || typeof error !== "object") return false;
42584
+ return Boolean(error.errorKind?.kind) || errorHttpStatus(error) > 0 || Boolean(error.code) || Boolean(error.retryAfterMs);
42585
+ }
41733
42586
  function presentErrorText(error, options = {}) {
41734
42587
  const presentation = describeError(error);
41735
42588
  if (["image-size", "payload-size", "request"].includes(presentation.kind)) return presentation.summary;
42589
+ const kindLine = hasTypedEvidence(error) ? KIND_LINES[presentation.providerKind] : null;
42590
+ if (kindLine && presentation.kind !== "unknown") {
42591
+ return typeof kindLine === "function" ? kindLine(presentation) : kindLine;
42592
+ }
41736
42593
  const surface = options.surface || options.tool || "";
41737
42594
  const subject = subjectForSurface(surface);
41738
42595
  const max = options.max ?? 240;
@@ -42760,6 +43617,29 @@ function deriveToolCardModel(input = {}, options = {}) {
42760
43617
  };
42761
43618
  }
42762
43619
 
43620
+ // src/tui/components/user-message-skills.mjs
43621
+ function appliedSkillNames(value) {
43622
+ return (Array.isArray(value) ? value : []).filter((name) => typeof name === "string" && name);
43623
+ }
43624
+ function appliedSkillsLine(value) {
43625
+ const names = appliedSkillNames(value);
43626
+ return names.length ? `Skills applied: ${names.join(", ")}` : "";
43627
+ }
43628
+ function userTextSegments(text, value) {
43629
+ const source = String(text ?? "");
43630
+ const applied = new Set(appliedSkillNames(value));
43631
+ if (!applied.size) return [{ text: source, mention: false }];
43632
+ const segments = [];
43633
+ let at = 0;
43634
+ for (const mention of skillMentions(source, (name) => applied.has(name))) {
43635
+ if (mention.start > at) segments.push({ text: source.slice(at, mention.start), mention: false });
43636
+ segments.push({ text: source.slice(mention.start, mention.end), mention: true });
43637
+ at = mention.end;
43638
+ }
43639
+ if (at < source.length || !segments.length) segments.push({ text: source.slice(at), mention: false });
43640
+ return segments;
43641
+ }
43642
+
42763
43643
  // src/runtime/agent/orchestrator/session/transcript-restore/tool-result-status.mjs
42764
43644
  function aggregateRawResultForDisplay(text) {
42765
43645
  if (typeof text !== "string" || !/^\[lines \d+-\d+\]$/m.test(text)) return text;
@@ -43364,8 +44244,10 @@ function estimateToolRenderedResultRows(value, { pathArg = "", isShell = false,
43364
44244
  function estimateTranscriptItemRows(item, columns, toolOutputExpanded, attachedTool = false) {
43365
44245
  if (!item) return 1;
43366
44246
  switch (item.kind) {
43367
- case "user":
43368
- return 1 + estimateWrappedRows(item.text, columns, 4);
44247
+ case "user": {
44248
+ const skillsLine = appliedSkillsLine(item.appliedSkills);
44249
+ return 1 + estimateWrappedRows(item.text, columns, 4) + (skillsLine ? estimateWrappedRows(skillsLine, columns, 4) : 0);
44250
+ }
43369
44251
  case "assistant":
43370
44252
  return 1 + (item.streaming ? measureStreamingMarkdownRenderedRows(item.text, columns, item.id) : measureMarkdownRenderedRows(item.text, columns, { trimPartialFences: true }));
43371
44253
  case "tool": {
@@ -44416,12 +45298,12 @@ function useMouseInput({
44416
45298
  const passthroughCtrlWheelZoom = useCallback6(() => {
44417
45299
  zoomRestoreSchedulerRef.current.passthrough();
44418
45300
  }, []);
44419
- useEffect10(() => {
45301
+ useEffect11(() => {
44420
45302
  const scheduler = zoomRestoreSchedulerRef.current;
44421
45303
  scheduler.attach();
44422
45304
  return () => scheduler.detach();
44423
45305
  }, []);
44424
- useEffect10(() => {
45306
+ useEffect11(() => {
44425
45307
  if (!inkInput || !isRawModeSupported) return void 0;
44426
45308
  const geometry = createMouseGeometry({
44427
45309
  transcriptViewportRef,
@@ -44511,7 +45393,7 @@ function useMouseInput({
44511
45393
  }
44512
45394
 
44513
45395
  // src/tui/app/use-transcript-scroll.mjs
44514
- import { useCallback as useCallback12, useEffect as useEffect13, useLayoutEffect as useLayoutEffect3, useRef as useRef10 } from "react";
45396
+ import { useCallback as useCallback12, useEffect as useEffect14, useLayoutEffect as useLayoutEffect3, useRef as useRef10 } from "react";
44515
45397
 
44516
45398
  // src/tui/app/transcript-scroll-anchor.mjs
44517
45399
  function readingAnchorAt(geom, target) {
@@ -44533,7 +45415,7 @@ function bottomSnapRows(viewRows) {
44533
45415
  }
44534
45416
 
44535
45417
  // src/tui/app/use-selection-stitch.mjs
44536
- import { useCallback as useCallback7, useEffect as useEffect11, useRef as useRef6 } from "react";
45418
+ import { useCallback as useCallback7, useEffect as useEffect12, useRef as useRef6 } from "react";
44537
45419
  function storeStitchRows(buffer, rows2, scroll) {
44538
45420
  for (const row of rows2) {
44539
45421
  if (!row || typeof row.y !== "number") continue;
@@ -44547,7 +45429,7 @@ function useSelectionStitchBuffer({ store, dragRef, scrollTargetRef }) {
44547
45429
  const stitchBufferRef = useRef6(/* @__PURE__ */ new Map());
44548
45430
  const stitchHarvestTimerRef = useRef6(null);
44549
45431
  const stitchHarvestScrollRef = useRef6(0);
44550
- useEffect11(
45432
+ useEffect12(
44551
45433
  () => () => {
44552
45434
  if (stitchHarvestTimerRef.current) clearTimeout(stitchHarvestTimerRef.current);
44553
45435
  stitchHarvestTimerRef.current = null;
@@ -44676,7 +45558,7 @@ function useTranscriptFollow({
44676
45558
  }
44677
45559
 
44678
45560
  // src/tui/app/use-selection-paint.mjs
44679
- import { useCallback as useCallback9, useEffect as useEffect12, useRef as useRef8 } from "react";
45561
+ import { useCallback as useCallback9, useEffect as useEffect13, useRef as useRef8 } from "react";
44680
45562
 
44681
45563
  // src/tui/session/render-frame-source.mjs
44682
45564
  var sources = /* @__PURE__ */ new Set();
@@ -44868,7 +45750,7 @@ function useSelectionPaint({
44868
45750
  }) {
44869
45751
  const selectionPaintRef = useRef8({ t: 0, rect: null, pending: null, timer: null });
44870
45752
  const selectionTextCaptureRef = useRef8(0);
44871
- useEffect12(
45753
+ useEffect13(
44872
45754
  () => () => {
44873
45755
  const paintState = selectionPaintRef.current;
44874
45756
  if (paintState.timer) clearTimeout(paintState.timer);
@@ -45114,7 +45996,7 @@ function useSelectionFocusMove({
45114
45996
  // src/tui/app/use-transcript-scroll.mjs
45115
45997
  function useScrollCoalescer(scrollTranscriptRows) {
45116
45998
  const scrollCoalesceRef = useRef10({ pendingRows: 0, direction: 0, timer: null });
45117
- useEffect13(
45999
+ useEffect14(
45118
46000
  () => () => {
45119
46001
  const state = scrollCoalesceRef.current;
45120
46002
  if (state.timer) clearTimeout(state.timer);
@@ -45370,9 +46252,9 @@ function useTranscriptScroll({
45370
46252
  }
45371
46253
 
45372
46254
  // src/tui/app/use-transcript-scroll-state.mjs
45373
- import { useRef as useRef11, useState as useState6 } from "react";
46255
+ import { useRef as useRef11, useState as useState7 } from "react";
45374
46256
  function useTranscriptScrollState() {
45375
- const [scrollOffset, setScrollOffset] = useState6(0);
46257
+ const [scrollOffset, setScrollOffset] = useState7(0);
45376
46258
  const scrollPositionRef = useRef11(0);
45377
46259
  const scrollTargetRef = useRef11(0);
45378
46260
  const maxScrollRowsRef = useRef11(0);
@@ -45380,7 +46262,7 @@ function useTranscriptScrollState() {
45380
46262
  const transcriptAnchorRef = useRef11(null);
45381
46263
  const transcriptAnchorDirtyRef = useRef11(false);
45382
46264
  const transcriptGeomRef = useRef11({ prefixRows: null, totalRows: 0, viewRows: 1 });
45383
- const [measuredRowsVersion, setMeasuredRowsVersion] = useState6(0);
46265
+ const [measuredRowsVersion, setMeasuredRowsVersion] = useState7(0);
45384
46266
  const followingRef = useRef11(false);
45385
46267
  const lastItemsCountRef = useRef11(0);
45386
46268
  const lastFirstItemIdRef = useRef11(null);
@@ -45403,13 +46285,14 @@ function useTranscriptScrollState() {
45403
46285
  }
45404
46286
 
45405
46287
  // src/tui/app/use-prompt-state.mjs
45406
- import { useRef as useRef12, useState as useState7 } from "react";
46288
+ import { useRef as useRef12, useState as useState8 } from "react";
45407
46289
  function usePromptState() {
45408
- const [promptDraft, setPromptDraft] = useState7("");
45409
- const [promptDraftOverride, setPromptDraftOverride] = useState7(null);
46290
+ const [promptDraft, setPromptDraft] = useState8("");
46291
+ const [promptDraftOverride, setPromptDraftOverride] = useState8(null);
46292
+ const [promptCaret, setPromptCaret] = useState8(null);
45410
46293
  const promptLayoutValueRef = useRef12("");
45411
- const [, setPromptLayoutRows] = useState7(1);
45412
- const [textEntryLayoutRows, setTextEntryLayoutRows] = useState7(1);
46294
+ const [, setPromptLayoutRows] = useState8(1);
46295
+ const [textEntryLayoutRows, setTextEntryLayoutRows] = useState8(1);
45413
46296
  const promptValueRef = useRef12("");
45414
46297
  const promptSelectionRef = useRef12(null);
45415
46298
  const promptBoxRectRef = useRef12(null);
@@ -45421,6 +46304,8 @@ function usePromptState() {
45421
46304
  setPromptDraft,
45422
46305
  promptDraftOverride,
45423
46306
  setPromptDraftOverride,
46307
+ promptCaret,
46308
+ setPromptCaret,
45424
46309
  promptLayoutValueRef,
45425
46310
  setPromptLayoutRows,
45426
46311
  textEntryLayoutRows,
@@ -45468,7 +46353,7 @@ function useInteractionRefs() {
45468
46353
  }
45469
46354
 
45470
46355
  // src/tui/app/use-pasted-buffers.mjs
45471
- import { useCallback as useCallback13, useRef as useRef14, useState as useState8 } from "react";
46356
+ import { useCallback as useCallback13, useRef as useRef14, useState as useState9 } from "react";
45472
46357
 
45473
46358
  // src/tui/paste-attachments.mjs
45474
46359
  import { execFile } from "node:child_process";
@@ -46035,7 +46920,7 @@ async function readClipboardText() {
46035
46920
 
46036
46921
  // src/tui/app/use-pasted-buffers.mjs
46037
46922
  function usePastedBufferSlice({ toEntry, formatRef }) {
46038
- const [, setBuffers] = useState8({});
46923
+ const [, setBuffers] = useState9({});
46039
46924
  const buffersRef = useRef14({});
46040
46925
  const nextIdRef = useRef14(1);
46041
46926
  const install = useCallback13((buffers, { merge = true } = {}) => {
@@ -46104,11 +46989,11 @@ function usePastedBuffers() {
46104
46989
  }
46105
46990
 
46106
46991
  // src/tui/app/use-prompt-hint.mjs
46107
- import { useCallback as useCallback14, useEffect as useEffect14, useRef as useRef15, useState as useState9 } from "react";
46992
+ import { useCallback as useCallback14, useEffect as useEffect15, useRef as useRef15, useState as useState10 } from "react";
46108
46993
  var PROMPT_HINT_DISMISS_MS = 2200;
46109
46994
  function usePromptHint() {
46110
- const [promptHint, setPromptHint] = useState9("");
46111
- const [promptHintTone, setPromptHintTone] = useState9("info");
46995
+ const [promptHint, setPromptHint] = useState10("");
46996
+ const [promptHintTone, setPromptHintTone] = useState10("info");
46112
46997
  const promptHintTimerRef = useRef15(null);
46113
46998
  const promptHintActiveRef = useRef15(false);
46114
46999
  const showPromptHint = useCallback14((text, tone = "info", dismissMs = PROMPT_HINT_DISMISS_MS) => {
@@ -46135,7 +47020,7 @@ function usePromptHint() {
46135
47020
  setPromptHint("");
46136
47021
  setPromptHintTone("info");
46137
47022
  }, []);
46138
- useEffect14(
47023
+ useEffect15(
46139
47024
  () => () => {
46140
47025
  if (promptHintTimerRef.current) clearTimeout(promptHintTimerRef.current);
46141
47026
  },
@@ -46153,7 +47038,7 @@ function usePromptHint() {
46153
47038
  }
46154
47039
 
46155
47040
  // src/tui/app/use-welcome-prompt-hint.mjs
46156
- import { useCallback as useCallback15, useEffect as useEffect15, useRef as useRef16, useState as useState10 } from "react";
47041
+ import { useCallback as useCallback15, useEffect as useEffect16, useRef as useRef16, useState as useState11 } from "react";
46157
47042
 
46158
47043
  // src/tui/app/app-format.mjs
46159
47044
  import stringWidth5 from "string-width";
@@ -46654,8 +47539,8 @@ function cleanRightMessage(value) {
46654
47539
 
46655
47540
  // src/tui/app/use-welcome-prompt-hint.mjs
46656
47541
  function useWelcomePromptHint({ store, state, toastErrorSignature }) {
46657
- const [welcomePromptHintDismissed, setWelcomePromptHintDismissed] = useState10(false);
46658
- const [conditionalWelcomePromptHint, setConditionalWelcomePromptHint] = useState10("");
47542
+ const [welcomePromptHintDismissed, setWelcomePromptHintDismissed] = useState11(false);
47543
+ const [conditionalWelcomePromptHint, setConditionalWelcomePromptHint] = useState11("");
46659
47544
  const welcomePromptHintRef = useRef16(null);
46660
47545
  if (welcomePromptHintRef.current === null) {
46661
47546
  welcomePromptHintRef.current = randomWelcomePromptHint();
@@ -46665,7 +47550,7 @@ function useWelcomePromptHint({ store, state, toastErrorSignature }) {
46665
47550
  if (!welcomePromptHintVisibleRef.current) return;
46666
47551
  setWelcomePromptHintDismissed(true);
46667
47552
  }, []);
46668
- useEffect15(() => {
47553
+ useEffect16(() => {
46669
47554
  let alive = true;
46670
47555
  const refreshConditionalWelcomeHint = async () => {
46671
47556
  let quickModels;
@@ -48372,7 +49257,7 @@ function renderWelcomeBanner({ frameColumns, cwd: cwd2 }) {
48372
49257
  }
48373
49258
 
48374
49259
  // src/tui/hooks/useSharedTick.mjs
48375
- import { useEffect as useEffect16, useRef as useRef17, useState as useState11 } from "react";
49260
+ import { useEffect as useEffect17, useRef as useRef17, useState as useState12 } from "react";
48376
49261
  var TICK_SLOP_MS = 16;
48377
49262
  var subscribers = /* @__PURE__ */ new Set();
48378
49263
  var timer = null;
@@ -48407,10 +49292,10 @@ function onTick() {
48407
49292
  reconcileTimer();
48408
49293
  }
48409
49294
  function useSharedTick(intervalMs, isActive = true, onTick2 = null) {
48410
- const [, setTick] = useState11(0);
49295
+ const [, setTick] = useState12(0);
48411
49296
  const cbRef = useRef17(onTick2);
48412
49297
  cbRef.current = onTick2;
48413
- useEffect16(() => {
49298
+ useEffect17(() => {
48414
49299
  if (!isActive) return void 0;
48415
49300
  const interval = Math.max(1, Number(intervalMs) || 0);
48416
49301
  const sub = {
@@ -48954,7 +49839,7 @@ function statuslineFooterIdentityChanged(args, lastArgs) {
48954
49839
  if (!lastArgs) return true;
48955
49840
  if (args.sessionId !== lastArgs.sessionId) return true;
48956
49841
  if (args.provider !== lastArgs.provider || args.model !== lastArgs.model) return true;
48957
- if (args.effort !== lastArgs.effort || args.fast !== lastArgs.fast) return true;
49842
+ if (args.effort !== lastArgs.effort || args.fast !== lastArgs.fast || args.ultra !== lastArgs.ultra) return true;
48958
49843
  if (args.contextWindow !== lastArgs.contextWindow || args.rawContextWindow !== lastArgs.rawContextWindow) return true;
48959
49844
  if (args.displayContextWindow !== lastArgs.displayContextWindow) return true;
48960
49845
  if (args.compactBoundaryTokens !== lastArgs.compactBoundaryTokens) return true;
@@ -49027,7 +49912,7 @@ import { existsSync as existsSync7, readFileSync as readFileSync7 } from "node:f
49027
49912
  import { join as join7 } from "node:path";
49028
49913
 
49029
49914
  // src/runtime/shared/llm/provider-model-identities.mjs
49030
- function fallbackModel(id, display, family, contextWindow, wire) {
49915
+ function fallbackModel(id, display, family, contextWindow, wire, levels = []) {
49031
49916
  const tiered = wire && typeof wire === "object";
49032
49917
  return {
49033
49918
  id,
@@ -49039,7 +49924,7 @@ function fallbackModel(id, display, family, contextWindow, wire) {
49039
49924
  supportsVision: true,
49040
49925
  supportsReasoning: true,
49041
49926
  supportsFunctionCalling: true,
49042
- reasoningLevels: tiered ? Object.keys(wire) : [],
49927
+ reasoningLevels: tiered ? Object.keys(wire) : [...levels],
49043
49928
  wire
49044
49929
  };
49045
49930
  }
@@ -49053,8 +49938,16 @@ var ANTIGRAVITY_MODELS = Object.freeze([
49053
49938
  low: "gemini-3.1-pro-low",
49054
49939
  high: "gemini-3.1-pro-high"
49055
49940
  }),
49056
- fallbackModel("claude-opus-4-6-thinking", "Claude Opus 4.6 (Thinking)", null, 25e4, "claude-opus-4-6-thinking"),
49057
- fallbackModel("claude-sonnet-4-6", "Claude Sonnet 4.6 (Thinking)", null, 25e4, "claude-sonnet-4-6"),
49941
+ fallbackModel("claude-opus-4-6-thinking", "Claude Opus 4.6 (Thinking)", null, 25e4, "claude-opus-4-6-thinking", [
49942
+ "low",
49943
+ "medium",
49944
+ "high"
49945
+ ]),
49946
+ fallbackModel("claude-sonnet-4-6", "Claude Sonnet 4.6 (Thinking)", null, 25e4, "claude-sonnet-4-6", [
49947
+ "low",
49948
+ "medium",
49949
+ "high"
49950
+ ]),
49058
49951
  fallbackModel("gpt-oss-120b-medium", "GPT-OSS 120B (Medium)", "gpt-oss", 131072, "gpt-oss-120b-medium")
49059
49952
  ]);
49060
49953
  var ANTIGRAVITY_PRICING_ALIASES = Object.freeze({
@@ -49232,6 +50125,12 @@ var PROVIDER_CATALOGS = Object.freeze({
49232
50125
  // Effort tiers live in the wire id; a row without levels has no effort
49233
50126
  // surface (resolveAntigravityWireModel drops the effort).
49234
50127
  "antigravity-oauth": { relay: true, rosterFiles: ["antigravity-oauth-models.json"], rosterLadderFinal: true },
50128
+ // api.commandcode.ai/provider/v1 relays other vendors' models.
50129
+ "command-code-oauth": {
50130
+ relay: true,
50131
+ rosterFiles: ["command-code-oauth-models.json"],
50132
+ rosterLimitsAuthoritative: true
50133
+ },
49235
50134
  "cursor-oauth": { relay: true },
49236
50135
  "cursor-api": { relay: true },
49237
50136
  "opencode-go": { relay: true }
@@ -49958,6 +50857,7 @@ function localBootStatusLine(args = {}) {
49958
50857
  model = "",
49959
50858
  effort = "",
49960
50859
  fast = false,
50860
+ ultra = false,
49961
50861
  stats = null,
49962
50862
  contextWindow = 0,
49963
50863
  displayContextWindow = 0,
@@ -49966,7 +50866,9 @@ function localBootStatusLine(args = {}) {
49966
50866
  const raw = String(model || "").trim();
49967
50867
  const { STATUS, SUBTLE } = statusColors();
49968
50868
  const display = shortenModelName(displayModelName(raw, provider, ""), terminalColumns());
49969
- const flags = [effort ? String(effort).toUpperCase() : "", fast === true ? "FAST" : ""].filter(Boolean);
50869
+ let speedLabel = "";
50870
+ if (fast === true) speedLabel = ultra === true ? "Ultrafast" : "Fast";
50871
+ const flags = [effort ? effortDisplayLabel(effort) : "", speedLabel].filter(Boolean);
49970
50872
  const modelBits = [display, ...flags].join(` ${SUBTLE}\xB7${RESET3} `);
49971
50873
  const ctxPct = measuredContextUsage({
49972
50874
  stats,
@@ -50000,7 +50902,7 @@ ${freshL2}` : cachedL1;
50000
50902
  }
50001
50903
 
50002
50904
  // src/tui/components/status-line/use-statusline-text.mjs
50003
- import { useEffect as useEffect17, useRef as useRef19, useState as useState12 } from "react";
50905
+ import { useEffect as useEffect18, useRef as useRef19, useState as useState13 } from "react";
50004
50906
  function useStatusLineText({
50005
50907
  sessionId,
50006
50908
  clientHostPid,
@@ -50008,6 +50910,7 @@ function useStatusLineText({
50008
50910
  model,
50009
50911
  effort,
50010
50912
  fast,
50913
+ ultra,
50011
50914
  cwd: cwd2,
50012
50915
  stats,
50013
50916
  contextWindow,
@@ -50023,13 +50926,14 @@ function useStatusLineText({
50023
50926
  initialLine,
50024
50927
  themeEpoch
50025
50928
  }) {
50026
- const [line, setLine] = useState12(
50929
+ const [line, setLine] = useState13(
50027
50930
  () => normalizeStatusLine(
50028
50931
  initialLine || localBootStatusLine({
50029
50932
  provider,
50030
50933
  model,
50031
50934
  effort,
50032
50935
  fast,
50936
+ ultra,
50033
50937
  stats,
50034
50938
  contextWindow,
50035
50939
  displayContextWindow,
@@ -50042,7 +50946,7 @@ function useStatusLineText({
50042
50946
  })
50043
50947
  )
50044
50948
  );
50045
- const [refreshTick, setRefreshTick] = useState12(0);
50949
+ const [refreshTick, setRefreshTick] = useState13(0);
50046
50950
  const statuslineArgsRef = useRef19(null);
50047
50951
  const bootFullDoneRef = useRef19(false);
50048
50952
  const mountAtRef = useRef19(Date.now());
@@ -50060,6 +50964,7 @@ function useStatusLineText({
50060
50964
  model,
50061
50965
  effort,
50062
50966
  fast,
50967
+ ultra,
50063
50968
  cwd: cwd2,
50064
50969
  stats,
50065
50970
  contextWindow,
@@ -50092,13 +50997,13 @@ function useStatusLineText({
50092
50997
  String(statsForSignature.currentContextSource || "")
50093
50998
  ].join("|");
50094
50999
  const refreshMs = hasActiveStatuslineWork(line, agentWorkers, agentJobs, activeTools) ? STATUSLINE_ACTIVE_REFRESH_MS : STATUSLINE_REFRESH_MS;
50095
- useEffect17(() => {
51000
+ useEffect18(() => {
50096
51001
  scheduleStatuslineModulePrewarm();
50097
51002
  }, []);
50098
51003
  useSharedTick(refreshMs, true, () => {
50099
51004
  setRefreshTick((tick) => (tick + 1) % 1e6);
50100
51005
  });
50101
- useEffect17(() => {
51006
+ useEffect18(() => {
50102
51007
  let alive = true;
50103
51008
  let bootRetryTimer = null;
50104
51009
  const effectId = renderEffectIdRef.current + 1;
@@ -50107,7 +51012,7 @@ function useStatusLineText({
50107
51012
  const args = statuslineArgsRef.current;
50108
51013
  const identityChanged = statuslineFooterIdentityChanged({ ...args, agentRevision }, lastImmediateArgsRef.current);
50109
51014
  const prevImmediate = lastImmediateArgsRef.current;
50110
- const routeChanged = !prevImmediate || prevImmediate.sessionId !== args.sessionId || prevImmediate.provider !== args.provider || prevImmediate.model !== args.model || prevImmediate.effort !== args.effort || prevImmediate.fast !== args.fast;
51015
+ const routeChanged = !prevImmediate || prevImmediate.sessionId !== args.sessionId || prevImmediate.provider !== args.provider || prevImmediate.model !== args.model || prevImmediate.effort !== args.effort || prevImmediate.fast !== args.fast || prevImmediate.ultra !== args.ultra;
50111
51016
  const themeChanged = themeEpochRef.current !== themeEpoch;
50112
51017
  if (themeChanged) {
50113
51018
  themeEpochRef.current = themeEpoch;
@@ -50128,6 +51033,7 @@ function useStatusLineText({
50128
51033
  model: args.model,
50129
51034
  effort: args.effort,
50130
51035
  fast: args.fast,
51036
+ ultra: args.ultra,
50131
51037
  contextWindow: args.contextWindow,
50132
51038
  displayContextWindow: args.displayContextWindow,
50133
51039
  rawContextWindow: args.rawContextWindow,
@@ -50196,6 +51102,7 @@ function useStatusLineText({
50196
51102
  model,
50197
51103
  effort,
50198
51104
  fast,
51105
+ ultra,
50199
51106
  cwd2,
50200
51107
  statsSignature,
50201
51108
  contextWindow,
@@ -50223,6 +51130,7 @@ function StatusLineView({
50223
51130
  model,
50224
51131
  effort,
50225
51132
  fast,
51133
+ ultra = false,
50226
51134
  cwd: cwd2,
50227
51135
  stats,
50228
51136
  contextWindow,
@@ -50246,6 +51154,7 @@ function StatusLineView({
50246
51154
  model,
50247
51155
  effort,
50248
51156
  fast,
51157
+ ultra,
50249
51158
  cwd: cwd2,
50250
51159
  stats,
50251
51160
  contextWindow,
@@ -50287,7 +51196,7 @@ function StatusLineView({
50287
51196
  var StatusLine = React11.memo(StatusLineView);
50288
51197
 
50289
51198
  // src/tui/components/PromptInput.jsx
50290
- import { useEffect as useEffect18, useLayoutEffect as useLayoutEffect4, useState as useState13, useRef as useRef20 } from "react";
51199
+ import { useEffect as useEffect19, useLayoutEffect as useLayoutEffect4, useState as useState14, useRef as useRef20 } from "react";
50291
51200
 
50292
51201
  // src/tui/input-editing.mjs
50293
51202
  var graphemeSegmenter4 = new Intl.Segmenter(void 0, { granularity: "grapheme" });
@@ -50990,6 +51899,11 @@ function gridSelectionActive(suppressShiftNavRef) {
50990
51899
  if (typeof suppressShiftNavRef?.current === "function") return suppressShiftNavRef.current();
50991
51900
  return Boolean(suppressShiftNavRef?.current);
50992
51901
  }
51902
+ function paletteResultDraft(result) {
51903
+ if (typeof result === "string") return { value: result, cursor: result.length, selectionAnchor: null };
51904
+ if (typeof result?.value === "string") return { value: result.value, cursor: result.cursor, selectionAnchor: null };
51905
+ return null;
51906
+ }
50993
51907
  function createPromptKeyHandler(ctx) {
50994
51908
  const {
50995
51909
  disabled,
@@ -51003,6 +51917,7 @@ function createPromptKeyHandler(ctx) {
51003
51917
  submitDraft,
51004
51918
  commandPaletteActive,
51005
51919
  commandPaletteOptionCount,
51920
+ commandPaletteMovesCaret,
51006
51921
  onCommandPaletteNavigate,
51007
51922
  onCommandPaletteAccept,
51008
51923
  onCommandPaletteComplete,
@@ -51083,8 +51998,11 @@ function createPromptKeyHandler(ctx) {
51083
51998
  return;
51084
51999
  }
51085
52000
  if (commandPaletteActive) {
51086
- const accepted = onCommandPaletteAccept?.(draftRef.current.value);
51087
- if (accepted !== false) {
52001
+ const accepted = onCommandPaletteAccept?.(draftRef.current.value, draftRef.current.cursor);
52002
+ const replacement = paletteResultDraft(accepted);
52003
+ if (replacement) {
52004
+ commitDraft(replacement);
52005
+ } else if (accepted !== false) {
51088
52006
  commitDraft({ value: "", cursor: 0, selectionAnchor: null });
51089
52007
  }
51090
52008
  return;
@@ -51163,10 +52081,10 @@ ${d.value.slice(d.cursor)}`,
51163
52081
  }
51164
52082
  if (key.tab) {
51165
52083
  if (commandPaletteActive) {
51166
- const completed = onCommandPaletteComplete?.(draftRef.current.value);
51167
- if (typeof completed === "string") {
51168
- commitDraft({ value: completed, cursor: completed.length, selectionAnchor: null });
51169
- }
52084
+ const completed = paletteResultDraft(
52085
+ onCommandPaletteComplete?.(draftRef.current.value, draftRef.current.cursor)
52086
+ );
52087
+ if (completed) commitDraft(completed);
51170
52088
  return;
51171
52089
  }
51172
52090
  if (onTab?.(draftRef.current.value) === true) return;
@@ -51176,7 +52094,7 @@ ${d.value.slice(d.cursor)}`,
51176
52094
  return;
51177
52095
  }
51178
52096
  if (key.leftArrow || rawShiftLeft) {
51179
- if (commandPaletteActive) {
52097
+ if (commandPaletteActive && !commandPaletteMovesCaret) {
51180
52098
  onCommandPaletteNavigate?.("left");
51181
52099
  return;
51182
52100
  }
@@ -51186,7 +52104,7 @@ ${d.value.slice(d.cursor)}`,
51186
52104
  return;
51187
52105
  }
51188
52106
  if (key.rightArrow || rawShiftRight) {
51189
- if (commandPaletteActive) {
52107
+ if (commandPaletteActive && !commandPaletteMovesCaret) {
51190
52108
  onCommandPaletteNavigate?.("right");
51191
52109
  return;
51192
52110
  }
@@ -51393,6 +52311,8 @@ function PromptInput({
51393
52311
  commandPaletteActive = false,
51394
52312
  commandPaletteOpen = commandPaletteActive,
51395
52313
  commandPaletteOptionCount = commandPaletteActive ? 2 : 0,
52314
+ commandPaletteMovesCaret = false,
52315
+ onCaretChange,
51396
52316
  mask = false,
51397
52317
  hint = "",
51398
52318
  hintTone = "info",
@@ -51415,13 +52335,14 @@ function PromptInput({
51415
52335
  mouseSelectionRef,
51416
52336
  suppressShiftNavRef
51417
52337
  }) {
51418
- const [draft, setDraft] = useState13(() => {
52338
+ const [draft, setDraft] = useState14(() => {
51419
52339
  const value2 = String(initialValue || "");
51420
52340
  return { value: value2, cursor: value2.length, selectionAnchor: null };
51421
52341
  });
51422
- const [, bumpCursorAnchorEpoch] = useState13(0);
52342
+ const [, bumpCursorAnchorEpoch] = useState14(0);
51423
52343
  const draftRef = useRef20(draft);
51424
52344
  const lastReportedValueRef = useRef20(draft.value);
52345
+ const lastReportedCursorRef = useRef20(null);
51425
52346
  const pasteGenerationRef = useRef20(0);
51426
52347
  const submitGateRef = useRef20(false);
51427
52348
  const escapeClearAtRef = useRef20(0);
@@ -51464,7 +52385,7 @@ function PromptInput({
51464
52385
  flush: flushImmediate
51465
52386
  });
51466
52387
  };
51467
- useEffect18(
52388
+ useEffect19(
51468
52389
  () => () => {
51469
52390
  cancelPromptImmediateFlush(flushThrottleRef.current);
51470
52391
  },
@@ -51491,8 +52412,15 @@ function PromptInput({
51491
52412
  lastReportedValueRef.current = next.value;
51492
52413
  onDraftChange?.(next.value);
51493
52414
  }
52415
+ reportCaret(next.cursor);
51494
52416
  if (valueRef) valueRef.current = next.value;
51495
52417
  };
52418
+ function reportCaret(nextCursor) {
52419
+ if (nextCursor === lastReportedCursorRef.current) return;
52420
+ lastReportedCursorRef.current = nextCursor;
52421
+ onCaretChange?.(nextCursor);
52422
+ }
52423
+ useEffect19(() => reportCaret(draftRef.current.cursor), []);
51496
52424
  const installCursorAnchor = () => {
51497
52425
  if (!boxRef.current || boxRef.current.internal_cursorAnchor) return false;
51498
52426
  boxRef.current.internal_cursorAnchor = createCursorAnchor({
@@ -51515,7 +52443,7 @@ function PromptInput({
51515
52443
  commitDraft
51516
52444
  });
51517
52445
  }
51518
- useEffect18(
52446
+ useEffect19(
51519
52447
  () => () => {
51520
52448
  const state = mouseExtendCoalesceRef.current;
51521
52449
  if (state.timer) clearTimeout(state.timer);
@@ -51573,7 +52501,7 @@ function PromptInput({
51573
52501
  apply(handled);
51574
52502
  }
51575
52503
  };
51576
- useEffect18(() => {
52504
+ useEffect19(() => {
51577
52505
  if (!draftOverride || typeof draftOverride.value !== "string") return;
51578
52506
  pasteGenerationRef.current += 1;
51579
52507
  const nextValue = draftOverride.value;
@@ -51582,7 +52510,7 @@ function PromptInput({
51582
52510
  commitDraft({ value: nextValue, cursor: nextCursor, selectionAnchor: nextAnchor }, { skipHistory: true });
51583
52511
  undoStack.reset();
51584
52512
  }, [draftOverride?.id, draftOverride?.value, draftOverride?.cursor, draftOverride?.selectionAnchor]);
51585
- useEffect18(
52513
+ useEffect19(
51586
52514
  () => () => {
51587
52515
  pasteGenerationRef.current += 1;
51588
52516
  if (selectionRef) selectionRef.current = null;
@@ -51611,8 +52539,11 @@ function PromptInput({
51611
52539
  const current = draftRef.current;
51612
52540
  const next = prefix ? insertText(current, prefix) : current;
51613
52541
  if (commandPaletteActive) {
51614
- const accepted = onCommandPaletteAccept?.(next.value);
51615
- if (accepted !== false) {
52542
+ const accepted = onCommandPaletteAccept?.(next.value, next.cursor);
52543
+ const replacement = paletteResultDraft(accepted);
52544
+ if (replacement) {
52545
+ commitDraft(replacement);
52546
+ } else if (accepted !== false) {
51616
52547
  commitDraft({ value: "", cursor: 0, selectionAnchor: null });
51617
52548
  } else if (next !== current) {
51618
52549
  commitDraft(next);
@@ -51641,6 +52572,7 @@ function PromptInput({
51641
52572
  commandPaletteActive,
51642
52573
  commandPaletteOpen,
51643
52574
  commandPaletteOptionCount,
52575
+ commandPaletteMovesCaret,
51644
52576
  onCommandPaletteNavigate,
51645
52577
  onCommandPaletteAccept,
51646
52578
  onCommandPaletteCancel,
@@ -52032,20 +52964,20 @@ function usePickerInput({
52032
52964
  }
52033
52965
 
52034
52966
  // src/tui/components/picker/use-picker-selection.mjs
52035
- import { useEffect as useEffect19, useRef as useRef21, useState as useState14 } from "react";
52967
+ import { useEffect as useEffect20, useRef as useRef21, useState as useState15 } from "react";
52036
52968
  function usePickerSelection({ items, initialIndex, onHighlight, confirmButtons, confirmBar }) {
52037
- const [selectedIndex, setSelectedIndex] = useState14(() => clampItemIndex(initialIndex, items.length));
52038
- const [confirmFocus, setConfirmFocus] = useState14(-1);
52969
+ const [selectedIndex, setSelectedIndex] = useState15(() => clampItemIndex(initialIndex, items.length));
52970
+ const [confirmFocus, setConfirmFocus] = useState15(-1);
52039
52971
  const lastTabAtRef = useRef21(0);
52040
- useEffect19(() => {
52972
+ useEffect20(() => {
52041
52973
  setConfirmFocus(-1);
52042
52974
  }, [confirmButtons.length, confirmBar]);
52043
- const [selectionMemo] = useState14(() => ({ value: null, initialIndex }));
52044
- useEffect19(() => {
52975
+ const [selectionMemo] = useState15(() => ({ value: null, initialIndex }));
52976
+ useEffect20(() => {
52045
52977
  const item = items[selectedIndex];
52046
52978
  if (item && item.value != null) selectionMemo.value = item.value;
52047
52979
  }, [items, selectedIndex, selectionMemo]);
52048
- useEffect19(() => {
52980
+ useEffect20(() => {
52049
52981
  setSelectedIndex((i) => {
52050
52982
  if (selectionMemo.value != null) {
52051
52983
  const found = items.findIndex((entry) => entry && entry.value === selectionMemo.value);
@@ -52056,7 +52988,7 @@ function usePickerSelection({ items, initialIndex, onHighlight, confirmButtons,
52056
52988
  return Math.min(Math.max(0, i), Math.max(0, items.length - 1));
52057
52989
  });
52058
52990
  }, [items, selectionMemo, initialIndex]);
52059
- useEffect19(() => {
52991
+ useEffect20(() => {
52060
52992
  if (initialIndex == null) {
52061
52993
  selectionMemo.initialIndex = null;
52062
52994
  return;
@@ -52065,7 +52997,7 @@ function usePickerSelection({ items, initialIndex, onHighlight, confirmButtons,
52065
52997
  selectionMemo.initialIndex = initialIndex;
52066
52998
  setSelectedIndex(clampItemIndex(initialIndex, items.length));
52067
52999
  }, [initialIndex, items.length, selectionMemo]);
52068
- useEffect19(() => {
53000
+ useEffect20(() => {
52069
53001
  if (typeof onHighlight !== "function") return;
52070
53002
  const item = items[selectedIndex];
52071
53003
  if (item) onHighlight(item.value, item, selectedIndex);
@@ -52313,12 +53245,21 @@ function queryMatchesAlias(command, query) {
52313
53245
  );
52314
53246
  }
52315
53247
  function commandDisplayLabel(command, query) {
53248
+ if (command?.label) return command.label;
52316
53249
  const usage = String(command?.usage || command?.name || "").replace(/^\/+/, "");
52317
53250
  const aliasText = command?.showAliasUsage !== false && queryMatchesAlias(command, query) && Array.isArray(command?.aliasUsage) && command.aliasUsage.length > 0 ? ` (${command.aliasUsage.join(", ")})` : "";
52318
53251
  const label = ACRONYM_LABELS.get(usage.toLowerCase()) || (usage ? `${usage.charAt(0).toUpperCase()}${usage.slice(1)}` : usage);
52319
53252
  return `${label}${aliasText}`;
52320
53253
  }
52321
- function SlashCommandPalette({ commands: commands2, selectedIndex = 0, title = "Commands", columns = 80, query = "" }) {
53254
+ function SlashCommandPalette({
53255
+ commands: commands2,
53256
+ selectedIndex = 0,
53257
+ title = "Commands",
53258
+ columns = 80,
53259
+ query = "",
53260
+ description: descriptionText = SLASH_DESCRIPTION,
53261
+ help: helpText = SLASH_HELP
53262
+ }) {
52322
53263
  const total = commands2.length;
52323
53264
  const half = Math.floor(MAX_VISIBLE2 / 2);
52324
53265
  let start = Math.max(0, selectedIndex - half);
@@ -52331,9 +53272,9 @@ function SlashCommandPalette({ commands: commands2, selectedIndex = 0, title = "
52331
53272
  const blankRows = Math.max(0, MAX_VISIBLE2 - visible.length - (noMatches ? 1 : 0));
52332
53273
  const labelWidth = Math.min(COMMAND_LABEL_WIDTH, Math.max(12, Math.floor(columns * 0.45)));
52333
53274
  const descriptionWidth = Math.max(0, columns - labelWidth - 12);
52334
- const description = truncatePanelText(SLASH_DESCRIPTION, Math.max(0, columns - 4));
53275
+ const description = truncatePanelText(descriptionText, Math.max(0, columns - 4));
52335
53276
  const titleWidth = stringWidth9(String(title || ""));
52336
- const help = truncatePanelText(SLASH_HELP, Math.max(0, columns - titleWidth - 7));
53277
+ const help = truncatePanelText(helpText, Math.max(0, columns - titleWidth - 7));
52337
53278
  return /* @__PURE__ */ jsx11(Box_default, { flexDirection: "column", flexShrink: 0, width: "100%", children: /* @__PURE__ */ jsxs9(Box_default, { flexDirection: "column", borderStyle: "round", borderColor: theme.promptBorder, paddingX: 1, width: "100%", children: [
52338
53279
  /* @__PURE__ */ jsxs9(Box_default, { flexDirection: "row", justifyContent: "space-between", children: [
52339
53280
  /* @__PURE__ */ jsx11(Text, { color: theme.panelTitle, wrap: "truncate", children: title }),
@@ -52374,7 +53315,7 @@ var CommandRow = React13.memo(function CommandRow2({ command, isSelected, labelW
52374
53315
  import stringWidth11 from "string-width";
52375
53316
 
52376
53317
  // src/tui/components/ContextInspector.jsx
52377
- import { useEffect as useEffect20, useRef as useRef22, useState as useState15 } from "react";
53318
+ import { useEffect as useEffect21, useRef as useRef22, useState as useState16 } from "react";
52378
53319
  import wrapAnsi4 from "wrap-ansi";
52379
53320
  import stringWidth10 from "string-width";
52380
53321
 
@@ -52435,13 +53376,13 @@ function fitLine2(text, width) {
52435
53376
  return result;
52436
53377
  }
52437
53378
  function ContextInspector({ inspection, columns, rows: rows2 = 16, windowTokens, onInspect, onRefresh }) {
52438
- const [category, setCategory] = useState15("");
52439
- const [index, setIndex] = useState15(0);
52440
- const [preview, setPreview] = useState15(null);
52441
- const [scroll, setScroll] = useState15(0);
52442
- const [fit, setFit] = useState15(false);
53379
+ const [category, setCategory] = useState16("");
53380
+ const [index, setIndex] = useState16(0);
53381
+ const [preview, setPreview] = useState16(null);
53382
+ const [scroll, setScroll] = useState16(0);
53383
+ const [fit, setFit] = useState16(false);
52443
53384
  const request = useRef22(0);
52444
- useEffect20(
53385
+ useEffect21(
52445
53386
  () => () => {
52446
53387
  request.current += 1;
52447
53388
  },
@@ -52807,7 +53748,7 @@ function ContextPanel({
52807
53748
  }
52808
53749
 
52809
53750
  // src/tui/components/UsagePanel.jsx
52810
- import { useEffect as useEffect21, useState as useState16 } from "react";
53751
+ import { useEffect as useEffect22, useState as useState17 } from "react";
52811
53752
  import stringWidth12 from "string-width";
52812
53753
 
52813
53754
  // src/session-runtime/services/usage-dashboard-model.mjs
@@ -52835,7 +53776,7 @@ import { Fragment as Fragment6, jsx as jsx14, jsxs as jsxs12 } from "react/jsx-r
52835
53776
  var PROVIDER_LABEL_WIDTH = 28;
52836
53777
  var CREDIT_LABEL = "Credit";
52837
53778
  var STATUS_SEPARATOR2 = " \u2502 ";
52838
- function resetLabel(value) {
53779
+ function resetLabel2(value) {
52839
53780
  const at = Number(value);
52840
53781
  if (!Number.isFinite(at) || at <= 0) return "";
52841
53782
  const date = new Date(at);
@@ -52874,7 +53815,7 @@ function creditsColor(w) {
52874
53815
  }
52875
53816
  function windowResetText(w) {
52876
53817
  if (isLocalEstimateWindow(w)) return "";
52877
- const reset = resetLabel(w?.resetAt);
53818
+ const reset = resetLabel2(w?.resetAt);
52878
53819
  if (!reset) return "";
52879
53820
  return `\u21BB ${reset}`;
52880
53821
  }
@@ -53023,11 +53964,11 @@ function UsagePanel({ dashboard, loading = false, columns = 80, fillHeight = fal
53023
53964
  const hasMeasuredRows = Number(panelRows) > 0;
53024
53965
  const maxProviderRows = hasMeasuredRows ? Math.max(1, Math.floor(panelRows) - 6) : rows2.length;
53025
53966
  const maxScrollOffset = Math.max(0, rows2.length - maxProviderRows);
53026
- const [scrollOffset, setScrollOffset] = useState16(0);
53967
+ const [scrollOffset, setScrollOffset] = useState17(0);
53027
53968
  const visibleRows = hasMeasuredRows ? rows2.slice(scrollOffset, scrollOffset + maxProviderRows) : rows2;
53028
53969
  const scrollable = rows2.length > maxProviderRows;
53029
53970
  const helpText = `${scrollable || isLoading || isChecking ? "\u2191/\u2193 Scroll \xB7 PgUp/PgDn Page \xB7 " : ""}Esc Back \xB7 /usage refresh`;
53030
- useEffect21(() => {
53971
+ useEffect22(() => {
53031
53972
  setScrollOffset((offset) => Math.min(Math.max(0, offset), maxScrollOffset));
53032
53973
  }, [maxScrollOffset]);
53033
53974
  use_input_default((_input, key) => {
@@ -53106,7 +54047,7 @@ function UsagePanel({ dashboard, loading = false, columns = 80, fillHeight = fal
53106
54047
  }
53107
54048
 
53108
54049
  // src/tui/components/TextEntryPanel.jsx
53109
- import { useEffect as useEffect22, useLayoutEffect as useLayoutEffect5, useRef as useRef23, useState as useState17 } from "react";
54050
+ import { useEffect as useEffect23, useLayoutEffect as useLayoutEffect5, useRef as useRef23, useState as useState18 } from "react";
53110
54051
  import stringWidth14 from "string-width";
53111
54052
 
53112
54053
  // src/tui/components/text-entry-layout.mjs
@@ -53261,12 +54202,12 @@ function TextEntryPanel({
53261
54202
  onSubmit,
53262
54203
  onCancel
53263
54204
  }) {
53264
- const [draft, setDraft] = useState17(() => ({
54205
+ const [draft, setDraft] = useState18(() => ({
53265
54206
  value: String(initialValue || ""),
53266
54207
  cursor: String(initialValue || "").length,
53267
54208
  selectionAnchor: null
53268
54209
  }));
53269
- const [, bumpCursorAnchorEpoch] = useState17(0);
54210
+ const [, bumpCursorAnchorEpoch] = useState18(0);
53270
54211
  const draftRef = useRef23(draft);
53271
54212
  const submitGateRef = useRef23(false);
53272
54213
  const boxRef = useRef23(null);
@@ -53295,13 +54236,13 @@ function TextEntryPanel({
53295
54236
  commitDraft(fn(draftRef.current), options);
53296
54237
  };
53297
54238
  const moveDraftVertically = createVerticalMover({ draftRef, contentWidthRef, preferredColumnRef, commitDraft });
53298
- useEffect22(() => {
54239
+ useEffect23(() => {
53299
54240
  const value = String(initialValue || "");
53300
54241
  commitDraft({ value, cursor: value.length, selectionAnchor: null });
53301
54242
  }, [title, initialValue]);
53302
54243
  const labelCells = stringWidth14(String(promptLabel || ""));
53303
54244
  const contentCells = Math.max(1, columns - 4 - labelCells);
53304
- useEffect22(() => {
54245
+ useEffect23(() => {
53305
54246
  if (!multiline) {
53306
54247
  onContentRowsChange?.(1);
53307
54248
  return;
@@ -53584,6 +54525,10 @@ function settingsPromptFields(kind) {
53584
54525
 
53585
54526
  // src/tui/app/app-view/floating-panel.jsx
53586
54527
  import { jsx as jsx16 } from "react/jsx-runtime";
54528
+ var SKILL_PALETTE_TEXT = {
54529
+ description: "Type to filter \xB7 Enter or Tab inserts the highlighted skill.",
54530
+ help: "\u2191/\u2193 select \xB7 Enter insert \xB7 Esc cancel"
54531
+ };
53587
54532
  function renderToolApproval({ toolApproval, store, frameColumns, expandedOptionPanel }) {
53588
54533
  const resolve3 = (approved) => {
53589
54534
  store.resolveToolApproval?.(toolApproval.id, {
@@ -53730,14 +54675,16 @@ function renderFloatingPanel(ctx) {
53730
54675
  );
53731
54676
  }
53732
54677
  if (slashPaletteOpen) {
54678
+ const skills = ctx.paletteKind === "skills";
53733
54679
  return /* @__PURE__ */ jsx16(
53734
54680
  SlashCommandPalette,
53735
54681
  {
53736
54682
  commands: slashCommands,
53737
54683
  selectedIndex: slashIndex,
53738
- title: "Commands",
54684
+ title: skills ? "Skills" : "Commands",
53739
54685
  columns: frameColumns,
53740
- query: activeSlashQuery
54686
+ query: activeSlashQuery,
54687
+ ...skills ? SKILL_PALETTE_TEXT : {}
53741
54688
  }
53742
54689
  );
53743
54690
  }
@@ -54074,10 +55021,13 @@ var UserMessage = React16.memo(function UserMessage2({
54074
55021
  text,
54075
55022
  attached = false,
54076
55023
  columns,
55024
+ appliedSkills,
54077
55025
  themeEpoch: _themeEpoch = 0
54078
55026
  }) {
54079
55027
  const bandColumns = Math.max(1, columns - 1);
54080
- return /* @__PURE__ */ jsx20(
55028
+ const skillsLine = appliedSkillsLine(appliedSkills);
55029
+ const segments = userTextSegments(text, appliedSkills);
55030
+ return /* @__PURE__ */ jsxs15(
54081
55031
  Box_default,
54082
55032
  {
54083
55033
  flexDirection: "column",
@@ -54086,7 +55036,12 @@ var UserMessage = React16.memo(function UserMessage2({
54086
55036
  backgroundColor: theme.userMessageBackground,
54087
55037
  paddingLeft: 2,
54088
55038
  paddingRight: 1,
54089
- children: /* @__PURE__ */ jsx20(Text, { color: theme.mixdogIvory, wrap: "wrap", children: text })
55039
+ children: [
55040
+ /* @__PURE__ */ jsx20(Text, { color: theme.mixdogIvory, wrap: "wrap", children: segments.length === 1 && !segments[0].mention ? text : segments.map(
55041
+ (segment, index) => segment.mention ? /* @__PURE__ */ jsx20(Text, { color: theme.panelTitle, bold: true, children: segment.text }, index) : segment.text
55042
+ ) }),
55043
+ skillsLine ? /* @__PURE__ */ jsx20(Text, { color: theme.subtle, wrap: "wrap", children: skillsLine }) : null
55044
+ ]
54090
55045
  }
54091
55046
  );
54092
55047
  });
@@ -54649,7 +55604,16 @@ var Item = React17.memo(function Item2({
54649
55604
  let node = null;
54650
55605
  switch (item.kind) {
54651
55606
  case "user":
54652
- node = /* @__PURE__ */ jsx27(UserMessage, { text: item.text, attached: prevKind === "user", columns, themeEpoch });
55607
+ node = /* @__PURE__ */ jsx27(
55608
+ UserMessage,
55609
+ {
55610
+ text: item.text,
55611
+ attached: prevKind === "user",
55612
+ columns,
55613
+ appliedSkills: item.appliedSkills,
55614
+ themeEpoch
55615
+ }
55616
+ );
54653
55617
  break;
54654
55618
  case "assistant":
54655
55619
  node = /* @__PURE__ */ jsx27(
@@ -54946,8 +55910,10 @@ function renderAppView(ctx) {
54946
55910
  inputHint,
54947
55911
  inputHintTone,
54948
55912
  liveSpinner,
55913
+ onPromptCaretChange,
54949
55914
  onPromptDraftChange,
54950
55915
  onSubmit,
55916
+ paletteKind,
54951
55917
  panelTransitionClearRows,
54952
55918
  picker,
54953
55919
  promptBoxRectRef,
@@ -54980,6 +55946,7 @@ function renderAppView(ctx) {
54980
55946
  onSubmit,
54981
55947
  disabled: exiting || !!picker || !!contextPanel || !!toolApproval || !tuiReady,
54982
55948
  onDraftChange: onPromptDraftChange,
55949
+ onCaretChange: onPromptCaretChange,
54983
55950
  interruptActive: state.busy,
54984
55951
  onInterrupt: handlePromptInterrupt,
54985
55952
  initialValue: promptDraft,
@@ -54999,6 +55966,7 @@ function renderAppView(ctx) {
54999
55966
  commandPaletteActive: slashPaletteOpen && slashCommands.length > 0,
55000
55967
  commandPaletteOpen: slashPaletteOpen,
55001
55968
  commandPaletteOptionCount: slashCommands.length,
55969
+ commandPaletteMovesCaret: paletteKind === "skills",
55002
55970
  onCommandPaletteNavigate: (direction) => {
55003
55971
  setSlashIndex((index) => stepPaletteIndex(index, direction, slashCommands.length));
55004
55972
  },
@@ -55108,6 +56076,7 @@ function renderAppView(ctx) {
55108
56076
  model: state.model,
55109
56077
  effort: state.effort,
55110
56078
  fast: state.fast,
56079
+ ultra: state.fast === true && state.modelParameters?.serviceTier === "ultrafast",
55111
56080
  cwd: state.cwd,
55112
56081
  stats: statuslineStats,
55113
56082
  contextWindow: state.contextWindow,
@@ -55278,9 +56247,10 @@ function usePromptDraftFlow({
55278
56247
  [settingsPrompt, setSettingsPrompt, openProjectPicker, openMemoryCorePicker, openAutoClearPicker]
55279
56248
  );
55280
56249
  const acceptSlashPalette = useCallback18(
55281
- (draftValue = "") => {
56250
+ (draftValue = "", caret) => {
55282
56251
  const command = slashCommands[slashIndex];
55283
56252
  if (!command) return false;
56253
+ if (command.kind === "skill") return completeSkillMention(draftValue, command.name, caret) ?? false;
55284
56254
  return withPickerEnterLatch(
55285
56255
  pickerOpenedFromEnterRef,
55286
56256
  pickerOpenedFromEnterTimerRef,
@@ -55290,9 +56260,10 @@ function usePromptDraftFlow({
55290
56260
  [slashCommands, slashIndex, pickerOpenedFromEnterRef, pickerOpenedFromEnterTimerRef, runSlashCommand]
55291
56261
  );
55292
56262
  const completeSlashPalette = useCallback18(
55293
- (draftValue = "") => {
56263
+ (draftValue = "", caret) => {
55294
56264
  const command = slashCommands[slashIndex];
55295
56265
  if (!command) return void 0;
56266
+ if (command.kind === "skill") return completeSkillMention(draftValue, command.name, caret);
55296
56267
  const token = slashCommandTokenForPaletteAccept(command, draftValue);
55297
56268
  return token ? `/${token} ` : void 0;
55298
56269
  },
@@ -55780,6 +56751,105 @@ function createCoreMemoryPicker({ store, surface, setSettingsPrompt, parseMemory
55780
56751
  };
55781
56752
  }
55782
56753
 
56754
+ // src/tui/app/extension-pickers/mcp-login.mjs
56755
+ var POLL_MS = 1500;
56756
+ function createMcpLogin({ store, setProviderPrompt, pollMs = POLL_MS }) {
56757
+ let active = null;
56758
+ const stop = (flow) => {
56759
+ flow.finished = true;
56760
+ clearTimeout(flow.timer);
56761
+ if (active === flow) active = null;
56762
+ };
56763
+ const closePrompt = (flow) => setProviderPrompt((prompt) => prompt === flow.prompt ? null : prompt);
56764
+ const showPrompt = (flow) => {
56765
+ if (flow.finished) return;
56766
+ const prompt = {
56767
+ kind: "oauth-code",
56768
+ providerName: `MCP ${flow.name}`,
56769
+ // The shared prompt pushes the one completion notice; no provider picker follows.
56770
+ successReturn: () => {
56771
+ },
56772
+ label: `MCP sign-in \xB7 ${flow.name}`,
56773
+ hint: "If the browser page fails to load, paste its address here.",
56774
+ detail: flow.url,
56775
+ login: {
56776
+ completeCode: async (text) => {
56777
+ const result = await store.completeMcpOAuthLogin(flow.id, text);
56778
+ if (result?.state !== "complete") throw new Error(result?.error || "sign-in did not complete");
56779
+ stop(flow);
56780
+ },
56781
+ cancel: () => {
56782
+ if (flow.finished) return;
56783
+ stop(flow);
56784
+ void Promise.resolve(store.cancelMcpOAuthLogin(flow.id)).catch(() => {
56785
+ });
56786
+ store.pushNotice(`MCP sign-in cancelled for ${flow.name}`, "info");
56787
+ }
56788
+ },
56789
+ failureReturn: () => showPrompt(flow)
56790
+ };
56791
+ flow.prompt = prompt;
56792
+ setProviderPrompt(prompt);
56793
+ };
56794
+ const poll = (flow) => {
56795
+ flow.timer = setTimeout(async () => {
56796
+ if (flow.finished) return;
56797
+ let status;
56798
+ try {
56799
+ status = await store.getMcpOAuthLoginStatus(flow.id);
56800
+ } catch (e) {
56801
+ if (flow.finished) return;
56802
+ stop(flow);
56803
+ closePrompt(flow);
56804
+ store.pushNotice(`MCP sign-in failed for ${flow.name}: ${e?.message || e}`, "error");
56805
+ return;
56806
+ }
56807
+ if (flow.finished) return;
56808
+ if (status?.state === "pending") {
56809
+ poll(flow);
56810
+ return;
56811
+ }
56812
+ stop(flow);
56813
+ closePrompt(flow);
56814
+ if (status?.state === "complete") store.pushNotice(`MCP sign-in complete for ${flow.name}`, "info");
56815
+ else if (status?.state === "cancelled") store.pushNotice(`MCP sign-in cancelled for ${flow.name}`, "info");
56816
+ else store.pushNotice(`MCP sign-in failed for ${flow.name}${status?.error ? `: ${status.error}` : ""}`, "error");
56817
+ }, pollMs);
56818
+ };
56819
+ const loginMcpServer = async (name) => {
56820
+ if (active) {
56821
+ const previous = active;
56822
+ stop(previous);
56823
+ closePrompt(previous);
56824
+ void Promise.resolve(store.cancelMcpOAuthLogin(previous.id)).catch(() => {
56825
+ });
56826
+ }
56827
+ try {
56828
+ const started = await store.beginMcpOAuthLogin(name, { openBrowser: true });
56829
+ if (started?.state === "complete") {
56830
+ store.pushNotice(`MCP sign-in complete for ${name}`, "info");
56831
+ return;
56832
+ }
56833
+ const flow = { id: started.flowId, name, url: started.url || "", finished: false, timer: null, prompt: null };
56834
+ active = flow;
56835
+ if (flow.url) store.pushNotice(`Sign in to ${name}: ${flow.url}`, "info");
56836
+ showPrompt(flow);
56837
+ poll(flow);
56838
+ } catch (e) {
56839
+ store.pushNotice(`MCP sign-in failed for ${name}: ${e?.message || e}`, "error");
56840
+ }
56841
+ };
56842
+ const logoutMcpServer = async (name) => {
56843
+ try {
56844
+ await store.signOutMcpServer(name);
56845
+ store.pushNotice(`MCP signed out of ${name}`, "info");
56846
+ } catch (e) {
56847
+ store.pushNotice(`MCP sign-out failed for ${name}: ${e?.message || e}`, "error");
56848
+ }
56849
+ };
56850
+ return { loginMcpServer, logoutMcpServer };
56851
+ }
56852
+
55783
56853
  // src/tui/app/extension-pickers/scope-note.mjs
55784
56854
  var scopeNote = (row) => {
55785
56855
  if (row?.activeHere === false) return "not in this project";
@@ -55809,8 +56879,9 @@ var serverDescription = (server, pending, optimistic) => {
55809
56879
  const transport = server.transport || "unknown";
55810
56880
  if (pending) return `${optimistic.enabled ? "enabling" : "disabling"}\u2026 \xB7 ${transport}`;
55811
56881
  const error = server.error ? ` \xB7 ${server.error}` : "";
56882
+ const signIn = server.authRequired ? ` \xB7 sign-in required: /mcp login ${server.name}` : "";
55812
56883
  return withScope(
55813
- `${server.source || "config"} \xB7 ${server.status || "unknown"} \xB7 ${transport} \xB7 ${server.toolCount || 0} tools${error}`,
56884
+ `${server.source || "config"} \xB7 ${server.status || "unknown"} \xB7 ${transport} \xB7 ${server.toolCount || 0} tools${error}${signIn}`,
55814
56885
  server
55815
56886
  );
55816
56887
  };
@@ -55899,32 +56970,45 @@ function createMcpServersPicker({ store, theme: theme2, surface, getPicker, setP
55899
56970
  }
55900
56971
 
55901
56972
  // src/tui/app/extension-pickers/plugins-pickers.mjs
56973
+ function mcpNames(p) {
56974
+ if (Array.isArray(p.mcpServers)) return p.mcpServers.map((server) => server.name);
56975
+ return p.mcpServerName ? [p.mcpServerName] : [];
56976
+ }
56977
+ var hasMcp = (p) => mcpNames(p).length > 0 || Boolean(p.mcpScript || p.mcpInline);
56978
+ function serverState(server) {
56979
+ if (server.serverEnabled === false) return "off";
56980
+ if (server.enabled === false) return "plugin off";
56981
+ return server.status || (server.connected ? "connected" : "disconnected");
56982
+ }
55902
56983
  var mcpSummary = (p) => {
55903
- if (!p.mcpScript) return "(none)";
55904
- const state = p.mcpEnabled ? "enabled" : "available";
55905
- return `${state} (${p.mcpServerName || "plugin-mcp"})`;
56984
+ if (!hasMcp(p))
56985
+ return Array.isArray(p.mcpErrors) && p.mcpErrors.length ? `(invalid: ${p.mcpErrors[0].message})` : "(none)";
56986
+ if (!Array.isArray(p.mcpServers)) return `${p.mcpEnabled ? "enabled" : "available"} (${mcpNames(p).join(", ")})`;
56987
+ const errors = Array.isArray(p.mcpErrors) && p.mcpErrors.length ? ` \xB7 ${p.mcpErrors.length} declaration error(s)` : "";
56988
+ return `${p.mcpServers.map((server) => `${server.name} ${serverState(server)}`).join(", ")}${errors}`;
55906
56989
  };
55907
56990
  function mcpActionItem(p) {
55908
- if (!p.mcpScript) {
56991
+ if (!hasMcp(p)) {
55909
56992
  return {
55910
56993
  value: "enable-mcp",
55911
- label: "No MCP script",
55912
- description: "plugin does not expose scripts/run-mcp.mjs or mcp/server.mjs",
56994
+ label: "No MCP server",
56995
+ description: "plugin declares no MCP servers (.mcp.json or manifest mcpServers)",
55913
56996
  _action: "noop"
55914
56997
  };
55915
56998
  }
55916
56999
  return {
55917
57000
  value: "enable-mcp",
55918
- label: p.mcpEnabled ? "Refresh MCP server" : "Enable MCP server",
55919
- description: `${p.mcpServerName || "plugin-mcp"} \xB7 ${p.mcpEnabled ? "configured" : p.mcpScript}`,
57001
+ label: p.mcpEnabled ? "Reconnect MCP servers" : "Enable MCP servers",
57002
+ description: `${mcpNames(p).join(", ") || "plugin MCP"} \xB7 ${p.mcpEnabled ? "on" : "turned off"}`,
55920
57003
  _action: "enable-mcp"
55921
57004
  };
55922
57005
  }
55923
57006
  function pluginSummary(plugin) {
55924
57007
  const version = plugin.version ? ` \xB7 ${plugin.version}` : "";
55925
- const mcpState = plugin.mcpEnabled ? "enabled" : plugin.mcpScript;
55926
- const mcp = plugin.mcpScript ? ` \xB7 mcp ${mcpState}` : "";
55927
- return `${plugin.sourceType || plugin.source}${version} \xB7 skills ${plugin.skillCount || 0}${mcp}`;
57008
+ const mcpOff = plugin.mcpEnabled ? "" : " off";
57009
+ const mcp = hasMcp(plugin) ? ` \xB7 mcp ${mcpNames(plugin).length || 1}${mcpOff}` : "";
57010
+ const warning = plugin.warning ? ` \xB7 \u26A0 ${plugin.warning}` : "";
57011
+ return `${plugin.sourceType || plugin.source}${version} \xB7 skills ${plugin.skillCount || 0}${mcp}${warning}`;
55928
57012
  }
55929
57013
  var pluginInfoNotice = (p) => [
55930
57014
  `${p.title || p.name}${p.version ? ` ${p.version}` : ""}`,
@@ -55933,6 +57017,7 @@ var pluginInfoNotice = (p) => [
55933
57017
  `mcp: ${mcpSummary(p)}`,
55934
57018
  `applies to: ${Array.isArray(p.scope) && p.scope.length ? p.scope.join(", ") : "all projects"}`,
55935
57019
  `root: ${p.root}`,
57020
+ p.warning ? `warning: ${p.warning}` : "",
55936
57021
  p.description ? `
55937
57022
  ${p.description}` : ""
55938
57023
  ].filter(Boolean).join("\n");
@@ -55958,9 +57043,9 @@ var pluginDetailItems = (p) => [
55958
57043
  },
55959
57044
  {
55960
57045
  value: "copy-mcp-name",
55961
- label: p.mcpScript ? "Copy MCP server name" : "No MCP server name",
55962
- description: p.mcpServerName || "",
55963
- _action: p.mcpScript ? "copy-mcp-name" : "noop"
57046
+ label: mcpNames(p).length ? "Copy MCP server name" : "No MCP server name",
57047
+ description: mcpNames(p).join(", "),
57048
+ _action: mcpNames(p).length ? "copy-mcp-name" : "noop"
55964
57049
  },
55965
57050
  {
55966
57051
  value: "uninstall",
@@ -56000,7 +57085,7 @@ function createPluginsPickers({
56000
57085
  return;
56001
57086
  }
56002
57087
  if (detail._action === "enable-mcp") {
56003
- void store.enablePluginMcp?.(p).then(own.defer(() => openMcpPicker())).catch((e) => store.pushNotice(`plugin MCP enable failed: ${e?.message || e}`, "error"));
57088
+ void store.enablePluginMcp?.(p).then(own.defer(() => openMcpPicker())).catch((e) => store.pushNotice(`plugin MCP reconnect failed: ${e?.message || e}`, "error"));
56004
57089
  return;
56005
57090
  }
56006
57091
  if (detail._action === "copy-root") {
@@ -56008,7 +57093,7 @@ function createPluginsPickers({
56008
57093
  return;
56009
57094
  }
56010
57095
  if (detail._action === "copy-mcp-name") {
56011
- copyText(p.mcpServerName || "", `copied plugin MCP server: ${p.mcpServerName}`);
57096
+ copyText(mcpNames(p).join(", "), `copied plugin MCP server: ${mcpNames(p).join(", ")}`);
56012
57097
  return;
56013
57098
  }
56014
57099
  if (detail._action === "uninstall") {
@@ -56355,7 +57440,7 @@ function createExtensionPickers({
56355
57440
  setSettingsPrompt,
56356
57441
  openMcpPicker: mcp.openMcpPicker
56357
57442
  });
56358
- return { ...mcp, ...skills, ...plugins };
57443
+ return { ...mcp, ...createMcpLogin({ store, setProviderPrompt }), ...skills, ...plugins };
56359
57444
  }
56360
57445
 
56361
57446
  // src/tui/app/maintenance-pickers/auto-clear-picker.mjs
@@ -57094,6 +58179,7 @@ var PROVIDER_DISPLAY_NAMES = /* @__PURE__ */ new Map([
57094
58179
  ["anthropic-oauth", "Anthropic OAuth"],
57095
58180
  ["grok-oauth", "Grok OAuth"],
57096
58181
  ["muse-code-oauth", "Muse Code"],
58182
+ ["command-code-oauth", "Command Code"],
57097
58183
  ["mimo-oauth", "MiMo"],
57098
58184
  ["cursor-oauth", "Cursor OAuth"],
57099
58185
  ["antigravity-oauth", "Antigravity OAuth"],
@@ -57140,6 +58226,7 @@ var PROVIDER_DISPLAY_RANKS = {
57140
58226
  "anthropic-oauth": 20,
57141
58227
  "grok-oauth": 30,
57142
58228
  "muse-code-oauth": 33,
58229
+ "command-code-oauth": 33.5,
57143
58230
  "mimo-oauth": 34,
57144
58231
  "antigravity-oauth": 31,
57145
58232
  "cursor-oauth": 32,
@@ -57159,13 +58246,6 @@ var PROVIDER_DISPLAY_RANKS = {
57159
58246
  openrouter: 950
57160
58247
  };
57161
58248
  var providerDisplayRank = (provider) => PROVIDER_DISPLAY_RANKS[String(provider || "").toLowerCase()] ?? 900;
57162
- var titleCaseOption = (value) => String(value || "").split(/([\s_-]+)/).map((part) => /^[\s_-]+$/.test(part) ? part : `${part.charAt(0).toUpperCase()}${part.slice(1).toLowerCase()}`).join("");
57163
- var effortDisplayLabel = (value) => {
57164
- const text = String(value || "").trim();
57165
- if (!text) return "";
57166
- if (text.toLowerCase() === "xhigh") return "XHigh";
57167
- return titleCaseOption(text);
57168
- };
57169
58249
  var fastDisplayLabel = (enabled = true) => `Fast ${enabled ? "On" : "Off"}`;
57170
58250
  var modelDescription = (m) => [String(m?.description || "").trim(), m.fastCapable ? "Fast Available" : ""].filter(Boolean).join(" \xB7 ");
57171
58251
  var modelRecordDisplayName = (model) => displayModelName(model?.id, model?.provider, model?.display || model?.name);
@@ -57221,7 +58301,11 @@ var buildProviderModelItems = (models, provider, currentRoute = null) => {
57221
58301
  _model: model
57222
58302
  }));
57223
58303
  };
57224
- var routeModelDetails = (route) => [routeModelDisplayName(route), route.effort ? effortDisplayLabel(route.effort) : "", route.fast ? "Fast" : ""].filter(Boolean).join(" \xB7 ");
58304
+ var routeSpeedLabel = (route) => {
58305
+ if (!route?.fast) return "";
58306
+ return route.modelParameters?.serviceTier === "ultrafast" ? "Ultrafast" : "Fast";
58307
+ };
58308
+ var routeModelDetails = (route) => [routeModelDisplayName(route), route.effort ? effortDisplayLabel(route.effort) : "", routeSpeedLabel(route)].filter(Boolean).join(" \xB7 ");
57225
58309
  var routeLabel = (route) => {
57226
58310
  if (!route?.provider || !route?.model) return "(unset)";
57227
58311
  return [providerDisplayName(route.provider), routeModelDetails(route)].filter(Boolean).join(" \xB7 ");
@@ -57231,7 +58315,7 @@ var agentModelProfile = (route) => route?.model ? routeModelDetails(route) : "";
57231
58315
  var agentModelParts = (route) => [
57232
58316
  { text: route?.model ? routeModelDisplayName(route) : "", width: 17 },
57233
58317
  { text: route?.effort ? effortDisplayLabel(route.effort) : "", width: 6 },
57234
- { text: route?.fast ? "Fast" : "", width: 4 }
58318
+ { text: routeSpeedLabel(route), width: 9 }
57235
58319
  ];
57236
58320
  var routeFromModel = (model, effort = null) => ({
57237
58321
  provider: model.provider,
@@ -60240,6 +61324,7 @@ var desktopOnlyNotice = (ctx) => {
60240
61324
  ctx.store.pushNotice("Schedules and webhooks are managed in the Mixdog desktop app", "info");
60241
61325
  return true;
60242
61326
  };
61327
+ var openMcpPanel = panelCommand("mcp", "MCP Servers", (deps) => deps.openMcpPicker());
60243
61328
  var openSettings = panelCommand("settings", "Settings", (deps) => deps.openSettingsPicker());
60244
61329
  var panelCommands = {
60245
61330
  project(ctx, arg) {
@@ -60251,7 +61336,20 @@ var panelCommands = {
60251
61336
  ctx.openSlashPanel("project", "Projects", () => ctx.deps.openProjectPicker());
60252
61337
  return true;
60253
61338
  },
60254
- mcp: panelCommand("mcp", "MCP Servers", (deps) => deps.openMcpPicker()),
61339
+ mcp(ctx, arg) {
61340
+ const [sub, ...rest] = arg.trim().split(/\s+/);
61341
+ const action = sub?.toLowerCase();
61342
+ if (action === "login" || action === "logout") {
61343
+ const name = rest.join(" ");
61344
+ if (!name) {
61345
+ ctx.store.pushNotice(`usage: /mcp ${action} <name>`, "warn");
61346
+ return true;
61347
+ }
61348
+ void (action === "login" ? ctx.deps.loginMcpServer(name) : ctx.deps.logoutMcpServer(name));
61349
+ return true;
61350
+ }
61351
+ return openMcpPanel(ctx);
61352
+ },
60255
61353
  skills: panelCommand("skills", "Skills", (deps) => deps.openSkillsPicker()),
60256
61354
  plugins: panelCommand("plugins", "Plugins", (deps) => deps.openPluginsPicker()),
60257
61355
  providers: panelCommand("providers", "Providers", (deps) => deps.openProviderSetupPicker()),
@@ -60661,6 +61759,8 @@ function createAppPickers({
60661
61759
  const {
60662
61760
  openMcpServersPicker,
60663
61761
  openMcpPicker,
61762
+ loginMcpServer,
61763
+ logoutMcpServer,
60664
61764
  openProjectSkillsPicker,
60665
61765
  openSkillsPicker,
60666
61766
  openSkillDetailPicker,
@@ -60788,6 +61888,8 @@ function createAppPickers({
60788
61888
  enterProject: (...a) => enterProject(...a),
60789
61889
  openProjectPicker: (...a) => openProjectPicker(...a),
60790
61890
  openMcpPicker: (...a) => openMcpPicker(...a),
61891
+ loginMcpServer,
61892
+ logoutMcpServer,
60791
61893
  openSkillsPicker: (...a) => openSkillsPicker(...a),
60792
61894
  openPluginsPicker: (...a) => openPluginsPicker(...a),
60793
61895
  openProviderSetupPicker: (...a) => openProviderSetupPicker(...a),
@@ -61135,7 +62237,7 @@ function useMessageSelector({
61135
62237
  }
61136
62238
 
61137
62239
  // src/tui/app/use-terminal-chrome.mjs
61138
- import { useEffect as useEffect23 } from "react";
62240
+ import { useEffect as useEffect24 } from "react";
61139
62241
 
61140
62242
  // src/tui/keyboard-protocol.mjs
61141
62243
  var ENABLE_KITTY_KEYBOARD = "\x1B[>1u";
@@ -61160,7 +62262,7 @@ function supportsExtendedKeys() {
61160
62262
 
61161
62263
  // src/tui/app/use-terminal-chrome.mjs
61162
62264
  function useTerminalChrome({ stdout: stdout2, isRawModeSupported, setResizeState }) {
61163
- useEffect23(() => {
62265
+ useEffect24(() => {
61164
62266
  if (!stdout2) return void 0;
61165
62267
  let trailing = null;
61166
62268
  const DEBOUNCE_MS = 80;
@@ -61195,7 +62297,7 @@ function useTerminalChrome({ stdout: stdout2, isRawModeSupported, setResizeState
61195
62297
  stdout2.off("resize", onResize);
61196
62298
  };
61197
62299
  }, [stdout2]);
61198
- useEffect23(() => {
62300
+ useEffect24(() => {
61199
62301
  if (!isRawModeSupported || !stdout2?.write) return;
61200
62302
  if (!supportsExtendedKeys()) return;
61201
62303
  try {
@@ -61206,7 +62308,7 @@ function useTerminalChrome({ stdout: stdout2, isRawModeSupported, setResizeState
61206
62308
  }
61207
62309
 
61208
62310
  // src/tui/app/use-transcript-window.mjs
61209
- import { useCallback as useCallback21, useEffect as useEffect25, useLayoutEffect as useLayoutEffect8 } from "react";
62311
+ import { useCallback as useCallback21, useEffect as useEffect26, useLayoutEffect as useLayoutEffect8 } from "react";
61210
62312
 
61211
62313
  // src/tui/session/transcript-spill.mjs
61212
62314
  import { readFileSync as readFileSync15 } from "node:fs";
@@ -61718,7 +62820,7 @@ function overlayHintPlacement(renderedItems, transcriptWindow, { overlayHintRequ
61718
62820
  }
61719
62821
 
61720
62822
  // src/tui/app/use-transcript-window/selection-shift.mjs
61721
- import { useEffect as useEffect24, useLayoutEffect as useLayoutEffect7 } from "react";
62823
+ import { useEffect as useEffect25, useLayoutEffect as useLayoutEffect7 } from "react";
61722
62824
  function useSelectionLayoutShift({
61723
62825
  transcriptWindow,
61724
62826
  transcriptContentHeight,
@@ -61752,7 +62854,7 @@ function useSelectionLayoutShift({
61752
62854
  withSelectionClip,
61753
62855
  paintSelectionRect
61754
62856
  ]);
61755
- useEffect24(() => {
62857
+ useEffect25(() => {
61756
62858
  if (!dragRef.current.rect) return;
61757
62859
  const clippedRect = withSelectionClip(dragRef.current.rect);
61758
62860
  dragRef.current = { ...dragRef.current, rect: clippedRect };
@@ -61892,7 +62994,7 @@ function useTranscriptWindow({
61892
62994
  withSelectionClip,
61893
62995
  paintSelectionRect
61894
62996
  });
61895
- useEffect25(() => {
62997
+ useEffect26(() => {
61896
62998
  clampScrollToOverflow(scrollRefs, {
61897
62999
  maxRows: transcriptWindow.maxScrollRows,
61898
63000
  scrollOffset,
@@ -62250,7 +63352,7 @@ function usePromptHistoryNavigation({
62250
63352
  }
62251
63353
 
62252
63354
  // src/tui/app/prompt-handlers/use-prompt-interrupt.mjs
62253
- import { useCallback as useCallback24, useEffect as useEffect26, useRef as useRef27 } from "react";
63355
+ import { useCallback as useCallback24, useEffect as useEffect27, useRef as useRef27 } from "react";
62254
63356
 
62255
63357
  // src/tui/components/prompt-input/interrupt-policy.mjs
62256
63358
  function promptInterruptRestoreText(result, currentText = "") {
@@ -62295,7 +63397,7 @@ function usePromptInterrupt({
62295
63397
  },
62296
63398
  [store, promptValueRef, restoreAttachments, clearPromptHint, syncPromptLayoutRows, setPromptDraftOverride]
62297
63399
  );
62298
- useEffect26(() => {
63400
+ useEffect27(() => {
62299
63401
  const pending = pendingRestoreRef.current;
62300
63402
  if (!pending) return;
62301
63403
  if (commitAsyncRestore(pending)) pendingRestoreRef.current = null;
@@ -62546,7 +63648,7 @@ function usePromptHandlers({
62546
63648
  }
62547
63649
 
62548
63650
  // src/tui/app/use-model-catalog-cache.mjs
62549
- import { useCallback as useCallback27, useEffect as useEffect27, useRef as useRef28 } from "react";
63651
+ import { useCallback as useCallback27, useEffect as useEffect28, useRef as useRef28 } from "react";
62550
63652
  function useModelCatalogCache({ store, onboardingRef }) {
62551
63653
  const providerModelsCacheRef = useRef28({ models: null, at: 0 });
62552
63654
  const webSearchModelsCacheRef = useRef28({ models: null, at: 0 });
@@ -62562,7 +63664,7 @@ function useModelCatalogCache({ store, onboardingRef }) {
62562
63664
  webSearchModelsCacheRef.current = { models: null, at: 0 };
62563
63665
  }
62564
63666
  }, []);
62565
- useEffect27(() => {
63667
+ useEffect28(() => {
62566
63668
  let alive = true;
62567
63669
  const timer2 = setTimeout(async () => {
62568
63670
  const seq = onboardingPrefetchSeqRef.current;
@@ -62598,10 +63700,10 @@ function useModelCatalogCache({ store, onboardingRef }) {
62598
63700
  }
62599
63701
 
62600
63702
  // src/tui/app/use-disabled-skills.mjs
62601
- import { useCallback as useCallback28, useEffect as useEffect28, useState as useState18 } from "react";
63703
+ import { useCallback as useCallback28, useEffect as useEffect29, useState as useState19 } from "react";
62602
63704
  function useDisabledSkills({ store }) {
62603
- const [disabledSkills, setDisabledSkillsInner] = useState18(() => /* @__PURE__ */ new Set());
62604
- useEffect28(() => {
63705
+ const [disabledSkills, setDisabledSkillsInner] = useState19(() => /* @__PURE__ */ new Set());
63706
+ useEffect29(() => {
62605
63707
  let alive = true;
62606
63708
  void Promise.resolve(store.getDisabledSkills?.()).then((result) => {
62607
63709
  if (!alive) return;
@@ -62635,7 +63737,7 @@ function useDisabledSkills({ store }) {
62635
63737
  }
62636
63738
 
62637
63739
  // src/tui/app/use-onboarding-start.mjs
62638
- import { useEffect as useEffect29 } from "react";
63740
+ import { useEffect as useEffect30 } from "react";
62639
63741
  function resolveOnboardingCompleted(store, onboardingCompleted) {
62640
63742
  if (typeof onboardingCompleted === "boolean") return onboardingCompleted;
62641
63743
  try {
@@ -62654,7 +63756,7 @@ function useOnboardingStart({
62654
63756
  setOnboardingActive,
62655
63757
  openOnboardingAuthStep
62656
63758
  }) {
62657
- useEffect29(() => {
63759
+ useEffect30(() => {
62658
63760
  if (onboardingStartedRef.current) return void 0;
62659
63761
  if (resolveOnboardingCompleted(store, onboardingCompleted) && !forceOnboarding) return void 0;
62660
63762
  let canceled = false;
@@ -62672,17 +63774,17 @@ function useOnboardingStart({
62672
63774
  // src/tui/App.jsx
62673
63775
  function App2({ store, initialStatusLine = "", forceOnboarding = false, onboardingCompleted = void 0 }) {
62674
63776
  const state = useSession(store);
62675
- const [toolOutputExpanded, setToolOutputExpanded] = useState19(false);
62676
- const [onboardingActive, setOnboardingActive] = useState19(false);
63777
+ const [toolOutputExpanded, setToolOutputExpanded] = useState20(false);
63778
+ const [onboardingActive, setOnboardingActive] = useState20(false);
62677
63779
  const { exit } = use_app_default();
62678
63780
  const { isRawModeSupported, internal_eventEmitter: inkInput } = use_stdin_default();
62679
63781
  const { stdout: stdout2 } = use_stdout_default();
62680
- const [exiting, setExiting] = useState19(false);
62681
- const [tuiReady, setTuiReady] = useState19(false);
63782
+ const [exiting, setExiting] = useState20(false);
63783
+ const [tuiReady, setTuiReady] = useState20(false);
62682
63784
  const exitRequestedRef = useRef29(false);
62683
- const [resizeState, setResizeState] = useState19(() => ({ ...terminalSize2(stdout2), epoch: 0 }));
62684
- const [panelTransitionEpoch, setPanelTransitionEpoch] = useState19(0);
62685
- const [panelInkMaskEpoch, setPanelInkMaskEpoch] = useState19(0);
63785
+ const [resizeState, setResizeState] = useState20(() => ({ ...terminalSize2(stdout2), epoch: 0 }));
63786
+ const [panelTransitionEpoch, setPanelTransitionEpoch] = useState20(0);
63787
+ const [panelInkMaskEpoch, setPanelInkMaskEpoch] = useState20(0);
62686
63788
  const rightSafetyColumns = 1;
62687
63789
  const frameColumns = Math.max(1, resizeState.columns - rightSafetyColumns);
62688
63790
  const {
@@ -62704,7 +63806,7 @@ function App2({ store, initialStatusLine = "", forceOnboarding = false, onboardi
62704
63806
  const pickerOpenedFromEnterRef = useRef29(false);
62705
63807
  const pickerOpenedFromEnterTimerRef = useRef29(null);
62706
63808
  const projectPickerRef = useRef29(null);
62707
- const [picker, setPickerState] = useState19(null);
63809
+ const [picker, setPickerState] = useState20(null);
62708
63810
  const livePickerRef = useRef29(null);
62709
63811
  const setPicker = useCallback29((next) => {
62710
63812
  const previousPicker = livePickerRef.current;
@@ -62718,8 +63820,8 @@ function App2({ store, initialStatusLine = "", forceOnboarding = false, onboardi
62718
63820
  );
62719
63821
  }, []);
62720
63822
  livePickerRef.current = picker;
62721
- const [contextPanel, setContextPanel] = useState19(null);
62722
- const [usagePanel, setUsagePanel] = useState19(null);
63823
+ const [contextPanel, setContextPanel] = useState20(null);
63824
+ const [usagePanel, setUsagePanel] = useState20(null);
62723
63825
  const surfaceRef = useRef29(null);
62724
63826
  if (!surfaceRef.current) {
62725
63827
  surfaceRef.current = createPanelSurface({ setPicker, setContextPanel, setUsagePanel });
@@ -62728,9 +63830,9 @@ function App2({ store, initialStatusLine = "", forceOnboarding = false, onboardi
62728
63830
  const settingsHeavyCacheRef = useRef29(null);
62729
63831
  const settingsRequestRef = useRef29(0);
62730
63832
  const closeUsagePanel = useCallback29(() => surface.closeUsage(), [surface]);
62731
- const [providerPrompt, setProviderPrompt] = useState19(null);
63833
+ const [providerPrompt, setProviderPrompt] = useState20(null);
62732
63834
  const oauthSubmitRef = useRef29(false);
62733
- const [settingsPrompt, setSettingsPrompt] = useState19(null);
63835
+ const [settingsPrompt, setSettingsPrompt] = useState20(null);
62734
63836
  const projectPicker = createProjectPicker({
62735
63837
  state,
62736
63838
  store,
@@ -62750,7 +63852,7 @@ function App2({ store, initialStatusLine = "", forceOnboarding = false, onboardi
62750
63852
  setPicker(projectPicker.buildProjectPickerState({ initialEntry: true, loading: true }));
62751
63853
  }
62752
63854
  }
62753
- useEffect30(() => {
63855
+ useEffect31(() => {
62754
63856
  if (livePickerRef.current?._projectInitialPending !== true) return;
62755
63857
  void projectPickerRef.current?.openProjectPicker({ initialEntry: true });
62756
63858
  }, [store]);
@@ -62762,6 +63864,8 @@ function App2({ store, initialStatusLine = "", forceOnboarding = false, onboardi
62762
63864
  setPromptDraft,
62763
63865
  promptDraftOverride,
62764
63866
  setPromptDraftOverride,
63867
+ promptCaret,
63868
+ setPromptCaret,
62765
63869
  promptLayoutValueRef,
62766
63870
  setPromptLayoutRows,
62767
63871
  textEntryLayoutRows,
@@ -62803,8 +63907,8 @@ function App2({ store, initialStatusLine = "", forceOnboarding = false, onboardi
62803
63907
  welcomePromptHintVisibleRef,
62804
63908
  dismissWelcomePromptHint
62805
63909
  } = useWelcomePromptHint({ store, state, toastErrorSignature });
62806
- const [slashIndex, setSlashIndex] = useState19(0);
62807
- const [slashDismissedFor, setSlashDismissedFor] = useState19("");
63910
+ const [slashIndex, setSlashIndex] = useState20(0);
63911
+ const [slashDismissedFor, setSlashDismissedFor] = useState20("");
62808
63912
  const slashPaletteRef = useRef29({ open: false, count: 0 });
62809
63913
  const scrollFocusRef = useRef29({});
62810
63914
  const onboardingStartedRef = useRef29(false);
@@ -62886,7 +63990,7 @@ function App2({ store, initialStatusLine = "", forceOnboarding = false, onboardi
62886
63990
  settingsPrompt,
62887
63991
  setTextEntryLayoutRows
62888
63992
  });
62889
- useEffect30(() => {
63993
+ useEffect31(() => {
62890
63994
  const timer2 = setTimeout(() => setTuiReady(true), 0);
62891
63995
  return () => clearTimeout(timer2);
62892
63996
  }, []);
@@ -62932,7 +64036,7 @@ function App2({ store, initialStatusLine = "", forceOnboarding = false, onboardi
62932
64036
  getStitchedSelectionText,
62933
64037
  showSelectionCopyHint
62934
64038
  });
62935
- useEffect30(
64039
+ useEffect31(
62936
64040
  () => () => {
62937
64041
  stopSmoothScroll();
62938
64042
  },
@@ -63060,7 +64164,7 @@ function App2({ store, initialStatusLine = "", forceOnboarding = false, onboardi
63060
64164
  setSettingsPrompt,
63061
64165
  closeUsagePanel
63062
64166
  });
63063
- useEffect30(() => {
64167
+ useEffect31(() => {
63064
64168
  if (contextPanel?.kind === "context") openContextPicker();
63065
64169
  }, [
63066
64170
  contextPanel?.kind,
@@ -63112,7 +64216,8 @@ function App2({ store, initialStatusLine = "", forceOnboarding = false, onboardi
63112
64216
  pastedImagesRef,
63113
64217
  pastedTextsRef
63114
64218
  });
63115
- const { activeSlashQuery, slashCommands, slashPaletteOpen } = deriveSlashPalette({
64219
+ const mentionSkills = useSkillMentionSkills(store, skillMentionQuery(promptDraft, promptCaret) !== null);
64220
+ const { activeSlashQuery, slashCommands, slashPaletteOpen, paletteKind } = deriveSlashPalette({
63116
64221
  providerPrompt,
63117
64222
  settingsPrompt,
63118
64223
  toolApproval,
@@ -63122,7 +64227,9 @@ function App2({ store, initialStatusLine = "", forceOnboarding = false, onboardi
63122
64227
  exiting,
63123
64228
  commandBusy: state.commandBusy,
63124
64229
  promptDraft,
63125
- slashDismissedFor
64230
+ slashDismissedFor,
64231
+ skills: mentionSkills,
64232
+ promptCaret
63126
64233
  });
63127
64234
  slashPaletteRef.current = { open: slashPaletteOpen, count: slashCommands.length };
63128
64235
  scrollFocusRef.current = {
@@ -63134,7 +64241,7 @@ function App2({ store, initialStatusLine = "", forceOnboarding = false, onboardi
63134
64241
  providerPrompt: !!providerPrompt,
63135
64242
  settingsPrompt: !!settingsPrompt
63136
64243
  };
63137
- useEffect30(() => {
64244
+ useEffect31(() => {
63138
64245
  setSlashIndex((index) => Math.min(index, Math.max(0, slashCommands.length - 1)));
63139
64246
  }, [slashCommands.length, activeSlashQuery]);
63140
64247
  const {
@@ -63302,10 +64409,12 @@ function App2({ store, initialStatusLine = "", forceOnboarding = false, onboardi
63302
64409
  hasUserMessages,
63303
64410
  initialStatusLine,
63304
64411
  onPromptDraftChange,
64412
+ onPromptCaretChange: setPromptCaret,
63305
64413
  onSubmit,
63306
64414
  overlayHintAttachItemIndex,
63307
64415
  overlayHintFallbackRow,
63308
64416
  overlayHintOnLastItem,
64417
+ paletteKind,
63309
64418
  panelInkMaskEpoch,
63310
64419
  panelTransitionEpoch,
63311
64420
  picker,