pi-namespace-patch 1.0.0-namespace.2 → 1.0.2-namespace.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 (185) hide show
  1. package/CHANGELOG.md +54 -0
  2. package/README.md +22 -4
  3. package/dist/bundle/chunks/{anthropic-messages-UID2PALB.js → anthropic-messages-MVG2FL56.js} +3 -3
  4. package/dist/bundle/chunks/azure-openai-responses-7AMFUIWJ.js +2 -0
  5. package/dist/bundle/chunks/bedrock-converse-stream.js +2 -2
  6. package/dist/bundle/chunks/chunk-2KAZSACP.js +2 -0
  7. package/dist/bundle/chunks/{chunk-2KTBZM5G.js → chunk-6FX7UEPL.js} +5 -5
  8. package/dist/bundle/chunks/{chunk-2VNGUWBO.js → chunk-BYB6ZAAQ.js} +1 -1
  9. package/dist/bundle/chunks/chunk-DN3QEIXS.js +2 -0
  10. package/dist/bundle/chunks/chunk-F5ZABL6Z.js +20 -0
  11. package/dist/bundle/chunks/{chunk-3LH3ZQKY.js → chunk-G7EDXK4D.js} +1 -1
  12. package/dist/bundle/chunks/chunk-IKZJX7ZT.js +2 -0
  13. package/dist/bundle/chunks/{chunk-4N5K4RKC.js → chunk-OLBCNJCL.js} +31 -32
  14. package/dist/bundle/chunks/{chunk-PRD6WYBT.js → chunk-OYBSLV7Y.js} +1 -1
  15. package/dist/bundle/chunks/{chunk-IBCPYVFK.js → chunk-PDFMCAOZ.js} +4 -4
  16. package/dist/bundle/chunks/{chunk-LTXEMVMA.js → chunk-SYF2TF6W.js} +2 -2
  17. package/dist/bundle/chunks/chunk-WCQZGZ6I.js +82 -0
  18. package/dist/bundle/chunks/{chunk-KDN6RCEQ.js → chunk-ZSI3BL5Q.js} +2 -2
  19. package/dist/bundle/chunks/{cli-QOMC26IJ.js → cli-KILDDGW3.js} +2 -2
  20. package/dist/bundle/chunks/{cloudflare-workers-ai-system-one-NPQN263E.js → cloudflare-workers-ai-system-one-X5PVWWYJ.js} +1 -1
  21. package/dist/bundle/chunks/codemode-worker.js +24 -3
  22. package/dist/bundle/chunks/easter-egg-3d-T5FFWIBR.js +2 -0
  23. package/dist/bundle/chunks/{execute-GVRSEGHL.js → execute-RYVK27GT.js} +25 -4
  24. package/dist/bundle/chunks/{google-generative-ai-APTPZOQL.js → google-generative-ai-ZOK6CV7D.js} +1 -1
  25. package/dist/bundle/chunks/{google-vertex-MXCOSOY3.js → google-vertex-VKWZQ3AY.js} +1 -1
  26. package/dist/bundle/chunks/{mistral-conversations-DKVFNQL6.js → mistral-conversations-7DAUEE4N.js} +1 -1
  27. package/dist/bundle/chunks/node-N5BSDOA5.js +16 -0
  28. package/dist/bundle/chunks/openai-chatgpt.js +1 -1
  29. package/dist/bundle/chunks/{openai-codex-responses-GK67DQQJ.js → openai-codex-responses-TC3OK7B4.js} +1 -1
  30. package/dist/bundle/chunks/openai-completions-GWHGMQ3T.js +7 -0
  31. package/dist/bundle/chunks/openai-responses-EZ7FJ2KL.js +3 -0
  32. package/dist/bundle/chunks/{runtime-2SO2JDWM.js → runtime-D5I2NTIF.js} +1 -1
  33. package/dist/bundle/chunks/virtual-modules-J2M3WAR2.js +2 -0
  34. package/dist/bundle/cli-runtime.js +1 -1
  35. package/dist/bundle/index.js +1 -1
  36. package/dist/bundle/rpc-entry.js +1 -1
  37. package/dist/cli/args.d.ts.map +1 -1
  38. package/dist/cli/args.js +4 -1
  39. package/dist/cli/args.js.map +1 -1
  40. package/dist/config.d.ts.map +1 -1
  41. package/dist/config.js +3 -0
  42. package/dist/config.js.map +1 -1
  43. package/dist/core/agent-session.d.ts.map +1 -1
  44. package/dist/core/agent-session.js +1 -1
  45. package/dist/core/agent-session.js.map +1 -1
  46. package/dist/core/export-html/tool-renderer.d.ts +3 -3
  47. package/dist/core/export-html/tool-renderer.d.ts.map +1 -1
  48. package/dist/core/export-html/tool-renderer.js +3 -3
  49. package/dist/core/export-html/tool-renderer.js.map +1 -1
  50. package/dist/core/extensions/index.d.ts +1 -1
  51. package/dist/core/extensions/index.d.ts.map +1 -1
  52. package/dist/core/extensions/index.js.map +1 -1
  53. package/dist/core/extensions/loader.d.ts.map +1 -1
  54. package/dist/core/extensions/loader.js +5 -0
  55. package/dist/core/extensions/loader.js.map +1 -1
  56. package/dist/core/extensions/runner.d.ts +3 -1
  57. package/dist/core/extensions/runner.d.ts.map +1 -1
  58. package/dist/core/extensions/runner.js +6 -0
  59. package/dist/core/extensions/runner.js.map +1 -1
  60. package/dist/core/extensions/types.d.ts +9 -0
  61. package/dist/core/extensions/types.d.ts.map +1 -1
  62. package/dist/core/extensions/types.js.map +1 -1
  63. package/dist/core/mcp-servers.d.ts +6 -0
  64. package/dist/core/mcp-servers.d.ts.map +1 -1
  65. package/dist/core/mcp-servers.js +11 -0
  66. package/dist/core/mcp-servers.js.map +1 -1
  67. package/dist/core/model-config.d.ts +36 -0
  68. package/dist/core/model-config.d.ts.map +1 -1
  69. package/dist/core/model-config.js +14 -2
  70. package/dist/core/model-config.js.map +1 -1
  71. package/dist/core/model-resolver.js +1 -1
  72. package/dist/core/model-resolver.js.map +1 -1
  73. package/dist/core/provider-composer.d.ts +2 -1
  74. package/dist/core/provider-composer.d.ts.map +1 -1
  75. package/dist/core/provider-composer.js +13 -0
  76. package/dist/core/provider-composer.js.map +1 -1
  77. package/dist/core/tools/renderers/index.d.ts +2 -2
  78. package/dist/core/tools/renderers/index.d.ts.map +1 -1
  79. package/dist/core/tools/renderers/index.js.map +1 -1
  80. package/dist/extensions/mcp/cli.d.ts.map +1 -1
  81. package/dist/extensions/mcp/cli.js +3 -0
  82. package/dist/extensions/mcp/cli.js.map +1 -1
  83. package/dist/extensions/mcp/config.d.ts +15 -3
  84. package/dist/extensions/mcp/config.d.ts.map +1 -1
  85. package/dist/extensions/mcp/config.js +46 -10
  86. package/dist/extensions/mcp/config.js.map +1 -1
  87. package/dist/extensions/mcp/index.d.ts +4 -1
  88. package/dist/extensions/mcp/index.d.ts.map +1 -1
  89. package/dist/extensions/mcp/index.js +80 -45
  90. package/dist/extensions/mcp/index.js.map +1 -1
  91. package/dist/extensions/mcp/oauth.d.ts +4 -1
  92. package/dist/extensions/mcp/oauth.d.ts.map +1 -1
  93. package/dist/extensions/mcp/oauth.js +54 -10
  94. package/dist/extensions/mcp/oauth.js.map +1 -1
  95. package/dist/extensions/mcp/runtime.d.ts.map +1 -1
  96. package/dist/extensions/mcp/runtime.js +1 -0
  97. package/dist/extensions/mcp/runtime.js.map +1 -1
  98. package/dist/extensions/mcp/tools.d.ts +3 -1
  99. package/dist/extensions/mcp/tools.d.ts.map +1 -1
  100. package/dist/extensions/mcp/tools.js +19 -13
  101. package/dist/extensions/mcp/tools.js.map +1 -1
  102. package/dist/extensions/mcp/ui.d.ts.map +1 -1
  103. package/dist/extensions/mcp/ui.js +8 -4
  104. package/dist/extensions/mcp/ui.js.map +1 -1
  105. package/dist/index.d.ts +1 -1
  106. package/dist/index.d.ts.map +1 -1
  107. package/dist/index.js.map +1 -1
  108. package/dist/modes/interactive/components/armin.d.ts +3 -0
  109. package/dist/modes/interactive/components/armin.d.ts.map +1 -1
  110. package/dist/modes/interactive/components/armin.js +7 -5
  111. package/dist/modes/interactive/components/armin.js.map +1 -1
  112. package/dist/modes/interactive/components/auth-url.d.ts +14 -0
  113. package/dist/modes/interactive/components/auth-url.d.ts.map +1 -0
  114. package/dist/modes/interactive/components/auth-url.js +37 -0
  115. package/dist/modes/interactive/components/auth-url.js.map +1 -0
  116. package/dist/modes/interactive/components/easter-egg-3d.d.ts +104 -0
  117. package/dist/modes/interactive/components/easter-egg-3d.d.ts.map +1 -0
  118. package/dist/modes/interactive/components/{pi-logo-animation.js → easter-egg-3d.js} +127 -74
  119. package/dist/modes/interactive/components/easter-egg-3d.js.map +1 -0
  120. package/dist/modes/interactive/components/easter-egg-3d.lazy.d.ts +6 -0
  121. package/dist/modes/interactive/components/easter-egg-3d.lazy.d.ts.map +1 -0
  122. package/dist/modes/interactive/components/easter-egg-3d.lazy.js +23 -0
  123. package/dist/modes/interactive/components/easter-egg-3d.lazy.js.map +1 -0
  124. package/dist/modes/interactive/components/index.d.ts +0 -1
  125. package/dist/modes/interactive/components/index.d.ts.map +1 -1
  126. package/dist/modes/interactive/components/index.js +0 -1
  127. package/dist/modes/interactive/components/index.js.map +1 -1
  128. package/dist/modes/interactive/components/login-dialog.d.ts +2 -0
  129. package/dist/modes/interactive/components/login-dialog.d.ts.map +1 -1
  130. package/dist/modes/interactive/components/login-dialog.js +11 -5
  131. package/dist/modes/interactive/components/login-dialog.js.map +1 -1
  132. package/dist/modes/interactive/components/tool-execution.d.ts +6 -18
  133. package/dist/modes/interactive/components/tool-execution.d.ts.map +1 -1
  134. package/dist/modes/interactive/components/tool-execution.js +22 -45
  135. package/dist/modes/interactive/components/tool-execution.js.map +1 -1
  136. package/dist/modes/interactive/interactive-mode.d.ts +2 -2
  137. package/dist/modes/interactive/interactive-mode.d.ts.map +1 -1
  138. package/dist/modes/interactive/interactive-mode.js +15 -17
  139. package/dist/modes/interactive/interactive-mode.js.map +1 -1
  140. package/dist/package-manager-cli.d.ts.map +1 -1
  141. package/dist/package-manager-cli.js +12 -0
  142. package/dist/package-manager-cli.js.map +1 -1
  143. package/dist/utils/image-convert.d.ts +12 -0
  144. package/dist/utils/image-convert.d.ts.map +1 -1
  145. package/dist/utils/image-convert.js +45 -6
  146. package/dist/utils/image-convert.js.map +1 -1
  147. package/docs/cli.md +2 -0
  148. package/docs/codemode.md +1 -1
  149. package/docs/extensions.md +4 -0
  150. package/docs/keybindings.md +1 -1
  151. package/docs/mcp.md +23 -1
  152. package/docs/models.md +28 -2
  153. package/docs/quickstart.md +16 -2
  154. package/examples/extensions/custom-provider-anthropic/package-lock.json +2 -2
  155. package/examples/extensions/custom-provider-anthropic/package.json +1 -1
  156. package/examples/extensions/custom-provider-gitlab-duo/package.json +1 -1
  157. package/examples/extensions/gondolin/package-lock.json +2 -2
  158. package/examples/extensions/gondolin/package.json +1 -1
  159. package/examples/extensions/sandbox/package-lock.json +2 -2
  160. package/examples/extensions/sandbox/package.json +1 -1
  161. package/examples/extensions/with-deps/package-lock.json +2 -2
  162. package/examples/extensions/with-deps/package.json +1 -1
  163. package/package.json +13 -14
  164. package/dist/bundle/chunks/azure-openai-responses-AFMVM6NP.js +0 -2
  165. package/dist/bundle/chunks/chunk-6D7LHLKG.js +0 -2
  166. package/dist/bundle/chunks/chunk-7FH3BDRG.js +0 -82
  167. package/dist/bundle/chunks/chunk-DTD7JQ7Y.js +0 -42
  168. package/dist/bundle/chunks/chunk-MJOHEBV7.js +0 -2
  169. package/dist/bundle/chunks/node-O3RIBJRH.js +0 -16
  170. package/dist/bundle/chunks/openai-completions-JXDDPZ23.js +0 -7
  171. package/dist/bundle/chunks/openai-responses-CQDDLDQF.js +0 -3
  172. package/dist/bundle/chunks/pi-logo-animation-MPKZE4EK.js +0 -2
  173. package/dist/bundle/chunks/virtual-modules-3THEGRQQ.js +0 -2
  174. package/dist/modes/interactive/components/daxnuts.d.ts +0 -23
  175. package/dist/modes/interactive/components/daxnuts.d.ts.map +0 -1
  176. package/dist/modes/interactive/components/daxnuts.js +0 -140
  177. package/dist/modes/interactive/components/daxnuts.js.map +0 -1
  178. package/dist/modes/interactive/components/pi-logo-animation.d.ts +0 -68
  179. package/dist/modes/interactive/components/pi-logo-animation.d.ts.map +0 -1
  180. package/dist/modes/interactive/components/pi-logo-animation.js.map +0 -1
  181. package/dist/modes/interactive/components/pi-logo-animation.lazy.d.ts +0 -7
  182. package/dist/modes/interactive/components/pi-logo-animation.lazy.d.ts.map +0 -1
  183. package/dist/modes/interactive/components/pi-logo-animation.lazy.js +0 -12
  184. package/dist/modes/interactive/components/pi-logo-animation.lazy.js.map +0 -1
  185. package/npm-shrinkwrap.json +0 -1952
@@ -26,7 +26,6 @@
26
26
  * current session for registered servers.
27
27
  */
28
28
  import { join, resolve } from "node:path";
29
- import { hyperlink } from "@earendil-works/pi-tui";
30
29
  import { getAgentDir } from "../../config.js";
31
30
  import { mcpNamespace } from "../../core/mcp-servers.js";
32
31
  import { openBrowser } from "../../utils/open-browser.js";
@@ -35,7 +34,7 @@ import { isToolSearchTool, TOOL_SEARCH_TOOL_NAME } from "../tool-search/tool.js"
35
34
  import { getMcpToolExposure, loadMcpConfig, updateMcpServerConfig, } from "./config.js";
36
35
  import { createMcpResourceToolDefinitions, LIST_MCP_RESOURCE_TEMPLATES_TOOL, LIST_MCP_RESOURCES_TOOL, READ_MCP_RESOURCE_TOOL, } from "./resources.js";
37
36
  import { loadMcpRuntime } from "./runtime.lazy.js";
38
- import { createMcpToolDefinition, createMcpToolName } from "./tools.js";
37
+ import { createMcpToolDefinition, createMcpToolName, createMcpToolRenderers } from "./tools.js";
39
38
  import { showMcpManager } from "./ui.js";
40
39
  const DEFAULT_STARTUP_WAIT_MS = 10_000;
41
40
  const RESOURCE_TOOL_NAMES = new Set([
@@ -194,6 +193,8 @@ export function createMcpExtension(options = {}) {
194
193
  /** Servers from `mcp.json`, which take precedence over registered servers of the same name. */
195
194
  let configuredEntries = [];
196
195
  let configErrors = [];
196
+ /** The trusted project's `mcp.json`, where `/mcp` saves project overrides of global servers. */
197
+ let projectConfig;
197
198
  /** Registered servers that `mcp.json` overrides, shown in `/mcp`. */
198
199
  let overridden = [];
199
200
  /** Between session_start and session_shutdown. Registrations before that are read on session_start. */
@@ -214,7 +215,10 @@ export function createMcpExtension(options = {}) {
214
215
  let modelRegistry;
215
216
  let serverLog;
216
217
  const openUrl = options.openUrl ?? openBrowser;
217
- const updateConfig = options.updateConfig ?? ((entry, patch) => updateMcpServerConfig(entry.source, entry.name, patch));
218
+ const updateConfig = options.updateConfig ??
219
+ ((entry, patch) => updateMcpServerConfig(entry.override ?? entry.source, entry.name, patch, {
220
+ override: entry.override !== undefined,
221
+ }));
218
222
  const listeners = new Set();
219
223
  const emitChange = () => {
220
224
  for (const listener of listeners)
@@ -259,6 +263,11 @@ export function createMcpExtension(options = {}) {
259
263
  const serverTools = new Map();
260
264
  /** Last definition registered under each tool name, to re-register withdrawn tools as hidden. */
261
265
  const definitions = new Map();
266
+ // A resumed session renders calls to MCP tools before their server connected, if it ever does.
267
+ pi.registerToolRenderer((toolName, next) => {
268
+ const match = /^mcp__(.+?)__(.+)$/.exec(toolName);
269
+ return next() ?? (match ? createMcpToolRenderers(`${match[1]}/${match[2]}`) : undefined);
270
+ });
262
271
  const registerTools = (connection) => {
263
272
  const server = connection.entry.name;
264
273
  const entry = findServer(server)?.entry ?? connection.entry;
@@ -481,18 +490,20 @@ export function createMcpExtension(options = {}) {
481
490
  };
482
491
  /**
483
492
  * Save a config change; returns an error message when the file could not be updated. Changes to
484
- * registered servers only apply to the current session.
493
+ * registered servers only apply to the current session. `inProject` adds a project override.
485
494
  */
486
- const saveConfig = (server, patch) => {
487
- if (server.entry.scope !== "extension") {
495
+ const saveConfig = (server, patch, inProject = false) => {
496
+ const override = inProject ? projectConfig : server.entry.override;
497
+ const entry = override ? { ...server.entry, override } : server.entry;
498
+ if (entry.scope !== "extension") {
488
499
  try {
489
- updateConfig(server.entry, patch);
500
+ updateConfig(entry, patch);
490
501
  }
491
502
  catch (error) {
492
- return `Could not update ${server.entry.source}: ${errorMessage(error)}`;
503
+ return `Could not update ${entry.override ?? entry.source}: ${errorMessage(error)}`;
493
504
  }
494
505
  }
495
- server.entry = { ...server.entry, config: { ...server.entry.config, ...patch } };
506
+ server.entry = { ...entry, config: { ...entry.config, ...patch } };
496
507
  return undefined;
497
508
  };
498
509
  const signIn = async (server, prompt) => {
@@ -547,8 +558,8 @@ export function createMcpExtension(options = {}) {
547
558
  }
548
559
  };
549
560
  /** Returns an error message when the config could not be saved; connection errors show in the state. */
550
- const setEnabled = async (server, enabled) => {
551
- const failed = saveConfig(server, { enabled });
561
+ const setEnabled = async (server, enabled, inProject = false) => {
562
+ const failed = saveConfig(server, { enabled }, inProject);
552
563
  if (failed)
553
564
  return failed;
554
565
  if (!enabled) {
@@ -594,7 +605,7 @@ export function createMcpExtension(options = {}) {
594
605
  .map((server) => ({
595
606
  value: server.entry.name,
596
607
  label: server.entry.name,
597
- description: `${describeState(server)} · ${exposureOf(server.entry)} · ${server.entry.scope ?? server.entry.source}`,
608
+ description: `${describeState(server)} · ${exposureOf(server.entry)} · ${server.entry.override ? "global, project override" : (server.entry.scope ?? server.entry.source)}`,
598
609
  })),
599
610
  empty: `No MCP servers configured. Add them to ${resolve(getAgentDir(), "mcp.json")} or .pi/mcp.json.`,
600
611
  confirmLabel: "manage",
@@ -614,12 +625,20 @@ export function createMcpExtension(options = {}) {
614
625
  const { entry, connection } = server;
615
626
  const saved = entry.scope === "extension"
616
627
  ? "for this session"
617
- : entry.scope
618
- ? `saved to the ${entry.scope} mcp.json`
619
- : "saved to mcp.json";
628
+ : entry.override
629
+ ? "saved to the project mcp.json"
630
+ : entry.scope
631
+ ? `saved to the ${entry.scope} mcp.json`
632
+ : "saved to mcp.json";
633
+ // Global servers without an override can be turned on or off for the trusted project alone.
634
+ const inProject = entry.scope === "global" && !entry.override && projectConfig !== undefined;
635
+ const inProjectSaved = "saved to the project mcp.json";
620
636
  const items = [];
621
637
  if (!isEnabled(server)) {
622
638
  items.push({ value: "enable", label: "Enable", description: saved });
639
+ if (inProject) {
640
+ items.push({ value: "enable-project", label: "Enable in this project", description: inProjectSaved });
641
+ }
623
642
  }
624
643
  else {
625
644
  const state = connection?.state;
@@ -636,10 +655,14 @@ export function createMcpExtension(options = {}) {
636
655
  }
637
656
  items.push({ value: "exposure", label: "Exposure", description: exposureOf(entry) });
638
657
  items.push({ value: "disable", label: "Disable", description: saved });
658
+ if (inProject) {
659
+ items.push({ value: "disable-project", label: "Disable in this project", description: inProjectSaved });
660
+ }
639
661
  }
640
662
  const details = [
641
663
  describeTransport(entry),
642
664
  `${entry.scope ?? "config"}: ${entry.source}`,
665
+ ...(entry.override ? [`project override: ${entry.override}`] : []),
643
666
  `State: ${describeState(server, false)}`,
644
667
  ];
645
668
  const error = [server.message, connection?.state === "connected" ? undefined : connection?.error]
@@ -681,7 +704,7 @@ export function createMcpExtension(options = {}) {
681
704
  title: `Exposure of ${server.entry.name}`,
682
705
  details: server.entry.scope === "extension"
683
706
  ? `Applies to this session; the server is registered by ${server.entry.source}.`
684
- : `Saved to ${server.entry.source}.`,
707
+ : `Saved to ${server.entry.override ?? server.entry.source}.`,
685
708
  items: Object.keys(EXPOSURE_DESCRIPTIONS).map((exposure) => ({
686
709
  value: exposure,
687
710
  label: `${exposure === current ? "✓ " : " "}${exposure}`,
@@ -695,27 +718,30 @@ export function createMcpExtension(options = {}) {
695
718
  return undefined;
696
719
  return setExposure(server, choice);
697
720
  };
721
+ /** Sign in with the manager view's sign-in screen, which shows the URL with a copy key. */
722
+ const signInWithUi = (ui, server) => {
723
+ const title = `Sign in to ${server.entry.name}`;
724
+ let authorizationUrl = "";
725
+ ui.status(title, "Contacting the authorization server…");
726
+ return signIn(server, {
727
+ showAuthorizationUrl: (url) => {
728
+ authorizationUrl = url.href;
729
+ openUrl(url.href);
730
+ },
731
+ promptForRedirectUrl: async (signal) => {
732
+ const value = await ui.redirectUrl(title, authorizationUrl, signal);
733
+ ui.status(title, "Connecting…");
734
+ return value;
735
+ },
736
+ });
737
+ };
698
738
  const runAction = async (ui, ctx, server, action) => {
699
739
  const { name } = server.entry;
700
740
  let message;
701
741
  switch (action) {
702
- case "signin": {
703
- const title = `Sign in to ${name}`;
704
- let authorizationUrl = "";
705
- ui.status(title, "Contacting the authorization server…");
706
- message = await signIn(server, {
707
- showAuthorizationUrl: (url) => {
708
- authorizationUrl = url.href;
709
- openUrl(url.href);
710
- },
711
- promptForRedirectUrl: async (signal) => {
712
- const value = await ui.redirectUrl(title, authorizationUrl, signal);
713
- ui.status(title, "Connecting…");
714
- return value;
715
- },
716
- });
742
+ case "signin":
743
+ message = await signInWithUi(ui, server);
717
744
  break;
718
- }
719
745
  case "reconnect":
720
746
  // A failure shows as the connection's state and error.
721
747
  ui.status(`MCP server ${name}`, "Reconnecting…");
@@ -732,9 +758,13 @@ export function createMcpExtension(options = {}) {
732
758
  break;
733
759
  case "enable":
734
760
  case "disable":
735
- ui.status(`MCP server ${name}`, action === "enable" ? "Connecting…" : "Disconnecting…");
736
- message = await setEnabled(server, action === "enable");
761
+ case "enable-project":
762
+ case "disable-project": {
763
+ const enable = action.startsWith("enable");
764
+ ui.status(`MCP server ${name}`, enable ? "Connecting…" : "Disconnecting…");
765
+ message = await setEnabled(server, enable, action.endsWith("-project"));
737
766
  break;
767
+ }
738
768
  }
739
769
  server.message = message;
740
770
  ensureDiscoveryActive(ctx);
@@ -819,17 +849,21 @@ export function createMcpExtension(options = {}) {
819
849
  ctx.ui.notify(`Signing in to MCP server "${name}" requires interactive mode.`, "error");
820
850
  return;
821
851
  }
822
- const failure = await signIn(server, {
823
- showAuthorizationUrl: (url) => {
824
- // Long URLs wrap, which some terminals cannot open; a short link line stays on one line.
825
- const lines = ctx.mode === "tui"
826
- ? `${hyperlink(url.href, url.href)}\n${hyperlink(process.platform === "darwin" ? "Cmd+click to open" : "Ctrl+click to open", url.href)}`
827
- : url.href;
828
- ctx.ui.notify(`Sign in to MCP server "${name}" in your browser:\n${lines}`, "info");
829
- openUrl(url.href);
830
- },
831
- promptForRedirectUrl: (signal) => ctx.ui.input(`Waiting for sign-in to "${name}". If the browser cannot reach this machine, paste the URL it was redirected to.`, "http://127.0.0.1:.../callback?code=...", { signal }),
832
- });
852
+ let failure;
853
+ if (ctx.mode === "tui") {
854
+ await showMcpManager(ctx, async (ui) => {
855
+ failure = await signInWithUi(ui, server);
856
+ });
857
+ }
858
+ else {
859
+ failure = await signIn(server, {
860
+ showAuthorizationUrl: (url) => {
861
+ ctx.ui.notify(`Sign in to MCP server "${name}" in your browser:\n${url.href}`, "info");
862
+ openUrl(url.href);
863
+ },
864
+ promptForRedirectUrl: (signal) => ctx.ui.input(`Waiting for sign-in to "${name}". If the browser cannot reach this machine, paste the URL it was redirected to.`, "http://127.0.0.1:.../callback?code=...", { signal }),
865
+ });
866
+ }
833
867
  if (failure) {
834
868
  ctx.ui.notify(failure, failure === "Sign-in cancelled." ? "info" : "error");
835
869
  return;
@@ -840,6 +874,7 @@ export function createMcpExtension(options = {}) {
840
874
  pi.on("session_start", (_event, ctx) => {
841
875
  const loaded = (options.loadConfig ?? defaultLoadConfig)(ctx);
842
876
  configErrors = loaded.errors;
877
+ projectConfig = loaded.projectConfig;
843
878
  autoEnableCodemode = loaded.autoEnableCodemode ?? true;
844
879
  warnedUnreachable = false;
845
880
  waitedForStartup = false;