@herbertgao/pi-extensions 2026.9.11 → 2026.9.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.
Files changed (192) hide show
  1. package/README.md +4 -4
  2. package/THIRD_PARTY_NOTICES.md +1 -1
  3. package/node_modules/@herbertgao/pi-cc-extensions/package.json +1 -1
  4. package/node_modules/@herbertgao/pi-subagents/CHANGELOG.md +8 -0
  5. package/node_modules/@herbertgao/pi-subagents/package.json +1 -1
  6. package/node_modules/@herbertgao/pi-subagents/src/agent-manager.ts +5 -4
  7. package/node_modules/@herbertgao/pi-subagents/src/mention-clone.ts +39 -16
  8. package/node_modules/@juicesharp/rpiv-ask-user-question/package.json +2 -2
  9. package/node_modules/@narumitw/pi-btw/README.md +21 -4
  10. package/node_modules/@narumitw/pi-btw/dist/index.ts +1668 -958
  11. package/node_modules/@narumitw/pi-btw/dist/index.ts.map +4 -4
  12. package/node_modules/@narumitw/pi-btw/docs/workflows.md +10 -2
  13. package/node_modules/@narumitw/pi-btw/package.json +1 -1
  14. package/node_modules/@narumitw/pi-btw/src/btw.ts +17 -79
  15. package/node_modules/@narumitw/pi-btw/src/conversation-context.ts +74 -0
  16. package/node_modules/@narumitw/pi-btw/src/fullscreen-ui.ts +196 -7
  17. package/node_modules/@narumitw/pi-btw/src/main-thread-updates.ts +40 -0
  18. package/node_modules/@narumitw/pi-btw/src/menu.ts +34 -2
  19. package/node_modules/@narumitw/pi-btw/src/settings.ts +49 -0
  20. package/node_modules/@narumitw/pi-btw/src/transcript-pager.ts +9 -1
  21. package/node_modules/@narumitw/pi-btw/src/workspace-layout.ts +559 -0
  22. package/node_modules/pi-mcp-adapter/CHANGELOG.md +62 -0
  23. package/node_modules/pi-mcp-adapter/README.md +75 -7
  24. package/node_modules/pi-mcp-adapter/bearer-command-resolver.ts +193 -0
  25. package/node_modules/pi-mcp-adapter/cli.js +56 -5
  26. package/node_modules/pi-mcp-adapter/commands.ts +96 -5
  27. package/node_modules/pi-mcp-adapter/config.ts +73 -6
  28. package/node_modules/pi-mcp-adapter/direct-tool-surface.ts +22 -28
  29. package/node_modules/pi-mcp-adapter/direct-tools.ts +13 -5
  30. package/node_modules/pi-mcp-adapter/dist/abort.d.ts +2 -0
  31. package/node_modules/pi-mcp-adapter/dist/abort.js +36 -0
  32. package/node_modules/pi-mcp-adapter/dist/abort.js.map +1 -0
  33. package/node_modules/pi-mcp-adapter/dist/bearer-command-resolver.d.ts +6 -0
  34. package/node_modules/pi-mcp-adapter/dist/bearer-command-resolver.js +194 -0
  35. package/node_modules/pi-mcp-adapter/dist/bearer-command-resolver.js.map +1 -0
  36. package/node_modules/pi-mcp-adapter/dist/config.d.ts +5 -0
  37. package/node_modules/pi-mcp-adapter/dist/config.js +75 -6
  38. package/node_modules/pi-mcp-adapter/dist/config.js.map +1 -1
  39. package/node_modules/pi-mcp-adapter/dist/consent-manager.d.ts +18 -0
  40. package/node_modules/pi-mcp-adapter/dist/consent-manager.js +88 -0
  41. package/node_modules/pi-mcp-adapter/dist/consent-manager.js.map +1 -0
  42. package/node_modules/pi-mcp-adapter/dist/elicitation-handler.d.ts +17 -0
  43. package/node_modules/pi-mcp-adapter/dist/elicitation-handler.js +316 -0
  44. package/node_modules/pi-mcp-adapter/dist/elicitation-handler.js.map +1 -0
  45. package/node_modules/pi-mcp-adapter/dist/errors.d.ts +131 -0
  46. package/node_modules/pi-mcp-adapter/dist/errors.js +278 -0
  47. package/node_modules/pi-mcp-adapter/dist/errors.js.map +1 -0
  48. package/node_modules/pi-mcp-adapter/dist/http-ca.d.ts +8 -0
  49. package/node_modules/pi-mcp-adapter/dist/http-ca.js +88 -0
  50. package/node_modules/pi-mcp-adapter/dist/http-ca.js.map +1 -0
  51. package/node_modules/pi-mcp-adapter/dist/jev-client.d.ts +15 -0
  52. package/node_modules/pi-mcp-adapter/dist/jev-client.js +340 -0
  53. package/node_modules/pi-mcp-adapter/dist/jev-client.js.map +1 -0
  54. package/node_modules/pi-mcp-adapter/dist/jev-contracts.d.ts +77 -0
  55. package/node_modules/pi-mcp-adapter/dist/jev-contracts.js +2 -0
  56. package/node_modules/pi-mcp-adapter/dist/jev-contracts.js.map +1 -0
  57. package/node_modules/pi-mcp-adapter/dist/jev-key-store.d.ts +22 -0
  58. package/node_modules/pi-mcp-adapter/dist/jev-key-store.js +85 -0
  59. package/node_modules/pi-mcp-adapter/dist/jev-key-store.js.map +1 -0
  60. package/node_modules/pi-mcp-adapter/dist/json-schema-validator.d.ts +2 -0
  61. package/node_modules/pi-mcp-adapter/dist/json-schema-validator.js +55 -0
  62. package/node_modules/pi-mcp-adapter/dist/json-schema-validator.js.map +1 -0
  63. package/node_modules/pi-mcp-adapter/dist/lifecycle.d.ts +56 -0
  64. package/node_modules/pi-mcp-adapter/dist/lifecycle.js +410 -0
  65. package/node_modules/pi-mcp-adapter/dist/lifecycle.js.map +1 -0
  66. package/node_modules/pi-mcp-adapter/dist/logger.d.ts +51 -0
  67. package/node_modules/pi-mcp-adapter/dist/logger.js +131 -0
  68. package/node_modules/pi-mcp-adapter/dist/logger.js.map +1 -0
  69. package/node_modules/pi-mcp-adapter/dist/mcp-auth-fetch.d.ts +26 -0
  70. package/node_modules/pi-mcp-adapter/dist/mcp-auth-fetch.js +103 -0
  71. package/node_modules/pi-mcp-adapter/dist/mcp-auth-fetch.js.map +1 -0
  72. package/node_modules/pi-mcp-adapter/dist/mcp-auth-flow.d.ts +118 -0
  73. package/node_modules/pi-mcp-adapter/dist/mcp-auth-flow.js +1098 -0
  74. package/node_modules/pi-mcp-adapter/dist/mcp-auth-flow.js.map +1 -0
  75. package/node_modules/pi-mcp-adapter/dist/mcp-auth.d.ts +168 -0
  76. package/node_modules/pi-mcp-adapter/dist/mcp-auth.js +1117 -0
  77. package/node_modules/pi-mcp-adapter/dist/mcp-auth.js.map +1 -0
  78. package/node_modules/pi-mcp-adapter/dist/mcp-bearer-store.js +7 -140
  79. package/node_modules/pi-mcp-adapter/dist/mcp-bearer-store.js.map +1 -1
  80. package/node_modules/pi-mcp-adapter/dist/mcp-callback-server.d.ts +53 -0
  81. package/node_modules/pi-mcp-adapter/dist/mcp-callback-server.js +441 -0
  82. package/node_modules/pi-mcp-adapter/dist/mcp-callback-server.js.map +1 -0
  83. package/node_modules/pi-mcp-adapter/dist/mcp-oauth-provider.d.ts +148 -0
  84. package/node_modules/pi-mcp-adapter/dist/mcp-oauth-provider.js +689 -0
  85. package/node_modules/pi-mcp-adapter/dist/mcp-oauth-provider.js.map +1 -0
  86. package/node_modules/pi-mcp-adapter/dist/mcp-probe.d.ts +6 -0
  87. package/node_modules/pi-mcp-adapter/dist/mcp-probe.js +166 -0
  88. package/node_modules/pi-mcp-adapter/dist/mcp-probe.js.map +1 -0
  89. package/node_modules/pi-mcp-adapter/dist/mcp-tasks.d.ts +102 -0
  90. package/node_modules/pi-mcp-adapter/dist/mcp-tasks.js +369 -0
  91. package/node_modules/pi-mcp-adapter/dist/mcp-tasks.js.map +1 -0
  92. package/node_modules/pi-mcp-adapter/dist/mcp-trace.d.ts +95 -0
  93. package/node_modules/pi-mcp-adapter/dist/mcp-trace.js +242 -0
  94. package/node_modules/pi-mcp-adapter/dist/mcp-trace.js.map +1 -0
  95. package/node_modules/pi-mcp-adapter/dist/metadata-cache.js +2 -11
  96. package/node_modules/pi-mcp-adapter/dist/metadata-cache.js.map +1 -1
  97. package/node_modules/pi-mcp-adapter/dist/npx-resolver.d.ts +6 -0
  98. package/node_modules/pi-mcp-adapter/dist/npx-resolver.js +505 -0
  99. package/node_modules/pi-mcp-adapter/dist/npx-resolver.js.map +1 -0
  100. package/node_modules/pi-mcp-adapter/dist/request-headers-command.d.ts +10 -0
  101. package/node_modules/pi-mcp-adapter/dist/request-headers-command.js +312 -0
  102. package/node_modules/pi-mcp-adapter/dist/request-headers-command.js.map +1 -0
  103. package/node_modules/pi-mcp-adapter/dist/runtime-owner.d.ts +13 -0
  104. package/node_modules/pi-mcp-adapter/dist/runtime-owner.js +97 -0
  105. package/node_modules/pi-mcp-adapter/dist/runtime-owner.js.map +1 -0
  106. package/node_modules/pi-mcp-adapter/dist/sampling-handler.d.ts +17 -0
  107. package/node_modules/pi-mcp-adapter/dist/sampling-handler.js +203 -0
  108. package/node_modules/pi-mcp-adapter/dist/sampling-handler.js.map +1 -0
  109. package/node_modules/pi-mcp-adapter/dist/secure-keyring.d.ts +11 -0
  110. package/node_modules/pi-mcp-adapter/dist/secure-keyring.js +172 -0
  111. package/node_modules/pi-mcp-adapter/dist/secure-keyring.js.map +1 -0
  112. package/node_modules/pi-mcp-adapter/dist/server-manager.d.ts +157 -0
  113. package/node_modules/pi-mcp-adapter/dist/server-manager.js +1743 -0
  114. package/node_modules/pi-mcp-adapter/dist/server-manager.js.map +1 -0
  115. package/node_modules/pi-mcp-adapter/dist/session-approvals.d.ts +34 -0
  116. package/node_modules/pi-mcp-adapter/dist/session-approvals.js +140 -0
  117. package/node_modules/pi-mcp-adapter/dist/session-approvals.js.map +1 -0
  118. package/node_modules/pi-mcp-adapter/dist/session-recovery.d.ts +26 -0
  119. package/node_modules/pi-mcp-adapter/dist/session-recovery.js +142 -0
  120. package/node_modules/pi-mcp-adapter/dist/session-recovery.js.map +1 -0
  121. package/node_modules/pi-mcp-adapter/dist/state.d.ts +73 -0
  122. package/node_modules/pi-mcp-adapter/dist/state.js +2 -0
  123. package/node_modules/pi-mcp-adapter/dist/state.js.map +1 -0
  124. package/node_modules/pi-mcp-adapter/dist/types.d.ts +36 -0
  125. package/node_modules/pi-mcp-adapter/dist/types.js +18 -0
  126. package/node_modules/pi-mcp-adapter/dist/types.js.map +1 -1
  127. package/node_modules/pi-mcp-adapter/dist/ui-resource-handler.d.ts +17 -0
  128. package/node_modules/pi-mcp-adapter/dist/ui-resource-handler.js +219 -0
  129. package/node_modules/pi-mcp-adapter/dist/ui-resource-handler.js.map +1 -0
  130. package/node_modules/pi-mcp-adapter/dist/unix-socket-transport.d.ts +15 -0
  131. package/node_modules/pi-mcp-adapter/dist/unix-socket-transport.js +85 -0
  132. package/node_modules/pi-mcp-adapter/dist/unix-socket-transport.js.map +1 -0
  133. package/node_modules/pi-mcp-adapter/dist/utils.d.ts +1 -0
  134. package/node_modules/pi-mcp-adapter/dist/utils.js +13 -0
  135. package/node_modules/pi-mcp-adapter/dist/utils.js.map +1 -1
  136. package/node_modules/pi-mcp-adapter/elicitation-handler.ts +29 -19
  137. package/node_modules/pi-mcp-adapter/examples/jev-accessibility-loop.mjs +85 -0
  138. package/node_modules/pi-mcp-adapter/examples/jev-semantic-filter.mjs +34 -0
  139. package/node_modules/pi-mcp-adapter/index.ts +129 -6
  140. package/node_modules/pi-mcp-adapter/init.ts +6 -19
  141. package/node_modules/pi-mcp-adapter/jev-client.ts +273 -0
  142. package/node_modules/pi-mcp-adapter/jev-contracts.ts +53 -0
  143. package/node_modules/pi-mcp-adapter/jev-key-store.ts +79 -0
  144. package/node_modules/pi-mcp-adapter/lifecycle.ts +14 -3
  145. package/node_modules/pi-mcp-adapter/mcp-bearer-store.ts +7 -142
  146. package/node_modules/pi-mcp-adapter/mcp-code.ts +119 -11
  147. package/node_modules/pi-mcp-adapter/mcp-output-guard.ts +4 -0
  148. package/node_modules/pi-mcp-adapter/mcp-references.ts +5 -3
  149. package/node_modules/pi-mcp-adapter/mcp-script-worker.mjs +5 -0
  150. package/node_modules/pi-mcp-adapter/mcp-tasks.ts +467 -0
  151. package/node_modules/pi-mcp-adapter/metadata-cache.ts +2 -13
  152. package/node_modules/pi-mcp-adapter/namespace-tools.ts +1 -1
  153. package/node_modules/pi-mcp-adapter/package.json +17 -9
  154. package/node_modules/pi-mcp-adapter/proxy-modes.ts +319 -166
  155. package/node_modules/pi-mcp-adapter/request-headers-command.ts +6 -3
  156. package/node_modules/pi-mcp-adapter/search-ranking.ts +38 -7
  157. package/node_modules/pi-mcp-adapter/secure-keyring.ts +170 -0
  158. package/node_modules/pi-mcp-adapter/semantic-search.ts +186 -0
  159. package/node_modules/pi-mcp-adapter/server-manager.ts +293 -50
  160. package/node_modules/pi-mcp-adapter/session-approvals.ts +14 -0
  161. package/node_modules/pi-mcp-adapter/skills/mcp-scripting/SKILL.md +2 -0
  162. package/node_modules/pi-mcp-adapter/state.ts +3 -1
  163. package/node_modules/pi-mcp-adapter/tool-approval.ts +26 -4
  164. package/node_modules/pi-mcp-adapter/tool-metadata.ts +6 -14
  165. package/node_modules/pi-mcp-adapter/tool-registrar.ts +8 -6
  166. package/node_modules/pi-mcp-adapter/tool-result-renderer.ts +4 -1
  167. package/node_modules/pi-mcp-adapter/types.ts +53 -0
  168. package/node_modules/pi-mcp-adapter/ui-server.ts +17 -9
  169. package/node_modules/pi-mcp-adapter/utils.ts +16 -0
  170. package/node_modules/pi-multi-account/CHANGELOG.md +23 -0
  171. package/node_modules/pi-multi-account/README.md +38 -11
  172. package/node_modules/pi-multi-account/index.ts +371 -96
  173. package/node_modules/pi-multi-account/package.json +5 -4
  174. package/node_modules/pi-multi-account/provider-payload-stream.ts +36 -28
  175. package/node_modules/pi-multi-account/usage.ts +31 -2
  176. package/node_modules/pi-typesafe/README.md +3 -1
  177. package/node_modules/pi-typesafe/dist/auth.d.ts +10 -3
  178. package/node_modules/pi-typesafe/dist/auth.js +13 -7
  179. package/node_modules/pi-typesafe/dist/backends.d.ts +31 -0
  180. package/node_modules/pi-typesafe/dist/backends.js +33 -0
  181. package/node_modules/pi-typesafe/dist/client.d.ts +3 -9
  182. package/node_modules/pi-typesafe/dist/client.js +63 -39
  183. package/node_modules/pi-typesafe/dist/credentials.d.ts +11 -5
  184. package/node_modules/pi-typesafe/dist/credentials.js +15 -8
  185. package/node_modules/pi-typesafe/dist/extension.js +4 -1
  186. package/node_modules/pi-typesafe/dist/index.d.ts +1 -1
  187. package/node_modules/pi-typesafe/dist/index.js +1 -1
  188. package/node_modules/pi-typesafe/dist/login.d.ts +13 -7
  189. package/node_modules/pi-typesafe/dist/login.js +17 -8
  190. package/node_modules/pi-typesafe/dist/schema.js +19 -13
  191. package/node_modules/pi-typesafe/package.json +1 -1
  192. package/package.json +11 -10
@@ -3,9 +3,12 @@ import { formatWithOptions } from "node:util";
3
3
  import { Worker } from "node:worker_threads";
4
4
  import { throwIfAborted } from "./abort.ts";
5
5
  import { guardMcpOutput, guardedMcpDetails, resolveMcpOutputGuardOptions } from "./mcp-output-guard.ts";
6
+ import { evaluateJev, validateJevSettings } from "./jev-client.ts";
7
+ import type { JevErrorCode, JevEvaluateInput, JevEvaluationEnvelope } from "./jev-contracts.ts";
6
8
  import { executeCall } from "./proxy-modes.ts";
7
9
  import { combineAbortSignals } from "./runtime-owner.ts";
8
10
  import { paginate, rankSuggestions, rankToolMatches } from "./search-ranking.ts";
11
+ import { semanticSearch, type SemanticSearchEvaluator } from "./semantic-search.ts";
9
12
  import { isServerInActiveFailureBackoff } from "./failure-backoff.ts";
10
13
  import type { McpExtensionState } from "./state.ts";
11
14
  import { findToolByName, formatSchema, hasSchemaDescriptions } from "./tool-metadata.ts";
@@ -22,11 +25,12 @@ class McpScriptTimeoutError extends Error {
22
25
  }
23
26
  }
24
27
 
25
- type SearchInput = { query?: unknown; server?: unknown; limit?: unknown; offset?: unknown };
28
+ type SearchInput = { query?: unknown; server?: unknown; limit?: unknown; offset?: unknown; searchMode?: unknown; regex?: unknown };
26
29
  type DescribeInput = { path?: unknown };
27
30
  type WorkerMessage =
28
31
  | { type: "emit"; block: unknown }
29
32
  | { type: "call"; id: number; path: string; args?: unknown }
33
+ | { type: "evaluate"; id: number; input: unknown }
30
34
  | { type: "search"; id: number; input?: unknown }
31
35
  | { type: "describe"; id: number; input?: unknown }
32
36
  | { type: "done"; returnBlock?: unknown }
@@ -94,6 +98,9 @@ function parseWorkerMessage(value: unknown): WorkerMessage | null {
94
98
  ? { type: "call", id: message.id, path: message.path, args: message.args }
95
99
  : { type: "call", id: message.id, path: message.path };
96
100
  }
101
+ if (message.type === "evaluate" && typeof message.id === "number" && "input" in message) {
102
+ return { type: "evaluate", id: message.id, input: message.input };
103
+ }
97
104
  if ((message.type === "search" || message.type === "describe") && typeof message.id === "number") {
98
105
  return "input" in message
99
106
  ? { type: message.type, id: message.id, input: message.input }
@@ -108,12 +115,20 @@ function parseWorkerMessage(value: unknown): WorkerMessage | null {
108
115
  return null;
109
116
  }
110
117
 
118
+ export type McpScriptJevEvaluator = (
119
+ state: McpExtensionState,
120
+ input: JevEvaluateInput,
121
+ options: { purpose: "script"; signal?: AbortSignal; observedSources?: readonly string[] },
122
+ ) => Promise<JevEvaluationEnvelope>;
123
+
111
124
  export async function runMcpScript(
112
125
  state: McpExtensionState,
113
126
  code: string,
114
127
  timeoutMs = DEFAULT_MCP_SCRIPT_TIMEOUT_MS,
115
128
  getPiTools?: () => ToolInfo[],
116
129
  signal?: AbortSignal,
130
+ jevEvaluator: McpScriptJevEvaluator = evaluateJev,
131
+ semanticEvaluator?: SemanticSearchEvaluator,
117
132
  ) {
118
133
  const resolvedTimeoutMs = Number.isFinite(timeoutMs) && timeoutMs > 0
119
134
  ? Math.floor(timeoutMs)
@@ -122,6 +137,7 @@ export async function runMcpScript(
122
137
  const externalSignal = combineAbortSignals(state.owner?.signal, signal);
123
138
  const timeoutController = new AbortController();
124
139
  const callSignal = combineAbortSignals(externalSignal, timeoutController.signal);
140
+ const observedSources = new Set<string>();
125
141
 
126
142
  type ScriptOperation =
127
143
  | { operation: "call"; path: string; ok: true; durationMs: number }
@@ -129,7 +145,9 @@ export async function runMcpScript(
129
145
  | { operation: "search"; query: string; ok: true; durationMs: number }
130
146
  | { operation: "search"; query: string; ok: false; error: string; durationMs: number }
131
147
  | { operation: "describe"; path: string; ok: true; durationMs: number }
132
- | { operation: "describe"; path: string; ok: false; error: string; durationMs: number };
148
+ | { operation: "describe"; path: string; ok: false; error: string; durationMs: number }
149
+ | { operation: "evaluate"; ok: true; model: string; inputTokens: number; outputTokens: number; durationMs: number }
150
+ | { operation: "evaluate"; ok: false; error: JevErrorCode | "incomplete"; durationMs: number };
133
151
  type TrackedScriptOperation = ScriptOperation & { startedAt: number };
134
152
  const calls: TrackedScriptOperation[] = [];
135
153
  const snapshotCalls = (): ScriptOperation[] => calls.map(({ startedAt, ...operation }) => ({
@@ -140,6 +158,12 @@ export async function runMcpScript(
140
158
  }));
141
159
  let callsSnapshot: ScriptOperation[] | undefined;
142
160
  let intermediateBytes = 0;
161
+ const reserveIntermediateBytes = (dataJson: string): boolean => {
162
+ const bytes = Buffer.byteLength(dataJson, "utf8");
163
+ if (bytes > MCP_SCRIPT_INTERMEDIATE_MAX_BYTES - intermediateBytes) return false;
164
+ intermediateBytes += bytes;
165
+ return true;
166
+ };
143
167
  const callTool = async (path: string, args?: Record<string, unknown>): Promise<WorkerResultPayload> => {
144
168
  // Record before dispatch so calls still in flight at timeout/abort appear in the trace.
145
169
  const startedAt = Date.now();
@@ -152,6 +176,7 @@ export async function runMcpScript(
152
176
  },
153
177
  });
154
178
  const details = result.details;
179
+ if (typeof details.server === "string") observedSources.add(details.server);
155
180
  if (details.error !== undefined) {
156
181
  const errorCode = String(details.error);
157
182
  const suggestions = Array.isArray(details.suggestions)
@@ -169,8 +194,7 @@ export async function runMcpScript(
169
194
  }
170
195
  throwIfAborted(callSignal);
171
196
  if (dataJson === undefined) throw new Error("MCP intermediate result was not JSON serializable");
172
- const bytes = Buffer.byteLength(dataJson, "utf8");
173
- if (bytes > MCP_SCRIPT_INTERMEDIATE_MAX_BYTES - intermediateBytes) {
197
+ if (!reserveIntermediateBytes(dataJson)) {
174
198
  const code = "intermediate_result_too_large";
175
199
  calls[index] = { operation: "call", path, ok: false, error: code, durationMs: Date.now() - startedAt, startedAt };
176
200
  return {
@@ -181,23 +205,104 @@ export async function runMcpScript(
181
205
  };
182
206
  }
183
207
  // Rejected responses do not consume budget. This bounds transfer, not upstream allocation.
184
- intermediateBytes += bytes;
185
208
  calls[index] = { operation: "call", path, ok: true, durationMs: Date.now() - startedAt, startedAt };
186
209
  return { dataJson };
187
210
  };
188
211
 
189
- const searchTools = (input?: SearchInput) => {
212
+ const jevSettings = validateJevSettings(state.config.settings?.jev);
213
+ let evaluationAttempts = 0;
214
+ let evaluationBytes = 0;
215
+ let evaluationTokensRemaining = jevSettings.maxEvaluationTokensPerScript;
216
+ const tokenBudgetExhausted = (): JevEvaluationEnvelope => ({ ok: false, error: { code: "budget_exhausted", message: "TypeSafe evaluation token budget exhausted." } });
217
+ const chargeEvaluationTokens = (envelope: JevEvaluationEnvelope): JevEvaluationEnvelope => {
218
+ if (!envelope.ok) return envelope;
219
+ const used = envelope.data.usage.inputTokens + envelope.data.usage.outputTokens;
220
+ if (!Number.isSafeInteger(used) || used < 0 || used > evaluationTokensRemaining) {
221
+ evaluationTokensRemaining = 0;
222
+ return tokenBudgetExhausted();
223
+ }
224
+ evaluationTokensRemaining -= used;
225
+ return envelope;
226
+ };
227
+ const admitEvaluation = (input: unknown): JevEvaluationEnvelope | undefined => {
228
+ if (++evaluationAttempts > jevSettings.maxEvaluationsPerScript) {
229
+ return { ok: false, error: { code: "budget_exhausted", message: "TypeSafe evaluation count budget exhausted." } };
230
+ }
231
+ if (evaluationTokensRemaining === 0) return tokenBudgetExhausted();
232
+ let serialized: string | undefined;
233
+ try { serialized = JSON.stringify(input); }
234
+ catch { return { ok: false, error: { code: "invalid_request", message: "Invalid TypeSafe evaluation request." } }; }
235
+ if (serialized === undefined) return { ok: false, error: { code: "invalid_request", message: "Invalid TypeSafe evaluation request." } };
236
+ const bytes = Buffer.byteLength(serialized, "utf8");
237
+ if (bytes > jevSettings.maxEvaluationBytesPerScript - evaluationBytes) {
238
+ return { ok: false, error: { code: "budget_exhausted", message: "TypeSafe evaluation byte budget exhausted." } };
239
+ }
240
+ evaluationBytes += bytes;
241
+ return undefined;
242
+ };
243
+ const evaluate = async (input: unknown): Promise<WorkerResultPayload> => {
244
+ const startedAt = Date.now();
245
+ const index = calls.push({ operation: "evaluate", ok: false, error: "incomplete", durationMs: 0, startedAt }) - 1;
246
+ let envelope: JevEvaluationEnvelope;
247
+ const rejected = admitEvaluation(input);
248
+ if (rejected) {
249
+ envelope = rejected;
250
+ } else {
251
+ envelope = await jevEvaluator(state, input as JevEvaluateInput, {
252
+ purpose: "script",
253
+ ...(callSignal ? { signal: callSignal } : {}),
254
+ ...(observedSources.size > 0 ? { observedSources: [...observedSources] } : {}),
255
+ });
256
+ }
257
+ envelope = chargeEvaluationTokens(envelope);
258
+ throwIfAborted(callSignal);
259
+ if (!reserveIntermediateBytes(JSON.stringify(envelope))) {
260
+ envelope = { ok: false, error: { code: "budget_exhausted", message: "TypeSafe evaluation exceeds the remaining mcpScript intermediate transfer budget (16 MiB per script)." } };
261
+ }
262
+ calls[index] = envelope.ok
263
+ ? {
264
+ operation: "evaluate", ok: true, model: envelope.data.model,
265
+ inputTokens: envelope.data.usage.inputTokens, outputTokens: envelope.data.usage.outputTokens,
266
+ durationMs: Date.now() - startedAt, startedAt,
267
+ }
268
+ : { operation: "evaluate", ok: false, error: envelope.error.code, durationMs: Date.now() - startedAt, startedAt };
269
+ return { envelope };
270
+ };
271
+
272
+ const searchTools = async (input?: SearchInput) => {
190
273
  const startedAt = Date.now();
191
274
  const query = typeof input?.query === "string" ? input.query : "";
275
+ const index = calls.push({ operation: "search", query, ok: false, error: "incomplete", durationMs: 0, startedAt }) - 1;
192
276
  let error: unknown;
193
277
  try {
194
- if (query.trim() === "") {
278
+ if (input?.searchMode !== undefined && input.searchMode !== "lexical" && input.searchMode !== "semantic") {
279
+ error = "invalid_search_mode";
280
+ return { items: [], total: 0, hasMore: false, nextOffset: null, error: { code: "invalid_search_mode", message: "Search mode must be lexical or semantic." } };
281
+ }
282
+ if (query.trim() === "" && input?.searchMode !== "semantic") {
195
283
  return { items: [], total: 0, hasMore: false, nextOffset: null };
196
284
  }
197
285
  const server = typeof input?.server === "string" ? input.server : undefined;
198
286
  const limit = typeof input?.limit === "number" ? input.limit : 12;
199
287
  const offset = typeof input?.offset === "number" ? input.offset : 0;
200
- const page = paginate(rankToolMatches(state, query, server), offset, limit);
288
+ const searchMode = input?.searchMode === "semantic" ? "semantic" : "lexical";
289
+ if (searchMode === "semantic" && input?.regex === true) {
290
+ error = "invalid_search_mode";
291
+ return { items: [], total: 0, hasMore: false, nextOffset: null, error: { code: "invalid_search_mode", message: "Semantic search cannot be combined with regex search." } };
292
+ }
293
+ const semantic = searchMode === "semantic"
294
+ ? await semanticSearch(state, query, server, callSignal, async (semanticState, semanticInput, options) => {
295
+ const rejected = admitEvaluation(semanticInput);
296
+ if (rejected) return rejected;
297
+ const envelope = await (semanticEvaluator ?? evaluateJev)(semanticState, semanticInput, options);
298
+ return chargeEvaluationTokens(envelope);
299
+ }, [...observedSources])
300
+ : undefined;
301
+ if (semantic && !semantic.ok) {
302
+ error = semantic.error.code;
303
+ return { items: [], total: 0, hasMore: false, nextOffset: null, error: semantic.error };
304
+ }
305
+ const page = paginate(semantic?.matches ?? rankToolMatches(state, query, server), offset, limit);
201
306
  return {
202
307
  ...page,
203
308
  items: page.items.map(({ server: matchServer, tool, score }) => ({
@@ -207,14 +312,15 @@ export async function runMcpScript(
207
312
  ...(tool.description ? { description: tool.description } : {}),
208
313
  score,
209
314
  })),
315
+ ...(semantic ? { backend: semantic.backend } : {}),
210
316
  };
211
317
  } catch (caught) {
212
318
  error = caught;
213
319
  throw caught;
214
320
  } finally {
215
- calls.push(error === undefined
321
+ calls[index] = error === undefined
216
322
  ? { operation: "search", query, ok: true, durationMs: Date.now() - startedAt, startedAt }
217
- : { operation: "search", query, ok: false, error: error instanceof Error ? error.message : String(error), durationMs: Date.now() - startedAt, startedAt });
323
+ : { operation: "search", query, ok: false, error: error instanceof Error ? error.message : String(error), durationMs: Date.now() - startedAt, startedAt };
218
324
  }
219
325
  };
220
326
 
@@ -308,8 +414,10 @@ export async function runMcpScript(
308
414
  let payload: WorkerResultPayload;
309
415
  if (message.type === "call") {
310
416
  payload = await callTool(message.path, message.args as Record<string, unknown> | undefined);
417
+ } else if (message.type === "evaluate") {
418
+ payload = await evaluate(message.input);
311
419
  } else if (message.type === "search") {
312
- payload = { envelope: searchTools(message.input as SearchInput | undefined) };
420
+ payload = { envelope: await searchTools(message.input as SearchInput | undefined) };
313
421
  } else {
314
422
  payload = { envelope: describeTool(message.input as DescribeInput | undefined) };
315
423
  }
@@ -404,12 +404,16 @@ function summarizeStructuredContent(value: unknown): Record<string, unknown> {
404
404
  fields[key] = candidate;
405
405
  preservedBytes += entryBytes;
406
406
  }
407
+ const preservedCount = Object.keys(fields).length;
407
408
  return {
409
+ omitted: true,
408
410
  preservedFields: fields,
409
411
  summary: {
410
412
  type: "object",
411
413
  estimatedBytes: estimateValueBytes(value),
412
414
  keyCount: keys.length,
415
+ preservedCount,
416
+ droppedCount: keys.length - preservedCount,
413
417
  keysPreview: previewKeys,
414
418
  omitted: true,
415
419
  },
@@ -7,6 +7,7 @@ import {
7
7
  isServerDisabled,
8
8
  isToolAllowed,
9
9
  resolveToolPrefix,
10
+ resolveUniqueNameOwnership,
10
11
  type CachedTool,
11
12
  type McpConfig,
12
13
  type ServerCacheEntry,
@@ -97,6 +98,7 @@ function hasNamespaceProxy(
97
98
  existingDirectNames: ReadonlySet<string>,
98
99
  serverName: string,
99
100
  ): boolean {
101
+ if (config.settings?.namespaceProxyTools === false) return false;
100
102
  const definition = config.mcpServers[serverName];
101
103
  if (!definition || isServerDisabled(definition)) return false;
102
104
  if (isMcpServerDirectlyRegistered(definition, config.settings, serverName, envOverride)) return false;
@@ -146,14 +148,14 @@ function registeredDirectNames(
146
148
  envOverride: DirectToolSelectorOverride | null,
147
149
  selectorIndex: ToolSelectorCandidateIndex | undefined,
148
150
  ): Map<string, DirectNameOwner> {
149
- const owners = new Map<string, DirectNameOwner>();
151
+ const entries: Array<{ name: string; owner: DirectNameOwner }> = [];
150
152
  for (const { serverName, definition, entry, prefix } of cachedServers(config, cache)) {
151
153
  const selection = resolveDirectSelection(config, definition, serverName, envOverride);
152
154
  for (const { name, originalName } of directNameEntries(entry, serverName, definition, prefix, selection, selectorIndex)) {
153
- if (!owners.has(name)) owners.set(name, { serverName, originalName });
155
+ entries.push({ name, owner: { serverName, originalName } });
154
156
  }
155
157
  }
156
- return owners;
158
+ return new Map(resolveUniqueNameOwnership(entries, (entry) => entry.name).unique.map(({ name, owner }) => [name, owner]));
157
159
  }
158
160
 
159
161
  function allCurrentCandidates(config: McpConfig, cache: MetadataCache | null): ToolSelectorCandidateIndex | undefined {
@@ -96,6 +96,10 @@ const tools = new Proxy(Object.create(null), {
96
96
  },
97
97
  });
98
98
 
99
+ const jev = Object.freeze({
100
+ evaluate: (input) => request("evaluate", { input }),
101
+ });
102
+
99
103
  const emit = (value) => {
100
104
  parentPort.postMessage({ type: "emit", block: toContentBlock(value) });
101
105
  };
@@ -112,6 +116,7 @@ void (async () => {
112
116
  try {
113
117
  const context = vm.createContext(Object.assign(Object.create(null), {
114
118
  tools,
119
+ jev,
115
120
  emit,
116
121
  console: capturedConsole,
117
122
  }), {