mixdog 1.2.1 → 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 (233) hide show
  1. package/package.json +1 -1
  2. package/scripts/gate-local.mjs +19 -3
  3. package/scripts/model-catalog-audit.mjs +1 -15
  4. package/src/agents/reviewer/AGENT.md +3 -3
  5. package/src/agents/reviewer/agent.json +1 -1
  6. package/src/defaults/shipped-history.json +1 -0
  7. package/src/repl/slash-commands.mjs +16 -1
  8. package/src/runtime/agent/orchestrator/agent-runtime/agent-progress-watchdog.mjs +29 -4
  9. package/src/runtime/agent/orchestrator/agent-runtime/cache-strategy.mjs +10 -0
  10. package/src/runtime/agent/orchestrator/mcp/client-config.mjs +36 -7
  11. package/src/runtime/agent/orchestrator/mcp/client-handshake.mjs +49 -10
  12. package/src/runtime/agent/orchestrator/mcp/client-transport.mjs +40 -3
  13. package/src/runtime/agent/orchestrator/mcp/client.mjs +230 -96
  14. package/src/runtime/agent/orchestrator/mcp/oauth-callback.mjs +103 -0
  15. package/src/runtime/agent/orchestrator/mcp/oauth-credentials.mjs +150 -0
  16. package/src/runtime/agent/orchestrator/mcp/oauth-login.mjs +111 -0
  17. package/src/runtime/agent/orchestrator/mcp/oauth-probe.mjs +87 -0
  18. package/src/runtime/agent/orchestrator/mcp/oauth-provider.mjs +95 -0
  19. package/src/runtime/agent/orchestrator/mcp/oauth-request.mjs +122 -0
  20. package/src/runtime/agent/orchestrator/mcp/oauth-shared.mjs +9 -0
  21. package/src/runtime/agent/orchestrator/mcp/oauth.mjs +229 -0
  22. package/src/runtime/agent/orchestrator/providers/account-pool.mjs +188 -29
  23. package/src/runtime/agent/orchestrator/providers/anthropic-api-recovery.mjs +2 -1
  24. package/src/runtime/agent/orchestrator/providers/anthropic-api-transport.mjs +94 -31
  25. package/src/runtime/agent/orchestrator/providers/anthropic-error-contract.mjs +96 -0
  26. package/src/runtime/agent/orchestrator/providers/anthropic-fast-mode.mjs +39 -18
  27. package/src/runtime/agent/orchestrator/providers/anthropic-max-tokens-recovery.mjs +55 -0
  28. package/src/runtime/agent/orchestrator/providers/anthropic-max-tokens.mjs +25 -21
  29. package/src/runtime/agent/orchestrator/providers/anthropic-messages.mjs +3 -1
  30. package/src/runtime/agent/orchestrator/providers/anthropic-midstream-recovery.mjs +18 -4
  31. package/src/runtime/agent/orchestrator/providers/anthropic-model-resolve.mjs +13 -1
  32. package/src/runtime/agent/orchestrator/providers/anthropic-oauth-client-version.mjs +1 -1
  33. package/src/runtime/agent/orchestrator/providers/anthropic-oauth-midstream.mjs +10 -1
  34. package/src/runtime/agent/orchestrator/providers/anthropic-oauth-recovery.mjs +23 -9
  35. package/src/runtime/agent/orchestrator/providers/anthropic-oauth-request/initial-status.mjs +46 -20
  36. package/src/runtime/agent/orchestrator/providers/anthropic-oauth-request.mjs +14 -9
  37. package/src/runtime/agent/orchestrator/providers/anthropic-oauth.mjs +73 -35
  38. package/src/runtime/agent/orchestrator/providers/anthropic-overload-fallback.mjs +69 -0
  39. package/src/runtime/agent/orchestrator/providers/anthropic-server-fallback.mjs +4 -0
  40. package/src/runtime/agent/orchestrator/providers/anthropic-sse.mjs +8 -1
  41. package/src/runtime/agent/orchestrator/providers/anthropic.mjs +34 -7
  42. package/src/runtime/agent/orchestrator/providers/antigravity-oauth-catalog.mjs +30 -9
  43. package/src/runtime/agent/orchestrator/providers/antigravity-oauth.mjs +7 -0
  44. package/src/runtime/agent/orchestrator/providers/antigravity-request.mjs +30 -14
  45. package/src/runtime/agent/orchestrator/providers/antigravity-response.mjs +2 -1
  46. package/src/runtime/agent/orchestrator/providers/antigravity-retry-policy.mjs +93 -0
  47. package/src/runtime/agent/orchestrator/providers/antigravity-transport.mjs +82 -9
  48. package/src/runtime/agent/orchestrator/providers/command-code-oauth.mjs +3 -0
  49. package/src/runtime/agent/orchestrator/providers/cursor-auth.mjs +38 -5
  50. package/src/runtime/agent/orchestrator/providers/cursor-client-version.mjs +1 -1
  51. package/src/runtime/agent/orchestrator/providers/cursor-wire-guards.mjs +97 -2
  52. package/src/runtime/agent/orchestrator/providers/cursor-wire-stream-bridge.mjs +102 -23
  53. package/src/runtime/agent/orchestrator/providers/cursor-wire-transport.mjs +103 -33
  54. package/src/runtime/agent/orchestrator/providers/cursor-wire.mjs +29 -6
  55. package/src/runtime/agent/orchestrator/providers/cursor.mjs +18 -1
  56. package/src/runtime/agent/orchestrator/providers/effort-configuration.mjs +77 -17
  57. package/src/runtime/agent/orchestrator/providers/gemini-cache-policy.mjs +1 -1
  58. package/src/runtime/agent/orchestrator/providers/gemini-cache.mjs +29 -8
  59. package/src/runtime/agent/orchestrator/providers/gemini-error-contract.mjs +191 -0
  60. package/src/runtime/agent/orchestrator/providers/gemini-family.mjs +9 -0
  61. package/src/runtime/agent/orchestrator/providers/gemini-history-signatures.mjs +9 -4
  62. package/src/runtime/agent/orchestrator/providers/gemini-response.mjs +3 -1
  63. package/src/runtime/agent/orchestrator/providers/gemini-retry-policy.mjs +180 -0
  64. package/src/runtime/agent/orchestrator/providers/gemini-schema.mjs +21 -82
  65. package/src/runtime/agent/orchestrator/providers/gemini-sdk-request.mjs +4 -1
  66. package/src/runtime/agent/orchestrator/providers/gemini-stream.mjs +71 -12
  67. package/src/runtime/agent/orchestrator/providers/gemini-thinking.mjs +21 -20
  68. package/src/runtime/agent/orchestrator/providers/gemini.mjs +56 -23
  69. package/src/runtime/agent/orchestrator/providers/grok-oauth-tokens.mjs +3 -0
  70. package/src/runtime/agent/orchestrator/providers/grok-oauth.mjs +68 -19
  71. package/src/runtime/agent/orchestrator/providers/mimo-oauth.mjs +3 -0
  72. package/src/runtime/agent/orchestrator/providers/model-list-sanitize.mjs +2 -1
  73. package/src/runtime/agent/orchestrator/providers/muse-code-oauth.mjs +4 -9
  74. package/src/runtime/agent/orchestrator/providers/openai-compat-chat-send.mjs +4 -2
  75. package/src/runtime/agent/orchestrator/providers/openai-compat-chat-stream/stream-result.mjs +22 -0
  76. package/src/runtime/agent/orchestrator/providers/openai-compat-chat-stream.mjs +1 -0
  77. package/src/runtime/agent/orchestrator/providers/openai-compat-error-contract.mjs +50 -0
  78. package/src/runtime/agent/orchestrator/providers/openai-compat-response-normalization.mjs +23 -0
  79. package/src/runtime/agent/orchestrator/providers/openai-compat-responses-events.mjs +16 -8
  80. package/src/runtime/agent/orchestrator/providers/openai-compat-responses-state.mjs +3 -2
  81. package/src/runtime/agent/orchestrator/providers/openai-compat-responses.mjs +94 -13
  82. package/src/runtime/agent/orchestrator/providers/openai-compat-retry-profile.mjs +193 -0
  83. package/src/runtime/agent/orchestrator/providers/openai-compat-stream-common.mjs +66 -2
  84. package/src/runtime/agent/orchestrator/providers/openai-compat-stream.mjs +2 -1
  85. package/src/runtime/agent/orchestrator/providers/openai-compat-wire.mjs +6 -0
  86. package/src/runtime/agent/orchestrator/providers/openai-compat-xai-send.mjs +4 -2
  87. package/src/runtime/agent/orchestrator/providers/openai-compat-xai.mjs +23 -14
  88. package/src/runtime/agent/orchestrator/providers/openai-compat.mjs +17 -3
  89. package/src/runtime/agent/orchestrator/providers/openai-direct-request.mjs +42 -25
  90. package/src/runtime/agent/orchestrator/providers/openai-error-contract.mjs +274 -0
  91. package/src/runtime/agent/orchestrator/providers/openai-http-sse-request.mjs +72 -32
  92. package/src/runtime/agent/orchestrator/providers/openai-http-sse-response-state/response-events/terminal-frames.mjs +18 -11
  93. package/src/runtime/agent/orchestrator/providers/openai-http-sse-response-state/response-outcome.mjs +1 -2
  94. package/src/runtime/agent/orchestrator/providers/openai-http-sse-response-state/response-stamps.mjs +2 -2
  95. package/src/runtime/agent/orchestrator/providers/openai-http-sse-response-state/response-state.mjs +2 -3
  96. package/src/runtime/agent/orchestrator/providers/openai-http-sse-response-state.mjs +2 -2
  97. package/src/runtime/agent/orchestrator/providers/openai-http-sse-watchdogs.mjs +1 -3
  98. package/src/runtime/agent/orchestrator/providers/openai-oauth-dispatch.mjs +34 -3
  99. package/src/runtime/agent/orchestrator/providers/openai-oauth-http-sse.mjs +5 -1
  100. package/src/runtime/agent/orchestrator/providers/openai-oauth-tokens.mjs +22 -2
  101. package/src/runtime/agent/orchestrator/providers/openai-oauth.mjs +5 -0
  102. package/src/runtime/agent/orchestrator/providers/openai-responses-input.mjs +5 -9
  103. package/src/runtime/agent/orchestrator/providers/openai-retry-policy.mjs +9 -0
  104. package/src/runtime/agent/orchestrator/providers/openai-ws-handshake.mjs +16 -8
  105. package/src/runtime/agent/orchestrator/providers/openai-ws-send-attempts/attempt-context.mjs +1 -2
  106. package/src/runtime/agent/orchestrator/providers/openai-ws-send-attempts/policy.mjs +25 -14
  107. package/src/runtime/agent/orchestrator/providers/openai-ws-terminal.mjs +18 -11
  108. package/src/runtime/agent/orchestrator/providers/openai-ws.mjs +31 -20
  109. package/src/runtime/agent/orchestrator/providers/provider-error-kind.mjs +581 -0
  110. package/src/runtime/agent/orchestrator/providers/retry-backoff.mjs +46 -7
  111. package/src/runtime/agent/orchestrator/providers/retry-classification.mjs +118 -219
  112. package/src/runtime/agent/orchestrator/providers/retry-classifier.mjs +2 -0
  113. package/src/runtime/agent/orchestrator/providers/retry-executor.mjs +148 -45
  114. package/src/runtime/agent/orchestrator/providers/retry-midstream.mjs +81 -16
  115. package/src/runtime/agent/orchestrator/runtime-core/config-helpers.mjs +3 -0
  116. package/src/runtime/agent/orchestrator/runtime-core/goal-reminder.mjs +0 -18
  117. package/src/runtime/agent/orchestrator/runtime-core/model-capabilities.mjs +57 -28
  118. package/src/runtime/agent/orchestrator/runtime-core/orchestration.mjs +19 -16
  119. package/src/runtime/agent/orchestrator/runtime-core/plugin-mcp.mjs +1 -97
  120. package/src/runtime/agent/orchestrator/session/catalog-db/schema.mjs +3 -1
  121. package/src/runtime/agent/orchestrator/session/loop/send-phase.mjs +4 -0
  122. package/src/runtime/agent/orchestrator/session/loop/step-auto-effort.mjs +102 -18
  123. package/src/runtime/agent/orchestrator/session/loop/tool-phase.mjs +3 -1
  124. package/src/runtime/agent/orchestrator/session/manager/ask-queue.mjs +30 -2
  125. package/src/runtime/agent/orchestrator/session/manager/ask-session.mjs +11 -2
  126. package/src/runtime/agent/orchestrator/session/manager/ask-turn-execute.mjs +41 -21
  127. package/src/runtime/agent/orchestrator/session/manager/pending-message-entry.mjs +5 -10
  128. package/src/runtime/agent/orchestrator/session/manager/session-close.mjs +1 -1
  129. package/src/runtime/agent/orchestrator/session/manager/turn-interruption.mjs +18 -7
  130. package/src/runtime/agent/orchestrator/session/send-with-recovery.mjs +155 -29
  131. package/src/runtime/agent/orchestrator/session/store/save-worker.mjs +6 -3
  132. package/src/runtime/agent/orchestrator/session/store/write-guards.mjs +16 -0
  133. package/src/runtime/agent/orchestrator/session/store-agent-worker-rows.mjs +22 -10
  134. package/src/runtime/agent/orchestrator/session/store-summary-catalog.mjs +2 -0
  135. package/src/runtime/agent/orchestrator/session/store-summary-fields.mjs +5 -0
  136. package/src/runtime/agent/orchestrator/session/store-summary-index.mjs +3 -0
  137. package/src/runtime/agent/orchestrator/session/transcript-restore/restore.mjs +20 -1
  138. package/src/runtime/agent/orchestrator/tools/builtin/arg-guard.mjs +2 -2
  139. package/src/runtime/agent/orchestrator/tools/builtin/bash-tool/deadline-plan.mjs +12 -15
  140. package/src/runtime/agent/orchestrator/tools/builtin/builtin-tools.mjs +5 -5
  141. package/src/runtime/memory/lib/pg/process.mjs +34 -24
  142. package/src/runtime/memory/lib/pg/supervisor.mjs +16 -13
  143. package/src/runtime/office/README.md +1 -1
  144. package/src/runtime/office/shared/values.mjs +0 -5
  145. package/src/runtime/shared/background-tasks.mjs +92 -14
  146. package/src/runtime/shared/err-text.mjs +25 -0
  147. package/src/runtime/shared/error-presentation.mjs +159 -19
  148. package/src/runtime/shared/llm/anthropic-betas.mjs +4 -3
  149. package/src/runtime/shared/llm/anthropic-effort.mjs +123 -134
  150. package/src/runtime/shared/llm/anthropic-thinking-contract.mjs +50 -14
  151. package/src/runtime/shared/llm/model-catalog.mjs +53 -40
  152. package/src/runtime/shared/llm/openai-daybreak.mjs +4 -16
  153. package/src/runtime/shared/llm/provider-catalog-registry.mjs +11 -0
  154. package/src/runtime/shared/llm/provider-model-identities.mjs +13 -4
  155. package/src/runtime/shared/llm/usage-rollup.mjs +0 -1
  156. package/src/runtime/shared/model-display.mjs +13 -0
  157. package/src/runtime/shared/quota-resume-store.mjs +11 -0
  158. package/src/runtime/shared/session-baseline-store.mjs +960 -0
  159. package/src/runtime/shared/statusline/statusline-format.mjs +4 -4
  160. package/src/runtime/shared/task-notification-envelope.mjs +2 -2
  161. package/src/runtime/shared/turn-changes.mjs +447 -219
  162. package/src/runtime/shared/turn-snapshot-store.mjs +182 -1
  163. package/src/runtime/shared/turn-snapshot.mjs +170 -48
  164. package/src/runtime/shared/turn-worktree-snapshot.mjs +135 -46
  165. package/src/runtime/shared/worktrees/contract.mjs +0 -24
  166. package/src/runtime/shared/worktrees/test-support.mjs +19 -4
  167. package/src/session-runtime/boot/apis.mjs +6 -0
  168. package/src/session-runtime/boot/infrastructure.mjs +6 -0
  169. package/src/session-runtime/lifecycle/session-catalog.mjs +2 -0
  170. package/src/session-runtime/lifecycle/teardown.mjs +1 -1
  171. package/src/session-runtime/mcp-glue/connect.mjs +29 -9
  172. package/src/session-runtime/mcp-glue/server-catalog.mjs +20 -3
  173. package/src/session-runtime/mcp-glue.mjs +3 -0
  174. package/src/session-runtime/mcp-oauth-login.mjs +174 -0
  175. package/src/session-runtime/model-route/model-switch-target.mjs +34 -0
  176. package/src/session-runtime/model-route/set-route.mjs +83 -15
  177. package/src/session-runtime/model-route/web-search-route.mjs +1 -1
  178. package/src/session-runtime/native-web-search/routes.mjs +22 -3
  179. package/src/session-runtime/provider-models/model-meta.mjs +12 -3
  180. package/src/session-runtime/quick-model-rows/web-search-rows.mjs +13 -8
  181. package/src/session-runtime/quick-web-search-models.mjs +13 -38
  182. package/src/session-runtime/resource-extension-sync.mjs +4 -0
  183. package/src/session-runtime/resource-mcp-api.mjs +98 -2
  184. package/src/session-runtime/runtime-review-api.mjs +13 -0
  185. package/src/session-runtime/services/agent-tool/job-task-reconcile.mjs +13 -1
  186. package/src/session-runtime/services/agent-tool/job-views/agent-list.mjs +7 -2
  187. package/src/session-runtime/services/agent-tool/send-flow.mjs +22 -4
  188. package/src/session-runtime/services/agent-tool/spawn-flow/job-start.mjs +2 -0
  189. package/src/session-runtime/services/agent-tool/spawn-flow/spawn-run.mjs +22 -5
  190. package/src/session-runtime/services/agent-tool/worker-index/row-liveness.mjs +8 -1
  191. package/src/session-runtime/services/agent-tool/worker-index/row-shape.mjs +2 -2
  192. package/src/session-runtime/services/agent-tool/worker-rows.mjs +17 -0
  193. package/src/session-runtime/settings-compaction-api.mjs +1 -0
  194. package/src/standalone/daemon-drain-policy.mjs +8 -0
  195. package/src/standalone/daemon-telemetry.mjs +55 -0
  196. package/src/standalone/daemon.mjs +3 -7
  197. package/src/standalone/session-protocol.mjs +7 -0
  198. package/src/standalone/session-service/agent-tree/agent-cancel.mjs +33 -2
  199. package/src/standalone/session-service/agent-tree/agent-turns.mjs +26 -10
  200. package/src/standalone/session-service/agent-tree.mjs +12 -0
  201. package/src/standalone/session-service/quota-resume.mjs +8 -0
  202. package/src/standalone/session-service/retention/busy.mjs +15 -1
  203. package/src/standalone/session-service-api.mjs +5 -0
  204. package/src/standalone/session-service.mjs +1 -0
  205. package/src/tui/app/app-view.jsx +1 -0
  206. package/src/tui/app/create-app-pickers.mjs +4 -0
  207. package/src/tui/app/extension-pickers/mcp-login.mjs +107 -0
  208. package/src/tui/app/extension-pickers/mcp-servers-picker.mjs +2 -1
  209. package/src/tui/app/extension-pickers.mjs +2 -1
  210. package/src/tui/app/model-options.mjs +11 -16
  211. package/src/tui/app/slash-commands.mjs +7 -2
  212. package/src/tui/app/slash-dispatch/panel-commands.mjs +16 -1
  213. package/src/tui/components/StatusLine.jsx +2 -0
  214. package/src/tui/components/status-line/local-line.mjs +5 -2
  215. package/src/tui/components/status-line/use-statusline-text.mjs +7 -1
  216. package/src/tui/dist/index.mjs +816 -43
  217. package/src/tui/session/quota-resume.mjs +46 -14
  218. package/src/tui/session/session-api/commands.mjs +33 -24
  219. package/src/tui/session/session-api/extensions.mjs +22 -0
  220. package/src/tui/session/session-api/integrations.mjs +7 -0
  221. package/src/tui/session/session-api/lifecycle.mjs +5 -1
  222. package/src/tui/session/session-api/routes.mjs +71 -7
  223. package/src/tui/session/session-api/settings.mjs +5 -14
  224. package/src/tui/session/session-flow/drain.mjs +7 -1
  225. package/src/tui/session/session-flow/failed-turn-rewind.mjs +10 -4
  226. package/src/tui/session/turn.mjs +38 -15
  227. package/src/tui/statusline-ansi-bridge.mjs +1 -1
  228. package/src/ui/statusline-agents.mjs +15 -4
  229. package/src/ui/statusline.mjs +7 -3
  230. package/src/ui/streaming-markdown-heal.mjs +34 -3
  231. package/src/vendor/statusline/src/gateway/claude-current.mjs +14 -4
  232. package/src/runtime/memory/lib/memory-session-merge.mjs +0 -32
  233. package/src/runtime/shared/llm/usage-session-history.mjs +0 -266
@@ -35456,8 +35456,13 @@ var SLASH_COMMANDS = [
35456
35456
  { name: "theme", usage: "/theme", params: "[id]", description: "Change the TUI color theme" },
35457
35457
  { name: "agents", usage: "/agents", params: "[refresh]", description: "Show available workflow agents" },
35458
35458
  { name: "effort", usage: "/effort", params: "[level]", description: "Set reasoning effort for the current model" },
35459
- { name: "fast", usage: "/fast", params: "[on|off|ultra]", description: "Set Fast or Ultrafast mode for the current model" },
35460
- { 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" },
35461
35466
  { name: "skills", usage: "/skills", description: "Choose a skill for the next request" },
35462
35467
  { name: "memory", usage: "/memory", params: "[status|core ...]", description: "List and edit core memories" },
35463
35468
  { name: "plugins", usage: "/plugins", description: "Manage local plugin integrations" },
@@ -38796,12 +38801,35 @@ function healIncompleteLink(text, isPendingLocalPath) {
38796
38801
  if (label < 0 && isPendingLocalPath?.(caption)) return prefix;
38797
38802
  return `${prefix}[${closeEmphasis(caption)}${"]".repeat(Math.max(0, depth - 1))}]()`;
38798
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
+ }
38799
38826
  function healStreamingMarkdownTail(text, isPendingLocalPath) {
38800
- 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;
38801
38831
  const hasSyntax = HEALABLE_MARKDOWN_SYNTAX.test(value);
38802
38832
  if (!value || !hasSyntax && !isPendingLocalPath) return value;
38803
- const fence = openFence(value);
38804
- if (fence) return trimPartialClosingFence(value, fence);
38805
38833
  const healed = hasSyntax ? closeEmphasis(healIncompleteLink(closeInlineCode(value, isPendingLocalPath), isPendingLocalPath)) : value;
38806
38834
  const tail = isPendingLocalPath ? /\S+$/.exec(maskCode(healed)) : null;
38807
38835
  return tail && isPendingLocalPath(tail[0]) ? healed.slice(0, tail.index) : healed;
@@ -38997,6 +39025,13 @@ function resolveStreamingMarkdownParts(text, streamKey) {
38997
39025
  }
38998
39026
 
38999
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
+ };
39000
39035
  function titleModelPart(part) {
39001
39036
  const text = String(part || "").trim();
39002
39037
  if (!text) return "";
@@ -41697,6 +41732,479 @@ function transportErrorText(error) {
41697
41732
  return `${TRANSPORT_SENTENCES[verdict.kind]}${detail ? ` (${detail})` : ""}.`;
41698
41733
  }
41699
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
+
41700
42208
  // src/runtime/shared/error-presentation.mjs
41701
42209
  var DETAILS_LIMIT = 12e3;
41702
42210
  var SUMMARY_LIMIT = 180;
@@ -41712,7 +42220,7 @@ function safeErrorDetails(value) {
41712
42220
  \u2026`;
41713
42221
  return text;
41714
42222
  }
41715
- function messageOf2(value) {
42223
+ function messageOf3(value) {
41716
42224
  if (typeof value === "string") return value;
41717
42225
  if (value && typeof value === "object") {
41718
42226
  if (typeof value.message === "string") return value.message;
@@ -41726,7 +42234,7 @@ function messageOf2(value) {
41726
42234
  return value == null ? "" : String(value);
41727
42235
  }
41728
42236
  function unwrap(value) {
41729
- const raw = messageOf2(value).trim();
42237
+ const raw = messageOf3(value).trim();
41730
42238
  const start = raw.indexOf("{");
41731
42239
  let parsed;
41732
42240
  if (start >= 0) {
@@ -41746,39 +42254,147 @@ function unwrap(value) {
41746
42254
  return { raw, message, status, code };
41747
42255
  }
41748
42256
  function isRejected429(value) {
41749
- 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 };
41750
42349
  }
41751
42350
  function describeError(value) {
41752
- const { raw, message, status, code } = unwrap(value);
41753
- const rejected429 = isRejected429(value);
42351
+ const { raw, message, status: textStatus, code: textCode } = unwrap(value);
41754
42352
  const details = safeErrorDetails(raw);
41755
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;
41756
42361
  let kind = "unknown";
41757
42362
  let summary = "";
41758
42363
  let recovery = "";
41759
- const transport = transportErrorText(value) || transportErrorText(raw);
41760
- 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)) {
41761
42368
  kind = "reauth";
41762
42369
  summary = "Sign-in expired.";
41763
42370
  recovery = "Sign in again from Providers.";
41764
- } 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)) {
41765
42372
  kind = "authentication";
41766
42373
  summary = "Provider authentication failed";
41767
42374
  recovery = "Check your sign-in or API key, then try again.";
41768
- } 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(
41769
42380
  clean3
41770
42381
  )) {
41771
42382
  kind = "image-size";
41772
42383
  summary = "An attached image exceeds the provider limit.";
41773
42384
  recovery = "Reduce the image dimensions or number of images, then try again.";
41774
- } else if (status === 413 || /payload too large|request (?:body )?too large|The request exceeds the size limit/i.test(clean3)) {
41775
- kind = "payload-size";
41776
- summary = "The request exceeds the size limit.";
41777
- recovery = "Reduce the attachments or request size, then try again.";
41778
- } else if (!rejected429 && (status === 429 || /rate[_ -]?limit|quota.*(?:hit|exceed)|too many requests|The provider usage limit was reached/i.test(clean3))) {
41779
- kind = "rate-limit";
41780
- summary = "The provider usage limit was reached.";
41781
- 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
+ }
41782
42398
  } else if (transport) {
41783
42399
  kind = "connection";
41784
42400
  summary = transport.replace(/\.$/, "");
@@ -41798,6 +42414,11 @@ function describeError(value) {
41798
42414
  kind,
41799
42415
  summary,
41800
42416
  recovery,
42417
+ recoveryTemplate,
42418
+ params,
42419
+ providerKind: descriptor.kind,
42420
+ resetAt,
42421
+ retryAfterMs,
41801
42422
  details,
41802
42423
  // Known structured failures ignore volatile indexes; unknown failures
41803
42424
  // retain their diagnostic identity rather than merging unrelated work.
@@ -41948,9 +42569,27 @@ function isCancelLikeError(error) {
41948
42569
  const text = errText(error);
41949
42570
  return /aborted by session close/i.test(text) || /withRetry:\s*(?:sleep )?aborted/i.test(text) || /^sleep aborted$/i.test(text);
41950
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
+ }
41951
42586
  function presentErrorText(error, options = {}) {
41952
42587
  const presentation = describeError(error);
41953
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
+ }
41954
42593
  const surface = options.surface || options.tool || "";
41955
42594
  const subject = subjectForSurface(surface);
41956
42595
  const max = options.max ?? 240;
@@ -49200,7 +49839,7 @@ function statuslineFooterIdentityChanged(args, lastArgs) {
49200
49839
  if (!lastArgs) return true;
49201
49840
  if (args.sessionId !== lastArgs.sessionId) return true;
49202
49841
  if (args.provider !== lastArgs.provider || args.model !== lastArgs.model) return true;
49203
- 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;
49204
49843
  if (args.contextWindow !== lastArgs.contextWindow || args.rawContextWindow !== lastArgs.rawContextWindow) return true;
49205
49844
  if (args.displayContextWindow !== lastArgs.displayContextWindow) return true;
49206
49845
  if (args.compactBoundaryTokens !== lastArgs.compactBoundaryTokens) return true;
@@ -49273,7 +49912,7 @@ import { existsSync as existsSync7, readFileSync as readFileSync7 } from "node:f
49273
49912
  import { join as join7 } from "node:path";
49274
49913
 
49275
49914
  // src/runtime/shared/llm/provider-model-identities.mjs
49276
- function fallbackModel(id, display, family, contextWindow, wire) {
49915
+ function fallbackModel(id, display, family, contextWindow, wire, levels = []) {
49277
49916
  const tiered = wire && typeof wire === "object";
49278
49917
  return {
49279
49918
  id,
@@ -49285,7 +49924,7 @@ function fallbackModel(id, display, family, contextWindow, wire) {
49285
49924
  supportsVision: true,
49286
49925
  supportsReasoning: true,
49287
49926
  supportsFunctionCalling: true,
49288
- reasoningLevels: tiered ? Object.keys(wire) : [],
49927
+ reasoningLevels: tiered ? Object.keys(wire) : [...levels],
49289
49928
  wire
49290
49929
  };
49291
49930
  }
@@ -49299,8 +49938,16 @@ var ANTIGRAVITY_MODELS = Object.freeze([
49299
49938
  low: "gemini-3.1-pro-low",
49300
49939
  high: "gemini-3.1-pro-high"
49301
49940
  }),
49302
- fallbackModel("claude-opus-4-6-thinking", "Claude Opus 4.6 (Thinking)", null, 25e4, "claude-opus-4-6-thinking"),
49303
- 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
+ ]),
49304
49951
  fallbackModel("gpt-oss-120b-medium", "GPT-OSS 120B (Medium)", "gpt-oss", 131072, "gpt-oss-120b-medium")
49305
49952
  ]);
49306
49953
  var ANTIGRAVITY_PRICING_ALIASES = Object.freeze({
@@ -50210,6 +50857,7 @@ function localBootStatusLine(args = {}) {
50210
50857
  model = "",
50211
50858
  effort = "",
50212
50859
  fast = false,
50860
+ ultra = false,
50213
50861
  stats = null,
50214
50862
  contextWindow = 0,
50215
50863
  displayContextWindow = 0,
@@ -50218,7 +50866,9 @@ function localBootStatusLine(args = {}) {
50218
50866
  const raw = String(model || "").trim();
50219
50867
  const { STATUS, SUBTLE } = statusColors();
50220
50868
  const display = shortenModelName(displayModelName(raw, provider, ""), terminalColumns());
50221
- 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);
50222
50872
  const modelBits = [display, ...flags].join(` ${SUBTLE}\xB7${RESET3} `);
50223
50873
  const ctxPct = measuredContextUsage({
50224
50874
  stats,
@@ -50260,6 +50910,7 @@ function useStatusLineText({
50260
50910
  model,
50261
50911
  effort,
50262
50912
  fast,
50913
+ ultra,
50263
50914
  cwd: cwd2,
50264
50915
  stats,
50265
50916
  contextWindow,
@@ -50282,6 +50933,7 @@ function useStatusLineText({
50282
50933
  model,
50283
50934
  effort,
50284
50935
  fast,
50936
+ ultra,
50285
50937
  stats,
50286
50938
  contextWindow,
50287
50939
  displayContextWindow,
@@ -50312,6 +50964,7 @@ function useStatusLineText({
50312
50964
  model,
50313
50965
  effort,
50314
50966
  fast,
50967
+ ultra,
50315
50968
  cwd: cwd2,
50316
50969
  stats,
50317
50970
  contextWindow,
@@ -50359,7 +51012,7 @@ function useStatusLineText({
50359
51012
  const args = statuslineArgsRef.current;
50360
51013
  const identityChanged = statuslineFooterIdentityChanged({ ...args, agentRevision }, lastImmediateArgsRef.current);
50361
51014
  const prevImmediate = lastImmediateArgsRef.current;
50362
- 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;
50363
51016
  const themeChanged = themeEpochRef.current !== themeEpoch;
50364
51017
  if (themeChanged) {
50365
51018
  themeEpochRef.current = themeEpoch;
@@ -50380,6 +51033,7 @@ function useStatusLineText({
50380
51033
  model: args.model,
50381
51034
  effort: args.effort,
50382
51035
  fast: args.fast,
51036
+ ultra: args.ultra,
50383
51037
  contextWindow: args.contextWindow,
50384
51038
  displayContextWindow: args.displayContextWindow,
50385
51039
  rawContextWindow: args.rawContextWindow,
@@ -50448,6 +51102,7 @@ function useStatusLineText({
50448
51102
  model,
50449
51103
  effort,
50450
51104
  fast,
51105
+ ultra,
50451
51106
  cwd2,
50452
51107
  statsSignature,
50453
51108
  contextWindow,
@@ -50475,6 +51130,7 @@ function StatusLineView({
50475
51130
  model,
50476
51131
  effort,
50477
51132
  fast,
51133
+ ultra = false,
50478
51134
  cwd: cwd2,
50479
51135
  stats,
50480
51136
  contextWindow,
@@ -50498,6 +51154,7 @@ function StatusLineView({
50498
51154
  model,
50499
51155
  effort,
50500
51156
  fast,
51157
+ ultra,
50501
51158
  cwd: cwd2,
50502
51159
  stats,
50503
51160
  contextWindow,
@@ -53119,7 +53776,7 @@ import { Fragment as Fragment6, jsx as jsx14, jsxs as jsxs12 } from "react/jsx-r
53119
53776
  var PROVIDER_LABEL_WIDTH = 28;
53120
53777
  var CREDIT_LABEL = "Credit";
53121
53778
  var STATUS_SEPARATOR2 = " \u2502 ";
53122
- function resetLabel(value) {
53779
+ function resetLabel2(value) {
53123
53780
  const at = Number(value);
53124
53781
  if (!Number.isFinite(at) || at <= 0) return "";
53125
53782
  const date = new Date(at);
@@ -53158,7 +53815,7 @@ function creditsColor(w) {
53158
53815
  }
53159
53816
  function windowResetText(w) {
53160
53817
  if (isLocalEstimateWindow(w)) return "";
53161
- const reset = resetLabel(w?.resetAt);
53818
+ const reset = resetLabel2(w?.resetAt);
53162
53819
  if (!reset) return "";
53163
53820
  return `\u21BB ${reset}`;
53164
53821
  }
@@ -55419,6 +56076,7 @@ function renderAppView(ctx) {
55419
56076
  model: state.model,
55420
56077
  effort: state.effort,
55421
56078
  fast: state.fast,
56079
+ ultra: state.fast === true && state.modelParameters?.serviceTier === "ultrafast",
55422
56080
  cwd: state.cwd,
55423
56081
  stats: statuslineStats,
55424
56082
  contextWindow: state.contextWindow,
@@ -56093,6 +56751,105 @@ function createCoreMemoryPicker({ store, surface, setSettingsPrompt, parseMemory
56093
56751
  };
56094
56752
  }
56095
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
+
56096
56853
  // src/tui/app/extension-pickers/scope-note.mjs
56097
56854
  var scopeNote = (row) => {
56098
56855
  if (row?.activeHere === false) return "not in this project";
@@ -56122,8 +56879,9 @@ var serverDescription = (server, pending, optimistic) => {
56122
56879
  const transport = server.transport || "unknown";
56123
56880
  if (pending) return `${optimistic.enabled ? "enabling" : "disabling"}\u2026 \xB7 ${transport}`;
56124
56881
  const error = server.error ? ` \xB7 ${server.error}` : "";
56882
+ const signIn = server.authRequired ? ` \xB7 sign-in required: /mcp login ${server.name}` : "";
56125
56883
  return withScope(
56126
- `${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}`,
56127
56885
  server
56128
56886
  );
56129
56887
  };
@@ -56682,7 +57440,7 @@ function createExtensionPickers({
56682
57440
  setSettingsPrompt,
56683
57441
  openMcpPicker: mcp.openMcpPicker
56684
57442
  });
56685
- return { ...mcp, ...skills, ...plugins };
57443
+ return { ...mcp, ...createMcpLogin({ store, setProviderPrompt }), ...skills, ...plugins };
56686
57444
  }
56687
57445
 
56688
57446
  // src/tui/app/maintenance-pickers/auto-clear-picker.mjs
@@ -57488,13 +58246,6 @@ var PROVIDER_DISPLAY_RANKS = {
57488
58246
  openrouter: 950
57489
58247
  };
57490
58248
  var providerDisplayRank = (provider) => PROVIDER_DISPLAY_RANKS[String(provider || "").toLowerCase()] ?? 900;
57491
- var titleCaseOption = (value) => String(value || "").split(/([\s_-]+)/).map((part) => /^[\s_-]+$/.test(part) ? part : `${part.charAt(0).toUpperCase()}${part.slice(1).toLowerCase()}`).join("");
57492
- var effortDisplayLabel = (value) => {
57493
- const text = String(value || "").trim();
57494
- if (!text) return "";
57495
- if (text.toLowerCase() === "xhigh") return "XHigh";
57496
- return titleCaseOption(text);
57497
- };
57498
58249
  var fastDisplayLabel = (enabled = true) => `Fast ${enabled ? "On" : "Off"}`;
57499
58250
  var modelDescription = (m) => [String(m?.description || "").trim(), m.fastCapable ? "Fast Available" : ""].filter(Boolean).join(" \xB7 ");
57500
58251
  var modelRecordDisplayName = (model) => displayModelName(model?.id, model?.provider, model?.display || model?.name);
@@ -57550,7 +58301,11 @@ var buildProviderModelItems = (models, provider, currentRoute = null) => {
57550
58301
  _model: model
57551
58302
  }));
57552
58303
  };
57553
- 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 ");
57554
58309
  var routeLabel = (route) => {
57555
58310
  if (!route?.provider || !route?.model) return "(unset)";
57556
58311
  return [providerDisplayName(route.provider), routeModelDetails(route)].filter(Boolean).join(" \xB7 ");
@@ -57560,7 +58315,7 @@ var agentModelProfile = (route) => route?.model ? routeModelDetails(route) : "";
57560
58315
  var agentModelParts = (route) => [
57561
58316
  { text: route?.model ? routeModelDisplayName(route) : "", width: 17 },
57562
58317
  { text: route?.effort ? effortDisplayLabel(route.effort) : "", width: 6 },
57563
- { text: route?.fast ? "Fast" : "", width: 4 }
58318
+ { text: routeSpeedLabel(route), width: 9 }
57564
58319
  ];
57565
58320
  var routeFromModel = (model, effort = null) => ({
57566
58321
  provider: model.provider,
@@ -60569,6 +61324,7 @@ var desktopOnlyNotice = (ctx) => {
60569
61324
  ctx.store.pushNotice("Schedules and webhooks are managed in the Mixdog desktop app", "info");
60570
61325
  return true;
60571
61326
  };
61327
+ var openMcpPanel = panelCommand("mcp", "MCP Servers", (deps) => deps.openMcpPicker());
60572
61328
  var openSettings = panelCommand("settings", "Settings", (deps) => deps.openSettingsPicker());
60573
61329
  var panelCommands = {
60574
61330
  project(ctx, arg) {
@@ -60580,7 +61336,20 @@ var panelCommands = {
60580
61336
  ctx.openSlashPanel("project", "Projects", () => ctx.deps.openProjectPicker());
60581
61337
  return true;
60582
61338
  },
60583
- 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
+ },
60584
61353
  skills: panelCommand("skills", "Skills", (deps) => deps.openSkillsPicker()),
60585
61354
  plugins: panelCommand("plugins", "Plugins", (deps) => deps.openPluginsPicker()),
60586
61355
  providers: panelCommand("providers", "Providers", (deps) => deps.openProviderSetupPicker()),
@@ -60990,6 +61759,8 @@ function createAppPickers({
60990
61759
  const {
60991
61760
  openMcpServersPicker,
60992
61761
  openMcpPicker,
61762
+ loginMcpServer,
61763
+ logoutMcpServer,
60993
61764
  openProjectSkillsPicker,
60994
61765
  openSkillsPicker,
60995
61766
  openSkillDetailPicker,
@@ -61117,6 +61888,8 @@ function createAppPickers({
61117
61888
  enterProject: (...a) => enterProject(...a),
61118
61889
  openProjectPicker: (...a) => openProjectPicker(...a),
61119
61890
  openMcpPicker: (...a) => openMcpPicker(...a),
61891
+ loginMcpServer,
61892
+ logoutMcpServer,
61120
61893
  openSkillsPicker: (...a) => openSkillsPicker(...a),
61121
61894
  openPluginsPicker: (...a) => openPluginsPicker(...a),
61122
61895
  openProviderSetupPicker: (...a) => openProviderSetupPicker(...a),