mastracode 0.31.1-alpha.8 → 0.32.0-alpha.13

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.
package/CHANGELOG.md CHANGED
@@ -1,5 +1,98 @@
1
1
  # mastracode
2
2
 
3
+ ## 0.32.0-alpha.13
4
+
5
+ ### Patch Changes
6
+
7
+ - Updated dependencies [[`c9e3521`](https://github.com/mastra-ai/mastra/commit/c9e3521628422db84e00a5ff1dea7426c8cce537)]:
8
+ - @mastra/pg@1.17.0-alpha.3
9
+ - @mastra/code-sdk@1.0.0-alpha.13
10
+
11
+ ## 0.32.0-alpha.12
12
+
13
+ ### Patch Changes
14
+
15
+ - Fixed local database cleanup across interactive, ACP, and headless exits. ([#19901](https://github.com/mastra-ai/mastra/pull/19901))
16
+
17
+ - Updated dependencies [[`6193d6d`](https://github.com/mastra-ai/mastra/commit/6193d6d4ae62ad68daaaf450992198e9e49493f1), [`c7d30cd`](https://github.com/mastra-ai/mastra/commit/c7d30cd86009c407df91105591f03cd6e3d2854d), [`ef03fbc`](https://github.com/mastra-ai/mastra/commit/ef03fbcc556bcbc04c9b3d06fab88771ecaa043c), [`ef03fbc`](https://github.com/mastra-ai/mastra/commit/ef03fbcc556bcbc04c9b3d06fab88771ecaa043c), [`6193d6d`](https://github.com/mastra-ai/mastra/commit/6193d6d4ae62ad68daaaf450992198e9e49493f1), [`a7bbe77`](https://github.com/mastra-ai/mastra/commit/a7bbe773577f60bc4761b534ef7ec6b476332dad), [`a7bbe77`](https://github.com/mastra-ai/mastra/commit/a7bbe773577f60bc4761b534ef7ec6b476332dad), [`4e68363`](https://github.com/mastra-ai/mastra/commit/4e683634f94ebd062d26a3bb6093a8dfc7263d37), [`9251370`](https://github.com/mastra-ai/mastra/commit/9251370ad413af464aa22d7566338bec5613e8de)]:
18
+ - @mastra/code-sdk@1.0.0-alpha.12
19
+ - @mastra/core@1.52.0-alpha.11
20
+ - @mastra/libsql@1.17.0-alpha.3
21
+
22
+ ## 0.32.0-alpha.11
23
+
24
+ ### Minor Changes
25
+
26
+ - Add browser-based OAuth authentication for HTTP MCP servers to Mastra Code. ([#19467](https://github.com/mastra-ai/mastra/pull/19467))
27
+
28
+ When an HTTP MCP server rejects a connection with an authorization error, the
29
+ `/mcp` selector now shows a "needs auth" badge and an **Authenticate** action.
30
+ Choosing it opens the provider's consent page in the browser and completes the
31
+ OAuth 2.1 authorization-code flow (PKCE + Dynamic Client Registration) over a
32
+ loopback callback server, persists the tokens, and reconnects — no manual
33
+ configuration required for a bare `{ "url": ... }` server entry. A **Cancel
34
+ authentication** action aborts an in-flight flow and returns the server to the
35
+ needs-auth state.
36
+
37
+ The server manager gains `authenticateServer(name)` and
38
+ `cancelServerAuthentication(name)`, `McpServerStatus` gains an optional
39
+ `needsAuth` flag, and the OAuth `redirectUrl` in MCP server config is now
40
+ optional (it defaults to a stable loopback URL). The config also accepts
41
+ `callbackPort` as a shorthand that synthesizes
42
+ `http://localhost:<callbackPort>/callback`, the Claude Code / Codex
43
+ convention, so configs written for those clients (like Slack's official MCP
44
+ plugin config) work verbatim. `callbackPort` and `redirectUrl` are mutually
45
+ exclusive.
46
+
47
+ ```ts
48
+ const server = manager.getServerStatuses().find(s => s.name === 'supabase');
49
+ if (server?.needsAuth) {
50
+ // Opens the consent page in the browser, completes the OAuth flow, and
51
+ // resolves with the reconnected server status.
52
+ const status = await manager.authenticateServer('supabase', {
53
+ onAuthorizationUrl: url => openInBrowser(url),
54
+ });
55
+ console.log(status.connected);
56
+
57
+ // Abort an abandoned browser flow and return the server to needs-auth:
58
+ // await manager.cancelServerAuthentication('supabase')
59
+ }
60
+ ```
61
+
62
+ ### Patch Changes
63
+
64
+ - Updated dependencies [[`6341b72`](https://github.com/mastra-ai/mastra/commit/6341b720fa80e65731cbbd7d88d1088f4c5b9914)]:
65
+ - @mastra/code-sdk@1.0.0-alpha.11
66
+
67
+ ## 0.31.1-alpha.10
68
+
69
+ ### Patch Changes
70
+
71
+ - dependencies updates: ([#19813](https://github.com/mastra-ai/mastra/pull/19813))
72
+ - Updated dependency [`@ai-sdk/amazon-bedrock@^3.0.107` ↗︎](https://www.npmjs.com/package/@ai-sdk/amazon-bedrock/v/3.0.107) (from `^3.0.105`, in `dependencies`)
73
+ - Updated dependency [`@ai-sdk/anthropic@^3.0.98` ↗︎](https://www.npmjs.com/package/@ai-sdk/anthropic/v/3.0.98) (from `^3.0.96`, in `dependencies`)
74
+ - Updated dependency [`@ai-sdk/openai@^3.0.86` ↗︎](https://www.npmjs.com/package/@ai-sdk/openai/v/3.0.86) (from `^3.0.84`, in `dependencies`)
75
+ - Updated dependency [`@ai-sdk/openai-compatible@^2.0.62` ↗︎](https://www.npmjs.com/package/@ai-sdk/openai-compatible/v/2.0.62) (from `^2.0.59`, in `dependencies`)
76
+ - Updated dependency [`ai@^6.0.230` ↗︎](https://www.npmjs.com/package/ai/v/6.0.230) (from `^6.0.225`, in `dependencies`)
77
+
78
+ - Preserved Mastra Code's displayed active goal time across pauses, approval waits, and thread reloads. ([#19837](https://github.com/mastra-ai/mastra/pull/19837))
79
+
80
+ - Updated dependencies [[`41a5392`](https://github.com/mastra-ai/mastra/commit/41a5392d9f6c5e18d6b227f0fc0ddf49c50774e9), [`41a5392`](https://github.com/mastra-ai/mastra/commit/41a5392d9f6c5e18d6b227f0fc0ddf49c50774e9), [`b4b7ea8`](https://github.com/mastra-ai/mastra/commit/b4b7ea8733f033fc441ea47ed03f6afb17ec2248), [`675fbff`](https://github.com/mastra-ai/mastra/commit/675fbff84d3274391b33e852f76083c38a5514e5), [`da009e1`](https://github.com/mastra-ai/mastra/commit/da009e1aacd89ed94b8d1b2af09c9d4fe7c4db49), [`b4b7ea8`](https://github.com/mastra-ai/mastra/commit/b4b7ea8733f033fc441ea47ed03f6afb17ec2248), [`35c2181`](https://github.com/mastra-ai/mastra/commit/35c2181e6a50e47c90ba36260db7c9723d54696f), [`232fcbc`](https://github.com/mastra-ai/mastra/commit/232fcbc14fce625dd672ba043329c0b732c62be2), [`b4b7ea8`](https://github.com/mastra-ai/mastra/commit/b4b7ea8733f033fc441ea47ed03f6afb17ec2248), [`675fbff`](https://github.com/mastra-ai/mastra/commit/675fbff84d3274391b33e852f76083c38a5514e5), [`6deac4a`](https://github.com/mastra-ai/mastra/commit/6deac4a520750d807a2154333bf1b91a2df958a5), [`c328769`](https://github.com/mastra-ai/mastra/commit/c3287698ff8ef98dba86d415faa566fa3e5f4d56), [`232fcbc`](https://github.com/mastra-ai/mastra/commit/232fcbc14fce625dd672ba043329c0b732c62be2), [`3491666`](https://github.com/mastra-ai/mastra/commit/34916663c4fdd43b48c21f4ab2d5fb6dcccc94f9)]:
81
+ - @mastra/code-sdk@1.0.0-alpha.10
82
+ - @mastra/core@1.52.0-alpha.10
83
+ - @mastra/libsql@1.17.0-alpha.2
84
+ - @mastra/pg@1.17.0-alpha.2
85
+ - @mastra/observability@1.16.2-alpha.1
86
+ - @mastra/mcp@1.15.0-alpha.0
87
+
88
+ ## 0.31.1-alpha.9
89
+
90
+ ### Patch Changes
91
+
92
+ - Updated dependencies [[`0a2c22c`](https://github.com/mastra-ai/mastra/commit/0a2c22c902604439ec490319e14c17f331e0c84c), [`3a8024c`](https://github.com/mastra-ai/mastra/commit/3a8024ce615f8aa89479c0d71fe61d10bb0040be)]:
93
+ - @mastra/core@1.52.0-alpha.9
94
+ - @mastra/code-sdk@0.2.0-alpha.9
95
+
3
96
  ## 0.31.1-alpha.8
4
97
 
5
98
  ### Patch Changes
@@ -1240,9 +1240,6 @@ async function startGoal(ctx, objective, judgeModelId, maxTurns, options = {}) {
1240
1240
  return;
1241
1241
  }
1242
1242
  state.planStartedGoalId = void 0;
1243
- if (options.trigger === "none") {
1244
- goalManager.resetActiveTimer();
1245
- }
1246
1243
  if (shouldPersistToCreatedThread) {
1247
1244
  goalManager.persistOnNextThreadCreate();
1248
1245
  }
@@ -2459,7 +2456,14 @@ var FAILED_ACTIONS = [
2459
2456
  { label: "View logs", key: "logs" },
2460
2457
  { label: "Reconnect", key: "reconnect" }
2461
2458
  ];
2459
+ var NEEDS_AUTH_ACTIONS = [
2460
+ { label: "Authenticate", key: "authenticate" },
2461
+ { label: "View error", key: "error" },
2462
+ { label: "View logs", key: "logs" },
2463
+ { label: "Reconnect", key: "reconnect" }
2464
+ ];
2462
2465
  var CONNECTING_ACTIONS = [{ label: "Waiting for connection...", key: "none" }];
2466
+ var AUTHENTICATING_ACTIONS = [{ label: "Cancel authentication", key: "cancel-authenticate" }];
2463
2467
  var McpSelectorComponent = class extends Box {
2464
2468
  listContainer;
2465
2469
  statuses;
@@ -2468,6 +2472,8 @@ var McpSelectorComponent = class extends Box {
2468
2472
  getStatusesCallback;
2469
2473
  onReloadAllCallback;
2470
2474
  onReconnectServerCallback;
2475
+ onAuthenticateServerCallback;
2476
+ onCancelAuthenticateServerCallback;
2471
2477
  getServerLogsCallback;
2472
2478
  showInfoCallback;
2473
2479
  onCloseCallback;
@@ -2481,6 +2487,13 @@ var McpSelectorComponent = class extends Box {
2481
2487
  _detailView = false;
2482
2488
  // Loading state during reload
2483
2489
  _reloading = false;
2490
+ // Names of servers with an in-flight OAuth flow (so their sub-menu offers a
2491
+ // cancel path while they show as connecting).
2492
+ _authenticating = /* @__PURE__ */ new Set();
2493
+ // Names of servers the user is actively cancelling. The authenticate flow
2494
+ // resolves with a failed status when cancelled, so we track this to suppress
2495
+ // the misleading "Failed to authenticate" toast on a deliberate cancel.
2496
+ _cancelling = /* @__PURE__ */ new Set();
2484
2497
  // Focusable implementation
2485
2498
  _focused = false;
2486
2499
  get focused() {
@@ -2497,6 +2510,8 @@ var McpSelectorComponent = class extends Box {
2497
2510
  this.getStatusesCallback = options.getStatuses;
2498
2511
  this.onReloadAllCallback = options.onReloadAll;
2499
2512
  this.onReconnectServerCallback = options.onReconnectServer;
2513
+ this.onAuthenticateServerCallback = options.onAuthenticateServer;
2514
+ this.onCancelAuthenticateServerCallback = options.onCancelAuthenticateServer;
2500
2515
  this.getServerLogsCallback = options.getServerLogs;
2501
2516
  this.showInfoCallback = options.showInfo;
2502
2517
  this.onCloseCallback = options.onClose;
@@ -2531,12 +2546,18 @@ var McpSelectorComponent = class extends Box {
2531
2546
  if (this._reloading) {
2532
2547
  icon = theme.fg("warning", "\u27F3");
2533
2548
  stateText = theme.fg("warning", "reconnecting...");
2549
+ } else if (this.isAuthenticating(status)) {
2550
+ icon = theme.fg("warning", "\u27F3");
2551
+ stateText = theme.fg("warning", "authenticating \u2014 Enter to cancel");
2534
2552
  } else if (status.connecting) {
2535
2553
  icon = theme.fg("warning", "\u27F3");
2536
2554
  stateText = theme.fg("warning", "connecting...");
2537
2555
  } else if (status.connected) {
2538
2556
  icon = theme.fg("success", "\u2714");
2539
2557
  stateText = theme.fg("success", "connected");
2558
+ } else if (status.needsAuth) {
2559
+ icon = theme.fg("warning", "\u26A0");
2560
+ stateText = theme.fg("warning", "needs auth");
2540
2561
  } else {
2541
2562
  icon = theme.fg("error", "\u2717");
2542
2563
  stateText = theme.fg("error", "failed");
@@ -2575,10 +2596,20 @@ var McpSelectorComponent = class extends Box {
2575
2596
  }
2576
2597
  this.tui.requestRender();
2577
2598
  }
2599
+ /**
2600
+ * Whether an OAuth flow is in flight for this server. True if either the local
2601
+ * set (this selector instance started the flow) or the manager-owned status
2602
+ * flag (survives close/reopen) says so.
2603
+ */
2604
+ isAuthenticating(status) {
2605
+ return status.authenticating === true || this._authenticating.has(status.name);
2606
+ }
2607
+ isBusy() {
2608
+ return this.statuses.some((s) => s.connecting || this.isAuthenticating(s)) || this._authenticating.size > 0;
2609
+ }
2578
2610
  startPollingIfNeeded() {
2579
2611
  if (this.pollTimer) return;
2580
- const hasConnecting = this.statuses.some((s) => s.connecting);
2581
- if (!hasConnecting) return;
2612
+ if (!this.isBusy()) return;
2582
2613
  this.pollTimer = setInterval(() => {
2583
2614
  if (this._detailView || this._reloading) return;
2584
2615
  const fresh = this.getStatusesCallback();
@@ -2589,7 +2620,7 @@ var McpSelectorComponent = class extends Box {
2589
2620
  this.selectedIndex = Math.max(0, total - 1);
2590
2621
  }
2591
2622
  this.updateList();
2592
- if (!this.statuses.some((s) => s.connecting)) {
2623
+ if (!this.isBusy()) {
2593
2624
  this.stopPolling();
2594
2625
  }
2595
2626
  }, 500);
@@ -2646,10 +2677,14 @@ var McpSelectorComponent = class extends Box {
2646
2677
  openSubMenu() {
2647
2678
  const status = this.statuses[this.selectedIndex];
2648
2679
  if (!status) return;
2649
- if (status.connecting) {
2680
+ if (this.isAuthenticating(status)) {
2681
+ this.subMenuActions = AUTHENTICATING_ACTIONS;
2682
+ } else if (status.connecting) {
2650
2683
  this.subMenuActions = CONNECTING_ACTIONS;
2651
2684
  } else if (status.connected) {
2652
2685
  this.subMenuActions = CONNECTED_ACTIONS;
2686
+ } else if (status.needsAuth) {
2687
+ this.subMenuActions = NEEDS_AUTH_ACTIONS;
2653
2688
  } else {
2654
2689
  this.subMenuActions = FAILED_ACTIONS;
2655
2690
  }
@@ -2697,6 +2732,16 @@ var McpSelectorComponent = class extends Box {
2697
2732
  this.doReconnectServer(status);
2698
2733
  break;
2699
2734
  }
2735
+ case "authenticate": {
2736
+ this.subMenuOpen = false;
2737
+ this.doAuthenticateServer(status);
2738
+ break;
2739
+ }
2740
+ case "cancel-authenticate": {
2741
+ this.subMenuOpen = false;
2742
+ this.doCancelAuthentication(status);
2743
+ break;
2744
+ }
2700
2745
  }
2701
2746
  }
2702
2747
  doReloadAll() {
@@ -2705,6 +2750,11 @@ var McpSelectorComponent = class extends Box {
2705
2750
  this.onReloadAllCallback().then((result) => {
2706
2751
  this.statuses = result.statuses;
2707
2752
  this.skipped = result.skipped;
2753
+ const liveNames = new Set(result.statuses.map((s) => s.name));
2754
+ for (const name of this._authenticating) {
2755
+ if (!liveNames.has(name)) this._authenticating.delete(name);
2756
+ }
2757
+ this._cancelling.clear();
2708
2758
  const total = this.getTotalItems();
2709
2759
  if (this.selectedIndex >= total) {
2710
2760
  this.selectedIndex = Math.max(0, total - 1);
@@ -2713,7 +2763,11 @@ var McpSelectorComponent = class extends Box {
2713
2763
  const totalTools = connected.reduce((sum, s) => sum + s.toolCount, 0);
2714
2764
  this.showInfoCallback(`MCP: Reloaded. ${connected.length} server(s) connected, ${totalTools} tool(s).`);
2715
2765
  for (const s of result.statuses.filter((s2) => !s2.connected)) {
2716
- this.showInfoCallback(`MCP: Failed to connect to "${s.name}": ${s.error ?? "Unknown error"}`);
2766
+ if (s.needsAuth) {
2767
+ this.showInfoCallback(`MCP: \u26A0 "${s.name}" needs authentication \u2192 run /mcp to authenticate`);
2768
+ } else {
2769
+ this.showInfoCallback(`MCP: Failed to connect to "${s.name}": ${s.error ?? "Unknown error"}`);
2770
+ }
2717
2771
  }
2718
2772
  }).catch(() => {
2719
2773
  this.showInfoCallback("MCP: Reload failed. Retrying may help.");
@@ -2770,6 +2824,81 @@ var McpSelectorComponent = class extends Box {
2770
2824
  }
2771
2825
  });
2772
2826
  }
2827
+ doAuthenticateServer(status) {
2828
+ if (status.connecting) return;
2829
+ const name = status.name;
2830
+ const idx = this.statuses.findIndex((s) => s.name === name);
2831
+ if (idx >= 0) {
2832
+ this.statuses[idx] = {
2833
+ name,
2834
+ connected: false,
2835
+ connecting: true,
2836
+ toolCount: 0,
2837
+ toolNames: [],
2838
+ transport: status.transport
2839
+ };
2840
+ }
2841
+ this._authenticating.add(name);
2842
+ if (idx >= 0) {
2843
+ this.selectedIndex = idx;
2844
+ }
2845
+ this.openSubMenu();
2846
+ this.startPollingIfNeeded();
2847
+ this.showInfoCallback(`MCP: Authenticating "${name}" \u2014 complete the sign-in in your browser.`);
2848
+ this.onAuthenticateServerCallback(name).then((updated) => {
2849
+ if (this._reloading) return;
2850
+ const i = this.statuses.findIndex((s) => s.name === name);
2851
+ if (i >= 0) {
2852
+ this.statuses[i] = updated;
2853
+ }
2854
+ if (updated.connected) {
2855
+ this.showInfoCallback(`MCP: Authenticated "${name}" \u2014 ${updated.toolCount} tool(s)`);
2856
+ } else if (!updated.cancelled && !this._cancelling.has(name)) {
2857
+ this.showInfoCallback(`MCP: Failed to authenticate "${name}": ${updated.error ?? "Unknown error"}`);
2858
+ }
2859
+ }).catch((err) => {
2860
+ if (this._reloading) return;
2861
+ const errMsg = err instanceof Error ? err.message : String(err);
2862
+ const i = this.statuses.findIndex((s) => s.name === name);
2863
+ if (i >= 0) {
2864
+ this.statuses[i] = {
2865
+ name,
2866
+ connected: false,
2867
+ connecting: false,
2868
+ toolCount: 0,
2869
+ toolNames: [],
2870
+ transport: status.transport,
2871
+ error: errMsg,
2872
+ needsAuth: true
2873
+ };
2874
+ }
2875
+ if (!this._cancelling.has(name)) {
2876
+ this.showInfoCallback(`MCP: Failed to authenticate "${name}": ${errMsg}`);
2877
+ }
2878
+ }).finally(() => {
2879
+ this._authenticating.delete(name);
2880
+ this._cancelling.delete(name);
2881
+ if (this.subMenuOpen && this.statuses[this.selectedIndex]?.name === name) {
2882
+ this.subMenuOpen = false;
2883
+ }
2884
+ if (!this._reloading) {
2885
+ this.updateList();
2886
+ }
2887
+ });
2888
+ }
2889
+ doCancelAuthentication(status) {
2890
+ const name = status.name;
2891
+ if (!this.isAuthenticating(status)) return;
2892
+ this._cancelling.add(name);
2893
+ this.showInfoCallback(`MCP: Cancelling authentication for "${name}"...`);
2894
+ this.updateList();
2895
+ this.onCancelAuthenticateServerCallback(name).then((cancelled) => {
2896
+ if (cancelled) {
2897
+ this.showInfoCallback(`MCP: Cancelled authentication for "${name}".`);
2898
+ }
2899
+ }).catch(() => {
2900
+ });
2901
+ }
2773
2902
  showToolList(status) {
2774
2903
  this.listContainer.clear();
2775
2904
  this.listContainer.addChild(
@@ -2935,6 +3064,22 @@ function notify(state, reason, message) {
2935
3064
  hookManager: state.hookManager
2936
3065
  });
2937
3066
  }
3067
+ function openUrlInBrowser(url) {
3068
+ let parsed;
3069
+ try {
3070
+ parsed = new URL(url);
3071
+ } catch {
3072
+ return;
3073
+ }
3074
+ if (parsed.protocol !== "http:" && parsed.protocol !== "https:") {
3075
+ return;
3076
+ }
3077
+ const [cmd, args] = process.platform === "darwin" ? ["open", [url]] : process.platform === "win32" ? ["rundll32", ["url.dll,FileProtocolHandler", url]] : ["xdg-open", [url]];
3078
+ const child = spawn(cmd, args, { stdio: "ignore", detached: true });
3079
+ child.on("error", () => {
3080
+ });
3081
+ child.unref();
3082
+ }
2938
3083
 
2939
3084
  // src/tui/commands/mcp.ts
2940
3085
  async function handleMcpCommand(ctx, args) {
@@ -2977,8 +3122,8 @@ Example mcp.json:
2977
3122
  }
2978
3123
  }
2979
3124
 
2980
- Note: For dynamic auth (token refresh), use a stdio wrapper.
2981
- "headers" only supports static values.`
3125
+ Servers that require OAuth can be added with just a "url" \u2014
3126
+ authenticate them from the /mcp selector.`
2982
3127
  );
2983
3128
  return;
2984
3129
  }
@@ -3003,6 +3148,20 @@ Note: For dynamic auth (token refresh), use a stdio wrapper.
3003
3148
  onReconnectServer: async (name) => {
3004
3149
  return mm.reconnectServer(name);
3005
3150
  },
3151
+ onAuthenticateServer: async (name) => {
3152
+ return mm.authenticateServer(name, {
3153
+ onAuthorizationUrl: (url) => {
3154
+ showInfo(ctx.state, `MCP: To authenticate "${name}", open:
3155
+ ${url}`);
3156
+ if (process.env.MASTRA_MCP_OAUTH_NO_BROWSER !== "1") {
3157
+ openUrlInBrowser(url);
3158
+ }
3159
+ }
3160
+ });
3161
+ },
3162
+ onCancelAuthenticateServer: async (name) => {
3163
+ return mm.cancelServerAuthentication(name);
3164
+ },
3006
3165
  getServerLogs: (name) => {
3007
3166
  return mm.getServerLogs(name);
3008
3167
  },
@@ -3028,7 +3187,11 @@ async function reloadServers(ctx) {
3028
3187
  const totalTools = connected.reduce((sum, s) => sum + s.toolCount, 0);
3029
3188
  ctx.showInfo(`MCP: Reloaded. ${connected.length} server(s) connected, ${totalTools} tool(s).`);
3030
3189
  for (const s of statuses.filter((s2) => !s2.connected)) {
3031
- ctx.showInfo(`MCP: Failed to connect to "${s.name}": ${s.error}`);
3190
+ if (s.needsAuth) {
3191
+ ctx.showInfo(`MCP: \u26A0 "${s.name}" needs authentication \u2192 run /mcp to authenticate`);
3192
+ } else {
3193
+ ctx.showInfo(`MCP: Failed to connect to "${s.name}": ${s.error}`);
3194
+ }
3032
3195
  }
3033
3196
  } catch (error) {
3034
3197
  ctx.showError(`MCP reload failed: ${error instanceof Error ? error.message : String(error)}`);
@@ -3046,8 +3209,8 @@ function showTextStatus(ctx) {
3046
3209
  lines.push(` Claude: ${paths.claude}`);
3047
3210
  lines.push("");
3048
3211
  for (const status of statuses) {
3049
- const icon = status.connecting ? "\u27F3" : status.connected ? "\u2713" : "\u2717";
3050
- const state = status.connecting ? "connecting..." : status.connected ? "connected" : `error: ${status.error}`;
3212
+ const icon = status.authenticating ? "\u26A0" : status.connecting ? "\u27F3" : status.connected ? "\u2713" : status.needsAuth ? "\u26A0" : "\u2717";
3213
+ const state = status.authenticating ? "authenticating \u2014 cancel via /mcp" : status.connecting ? "connecting..." : status.connected ? "connected" : status.needsAuth ? "needs auth \u2014 authenticate via /mcp" : `error: ${status.error}`;
3051
3214
  lines.push(` ${icon} ${status.name} [${status.transport}] (${state})`);
3052
3215
  if (status.toolNames.length > 0) {
3053
3216
  for (const toolName of status.toolNames) {
@@ -13598,22 +13761,6 @@ Run /browser on to apply.`);
13598
13761
  }
13599
13762
  ctx.showInfo(summary.join("\n"));
13600
13763
  }
13601
- function openUrlInBrowser(url) {
13602
- let parsed;
13603
- try {
13604
- parsed = new URL(url);
13605
- } catch {
13606
- return;
13607
- }
13608
- if (parsed.protocol !== "http:" && parsed.protocol !== "https:") {
13609
- return;
13610
- }
13611
- const [cmd, args] = process.platform === "darwin" ? ["open", [url]] : process.platform === "win32" ? ["rundll32", ["url.dll,FileProtocolHandler", url]] : ["xdg-open", [url]];
13612
- const child = spawn(cmd, args, { stdio: "ignore", detached: true });
13613
- child.on("error", () => {
13614
- });
13615
- child.unref();
13616
- }
13617
13764
  var LoginDialogComponent = class extends Box {
13618
13765
  constructor(tui, providerId, onComplete) {
13619
13766
  super(2, 1, (text) => theme.bg("overlayBg", text));
@@ -15549,7 +15696,6 @@ function pruneChatContainer(state) {
15549
15696
  // src/tui/handlers/agent-lifecycle.ts
15550
15697
  function handleAgentStart(ctx) {
15551
15698
  const { state } = ctx;
15552
- state.goalManager.startActiveTimer();
15553
15699
  getCurrentGitBranchAsync(state.projectInfo.rootPath).then((freshBranch) => {
15554
15700
  if (freshBranch) {
15555
15701
  state.projectInfo.gitBranch = freshBranch;
@@ -15566,7 +15712,6 @@ function handleAgentStart(ctx) {
15566
15712
  }
15567
15713
  function handleAgentEnd(ctx) {
15568
15714
  const { state } = ctx;
15569
- state.goalManager.stopActiveTimer();
15570
15715
  if (state.gradientAnimator) {
15571
15716
  state.gradientAnimator.fadeOut();
15572
15717
  }
@@ -15646,7 +15791,6 @@ function drainQueuedAction(ctx) {
15646
15791
  }
15647
15792
  function handleAgentAborted(ctx) {
15648
15793
  const { state } = ctx;
15649
- state.goalManager.stopActiveTimer();
15650
15794
  if (state.gradientAnimator) {
15651
15795
  state.gradientAnimator.fadeOut();
15652
15796
  }
@@ -15683,7 +15827,6 @@ function handleAgentAborted(ctx) {
15683
15827
  }
15684
15828
  function handleAgentError(ctx) {
15685
15829
  const { state } = ctx;
15686
- state.goalManager.stopActiveTimer();
15687
15830
  if (state.gradientAnimator) {
15688
15831
  state.gradientAnimator.fadeOut();
15689
15832
  }
@@ -20773,7 +20916,11 @@ var MastraTUI = class _MastraTUI {
20773
20916
  if (this.state.mcpManager?.hasServers()) {
20774
20917
  this.state.mcpManager.initInBackground().then((result) => {
20775
20918
  for (const s of result.failed) {
20776
- showInfo(this.state, `MCP: Failed to connect to "${s.name}": ${s.error}`);
20919
+ if (s.needsAuth) {
20920
+ showInfo(this.state, `MCP: \u26A0 "${s.name}" needs authentication \u2192 run /mcp to authenticate`);
20921
+ } else {
20922
+ showInfo(this.state, `MCP: Failed to connect to "${s.name}": ${s.error}`);
20923
+ }
20777
20924
  }
20778
20925
  for (const s of result.skipped) {
20779
20926
  showInfo(this.state, `MCP: Skipped "${s.name}": ${s.reason}`);
@@ -21644,5 +21791,5 @@ Would you like to update now?`;
21644
21791
  };
21645
21792
 
21646
21793
  export { AssistantMessageComponent, LoginDialogComponent, LoginSelectorComponent, MastraTUI, ModelSelectorComponent, OMProgressComponent, ToolExecutionComponentEnhanced, UserMessageComponent, applyThemeMode, createTUIState, detectTerminalTheme, formatOMStatus, getEditorTheme, getMarkdownTheme, getThemeMode, mastra, restoreTerminalForeground, theme };
21647
- //# sourceMappingURL=chunk-EXOGBKXL.js.map
21648
- //# sourceMappingURL=chunk-EXOGBKXL.js.map
21794
+ //# sourceMappingURL=chunk-FAXDM2KQ.js.map
21795
+ //# sourceMappingURL=chunk-FAXDM2KQ.js.map