@herbertgao/pi-extensions 2026.8.1 → 2026.8.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 (162) hide show
  1. package/README.md +5 -2
  2. package/node_modules/@czottmann/pi-automode/README.md +16 -2
  3. package/node_modules/@czottmann/pi-automode/docs/GLOSSARY.md +35 -0
  4. package/node_modules/@czottmann/pi-automode/docs/automode-classifier-flow.md +18 -9
  5. package/node_modules/@czottmann/pi-automode/docs/defaults.md +6 -2
  6. package/node_modules/@czottmann/pi-automode/examples/automode.local.json +6 -0
  7. package/node_modules/@czottmann/pi-automode/extensions/auto-mode/classifier.ts +11 -7
  8. package/node_modules/@czottmann/pi-automode/extensions/auto-mode/config.ts +100 -0
  9. package/node_modules/@czottmann/pi-automode/extensions/auto-mode/constants.ts +32 -0
  10. package/node_modules/@czottmann/pi-automode/extensions/auto-mode/extension.ts +78 -3
  11. package/node_modules/@czottmann/pi-automode/extensions/auto-mode/hard-deny.ts +16 -4
  12. package/node_modules/@czottmann/pi-automode/extensions/auto-mode/paths.ts +23 -1
  13. package/node_modules/@czottmann/pi-automode/extensions/auto-mode/permissions.ts +22 -1
  14. package/node_modules/@czottmann/pi-automode/extensions/auto-mode/types.ts +18 -2
  15. package/node_modules/@czottmann/pi-automode/package.json +4 -4
  16. package/node_modules/@dietrichgebert/ponytail/.opencode/command/ponytail-audit.md +5 -0
  17. package/node_modules/@dietrichgebert/ponytail/.opencode/command/ponytail-debt.md +5 -0
  18. package/node_modules/@dietrichgebert/ponytail/.opencode/command/ponytail-gain.md +5 -0
  19. package/node_modules/@dietrichgebert/ponytail/.opencode/command/ponytail-help.md +5 -0
  20. package/node_modules/@dietrichgebert/ponytail/.opencode/command/ponytail-review.md +5 -0
  21. package/node_modules/@dietrichgebert/ponytail/.opencode/command/ponytail.md +5 -0
  22. package/node_modules/@dietrichgebert/ponytail/.opencode/plugins/ponytail-frontmatter.cjs +23 -0
  23. package/node_modules/@dietrichgebert/ponytail/.opencode/plugins/ponytail.mjs +99 -0
  24. package/node_modules/@dietrichgebert/ponytail/.qoder/rules/ponytail.md +30 -0
  25. package/node_modules/@dietrichgebert/ponytail/.qoder-plugin/plugin.json +16 -0
  26. package/node_modules/@dietrichgebert/ponytail/AGENTS.md +32 -0
  27. package/node_modules/@dietrichgebert/ponytail/LICENSE +21 -0
  28. package/node_modules/@dietrichgebert/ponytail/README.es.md +298 -0
  29. package/node_modules/@dietrichgebert/ponytail/README.ko.md +315 -0
  30. package/node_modules/@dietrichgebert/ponytail/README.md +351 -0
  31. package/node_modules/@dietrichgebert/ponytail/assets/benchmark-3model.svg +21 -0
  32. package/node_modules/@dietrichgebert/ponytail/assets/benchmark-agentic.svg +62 -0
  33. package/node_modules/@dietrichgebert/ponytail/assets/logo-dark.png +0 -0
  34. package/node_modules/@dietrichgebert/ponytail/assets/logo-dark.svg +115 -0
  35. package/node_modules/@dietrichgebert/ponytail/assets/logo-greenpt-dark.svg +27 -0
  36. package/node_modules/@dietrichgebert/ponytail/assets/logo-greenpt.svg +27 -0
  37. package/node_modules/@dietrichgebert/ponytail/assets/logo.png +0 -0
  38. package/node_modules/@dietrichgebert/ponytail/assets/social-preview.png +0 -0
  39. package/node_modules/@dietrichgebert/ponytail/assets/waitlist-banner-es.png +0 -0
  40. package/node_modules/@dietrichgebert/ponytail/assets/waitlist-banner-ko.png +0 -0
  41. package/node_modules/@dietrichgebert/ponytail/assets/waitlist-banner.png +0 -0
  42. package/node_modules/@dietrichgebert/ponytail/hooks/claude-codex-hooks.json +44 -0
  43. package/node_modules/@dietrichgebert/ponytail/hooks/copilot-hooks.json +21 -0
  44. package/node_modules/@dietrichgebert/ponytail/hooks/ponytail-activate.js +96 -0
  45. package/node_modules/@dietrichgebert/ponytail/hooks/ponytail-config.js +169 -0
  46. package/node_modules/@dietrichgebert/ponytail/hooks/ponytail-instructions.js +98 -0
  47. package/node_modules/@dietrichgebert/ponytail/hooks/ponytail-mode-tracker.js +130 -0
  48. package/node_modules/@dietrichgebert/ponytail/hooks/ponytail-runtime.js +85 -0
  49. package/node_modules/@dietrichgebert/ponytail/hooks/ponytail-statusline.ps1 +24 -0
  50. package/node_modules/@dietrichgebert/ponytail/hooks/ponytail-statusline.sh +18 -0
  51. package/node_modules/@dietrichgebert/ponytail/hooks/ponytail-subagent.js +77 -0
  52. package/node_modules/@dietrichgebert/ponytail/hooks/qoder-hooks.json +26 -0
  53. package/node_modules/@dietrichgebert/ponytail/package.json +47 -0
  54. package/node_modules/@dietrichgebert/ponytail/pi-extension/index.js +211 -0
  55. package/node_modules/@dietrichgebert/ponytail/pi-extension/package.json +8 -0
  56. package/node_modules/@dietrichgebert/ponytail/scripts/uninstall.js +60 -0
  57. package/node_modules/@dietrichgebert/ponytail/skills/ponytail/SKILL.md +120 -0
  58. package/node_modules/@dietrichgebert/ponytail/skills/ponytail-audit/SKILL.md +41 -0
  59. package/node_modules/@dietrichgebert/ponytail/skills/ponytail-debt/SKILL.md +44 -0
  60. package/node_modules/@dietrichgebert/ponytail/skills/ponytail-gain/SKILL.md +50 -0
  61. package/node_modules/@dietrichgebert/ponytail/skills/ponytail-help/SKILL.md +71 -0
  62. package/node_modules/@dietrichgebert/ponytail/skills/ponytail-review/SKILL.md +57 -0
  63. package/node_modules/@herbertgao/pi-cc-extensions/README.en.md +1 -3
  64. package/node_modules/@herbertgao/pi-cc-extensions/README.md +1 -3
  65. package/node_modules/@herbertgao/pi-cc-extensions/extensions/config/panel.ts +10 -6
  66. package/node_modules/@herbertgao/pi-cc-extensions/extensions/feature/agent-summary.ts +6 -2
  67. package/node_modules/@herbertgao/pi-cc-extensions/extensions/feature/compact-thinking.ts +24 -83
  68. package/node_modules/@herbertgao/pi-cc-extensions/extensions/feature/context.ts +1 -1
  69. package/node_modules/@herbertgao/pi-cc-extensions/extensions/feature/markdown-enhance.ts +119 -0
  70. package/node_modules/@herbertgao/pi-cc-extensions/extensions/renderer/compact-mode.ts +73 -9
  71. package/node_modules/@herbertgao/pi-cc-extensions/extensions/renderer/index.ts +2 -2
  72. package/node_modules/@herbertgao/pi-cc-extensions/extensions/renderer/mouse-hover.ts +130 -0
  73. package/node_modules/@herbertgao/pi-cc-extensions/extensions/renderer/mouse-interaction.ts +65 -542
  74. package/node_modules/@herbertgao/pi-cc-extensions/extensions/renderer/mouse-layout.ts +160 -0
  75. package/node_modules/@herbertgao/pi-cc-extensions/extensions/renderer/mouse-packets.ts +143 -0
  76. package/node_modules/@herbertgao/pi-cc-extensions/extensions/renderer/mouse-scroll.ts +184 -0
  77. package/node_modules/@herbertgao/pi-cc-extensions/extensions/renderer/tool-diff/diff-renderer.ts +2 -2
  78. package/node_modules/@herbertgao/pi-cc-extensions/extensions/renderer/tool-grouping.ts +9 -2
  79. package/node_modules/@herbertgao/pi-cc-extensions/extensions/renderer/transcript-refresh.ts +91 -0
  80. package/node_modules/@herbertgao/pi-cc-extensions/extensions/utils/agent-summary.ts +1 -1
  81. package/node_modules/@herbertgao/pi-cc-extensions/package.json +3 -3
  82. package/node_modules/@herbertgao/pi-cc-extensions/themes/cc-dark.json +1 -0
  83. package/node_modules/@herbertgao/pi-cc-extensions/themes/cc-light.json +2 -2
  84. package/node_modules/@herbertgao/pi-stash/README.md +9 -9
  85. package/node_modules/@herbertgao/pi-stash/package.json +1 -1
  86. package/node_modules/@herbertgao/pi-stash/src/index.ts +2 -1
  87. package/node_modules/@herbertgao/pi-subagents/CHANGELOG.md +14 -0
  88. package/node_modules/@herbertgao/pi-subagents/README.md +6 -2
  89. package/node_modules/@herbertgao/pi-subagents/package.json +3 -3
  90. package/node_modules/@herbertgao/pi-subagents/src/custom-agents.ts +85 -11
  91. package/node_modules/@herbertgao/pi-subagents/src/index.ts +28 -4
  92. package/node_modules/@herbertgao/pi-subagents/src/settings.ts +12 -0
  93. package/node_modules/@herbertgao/pi-subagents/src/types.ts +2 -0
  94. package/node_modules/@narumitw/pi-btw/LICENSE +21 -0
  95. package/node_modules/@narumitw/pi-btw/README.md +210 -0
  96. package/node_modules/@narumitw/pi-btw/package.json +53 -0
  97. package/node_modules/@narumitw/pi-btw/src/bring-to-main.ts +632 -0
  98. package/node_modules/@narumitw/pi-btw/src/btw.ts +996 -0
  99. package/node_modules/@narumitw/pi-btw/src/fullscreen-ui.ts +339 -0
  100. package/node_modules/@narumitw/pi-btw/src/index.ts +1 -0
  101. package/node_modules/@narumitw/pi-btw/src/menu.ts +296 -0
  102. package/node_modules/@narumitw/pi-btw/src/settings.ts +237 -0
  103. package/node_modules/@narumitw/pi-btw/src/side-thread.ts +238 -0
  104. package/node_modules/@narumitw/pi-btw/src/text.ts +10 -0
  105. package/node_modules/@narumitw/pi-btw/src/transcript-pager.ts +620 -0
  106. package/node_modules/@pi-plugins/fast-mode/LICENSE +21 -0
  107. package/node_modules/@pi-plugins/fast-mode/README.md +92 -0
  108. package/node_modules/@pi-plugins/fast-mode/dist/index.d.mts +6 -0
  109. package/node_modules/@pi-plugins/fast-mode/dist/index.d.mts.map +1 -0
  110. package/node_modules/@pi-plugins/fast-mode/dist/index.mjs +2026 -0
  111. package/node_modules/@pi-plugins/fast-mode/dist/index.mjs.map +1 -0
  112. package/node_modules/@pi-plugins/fast-mode/package.json +73 -0
  113. package/node_modules/pi-mcp-adapter/CHANGELOG.md +59 -0
  114. package/node_modules/pi-mcp-adapter/README.md +62 -13
  115. package/node_modules/pi-mcp-adapter/agent-plugin-loader.ts +377 -0
  116. package/node_modules/pi-mcp-adapter/commands.ts +9 -7
  117. package/node_modules/pi-mcp-adapter/config.ts +110 -49
  118. package/node_modules/pi-mcp-adapter/direct-tools.ts +34 -19
  119. package/node_modules/pi-mcp-adapter/elicitation-handler.ts +37 -36
  120. package/node_modules/pi-mcp-adapter/errors.ts +21 -17
  121. package/node_modules/pi-mcp-adapter/host-html-template.ts +13 -7
  122. package/node_modules/pi-mcp-adapter/index.ts +37 -14
  123. package/node_modules/pi-mcp-adapter/init.ts +9 -7
  124. package/node_modules/pi-mcp-adapter/json-schema-validator.ts +2 -2
  125. package/node_modules/pi-mcp-adapter/lifecycle.ts +8 -8
  126. package/node_modules/pi-mcp-adapter/logger.ts +1 -1
  127. package/node_modules/pi-mcp-adapter/mcp-auth-flow.ts +36 -22
  128. package/node_modules/pi-mcp-adapter/mcp-auth.ts +120 -2
  129. package/node_modules/pi-mcp-adapter/mcp-code.ts +13 -11
  130. package/node_modules/pi-mcp-adapter/mcp-oauth-provider.ts +19 -13
  131. package/node_modules/pi-mcp-adapter/mcp-output-guard.ts +15 -11
  132. package/node_modules/pi-mcp-adapter/mcp-panel.ts +34 -15
  133. package/node_modules/pi-mcp-adapter/mcp-probe.ts +131 -34
  134. package/node_modules/pi-mcp-adapter/mcp-script-worker.mjs +2 -2
  135. package/node_modules/pi-mcp-adapter/mcp-setup-panel.ts +7 -4
  136. package/node_modules/pi-mcp-adapter/mcp-trace.ts +59 -64
  137. package/node_modules/pi-mcp-adapter/metadata-cache.ts +34 -26
  138. package/node_modules/pi-mcp-adapter/npx-resolver.ts +6 -4
  139. package/node_modules/pi-mcp-adapter/oauth-handler.ts +1 -1
  140. package/node_modules/pi-mcp-adapter/onboarding-state.ts +19 -11
  141. package/node_modules/pi-mcp-adapter/package.json +13 -8
  142. package/node_modules/pi-mcp-adapter/panel-keys.ts +20 -4
  143. package/node_modules/pi-mcp-adapter/prompts.ts +2 -2
  144. package/node_modules/pi-mcp-adapter/proxy-modes.ts +48 -11
  145. package/node_modules/pi-mcp-adapter/sampling-handler.ts +22 -15
  146. package/node_modules/pi-mcp-adapter/search-ranking.ts +2 -1
  147. package/node_modules/pi-mcp-adapter/server-manager.ts +165 -113
  148. package/node_modules/pi-mcp-adapter/session-recovery.ts +11 -12
  149. package/node_modules/pi-mcp-adapter/skills/mcp-scripting/SKILL.md +3 -3
  150. package/node_modules/pi-mcp-adapter/state.ts +3 -1
  151. package/node_modules/pi-mcp-adapter/tool-approval.ts +67 -4
  152. package/node_modules/pi-mcp-adapter/tool-metadata.ts +6 -5
  153. package/node_modules/pi-mcp-adapter/tool-result-renderer.ts +14 -2
  154. package/node_modules/pi-mcp-adapter/ts-shape.ts +9 -2
  155. package/node_modules/pi-mcp-adapter/types.ts +109 -22
  156. package/node_modules/pi-mcp-adapter/ui-app-bridge-helpers.ts +40 -0
  157. package/node_modules/pi-mcp-adapter/ui-resource-handler.ts +28 -19
  158. package/node_modules/pi-mcp-adapter/ui-server.ts +90 -58
  159. package/node_modules/pi-mcp-adapter/ui-session.ts +16 -14
  160. package/node_modules/pi-mcp-adapter/unix-socket-transport.ts +4 -4
  161. package/node_modules/pi-mcp-adapter/utils.ts +23 -9
  162. package/package.json +22 -7
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "pi-mcp-adapter",
3
- "version": "2.19.0",
3
+ "version": "2.21.2",
4
4
  "description": "MCP (Model Context Protocol) adapter extension for Pi coding agent",
5
5
  "type": "module",
6
6
  "types": "./index.ts",
@@ -25,6 +25,7 @@
25
25
  "pi-mcp-adapter": "cli.js"
26
26
  },
27
27
  "scripts": {
28
+ "typecheck": "tsc --noEmit",
28
29
  "test": "vitest run",
29
30
  "test:watch": "vitest",
30
31
  "test:coverage": "vitest run --coverage",
@@ -80,6 +81,7 @@
80
81
  "types.ts",
81
82
  "ui-stream-types.ts",
82
83
  "ui-tool-visibility.ts",
84
+ "ui-app-bridge-helpers.ts",
83
85
  "config.ts",
84
86
  "server-manager.ts",
85
87
  "unix-socket-transport.ts",
@@ -93,6 +95,7 @@
93
95
  "mcp-code.ts",
94
96
  "mcp-script-worker.mjs",
95
97
  "mcp-probe.ts",
98
+ "agent-plugin-loader.ts",
96
99
  "resource-tools.ts",
97
100
  "lifecycle.ts",
98
101
  "mcp-status.ts",
@@ -122,8 +125,9 @@
122
125
  "LICENSE"
123
126
  ],
124
127
  "dependencies": {
128
+ "@modelcontextprotocol/client": "2.0.0",
129
+ "@modelcontextprotocol/core": "2.0.0",
125
130
  "@modelcontextprotocol/ext-apps": "^1.2.2",
126
- "@modelcontextprotocol/sdk": "^1.30.0",
127
131
  "@napi-rs/keyring": "^1.3.0",
128
132
  "ajv": "^8.17.1",
129
133
  "ajv-formats": "^3.0.1",
@@ -135,7 +139,7 @@
135
139
  "zod": "^3.25.0 || ^4.0.0"
136
140
  },
137
141
  "peerDependencies": {
138
- "@earendil-works/pi-ai": "*",
142
+ "@earendil-works/pi-ai": "^0.84.1",
139
143
  "@earendil-works/pi-tui": "*",
140
144
  "typebox": "*",
141
145
  "zod": "^3.25.0 || ^4.0.0"
@@ -152,16 +156,17 @@
152
156
  }
153
157
  },
154
158
  "devDependencies": {
155
- "@earendil-works/pi-ai": "0.74.2",
156
- "@earendil-works/pi-coding-agent": "0.79.10",
157
- "@earendil-works/pi-tui": "0.74.2",
159
+ "@earendil-works/pi-ai": "0.84.1",
160
+ "@earendil-works/pi-coding-agent": "0.84.1",
161
+ "@earendil-works/pi-tui": "0.84.1",
158
162
  "@modelcontextprotocol/conformance": "0.1.16",
159
163
  "@types/bun": "^1.0.0",
160
- "@types/node": "^20.0.0",
164
+ "@types/cross-spawn": "6.0.6",
165
+ "@types/node": "20.19.43",
161
166
  "@types/open": "^6.2.1",
162
167
  "tsx": "^4.21.0",
163
168
  "typebox": "1.3.3",
164
- "typescript": "^5.0.0",
169
+ "typescript": "5.9.3",
165
170
  "vitest": "^3.0.0"
166
171
  }
167
172
  }
@@ -1,6 +1,6 @@
1
- import { matchesKey } from "@earendil-works/pi-tui";
1
+ import { matchesKey, type KeyId } from "@earendil-works/pi-tui";
2
2
 
3
- /** The `tui.select.*` keybinding ids the adapter panels resolve. */
3
+ /** The panel keybinding ids the adapter panels resolve through pi-tui. */
4
4
  export type PanelSelectKeybinding =
5
5
  | "tui.select.up"
6
6
  | "tui.select.down"
@@ -9,29 +9,45 @@ export type PanelSelectKeybinding =
9
9
  /** Structural subset of pi-tui's `KeybindingsManager` (which satisfies it). */
10
10
  export interface PanelKeybindings {
11
11
  matches(data: string, keybinding: PanelSelectKeybinding): boolean;
12
+ getUserBindings?(): Record<string, KeyId | KeyId[] | undefined>;
12
13
  }
13
14
 
14
15
  /**
15
- * Key matchers for list navigation: user's `tui.select.*` bindings when a
16
- * manager is provided, otherwise the previous hardcoded defaults.
16
+ * Key matchers for panel actions: user bindings when a manager is provided,
17
+ * otherwise the previous hardcoded defaults.
17
18
  */
18
19
  export interface PanelKeys {
19
20
  selectUp(data: string): boolean;
20
21
  selectDown(data: string): boolean;
21
22
  selectConfirm(data: string): boolean;
23
+ save(data: string): boolean;
24
+ saveLabel(): string | null;
25
+ }
26
+
27
+ function configuredSaveKeys(keybindings?: PanelKeybindings): { keys: KeyId[]; configured: boolean } {
28
+ const explicit = keybindings?.getUserBindings?.()["mcp.panel.save"];
29
+ if (explicit !== undefined) return { keys: Array.isArray(explicit) ? explicit : [explicit], configured: true };
30
+ return { keys: [], configured: false };
22
31
  }
23
32
 
24
33
  export function createPanelKeys(keybindings?: PanelKeybindings): PanelKeys {
34
+ const saveBinding = configuredSaveKeys(keybindings);
25
35
  if (keybindings) {
26
36
  return {
27
37
  selectUp: (data) => keybindings.matches(data, "tui.select.up"),
28
38
  selectDown: (data) => keybindings.matches(data, "tui.select.down"),
29
39
  selectConfirm: (data) => keybindings.matches(data, "tui.select.confirm"),
40
+ save: (data) => saveBinding.keys.length > 0
41
+ ? saveBinding.keys.some((key) => matchesKey(data, key))
42
+ : !saveBinding.configured && matchesKey(data, "ctrl+s"),
43
+ saveLabel: () => saveBinding.keys[0] ?? (saveBinding.configured ? null : "ctrl+s"),
30
44
  };
31
45
  }
32
46
  return {
33
47
  selectUp: (data) => matchesKey(data, "up"),
34
48
  selectDown: (data) => matchesKey(data, "down"),
35
49
  selectConfirm: (data) => matchesKey(data, "return"),
50
+ save: (data) => matchesKey(data, "ctrl+s"),
51
+ saveLabel: () => "ctrl+s",
36
52
  };
37
53
  }
@@ -2,7 +2,7 @@ import type { ExtensionAPI, ExtensionCommandContext } from "@earendil-works/pi-c
2
2
  import type {
3
3
  GetPromptResult,
4
4
  PromptMessage,
5
- } from "@modelcontextprotocol/sdk/types.js";
5
+ } from "@modelcontextprotocol/client";
6
6
  import type { McpExtensionState } from "./state.ts";
7
7
  import { isServerDisabled, type McpConfig, type PromptMetadata } from "./types.ts";
8
8
  import { formatPromptCommandName } from "./types.ts";
@@ -117,7 +117,7 @@ function findUnquotedEquals(token: string): number {
117
117
  }
118
118
 
119
119
  function stripQuotes(value: string): string {
120
- if (value.length >= 2 && (value.startsWith('"') || value.startsWith("'")) && value.endsWith(value[0])) {
120
+ if (value.length >= 2 && (value.startsWith('"') || value.startsWith("'")) && value.endsWith(value.charAt(0))) {
121
121
  return value.slice(1, -1);
122
122
  }
123
123
  return value;
@@ -1,5 +1,5 @@
1
1
  import type { AgentToolResult, ToolInfo } from "@earendil-works/pi-coding-agent";
2
- import { UrlElicitationRequiredError } from "@modelcontextprotocol/sdk/types.js";
2
+ import { UrlElicitationRequiredError, type Client } from "@modelcontextprotocol/client";
3
3
  import { createRequire } from "node:module";
4
4
  import type { McpExtensionState } from "./state.ts";
5
5
  import type { ToolMetadata, McpContent } from "./types.ts";
@@ -20,6 +20,7 @@ import { paginate, rankSuggestions, rankToolMatches } from "./search-ranking.ts"
20
20
  import { ensureToolCallApproved, isToolCallApprovalRequired } from "./tool-approval.ts";
21
21
 
22
22
  type ProxyToolResult = AgentToolResult<Record<string, unknown>>;
23
+ type ClientCallToolResult = Awaited<ReturnType<Client["callTool"]>>;
23
24
 
24
25
  const require = createRequire(import.meta.url);
25
26
  const MAX_REGEX_SEARCH_QUERY_LENGTH = 256;
@@ -524,10 +525,28 @@ export function executeSearch(
524
525
 
525
526
  const page = paginate(matches, offset, limit);
526
527
  if (page.total === 0) {
528
+ const connectingServers = server
529
+ ? state.config.mcpServers[server] && state.manager.isConnecting(server) ? [server] : []
530
+ : Object.keys(state.config.mcpServers)
531
+ .filter(name => !isServerDisabled(state.config.mcpServers[name]) && state.manager.isConnecting(name))
532
+ .sort((a, b) => a.localeCompare(b));
527
533
  const msg = server ? `No tools matching "${query}" in "${server}"` : `No tools matching "${query}"`;
534
+ const connectingMessage = connectingServers.length === 1
535
+ ? ` Server "${connectingServers[0]}" is still connecting; retry in a moment.`
536
+ : connectingServers.length > 1
537
+ ? ` Servers ${connectingServers.map(name => `"${name}"`).join(", ")} are still connecting; retry in a moment.`
538
+ : "";
528
539
  return {
529
- content: [{ type: "text" as const, text: msg }],
530
- details: { mode: "search", matches: [], count: 0, hasMore: false, nextOffset: null, query },
540
+ content: [{ type: "text" as const, text: `${msg}${connectingMessage}` }],
541
+ details: {
542
+ mode: "search",
543
+ matches: [],
544
+ count: 0,
545
+ hasMore: false,
546
+ nextOffset: null,
547
+ query,
548
+ ...(connectingServers.length > 0 ? { connectingServers } : {}),
549
+ },
531
550
  };
532
551
  }
533
552
 
@@ -748,6 +767,7 @@ export async function executeCall(
748
767
  serverOverride?: string,
749
768
  getPiTools?: () => ToolInfo[],
750
769
  signal?: AbortSignal,
770
+ origin?: "proxy" | "script",
751
771
  ): Promise<ProxyToolResult> {
752
772
  const ownedSignal = combineAbortSignals(state.owner?.signal, signal);
753
773
  throwIfAborted(ownedSignal);
@@ -1033,7 +1053,14 @@ export async function executeCall(
1033
1053
  return disabledCallResult(serverName, toolMeta);
1034
1054
  }
1035
1055
 
1036
- const approval = await ensureToolCallApproved(state, serverName, toolMeta, args, ownedSignal);
1056
+ const approval = await ensureToolCallApproved(
1057
+ state,
1058
+ serverName,
1059
+ toolMeta,
1060
+ args,
1061
+ ownedSignal,
1062
+ origin ?? (toolMeta.resourceUri ? "resource" : "proxy"),
1063
+ );
1037
1064
  if (approval.ok === false) {
1038
1065
  const denied = approval.reason === "denied";
1039
1066
  const message = denied
@@ -1086,7 +1113,12 @@ export async function executeCall(
1086
1113
 
1087
1114
  if (toolMeta.resourceUri) {
1088
1115
  const result = await withSessionRecovery(
1089
- { manager: state.manager, config: state.config, signal: ownedSignal, onNeedsAuth: recoverAuthConnection },
1116
+ {
1117
+ manager: state.manager,
1118
+ config: state.config,
1119
+ ...(ownedSignal ? { signal: ownedSignal } : {}),
1120
+ onNeedsAuth: recoverAuthConnection,
1121
+ },
1090
1122
  serverName,
1091
1123
  (conn) => conn.client.readResource({ uri: toolMeta.resourceUri! }, requestOptions),
1092
1124
  );
@@ -1107,24 +1139,29 @@ export async function executeCall(
1107
1139
  toolName: toolMeta.originalName,
1108
1140
  toolArgs: args ?? {},
1109
1141
  uiResourceUri: toolMeta.uiResourceUri,
1110
- streamMode: toolMeta.uiStreamMode,
1111
- signal,
1142
+ ...(toolMeta.uiStreamMode !== undefined ? { streamMode: toolMeta.uiStreamMode } : {}),
1143
+ ...(signal ? { signal } : {}),
1112
1144
  onNeedsAuth: recoverAuthConnection,
1113
1145
  })
1114
1146
  : null;
1115
1147
 
1116
- const result = await withSessionRecovery(
1117
- { manager: state.manager, config: state.config, signal: ownedSignal, onNeedsAuth: recoverAuthConnection },
1148
+ const result = await withSessionRecovery<ClientCallToolResult>(
1149
+ {
1150
+ manager: state.manager,
1151
+ config: state.config,
1152
+ ...(ownedSignal ? { signal: ownedSignal } : {}),
1153
+ onNeedsAuth: recoverAuthConnection,
1154
+ },
1118
1155
  serverName,
1119
1156
  (conn) => abortable(conn.client.callTool({
1120
1157
  name: toolMeta.originalName,
1121
1158
  arguments: args ?? {},
1122
1159
  _meta: uiSession?.requestMeta,
1123
- }, undefined, requestOptions), ownedSignal),
1160
+ }, requestOptions), ownedSignal),
1124
1161
  );
1125
1162
 
1126
1163
  if (toolMeta.uiResourceUri) {
1127
- uiSession?.sendToolResult(result as unknown as import("@modelcontextprotocol/sdk/types.js").CallToolResult);
1164
+ uiSession?.sendToolResult(result as unknown as import("@modelcontextprotocol/client").CallToolResult);
1128
1165
 
1129
1166
  if (result.isError) {
1130
1167
  const mcpContent = (result.content ?? []) as McpContent[];
@@ -1,22 +1,25 @@
1
- import { complete, type Api, type AssistantMessage, type Message, type Model, type TextContent } from "@earendil-works/pi-ai";
1
+ import { complete } from "@earendil-works/pi-ai/compat";
2
+ import type { Api, AssistantMessage, Message, Model, ProviderHeaders, TextContent } from "@earendil-works/pi-ai";
2
3
  import { truncateAtWord } from "./utils.ts";
3
4
  import { throwIfAborted } from "./abort.ts";
4
5
  import type { ExtensionUIContext, ModelRegistry } from "@earendil-works/pi-coding-agent";
5
- import type { Client } from "@modelcontextprotocol/sdk/client/index.js";
6
+ import type { Client } from "@modelcontextprotocol/client";
6
7
  import {
7
- CreateMessageRequestSchema,
8
8
  type CreateMessageRequest,
9
9
  type CreateMessageResult,
10
10
  type ModelPreferences,
11
11
  type SamplingMessage,
12
12
  type SamplingMessageContentBlock,
13
- } from "@modelcontextprotocol/sdk/types.js";
13
+ } from "@modelcontextprotocol/client";
14
+
15
+ export type SamplingUIContext = Pick<ExtensionUIContext, "confirm">;
16
+ export type SamplingModelRegistry = Pick<ModelRegistry, "getAvailable" | "getApiKeyAndHeaders">;
14
17
 
15
18
  export interface SamplingHandlerOptions {
16
19
  serverName: string;
17
20
  autoApprove: boolean;
18
- ui?: ExtensionUIContext;
19
- modelRegistry: ModelRegistry;
21
+ ui?: SamplingUIContext;
22
+ modelRegistry: SamplingModelRegistry;
20
23
  getCurrentModel: () => Model<Api> | undefined;
21
24
  getSignal: () => AbortSignal | undefined;
22
25
  }
@@ -24,7 +27,7 @@ export interface SamplingHandlerOptions {
24
27
  export type ServerSamplingConfig = Omit<SamplingHandlerOptions, "serverName">;
25
28
 
26
29
  export function registerSamplingHandler(client: Client, options: SamplingHandlerOptions): void {
27
- client.setRequestHandler(CreateMessageRequestSchema, request => {
30
+ client.setRequestHandler("sampling/createMessage", request => {
28
31
  return handleSamplingRequest(options, request);
29
32
  });
30
33
  }
@@ -66,16 +69,16 @@ export async function handleSamplingRequest(
66
69
  const result = await complete(
67
70
  model,
68
71
  {
69
- systemPrompt: params.systemPrompt,
72
+ ...(params.systemPrompt !== undefined ? { systemPrompt: params.systemPrompt } : {}),
70
73
  messages,
71
74
  },
72
75
  {
73
- apiKey,
74
- headers,
76
+ ...(apiKey !== undefined ? { apiKey } : {}),
77
+ ...(headers !== undefined ? { headers } : {}),
75
78
  maxTokens: params.maxTokens,
76
- temperature: params.temperature,
77
- metadata: params.metadata as Record<string, unknown> | undefined,
78
- signal,
79
+ ...(params.temperature !== undefined ? { temperature: params.temperature } : {}),
80
+ ...(params.metadata !== undefined ? { metadata: params.metadata as Record<string, unknown> } : {}),
81
+ ...(signal ? { signal } : {}),
79
82
  },
80
83
  );
81
84
 
@@ -127,7 +130,7 @@ async function resolveSamplingModel(
127
130
  ): Promise<{
128
131
  model: Model<Api>;
129
132
  apiKey?: string;
130
- headers?: Record<string, string>;
133
+ headers?: ProviderHeaders;
131
134
  }> {
132
135
  const candidates: Model<Api>[] = [];
133
136
  const availableModels = options.modelRegistry.getAvailable();
@@ -160,7 +163,11 @@ async function resolveSamplingModel(
160
163
  errors.push(`${model.provider}/${model.id}: ${auth.error}`);
161
164
  continue;
162
165
  }
163
- return { model, apiKey: auth.apiKey, headers: auth.headers };
166
+ return {
167
+ model,
168
+ ...(auth.apiKey !== undefined ? { apiKey: auth.apiKey } : {}),
169
+ ...(auth.headers !== undefined ? { headers: auth.headers } : {}),
170
+ };
164
171
  }
165
172
 
166
173
  if (errors.length > 0) {
@@ -82,7 +82,8 @@ export function scoreToolMatch(tool: ToolMetadata, server: string, query: string
82
82
  if (!phraseMatched && (queryTokens.length <= 2 ? coverage !== 1 : coverage < 0.6)) return null;
83
83
 
84
84
  score += coverage === 1 ? 25 : Math.round(coverage * 10);
85
- if (tokenize(fields.name).includes(queryTokens[0])) score += 8;
85
+ const firstQueryToken = queryTokens[0];
86
+ if (firstQueryToken !== undefined && tokenize(fields.name).includes(firstQueryToken)) score += 8;
86
87
  if (wholeFieldExact) score += 20;
87
88
  return score;
88
89
  }