@eclipse-docks/extension-webmcp 0.8.13 → 0.8.14
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/dist/index.js
CHANGED
|
@@ -1,14 +1,13 @@
|
|
|
1
1
|
import { extensionRegistry } from "@eclipse-docks/core";
|
|
2
2
|
import pkg from "../package.json";
|
|
3
|
-
|
|
3
|
+
// src/index.ts
|
|
4
4
|
extensionRegistry.registerExtension({
|
|
5
5
|
id: pkg.name,
|
|
6
6
|
name: "WebMCP",
|
|
7
7
|
description: "Exposes app commands as WebMCP tools for browser agents and MCP clients",
|
|
8
|
-
loader: () => import("./webmcp-extension-
|
|
8
|
+
loader: () => import("./webmcp-extension-Ba9VDevx.js"),
|
|
9
9
|
icon: "plug",
|
|
10
10
|
experimental: true
|
|
11
11
|
});
|
|
12
|
-
//#endregion
|
|
13
12
|
|
|
14
13
|
//# sourceMappingURL=index.js.map
|
|
@@ -1,5 +1,5 @@
|
|
|
1
1
|
import { TOPIC_COMMAND_REGISTERED, commandRegistry, createLogger, subscribe, unsubscribe } from "@eclipse-docks/core";
|
|
2
|
-
|
|
2
|
+
// src/command-tool-schema.ts
|
|
3
3
|
/** Sanitize names for OpenAI-style function/parameter ids. */
|
|
4
4
|
function sanitizeFunctionName(name) {
|
|
5
5
|
return name.replace(/[^a-zA-Z0-9_-]/g, "_").replace(/^[^a-zA-Z]/, "cmd_$&").replace(/_+/g, "_").replace(/^_|_$/g, "");
|
|
@@ -27,8 +27,7 @@ function commandToToolSchema(command) {
|
|
|
27
27
|
}
|
|
28
28
|
};
|
|
29
29
|
}
|
|
30
|
-
|
|
31
|
-
//#region src/execute-command-tool.ts
|
|
30
|
+
// src/execute-command-tool.ts
|
|
32
31
|
var logger$1 = createLogger("WebMCP");
|
|
33
32
|
function normalizeToolInput(inputObject) {
|
|
34
33
|
if (inputObject == null) return {};
|
|
@@ -74,8 +73,7 @@ async function executeCommandTool(commandId, inputObject, signal) {
|
|
|
74
73
|
throw error instanceof Error ? error : new Error(message);
|
|
75
74
|
}
|
|
76
75
|
}
|
|
77
|
-
|
|
78
|
-
//#region src/get-model-context.ts
|
|
76
|
+
// src/get-model-context.ts
|
|
79
77
|
function getModelContext() {
|
|
80
78
|
if (typeof document !== "undefined") {
|
|
81
79
|
const { modelContext } = document;
|
|
@@ -83,8 +81,7 @@ function getModelContext() {
|
|
|
83
81
|
}
|
|
84
82
|
if (typeof navigator !== "undefined" && navigator.modelContext) return navigator.modelContext;
|
|
85
83
|
}
|
|
86
|
-
|
|
87
|
-
//#region src/sanitize-tool-name.ts
|
|
84
|
+
// src/sanitize-tool-name.ts
|
|
88
85
|
var WEBMCP_TOOL_NAME_MAX_LENGTH = 128;
|
|
89
86
|
function sanitizeWebMcpToolName(name) {
|
|
90
87
|
let sanitized = name.replace(/[^a-zA-Z0-9_.-]/g, "_").replace(/^[^a-zA-Z]/, "cmd_$&").replace(/_+/g, "_").replace(/^_|_$/g, "");
|
|
@@ -92,8 +89,7 @@ function sanitizeWebMcpToolName(name) {
|
|
|
92
89
|
if (sanitized.length > WEBMCP_TOOL_NAME_MAX_LENGTH) sanitized = sanitized.slice(0, WEBMCP_TOOL_NAME_MAX_LENGTH);
|
|
93
90
|
return sanitized;
|
|
94
91
|
}
|
|
95
|
-
|
|
96
|
-
//#region src/webmcp-service.ts
|
|
92
|
+
// src/webmcp-service.ts
|
|
97
93
|
var logger = createLogger("WebMCP");
|
|
98
94
|
var READ_ONLY_COMMAND_IDS = /* @__PURE__ */ new Set([
|
|
99
95
|
"ls",
|
|
@@ -215,15 +211,13 @@ var WebMCPService = class {
|
|
|
215
211
|
}
|
|
216
212
|
}
|
|
217
213
|
};
|
|
218
|
-
|
|
219
|
-
//#region src/webmcp-extension.ts
|
|
214
|
+
// src/webmcp-extension.ts
|
|
220
215
|
var activeService = null;
|
|
221
216
|
var webmcp_extension_default = async (_uiContext) => {
|
|
222
217
|
if (activeService) activeService.stop();
|
|
223
218
|
activeService = new WebMCPService();
|
|
224
219
|
await activeService.start();
|
|
225
220
|
};
|
|
226
|
-
//#endregion
|
|
227
221
|
export { webmcp_extension_default as default };
|
|
228
222
|
|
|
229
|
-
//# sourceMappingURL=webmcp-extension-
|
|
223
|
+
//# sourceMappingURL=webmcp-extension-Ba9VDevx.js.map
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"webmcp-extension-B8sAANqe.js","names":["logger"],"sources":["../src/command-tool-schema.ts","../src/execute-command-tool.ts","../src/get-model-context.ts","../src/sanitize-tool-name.ts","../src/webmcp-service.ts","../src/webmcp-extension.ts"],"sourcesContent":["import type { Command } from '@eclipse-docks/core';\n\nexport interface CommandToolSchema {\n name: string;\n description: string;\n parameters: {\n type: 'object';\n properties: Record<string, { type: string; description: string; enum?: string[] }>;\n required: string[];\n };\n}\n\n/** Sanitize names for OpenAI-style function/parameter ids. */\nexport function sanitizeFunctionName(name: string): string {\n return name\n .replace(/[^a-zA-Z0-9_-]/g, '_')\n .replace(/^[^a-zA-Z]/, 'cmd_$&')\n .replace(/_+/g, '_')\n .replace(/^_|_$/g, '');\n}\n\n/** Map a Docks command to a flat tool schema for WebMCP. */\nexport function commandToToolSchema(command: Command): CommandToolSchema {\n const properties: CommandToolSchema['parameters']['properties'] = {};\n const required: string[] = [];\n\n for (const param of command.parameters ?? []) {\n const sanitizedParamName = sanitizeFunctionName(param.name);\n properties[sanitizedParamName] = {\n type: param.type || 'string',\n description: param.description,\n ...(param.allowedValues ? { enum: param.allowedValues } : {}),\n };\n if (param.required === true) required.push(sanitizedParamName);\n }\n\n return {\n name: sanitizeFunctionName(command.id),\n description: String(command.description || command.name || command.id),\n parameters: { type: 'object', properties, required },\n };\n}\n","import { commandRegistry, createLogger, type Command } from \"@eclipse-docks/core\";\nimport { sanitizeFunctionName } from \"./command-tool-schema\";\n\nconst logger = createLogger(\"WebMCP\");\n\nfunction normalizeToolInput(inputObject: unknown): Record<string, unknown> {\n if (inputObject == null) {\n return {};\n }\n\n if (typeof inputObject === \"string\") {\n try {\n const parsed: unknown = JSON.parse(inputObject);\n return normalizeToolInput(parsed);\n } catch {\n return {};\n }\n }\n\n if (typeof inputObject !== \"object\" || Array.isArray(inputObject)) {\n return {};\n }\n\n const record = inputObject as Record<string, unknown>;\n if (\n \"params\" in record &&\n record.params != null &&\n typeof record.params === \"object\" &&\n !Array.isArray(record.params)\n ) {\n return record.params as Record<string, unknown>;\n }\n\n return record;\n}\n\nfunction sanitizeArguments(\n args: Record<string, unknown>,\n command: Command | undefined\n): Record<string, unknown> {\n if (!command?.parameters?.length) {\n return args;\n }\n\n const sanitizedArgs: Record<string, unknown> = {};\n for (const param of command.parameters) {\n const sanitizedParamName = sanitizeFunctionName(param.name);\n if (sanitizedParamName in args) {\n sanitizedArgs[param.name] = args[sanitizedParamName];\n continue;\n }\n if (param.name in args) {\n sanitizedArgs[param.name] = args[param.name];\n }\n }\n return sanitizedArgs;\n}\n\nfunction formatCommandResult(result: unknown): unknown {\n if (result === undefined || result === null) {\n return \"Done\";\n }\n return result;\n}\n\nexport async function executeCommandTool(\n commandId: string,\n inputObject: unknown,\n signal?: AbortSignal\n): Promise<unknown> {\n if (signal?.aborted) {\n throw signal.reason ?? new DOMException(\"The tool execution was aborted.\", \"AbortError\");\n }\n\n const command = commandRegistry.getCommand(commandId);\n const args = sanitizeArguments(normalizeToolInput(inputObject), command);\n const execContext = commandRegistry.createExecutionContext(args);\n\n try {\n const result = await commandRegistry.execute(commandId, execContext);\n\n if (signal?.aborted) {\n throw signal.reason ?? new DOMException(\"The tool execution was aborted.\", \"AbortError\");\n }\n\n return formatCommandResult(result);\n } catch (error) {\n const message = error instanceof Error ? error.message : String(error);\n logger.error(`Command \"${commandId}\" failed: ${message}`);\n throw error instanceof Error ? error : new Error(message);\n }\n}\n","import type { ModelContext } from \"./model-context\";\n\nexport function getModelContext(): ModelContext | undefined {\n if (typeof document !== \"undefined\") {\n const { modelContext } = document;\n if (modelContext) {\n return modelContext;\n }\n }\n\n if (typeof navigator !== \"undefined\" && navigator.modelContext) {\n return navigator.modelContext;\n }\n\n return undefined;\n}\n\nexport function isModelContextAvailable(): boolean {\n return getModelContext() !== undefined;\n}\n","const WEBMCP_TOOL_NAME_MAX_LENGTH = 128;\n\nexport function sanitizeWebMcpToolName(name: string): string {\n let sanitized = name\n .replace(/[^a-zA-Z0-9_.-]/g, \"_\")\n .replace(/^[^a-zA-Z]/, \"cmd_$&\")\n .replace(/_+/g, \"_\")\n .replace(/^_|_$/g, \"\");\n\n if (!sanitized) {\n sanitized = \"tool\";\n }\n\n if (sanitized.length > WEBMCP_TOOL_NAME_MAX_LENGTH) {\n sanitized = sanitized.slice(0, WEBMCP_TOOL_NAME_MAX_LENGTH);\n }\n\n return sanitized;\n}\n","import {\n commandRegistry,\n createLogger,\n subscribe,\n unsubscribe,\n TOPIC_COMMAND_REGISTERED,\n} from \"@eclipse-docks/core\";\nimport type { Command } from \"@eclipse-docks/core\";\nimport { commandToToolSchema } from \"./command-tool-schema\";\nimport { executeCommandTool } from \"./execute-command-tool\";\nimport { getModelContext } from \"./get-model-context\";\nimport { sanitizeWebMcpToolName } from \"./sanitize-tool-name\";\n\nconst logger = createLogger(\"WebMCP\");\n\nconst READ_ONLY_COMMAND_IDS = new Set([\n \"ls\",\n \"cat\",\n \"head\",\n \"tail\",\n \"exists\",\n \"wc\",\n \"version-info\",\n \"js\",\n]);\n\nconst APP_LOADED_EVENT = \"app-loaded\";\n\nfunction resolveCommandText(value: unknown, fallback: string): string {\n if (value == null) return fallback;\n const text = typeof value === 'function' ? String(value()) : String(value);\n return text.trim() || fallback;\n}\n\nfunction toolDescription(command: Command, description: string): string {\n return resolveCommandText(\n description || command.description || command.name || command.id,\n command.id,\n );\n}\n\nexport class WebMCPService {\n private readonly registrationControllers = new Map<string, AbortController>();\n private readonly registeredIds = new Set<string>();\n private readonly registeredToolNames = new Set<string>();\n private readonly pendingRegistrations = new Set<string>();\n private commandSubscriptionToken: ReturnType<typeof subscribe> | null = null;\n private appLoadedListener: (() => void) | null = null;\n\n async start(): Promise<void> {\n if (!getModelContext()) {\n logger.info(\"Web Model Context API not available in this browser.\");\n return;\n }\n\n this.commandSubscriptionToken = subscribe(TOPIC_COMMAND_REGISTERED, (command: Command) => {\n void this.registerCommand(command);\n });\n\n this.appLoadedListener = () => {\n void this.syncAllCommands(\"app-loaded\");\n };\n window.addEventListener(APP_LOADED_EVENT, this.appLoadedListener, { once: true });\n\n await this.syncAllCommands(\"startup\");\n }\n\n stop(): void {\n if (this.appLoadedListener) {\n window.removeEventListener(APP_LOADED_EVENT, this.appLoadedListener);\n this.appLoadedListener = null;\n }\n\n if (this.commandSubscriptionToken !== null) {\n unsubscribe(this.commandSubscriptionToken);\n this.commandSubscriptionToken = null;\n }\n\n for (const controller of this.registrationControllers.values()) {\n controller.abort();\n }\n this.registrationControllers.clear();\n this.registeredIds.clear();\n this.registeredToolNames.clear();\n this.pendingRegistrations.clear();\n }\n\n private toolDefToInputSchema(params: {\n properties?: Record<string, unknown>;\n required?: string[];\n }): Record<string, unknown> {\n return {\n type: \"object\",\n properties: params.properties ?? {},\n ...(params.required?.length ? { required: params.required } : {}),\n };\n }\n\n private isReadOnlyCommand(command: Command): boolean {\n return READ_ONLY_COMMAND_IDS.has(command.id);\n }\n\n private async syncAllCommands(reason: string): Promise<void> {\n const commands = Object.values(commandRegistry.listCommands()) as Command[];\n const results = await Promise.all(commands.map((command) => this.registerCommand(command)));\n const registeredCount = results.filter(Boolean).length;\n logger.info(`Synced ${registeredCount}/${commands.length} command(s) as WebMCP tools (${reason}).`);\n\n const modelContext = getModelContext();\n if (modelContext?.getTools) {\n try {\n const tools = await modelContext.getTools();\n logger.info(`document.modelContext.getTools() reports ${tools.length} tool(s).`);\n } catch (error) {\n logger.warn(\"document.modelContext.getTools() failed:\", error);\n }\n }\n }\n\n private async registerCommand(command: Command): Promise<boolean> {\n if (this.registeredIds.has(command.id) || this.pendingRegistrations.has(command.id)) {\n return false;\n }\n\n const modelContext = getModelContext();\n if (!modelContext) return false;\n\n const toolName = sanitizeWebMcpToolName(command.id);\n if (this.registeredToolNames.has(toolName)) {\n logger.warn(`Skipping command \"${command.id}\": WebMCP tool name \"${toolName}\" is already registered.`);\n return false;\n }\n\n this.pendingRegistrations.add(command.id);\n\n const toolDef = commandToToolSchema(command);\n const commandId = command.id;\n\n const registrationController = new AbortController();\n\n try {\n await modelContext.registerTool(\n {\n name: toolName,\n title: resolveCommandText(command.name, command.id),\n description: toolDescription(command, toolDef.description),\n inputSchema: this.toolDefToInputSchema(toolDef.parameters),\n annotations: {\n readOnlyHint: this.isReadOnlyCommand(command),\n },\n async execute(inputObject, options?) {\n return executeCommandTool(commandId, inputObject, options?.signal);\n },\n },\n { signal: registrationController.signal }\n );\n\n this.registrationControllers.set(toolName, registrationController);\n this.registeredIds.add(command.id);\n this.registeredToolNames.add(toolName);\n return true;\n } catch (error) {\n registrationController.abort();\n if (error instanceof DOMException && error.name === 'InvalidStateError') {\n this.registeredIds.add(command.id);\n this.registeredToolNames.add(toolName);\n return true;\n }\n logger.warn(`Failed to register WebMCP tool \"${toolName}\" for command \"${commandId}\":`, error);\n return false;\n } finally {\n this.pendingRegistrations.delete(command.id);\n }\n }\n}\n","import { WebMCPService } from \"./webmcp-service\";\n\nlet activeService: WebMCPService | null = null;\n\nexport default async (_uiContext: unknown): Promise<void> => {\n if (activeService) {\n activeService.stop();\n }\n\n activeService = new WebMCPService();\n await activeService.start();\n};\n"],"mappings":"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"}
|
|
1
|
+
{"version":3,"file":"webmcp-extension-Ba9VDevx.js","names":["logger"],"sources":["../src/command-tool-schema.ts","../src/execute-command-tool.ts","../src/get-model-context.ts","../src/sanitize-tool-name.ts","../src/webmcp-service.ts","../src/webmcp-extension.ts"],"sourcesContent":["import type { Command } from '@eclipse-docks/core';\n\nexport interface CommandToolSchema {\n name: string;\n description: string;\n parameters: {\n type: 'object';\n properties: Record<string, { type: string; description: string; enum?: string[] }>;\n required: string[];\n };\n}\n\n/** Sanitize names for OpenAI-style function/parameter ids. */\nexport function sanitizeFunctionName(name: string): string {\n return name\n .replace(/[^a-zA-Z0-9_-]/g, '_')\n .replace(/^[^a-zA-Z]/, 'cmd_$&')\n .replace(/_+/g, '_')\n .replace(/^_|_$/g, '');\n}\n\n/** Map a Docks command to a flat tool schema for WebMCP. */\nexport function commandToToolSchema(command: Command): CommandToolSchema {\n const properties: CommandToolSchema['parameters']['properties'] = {};\n const required: string[] = [];\n\n for (const param of command.parameters ?? []) {\n const sanitizedParamName = sanitizeFunctionName(param.name);\n properties[sanitizedParamName] = {\n type: param.type || 'string',\n description: param.description,\n ...(param.allowedValues ? { enum: param.allowedValues } : {}),\n };\n if (param.required === true) required.push(sanitizedParamName);\n }\n\n return {\n name: sanitizeFunctionName(command.id),\n description: String(command.description || command.name || command.id),\n parameters: { type: 'object', properties, required },\n };\n}\n","import { commandRegistry, createLogger, type Command } from \"@eclipse-docks/core\";\nimport { sanitizeFunctionName } from \"./command-tool-schema\";\n\nconst logger = createLogger(\"WebMCP\");\n\nfunction normalizeToolInput(inputObject: unknown): Record<string, unknown> {\n if (inputObject == null) {\n return {};\n }\n\n if (typeof inputObject === \"string\") {\n try {\n const parsed: unknown = JSON.parse(inputObject);\n return normalizeToolInput(parsed);\n } catch {\n return {};\n }\n }\n\n if (typeof inputObject !== \"object\" || Array.isArray(inputObject)) {\n return {};\n }\n\n const record = inputObject as Record<string, unknown>;\n if (\n \"params\" in record &&\n record.params != null &&\n typeof record.params === \"object\" &&\n !Array.isArray(record.params)\n ) {\n return record.params as Record<string, unknown>;\n }\n\n return record;\n}\n\nfunction sanitizeArguments(\n args: Record<string, unknown>,\n command: Command | undefined\n): Record<string, unknown> {\n if (!command?.parameters?.length) {\n return args;\n }\n\n const sanitizedArgs: Record<string, unknown> = {};\n for (const param of command.parameters) {\n const sanitizedParamName = sanitizeFunctionName(param.name);\n if (sanitizedParamName in args) {\n sanitizedArgs[param.name] = args[sanitizedParamName];\n continue;\n }\n if (param.name in args) {\n sanitizedArgs[param.name] = args[param.name];\n }\n }\n return sanitizedArgs;\n}\n\nfunction formatCommandResult(result: unknown): unknown {\n if (result === undefined || result === null) {\n return \"Done\";\n }\n return result;\n}\n\nexport async function executeCommandTool(\n commandId: string,\n inputObject: unknown,\n signal?: AbortSignal\n): Promise<unknown> {\n if (signal?.aborted) {\n throw signal.reason ?? new DOMException(\"The tool execution was aborted.\", \"AbortError\");\n }\n\n const command = commandRegistry.getCommand(commandId);\n const args = sanitizeArguments(normalizeToolInput(inputObject), command);\n const execContext = commandRegistry.createExecutionContext(args);\n\n try {\n const result = await commandRegistry.execute(commandId, execContext);\n\n if (signal?.aborted) {\n throw signal.reason ?? new DOMException(\"The tool execution was aborted.\", \"AbortError\");\n }\n\n return formatCommandResult(result);\n } catch (error) {\n const message = error instanceof Error ? error.message : String(error);\n logger.error(`Command \"${commandId}\" failed: ${message}`);\n throw error instanceof Error ? error : new Error(message);\n }\n}\n","import type { ModelContext } from \"./model-context\";\n\nexport function getModelContext(): ModelContext | undefined {\n if (typeof document !== \"undefined\") {\n const { modelContext } = document;\n if (modelContext) {\n return modelContext;\n }\n }\n\n if (typeof navigator !== \"undefined\" && navigator.modelContext) {\n return navigator.modelContext;\n }\n\n return undefined;\n}\n\nexport function isModelContextAvailable(): boolean {\n return getModelContext() !== undefined;\n}\n","const WEBMCP_TOOL_NAME_MAX_LENGTH = 128;\n\nexport function sanitizeWebMcpToolName(name: string): string {\n let sanitized = name\n .replace(/[^a-zA-Z0-9_.-]/g, \"_\")\n .replace(/^[^a-zA-Z]/, \"cmd_$&\")\n .replace(/_+/g, \"_\")\n .replace(/^_|_$/g, \"\");\n\n if (!sanitized) {\n sanitized = \"tool\";\n }\n\n if (sanitized.length > WEBMCP_TOOL_NAME_MAX_LENGTH) {\n sanitized = sanitized.slice(0, WEBMCP_TOOL_NAME_MAX_LENGTH);\n }\n\n return sanitized;\n}\n","import {\n commandRegistry,\n createLogger,\n subscribe,\n unsubscribe,\n TOPIC_COMMAND_REGISTERED,\n} from \"@eclipse-docks/core\";\nimport type { Command } from \"@eclipse-docks/core\";\nimport { commandToToolSchema } from \"./command-tool-schema\";\nimport { executeCommandTool } from \"./execute-command-tool\";\nimport { getModelContext } from \"./get-model-context\";\nimport { sanitizeWebMcpToolName } from \"./sanitize-tool-name\";\n\nconst logger = createLogger(\"WebMCP\");\n\nconst READ_ONLY_COMMAND_IDS = new Set([\n \"ls\",\n \"cat\",\n \"head\",\n \"tail\",\n \"exists\",\n \"wc\",\n \"version-info\",\n \"js\",\n]);\n\nconst APP_LOADED_EVENT = \"app-loaded\";\n\nfunction resolveCommandText(value: unknown, fallback: string): string {\n if (value == null) return fallback;\n const text = typeof value === 'function' ? String(value()) : String(value);\n return text.trim() || fallback;\n}\n\nfunction toolDescription(command: Command, description: string): string {\n return resolveCommandText(\n description || command.description || command.name || command.id,\n command.id,\n );\n}\n\nexport class WebMCPService {\n private readonly registrationControllers = new Map<string, AbortController>();\n private readonly registeredIds = new Set<string>();\n private readonly registeredToolNames = new Set<string>();\n private readonly pendingRegistrations = new Set<string>();\n private commandSubscriptionToken: ReturnType<typeof subscribe> | null = null;\n private appLoadedListener: (() => void) | null = null;\n\n async start(): Promise<void> {\n if (!getModelContext()) {\n logger.info(\"Web Model Context API not available in this browser.\");\n return;\n }\n\n this.commandSubscriptionToken = subscribe(TOPIC_COMMAND_REGISTERED, (command: Command) => {\n void this.registerCommand(command);\n });\n\n this.appLoadedListener = () => {\n void this.syncAllCommands(\"app-loaded\");\n };\n window.addEventListener(APP_LOADED_EVENT, this.appLoadedListener, { once: true });\n\n await this.syncAllCommands(\"startup\");\n }\n\n stop(): void {\n if (this.appLoadedListener) {\n window.removeEventListener(APP_LOADED_EVENT, this.appLoadedListener);\n this.appLoadedListener = null;\n }\n\n if (this.commandSubscriptionToken !== null) {\n unsubscribe(this.commandSubscriptionToken);\n this.commandSubscriptionToken = null;\n }\n\n for (const controller of this.registrationControllers.values()) {\n controller.abort();\n }\n this.registrationControllers.clear();\n this.registeredIds.clear();\n this.registeredToolNames.clear();\n this.pendingRegistrations.clear();\n }\n\n private toolDefToInputSchema(params: {\n properties?: Record<string, unknown>;\n required?: string[];\n }): Record<string, unknown> {\n return {\n type: \"object\",\n properties: params.properties ?? {},\n ...(params.required?.length ? { required: params.required } : {}),\n };\n }\n\n private isReadOnlyCommand(command: Command): boolean {\n return READ_ONLY_COMMAND_IDS.has(command.id);\n }\n\n private async syncAllCommands(reason: string): Promise<void> {\n const commands = Object.values(commandRegistry.listCommands()) as Command[];\n const results = await Promise.all(commands.map((command) => this.registerCommand(command)));\n const registeredCount = results.filter(Boolean).length;\n logger.info(`Synced ${registeredCount}/${commands.length} command(s) as WebMCP tools (${reason}).`);\n\n const modelContext = getModelContext();\n if (modelContext?.getTools) {\n try {\n const tools = await modelContext.getTools();\n logger.info(`document.modelContext.getTools() reports ${tools.length} tool(s).`);\n } catch (error) {\n logger.warn(\"document.modelContext.getTools() failed:\", error);\n }\n }\n }\n\n private async registerCommand(command: Command): Promise<boolean> {\n if (this.registeredIds.has(command.id) || this.pendingRegistrations.has(command.id)) {\n return false;\n }\n\n const modelContext = getModelContext();\n if (!modelContext) return false;\n\n const toolName = sanitizeWebMcpToolName(command.id);\n if (this.registeredToolNames.has(toolName)) {\n logger.warn(`Skipping command \"${command.id}\": WebMCP tool name \"${toolName}\" is already registered.`);\n return false;\n }\n\n this.pendingRegistrations.add(command.id);\n\n const toolDef = commandToToolSchema(command);\n const commandId = command.id;\n\n const registrationController = new AbortController();\n\n try {\n await modelContext.registerTool(\n {\n name: toolName,\n title: resolveCommandText(command.name, command.id),\n description: toolDescription(command, toolDef.description),\n inputSchema: this.toolDefToInputSchema(toolDef.parameters),\n annotations: {\n readOnlyHint: this.isReadOnlyCommand(command),\n },\n async execute(inputObject, options?) {\n return executeCommandTool(commandId, inputObject, options?.signal);\n },\n },\n { signal: registrationController.signal }\n );\n\n this.registrationControllers.set(toolName, registrationController);\n this.registeredIds.add(command.id);\n this.registeredToolNames.add(toolName);\n return true;\n } catch (error) {\n registrationController.abort();\n if (error instanceof DOMException && error.name === 'InvalidStateError') {\n this.registeredIds.add(command.id);\n this.registeredToolNames.add(toolName);\n return true;\n }\n logger.warn(`Failed to register WebMCP tool \"${toolName}\" for command \"${commandId}\":`, error);\n return false;\n } finally {\n this.pendingRegistrations.delete(command.id);\n }\n }\n}\n","import { WebMCPService } from \"./webmcp-service\";\n\nlet activeService: WebMCPService | null = null;\n\nexport default async (_uiContext: unknown): Promise<void> => {\n if (activeService) {\n activeService.stop();\n }\n\n activeService = new WebMCPService();\n await activeService.start();\n};\n"],"mappings":"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"}
|