@duckmind/dm-windows-x64 0.63.4 → 0.63.9

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 (121) hide show
  1. package/dm.exe +0 -0
  2. package/extensions/.dm-extensions.json +236 -13
  3. package/extensions/dm-context/package.json +1 -1
  4. package/extensions/dm-context/skills/context-management/SKILL.md +173 -223
  5. package/extensions/dm-context/skills/context-management/references/development-and-troubleshooting.md +75 -0
  6. package/extensions/dm-context/skills/context-management/references/interleaved-async-work.md +143 -0
  7. package/extensions/dm-context/skills/context-management/references/planning-and-execution.md +81 -0
  8. package/extensions/dm-context/skills/context-management/references/repeated-items-and-batch-work.md +69 -0
  9. package/extensions/dm-context/skills/context-management/references/retry-branch-and-pivot.md +80 -0
  10. package/extensions/dm-context/skills/context-management/references/search-research-and-reading.md +103 -0
  11. package/extensions/dm-context/skills/context-management/references/task-switching-and-cleanup.md +73 -0
  12. package/extensions/dm-context/src/context.js +3 -2
  13. package/extensions/dm-context/src/index.js +168 -84
  14. package/extensions/dm-mcp-adapter/OAUTH.md +3 -0
  15. package/extensions/dm-mcp-adapter/THIRD_PARTY_NOTICES.md +4 -0
  16. package/extensions/dm-mcp-adapter/abort.js +35 -0
  17. package/extensions/dm-mcp-adapter/agent-dir.js +45 -0
  18. package/extensions/dm-mcp-adapter/agent-plugin-loader.js +349 -0
  19. package/extensions/dm-mcp-adapter/app-bridge.bundle.js +5843 -0
  20. package/extensions/dm-mcp-adapter/cli.js +354 -0
  21. package/extensions/dm-mcp-adapter/commands.js +619 -0
  22. package/extensions/dm-mcp-adapter/config.js +1060 -0
  23. package/extensions/dm-mcp-adapter/consent-manager.js +60 -0
  24. package/extensions/dm-mcp-adapter/direct-tools.js +544 -0
  25. package/extensions/dm-mcp-adapter/dist/agent-dir.js +45 -0
  26. package/extensions/dm-mcp-adapter/dist/agent-plugin-loader.js +349 -0
  27. package/extensions/dm-mcp-adapter/dist/config.js +1060 -0
  28. package/extensions/dm-mcp-adapter/dist/mcp-bearer-store.js +311 -0
  29. package/extensions/dm-mcp-adapter/dist/metadata-cache.js +285 -0
  30. package/extensions/dm-mcp-adapter/dist/package-mcp-loader.js +144 -0
  31. package/extensions/dm-mcp-adapter/dist/resource-tools.js +7 -0
  32. package/extensions/dm-mcp-adapter/dist/types.js +247 -0
  33. package/extensions/dm-mcp-adapter/dist/ui-app-bridge-helpers.js +36 -0
  34. package/extensions/dm-mcp-adapter/dist/ui-stream-types.js +58 -0
  35. package/extensions/dm-mcp-adapter/dist/ui-tool-visibility.js +26 -0
  36. package/extensions/dm-mcp-adapter/dist/utils.js +307 -0
  37. package/extensions/dm-mcp-adapter/elicitation-handler.js +306 -0
  38. package/extensions/dm-mcp-adapter/error-signal.js +16 -0
  39. package/extensions/dm-mcp-adapter/errors.js +225 -0
  40. package/extensions/dm-mcp-adapter/failure-backoff.js +19 -0
  41. package/extensions/dm-mcp-adapter/glimpse-ui.js +61 -0
  42. package/extensions/dm-mcp-adapter/host-html-template.js +464 -0
  43. package/extensions/dm-mcp-adapter/index.js +1079 -0
  44. package/extensions/dm-mcp-adapter/init.js +624 -0
  45. package/extensions/dm-mcp-adapter/json-schema-validator.js +53 -0
  46. package/extensions/dm-mcp-adapter/lifecycle.js +385 -0
  47. package/extensions/dm-mcp-adapter/logger.js +115 -0
  48. package/extensions/dm-mcp-adapter/mcp-auth-flow.js +824 -0
  49. package/extensions/dm-mcp-adapter/mcp-auth.js +732 -0
  50. package/extensions/dm-mcp-adapter/mcp-bearer-store.js +311 -0
  51. package/extensions/dm-mcp-adapter/mcp-callback-server.js +388 -0
  52. package/extensions/dm-mcp-adapter/mcp-code.js +291 -0
  53. package/extensions/dm-mcp-adapter/mcp-keyring-helper.cjs +88 -0
  54. package/extensions/dm-mcp-adapter/mcp-oauth-provider.js +490 -0
  55. package/extensions/dm-mcp-adapter/mcp-output-guard.js +386 -0
  56. package/extensions/dm-mcp-adapter/mcp-panel.js +951 -0
  57. package/extensions/dm-mcp-adapter/mcp-probe.js +151 -0
  58. package/extensions/dm-mcp-adapter/mcp-references.js +263 -0
  59. package/extensions/dm-mcp-adapter/mcp-script-worker.mjs +126 -0
  60. package/extensions/dm-mcp-adapter/mcp-setup-panel.js +578 -0
  61. package/extensions/dm-mcp-adapter/mcp-status.js +80 -0
  62. package/extensions/dm-mcp-adapter/mcp-trace.js +215 -0
  63. package/extensions/dm-mcp-adapter/metadata-cache.js +292 -0
  64. package/extensions/dm-mcp-adapter/namespace-tools.js +155 -0
  65. package/extensions/dm-mcp-adapter/npx-resolver.js +465 -0
  66. package/extensions/dm-mcp-adapter/oauth-handler.js +17 -0
  67. package/extensions/dm-mcp-adapter/oauth.js +17 -0
  68. package/extensions/dm-mcp-adapter/onboarding-state.js +62 -0
  69. package/extensions/dm-mcp-adapter/package-mcp-loader.js +144 -0
  70. package/extensions/dm-mcp-adapter/package.json +68 -0
  71. package/extensions/dm-mcp-adapter/panel-keys.js +26 -0
  72. package/extensions/dm-mcp-adapter/prompts.js +258 -0
  73. package/extensions/dm-mcp-adapter/proxy-modes.js +1336 -0
  74. package/extensions/dm-mcp-adapter/request-headers-command.js +293 -0
  75. package/extensions/dm-mcp-adapter/resource-tools.js +7 -0
  76. package/extensions/dm-mcp-adapter/runtime-owner.js +79 -0
  77. package/extensions/dm-mcp-adapter/sampling-handler.js +222 -0
  78. package/extensions/dm-mcp-adapter/sandbox-proxy-template.js +190 -0
  79. package/extensions/dm-mcp-adapter/search-ranking.js +198 -0
  80. package/extensions/dm-mcp-adapter/server-manager.js +1258 -0
  81. package/extensions/dm-mcp-adapter/session-recovery.js +82 -0
  82. package/extensions/dm-mcp-adapter/skills/mcp-scripting/SKILL.md +39 -0
  83. package/extensions/dm-mcp-adapter/state.js +0 -0
  84. package/extensions/dm-mcp-adapter/test-runner.mjs +18 -0
  85. package/extensions/dm-mcp-adapter/tool-approval.js +151 -0
  86. package/extensions/dm-mcp-adapter/tool-metadata.js +247 -0
  87. package/extensions/dm-mcp-adapter/tool-registrar.js +212 -0
  88. package/extensions/dm-mcp-adapter/tool-result-renderer.js +355 -0
  89. package/extensions/dm-mcp-adapter/ts-shape.js +157 -0
  90. package/extensions/dm-mcp-adapter/types.js +264 -0
  91. package/extensions/dm-mcp-adapter/ui-app-bridge-helpers.js +36 -0
  92. package/extensions/dm-mcp-adapter/ui-resource-handler.js +209 -0
  93. package/extensions/dm-mcp-adapter/ui-server.js +815 -0
  94. package/extensions/dm-mcp-adapter/ui-session.js +455 -0
  95. package/extensions/dm-mcp-adapter/ui-stream-types.js +58 -0
  96. package/extensions/dm-mcp-adapter/ui-tool-visibility.js +26 -0
  97. package/extensions/dm-mcp-adapter/unix-socket-transport.js +83 -0
  98. package/extensions/dm-mcp-adapter/utils.js +307 -0
  99. package/extensions/dm-skills-manager/THIRD_PARTY_NOTICES.md +27 -0
  100. package/extensions/dm-skills-manager/extensions/skills-manager/components.js +265 -0
  101. package/extensions/dm-skills-manager/extensions/skills-manager/constants.js +31 -0
  102. package/extensions/dm-skills-manager/extensions/skills-manager/creation-fallback.js +20 -0
  103. package/extensions/dm-skills-manager/extensions/skills-manager/creation.js +145 -0
  104. package/extensions/dm-skills-manager/extensions/skills-manager/dialog.js +738 -0
  105. package/extensions/dm-skills-manager/extensions/skills-manager/dm-ai-compat.js +15 -0
  106. package/extensions/dm-skills-manager/extensions/skills-manager/format.js +125 -0
  107. package/extensions/dm-skills-manager/extensions/skills-manager/glyphs.js +142 -0
  108. package/extensions/dm-skills-manager/extensions/skills-manager/layout.js +93 -0
  109. package/extensions/dm-skills-manager/extensions/skills-manager/paths.js +76 -0
  110. package/extensions/dm-skills-manager/extensions/skills-manager/registry.js +95 -0
  111. package/extensions/dm-skills-manager/extensions/skills-manager/settings.js +93 -0
  112. package/extensions/dm-skills-manager/extensions/skills-manager/startup.js +32 -0
  113. package/extensions/dm-skills-manager/extensions/skills-manager/toggle.js +54 -0
  114. package/extensions/dm-skills-manager/extensions/skills-manager/types.js +14 -0
  115. package/extensions/dm-skills-manager/extensions/skills-manager/ui.js +121 -0
  116. package/extensions/dm-skills-manager/extensions/skills-manager.js +111 -0
  117. package/extensions/dm-skills-manager/package.json +121 -0
  118. package/package.json +13 -1
  119. package/extensions/dm-localllm-provider/detect.test.js +0 -1051
  120. package/extensions/dm-localllm-provider/index.test.js +0 -149
  121. package/extensions/dm-localllm-provider/keychain.test.js +0 -61
@@ -0,0 +1,144 @@
1
+ import { existsSync, readFileSync, realpathSync, statSync } from "node:fs";
2
+ import { isAbsolute, join, relative, resolve, sep } from "node:path";
3
+ import stripJsonComments from "strip-json-comments";
4
+ import { getAgentDir, getConfigDirName } from "./agent-dir.js";
5
+ export function loadPackageMcpConfigs(cwd = process.cwd()) {
6
+ const mcpServers = {};
7
+ const seen = new Set;
8
+ for (const packageRoot of getConfiguredPackageRoots(cwd)) {
9
+ const manifest = readPackageManifest(packageRoot);
10
+ if (!manifest || typeof manifest.name !== "string" || !manifest.name)
11
+ continue;
12
+ const paths = getManifestMcpPaths(manifest.pi?.mcp, manifest.name);
13
+ if (!paths)
14
+ continue;
15
+ const packagePrefix = formatPackageName(manifest.name);
16
+ const packageServers = new Set;
17
+ for (const path of paths) {
18
+ const configPath = resolvePackageConfigPath(packageRoot, path);
19
+ if (!configPath) {
20
+ console.warn(`DM package ${manifest.name} skips MCP config ${path}: file must stay inside the package`);
21
+ continue;
22
+ }
23
+ const config = readMcpConfig(configPath, manifest.name);
24
+ if (!config)
25
+ continue;
26
+ for (const [serverName, server] of Object.entries(config.mcpServers)) {
27
+ const normalizedName = `${packagePrefix}__${formatServerName(serverName)}`;
28
+ if (packageServers.has(normalizedName) || seen.has(normalizedName)) {
29
+ console.warn(`DM package ${manifest.name} skips duplicate normalized MCP server ${normalizedName}`);
30
+ continue;
31
+ }
32
+ packageServers.add(normalizedName);
33
+ seen.add(normalizedName);
34
+ mcpServers[normalizedName] = server;
35
+ }
36
+ }
37
+ }
38
+ return { mcpServers };
39
+ }
40
+ function getConfiguredPackageRoots(cwd) {
41
+ const roots = [];
42
+ for (const [settingsPath, scope] of [
43
+ [join(cwd, getConfigDirName(), "settings.json"), "project"],
44
+ [join(getAgentDir(), "settings.json"), "user"]
45
+ ]) {
46
+ const settings = readOptionalJson(settingsPath, `${scope} DM settings`);
47
+ if (settings === undefined)
48
+ continue;
49
+ if (typeof settings !== "object" || settings === null || Array.isArray(settings)) {
50
+ throw new Error(`${scope} DM settings ${settingsPath} must be a JSON object`);
51
+ }
52
+ const packages = settings.packages;
53
+ if (packages === undefined)
54
+ continue;
55
+ if (!Array.isArray(packages))
56
+ throw new Error(`${scope} DM settings ${settingsPath} packages must be an array`);
57
+ for (const entry of packages) {
58
+ const source = typeof entry === "string" ? entry : entry && typeof entry === "object" && !Array.isArray(entry) && typeof entry.source === "string" ? entry.source : undefined;
59
+ if (!source)
60
+ throw new Error(`${scope} DM settings ${settingsPath} package entries must be strings or objects with a string source`);
61
+ const root = resolvePackageRoot(source, scope, cwd);
62
+ if (root && !roots.includes(root))
63
+ roots.push(root);
64
+ }
65
+ }
66
+ return roots;
67
+ }
68
+ function resolvePackageRoot(source, scope, cwd) {
69
+ const baseDir = scope === "user" ? getAgentDir() : join(cwd, getConfigDirName());
70
+ if (source.startsWith("npm:")) {
71
+ const name = source.slice(4).trim().match(/^(@?[^@]+(?:\/[^@]+)?)/)?.[1];
72
+ return name ? resolveContainedPath(join(baseDir, "npm", "node_modules"), name) : null;
73
+ }
74
+ const gitSource = source.startsWith("git:") ? source.slice(4).trim() : /^(?:(?:https?|ssh):\/\/|git@[^:]+:)/.test(source) ? source : null;
75
+ if (gitSource) {
76
+ const value = gitSource.replace(/^ssh:\/\/git@/, "").replace(/^git@([^:]+):/, "$1/").replace(/^[a-z]+:\/\//i, "");
77
+ const path = value.replace(/@[^/]+$/, "").replace(/\.git$/, "");
78
+ return path && !path.startsWith("/") ? resolveContainedPath(join(baseDir, "git"), path) : null;
79
+ }
80
+ return isAbsolute(source) ? resolve(source) : resolve(baseDir, source);
81
+ }
82
+ function readPackageManifest(packageRoot) {
83
+ const manifest = readOptionalJson(join(packageRoot, "package.json"), `DM package manifest ${packageRoot}`);
84
+ return manifest && typeof manifest === "object" && !Array.isArray(manifest) ? manifest : null;
85
+ }
86
+ function getManifestMcpPaths(value, packageName) {
87
+ const paths = typeof value === "string" ? [value] : Array.isArray(value) && value.every((path) => typeof path === "string") ? value : null;
88
+ if (value !== undefined && !paths)
89
+ console.warn(`DM package ${packageName} ignores invalid pi.mcp manifest entry`);
90
+ return paths;
91
+ }
92
+ function readMcpConfig(path, packageName) {
93
+ const config = readRequiredJson(path, `DM package ${packageName} MCP config`);
94
+ if (!config || typeof config !== "object" || Array.isArray(config)) {
95
+ throw new Error(`DM package ${packageName} MCP config ${path} must be a JSON object`);
96
+ }
97
+ const servers = config.mcpServers;
98
+ if (!servers || typeof servers !== "object" || Array.isArray(servers)) {
99
+ throw new Error(`DM package ${packageName} MCP config ${path} must contain a JSON object mcpServers field`);
100
+ }
101
+ const mcpServers = {};
102
+ for (const [name, server] of Object.entries(servers)) {
103
+ if (!server || typeof server !== "object" || Array.isArray(server)) {
104
+ throw new Error(`DM package ${packageName} MCP config ${path} server ${name} must be a JSON object`);
105
+ }
106
+ mcpServers[name] = server;
107
+ }
108
+ return { mcpServers };
109
+ }
110
+ function readRequiredJson(path, description) {
111
+ try {
112
+ return JSON.parse(stripJsonComments(readFileSync(path, "utf8"), { trailingCommas: true }));
113
+ } catch (error) {
114
+ throw new Error(`${description} ${path} contains invalid JSON: ${error instanceof Error ? error.message : String(error)}`, { cause: error });
115
+ }
116
+ }
117
+ function readOptionalJson(path, description) {
118
+ if (!existsSync(path))
119
+ return;
120
+ return readRequiredJson(path, description);
121
+ }
122
+ function resolveContainedPath(root, path) {
123
+ const resolved = resolve(root, path);
124
+ const rel = relative(root, resolved);
125
+ return rel === "" || !rel.startsWith("..") && !rel.startsWith(sep) && !isAbsolute(rel) ? resolved : null;
126
+ }
127
+ function resolvePackageConfigPath(packageRoot, path) {
128
+ const lexicalPath = resolveContainedPath(packageRoot, path);
129
+ if (!lexicalPath || !existsSync(lexicalPath) || !statSync(lexicalPath).isFile())
130
+ return null;
131
+ try {
132
+ const realPackageRoot = realpathSync(packageRoot);
133
+ const realConfigPath = realpathSync(lexicalPath);
134
+ return resolveContainedPath(realPackageRoot, realConfigPath);
135
+ } catch {
136
+ return null;
137
+ }
138
+ }
139
+ function formatPackageName(name) {
140
+ return name.replace(/[^A-Za-z0-9_-]+/g, "_").replace(/^[_-]+|[_-]+$/g, "") || "package";
141
+ }
142
+ function formatServerName(name) {
143
+ return name.replace(/[^A-Za-z0-9_-]+/g, "_").replace(/^[_-]+|[_-]+$/g, "") || "server";
144
+ }
@@ -0,0 +1,7 @@
1
+ export function resourceNameToToolName(name) {
2
+ let result = name.replace(/[^a-zA-Z0-9]/g, "_").replace(/_+/g, "_").replace(/^_+/, "").replace(/_+$/, "").toLowerCase();
3
+ if (!result || /^\d/.test(result)) {
4
+ result = "resource" + (result ? "_" + result : "");
5
+ }
6
+ return result;
7
+ }
@@ -0,0 +1,247 @@
1
+ export const MCP_STATUS_EVENT = "dm-mcp-adapter/status/v1";
2
+ export const MCP_STATUS_SNAPSHOT_VERSION = 1;
3
+ export { UI_STREAM_HOST_CONTEXT_KEY, UI_STREAM_REQUEST_META_KEY, UI_STREAM_RESULT_PATCH_METHOD, SERVER_STREAM_RESULT_PATCH_METHOD, UI_STREAM_STRUCTURED_CONTENT_KEY, uiStreamModeSchema, visualizationStreamPhaseSchema, visualizationStreamFrameTypeSchema, visualizationStreamStatusSchema, uiStreamHostContextSchema, visualizationStreamEnvelopeSchema, uiStreamCallToolResultSchema, uiStreamResultPatchNotificationSchema, serverStreamResultPatchNotificationSchema, getUiStreamHostContext, getVisualizationStreamEnvelope } from "./ui-stream-types.js";
4
+ export function extractUiPromptText(params) {
5
+ if (params.type === "prompt" || params.prompt) {
6
+ const prompt = params.prompt ?? String(params.message ?? "");
7
+ return prompt || undefined;
8
+ }
9
+ if (params.role === "user" && Array.isArray(params.content)) {
10
+ const text = params.content.map((block) => block && typeof block === "object" && ("text" in block) ? String(block.text ?? "") : "").filter(Boolean).join(`
11
+
12
+ `);
13
+ return text || undefined;
14
+ }
15
+ return;
16
+ }
17
+ export function parseUiPromptHandoff(prompt) {
18
+ const newlineIndex = prompt.indexOf(`
19
+ `);
20
+ if (newlineIndex <= 0) {
21
+ return;
22
+ }
23
+ const intent = prompt.slice(0, newlineIndex).trim();
24
+ const payloadText = prompt.slice(newlineIndex + 1).trim();
25
+ if (!intent || !payloadText) {
26
+ return;
27
+ }
28
+ if (!/^[A-Za-z][A-Za-z0-9_-]*$/.test(intent)) {
29
+ return;
30
+ }
31
+ try {
32
+ const parsed = JSON.parse(payloadText);
33
+ if (!parsed || typeof parsed !== "object" || Array.isArray(parsed)) {
34
+ return;
35
+ }
36
+ return {
37
+ intent,
38
+ params: parsed,
39
+ raw: prompt
40
+ };
41
+ } catch {
42
+ return;
43
+ }
44
+ }
45
+ export function createUiModelContextUpdate(params, maxChars = 12000) {
46
+ const payload = Object.fromEntries(Object.entries(params).filter(([, value]) => value !== undefined));
47
+ if (Object.keys(payload).length === 0)
48
+ return;
49
+ const serialized = JSON.stringify(payload);
50
+ if (serialized.length <= maxChars) {
51
+ return { payload, summary: serialized, truncated: false };
52
+ }
53
+ return {
54
+ summary: `${serialized.slice(0, Math.max(0, maxChars - 1))}…`,
55
+ truncated: true
56
+ };
57
+ }
58
+ export function isServerDisabled(definition) {
59
+ return definition?.disabled === true;
60
+ }
61
+ export const MCP_TOOL_APPROVAL_REQUEST_EVENT = "dm-mcp-adapter:tool-approval-request";
62
+ function sanitizeServerPrefix(serverName, preserveProviderValid = true) {
63
+ const validCharacters = preserveProviderValid ? /^[A-Za-z0-9_-]$/ : /^[A-Za-z0-9]$/;
64
+ return Array.from(serverName, (char) => validCharacters.test(char) ? char : `_${char.codePointAt(0).toString(16)}_`).join("");
65
+ }
66
+ export function getServerPrefix(serverName, mode) {
67
+ if (mode === "none")
68
+ return "";
69
+ if (mode === "short") {
70
+ let short = sanitizeServerPrefix(serverName.replace(/-?mcp$/i, ""));
71
+ if (!short)
72
+ short = "mcp";
73
+ return short;
74
+ }
75
+ if (mode === "mcp")
76
+ return `mcp__${sanitizeServerPrefix(serverName)}`;
77
+ return sanitizeServerPrefix(serverName);
78
+ }
79
+ export function formatToolName(toolName, serverName, prefix) {
80
+ const p = getServerPrefix(serverName, prefix);
81
+ const sanitized = toolName.replace(/\./g, "_");
82
+ return p ? `${p}_${sanitized}` : sanitized;
83
+ }
84
+ export function resolveToolPrefix(definition, globalPrefix) {
85
+ return definition?.toolPrefix ?? globalPrefix ?? "server";
86
+ }
87
+ export function resolveServerFromToolName(toolName, serverNames, prefix) {
88
+ if (prefix === "none")
89
+ return;
90
+ const candidates = [];
91
+ for (const name of serverNames) {
92
+ const p = getServerPrefix(name, prefix);
93
+ if (p && toolName.startsWith(p + "_"))
94
+ candidates.push({ name, prefix: p });
95
+ }
96
+ if (candidates.length === 0)
97
+ return;
98
+ candidates.sort((a, b) => b.prefix.length - a.prefix.length);
99
+ const best = candidates[0];
100
+ if (candidates.some((c) => c.prefix === best.prefix && c.name !== best.name)) {
101
+ return;
102
+ }
103
+ return best?.name;
104
+ }
105
+ export function sanitizePromptName(name) {
106
+ const cleaned = name.replace(/[^A-Za-z0-9_-]+/g, "_").replace(/^[_-]+|[_-]+$/g, "");
107
+ if (!cleaned)
108
+ return "prompt";
109
+ return /^[0-9]/.test(cleaned) ? `_${cleaned}` : cleaned;
110
+ }
111
+ export function formatPromptCommandName(promptName, serverName, prefix) {
112
+ const serverPart = getServerPrefix(serverName, prefix) || sanitizeServerPrefix(serverName) || "server";
113
+ return `mcp__${serverPart}__${sanitizePromptName(promptName)}`;
114
+ }
115
+ function getLegacyServerPrefix(serverName, mode) {
116
+ if (mode === "none")
117
+ return "";
118
+ if (mode === "short")
119
+ return sanitizeServerPrefix(serverName.replace(/-?mcp$/i, ""), false) || "mcp";
120
+ if (mode === "mcp")
121
+ return `mcp__${sanitizeServerPrefix(serverName, false)}`;
122
+ return sanitizeServerPrefix(serverName, false);
123
+ }
124
+ function formatLegacyToolName(toolName, serverName, prefix) {
125
+ const serverPrefix = getLegacyServerPrefix(serverName, prefix);
126
+ const sanitizedToolName = toolName.replace(/[.-]/g, "_");
127
+ return serverPrefix ? `${serverPrefix}_${sanitizedToolName}` : sanitizedToolName;
128
+ }
129
+ export function getToolNameCandidates(toolName, serverName, prefix, includeLegacy = true) {
130
+ const candidates = new Set([
131
+ toolName,
132
+ formatToolName(toolName, serverName, prefix),
133
+ formatToolName(toolName, serverName, "server"),
134
+ formatToolName(toolName, serverName, "short"),
135
+ formatToolName(toolName, serverName, "mcp")
136
+ ]);
137
+ if (includeLegacy) {
138
+ const legacyToolName = toolName.replace(/-/g, "_");
139
+ candidates.add(legacyToolName);
140
+ candidates.add(formatToolName(legacyToolName, serverName, prefix));
141
+ candidates.add(formatToolName(legacyToolName, serverName, "server"));
142
+ candidates.add(formatToolName(legacyToolName, serverName, "short"));
143
+ candidates.add(formatToolName(legacyToolName, serverName, "mcp"));
144
+ candidates.add(formatLegacyToolName(toolName, serverName, prefix));
145
+ candidates.add(formatLegacyToolName(toolName, serverName, "server"));
146
+ candidates.add(formatLegacyToolName(toolName, serverName, "short"));
147
+ candidates.add(formatLegacyToolName(toolName, serverName, "mcp"));
148
+ candidates.add(formatToolName(toolName, serverName, prefix).replace(/-/g, "_"));
149
+ candidates.add(formatToolName(toolName, serverName, "server").replace(/-/g, "_"));
150
+ candidates.add(formatToolName(toolName, serverName, "short").replace(/-/g, "_"));
151
+ candidates.add(formatToolName(toolName, serverName, "mcp").replace(/-/g, "_"));
152
+ }
153
+ return candidates;
154
+ }
155
+ function globToRegExp(pattern) {
156
+ const escaped = pattern.replace(/[.+^${}()|[\]\\]/g, "\\$&").replace(/\*/g, ".*").replace(/\?/g, ".");
157
+ return new RegExp(`^${escaped}$`);
158
+ }
159
+ export function createToolSelectorCandidateIndex(allCurrentCandidates, additionalCurrentCandidatesByToolName) {
160
+ return {
161
+ allCurrentCandidates,
162
+ matchingCountByPattern: new Map,
163
+ matcherByPattern: new Map,
164
+ ...additionalCurrentCandidatesByToolName ? { additionalCurrentCandidatesByToolName } : {}
165
+ };
166
+ }
167
+ export function matchesToolPattern(candidates, patterns) {
168
+ if (!Array.isArray(patterns) || patterns.length === 0)
169
+ return false;
170
+ for (const pattern of patterns) {
171
+ if (typeof pattern !== "string")
172
+ continue;
173
+ if (!pattern.includes("*") && !pattern.includes("?") && candidates.has(pattern)) {
174
+ return true;
175
+ }
176
+ if ((pattern.includes("*") || pattern.includes("?")) && [...candidates].some((candidate) => globToRegExp(pattern).test(candidate))) {
177
+ return true;
178
+ }
179
+ }
180
+ return false;
181
+ }
182
+ function indexHasOtherCurrentMatch(index, toolName, currentCandidates, pattern) {
183
+ const additionalCandidates = index.additionalCurrentCandidatesByToolName?.get(toolName);
184
+ const hasCandidate = (candidate) => index.allCurrentCandidates.has(candidate) || additionalCandidates?.has(candidate) === true;
185
+ const isGlob = pattern.includes("*") || pattern.includes("?");
186
+ if (!isGlob) {
187
+ return hasCandidate(pattern) && !currentCandidates.has(pattern);
188
+ }
189
+ let matcher = index.matcherByPattern.get(pattern);
190
+ if (!matcher) {
191
+ matcher = globToRegExp(pattern);
192
+ index.matcherByPattern.set(pattern, matcher);
193
+ }
194
+ let matchingCount = index.matchingCountByPattern.get(pattern);
195
+ if (matchingCount === undefined) {
196
+ matchingCount = 0;
197
+ for (const candidate of index.allCurrentCandidates) {
198
+ if (matcher.test(candidate))
199
+ matchingCount++;
200
+ }
201
+ index.matchingCountByPattern.set(pattern, matchingCount);
202
+ }
203
+ let totalMatchingCount = matchingCount;
204
+ if (additionalCandidates) {
205
+ for (const candidate of additionalCandidates) {
206
+ if (!index.allCurrentCandidates.has(candidate) && matcher.test(candidate))
207
+ totalMatchingCount++;
208
+ }
209
+ }
210
+ if (totalMatchingCount === 0)
211
+ return false;
212
+ let currentMatchingCount = 0;
213
+ for (const candidate of currentCandidates) {
214
+ if (hasCandidate(candidate) && matcher.test(candidate))
215
+ currentMatchingCount++;
216
+ }
217
+ return totalMatchingCount > currentMatchingCount;
218
+ }
219
+ function matchesToolSelector(toolName, serverName, prefix, patterns, otherCurrentCandidates) {
220
+ if (!Array.isArray(patterns) || patterns.length === 0)
221
+ return false;
222
+ const currentCandidates = getToolNameCandidates(toolName, serverName, prefix, false);
223
+ if (matchesToolPattern(currentCandidates, patterns))
224
+ return true;
225
+ if (!otherCurrentCandidates)
226
+ return matchesToolPattern(getToolNameCandidates(toolName, serverName, prefix), patterns);
227
+ const legacyCandidates = getToolNameCandidates(toolName, serverName, prefix);
228
+ for (const candidate of currentCandidates)
229
+ legacyCandidates.delete(candidate);
230
+ return patterns.some((pattern) => {
231
+ if (typeof pattern !== "string" || !matchesToolPattern(legacyCandidates, [pattern]))
232
+ return false;
233
+ const hasCollision = otherCurrentCandidates instanceof Set ? matchesToolPattern(otherCurrentCandidates, [pattern]) : indexHasOtherCurrentMatch(otherCurrentCandidates, toolName, currentCandidates, pattern);
234
+ return !hasCollision;
235
+ });
236
+ }
237
+ export function isToolIncluded(toolName, serverName, prefix, includeTools, otherCurrentCandidates) {
238
+ if (!Array.isArray(includeTools) || includeTools.length === 0)
239
+ return true;
240
+ return matchesToolSelector(toolName, serverName, prefix, includeTools, otherCurrentCandidates);
241
+ }
242
+ export function isToolExcluded(toolName, serverName, prefix, excludeTools, otherCurrentCandidates) {
243
+ return matchesToolSelector(toolName, serverName, prefix, excludeTools, otherCurrentCandidates);
244
+ }
245
+ export function isToolAllowed(toolName, serverName, prefix, includeTools, excludeTools, otherCurrentCandidates) {
246
+ return isToolIncluded(toolName, serverName, prefix, includeTools, otherCurrentCandidates) && !isToolExcluded(toolName, serverName, prefix, excludeTools, otherCurrentCandidates);
247
+ }
@@ -0,0 +1,36 @@
1
+ export const RESOURCE_MIME_TYPE = "text/html;profile=mcp-app";
2
+ const RESOURCE_URI_META_KEY = "ui/resourceUri";
3
+ export function getToolUiResourceUri(tool) {
4
+ const meta = tool._meta;
5
+ let resourceUri = getNestedResourceUri(meta);
6
+ if (resourceUri === undefined) {
7
+ resourceUri = meta?.[RESOURCE_URI_META_KEY];
8
+ }
9
+ if (typeof resourceUri === "string" && resourceUri.startsWith("ui://")) {
10
+ return resourceUri;
11
+ }
12
+ if (resourceUri !== undefined) {
13
+ throw new Error(`Invalid UI resource URI: ${JSON.stringify(resourceUri)}`);
14
+ }
15
+ return;
16
+ }
17
+ export function buildAllowAttribute(permissions) {
18
+ if (!permissions)
19
+ return "";
20
+ const allowed = [];
21
+ if (permissions.camera)
22
+ allowed.push("camera");
23
+ if (permissions.microphone)
24
+ allowed.push("microphone");
25
+ if (permissions.geolocation)
26
+ allowed.push("geolocation");
27
+ if (permissions.clipboardWrite)
28
+ allowed.push("clipboard-write");
29
+ return allowed.join("; ");
30
+ }
31
+ function getNestedResourceUri(meta) {
32
+ const ui = meta?.ui;
33
+ if (!ui || typeof ui !== "object")
34
+ return;
35
+ return ui.resourceUri;
36
+ }
@@ -0,0 +1,58 @@
1
+ import { z } from "zod";
2
+ export const UI_STREAM_HOST_CONTEXT_KEY = "dm-mcp-adapter/stream";
3
+ export const UI_STREAM_REQUEST_META_KEY = "dm-mcp-adapter/stream-token";
4
+ export const UI_STREAM_RESULT_PATCH_METHOD = "notifications/dm-mcp-adapter/ui-result-patch";
5
+ export const SERVER_STREAM_RESULT_PATCH_METHOD = "notifications/dm-mcp-adapter/result-patch";
6
+ export const UI_STREAM_STRUCTURED_CONTENT_KEY = "dm-mcp-adapter/stream";
7
+ export const uiStreamModeSchema = z.enum(["eager", "stream-first"]);
8
+ export const visualizationStreamPhaseSchema = z.enum(["shell", "narrative", "structure", "detail", "settled"]);
9
+ export const visualizationStreamFrameTypeSchema = z.enum(["patch", "checkpoint", "final"]);
10
+ export const visualizationStreamStatusSchema = z.enum(["ok", "error"]);
11
+ const looseRecordSchema = z.record(z.string(), z.unknown());
12
+ const looseArraySchema = z.array(z.unknown());
13
+ export const uiStreamHostContextSchema = z.object({
14
+ mode: uiStreamModeSchema,
15
+ streamId: z.string().min(1),
16
+ intermediateResultPatches: z.boolean(),
17
+ partialInput: z.boolean()
18
+ });
19
+ export const visualizationStreamEnvelopeSchema = z.object({
20
+ streamId: z.string().min(1),
21
+ sequence: z.number().int().nonnegative(),
22
+ frameType: visualizationStreamFrameTypeSchema,
23
+ phase: visualizationStreamPhaseSchema,
24
+ status: visualizationStreamStatusSchema,
25
+ message: z.string().optional(),
26
+ spec: looseRecordSchema.optional(),
27
+ checkpoint: looseRecordSchema.optional()
28
+ });
29
+ export const uiStreamCallToolResultSchema = z.object({
30
+ content: looseArraySchema.optional(),
31
+ structuredContent: looseRecordSchema.optional(),
32
+ isError: z.boolean().optional(),
33
+ _meta: looseRecordSchema.optional()
34
+ }).passthrough();
35
+ export const uiStreamResultPatchNotificationSchema = z.object({
36
+ method: z.literal(UI_STREAM_RESULT_PATCH_METHOD),
37
+ params: uiStreamCallToolResultSchema
38
+ });
39
+ export const serverStreamResultPatchNotificationSchema = z.object({
40
+ method: z.literal(SERVER_STREAM_RESULT_PATCH_METHOD),
41
+ params: z.object({
42
+ streamToken: z.string().min(1),
43
+ result: uiStreamCallToolResultSchema
44
+ })
45
+ });
46
+ export function getUiStreamHostContext(hostContext) {
47
+ const candidate = hostContext?.[UI_STREAM_HOST_CONTEXT_KEY];
48
+ const parsed = uiStreamHostContextSchema.safeParse(candidate);
49
+ return parsed.success ? parsed.data : undefined;
50
+ }
51
+ export function getVisualizationStreamEnvelope(structuredContent) {
52
+ if (!structuredContent || typeof structuredContent !== "object" || Array.isArray(structuredContent)) {
53
+ return;
54
+ }
55
+ const candidate = structuredContent[UI_STREAM_STRUCTURED_CONTENT_KEY];
56
+ const parsed = visualizationStreamEnvelopeSchema.safeParse(candidate);
57
+ return parsed.success ? parsed.data : undefined;
58
+ }
@@ -0,0 +1,26 @@
1
+ export function extractUiToolVisibility(meta) {
2
+ if (!meta || typeof meta !== "object")
3
+ return;
4
+ const ui = meta.ui;
5
+ if (!ui || typeof ui !== "object" || Array.isArray(ui))
6
+ return;
7
+ const visibility = ui.visibility;
8
+ if (visibility === undefined)
9
+ return;
10
+ if (!Array.isArray(visibility))
11
+ return [];
12
+ const values = [];
13
+ for (const entry of visibility) {
14
+ if (entry !== "model" && entry !== "app")
15
+ return [];
16
+ if (!values.includes(entry))
17
+ values.push(entry);
18
+ }
19
+ return values;
20
+ }
21
+ export function isUiToolVisibleToModel(visibility) {
22
+ return visibility === undefined || visibility.includes("model");
23
+ }
24
+ export function isUiToolCallableByApp(visibility) {
25
+ return visibility === undefined || visibility.includes("app");
26
+ }