@tempad-dev/mcp 0.3.11 → 0.3.12
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/cli.mjs
CHANGED
|
@@ -1,5 +1,5 @@
|
|
|
1
1
|
#!/usr/bin/env node
|
|
2
|
-
import { a as SOCK_PATH, c as log, i as RUNTIME_DIR, n as LOCK_PATH, o as ensureDir, r as PACKAGE_VERSION } from "./shared-
|
|
2
|
+
import { a as SOCK_PATH, c as log, i as RUNTIME_DIR, n as LOCK_PATH, o as ensureDir, r as PACKAGE_VERSION } from "./shared-cWtEAcwU.mjs";
|
|
3
3
|
import { spawn } from "node:child_process";
|
|
4
4
|
import { connect } from "node:net";
|
|
5
5
|
import { join } from "node:path";
|
package/dist/hub.mjs
CHANGED
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
import { a as SOCK_PATH, c as log, i as RUNTIME_DIR, o as ensureDir, r as PACKAGE_VERSION, s as ensureFile, t as ASSET_DIR } from "./shared-
|
|
1
|
+
import { a as SOCK_PATH, c as log, i as RUNTIME_DIR, o as ensureDir, r as PACKAGE_VERSION, s as ensureFile, t as ASSET_DIR } from "./shared-cWtEAcwU.mjs";
|
|
2
2
|
import { createServer } from "node:net";
|
|
3
3
|
import { join } from "node:path";
|
|
4
4
|
import { URL as URL$1 } from "node:url";
|
|
@@ -3893,6 +3893,15 @@ const MCP_ASSET_URI_PREFIX = "asset://tempad/";
|
|
|
3893
3893
|
const MCP_ASSET_URI_TEMPLATE = `${MCP_ASSET_URI_PREFIX}{hash}`;
|
|
3894
3894
|
const MCP_HASH_HEX_LENGTH = 8;
|
|
3895
3895
|
const MCP_HASH_PATTERN = new RegExp(`^[a-f0-9]{${MCP_HASH_HEX_LENGTH}}$`, "i");
|
|
3896
|
+
const TEMPAD_MCP_ERROR_CODES = {
|
|
3897
|
+
NO_ACTIVE_EXTENSION: "NO_ACTIVE_EXTENSION",
|
|
3898
|
+
EXTENSION_TIMEOUT: "EXTENSION_TIMEOUT",
|
|
3899
|
+
EXTENSION_DISCONNECTED: "EXTENSION_DISCONNECTED",
|
|
3900
|
+
INVALID_SELECTION: "INVALID_SELECTION",
|
|
3901
|
+
NODE_NOT_VISIBLE: "NODE_NOT_VISIBLE",
|
|
3902
|
+
ASSET_SERVER_NOT_CONFIGURED: "ASSET_SERVER_NOT_CONFIGURED",
|
|
3903
|
+
TRANSPORT_NOT_CONNECTED: "TRANSPORT_NOT_CONNECTED"
|
|
3904
|
+
};
|
|
3896
3905
|
const RegisteredMessageSchema = object({
|
|
3897
3906
|
type: literal("registered"),
|
|
3898
3907
|
id: string()
|
|
@@ -4162,7 +4171,6 @@ function createAssetHttpServer(store) {
|
|
|
4162
4171
|
if (existingPath !== filePath) try {
|
|
4163
4172
|
renameSync(existingPath, filePath);
|
|
4164
4173
|
existing.filePath = filePath;
|
|
4165
|
-
existingPath = filePath;
|
|
4166
4174
|
} catch (error) {
|
|
4167
4175
|
log.warn({
|
|
4168
4176
|
error,
|
|
@@ -4433,18 +4441,23 @@ function createAssetStore(options = {}) {
|
|
|
4433
4441
|
|
|
4434
4442
|
//#endregion
|
|
4435
4443
|
//#region src/instructions.md?raw
|
|
4436
|
-
var instructions_default = "You are connected to a Figma design file via
|
|
4444
|
+
var instructions_default = "You are connected to a Figma design file via TemPad Dev MCP.\n\nTreat tool outputs as design facts. Refactor only to match the user’s repo conventions; do not invent key style values.\n\nRules:\n\n- Never output any `data-hint-*` attributes from tool outputs (hints only).\n- If `get_code` warns `depth-cap`, call `get_code` again for each listed `nodeId` before implementing.\n- Use `get_structure` / `get_screenshot` only to resolve layout/overlap/masks/effects uncertainty. Screenshots are for visual verification only; do not derive numeric values from pixels.\n- Tokens: `get_code.tokens` keys are canonical names (`--...`). Multi‑mode values use `${collectionName}:${modeName}`. Nodes may hint per-node overrides via `data-hint-variable-mode=\"Collection=Mode;...\"`.\n- Assets: fetch bytes via `resources/read` using `resourceUri` when possible; fall back to `asset.url` for large blobs. Preserve SVG/vector assets exactly; never redraw vectors.\n";
|
|
4437
4445
|
|
|
4438
4446
|
//#endregion
|
|
4439
4447
|
//#region src/request.ts
|
|
4440
4448
|
const pendingCalls = /* @__PURE__ */ new Map();
|
|
4449
|
+
function createToolError(code, message) {
|
|
4450
|
+
const err = new Error(message);
|
|
4451
|
+
err.code = code;
|
|
4452
|
+
return err;
|
|
4453
|
+
}
|
|
4441
4454
|
function register(extensionId, timeout) {
|
|
4442
4455
|
const requestId = nanoid();
|
|
4443
4456
|
return {
|
|
4444
4457
|
promise: new Promise((resolve$1, reject$1) => {
|
|
4445
4458
|
const timer = setTimeout(() => {
|
|
4446
4459
|
pendingCalls.delete(requestId);
|
|
4447
|
-
reject$1(
|
|
4460
|
+
reject$1(createToolError(TEMPAD_MCP_ERROR_CODES.EXTENSION_TIMEOUT, `Extension did not respond within ${timeout / 1e3}s.`));
|
|
4448
4461
|
}, timeout);
|
|
4449
4462
|
pendingCalls.set(requestId, {
|
|
4450
4463
|
resolve: resolve$1,
|
|
@@ -4479,7 +4492,7 @@ function cleanupForExtension(extensionId) {
|
|
|
4479
4492
|
const { timer, reject: fail, extensionId: extId } = call;
|
|
4480
4493
|
if (extId === extensionId) {
|
|
4481
4494
|
clearTimeout(timer);
|
|
4482
|
-
fail(
|
|
4495
|
+
fail(createToolError(TEMPAD_MCP_ERROR_CODES.EXTENSION_DISCONNECTED, "Extension disconnected before providing a result."));
|
|
4483
4496
|
pendingCalls.delete(reqId);
|
|
4484
4497
|
log.warn({
|
|
4485
4498
|
reqId,
|
|
@@ -4509,44 +4522,71 @@ function hubTool(definition) {
|
|
|
4509
4522
|
const TOOL_DEFS = [
|
|
4510
4523
|
extTool({
|
|
4511
4524
|
name: "get_code",
|
|
4512
|
-
description: "
|
|
4525
|
+
description: "High-fidelity code snapshot for nodeId/current single selection (omit nodeId to use selection): JSX/Vue markup + Tailwind-like classes, plus assets/tokens metadata and codegen config. Start here, then refactor into repo conventions while preserving values/intent; strip any data-hint-* attributes (hints only). If warnings include depth-cap, call get_code again for each listed nodeId. If warnings include auto-layout (inferred), use get_structure/get_screenshot to confirm hierarchy/overlap (do not derive numeric values from pixels). Tokens are keyed by canonical names like `--color-primary` (multi-mode keys use `${collection}:${mode}`; node overrides may appear as data-hint-variable-mode).",
|
|
4513
4526
|
parameters: GetCodeParametersSchema,
|
|
4514
4527
|
target: "extension",
|
|
4515
4528
|
format: createCodeToolResponse
|
|
4516
4529
|
}),
|
|
4517
4530
|
extTool({
|
|
4518
4531
|
name: "get_token_defs",
|
|
4519
|
-
description: "Resolve canonical token names to values (including modes) for tokens referenced by get_code.
|
|
4532
|
+
description: "Resolve canonical token names to literal values (optionally including all modes) for tokens referenced by get_code.",
|
|
4520
4533
|
parameters: GetTokenDefsParametersSchema,
|
|
4521
4534
|
target: "extension",
|
|
4522
4535
|
exposed: false
|
|
4523
4536
|
}),
|
|
4524
4537
|
extTool({
|
|
4525
4538
|
name: "get_screenshot",
|
|
4526
|
-
description: "Capture a rendered screenshot for
|
|
4539
|
+
description: "Capture a rendered PNG screenshot for nodeId/current single selection for visual verification (layering/overlap/masks/effects).",
|
|
4527
4540
|
parameters: GetScreenshotParametersSchema,
|
|
4528
4541
|
target: "extension",
|
|
4529
4542
|
format: createScreenshotToolResponse
|
|
4530
4543
|
}),
|
|
4531
4544
|
extTool({
|
|
4532
4545
|
name: "get_structure",
|
|
4533
|
-
description: "Get a structural + geometry outline for
|
|
4546
|
+
description: "Get a structural + geometry outline for nodeId/current single selection to understand hierarchy and layout intent.",
|
|
4534
4547
|
parameters: GetStructureParametersSchema,
|
|
4535
4548
|
target: "extension"
|
|
4536
4549
|
}),
|
|
4537
4550
|
hubTool({
|
|
4538
4551
|
name: "get_assets",
|
|
4539
|
-
description: "Resolve asset hashes to downloadable URLs/URIs for assets referenced by
|
|
4552
|
+
description: "Resolve asset hashes to downloadable URLs/URIs for assets referenced by tool responses (preserve vectors exactly).",
|
|
4540
4553
|
parameters: GetAssetsParametersSchema,
|
|
4541
4554
|
target: "hub",
|
|
4542
4555
|
outputSchema: GetAssetsResultSchema,
|
|
4543
4556
|
exposed: false
|
|
4544
4557
|
})
|
|
4545
4558
|
];
|
|
4559
|
+
function extractToolErrorCode(error) {
|
|
4560
|
+
if (!error || typeof error !== "object") return void 0;
|
|
4561
|
+
if ("code" in error && typeof error.code === "string") return error.code;
|
|
4562
|
+
if ("cause" in error) {
|
|
4563
|
+
const cause = error.cause;
|
|
4564
|
+
if (cause && typeof cause === "object") {
|
|
4565
|
+
const causeCode = cause.code;
|
|
4566
|
+
if (typeof causeCode === "string") return causeCode;
|
|
4567
|
+
}
|
|
4568
|
+
}
|
|
4569
|
+
}
|
|
4570
|
+
function extractToolErrorMessage(error) {
|
|
4571
|
+
if (error instanceof Error) return error.message || "Unknown error occurred.";
|
|
4572
|
+
if (typeof error === "string") return error;
|
|
4573
|
+
if (error && typeof error === "object") {
|
|
4574
|
+
const candidate = error;
|
|
4575
|
+
if (typeof candidate.message === "string" && candidate.message.trim()) return candidate.message;
|
|
4576
|
+
}
|
|
4577
|
+
return "Unknown error occurred.";
|
|
4578
|
+
}
|
|
4546
4579
|
function createToolErrorResponse(toolName, error) {
|
|
4580
|
+
const message = extractToolErrorMessage(error);
|
|
4581
|
+
const code = extractToolErrorCode(error);
|
|
4547
4582
|
return { content: [{
|
|
4548
4583
|
type: "text",
|
|
4549
|
-
text: `Tool "${toolName}" failed: ${
|
|
4584
|
+
text: `Tool "${toolName}" failed: ${message}${(() => {
|
|
4585
|
+
const help = [];
|
|
4586
|
+
if (code === TEMPAD_MCP_ERROR_CODES.NO_ACTIVE_EXTENSION || code === TEMPAD_MCP_ERROR_CODES.EXTENSION_TIMEOUT || code === TEMPAD_MCP_ERROR_CODES.EXTENSION_DISCONNECTED || code === TEMPAD_MCP_ERROR_CODES.ASSET_SERVER_NOT_CONFIGURED || code === TEMPAD_MCP_ERROR_CODES.TRANSPORT_NOT_CONNECTED || /no active tempad dev extension/i.test(message) || /asset server url is not configured/i.test(message) || /mcp transport is not connected/i.test(message) || /websocket/i.test(message)) help.push("Troubleshooting:", "- In Figma, open TemPad Dev panel and enable MCP (Preferences → MCP server).", "- If multiple Figma tabs are open, click the MCP badge to activate this tab.", "- Keep the Figma tab active/foreground while running MCP tools.");
|
|
4587
|
+
if (code === TEMPAD_MCP_ERROR_CODES.INVALID_SELECTION || code === TEMPAD_MCP_ERROR_CODES.NODE_NOT_VISIBLE || /select exactly one visible node/i.test(message) || /no visible node found/i.test(message)) help.push("Tip: Select exactly one visible node, or pass nodeId.");
|
|
4588
|
+
return help.length ? `\n\n${help.join("\n")}` : "";
|
|
4589
|
+
})()}`
|
|
4550
4590
|
}] };
|
|
4551
4591
|
}
|
|
4552
4592
|
function formatBytes$1(bytes) {
|
|
@@ -4662,6 +4702,30 @@ function enrichToolDefinition(tool) {
|
|
|
4662
4702
|
}
|
|
4663
4703
|
}
|
|
4664
4704
|
const TOOL_DEFINITIONS = TOOL_DEFS.map((tool) => enrichToolDefinition(tool));
|
|
4705
|
+
function createCodedError(code, message) {
|
|
4706
|
+
const err = new Error(message);
|
|
4707
|
+
err.code = code;
|
|
4708
|
+
return err;
|
|
4709
|
+
}
|
|
4710
|
+
function coerceToolError(error) {
|
|
4711
|
+
if (error instanceof Error) return error;
|
|
4712
|
+
if (typeof error === "string") return new Error(error);
|
|
4713
|
+
if (error && typeof error === "object") {
|
|
4714
|
+
const candidate = error;
|
|
4715
|
+
const message = typeof candidate.message === "string" ? candidate.message : safeStringify(error);
|
|
4716
|
+
const err = new Error(message);
|
|
4717
|
+
if (typeof candidate.code === "string") err.code = candidate.code;
|
|
4718
|
+
return err;
|
|
4719
|
+
}
|
|
4720
|
+
return new Error(String(error));
|
|
4721
|
+
}
|
|
4722
|
+
function safeStringify(input) {
|
|
4723
|
+
try {
|
|
4724
|
+
return JSON.stringify(input);
|
|
4725
|
+
} catch {
|
|
4726
|
+
return String(input);
|
|
4727
|
+
}
|
|
4728
|
+
}
|
|
4665
4729
|
function hasFormatter(tool) {
|
|
4666
4730
|
return tool.target === "extension" && "format" in tool;
|
|
4667
4731
|
}
|
|
@@ -4793,7 +4857,7 @@ function registerProxiedTool(tool) {
|
|
|
4793
4857
|
try {
|
|
4794
4858
|
const parsedArgs = schema.parse(args);
|
|
4795
4859
|
const activeExt = extensions.find((e) => e.active);
|
|
4796
|
-
if (!activeExt) throw
|
|
4860
|
+
if (!activeExt) throw createCodedError(TEMPAD_MCP_ERROR_CODES.NO_ACTIVE_EXTENSION, "No active TemPad Dev extension available.");
|
|
4797
4861
|
const { promise, requestId } = register(activeExt.id, toolTimeoutMs);
|
|
4798
4862
|
const message = {
|
|
4799
4863
|
type: "toolCall",
|
|
@@ -5098,7 +5162,7 @@ wss.on("connection", (ws) => {
|
|
|
5098
5162
|
break;
|
|
5099
5163
|
case "toolResult": {
|
|
5100
5164
|
const { id, payload, error } = msg;
|
|
5101
|
-
if (error) reject(id,
|
|
5165
|
+
if (error) reject(id, coerceToolError(error));
|
|
5102
5166
|
else resolve(id, payload);
|
|
5103
5167
|
break;
|
|
5104
5168
|
}
|