@akon-labs/nexus-cli 0.1.9 → 0.1.10
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/CHANGELOG.md +21 -0
- package/LICENSE +1 -0
- package/README.md +3 -2
- package/dist/app-bridge.bundle.js +67 -0
- package/dist/cli.js +20263 -2158
- package/dist/core/agent-session.d.ts.map +1 -1
- package/dist/core/agent-session.js +1 -1
- package/dist/core/agent-session.js.map +1 -1
- package/dist/core/auto-model.d.ts +1 -1
- package/dist/core/auto-model.d.ts.map +1 -1
- package/dist/core/auto-model.js +1 -1
- package/dist/core/auto-model.js.map +1 -1
- package/dist/core/model-resolver.d.ts +2 -2
- package/dist/core/model-resolver.d.ts.map +1 -1
- package/dist/core/model-resolver.js +3 -3
- package/dist/core/model-resolver.js.map +1 -1
- package/dist/core/package-manager.d.ts +15 -0
- package/dist/core/package-manager.d.ts.map +1 -1
- package/dist/core/package-manager.js +50 -0
- package/dist/core/package-manager.js.map +1 -1
- package/dist/core/sdk.d.ts.map +1 -1
- package/dist/core/sdk.js +1 -1
- package/dist/core/sdk.js.map +1 -1
- package/dist/core/slash-commands.d.ts.map +1 -1
- package/dist/core/slash-commands.js +3 -3
- package/dist/core/slash-commands.js.map +1 -1
- package/dist/core/system-prompt.d.ts.map +1 -1
- package/dist/core/system-prompt.js +1 -1
- package/dist/core/system-prompt.js.map +1 -1
- package/dist/core/tools/index.d.ts +1 -1
- package/dist/core/tools/index.d.ts.map +1 -1
- package/dist/core/tools/index.js +5 -5
- package/dist/core/tools/index.js.map +1 -1
- package/dist/core/tools/websearch.d.ts.map +1 -1
- package/dist/core/tools/websearch.js +3 -3
- package/dist/core/tools/websearch.js.map +1 -1
- package/dist/extensions/gitnexus/gateway.d.ts +6 -6
- package/dist/extensions/gitnexus/gateway.d.ts.map +1 -1
- package/dist/extensions/gitnexus/gateway.js +4 -4
- package/dist/extensions/gitnexus/gateway.js.map +1 -1
- package/dist/extensions/gitnexus/index.d.ts.map +1 -1
- package/dist/extensions/gitnexus/index.js +4 -2
- package/dist/extensions/gitnexus/index.js.map +1 -1
- package/dist/extensions/mcp/abort.d.ts +3 -0
- package/dist/extensions/mcp/abort.d.ts.map +1 -0
- package/dist/extensions/mcp/abort.js +41 -0
- package/dist/extensions/mcp/abort.js.map +1 -0
- package/dist/extensions/mcp/agent-dir.d.ts +6 -0
- package/dist/extensions/mcp/agent-dir.d.ts.map +1 -0
- package/dist/extensions/mcp/agent-dir.js +18 -0
- package/dist/extensions/mcp/agent-dir.js.map +1 -0
- package/dist/extensions/mcp/agent-plugin-loader.d.ts +9 -0
- package/dist/extensions/mcp/agent-plugin-loader.d.ts.map +1 -0
- package/dist/extensions/mcp/agent-plugin-loader.js +384 -0
- package/dist/extensions/mcp/agent-plugin-loader.js.map +1 -0
- package/dist/extensions/mcp/app-bridge.bundle.js +67 -0
- package/dist/extensions/mcp/commands.d.ts +27 -0
- package/dist/extensions/mcp/commands.d.ts.map +1 -0
- package/dist/extensions/mcp/commands.js +629 -0
- package/dist/extensions/mcp/commands.js.map +1 -0
- package/dist/extensions/mcp/config.d.ts +121 -38
- package/dist/extensions/mcp/config.d.ts.map +1 -1
- package/dist/extensions/mcp/config.js +1030 -70
- package/dist/extensions/mcp/config.js.map +1 -1
- package/dist/extensions/mcp/consent-manager.d.ts +14 -0
- package/dist/extensions/mcp/consent-manager.d.ts.map +1 -0
- package/dist/extensions/mcp/consent-manager.js +60 -0
- package/dist/extensions/mcp/consent-manager.js.map +1 -0
- package/dist/extensions/mcp/direct-tools.d.ts +11 -0
- package/dist/extensions/mcp/direct-tools.d.ts.map +1 -0
- package/dist/extensions/mcp/direct-tools.js +562 -0
- package/dist/extensions/mcp/direct-tools.js.map +1 -0
- package/dist/extensions/mcp/elicitation-handler.d.ts +18 -0
- package/dist/extensions/mcp/elicitation-handler.d.ts.map +1 -0
- package/dist/extensions/mcp/elicitation-handler.js +320 -0
- package/dist/extensions/mcp/elicitation-handler.js.map +1 -0
- package/dist/extensions/mcp/error-signal.d.ts +16 -0
- package/dist/extensions/mcp/error-signal.d.ts.map +1 -0
- package/dist/extensions/mcp/error-signal.js +22 -0
- package/dist/extensions/mcp/error-signal.js.map +1 -0
- package/dist/extensions/mcp/errors.d.ts +104 -0
- package/dist/extensions/mcp/errors.d.ts.map +1 -0
- package/dist/extensions/mcp/errors.js +171 -0
- package/dist/extensions/mcp/errors.js.map +1 -0
- package/dist/extensions/mcp/glimpse-ui.d.ts +10 -0
- package/dist/extensions/mcp/glimpse-ui.d.ts.map +1 -0
- package/dist/extensions/mcp/glimpse-ui.js +67 -0
- package/dist/extensions/mcp/glimpse-ui.js.map +1 -0
- package/dist/extensions/mcp/host-html-template.d.ts +17 -0
- package/dist/extensions/mcp/host-html-template.d.ts.map +1 -0
- package/dist/extensions/mcp/host-html-template.js +442 -0
- package/dist/extensions/mcp/host-html-template.js.map +1 -0
- package/dist/extensions/mcp/index.d.ts +20 -15
- package/dist/extensions/mcp/index.d.ts.map +1 -1
- package/dist/extensions/mcp/index.js +1064 -82
- package/dist/extensions/mcp/index.js.map +1 -1
- package/dist/extensions/mcp/init.d.ts +28 -0
- package/dist/extensions/mcp/init.d.ts.map +1 -0
- package/dist/extensions/mcp/init.js +631 -0
- package/dist/extensions/mcp/init.js.map +1 -0
- package/dist/extensions/mcp/json-schema-validator.d.ts +3 -0
- package/dist/extensions/mcp/json-schema-validator.d.ts.map +1 -0
- package/dist/extensions/mcp/json-schema-validator.js +53 -0
- package/dist/extensions/mcp/json-schema-validator.js.map +1 -0
- package/dist/extensions/mcp/lifecycle.d.ts +56 -0
- package/dist/extensions/mcp/lifecycle.d.ts.map +1 -0
- package/dist/extensions/mcp/lifecycle.js +395 -0
- package/dist/extensions/mcp/lifecycle.js.map +1 -0
- package/dist/extensions/mcp/logger.d.ts +52 -0
- package/dist/extensions/mcp/logger.d.ts.map +1 -0
- package/dist/extensions/mcp/logger.js +134 -0
- package/dist/extensions/mcp/logger.js.map +1 -0
- package/dist/extensions/mcp/mcp-auth-flow.d.ts +117 -0
- package/dist/extensions/mcp/mcp-auth-flow.d.ts.map +1 -0
- package/dist/extensions/mcp/mcp-auth-flow.js +869 -0
- package/dist/extensions/mcp/mcp-auth-flow.js.map +1 -0
- package/dist/extensions/mcp/mcp-auth.d.ts +162 -0
- package/dist/extensions/mcp/mcp-auth.d.ts.map +1 -0
- package/dist/extensions/mcp/mcp-auth.js +897 -0
- package/dist/extensions/mcp/mcp-auth.js.map +1 -0
- package/dist/extensions/mcp/mcp-bearer-store.d.ts +25 -0
- package/dist/extensions/mcp/mcp-bearer-store.d.ts.map +1 -0
- package/dist/extensions/mcp/mcp-bearer-store.js +350 -0
- package/dist/extensions/mcp/mcp-bearer-store.js.map +1 -0
- package/dist/extensions/mcp/mcp-callback-server.d.ts +54 -0
- package/dist/extensions/mcp/mcp-callback-server.d.ts.map +1 -0
- package/dist/extensions/mcp/mcp-callback-server.js +454 -0
- package/dist/extensions/mcp/mcp-callback-server.js.map +1 -0
- package/dist/extensions/mcp/mcp-code.d.ts +48 -0
- package/dist/extensions/mcp/mcp-code.d.ts.map +1 -0
- package/dist/extensions/mcp/mcp-code.js +358 -0
- package/dist/extensions/mcp/mcp-code.js.map +1 -0
- package/dist/extensions/mcp/mcp-keyring-helper.cjs +89 -0
- package/dist/extensions/mcp/mcp-oauth-provider.d.ts +135 -0
- package/dist/extensions/mcp/mcp-oauth-provider.d.ts.map +1 -0
- package/dist/extensions/mcp/mcp-oauth-provider.js +491 -0
- package/dist/extensions/mcp/mcp-oauth-provider.js.map +1 -0
- package/dist/extensions/mcp/mcp-output-guard.d.ts +59 -0
- package/dist/extensions/mcp/mcp-output-guard.d.ts.map +1 -0
- package/dist/extensions/mcp/mcp-output-guard.js +343 -0
- package/dist/extensions/mcp/mcp-output-guard.js.map +1 -0
- package/dist/extensions/mcp/mcp-panel.d.ts +71 -0
- package/dist/extensions/mcp/mcp-panel.d.ts.map +1 -0
- package/dist/extensions/mcp/mcp-panel.js +973 -0
- package/dist/extensions/mcp/mcp-panel.js.map +1 -0
- package/dist/extensions/mcp/mcp-probe.d.ts +7 -0
- package/dist/extensions/mcp/mcp-probe.d.ts.map +1 -0
- package/dist/extensions/mcp/mcp-probe.js +155 -0
- package/dist/extensions/mcp/mcp-probe.js.map +1 -0
- package/dist/extensions/mcp/mcp-script-worker.mjs +130 -0
- package/dist/extensions/mcp/mcp-setup-panel.d.ts +85 -0
- package/dist/extensions/mcp/mcp-setup-panel.d.ts.map +1 -0
- package/dist/extensions/mcp/mcp-setup-panel.js +618 -0
- package/dist/extensions/mcp/mcp-setup-panel.js.map +1 -0
- package/dist/extensions/mcp/mcp-status.d.ts +12 -0
- package/dist/extensions/mcp/mcp-status.d.ts.map +1 -0
- package/dist/extensions/mcp/mcp-status.js +98 -0
- package/dist/extensions/mcp/mcp-status.js.map +1 -0
- package/dist/extensions/mcp/mcp-trace.d.ts +95 -0
- package/dist/extensions/mcp/mcp-trace.d.ts.map +1 -0
- package/dist/extensions/mcp/mcp-trace.js +252 -0
- package/dist/extensions/mcp/mcp-trace.js.map +1 -0
- package/dist/extensions/mcp/metadata-cache.d.ts +20 -0
- package/dist/extensions/mcp/metadata-cache.d.ts.map +1 -0
- package/dist/extensions/mcp/metadata-cache.js +318 -0
- package/dist/extensions/mcp/metadata-cache.js.map +1 -0
- package/dist/extensions/mcp/npx-resolver.d.ts +7 -0
- package/dist/extensions/mcp/npx-resolver.d.ts.map +1 -0
- package/dist/extensions/mcp/npx-resolver.js +505 -0
- package/dist/extensions/mcp/npx-resolver.js.map +1 -0
- package/dist/extensions/mcp/oauth.d.ts +21 -0
- package/dist/extensions/mcp/oauth.d.ts.map +1 -0
- package/dist/extensions/mcp/oauth.js +15 -0
- package/dist/extensions/mcp/oauth.js.map +1 -0
- package/dist/extensions/mcp/onboarding-state.d.ts +13 -0
- package/dist/extensions/mcp/onboarding-state.d.ts.map +1 -0
- package/dist/extensions/mcp/onboarding-state.js +65 -0
- package/dist/extensions/mcp/onboarding-state.js.map +1 -0
- package/dist/extensions/mcp/package-mcp-loader.d.ts +3 -0
- package/dist/extensions/mcp/package-mcp-loader.d.ts.map +1 -0
- package/dist/extensions/mcp/package-mcp-loader.js +170 -0
- package/dist/extensions/mcp/package-mcp-loader.js.map +1 -0
- package/dist/extensions/mcp/panel-keys.d.ts +21 -0
- package/dist/extensions/mcp/panel-keys.d.ts.map +1 -0
- package/dist/extensions/mcp/panel-keys.js +29 -0
- package/dist/extensions/mcp/panel-keys.js.map +1 -0
- package/dist/extensions/mcp/prompts.d.ts +63 -0
- package/dist/extensions/mcp/prompts.d.ts.map +1 -0
- package/dist/extensions/mcp/prompts.js +297 -0
- package/dist/extensions/mcp/prompts.js.map +1 -0
- package/dist/extensions/mcp/proxy-modes.d.ts +15 -0
- package/dist/extensions/mcp/proxy-modes.d.ts.map +1 -0
- package/dist/extensions/mcp/proxy-modes.js +1421 -0
- package/dist/extensions/mcp/proxy-modes.js.map +1 -0
- package/dist/extensions/mcp/request-headers-command.d.ts +11 -0
- package/dist/extensions/mcp/request-headers-command.d.ts.map +1 -0
- package/dist/extensions/mcp/request-headers-command.js +334 -0
- package/dist/extensions/mcp/request-headers-command.js.map +1 -0
- package/dist/extensions/mcp/resource-tools.d.ts +2 -0
- package/dist/extensions/mcp/resource-tools.d.ts.map +1 -0
- package/dist/extensions/mcp/resource-tools.js +15 -0
- package/dist/extensions/mcp/resource-tools.js.map +1 -0
- package/dist/extensions/mcp/runtime-owner.d.ts +14 -0
- package/dist/extensions/mcp/runtime-owner.d.ts.map +1 -0
- package/dist/extensions/mcp/runtime-owner.js +84 -0
- package/dist/extensions/mcp/runtime-owner.js.map +1 -0
- package/dist/extensions/mcp/sampling-handler.d.ts +18 -0
- package/dist/extensions/mcp/sampling-handler.d.ts.map +1 -0
- package/dist/extensions/mcp/sampling-handler.js +229 -0
- package/dist/extensions/mcp/sampling-handler.js.map +1 -0
- package/dist/extensions/mcp/search-ranking.d.ts +25 -0
- package/dist/extensions/mcp/search-ranking.d.ts.map +1 -0
- package/dist/extensions/mcp/search-ranking.js +234 -0
- package/dist/extensions/mcp/search-ranking.js.map +1 -0
- package/dist/extensions/mcp/server-manager.d.ts +116 -0
- package/dist/extensions/mcp/server-manager.d.ts.map +1 -0
- package/dist/extensions/mcp/server-manager.js +1052 -0
- package/dist/extensions/mcp/server-manager.js.map +1 -0
- package/dist/extensions/mcp/session-recovery.d.ts +27 -0
- package/dist/extensions/mcp/session-recovery.d.ts.map +1 -0
- package/dist/extensions/mcp/session-recovery.js +140 -0
- package/dist/extensions/mcp/session-recovery.js.map +1 -0
- package/dist/extensions/mcp/skills/mcp-scripting/SKILL.md +38 -0
- package/dist/extensions/mcp/state.d.ts +62 -0
- package/dist/extensions/mcp/state.d.ts.map +1 -0
- package/dist/extensions/mcp/state.js +2 -0
- package/dist/extensions/mcp/state.js.map +1 -0
- package/dist/extensions/mcp/tool-approval.d.ts +11 -0
- package/dist/extensions/mcp/tool-approval.d.ts.map +1 -0
- package/dist/extensions/mcp/tool-approval.js +156 -0
- package/dist/extensions/mcp/tool-approval.js.map +1 -0
- package/dist/extensions/mcp/tool-metadata.d.ts +11 -0
- package/dist/extensions/mcp/tool-metadata.d.ts.map +1 -0
- package/dist/extensions/mcp/tool-metadata.js +264 -0
- package/dist/extensions/mcp/tool-metadata.js.map +1 -0
- package/dist/extensions/mcp/tool-registrar.d.ts +21 -0
- package/dist/extensions/mcp/tool-registrar.d.ts.map +1 -0
- package/dist/extensions/mcp/tool-registrar.js +229 -0
- package/dist/extensions/mcp/tool-registrar.js.map +1 -0
- package/dist/extensions/mcp/tool-result-renderer.d.ts +83 -0
- package/dist/extensions/mcp/tool-result-renderer.d.ts.map +1 -0
- package/dist/extensions/mcp/tool-result-renderer.js +345 -0
- package/dist/extensions/mcp/tool-result-renderer.js.map +1 -0
- package/dist/extensions/mcp/ts-shape.d.ts +3 -0
- package/dist/extensions/mcp/ts-shape.d.ts.map +1 -0
- package/dist/extensions/mcp/ts-shape.js +160 -0
- package/dist/extensions/mcp/ts-shape.js.map +1 -0
- package/dist/extensions/mcp/types.d.ts +521 -0
- package/dist/extensions/mcp/types.d.ts.map +1 -0
- package/dist/extensions/mcp/types.js +294 -0
- package/dist/extensions/mcp/types.js.map +1 -0
- package/dist/extensions/mcp/ui-app-bridge-helpers.d.ts +7 -0
- package/dist/extensions/mcp/ui-app-bridge-helpers.d.ts.map +1 -0
- package/dist/extensions/mcp/ui-app-bridge-helpers.js +37 -0
- package/dist/extensions/mcp/ui-app-bridge-helpers.js.map +1 -0
- package/dist/extensions/mcp/ui-resource-handler.d.ts +18 -0
- package/dist/extensions/mcp/ui-resource-handler.d.ts.map +1 -0
- package/dist/extensions/mcp/ui-resource-handler.js +210 -0
- package/dist/extensions/mcp/ui-resource-handler.js.map +1 -0
- package/dist/extensions/mcp/ui-server.d.ts +52 -0
- package/dist/extensions/mcp/ui-server.d.ts.map +1 -0
- package/dist/extensions/mcp/ui-server.js +740 -0
- package/dist/extensions/mcp/ui-server.js.map +1 -0
- package/dist/extensions/mcp/ui-session.d.ts +40 -0
- package/dist/extensions/mcp/ui-session.d.ts.map +1 -0
- package/dist/extensions/mcp/ui-session.js +477 -0
- package/dist/extensions/mcp/ui-session.js.map +1 -0
- package/dist/extensions/mcp/ui-stream-types.d.ts +105 -0
- package/dist/extensions/mcp/ui-stream-types.d.ts.map +1 -0
- package/dist/extensions/mcp/ui-stream-types.js +61 -0
- package/dist/extensions/mcp/ui-stream-types.js.map +1 -0
- package/dist/extensions/mcp/ui-tool-visibility.d.ts +5 -0
- package/dist/extensions/mcp/ui-tool-visibility.d.ts.map +1 -0
- package/dist/extensions/mcp/ui-tool-visibility.js +27 -0
- package/dist/extensions/mcp/ui-tool-visibility.js.map +1 -0
- package/dist/extensions/mcp/unix-socket-transport.d.ts +15 -0
- package/dist/extensions/mcp/unix-socket-transport.d.ts.map +1 -0
- package/dist/extensions/mcp/unix-socket-transport.js +85 -0
- package/dist/extensions/mcp/unix-socket-transport.js.map +1 -0
- package/dist/extensions/mcp/utils.d.ts +32 -0
- package/dist/extensions/mcp/utils.d.ts.map +1 -0
- package/dist/extensions/mcp/utils.js +336 -0
- package/dist/extensions/mcp/utils.js.map +1 -0
- package/dist/extensions/subagent/index.d.ts +61 -1
- package/dist/extensions/subagent/index.d.ts.map +1 -1
- package/dist/extensions/subagent/index.js +177 -4
- package/dist/extensions/subagent/index.js.map +1 -1
- package/dist/extensions/web-access.d.ts.map +1 -1
- package/dist/extensions/web-access.js +1 -1
- package/dist/extensions/web-access.js.map +1 -1
- package/dist/index.d.ts +2 -0
- package/dist/index.d.ts.map +1 -1
- package/dist/index.js +20057 -1947
- package/dist/index.js.map +1 -1
- package/dist/mcp-keyring-helper.cjs +89 -0
- package/dist/mcp-script-worker.mjs +130 -0
- package/dist/modes/interactive/components/model-selector.d.ts.map +1 -1
- package/dist/modes/interactive/components/model-selector.js +1 -1
- package/dist/modes/interactive/components/model-selector.js.map +1 -1
- package/dist/modes/interactive/components/response-separator.d.ts +1 -1
- package/dist/modes/interactive/components/response-separator.d.ts.map +1 -1
- package/dist/modes/interactive/components/response-separator.js +1 -1
- package/dist/modes/interactive/components/response-separator.js.map +1 -1
- package/dist/modes/interactive/interactive-mode.d.ts.map +1 -1
- package/dist/modes/interactive/interactive-mode.js +7 -5
- package/dist/modes/interactive/interactive-mode.js.map +1 -1
- package/dist/rpc-entry.js +20263 -2158
- package/dist/skills/mcp-scripting/SKILL.md +38 -0
- package/dist/vendor/ai.js +280 -205
- package/docs/mcp.md +178 -0
- package/docs/pi-subagents.md +75 -0
- package/docs/quickstart.md +1 -1
- package/docs/usage.md +2 -1
- package/examples/extensions/pi-subagents-worker-policy.ts +86 -0
- package/npm-shrinkwrap.json +763 -6
- package/package.json +15 -4
- package/dist/extensions/mcp/client.d.ts +0 -86
- package/dist/extensions/mcp/client.d.ts.map +0 -1
- package/dist/extensions/mcp/client.js +0 -275
- package/dist/extensions/mcp/client.js.map +0 -1
|
@@ -0,0 +1,318 @@
|
|
|
1
|
+
// metadata-cache.ts - Persistent MCP metadata cache
|
|
2
|
+
import { createHash } from "node:crypto";
|
|
3
|
+
import { existsSync, mkdirSync, readFileSync, renameSync, writeFileSync } from "node:fs";
|
|
4
|
+
import { dirname } from "node:path";
|
|
5
|
+
import { getAgentPath } from "./agent-dir.js";
|
|
6
|
+
import { resourceNameToToolName } from "./resource-tools.js";
|
|
7
|
+
import { createToolSelectorCandidateIndex, formatPromptCommandName, formatToolName, getToolNameCandidates, isServerDisabled, isToolAllowed, resolveToolPrefix, } from "./types.js";
|
|
8
|
+
import { getToolUiResourceUri } from "./ui-app-bridge-helpers.js";
|
|
9
|
+
import { extractUiToolVisibility, isUiToolVisibleToModel } from "./ui-tool-visibility.js";
|
|
10
|
+
import { extractToolUiStreamMode, interpolateEnvRecord, interpolateEnvVars, resolveBearerToken, resolveConfigPath, resolveServerUrl, } from "./utils.js";
|
|
11
|
+
const CACHE_VERSION = 1;
|
|
12
|
+
const CACHE_MAX_AGE_MS = 7 * 24 * 60 * 60 * 1000;
|
|
13
|
+
export function getMetadataCachePath() {
|
|
14
|
+
return getAgentPath("mcp-cache.json");
|
|
15
|
+
}
|
|
16
|
+
export function loadMetadataCache() {
|
|
17
|
+
const cachePath = getMetadataCachePath();
|
|
18
|
+
if (!existsSync(cachePath))
|
|
19
|
+
return null;
|
|
20
|
+
try {
|
|
21
|
+
const raw = JSON.parse(readFileSync(cachePath, "utf-8"));
|
|
22
|
+
if (!raw || typeof raw !== "object")
|
|
23
|
+
return null;
|
|
24
|
+
if (raw.version !== CACHE_VERSION)
|
|
25
|
+
return null;
|
|
26
|
+
if (!raw.servers || typeof raw.servers !== "object")
|
|
27
|
+
return null;
|
|
28
|
+
return raw;
|
|
29
|
+
}
|
|
30
|
+
catch {
|
|
31
|
+
return null;
|
|
32
|
+
}
|
|
33
|
+
}
|
|
34
|
+
export function saveMetadataCache(cache) {
|
|
35
|
+
const cachePath = getMetadataCachePath();
|
|
36
|
+
const dir = dirname(cachePath);
|
|
37
|
+
mkdirSync(dir, { recursive: true });
|
|
38
|
+
const merged = { version: CACHE_VERSION, servers: {} };
|
|
39
|
+
try {
|
|
40
|
+
if (existsSync(cachePath)) {
|
|
41
|
+
const existing = JSON.parse(readFileSync(cachePath, "utf-8"));
|
|
42
|
+
if (existing && existing.version === CACHE_VERSION && existing.servers) {
|
|
43
|
+
merged.servers = { ...existing.servers };
|
|
44
|
+
}
|
|
45
|
+
}
|
|
46
|
+
}
|
|
47
|
+
catch {
|
|
48
|
+
// Ignore parse errors and proceed with empty cache
|
|
49
|
+
}
|
|
50
|
+
merged.version = CACHE_VERSION;
|
|
51
|
+
merged.servers = { ...merged.servers, ...cache.servers };
|
|
52
|
+
const tmpPath = `${cachePath}.${process.pid}.tmp`;
|
|
53
|
+
writeFileSync(tmpPath, JSON.stringify(merged), "utf-8");
|
|
54
|
+
renameSync(tmpPath, cachePath);
|
|
55
|
+
}
|
|
56
|
+
export function computeServerHash(definition) {
|
|
57
|
+
// Hash only fields that affect server identity and tool/resource output.
|
|
58
|
+
// Exclude lifecycle, idleTimeout, requestTimeoutMs, debug — those are runtime behavior settings
|
|
59
|
+
// that don't change which tools a server exposes.
|
|
60
|
+
const identity = {
|
|
61
|
+
command: definition.command,
|
|
62
|
+
args: definition.args,
|
|
63
|
+
socket: resolveConfigPath(definition.socket),
|
|
64
|
+
env: interpolateEnvRecord(definition.env),
|
|
65
|
+
cwd: resolveConfigPath(definition.cwd),
|
|
66
|
+
url: resolveServerUrl(definition),
|
|
67
|
+
headers: interpolateEnvRecord(definition.headers),
|
|
68
|
+
requestHeadersCommand: definition.requestHeadersCommand
|
|
69
|
+
? {
|
|
70
|
+
command: interpolateEnvVars(definition.requestHeadersCommand.command),
|
|
71
|
+
args: definition.requestHeadersCommand.args?.map(interpolateEnvVars),
|
|
72
|
+
env: interpolateEnvRecord(definition.requestHeadersCommand.env),
|
|
73
|
+
timeoutMs: definition.requestHeadersCommand.timeoutMs,
|
|
74
|
+
}
|
|
75
|
+
: undefined,
|
|
76
|
+
auth: definition.auth,
|
|
77
|
+
protocolVersion: definition.protocolVersion,
|
|
78
|
+
bearerToken: resolveBearerToken(definition),
|
|
79
|
+
bearerTokenEnv: definition.bearerTokenEnv,
|
|
80
|
+
exposeResources: definition.exposeResources,
|
|
81
|
+
includeTools: definition.includeTools,
|
|
82
|
+
excludeTools: definition.excludeTools,
|
|
83
|
+
};
|
|
84
|
+
const normalized = stableStringify(identity);
|
|
85
|
+
return createHash("sha256").update(normalized).digest("hex");
|
|
86
|
+
}
|
|
87
|
+
export function isServerCacheValid(entry, definition, maxAgeMs = CACHE_MAX_AGE_MS) {
|
|
88
|
+
let configHash;
|
|
89
|
+
try {
|
|
90
|
+
configHash = computeServerHash(definition);
|
|
91
|
+
}
|
|
92
|
+
catch {
|
|
93
|
+
return false;
|
|
94
|
+
}
|
|
95
|
+
if (!entry || entry.configHash !== configHash)
|
|
96
|
+
return false;
|
|
97
|
+
if (!entry.cachedAt || typeof entry.cachedAt !== "number")
|
|
98
|
+
return false;
|
|
99
|
+
if (maxAgeMs > 0 && Date.now() - entry.cachedAt > maxAgeMs)
|
|
100
|
+
return false;
|
|
101
|
+
return true;
|
|
102
|
+
}
|
|
103
|
+
export function parseDirectToolSelectors(selectors) {
|
|
104
|
+
const servers = new Set();
|
|
105
|
+
const tools = new Map();
|
|
106
|
+
for (let selector of selectors) {
|
|
107
|
+
selector = selector.replace(/\/+$/, "");
|
|
108
|
+
if (selector.includes("/")) {
|
|
109
|
+
const [server, tool] = selector.split("/", 2);
|
|
110
|
+
if (server && tool) {
|
|
111
|
+
const serverTools = tools.get(server) ?? new Set();
|
|
112
|
+
serverTools.add(tool);
|
|
113
|
+
tools.set(server, serverTools);
|
|
114
|
+
}
|
|
115
|
+
else if (server) {
|
|
116
|
+
servers.add(server);
|
|
117
|
+
}
|
|
118
|
+
}
|
|
119
|
+
else if (selector) {
|
|
120
|
+
servers.add(selector);
|
|
121
|
+
}
|
|
122
|
+
}
|
|
123
|
+
return { servers, tools };
|
|
124
|
+
}
|
|
125
|
+
export function getMissingConfiguredDirectToolServers(config, cache, envOverride) {
|
|
126
|
+
const missing = [];
|
|
127
|
+
const globalDirect = config.settings?.directTools;
|
|
128
|
+
const envSelection = envOverride ? parseDirectToolSelectors(envOverride) : null;
|
|
129
|
+
for (const [serverName, definition] of Object.entries(config.mcpServers)) {
|
|
130
|
+
if (isServerDisabled(definition))
|
|
131
|
+
continue;
|
|
132
|
+
const hasDirectTools = envSelection
|
|
133
|
+
? envSelection.servers.has(serverName) || envSelection.tools.has(serverName)
|
|
134
|
+
: definition.directTools !== undefined
|
|
135
|
+
? !!definition.directTools
|
|
136
|
+
: !!globalDirect;
|
|
137
|
+
if (!hasDirectTools)
|
|
138
|
+
continue;
|
|
139
|
+
const serverCache = cache?.servers?.[serverName];
|
|
140
|
+
if (!serverCache || !isServerCacheValid(serverCache, definition)) {
|
|
141
|
+
missing.push(serverName);
|
|
142
|
+
}
|
|
143
|
+
}
|
|
144
|
+
return missing;
|
|
145
|
+
}
|
|
146
|
+
export function reconstructToolMetadata(serverName, entry, prefix, definition, configuredServers, cache, sharedSelectorCandidateIndex) {
|
|
147
|
+
const metadata = [];
|
|
148
|
+
const seenNames = new Set();
|
|
149
|
+
const effectivePrefix = resolveToolPrefix(definition, prefix);
|
|
150
|
+
const hasToolFilters = (Array.isArray(definition.includeTools) && definition.includeTools.length > 0) ||
|
|
151
|
+
(Array.isArray(definition.excludeTools) && definition.excludeTools.length > 0);
|
|
152
|
+
const selectorCandidateIndex = hasToolFilters
|
|
153
|
+
? (sharedSelectorCandidateIndex ??
|
|
154
|
+
(configuredServers && cache
|
|
155
|
+
? createCachedToolSelectorCandidateIndex(configuredServers, cache, prefix)
|
|
156
|
+
: undefined))
|
|
157
|
+
: undefined;
|
|
158
|
+
for (const tool of entry.tools ?? []) {
|
|
159
|
+
if (!tool?.name)
|
|
160
|
+
continue;
|
|
161
|
+
if (!isUiToolVisibleToModel(tool.uiVisibility)) {
|
|
162
|
+
continue;
|
|
163
|
+
}
|
|
164
|
+
if (!isToolAllowed(tool.name, serverName, effectivePrefix, definition.includeTools, definition.excludeTools, selectorCandidateIndex)) {
|
|
165
|
+
continue;
|
|
166
|
+
}
|
|
167
|
+
const name = formatToolName(tool.name, serverName, effectivePrefix);
|
|
168
|
+
if (seenNames.has(name)) {
|
|
169
|
+
continue;
|
|
170
|
+
}
|
|
171
|
+
seenNames.add(name);
|
|
172
|
+
metadata.push({
|
|
173
|
+
name,
|
|
174
|
+
originalName: tool.name,
|
|
175
|
+
description: tool.description ?? "",
|
|
176
|
+
...(tool.inputSchema !== undefined ? { inputSchema: tool.inputSchema } : {}),
|
|
177
|
+
...(tool.uiResourceUri !== undefined ? { uiResourceUri: tool.uiResourceUri } : {}),
|
|
178
|
+
...(tool.uiVisibility !== undefined ? { uiVisibility: tool.uiVisibility } : {}),
|
|
179
|
+
...(tool.uiStreamMode !== undefined ? { uiStreamMode: tool.uiStreamMode } : {}),
|
|
180
|
+
});
|
|
181
|
+
}
|
|
182
|
+
if (definition.exposeResources !== false) {
|
|
183
|
+
for (const resource of entry.resources ?? []) {
|
|
184
|
+
if (!resource?.name || !resource?.uri)
|
|
185
|
+
continue;
|
|
186
|
+
const baseName = `read_${resourceNameToToolName(resource.name)}`;
|
|
187
|
+
if (!isToolAllowed(baseName, serverName, effectivePrefix, definition.includeTools, definition.excludeTools, selectorCandidateIndex)) {
|
|
188
|
+
continue;
|
|
189
|
+
}
|
|
190
|
+
const name = formatToolName(baseName, serverName, effectivePrefix);
|
|
191
|
+
if (seenNames.has(name)) {
|
|
192
|
+
continue;
|
|
193
|
+
}
|
|
194
|
+
seenNames.add(name);
|
|
195
|
+
metadata.push({
|
|
196
|
+
name,
|
|
197
|
+
originalName: baseName,
|
|
198
|
+
description: resource.description ?? `Read resource: ${resource.uri}`,
|
|
199
|
+
resourceUri: resource.uri,
|
|
200
|
+
});
|
|
201
|
+
}
|
|
202
|
+
}
|
|
203
|
+
return metadata;
|
|
204
|
+
}
|
|
205
|
+
export function createCachedToolSelectorCandidateIndex(configuredServers, cache, prefix) {
|
|
206
|
+
const candidates = new Set();
|
|
207
|
+
for (const [serverName, definition] of Object.entries(configuredServers)) {
|
|
208
|
+
const entry = cache.servers[serverName];
|
|
209
|
+
if (!entry || !isServerCacheValid(entry, definition) || isServerDisabled(definition))
|
|
210
|
+
continue;
|
|
211
|
+
const effectivePrefix = resolveToolPrefix(definition, prefix);
|
|
212
|
+
for (const tool of entry.tools ?? []) {
|
|
213
|
+
if (!isUiToolVisibleToModel(tool.uiVisibility))
|
|
214
|
+
continue;
|
|
215
|
+
for (const candidate of getToolNameCandidates(tool.name, serverName, effectivePrefix, false))
|
|
216
|
+
candidates.add(candidate);
|
|
217
|
+
}
|
|
218
|
+
if (definition.exposeResources !== false) {
|
|
219
|
+
for (const resource of entry.resources ?? []) {
|
|
220
|
+
const baseName = `read_${resourceNameToToolName(resource.name)}`;
|
|
221
|
+
for (const candidate of getToolNameCandidates(baseName, serverName, effectivePrefix, false))
|
|
222
|
+
candidates.add(candidate);
|
|
223
|
+
}
|
|
224
|
+
}
|
|
225
|
+
}
|
|
226
|
+
return createToolSelectorCandidateIndex(candidates);
|
|
227
|
+
}
|
|
228
|
+
export function serializeTools(tools) {
|
|
229
|
+
return tools
|
|
230
|
+
.filter((t) => t?.name)
|
|
231
|
+
.map((t) => {
|
|
232
|
+
const uiResourceUri = tryGetToolUiResourceUri(t);
|
|
233
|
+
const uiVisibility = extractUiToolVisibility(t._meta);
|
|
234
|
+
const uiStreamMode = extractToolUiStreamMode(t._meta);
|
|
235
|
+
return {
|
|
236
|
+
name: t.name,
|
|
237
|
+
...(t.description !== undefined ? { description: t.description } : {}),
|
|
238
|
+
...(t.inputSchema !== undefined ? { inputSchema: t.inputSchema } : {}),
|
|
239
|
+
...(uiResourceUri !== undefined ? { uiResourceUri } : {}),
|
|
240
|
+
...(uiVisibility !== undefined ? { uiVisibility } : {}),
|
|
241
|
+
...(uiStreamMode !== undefined ? { uiStreamMode } : {}),
|
|
242
|
+
};
|
|
243
|
+
});
|
|
244
|
+
}
|
|
245
|
+
export function serializeResources(resources) {
|
|
246
|
+
return resources
|
|
247
|
+
.filter((r) => r?.name && r?.uri)
|
|
248
|
+
.map((r) => ({
|
|
249
|
+
uri: r.uri,
|
|
250
|
+
name: r.name,
|
|
251
|
+
...(r.description !== undefined ? { description: r.description } : {}),
|
|
252
|
+
}));
|
|
253
|
+
}
|
|
254
|
+
export function serializePrompts(prompts) {
|
|
255
|
+
return (prompts ?? [])
|
|
256
|
+
.filter((prompt) => prompt?.name)
|
|
257
|
+
.map((prompt) => ({
|
|
258
|
+
name: prompt.name,
|
|
259
|
+
...(prompt.title !== undefined ? { title: prompt.title } : {}),
|
|
260
|
+
...(prompt.description !== undefined ? { description: prompt.description } : {}),
|
|
261
|
+
...(Array.isArray(prompt.arguments)
|
|
262
|
+
? {
|
|
263
|
+
arguments: prompt.arguments
|
|
264
|
+
.filter((argument) => argument?.name)
|
|
265
|
+
.map((argument) => ({
|
|
266
|
+
name: argument.name,
|
|
267
|
+
...(argument.description !== undefined ? { description: argument.description } : {}),
|
|
268
|
+
...(argument.required !== undefined ? { required: argument.required } : {}),
|
|
269
|
+
})),
|
|
270
|
+
}
|
|
271
|
+
: {}),
|
|
272
|
+
}));
|
|
273
|
+
}
|
|
274
|
+
export function reconstructPromptMetadata(serverName, prompts, prefix, definition) {
|
|
275
|
+
const effectivePrefix = resolveToolPrefix(definition, prefix);
|
|
276
|
+
return (prompts ?? [])
|
|
277
|
+
.filter((prompt) => prompt?.name)
|
|
278
|
+
.map((prompt) => {
|
|
279
|
+
const args = Array.isArray(prompt.arguments)
|
|
280
|
+
? prompt.arguments
|
|
281
|
+
.filter((argument) => argument?.name)
|
|
282
|
+
.map((argument) => ({
|
|
283
|
+
name: argument.name,
|
|
284
|
+
...(argument.description !== undefined ? { description: argument.description } : {}),
|
|
285
|
+
...(argument.required !== undefined ? { required: argument.required } : {}),
|
|
286
|
+
}))
|
|
287
|
+
: [];
|
|
288
|
+
return {
|
|
289
|
+
serverName,
|
|
290
|
+
originalName: prompt.name,
|
|
291
|
+
commandName: formatPromptCommandName(prompt.name, serverName, effectivePrefix),
|
|
292
|
+
...(prompt.title !== undefined ? { title: prompt.title } : {}),
|
|
293
|
+
description: prompt.description ?? "",
|
|
294
|
+
arguments: args,
|
|
295
|
+
};
|
|
296
|
+
});
|
|
297
|
+
}
|
|
298
|
+
function stableStringify(value) {
|
|
299
|
+
if (value === null || value === undefined || typeof value !== "object") {
|
|
300
|
+
const serialized = JSON.stringify(value);
|
|
301
|
+
return serialized === undefined ? "undefined" : serialized;
|
|
302
|
+
}
|
|
303
|
+
if (Array.isArray(value)) {
|
|
304
|
+
return `[${value.map((v) => stableStringify(v)).join(",")}]`;
|
|
305
|
+
}
|
|
306
|
+
const obj = value;
|
|
307
|
+
const keys = Object.keys(obj).sort();
|
|
308
|
+
return `{${keys.map((k) => `${JSON.stringify(k)}:${stableStringify(obj[k])}`).join(",")}}`;
|
|
309
|
+
}
|
|
310
|
+
function tryGetToolUiResourceUri(tool) {
|
|
311
|
+
try {
|
|
312
|
+
return getToolUiResourceUri({ _meta: tool._meta });
|
|
313
|
+
}
|
|
314
|
+
catch {
|
|
315
|
+
return undefined;
|
|
316
|
+
}
|
|
317
|
+
}
|
|
318
|
+
//# sourceMappingURL=metadata-cache.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"metadata-cache.js","sourceRoot":"","sources":["../../../src/extensions/mcp/metadata-cache.ts"],"names":[],"mappings":"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","sourcesContent":["// metadata-cache.ts - Persistent MCP metadata cache\n\nimport { createHash } from \"node:crypto\";\nimport { existsSync, mkdirSync, readFileSync, renameSync, writeFileSync } from \"node:fs\";\nimport { dirname } from \"node:path\";\nimport { getAgentPath } from \"./agent-dir.ts\";\nimport { resourceNameToToolName } from \"./resource-tools.ts\";\nimport type {\n\tCachedPrompt,\n\tCachedResource,\n\tCachedTool,\n\tMcpConfig,\n\tMcpPrompt,\n\tMcpPromptArgument,\n\tMcpResource,\n\tMcpTool,\n\tMetadataCache,\n\tPromptMetadata,\n\tServerCacheEntry,\n\tServerEntry,\n\tToolMetadata,\n} from \"./types.ts\";\nimport {\n\tcreateToolSelectorCandidateIndex,\n\tformatPromptCommandName,\n\tformatToolName,\n\tgetToolNameCandidates,\n\tisServerDisabled,\n\tisToolAllowed,\n\tresolveToolPrefix,\n\ttype ToolPrefix,\n\ttype ToolSelectorCandidateIndex,\n} from \"./types.ts\";\nimport { getToolUiResourceUri } from \"./ui-app-bridge-helpers.ts\";\nimport { extractUiToolVisibility, isUiToolVisibleToModel } from \"./ui-tool-visibility.ts\";\nimport {\n\textractToolUiStreamMode,\n\tinterpolateEnvRecord,\n\tinterpolateEnvVars,\n\tresolveBearerToken,\n\tresolveConfigPath,\n\tresolveServerUrl,\n} from \"./utils.ts\";\n\nconst CACHE_VERSION = 1;\nconst CACHE_MAX_AGE_MS = 7 * 24 * 60 * 60 * 1000;\n\nexport type { CachedPrompt, CachedResource, CachedTool, MetadataCache, ServerCacheEntry } from \"./types.ts\";\n\nexport function getMetadataCachePath(): string {\n\treturn getAgentPath(\"mcp-cache.json\");\n}\n\nexport function loadMetadataCache(): MetadataCache | null {\n\tconst cachePath = getMetadataCachePath();\n\tif (!existsSync(cachePath)) return null;\n\ttry {\n\t\tconst raw = JSON.parse(readFileSync(cachePath, \"utf-8\"));\n\t\tif (!raw || typeof raw !== \"object\") return null;\n\t\tif (raw.version !== CACHE_VERSION) return null;\n\t\tif (!raw.servers || typeof raw.servers !== \"object\") return null;\n\t\treturn raw as MetadataCache;\n\t} catch {\n\t\treturn null;\n\t}\n}\n\nexport function saveMetadataCache(cache: MetadataCache): void {\n\tconst cachePath = getMetadataCachePath();\n\tconst dir = dirname(cachePath);\n\tmkdirSync(dir, { recursive: true });\n\n\tconst merged: MetadataCache = { version: CACHE_VERSION, servers: {} };\n\ttry {\n\t\tif (existsSync(cachePath)) {\n\t\t\tconst existing = JSON.parse(readFileSync(cachePath, \"utf-8\")) as MetadataCache;\n\t\t\tif (existing && existing.version === CACHE_VERSION && existing.servers) {\n\t\t\t\tmerged.servers = { ...existing.servers };\n\t\t\t}\n\t\t}\n\t} catch {\n\t\t// Ignore parse errors and proceed with empty cache\n\t}\n\n\tmerged.version = CACHE_VERSION;\n\tmerged.servers = { ...merged.servers, ...cache.servers };\n\n\tconst tmpPath = `${cachePath}.${process.pid}.tmp`;\n\twriteFileSync(tmpPath, JSON.stringify(merged), \"utf-8\");\n\trenameSync(tmpPath, cachePath);\n}\n\nexport function computeServerHash(definition: ServerEntry): string {\n\t// Hash only fields that affect server identity and tool/resource output.\n\t// Exclude lifecycle, idleTimeout, requestTimeoutMs, debug — those are runtime behavior settings\n\t// that don't change which tools a server exposes.\n\tconst identity: Record<string, unknown> = {\n\t\tcommand: definition.command,\n\t\targs: definition.args,\n\t\tsocket: resolveConfigPath(definition.socket),\n\t\tenv: interpolateEnvRecord(definition.env),\n\t\tcwd: resolveConfigPath(definition.cwd),\n\t\turl: resolveServerUrl(definition),\n\t\theaders: interpolateEnvRecord(definition.headers),\n\t\trequestHeadersCommand: definition.requestHeadersCommand\n\t\t\t? {\n\t\t\t\t\tcommand: interpolateEnvVars(definition.requestHeadersCommand.command),\n\t\t\t\t\targs: definition.requestHeadersCommand.args?.map(interpolateEnvVars),\n\t\t\t\t\tenv: interpolateEnvRecord(definition.requestHeadersCommand.env),\n\t\t\t\t\ttimeoutMs: definition.requestHeadersCommand.timeoutMs,\n\t\t\t\t}\n\t\t\t: undefined,\n\t\tauth: definition.auth,\n\t\tprotocolVersion: definition.protocolVersion,\n\t\tbearerToken: resolveBearerToken(definition),\n\t\tbearerTokenEnv: definition.bearerTokenEnv,\n\t\texposeResources: definition.exposeResources,\n\t\tincludeTools: definition.includeTools,\n\t\texcludeTools: definition.excludeTools,\n\t};\n\tconst normalized = stableStringify(identity);\n\treturn createHash(\"sha256\").update(normalized).digest(\"hex\");\n}\n\nexport function isServerCacheValid(\n\tentry: ServerCacheEntry,\n\tdefinition: ServerEntry,\n\tmaxAgeMs: number = CACHE_MAX_AGE_MS,\n): boolean {\n\tlet configHash: string;\n\ttry {\n\t\tconfigHash = computeServerHash(definition);\n\t} catch {\n\t\treturn false;\n\t}\n\tif (!entry || entry.configHash !== configHash) return false;\n\tif (!entry.cachedAt || typeof entry.cachedAt !== \"number\") return false;\n\tif (maxAgeMs > 0 && Date.now() - entry.cachedAt > maxAgeMs) return false;\n\treturn true;\n}\n\nexport function parseDirectToolSelectors(selectors: string[]): {\n\tservers: Set<string>;\n\ttools: Map<string, Set<string>>;\n} {\n\tconst servers = new Set<string>();\n\tconst tools = new Map<string, Set<string>>();\n\n\tfor (let selector of selectors) {\n\t\tselector = selector.replace(/\\/+$/, \"\");\n\t\tif (selector.includes(\"/\")) {\n\t\t\tconst [server, tool] = selector.split(\"/\", 2);\n\t\t\tif (server && tool) {\n\t\t\t\tconst serverTools = tools.get(server) ?? new Set<string>();\n\t\t\t\tserverTools.add(tool);\n\t\t\t\ttools.set(server, serverTools);\n\t\t\t} else if (server) {\n\t\t\t\tservers.add(server);\n\t\t\t}\n\t\t} else if (selector) {\n\t\t\tservers.add(selector);\n\t\t}\n\t}\n\n\treturn { servers, tools };\n}\n\nexport function getMissingConfiguredDirectToolServers(\n\tconfig: McpConfig,\n\tcache: MetadataCache | null,\n\tenvOverride?: string[],\n): string[] {\n\tconst missing: string[] = [];\n\tconst globalDirect = config.settings?.directTools;\n\tconst envSelection = envOverride ? parseDirectToolSelectors(envOverride) : null;\n\n\tfor (const [serverName, definition] of Object.entries(config.mcpServers)) {\n\t\tif (isServerDisabled(definition)) continue;\n\t\tconst hasDirectTools = envSelection\n\t\t\t? envSelection.servers.has(serverName) || envSelection.tools.has(serverName)\n\t\t\t: definition.directTools !== undefined\n\t\t\t\t? !!definition.directTools\n\t\t\t\t: !!globalDirect;\n\n\t\tif (!hasDirectTools) continue;\n\n\t\tconst serverCache = cache?.servers?.[serverName];\n\t\tif (!serverCache || !isServerCacheValid(serverCache, definition)) {\n\t\t\tmissing.push(serverName);\n\t\t}\n\t}\n\n\treturn missing;\n}\n\nexport function reconstructToolMetadata(\n\tserverName: string,\n\tentry: ServerCacheEntry,\n\tprefix: ToolPrefix,\n\tdefinition: Pick<ServerEntry, \"exposeResources\" | \"includeTools\" | \"excludeTools\" | \"toolPrefix\">,\n\tconfiguredServers?: Record<string, ServerEntry>,\n\tcache?: MetadataCache,\n\tsharedSelectorCandidateIndex?: ToolSelectorCandidateIndex,\n): ToolMetadata[] {\n\tconst metadata: ToolMetadata[] = [];\n\tconst seenNames = new Set<string>();\n\tconst effectivePrefix = resolveToolPrefix(definition, prefix);\n\tconst hasToolFilters =\n\t\t(Array.isArray(definition.includeTools) && definition.includeTools.length > 0) ||\n\t\t(Array.isArray(definition.excludeTools) && definition.excludeTools.length > 0);\n\tconst selectorCandidateIndex = hasToolFilters\n\t\t? (sharedSelectorCandidateIndex ??\n\t\t\t(configuredServers && cache\n\t\t\t\t? createCachedToolSelectorCandidateIndex(configuredServers, cache, prefix)\n\t\t\t\t: undefined))\n\t\t: undefined;\n\n\tfor (const tool of entry.tools ?? []) {\n\t\tif (!tool?.name) continue;\n\t\tif (!isUiToolVisibleToModel(tool.uiVisibility)) {\n\t\t\tcontinue;\n\t\t}\n\t\tif (\n\t\t\t!isToolAllowed(\n\t\t\t\ttool.name,\n\t\t\t\tserverName,\n\t\t\t\teffectivePrefix,\n\t\t\t\tdefinition.includeTools,\n\t\t\t\tdefinition.excludeTools,\n\t\t\t\tselectorCandidateIndex,\n\t\t\t)\n\t\t) {\n\t\t\tcontinue;\n\t\t}\n\n\t\tconst name = formatToolName(tool.name, serverName, effectivePrefix);\n\t\tif (seenNames.has(name)) {\n\t\t\tcontinue;\n\t\t}\n\t\tseenNames.add(name);\n\n\t\tmetadata.push({\n\t\t\tname,\n\t\t\toriginalName: tool.name,\n\t\t\tdescription: tool.description ?? \"\",\n\t\t\t...(tool.inputSchema !== undefined ? { inputSchema: tool.inputSchema } : {}),\n\t\t\t...(tool.uiResourceUri !== undefined ? { uiResourceUri: tool.uiResourceUri } : {}),\n\t\t\t...(tool.uiVisibility !== undefined ? { uiVisibility: tool.uiVisibility } : {}),\n\t\t\t...(tool.uiStreamMode !== undefined ? { uiStreamMode: tool.uiStreamMode } : {}),\n\t\t});\n\t}\n\n\tif (definition.exposeResources !== false) {\n\t\tfor (const resource of entry.resources ?? []) {\n\t\t\tif (!resource?.name || !resource?.uri) continue;\n\t\t\tconst baseName = `read_${resourceNameToToolName(resource.name)}`;\n\t\t\tif (\n\t\t\t\t!isToolAllowed(\n\t\t\t\t\tbaseName,\n\t\t\t\t\tserverName,\n\t\t\t\t\teffectivePrefix,\n\t\t\t\t\tdefinition.includeTools,\n\t\t\t\t\tdefinition.excludeTools,\n\t\t\t\t\tselectorCandidateIndex,\n\t\t\t\t)\n\t\t\t) {\n\t\t\t\tcontinue;\n\t\t\t}\n\n\t\t\tconst name = formatToolName(baseName, serverName, effectivePrefix);\n\t\t\tif (seenNames.has(name)) {\n\t\t\t\tcontinue;\n\t\t\t}\n\t\t\tseenNames.add(name);\n\n\t\t\tmetadata.push({\n\t\t\t\tname,\n\t\t\t\toriginalName: baseName,\n\t\t\t\tdescription: resource.description ?? `Read resource: ${resource.uri}`,\n\t\t\t\tresourceUri: resource.uri,\n\t\t\t});\n\t\t}\n\t}\n\n\treturn metadata;\n}\n\nexport function createCachedToolSelectorCandidateIndex(\n\tconfiguredServers: Record<string, ServerEntry>,\n\tcache: MetadataCache,\n\tprefix: ToolPrefix,\n): ToolSelectorCandidateIndex {\n\tconst candidates = new Set<string>();\n\tfor (const [serverName, definition] of Object.entries(configuredServers)) {\n\t\tconst entry = cache.servers[serverName];\n\t\tif (!entry || !isServerCacheValid(entry, definition) || isServerDisabled(definition)) continue;\n\t\tconst effectivePrefix = resolveToolPrefix(definition, prefix);\n\t\tfor (const tool of entry.tools ?? []) {\n\t\t\tif (!isUiToolVisibleToModel(tool.uiVisibility)) continue;\n\t\t\tfor (const candidate of getToolNameCandidates(tool.name, serverName, effectivePrefix, false))\n\t\t\t\tcandidates.add(candidate);\n\t\t}\n\t\tif (definition.exposeResources !== false) {\n\t\t\tfor (const resource of entry.resources ?? []) {\n\t\t\t\tconst baseName = `read_${resourceNameToToolName(resource.name)}`;\n\t\t\t\tfor (const candidate of getToolNameCandidates(baseName, serverName, effectivePrefix, false))\n\t\t\t\t\tcandidates.add(candidate);\n\t\t\t}\n\t\t}\n\t}\n\treturn createToolSelectorCandidateIndex(candidates);\n}\n\nexport function serializeTools(tools: McpTool[]): CachedTool[] {\n\treturn tools\n\t\t.filter((t) => t?.name)\n\t\t.map((t) => {\n\t\t\tconst uiResourceUri = tryGetToolUiResourceUri(t);\n\t\t\tconst uiVisibility = extractUiToolVisibility(t._meta);\n\t\t\tconst uiStreamMode = extractToolUiStreamMode(t._meta);\n\t\t\treturn {\n\t\t\t\tname: t.name,\n\t\t\t\t...(t.description !== undefined ? { description: t.description } : {}),\n\t\t\t\t...(t.inputSchema !== undefined ? { inputSchema: t.inputSchema } : {}),\n\t\t\t\t...(uiResourceUri !== undefined ? { uiResourceUri } : {}),\n\t\t\t\t...(uiVisibility !== undefined ? { uiVisibility } : {}),\n\t\t\t\t...(uiStreamMode !== undefined ? { uiStreamMode } : {}),\n\t\t\t};\n\t\t});\n}\n\nexport function serializeResources(resources: McpResource[]): CachedResource[] {\n\treturn resources\n\t\t.filter((r) => r?.name && r?.uri)\n\t\t.map((r) => ({\n\t\t\turi: r.uri,\n\t\t\tname: r.name,\n\t\t\t...(r.description !== undefined ? { description: r.description } : {}),\n\t\t}));\n}\n\nexport function serializePrompts(prompts: McpPrompt[]): CachedPrompt[] {\n\treturn (prompts ?? [])\n\t\t.filter((prompt) => prompt?.name)\n\t\t.map((prompt) => ({\n\t\t\tname: prompt.name,\n\t\t\t...(prompt.title !== undefined ? { title: prompt.title } : {}),\n\t\t\t...(prompt.description !== undefined ? { description: prompt.description } : {}),\n\t\t\t...(Array.isArray(prompt.arguments)\n\t\t\t\t? {\n\t\t\t\t\t\targuments: prompt.arguments\n\t\t\t\t\t\t\t.filter((argument) => argument?.name)\n\t\t\t\t\t\t\t.map((argument) => ({\n\t\t\t\t\t\t\t\tname: argument.name,\n\t\t\t\t\t\t\t\t...(argument.description !== undefined ? { description: argument.description } : {}),\n\t\t\t\t\t\t\t\t...(argument.required !== undefined ? { required: argument.required } : {}),\n\t\t\t\t\t\t\t})),\n\t\t\t\t\t}\n\t\t\t\t: {}),\n\t\t}));\n}\n\nexport function reconstructPromptMetadata(\n\tserverName: string,\n\tprompts: ReadonlyArray<McpPrompt | CachedPrompt>,\n\tprefix: ToolPrefix,\n\tdefinition?: Pick<ServerEntry, \"toolPrefix\">,\n): PromptMetadata[] {\n\tconst effectivePrefix = resolveToolPrefix(definition, prefix);\n\treturn (prompts ?? [])\n\t\t.filter((prompt) => prompt?.name)\n\t\t.map((prompt) => {\n\t\t\tconst args: McpPromptArgument[] = Array.isArray(prompt.arguments)\n\t\t\t\t? prompt.arguments\n\t\t\t\t\t\t.filter((argument) => argument?.name)\n\t\t\t\t\t\t.map((argument) => ({\n\t\t\t\t\t\t\tname: argument.name,\n\t\t\t\t\t\t\t...(argument.description !== undefined ? { description: argument.description } : {}),\n\t\t\t\t\t\t\t...(argument.required !== undefined ? { required: argument.required } : {}),\n\t\t\t\t\t\t}))\n\t\t\t\t: [];\n\t\t\treturn {\n\t\t\t\tserverName,\n\t\t\t\toriginalName: prompt.name,\n\t\t\t\tcommandName: formatPromptCommandName(prompt.name, serverName, effectivePrefix),\n\t\t\t\t...(prompt.title !== undefined ? { title: prompt.title } : {}),\n\t\t\t\tdescription: prompt.description ?? \"\",\n\t\t\t\targuments: args,\n\t\t\t};\n\t\t});\n}\n\nfunction stableStringify(value: unknown): string {\n\tif (value === null || value === undefined || typeof value !== \"object\") {\n\t\tconst serialized = JSON.stringify(value);\n\t\treturn serialized === undefined ? \"undefined\" : serialized;\n\t}\n\tif (Array.isArray(value)) {\n\t\treturn `[${value.map((v) => stableStringify(v)).join(\",\")}]`;\n\t}\n\tconst obj = value as Record<string, unknown>;\n\tconst keys = Object.keys(obj).sort();\n\treturn `{${keys.map((k) => `${JSON.stringify(k)}:${stableStringify(obj[k])}`).join(\",\")}}`;\n}\n\nfunction tryGetToolUiResourceUri(tool: McpTool): string | undefined {\n\ttry {\n\t\treturn getToolUiResourceUri({ _meta: tool._meta });\n\t} catch {\n\t\treturn undefined;\n\t}\n}\n"]}
|
|
@@ -0,0 +1,7 @@
|
|
|
1
|
+
export interface NpxResolution {
|
|
2
|
+
binPath: string;
|
|
3
|
+
extraArgs: string[];
|
|
4
|
+
isJs: boolean;
|
|
5
|
+
}
|
|
6
|
+
export declare function resolveNpxBinary(command: string, args: string[], signal?: AbortSignal): Promise<NpxResolution | null>;
|
|
7
|
+
//# sourceMappingURL=npx-resolver.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"npx-resolver.d.ts","sourceRoot":"","sources":["../../../src/extensions/mcp/npx-resolver.ts"],"names":[],"mappings":"AAoCA,MAAM,WAAW,aAAa;IAC7B,OAAO,EAAE,MAAM,CAAC;IAChB,SAAS,EAAE,MAAM,EAAE,CAAC;IACpB,IAAI,EAAE,OAAO,CAAC;CACd;AAaD,wBAAsB,gBAAgB,CACrC,OAAO,EAAE,MAAM,EACf,IAAI,EAAE,MAAM,EAAE,EACd,MAAM,CAAC,EAAE,WAAW,GAClB,OAAO,CAAC,aAAa,GAAG,IAAI,CAAC,CAuC/B","sourcesContent":["// npx-resolver.ts - Resolve npx/npm exec binaries to avoid npm parent processes\nimport {\n\tcloseSync,\n\texistsSync,\n\tmkdirSync,\n\topenSync,\n\treaddirSync,\n\treadFileSync,\n\treadSync,\n\trealpathSync,\n\trenameSync,\n\tstatSync,\n\tunlinkSync,\n\twriteFileSync,\n} from \"node:fs\";\nimport { dirname, extname, join, resolve, sep } from \"node:path\";\nimport crossSpawn from \"cross-spawn\";\nimport { throwIfAborted } from \"./abort.ts\";\nimport { getAgentPath } from \"./agent-dir.ts\";\n\nconst CACHE_VERSION = 2;\nconst CACHE_TTL_MS = 24 * 60 * 60 * 1000;\nconst EXACT_PACKAGE_VERSION_RE = /^\\d+\\.\\d+\\.\\d+(?:-[0-9A-Za-z][0-9A-Za-z.-]*)?(?:\\+[0-9A-Za-z][0-9A-Za-z.-]*)?$/;\n\ninterface NpxCacheEntry {\n\tresolvedBin: string;\n\tresolvedAt: number;\n\tpackageVersion?: string;\n\tisJs: boolean;\n}\n\ninterface NpxCache {\n\tversion: number;\n\tentries: Record<string, NpxCacheEntry>;\n}\n\nexport interface NpxResolution {\n\tbinPath: string;\n\textraArgs: string[];\n\tisJs: boolean;\n}\n\ninterface ParsedInvocation {\n\tpackageSpec: string;\n\tbinName?: string;\n\textraArgs: string[];\n}\n\ninterface ParsedPackageSpec {\n\tpackageName: string;\n\texactVersion?: string;\n}\n\nexport async function resolveNpxBinary(\n\tcommand: string,\n\targs: string[],\n\tsignal?: AbortSignal,\n): Promise<NpxResolution | null> {\n\tthrowIfAborted(signal);\n\tconst parsed = command === \"npx\" ? parseNpxArgs(args) : command === \"npm\" ? parseNpmExecArgs(args) : null;\n\n\tif (!parsed) return null;\n\n\tconst packageSpec = parsePackageSpec(parsed.packageSpec);\n\tconst cacheKey = JSON.stringify([command, parsed.packageSpec, parsed.binName ?? \"\"]);\n\tconst cache = loadCache();\n\tconst cached = cache?.entries?.[cacheKey];\n\n\tif (\n\t\tcached &&\n\t\tDate.now() - cached.resolvedAt < CACHE_TTL_MS &&\n\t\texistsSync(cached.resolvedBin) &&\n\t\t(!packageSpec?.exactVersion || cached.packageVersion === packageSpec.exactVersion)\n\t) {\n\t\treturn { binPath: cached.resolvedBin, extraArgs: parsed.extraArgs, isJs: cached.isJs };\n\t}\n\n\tconst resolved = resolveFromNpmCache(parsed.packageSpec, parsed.binName);\n\tif (resolved) {\n\t\tsaveCacheEntry(cacheKey, resolved);\n\t\treturn { binPath: resolved.resolvedBin, extraArgs: parsed.extraArgs, isJs: resolved.isJs };\n\t}\n\n\t// Slow path: force npx cache population\n\tawait forceNpxCache(parsed.packageSpec, signal);\n\tconst resolvedAfterInstall = resolveFromNpmCache(parsed.packageSpec, parsed.binName);\n\tif (resolvedAfterInstall) {\n\t\tsaveCacheEntry(cacheKey, resolvedAfterInstall);\n\t\treturn {\n\t\t\tbinPath: resolvedAfterInstall.resolvedBin,\n\t\t\textraArgs: parsed.extraArgs,\n\t\t\tisJs: resolvedAfterInstall.isJs,\n\t\t};\n\t}\n\n\treturn null;\n}\n\nfunction parseNpxArgs(args: string[]): ParsedInvocation | null {\n\tconst separatorIndex = args.indexOf(\"--\");\n\tconst before = separatorIndex >= 0 ? args.slice(0, separatorIndex) : args;\n\tconst after = separatorIndex >= 0 ? args.slice(separatorIndex + 1) : [];\n\n\tconst positionals: string[] = [];\n\tlet packageSpec: string | undefined;\n\tlet sawPackageFlag = false;\n\tlet foundFirstPositional = false;\n\n\tfor (let i = 0; i < before.length; i++) {\n\t\tconst arg = before[i];\n\t\tif (arg === undefined) return null;\n\t\tif (foundFirstPositional) {\n\t\t\tpositionals.push(arg);\n\t\t\tcontinue;\n\t\t}\n\t\tif (arg === \"-y\" || arg === \"--yes\") continue;\n\t\tif (arg === \"-p\" || arg === \"--package\") {\n\t\t\tconst value = before[i + 1];\n\t\t\tif (!value || value.startsWith(\"-\")) return null;\n\t\t\tif (!packageSpec) packageSpec = value;\n\t\t\tsawPackageFlag = true;\n\t\t\ti++;\n\t\t\tcontinue;\n\t\t}\n\t\tif (arg.startsWith(\"--package=\")) {\n\t\t\tconst value = arg.slice(\"--package=\".length);\n\t\t\tif (!value) return null;\n\t\t\tif (!packageSpec) packageSpec = value;\n\t\t\tsawPackageFlag = true;\n\t\t\tcontinue;\n\t\t}\n\t\tif (arg.startsWith(\"-\")) {\n\t\t\treturn null;\n\t\t}\n\t\tpositionals.push(arg);\n\t\tfoundFirstPositional = true;\n\t}\n\n\tconst separatedAfter = separatorIndex >= 0 && after.length > 0 ? [\"--\", ...after] : after;\n\n\tif (sawPackageFlag) {\n\t\tconst binName = positionals[0];\n\t\tif (!packageSpec || !binName) return null;\n\t\tconst extraArgs = positionals.slice(1).concat(separatedAfter);\n\t\treturn { packageSpec, binName, extraArgs };\n\t}\n\n\tconst packagePositional = positionals[0];\n\tif (!packagePositional) return null;\n\tconst extraArgs = positionals.slice(1).concat(separatedAfter);\n\treturn { packageSpec: packagePositional, extraArgs };\n}\n\nfunction parseNpmExecArgs(args: string[]): ParsedInvocation | null {\n\tif (args[0] !== \"exec\") return null;\n\tconst execArgs = args.slice(1);\n\tconst separatorIndex = execArgs.indexOf(\"--\");\n\tif (separatorIndex < 0) return null;\n\n\tconst before = execArgs.slice(0, separatorIndex);\n\tconst after = execArgs.slice(separatorIndex + 1);\n\n\tlet packageSpec: string | undefined;\n\tfor (let i = 0; i < before.length; i++) {\n\t\tconst arg = before[i];\n\t\tif (arg === undefined) return null;\n\t\tif (arg === \"-y\" || arg === \"--yes\") continue;\n\t\tif (arg === \"--package\") {\n\t\t\tconst value = before[i + 1];\n\t\t\tif (!value || value.startsWith(\"-\")) return null;\n\t\t\tif (!packageSpec) packageSpec = value;\n\t\t\ti++;\n\t\t\tcontinue;\n\t\t}\n\t\tif (arg.startsWith(\"--package=\")) {\n\t\t\tconst value = arg.slice(\"--package=\".length);\n\t\t\tif (!value) return null;\n\t\t\tif (!packageSpec) packageSpec = value;\n\t\t\tcontinue;\n\t\t}\n\t\tif (arg.startsWith(\"-\")) {\n\t\t\treturn null;\n\t\t}\n\t}\n\n\tconst binName = after[0];\n\tif (!packageSpec || !binName) return null;\n\tconst extraArgs = after.slice(1);\n\treturn { packageSpec, binName, extraArgs };\n}\n\nfunction resolveFromNpmCache(packageSpec: string, binName?: string): NpxCacheEntry | null {\n\tconst cacheDir = getNpmCacheDir();\n\tif (!cacheDir) return null;\n\n\tconst parsedSpec = parsePackageSpec(packageSpec);\n\tif (!parsedSpec) return null;\n\n\tconst { packageName, exactVersion } = parsedSpec;\n\tconst packageDir = findCachedPackageDir(cacheDir, packageName, exactVersion);\n\tif (!packageDir) return null;\n\n\tconst packageJsonPath = join(packageDir, \"package.json\");\n\tif (!existsSync(packageJsonPath)) return null;\n\n\tlet pkg: { bin?: string | Record<string, string>; version?: string } | null = null;\n\ttry {\n\t\tpkg = JSON.parse(readFileSync(packageJsonPath, \"utf-8\")) as {\n\t\t\tbin?: string | Record<string, string>;\n\t\t\tversion?: string;\n\t\t};\n\t} catch {\n\t\treturn null;\n\t}\n\n\tconst binField = pkg?.bin;\n\tif (!binField) return null;\n\n\tconst candidates = buildBinCandidates(packageName, binName);\n\tlet chosenBinName: string | undefined;\n\tlet binRel: string | undefined;\n\n\tif (typeof binField === \"string\") {\n\t\tchosenBinName = defaultBinName(packageName);\n\t\tbinRel = binField;\n\t} else {\n\t\tfor (const candidate of candidates) {\n\t\t\tif (binField[candidate]) {\n\t\t\t\tchosenBinName = candidate;\n\t\t\t\tbinRel = binField[candidate];\n\t\t\t\tbreak;\n\t\t\t}\n\t\t}\n\t\tif (!binRel) {\n\t\t\tconst firstEntry = Object.entries(binField)[0];\n\t\t\tif (firstEntry) {\n\t\t\t\tchosenBinName = firstEntry[0];\n\t\t\t\tbinRel = firstEntry[1];\n\t\t\t}\n\t\t}\n\t}\n\n\tif (!binRel) return null;\n\n\tconst nodeModulesDir = findNodeModulesDir(packageDir);\n\tconst binLink = chosenBinName ? join(nodeModulesDir, \".bin\", chosenBinName) : null;\n\tlet resolvedBin = binLink && existsSync(binLink) ? safeRealpath(binLink) : \"\";\n\tif (!resolvedBin) {\n\t\tresolvedBin = resolve(packageDir, binRel);\n\t\tif (!existsSync(resolvedBin)) return null;\n\t}\n\n\tconst isJs = detectJsBinary(resolvedBin);\n\treturn {\n\t\tresolvedBin,\n\t\tresolvedAt: Date.now(),\n\t\t...(pkg?.version !== undefined ? { packageVersion: pkg.version } : {}),\n\t\tisJs,\n\t};\n}\n\nconst FORCE_CACHE_TIMEOUT_MS = 30_000;\n\nasync function forceNpxCache(packageSpec: string, signal?: AbortSignal): Promise<void> {\n\tthrowIfAborted(signal);\n\ttry {\n\t\tawait new Promise<void>((resolve, reject) => {\n\t\t\tconst proc = crossSpawn(\"npm\", [\"exec\", \"--yes\", \"--package\", packageSpec, \"--\", \"node\", \"-e\", \"1\"], {\n\t\t\t\tstdio: \"ignore\",\n\t\t\t});\n\t\t\tconst timer = setTimeout(() => {\n\t\t\t\tproc.kill();\n\t\t\t\treject(new Error(\"timeout\"));\n\t\t\t}, FORCE_CACHE_TIMEOUT_MS);\n\t\t\tconst abort = () => {\n\t\t\t\tproc.kill();\n\t\t\t\treject(signal?.reason instanceof Error ? signal.reason : new Error(\"MCP request aborted\"));\n\t\t\t};\n\t\t\tsignal?.addEventListener(\"abort\", abort, { once: true });\n\t\t\ttimer.unref();\n\t\t\tproc.on(\"close\", () => {\n\t\t\t\tclearTimeout(timer);\n\t\t\t\tsignal?.removeEventListener(\"abort\", abort);\n\t\t\t\tresolve();\n\t\t\t});\n\t\t\tproc.on(\"error\", (err) => {\n\t\t\t\tclearTimeout(timer);\n\t\t\t\tsignal?.removeEventListener(\"abort\", abort);\n\t\t\t\treject(err);\n\t\t\t});\n\t\t});\n\t} catch (_error) {\n\t\tif (signal?.aborted) throwIfAborted(signal);\n\t\t// Ignore failures, resolution will fall back to original command\n\t}\n\tthrowIfAborted(signal);\n}\n\nfunction buildBinCandidates(packageName: string, explicitBin?: string): string[] {\n\tconst candidates: string[] = [];\n\tif (explicitBin) candidates.push(explicitBin);\n\n\tif (packageName.startsWith(\"@\")) {\n\t\tconst namePart = packageName.split(\"/\")[1] ?? \"\";\n\t\tconst scopePart = packageName.split(\"/\")[0]?.replace(\"@\", \"\") ?? \"\";\n\t\tif (namePart) candidates.push(namePart);\n\t\tif (scopePart && namePart) candidates.push(`${scopePart}-${namePart}`);\n\t} else {\n\t\tcandidates.push(packageName);\n\t}\n\n\treturn [...new Set(candidates.filter(Boolean))];\n}\n\nfunction parsePackageSpec(spec: string): ParsedPackageSpec | null {\n\tconst trimmed = spec.trim();\n\tif (!trimmed) return null;\n\n\tlet packageName: string;\n\tlet requestedVersion: string | undefined;\n\tif (trimmed.startsWith(\"@\")) {\n\t\tconst slashIndex = trimmed.indexOf(\"/\");\n\t\tif (slashIndex < 0) return null;\n\t\tconst atIndex = trimmed.lastIndexOf(\"@\");\n\t\tif (atIndex > slashIndex) {\n\t\t\tpackageName = trimmed.slice(0, atIndex);\n\t\t\trequestedVersion = trimmed.slice(atIndex + 1);\n\t\t} else {\n\t\t\tpackageName = trimmed;\n\t\t}\n\t} else {\n\t\tconst atIndex = trimmed.indexOf(\"@\");\n\t\tif (atIndex >= 0) {\n\t\t\tpackageName = trimmed.slice(0, atIndex);\n\t\t\trequestedVersion = trimmed.slice(atIndex + 1);\n\t\t} else {\n\t\t\tpackageName = trimmed;\n\t\t}\n\t}\n\n\tif (!packageName) return null;\n\tconst normalizedVersion = requestedVersion?.replace(/^=/, \"\").replace(/^v/i, \"\");\n\treturn {\n\t\tpackageName,\n\t\t...(normalizedVersion && EXACT_PACKAGE_VERSION_RE.test(normalizedVersion)\n\t\t\t? { exactVersion: normalizedVersion }\n\t\t\t: {}),\n\t};\n}\n\nfunction defaultBinName(packageName: string): string {\n\tif (packageName.startsWith(\"@\")) {\n\t\tconst parts = packageName.split(\"/\");\n\t\treturn parts[1] ?? packageName.replace(\"@\", \"\").replace(\"/\", \"-\");\n\t}\n\treturn packageName;\n}\n\nfunction findCachedPackageDir(cacheDir: string, packageName: string, exactVersion?: string): string | null {\n\tconst npxDir = join(cacheDir, \"_npx\");\n\tif (!existsSync(npxDir)) return null;\n\n\tconst packagePathParts = packageName.startsWith(\"@\") ? packageName.split(\"/\") : [packageName];\n\n\tconst candidates = readdirSync(npxDir, { withFileTypes: true })\n\t\t.filter((entry) => entry.isDirectory())\n\t\t.map((entry) => {\n\t\t\tconst full = join(npxDir, entry.name);\n\t\t\tconst mtime = safeStatMtime(full);\n\t\t\treturn { name: entry.name, mtime };\n\t\t})\n\t\t.sort((a, b) => b.mtime - a.mtime);\n\n\tfor (const entry of candidates) {\n\t\tconst pkgDir = join(npxDir, entry.name, \"node_modules\", ...packagePathParts);\n\t\tconst packageJsonPath = join(pkgDir, \"package.json\");\n\t\tif (!existsSync(packageJsonPath)) continue;\n\t\tif (exactVersion) {\n\t\t\ttry {\n\t\t\t\tconst pkg = JSON.parse(readFileSync(packageJsonPath, \"utf-8\")) as { version?: unknown };\n\t\t\t\tif (pkg.version !== exactVersion) continue;\n\t\t\t} catch {\n\t\t\t\tcontinue;\n\t\t\t}\n\t\t}\n\t\treturn pkgDir;\n\t}\n\n\treturn null;\n}\n\nfunction findNodeModulesDir(packageDir: string): string {\n\tconst parts = packageDir.split(sep);\n\tconst idx = parts.lastIndexOf(\"node_modules\");\n\tif (idx >= 0) {\n\t\treturn parts.slice(0, idx + 1).join(sep);\n\t}\n\treturn join(packageDir, \"..\");\n}\n\nfunction detectJsBinary(binPath: string): boolean {\n\tconst ext = extname(binPath).toLowerCase();\n\tif (ext === \".js\" || ext === \".mjs\" || ext === \".cjs\") return true;\n\ttry {\n\t\tconst fd = openSync(binPath, \"r\");\n\t\ttry {\n\t\t\tconst buf = Buffer.alloc(256);\n\t\t\treadSync(fd, buf, 0, 256, 0);\n\t\t\tconst firstLine = buf.toString(\"utf-8\").split(\"\\n\")[0] ?? \"\";\n\t\t\treturn firstLine.startsWith(\"#!\") && firstLine.includes(\"node\");\n\t\t} finally {\n\t\t\tcloseSync(fd);\n\t\t}\n\t} catch {\n\t\treturn false;\n\t}\n}\n\nlet npmCacheDirCached: string | null | undefined;\n\nfunction getNpmCacheDir(): string | null {\n\tif (npmCacheDirCached !== undefined) return npmCacheDirCached;\n\tif (process.env.NPM_CONFIG_CACHE) {\n\t\tnpmCacheDirCached = process.env.NPM_CONFIG_CACHE;\n\t\treturn npmCacheDirCached;\n\t}\n\ttry {\n\t\tconst result = crossSpawn.sync(\"npm\", [\"config\", \"get\", \"cache\"], { encoding: \"utf-8\" });\n\t\tif (result.status === 0) {\n\t\t\tconst path = String(result.stdout).trim();\n\t\t\tnpmCacheDirCached = path || null;\n\t\t\treturn npmCacheDirCached;\n\t\t}\n\t} catch {\n\t\tnpmCacheDirCached = null;\n\t\treturn null;\n\t}\n\tnpmCacheDirCached = null;\n\treturn null;\n}\n\nfunction getNpxCachePath(): string {\n\treturn getAgentPath(\"mcp-npx-cache.json\");\n}\n\nfunction readNpxCachePayload(cachePath: string): unknown | null {\n\tif (!existsSync(cachePath)) return null;\n\ttry {\n\t\treturn JSON.parse(readFileSync(cachePath, \"utf-8\")) as unknown;\n\t} catch {\n\t\treturn null;\n\t}\n}\n\nfunction asRecord(value: unknown): Record<string, unknown> | null {\n\treturn typeof value === \"object\" && value !== null && !Array.isArray(value)\n\t\t? (value as Record<string, unknown>)\n\t\t: null;\n}\n\nfunction createCacheEntries(): Record<string, NpxCacheEntry> {\n\treturn Object.create(null) as Record<string, NpxCacheEntry>;\n}\n\nfunction toNpxCacheEntry(value: unknown): NpxCacheEntry | null {\n\tconst raw = asRecord(value);\n\tif (!raw) return null;\n\tif (typeof raw.resolvedBin !== \"string\") return null;\n\tif (typeof raw.resolvedAt !== \"number\" || !Number.isFinite(raw.resolvedAt)) return null;\n\tif (typeof raw.isJs !== \"boolean\") return null;\n\tif (raw.packageVersion !== undefined && typeof raw.packageVersion !== \"string\") return null;\n\treturn {\n\t\tresolvedBin: raw.resolvedBin,\n\t\tresolvedAt: raw.resolvedAt,\n\t\t...(raw.packageVersion !== undefined ? { packageVersion: raw.packageVersion } : {}),\n\t\tisJs: raw.isJs,\n\t};\n}\n\nfunction toNpxCache(value: unknown): NpxCache | null {\n\tconst raw = asRecord(value);\n\tif (!raw || raw.version !== CACHE_VERSION) return null;\n\tconst rawEntries = asRecord(raw.entries);\n\tif (!rawEntries) return null;\n\n\tconst entries = createCacheEntries();\n\tfor (const [key, rawEntry] of Object.entries(rawEntries)) {\n\t\tconst entry = toNpxCacheEntry(rawEntry);\n\t\tif (entry) entries[key] = entry;\n\t}\n\treturn { version: CACHE_VERSION, entries };\n}\n\nfunction clearLegacyCache(): boolean {\n\tconst cachePath = getNpxCachePath();\n\tconst raw = asRecord(readNpxCachePayload(cachePath));\n\tif (raw?.version !== 1) return false;\n\ttry {\n\t\tunlinkSync(cachePath);\n\t} catch {\n\t\ttry {\n\t\t\twriteFileSync(cachePath, \"\", \"utf-8\");\n\t\t} catch {\n\t\t\t// Cache cleanup is best effort; resolution must still proceed.\n\t\t}\n\t}\n\treturn true;\n}\n\nclearLegacyCache();\n\nfunction loadCache(): NpxCache | null {\n\tif (clearLegacyCache()) return null;\n\n\treturn toNpxCache(readNpxCachePayload(getNpxCachePath()));\n}\n\nfunction saveCacheEntry(key: string, entry: NpxCacheEntry): void {\n\ttry {\n\t\tconst cachePath = getNpxCachePath();\n\t\tconst dir = dirname(cachePath);\n\t\tmkdirSync(dir, { recursive: true });\n\n\t\tconst existing = toNpxCache(readNpxCachePayload(cachePath));\n\t\tconst entries = createCacheEntries();\n\t\tif (existing) Object.assign(entries, existing.entries);\n\t\tconst merged: NpxCache = { version: CACHE_VERSION, entries };\n\n\t\tmerged.entries[key] = entry;\n\t\tconst tmpPath = `${cachePath}.${process.pid}.tmp`;\n\t\twriteFileSync(tmpPath, JSON.stringify(merged, null, 2), \"utf-8\");\n\t\trenameSync(tmpPath, cachePath);\n\t} catch {\n\t\t// Cache writes are best effort; resolution must still proceed.\n\t}\n}\n\nfunction safeRealpath(path: string): string {\n\ttry {\n\t\treturn realpathSync(path);\n\t} catch {\n\t\treturn \"\";\n\t}\n}\n\nfunction safeStatMtime(path: string): number {\n\ttry {\n\t\treturn statSync(path).mtimeMs;\n\t} catch {\n\t\treturn 0;\n\t}\n}\n"]}
|