@astralyn/pi 1.0.0 → 1.0.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 (197) hide show
  1. package/CHANGELOG.md +34 -0
  2. package/dist/bundle/chunks/{anthropic-messages-CG2BSDQS.js → anthropic-messages-YET4T7BO.js} +3 -3
  3. package/dist/bundle/chunks/azure-openai-responses-SBLL5YN3.js +2 -0
  4. package/dist/bundle/chunks/bedrock-converse-stream.js +2 -2
  5. package/dist/bundle/chunks/{chunk-HESRDUKO.js → chunk-5RBGZ6YW.js} +89 -63
  6. package/dist/bundle/chunks/{chunk-PFZKRUMO.js → chunk-IZ3S3GDX.js} +1 -1
  7. package/dist/bundle/chunks/{chunk-SGLYRVQL.js → chunk-MWM24AOB.js} +1 -1
  8. package/dist/bundle/chunks/{chunk-6UFFVA7M.js → chunk-NY3CWK44.js} +1 -1
  9. package/dist/bundle/chunks/chunk-SVJ7OGEB.js +2 -0
  10. package/dist/bundle/chunks/chunk-XDYM2567.js +20 -0
  11. package/dist/bundle/chunks/{cloudflare-workers-ai-system-one-YB7XPPP4.js → cloudflare-workers-ai-system-one-QI46LUZ6.js} +1 -1
  12. package/dist/bundle/chunks/codemode-worker.js +24 -3
  13. package/dist/bundle/chunks/{google-generative-ai-V5ZM5MCL.js → google-generative-ai-YTZCSHQN.js} +1 -1
  14. package/dist/bundle/chunks/{google-vertex-22THOFP5.js → google-vertex-OTFZJJXQ.js} +1 -1
  15. package/dist/bundle/chunks/{mistral-conversations-WHSCJJWP.js → mistral-conversations-ELH4V4TY.js} +1 -1
  16. package/dist/bundle/chunks/node-USQQ7C6M.js +16 -0
  17. package/dist/bundle/chunks/openai-chatgpt.js +1 -1
  18. package/dist/bundle/chunks/{openai-codex-responses-N7GDPBPP.js → openai-codex-responses-OLVTU4UA.js} +1 -1
  19. package/dist/bundle/chunks/openai-completions-53M2KJ67.js +7 -0
  20. package/dist/bundle/chunks/openai-responses-4ABDEL4Z.js +3 -0
  21. package/dist/bundle/chunks/{virtual-modules-4RQ2L6W4.js → virtual-modules-EDIGEIG6.js} +1 -1
  22. package/dist/bundle/cli.js +1 -1
  23. package/dist/bundle/index.js +1 -1
  24. package/dist/bundle/rpc-entry.js +1 -1
  25. package/dist/cli/args.d.ts.map +1 -1
  26. package/dist/cli/args.js +4 -1
  27. package/dist/cli/args.js.map +1 -1
  28. package/dist/config.d.ts.map +1 -1
  29. package/dist/config.js +3 -0
  30. package/dist/config.js.map +1 -1
  31. package/dist/core/agent-session.d.ts.map +1 -1
  32. package/dist/core/agent-session.js +1 -1
  33. package/dist/core/agent-session.js.map +1 -1
  34. package/dist/core/export-html/tool-renderer.d.ts +3 -3
  35. package/dist/core/export-html/tool-renderer.d.ts.map +1 -1
  36. package/dist/core/export-html/tool-renderer.js +3 -3
  37. package/dist/core/export-html/tool-renderer.js.map +1 -1
  38. package/dist/core/extensions/index.d.ts +1 -1
  39. package/dist/core/extensions/index.d.ts.map +1 -1
  40. package/dist/core/extensions/index.js.map +1 -1
  41. package/dist/core/extensions/loader.d.ts.map +1 -1
  42. package/dist/core/extensions/loader.js +5 -0
  43. package/dist/core/extensions/loader.js.map +1 -1
  44. package/dist/core/extensions/runner.d.ts +3 -1
  45. package/dist/core/extensions/runner.d.ts.map +1 -1
  46. package/dist/core/extensions/runner.js +6 -0
  47. package/dist/core/extensions/runner.js.map +1 -1
  48. package/dist/core/extensions/types.d.ts +9 -0
  49. package/dist/core/extensions/types.d.ts.map +1 -1
  50. package/dist/core/extensions/types.js.map +1 -1
  51. package/dist/core/mcp-servers.d.ts +6 -0
  52. package/dist/core/mcp-servers.d.ts.map +1 -1
  53. package/dist/core/mcp-servers.js +11 -0
  54. package/dist/core/mcp-servers.js.map +1 -1
  55. package/dist/core/model-config.d.ts +36 -0
  56. package/dist/core/model-config.d.ts.map +1 -1
  57. package/dist/core/model-config.js +14 -2
  58. package/dist/core/model-config.js.map +1 -1
  59. package/dist/core/model-resolver.js +1 -1
  60. package/dist/core/model-resolver.js.map +1 -1
  61. package/dist/core/provider-composer.d.ts +2 -1
  62. package/dist/core/provider-composer.d.ts.map +1 -1
  63. package/dist/core/provider-composer.js +13 -0
  64. package/dist/core/provider-composer.js.map +1 -1
  65. package/dist/core/tools/renderers/bash.d.ts.map +1 -1
  66. package/dist/core/tools/renderers/bash.js +4 -3
  67. package/dist/core/tools/renderers/bash.js.map +1 -1
  68. package/dist/core/tools/renderers/index.d.ts +2 -2
  69. package/dist/core/tools/renderers/index.d.ts.map +1 -1
  70. package/dist/core/tools/renderers/index.js.map +1 -1
  71. package/dist/core/tools/shell-tool.d.ts.map +1 -1
  72. package/dist/core/tools/shell-tool.js +9 -2
  73. package/dist/core/tools/shell-tool.js.map +1 -1
  74. package/dist/extensions/deepwiki/execute.d.ts +0 -3
  75. package/dist/extensions/deepwiki/execute.d.ts.map +1 -1
  76. package/dist/extensions/deepwiki/execute.js.map +1 -1
  77. package/dist/extensions/deepwiki/render.d.ts.map +1 -1
  78. package/dist/extensions/deepwiki/render.js +0 -5
  79. package/dist/extensions/deepwiki/render.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/extensions/question/render.d.ts.map +1 -1
  106. package/dist/extensions/question/render.js +3 -7
  107. package/dist/extensions/question/render.js.map +1 -1
  108. package/dist/index.d.ts +1 -1
  109. package/dist/index.d.ts.map +1 -1
  110. package/dist/index.js.map +1 -1
  111. package/dist/modes/interactive/components/armin.d.ts +3 -0
  112. package/dist/modes/interactive/components/armin.d.ts.map +1 -1
  113. package/dist/modes/interactive/components/armin.js +7 -5
  114. package/dist/modes/interactive/components/armin.js.map +1 -1
  115. package/dist/modes/interactive/components/auth-url.d.ts +14 -0
  116. package/dist/modes/interactive/components/auth-url.d.ts.map +1 -0
  117. package/dist/modes/interactive/components/auth-url.js +34 -0
  118. package/dist/modes/interactive/components/auth-url.js.map +1 -0
  119. package/dist/modes/interactive/components/easter-egg-3d.d.ts +104 -0
  120. package/dist/modes/interactive/components/easter-egg-3d.d.ts.map +1 -0
  121. package/dist/modes/interactive/components/{pi-logo-animation.js → easter-egg-3d.js} +121 -74
  122. package/dist/modes/interactive/components/easter-egg-3d.js.map +1 -0
  123. package/dist/modes/interactive/components/easter-egg-3d.lazy.d.ts +6 -0
  124. package/dist/modes/interactive/components/easter-egg-3d.lazy.d.ts.map +1 -0
  125. package/dist/modes/interactive/components/easter-egg-3d.lazy.js +24 -0
  126. package/dist/modes/interactive/components/easter-egg-3d.lazy.js.map +1 -0
  127. package/dist/modes/interactive/components/index.d.ts +0 -1
  128. package/dist/modes/interactive/components/index.d.ts.map +1 -1
  129. package/dist/modes/interactive/components/index.js +0 -1
  130. package/dist/modes/interactive/components/index.js.map +1 -1
  131. package/dist/modes/interactive/components/login-dialog.d.ts +2 -0
  132. package/dist/modes/interactive/components/login-dialog.d.ts.map +1 -1
  133. package/dist/modes/interactive/components/login-dialog.js +9 -5
  134. package/dist/modes/interactive/components/login-dialog.js.map +1 -1
  135. package/dist/modes/interactive/interactive-mode.d.ts +2 -2
  136. package/dist/modes/interactive/interactive-mode.d.ts.map +1 -1
  137. package/dist/modes/interactive/interactive-mode.js +34 -18
  138. package/dist/modes/interactive/interactive-mode.js.map +1 -1
  139. package/dist/modes/interactive/tasks/index.d.ts.map +1 -1
  140. package/dist/modes/interactive/tasks/index.js +11 -3
  141. package/dist/modes/interactive/tasks/index.js.map +1 -1
  142. package/dist/modes/interactive/tasks/layout.js +4 -5
  143. package/dist/modes/interactive/tasks/layout.js.map +1 -1
  144. package/dist/modes/interactive/tasks/manager.d.ts.map +1 -1
  145. package/dist/modes/interactive/tasks/manager.js +2 -0
  146. package/dist/modes/interactive/tasks/manager.js.map +1 -1
  147. package/dist/modes/interactive/tool-view/chat.d.ts +2 -3
  148. package/dist/modes/interactive/tool-view/chat.d.ts.map +1 -1
  149. package/dist/modes/interactive/tool-view/chat.js +18 -5
  150. package/dist/modes/interactive/tool-view/chat.js.map +1 -1
  151. package/dist/modes/interactive/tool-view/style.d.ts +2 -1
  152. package/dist/modes/interactive/tool-view/style.d.ts.map +1 -1
  153. package/dist/modes/interactive/tool-view/style.js +2 -2
  154. package/dist/modes/interactive/tool-view/style.js.map +1 -1
  155. package/dist/modes/interactive/tool-view/tool-execution.d.ts +4 -19
  156. package/dist/modes/interactive/tool-view/tool-execution.d.ts.map +1 -1
  157. package/dist/modes/interactive/tool-view/tool-execution.js +23 -67
  158. package/dist/modes/interactive/tool-view/tool-execution.js.map +1 -1
  159. package/dist/utils/image-convert.d.ts +12 -0
  160. package/dist/utils/image-convert.d.ts.map +1 -1
  161. package/dist/utils/image-convert.js +45 -6
  162. package/dist/utils/image-convert.js.map +1 -1
  163. package/docs/bundled/tasks.md +5 -3
  164. package/docs/bundled/tool-presentation.md +3 -2
  165. package/docs/codemode.md +1 -1
  166. package/docs/extensions.md +4 -0
  167. package/docs/keybindings.md +1 -1
  168. package/docs/mcp.md +23 -1
  169. package/docs/models.md +30 -3
  170. package/examples/extensions/custom-provider-anthropic/package-lock.json +2 -2
  171. package/examples/extensions/custom-provider-anthropic/package.json +1 -1
  172. package/examples/extensions/custom-provider-gitlab-duo/package.json +1 -1
  173. package/examples/extensions/gondolin/package-lock.json +2 -2
  174. package/examples/extensions/gondolin/package.json +1 -1
  175. package/examples/extensions/sandbox/package-lock.json +2 -2
  176. package/examples/extensions/sandbox/package.json +1 -1
  177. package/examples/extensions/with-deps/package-lock.json +2 -2
  178. package/examples/extensions/with-deps/package.json +1 -1
  179. package/npm-shrinkwrap.json +58 -58
  180. package/package.json +11 -11
  181. package/dist/bundle/chunks/azure-openai-responses-PBA4QKCM.js +0 -2
  182. package/dist/bundle/chunks/chunk-PJVFYVHE.js +0 -42
  183. package/dist/bundle/chunks/chunk-Z2RKSI3O.js +0 -2
  184. package/dist/bundle/chunks/node-CXWYTK2I.js +0 -16
  185. package/dist/bundle/chunks/openai-completions-RGGQK5UW.js +0 -7
  186. package/dist/bundle/chunks/openai-responses-3ZLD5JYI.js +0 -3
  187. package/dist/modes/interactive/components/daxnuts.d.ts +0 -23
  188. package/dist/modes/interactive/components/daxnuts.d.ts.map +0 -1
  189. package/dist/modes/interactive/components/daxnuts.js +0 -138
  190. package/dist/modes/interactive/components/daxnuts.js.map +0 -1
  191. package/dist/modes/interactive/components/pi-logo-animation.d.ts +0 -68
  192. package/dist/modes/interactive/components/pi-logo-animation.d.ts.map +0 -1
  193. package/dist/modes/interactive/components/pi-logo-animation.js.map +0 -1
  194. package/dist/modes/interactive/components/pi-logo-animation.lazy.d.ts +0 -7
  195. package/dist/modes/interactive/components/pi-logo-animation.lazy.d.ts.map +0 -1
  196. package/dist/modes/interactive/components/pi-logo-animation.lazy.js +0 -12
  197. package/dist/modes/interactive/components/pi-logo-animation.lazy.js.map +0 -1
@@ -26,14 +26,13 @@
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";
33
32
  import { getMcpToolExposure, loadMcpConfig, updateMcpServerConfig, } from "./config.js";
34
33
  import { createMcpResourceToolDefinitions, LIST_MCP_RESOURCE_TEMPLATES_TOOL, LIST_MCP_RESOURCES_TOOL, READ_MCP_RESOURCE_TOOL, } from "./resources.js";
35
34
  import { loadMcpRuntime } from "./runtime.lazy.js";
36
- import { createMcpToolDefinition, createMcpToolName } from "./tools.js";
35
+ import { createMcpToolDefinition, createMcpToolName, createMcpToolRenderers } from "./tools.js";
37
36
  import { showMcpManager } from "./ui.js";
38
37
  const DEFAULT_STARTUP_WAIT_MS = 10_000;
39
38
  const CODEMODE_TOOL_NAME = "codemode";
@@ -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;
@@ -492,18 +501,20 @@ export function createMcpExtension(options = {}) {
492
501
  };
493
502
  /**
494
503
  * Save a config change; returns an error message when the file could not be updated. Changes to
495
- * registered servers only apply to the current session.
504
+ * registered servers only apply to the current session. `inProject` adds a project override.
496
505
  */
497
- const saveConfig = (server, patch) => {
498
- if (server.entry.scope !== "extension") {
506
+ const saveConfig = (server, patch, inProject = false) => {
507
+ const override = inProject ? projectConfig : server.entry.override;
508
+ const entry = override ? { ...server.entry, override } : server.entry;
509
+ if (entry.scope !== "extension") {
499
510
  try {
500
- updateConfig(server.entry, patch);
511
+ updateConfig(entry, patch);
501
512
  }
502
513
  catch (error) {
503
- return `Could not update ${server.entry.source}: ${errorMessage(error)}`;
514
+ return `Could not update ${entry.override ?? entry.source}: ${errorMessage(error)}`;
504
515
  }
505
516
  }
506
- server.entry = { ...server.entry, config: { ...server.entry.config, ...patch } };
517
+ server.entry = { ...entry, config: { ...entry.config, ...patch } };
507
518
  return undefined;
508
519
  };
509
520
  const signIn = async (server, prompt) => {
@@ -558,8 +569,8 @@ export function createMcpExtension(options = {}) {
558
569
  }
559
570
  };
560
571
  /** Returns an error message when the config could not be saved; connection errors show in the state. */
561
- const setEnabled = async (server, enabled) => {
562
- const failed = saveConfig(server, { enabled });
572
+ const setEnabled = async (server, enabled, inProject = false) => {
573
+ const failed = saveConfig(server, { enabled }, inProject);
563
574
  if (failed)
564
575
  return failed;
565
576
  if (!enabled) {
@@ -605,7 +616,7 @@ export function createMcpExtension(options = {}) {
605
616
  .map((server) => ({
606
617
  value: server.entry.name,
607
618
  label: server.entry.name,
608
- description: `${describeState(server)} · ${exposureOf(server.entry)} · ${server.entry.scope ?? server.entry.source}`,
619
+ description: `${describeState(server)} · ${exposureOf(server.entry)} · ${server.entry.override ? "global, project override" : (server.entry.scope ?? server.entry.source)}`,
609
620
  })),
610
621
  empty: `No MCP servers configured. Add them to ${resolve(getAgentDir(), "mcp.json")} or .pi/mcp.json.`,
611
622
  confirmLabel: "manage",
@@ -625,12 +636,20 @@ export function createMcpExtension(options = {}) {
625
636
  const { entry, connection } = server;
626
637
  const saved = entry.scope === "extension"
627
638
  ? "for this session"
628
- : entry.scope
629
- ? `saved to the ${entry.scope} mcp.json`
630
- : "saved to mcp.json";
639
+ : entry.override
640
+ ? "saved to the project mcp.json"
641
+ : entry.scope
642
+ ? `saved to the ${entry.scope} mcp.json`
643
+ : "saved to mcp.json";
644
+ // Global servers without an override can be turned on or off for the trusted project alone.
645
+ const inProject = entry.scope === "global" && !entry.override && projectConfig !== undefined;
646
+ const inProjectSaved = "saved to the project mcp.json";
631
647
  const items = [];
632
648
  if (!isEnabled(server)) {
633
649
  items.push({ value: "enable", label: "Enable", description: saved });
650
+ if (inProject) {
651
+ items.push({ value: "enable-project", label: "Enable in this project", description: inProjectSaved });
652
+ }
634
653
  }
635
654
  else {
636
655
  const state = connection?.state;
@@ -647,10 +666,14 @@ export function createMcpExtension(options = {}) {
647
666
  }
648
667
  items.push({ value: "exposure", label: "Exposure", description: exposureOf(entry) });
649
668
  items.push({ value: "disable", label: "Disable", description: saved });
669
+ if (inProject) {
670
+ items.push({ value: "disable-project", label: "Disable in this project", description: inProjectSaved });
671
+ }
650
672
  }
651
673
  const details = [
652
674
  describeTransport(entry),
653
675
  `${entry.scope ?? "config"}: ${entry.source}`,
676
+ ...(entry.override ? [`project override: ${entry.override}`] : []),
654
677
  `State: ${describeState(server, false)}`,
655
678
  ];
656
679
  const error = [server.message, connection?.state === "connected" ? undefined : connection?.error]
@@ -692,7 +715,7 @@ export function createMcpExtension(options = {}) {
692
715
  title: `Exposure of ${server.entry.name}`,
693
716
  details: server.entry.scope === "extension"
694
717
  ? `Applies to this session; the server is registered by ${server.entry.source}.`
695
- : `Saved to ${server.entry.source}.`,
718
+ : `Saved to ${server.entry.override ?? server.entry.source}.`,
696
719
  items: Object.keys(EXPOSURE_DESCRIPTIONS).map((exposure) => ({
697
720
  value: exposure,
698
721
  label: `${exposure === current ? "✓ " : " "}${exposure}`,
@@ -706,27 +729,30 @@ export function createMcpExtension(options = {}) {
706
729
  return undefined;
707
730
  return setExposure(server, choice);
708
731
  };
732
+ /** Sign in with the manager view's sign-in screen, which shows the URL with a copy key. */
733
+ const signInWithUi = (ui, server) => {
734
+ const title = `Sign in to ${server.entry.name}`;
735
+ let authorizationUrl = "";
736
+ ui.status(title, "Contacting the authorization server…");
737
+ return signIn(server, {
738
+ showAuthorizationUrl: (url) => {
739
+ authorizationUrl = url.href;
740
+ openUrl(url.href);
741
+ },
742
+ promptForRedirectUrl: async (signal) => {
743
+ const value = await ui.redirectUrl(title, authorizationUrl, signal);
744
+ ui.status(title, "Connecting…");
745
+ return value;
746
+ },
747
+ });
748
+ };
709
749
  const runAction = async (ui, ctx, server, action) => {
710
750
  const { name } = server.entry;
711
751
  let message;
712
752
  switch (action) {
713
- case "signin": {
714
- const title = `Sign in to ${name}`;
715
- let authorizationUrl = "";
716
- ui.status(title, "Contacting the authorization server…");
717
- message = await signIn(server, {
718
- showAuthorizationUrl: (url) => {
719
- authorizationUrl = url.href;
720
- openUrl(url.href);
721
- },
722
- promptForRedirectUrl: async (signal) => {
723
- const value = await ui.redirectUrl(title, authorizationUrl, signal);
724
- ui.status(title, "Connecting…");
725
- return value;
726
- },
727
- });
753
+ case "signin":
754
+ message = await signInWithUi(ui, server);
728
755
  break;
729
- }
730
756
  case "reconnect":
731
757
  // A failure shows as the connection's state and error.
732
758
  ui.status(`MCP server ${name}`, "Reconnecting…");
@@ -743,9 +769,13 @@ export function createMcpExtension(options = {}) {
743
769
  break;
744
770
  case "enable":
745
771
  case "disable":
746
- ui.status(`MCP server ${name}`, action === "enable" ? "Connecting…" : "Disconnecting…");
747
- message = await setEnabled(server, action === "enable");
772
+ case "enable-project":
773
+ case "disable-project": {
774
+ const enable = action.startsWith("enable");
775
+ ui.status(`MCP server ${name}`, enable ? "Connecting…" : "Disconnecting…");
776
+ message = await setEnabled(server, enable, action.endsWith("-project"));
748
777
  break;
778
+ }
749
779
  }
750
780
  server.message = message;
751
781
  ensureDiscoveryActive(ctx);
@@ -830,17 +860,21 @@ export function createMcpExtension(options = {}) {
830
860
  ctx.ui.notify(`Signing in to MCP server "${name}" requires interactive mode.`, "error");
831
861
  return;
832
862
  }
833
- const failure = await signIn(server, {
834
- showAuthorizationUrl: (url) => {
835
- // Long URLs wrap, which some terminals cannot open; a short link line stays on one line.
836
- const lines = ctx.mode === "tui"
837
- ? `${hyperlink(url.href, url.href)}\n${hyperlink(process.platform === "darwin" ? "Cmd+click to open" : "Ctrl+click to open", url.href)}`
838
- : url.href;
839
- ctx.ui.notify(`Sign in to MCP server "${name}" in your browser:\n${lines}`, "info");
840
- openUrl(url.href);
841
- },
842
- 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 }),
843
- });
863
+ let failure;
864
+ if (ctx.mode === "tui") {
865
+ await showMcpManager(ctx, async (ui) => {
866
+ failure = await signInWithUi(ui, server);
867
+ });
868
+ }
869
+ else {
870
+ failure = await signIn(server, {
871
+ showAuthorizationUrl: (url) => {
872
+ ctx.ui.notify(`Sign in to MCP server "${name}" in your browser:\n${url.href}`, "info");
873
+ openUrl(url.href);
874
+ },
875
+ 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 }),
876
+ });
877
+ }
844
878
  if (failure) {
845
879
  ctx.ui.notify(failure, failure === "Sign-in cancelled." ? "info" : "error");
846
880
  return;
@@ -851,6 +885,7 @@ export function createMcpExtension(options = {}) {
851
885
  pi.on("session_start", (_event, ctx) => {
852
886
  const loaded = (options.loadConfig ?? defaultLoadConfig)(ctx);
853
887
  configErrors = loaded.errors;
888
+ projectConfig = loaded.projectConfig;
854
889
  autoEnableCodemode = loaded.autoEnableCodemode ?? true;
855
890
  warnedUnreachable = false;
856
891
  waitedForStartup = false;