@tempad-dev/mcp 0.3.5 → 0.3.7

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/request.mjs DELETED
@@ -1,68 +0,0 @@
1
- import { log } from "./shared.mjs";
2
- import { nanoid } from "nanoid";
3
-
4
- //#region src/request.ts
5
- const pendingCalls = /* @__PURE__ */ new Map();
6
- function register(extensionId, timeout) {
7
- const requestId = nanoid();
8
- return {
9
- promise: new Promise((resolve$1, reject$1) => {
10
- const timer = setTimeout(() => {
11
- pendingCalls.delete(requestId);
12
- reject$1(/* @__PURE__ */ new Error(`Extension did not respond within ${timeout / 1e3}s.`));
13
- }, timeout);
14
- pendingCalls.set(requestId, {
15
- resolve: resolve$1,
16
- reject: reject$1,
17
- timer,
18
- extensionId
19
- });
20
- }),
21
- requestId
22
- };
23
- }
24
- function resolve(requestId, payload) {
25
- const call = pendingCalls.get(requestId);
26
- if (call) {
27
- const { timer, resolve: finish } = call;
28
- clearTimeout(timer);
29
- finish(payload);
30
- pendingCalls.delete(requestId);
31
- } else log.warn({ reqId: requestId }, "Received result for unknown/timed-out call.");
32
- }
33
- function reject(requestId, error) {
34
- const call = pendingCalls.get(requestId);
35
- if (call) {
36
- const { timer, reject: fail } = call;
37
- clearTimeout(timer);
38
- fail(error);
39
- pendingCalls.delete(requestId);
40
- } else log.warn({ reqId: requestId }, "Received error for unknown/timed-out call.");
41
- }
42
- function cleanupForExtension(extensionId) {
43
- for (const [reqId, call] of pendingCalls.entries()) {
44
- const { timer, reject: fail, extensionId: extId } = call;
45
- if (extId === extensionId) {
46
- clearTimeout(timer);
47
- fail(/* @__PURE__ */ new Error("Extension disconnected before providing a result."));
48
- pendingCalls.delete(reqId);
49
- log.warn({
50
- reqId,
51
- extId: extensionId
52
- }, "Rejected pending call from disconnected extension.");
53
- }
54
- }
55
- }
56
- function cleanupAll() {
57
- pendingCalls.forEach((call, reqId) => {
58
- const { timer, reject: fail } = call;
59
- clearTimeout(timer);
60
- fail(/* @__PURE__ */ new Error("Hub is shutting down."));
61
- log.debug({ reqId }, "Rejected pending tool call due to shutdown.");
62
- });
63
- pendingCalls.clear();
64
- }
65
-
66
- //#endregion
67
- export { cleanupAll, cleanupForExtension, register, reject, resolve };
68
- //# sourceMappingURL=request.mjs.map
@@ -1 +0,0 @@
1
- {"version":3,"file":"request.mjs","names":["resolve"],"sources":["../src/request.ts"],"sourcesContent":["import { nanoid } from 'nanoid'\n\nimport type { PendingToolCall } from './types'\n\nimport { log } from './shared'\n\nconst pendingCalls = new Map<string, PendingToolCall>()\n\nexport function register<T>(\n extensionId: string,\n timeout: number\n): { promise: Promise<T>; requestId: string } {\n const requestId = nanoid()\n const promise = new Promise<T>((resolve, reject) => {\n const timer = setTimeout(() => {\n pendingCalls.delete(requestId)\n reject(new Error(`Extension did not respond within ${timeout / 1000}s.`))\n }, timeout)\n\n pendingCalls.set(requestId, {\n resolve: resolve as (value: unknown) => void,\n reject,\n timer,\n extensionId\n })\n })\n return { promise, requestId }\n}\n\nexport function resolve(requestId: string, payload: unknown): void {\n const call = pendingCalls.get(requestId)\n if (call) {\n const { timer, resolve: finish } = call\n clearTimeout(timer)\n finish(payload)\n pendingCalls.delete(requestId)\n } else {\n log.warn({ reqId: requestId }, 'Received result for unknown/timed-out call.')\n }\n}\n\nexport function reject(requestId: string, error: Error): void {\n const call = pendingCalls.get(requestId)\n if (call) {\n const { timer, reject: fail } = call\n clearTimeout(timer)\n fail(error)\n pendingCalls.delete(requestId)\n } else {\n log.warn({ reqId: requestId }, 'Received error for unknown/timed-out call.')\n }\n}\n\nexport function cleanupForExtension(extensionId: string): void {\n for (const [reqId, call] of pendingCalls.entries()) {\n const { timer, reject: fail, extensionId: extId } = call\n if (extId === extensionId) {\n clearTimeout(timer)\n fail(new Error('Extension disconnected before providing a result.'))\n pendingCalls.delete(reqId)\n log.warn({ reqId, extId: extensionId }, 'Rejected pending call from disconnected extension.')\n }\n }\n}\n\nexport function cleanupAll(): void {\n pendingCalls.forEach((call, reqId) => {\n const { timer, reject: fail } = call\n clearTimeout(timer)\n fail(new Error('Hub is shutting down.'))\n log.debug({ reqId }, 'Rejected pending tool call due to shutdown.')\n })\n pendingCalls.clear()\n}\n"],"mappings":";;;;AAMA,MAAM,+BAAe,IAAI,KAA8B;AAEvD,SAAgB,SACd,aACA,SAC4C;CAC5C,MAAM,YAAY,QAAQ;AAc1B,QAAO;EAAE,SAbO,IAAI,SAAY,WAAS,aAAW;GAClD,MAAM,QAAQ,iBAAiB;AAC7B,iBAAa,OAAO,UAAU;AAC9B,6BAAO,IAAI,MAAM,oCAAoC,UAAU,IAAK,IAAI,CAAC;MACxE,QAAQ;AAEX,gBAAa,IAAI,WAAW;IAC1B,SAASA;IACT;IACA;IACA;IACD,CAAC;IACF;EACgB;EAAW;;AAG/B,SAAgB,QAAQ,WAAmB,SAAwB;CACjE,MAAM,OAAO,aAAa,IAAI,UAAU;AACxC,KAAI,MAAM;EACR,MAAM,EAAE,OAAO,SAAS,WAAW;AACnC,eAAa,MAAM;AACnB,SAAO,QAAQ;AACf,eAAa,OAAO,UAAU;OAE9B,KAAI,KAAK,EAAE,OAAO,WAAW,EAAE,8CAA8C;;AAIjF,SAAgB,OAAO,WAAmB,OAAoB;CAC5D,MAAM,OAAO,aAAa,IAAI,UAAU;AACxC,KAAI,MAAM;EACR,MAAM,EAAE,OAAO,QAAQ,SAAS;AAChC,eAAa,MAAM;AACnB,OAAK,MAAM;AACX,eAAa,OAAO,UAAU;OAE9B,KAAI,KAAK,EAAE,OAAO,WAAW,EAAE,6CAA6C;;AAIhF,SAAgB,oBAAoB,aAA2B;AAC7D,MAAK,MAAM,CAAC,OAAO,SAAS,aAAa,SAAS,EAAE;EAClD,MAAM,EAAE,OAAO,QAAQ,MAAM,aAAa,UAAU;AACpD,MAAI,UAAU,aAAa;AACzB,gBAAa,MAAM;AACnB,wBAAK,IAAI,MAAM,oDAAoD,CAAC;AACpE,gBAAa,OAAO,MAAM;AAC1B,OAAI,KAAK;IAAE;IAAO,OAAO;IAAa,EAAE,qDAAqD;;;;AAKnG,SAAgB,aAAmB;AACjC,cAAa,SAAS,MAAM,UAAU;EACpC,MAAM,EAAE,OAAO,QAAQ,SAAS;AAChC,eAAa,MAAM;AACnB,uBAAK,IAAI,MAAM,wBAAwB,CAAC;AACxC,MAAI,MAAM,EAAE,OAAO,EAAE,8CAA8C;GACnE;AACF,cAAa,OAAO"}
@@ -1 +0,0 @@
1
- {"version":3,"file":"shared.mjs","names":["packageJson"],"sources":["../src/shared.ts"],"sourcesContent":["import { closeSync, mkdirSync, openSync } from 'node:fs'\nimport { tmpdir } from 'node:os'\nimport { join } from 'node:path'\nimport pino from 'pino'\n\nimport packageJson from '../package.json' assert { type: 'json' }\n\nexport function ensureDir(dirPath: string): void {\n mkdirSync(dirPath, { recursive: true, mode: 0o700 })\n}\n\nconst pkg = packageJson as { version?: unknown }\nexport const PACKAGE_VERSION = typeof pkg.version === 'string' ? pkg.version : '0.0.0'\n\nfunction resolveRuntimeDir(): string {\n if (process.env.TEMPAD_MCP_RUNTIME_DIR) return process.env.TEMPAD_MCP_RUNTIME_DIR\n return join(tmpdir(), 'tempad-dev', 'run')\n}\n\nfunction resolveLogDir(): string {\n if (process.env.TEMPAD_MCP_LOG_DIR) return process.env.TEMPAD_MCP_LOG_DIR\n return join(tmpdir(), 'tempad-dev', 'log')\n}\n\nfunction resolveAssetDir(): string {\n if (process.env.TEMPAD_MCP_ASSET_DIR) return process.env.TEMPAD_MCP_ASSET_DIR\n return join(tmpdir(), 'tempad-dev', 'assets')\n}\n\nexport const RUNTIME_DIR = resolveRuntimeDir()\nexport const LOG_DIR = resolveLogDir()\nexport const ASSET_DIR = resolveAssetDir()\n\nensureDir(RUNTIME_DIR)\nensureDir(LOG_DIR)\nensureDir(ASSET_DIR)\n\nexport function ensureFile(filePath: string): void {\n const fd = openSync(filePath, 'a')\n closeSync(fd)\n}\n\nexport const LOCK_PATH = join(RUNTIME_DIR, 'mcp.lock')\nensureFile(LOCK_PATH)\n\nconst timestamp = new Date().toISOString().replaceAll(':', '-').replaceAll('.', '-')\nconst pid = process.pid\nconst LOG_FILE = join(LOG_DIR, `mcp-${timestamp}-${pid}.log`)\n\nconst prettyTransport = pino.transport({\n target: 'pino-pretty',\n options: {\n translateTime: 'SYS:HH:MM:ss',\n destination: LOG_FILE\n }\n})\n\nexport const log = pino(\n {\n level: process.env.DEBUG ? 'debug' : 'info',\n msgPrefix: '[tempad-dev/mcp] '\n },\n prettyTransport\n)\n\nexport const SOCK_PATH =\n process.platform === 'win32' ? '\\\\\\\\.\\\\pipe\\\\tempad-mcp' : join(RUNTIME_DIR, 'mcp.sock')\n"],"mappings":";;;;;;;AAOA,SAAgB,UAAU,SAAuB;AAC/C,WAAU,SAAS;EAAE,WAAW;EAAM,MAAM;EAAO,CAAC;;AAGtD,MAAM,MAAMA;AACZ,MAAa,kBAAkB,OAAO,IAAI,YAAY,WAAW,IAAI,UAAU;AAE/E,SAAS,oBAA4B;AACnC,KAAI,QAAQ,IAAI,uBAAwB,QAAO,QAAQ,IAAI;AAC3D,QAAO,KAAK,QAAQ,EAAE,cAAc,MAAM;;AAG5C,SAAS,gBAAwB;AAC/B,KAAI,QAAQ,IAAI,mBAAoB,QAAO,QAAQ,IAAI;AACvD,QAAO,KAAK,QAAQ,EAAE,cAAc,MAAM;;AAG5C,SAAS,kBAA0B;AACjC,KAAI,QAAQ,IAAI,qBAAsB,QAAO,QAAQ,IAAI;AACzD,QAAO,KAAK,QAAQ,EAAE,cAAc,SAAS;;AAG/C,MAAa,cAAc,mBAAmB;AAC9C,MAAa,UAAU,eAAe;AACtC,MAAa,YAAY,iBAAiB;AAE1C,UAAU,YAAY;AACtB,UAAU,QAAQ;AAClB,UAAU,UAAU;AAEpB,SAAgB,WAAW,UAAwB;AAEjD,WADW,SAAS,UAAU,IAAI,CACrB;;AAGf,MAAa,YAAY,KAAK,aAAa,WAAW;AACtD,WAAW,UAAU;AAErB,MAAM,6BAAY,IAAI,MAAM,EAAC,aAAa,CAAC,WAAW,KAAK,IAAI,CAAC,WAAW,KAAK,IAAI;AACpF,MAAM,MAAM,QAAQ;AACpB,MAAM,WAAW,KAAK,SAAS,OAAO,UAAU,GAAG,IAAI,MAAM;AAE7D,MAAM,kBAAkB,KAAK,UAAU;CACrC,QAAQ;CACR,SAAS;EACP,eAAe;EACf,aAAa;EACd;CACF,CAAC;AAEF,MAAa,MAAM,KACjB;CACE,OAAO,QAAQ,IAAI,QAAQ,UAAU;CACrC,WAAW;CACZ,EACD,gBACD;AAED,MAAa,YACX,QAAQ,aAAa,UAAU,4BAA4B,KAAK,aAAa,WAAW"}
package/dist/tools.mjs DELETED
@@ -1,146 +0,0 @@
1
- import { dirname, join } from "node:path";
2
- import { fileURLToPath } from "node:url";
3
- import { readFileSync } from "node:fs";
4
- import { GetAssetsParametersSchema, GetAssetsResultSchema, GetCodeParametersSchema, GetScreenshotParametersSchema, GetStructureParametersSchema, GetTokenDefsParametersSchema } from "@tempad-dev/mcp-shared";
5
-
6
- //#region src/tools.ts
7
- const HERE = dirname(fileURLToPath(import.meta.url));
8
- const MCP_INSTRUCTIONS = readFileSync(join(HERE, "instructions.md"), "utf8");
9
- function extTool(definition) {
10
- return definition;
11
- }
12
- function hubTool(definition) {
13
- return definition;
14
- }
15
- const TOOL_DEFS = [
16
- extTool({
17
- name: "get_code",
18
- description: "Get a high-fidelity code snapshot for a nodeId/current selection, including assets/usedTokens and codegen preset/config. Start here, then refactor into your component/styling/file/naming conventions; strip any data-* hints. If no data-hint-auto-layout is present, layout is explicit; if any hint is none/inferred, pair with get_structure/get_screenshot to confirm hierarchy/overlap. Use data-hint-component plus repetition to decide on reusable components. Replace resource URIs with your canonical asset system as needed.",
19
- parameters: GetCodeParametersSchema,
20
- target: "extension",
21
- format: createCodeToolResponse
22
- }),
23
- extTool({
24
- name: "get_token_defs",
25
- description: "Resolve canonical token names to values (including modes) for tokens referenced by get_code. Use this to map into your design token/theming system, including responsive tokens.",
26
- parameters: GetTokenDefsParametersSchema,
27
- target: "extension",
28
- exposed: false
29
- }),
30
- extTool({
31
- name: "get_screenshot",
32
- description: "Capture a rendered screenshot for a nodeId/current selection for visual verification. Useful for confirming layering/overlap/masks/shadows/translucency when auto-layout hints are none/inferred.",
33
- parameters: GetScreenshotParametersSchema,
34
- target: "extension",
35
- format: createScreenshotToolResponse
36
- }),
37
- extTool({
38
- name: "get_structure",
39
- description: "Get a structural + geometry outline for a nodeId/current selection to understand hierarchy and layout intent. Use when auto-layout hints are none/inferred or you need explicit bounds for refactors/component extraction.",
40
- parameters: GetStructureParametersSchema,
41
- target: "extension"
42
- }),
43
- hubTool({
44
- name: "get_assets",
45
- description: "Resolve asset hashes to downloadable URLs/URIs for assets referenced by get_code, preserving vectors exactly. Pull bytes before routing through your asset/icon pipeline.",
46
- parameters: GetAssetsParametersSchema,
47
- target: "hub",
48
- outputSchema: GetAssetsResultSchema,
49
- exposed: false
50
- })
51
- ];
52
- function createToolErrorResponse(toolName, error) {
53
- return { content: [{
54
- type: "text",
55
- text: `Tool "${toolName}" failed: ${error instanceof Error ? error.message || "Unknown error occurred." : typeof error === "string" ? error : "Unknown error occurred."}`
56
- }] };
57
- }
58
- function formatBytes(bytes) {
59
- if (bytes < 1024) return `${bytes} B`;
60
- if (bytes < 1024 * 1024) return `${(bytes / 1024).toFixed(1)} KB`;
61
- return `${(bytes / (1024 * 1024)).toFixed(1)} MB`;
62
- }
63
- function createCodeToolResponse(payload) {
64
- if (!isCodeResult(payload)) throw new Error("Invalid get_code payload received from extension.");
65
- const summary = [];
66
- const codeSize = Buffer.byteLength(payload.code, "utf8");
67
- summary.push(`Generated \`${payload.lang}\` snippet (${formatBytes(codeSize)}).`);
68
- if (payload.message) summary.push(payload.message);
69
- summary.push(payload.assets.length ? `Assets attached: ${payload.assets.length}. Fetch bytes via resources/read using resourceUri.` : "No binary assets were attached to this response.");
70
- const tokenCount = payload.usedTokens ? Object.keys(payload.usedTokens.tokens ?? {}).length : 0;
71
- if (tokenCount) summary.push(`Token references included: ${tokenCount}.`);
72
- summary.push("Read structuredContent for the full code string and asset metadata.");
73
- const assetLinks = payload.assets.length > 0 ? payload.assets.map((asset) => createAssetResourceLinkBlock(asset)) : [];
74
- return {
75
- content: [{
76
- type: "text",
77
- text: summary.join("\n")
78
- }, ...assetLinks],
79
- structuredContent: payload
80
- };
81
- }
82
- function createScreenshotToolResponse(payload) {
83
- if (!isScreenshotResult(payload)) throw new Error("Invalid get_screenshot payload received from extension.");
84
- return {
85
- content: [
86
- {
87
- type: "text",
88
- text: describeScreenshot(payload)
89
- },
90
- {
91
- type: "text",
92
- text: `![Screenshot](${payload.asset.url})`
93
- },
94
- createResourceLinkBlock(payload.asset, payload)
95
- ],
96
- structuredContent: payload
97
- };
98
- }
99
- function createResourceLinkBlock(asset, result) {
100
- return {
101
- type: "resource_link",
102
- name: "Screenshot",
103
- uri: asset.resourceUri,
104
- mimeType: asset.mimeType,
105
- description: `Screenshot ${result.width}x${result.height} @${result.scale}x - Download: ${asset.url}`
106
- };
107
- }
108
- function describeScreenshot(result) {
109
- return `Screenshot ${result.width}x${result.height} @${result.scale}x (${formatBytes(result.bytes)})`;
110
- }
111
- function isScreenshotResult(payload) {
112
- if (typeof payload !== "object" || !payload) return false;
113
- const candidate = payload;
114
- return typeof candidate.asset === "object" && candidate.asset !== null && typeof candidate.width === "number" && typeof candidate.height === "number" && typeof candidate.scale === "number" && typeof candidate.bytes === "number" && typeof candidate.format === "string";
115
- }
116
- function isCodeResult(payload) {
117
- if (typeof payload !== "object" || !payload) return false;
118
- const candidate = payload;
119
- return typeof candidate.code === "string" && typeof candidate.lang === "string" && Array.isArray(candidate.assets);
120
- }
121
- function createAssetResourceLinkBlock(asset) {
122
- return {
123
- type: "resource_link",
124
- name: formatAssetResourceName(asset.hash),
125
- uri: asset.resourceUri,
126
- mimeType: asset.mimeType,
127
- description: `${describeAsset(asset)} - Download: ${asset.url}`
128
- };
129
- }
130
- function describeAsset(asset) {
131
- return `${asset.mimeType} (${formatBytes(asset.size)})`;
132
- }
133
- function formatAssetResourceName(hash) {
134
- return `asset:${hash.slice(0, 8)}`;
135
- }
136
- function coercePayloadToToolResponse(payload) {
137
- if (payload && typeof payload === "object" && Array.isArray(payload.content)) return payload;
138
- return { content: [{
139
- type: "text",
140
- text: typeof payload === "string" ? payload : JSON.stringify(payload, null, 2)
141
- }] };
142
- }
143
-
144
- //#endregion
145
- export { MCP_INSTRUCTIONS, TOOL_DEFS, coercePayloadToToolResponse, createToolErrorResponse };
146
- //# sourceMappingURL=tools.mjs.map
@@ -1 +0,0 @@
1
- {"version":3,"file":"tools.mjs","names":["summary: string[]"],"sources":["../src/tools.ts"],"sourcesContent":["import type { CallToolResult } from '@modelcontextprotocol/sdk/types.js'\nimport type {\n AssetDescriptor,\n GetScreenshotResult,\n ToolName,\n ToolResultMap,\n ToolSchema\n} from '@tempad-dev/mcp-shared'\nimport type { ZodType } from 'zod'\n\nimport {\n GetAssetsParametersSchema,\n GetAssetsResultSchema,\n GetCodeParametersSchema,\n GetScreenshotParametersSchema,\n GetStructureParametersSchema,\n GetTokenDefsParametersSchema\n} from '@tempad-dev/mcp-shared'\nimport { readFileSync } from 'node:fs'\nimport { dirname, join } from 'node:path'\nimport { fileURLToPath } from 'node:url'\n\nexport type {\n AssetDescriptor,\n GetAssetsParametersInput,\n GetAssetsResult,\n GetCodeParametersInput,\n GetCodeResult,\n GetScreenshotParametersInput,\n GetScreenshotResult,\n GetStructureParametersInput,\n GetStructureResult,\n GetTokenDefsParametersInput,\n GetTokenDefsResult,\n TokenEntry,\n ToolName,\n ToolResultMap,\n ToolSchema\n} from '@tempad-dev/mcp-shared'\n\nconst HERE = dirname(fileURLToPath(import.meta.url))\nexport const MCP_INSTRUCTIONS = readFileSync(join(HERE, 'instructions.md'), 'utf8')\n\ntype BaseToolMetadata<Name extends ToolName, Schema extends ZodType> = ToolSchema<Name> & {\n parameters: Schema\n format?: (payload: ToolResultMap[Name]) => CallToolResult\n}\n\ntype ExtensionToolMetadata<Name extends ToolName, Schema extends ZodType> = BaseToolMetadata<\n Name,\n Schema\n> & {\n target: 'extension'\n}\n\ntype HubToolMetadata<Name extends ToolName, Schema extends ZodType> = BaseToolMetadata<\n Name,\n Schema\n> & {\n target: 'hub'\n outputSchema?: ZodType\n}\n\nfunction extTool<Name extends ToolName, Schema extends ZodType>(\n definition: ExtensionToolMetadata<Name, Schema>\n): ExtensionToolMetadata<Name, Schema> {\n return definition\n}\n\nfunction hubTool<Name extends ToolName, Schema extends ZodType>(\n definition: HubToolMetadata<Name, Schema>\n): HubToolMetadata<Name, Schema> {\n return definition\n}\n\nexport const TOOL_DEFS = [\n extTool({\n name: 'get_code',\n description:\n 'Get a high-fidelity code snapshot for a nodeId/current selection, including assets/usedTokens and codegen preset/config. Start here, then refactor into your component/styling/file/naming conventions; strip any data-* hints. If no data-hint-auto-layout is present, layout is explicit; if any hint is none/inferred, pair with get_structure/get_screenshot to confirm hierarchy/overlap. Use data-hint-component plus repetition to decide on reusable components. Replace resource URIs with your canonical asset system as needed.',\n parameters: GetCodeParametersSchema,\n target: 'extension',\n format: createCodeToolResponse\n }),\n extTool({\n name: 'get_token_defs',\n description:\n 'Resolve canonical token names to values (including modes) for tokens referenced by get_code. Use this to map into your design token/theming system, including responsive tokens.',\n parameters: GetTokenDefsParametersSchema,\n target: 'extension',\n exposed: false\n }),\n extTool({\n name: 'get_screenshot',\n description:\n 'Capture a rendered screenshot for a nodeId/current selection for visual verification. Useful for confirming layering/overlap/masks/shadows/translucency when auto-layout hints are none/inferred.',\n parameters: GetScreenshotParametersSchema,\n target: 'extension',\n format: createScreenshotToolResponse\n }),\n extTool({\n name: 'get_structure',\n description:\n 'Get a structural + geometry outline for a nodeId/current selection to understand hierarchy and layout intent. Use when auto-layout hints are none/inferred or you need explicit bounds for refactors/component extraction.',\n parameters: GetStructureParametersSchema,\n target: 'extension'\n }),\n hubTool({\n name: 'get_assets',\n description:\n 'Resolve asset hashes to downloadable URLs/URIs for assets referenced by get_code, preserving vectors exactly. Pull bytes before routing through your asset/icon pipeline.',\n parameters: GetAssetsParametersSchema,\n target: 'hub',\n outputSchema: GetAssetsResultSchema,\n exposed: false\n })\n] as const\n\nfunction createToolErrorResponse(toolName: string, error: unknown): CallToolResult {\n const message =\n error instanceof Error\n ? error.message || 'Unknown error occurred.'\n : typeof error === 'string'\n ? error\n : 'Unknown error occurred.'\n return {\n content: [\n {\n type: 'text' as const,\n text: `Tool \"${toolName}\" failed: ${message}`\n }\n ]\n }\n}\n\nfunction formatBytes(bytes: number): string {\n if (bytes < 1024) return `${bytes} B`\n if (bytes < 1024 * 1024) return `${(bytes / 1024).toFixed(1)} KB`\n return `${(bytes / (1024 * 1024)).toFixed(1)} MB`\n}\n\nexport function createCodeToolResponse(payload: ToolResultMap['get_code']): CallToolResult {\n if (!isCodeResult(payload)) {\n throw new Error('Invalid get_code payload received from extension.')\n }\n\n const summary: string[] = []\n const codeSize = Buffer.byteLength(payload.code, 'utf8')\n summary.push(`Generated \\`${payload.lang}\\` snippet (${formatBytes(codeSize)}).`)\n if (payload.message) {\n summary.push(payload.message)\n }\n summary.push(\n payload.assets.length\n ? `Assets attached: ${payload.assets.length}. Fetch bytes via resources/read using resourceUri.`\n : 'No binary assets were attached to this response.'\n )\n const tokenCount = payload.usedTokens ? Object.keys(payload.usedTokens.tokens ?? {}).length : 0\n if (tokenCount) {\n summary.push(`Token references included: ${tokenCount}.`)\n }\n summary.push('Read structuredContent for the full code string and asset metadata.')\n\n const assetLinks =\n payload.assets.length > 0\n ? payload.assets.map((asset) => createAssetResourceLinkBlock(asset))\n : []\n\n return {\n content: [\n {\n type: 'text' as const,\n text: summary.join('\\n')\n },\n ...assetLinks\n ],\n structuredContent: payload\n }\n}\n\nexport function createScreenshotToolResponse(\n payload: ToolResultMap['get_screenshot']\n): CallToolResult {\n if (!isScreenshotResult(payload)) {\n throw new Error('Invalid get_screenshot payload received from extension.')\n }\n\n const descriptionBlock = {\n type: 'text' as const,\n text: describeScreenshot(payload)\n }\n\n return {\n content: [\n descriptionBlock,\n {\n type: 'text' as const,\n text: `![Screenshot](${payload.asset.url})`\n },\n createResourceLinkBlock(payload.asset, payload)\n ],\n structuredContent: payload\n }\n}\n\nfunction createResourceLinkBlock(asset: AssetDescriptor, result: GetScreenshotResult) {\n return {\n type: 'resource_link' as const,\n name: 'Screenshot',\n uri: asset.resourceUri,\n mimeType: asset.mimeType,\n description: `Screenshot ${result.width}x${result.height} @${result.scale}x - Download: ${asset.url}`\n }\n}\n\nfunction describeScreenshot(result: GetScreenshotResult): string {\n return `Screenshot ${result.width}x${result.height} @${result.scale}x (${formatBytes(result.bytes)})`\n}\n\nfunction isScreenshotResult(payload: unknown): payload is GetScreenshotResult {\n if (typeof payload !== 'object' || !payload) return false\n const candidate = payload as Partial<GetScreenshotResult & Record<string, unknown>>\n return (\n typeof candidate.asset === 'object' &&\n candidate.asset !== null &&\n typeof candidate.width === 'number' &&\n typeof candidate.height === 'number' &&\n typeof candidate.scale === 'number' &&\n typeof candidate.bytes === 'number' &&\n typeof candidate.format === 'string'\n )\n}\n\nfunction isCodeResult(payload: unknown): payload is ToolResultMap['get_code'] {\n if (typeof payload !== 'object' || !payload) return false\n const candidate = payload as Partial<ToolResultMap['get_code'] & Record<string, unknown>>\n return (\n typeof candidate.code === 'string' &&\n typeof candidate.lang === 'string' &&\n Array.isArray(candidate.assets)\n )\n}\n\nfunction createAssetResourceLinkBlock(asset: AssetDescriptor) {\n return {\n type: 'resource_link' as const,\n name: formatAssetResourceName(asset.hash),\n uri: asset.resourceUri,\n mimeType: asset.mimeType,\n description: `${describeAsset(asset)} - Download: ${asset.url}`\n }\n}\n\nfunction describeAsset(asset: AssetDescriptor): string {\n return `${asset.mimeType} (${formatBytes(asset.size)})`\n}\n\nfunction formatAssetResourceName(hash: string): string {\n return `asset:${hash.slice(0, 8)}`\n}\n\nexport function coercePayloadToToolResponse(payload: unknown): CallToolResult {\n if (\n payload &&\n typeof payload === 'object' &&\n Array.isArray((payload as CallToolResult).content)\n ) {\n return payload as CallToolResult\n }\n\n return {\n content: [\n {\n type: 'text' as const,\n text: typeof payload === 'string' ? payload : JSON.stringify(payload, null, 2)\n }\n ]\n }\n}\n\nexport { createToolErrorResponse }\n"],"mappings":"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"}