@ufira/vibma 0.2.1 → 0.3.0
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/mcp.cjs +810 -1430
- package/dist/mcp.cjs.map +1 -1
- package/dist/mcp.js +809 -1431
- package/dist/mcp.js.map +1 -1
- package/dist/tools/endpoint.cjs +119 -0
- package/dist/tools/endpoint.cjs.map +1 -0
- package/dist/tools/endpoint.d.cts +94 -0
- package/dist/tools/endpoint.d.ts +94 -0
- package/dist/tools/endpoint.js +92 -0
- package/dist/tools/endpoint.js.map +1 -0
- package/dist/tools/registry.cjs +73 -0
- package/dist/tools/registry.cjs.map +1 -0
- package/dist/tools/registry.d.cts +14 -0
- package/dist/tools/registry.d.ts +14 -0
- package/dist/tools/registry.js +47 -0
- package/dist/tools/registry.js.map +1 -0
- package/dist/tools/schemas.cjs +101 -0
- package/dist/tools/schemas.cjs.map +1 -0
- package/dist/tools/schemas.d.cts +52 -0
- package/dist/tools/schemas.d.ts +52 -0
- package/dist/tools/schemas.js +70 -0
- package/dist/tools/schemas.js.map +1 -0
- package/dist/tools/types.cjs +52 -0
- package/dist/tools/types.cjs.map +1 -0
- package/dist/tools/types.d.cts +53 -0
- package/dist/tools/types.d.ts +53 -0
- package/dist/tools/types.js +27 -0
- package/dist/tools/types.js.map +1 -0
- package/dist/utils/coercion.cjs +56 -0
- package/dist/utils/coercion.cjs.map +1 -0
- package/dist/utils/coercion.d.cts +10 -0
- package/dist/utils/coercion.d.ts +10 -0
- package/dist/utils/coercion.js +30 -0
- package/dist/utils/coercion.js.map +1 -0
- package/dist/utils/color.cjs +38 -0
- package/dist/utils/color.cjs.map +1 -0
- package/dist/utils/color.d.cts +4 -0
- package/dist/utils/color.d.ts +4 -0
- package/dist/utils/color.js +14 -0
- package/dist/utils/color.js.map +1 -0
- package/dist/utils/wcag.cjs +123 -0
- package/dist/utils/wcag.cjs.map +1 -0
- package/dist/utils/wcag.d.cts +80 -0
- package/dist/utils/wcag.d.ts +80 -0
- package/dist/utils/wcag.js +92 -0
- package/dist/utils/wcag.js.map +1 -0
- package/package.json +43 -15
- package/LICENSE +0 -22
- package/README.md +0 -54
|
@@ -0,0 +1,101 @@
|
|
|
1
|
+
var __defProp = Object.defineProperty;
|
|
2
|
+
var __getOwnPropDesc = Object.getOwnPropertyDescriptor;
|
|
3
|
+
var __getOwnPropNames = Object.getOwnPropertyNames;
|
|
4
|
+
var __hasOwnProp = Object.prototype.hasOwnProperty;
|
|
5
|
+
var __export = (target, all) => {
|
|
6
|
+
for (var name in all)
|
|
7
|
+
__defProp(target, name, { get: all[name], enumerable: true });
|
|
8
|
+
};
|
|
9
|
+
var __copyProps = (to, from, except, desc) => {
|
|
10
|
+
if (from && typeof from === "object" || typeof from === "function") {
|
|
11
|
+
for (let key of __getOwnPropNames(from))
|
|
12
|
+
if (!__hasOwnProp.call(to, key) && key !== except)
|
|
13
|
+
__defProp(to, key, { get: () => from[key], enumerable: !(desc = __getOwnPropDesc(from, key)) || desc.enumerable });
|
|
14
|
+
}
|
|
15
|
+
return to;
|
|
16
|
+
};
|
|
17
|
+
var __toCommonJS = (mod) => __copyProps(__defProp({}, "__esModule", { value: true }), mod);
|
|
18
|
+
|
|
19
|
+
// src/tools/schemas.ts
|
|
20
|
+
var schemas_exports = {};
|
|
21
|
+
__export(schemas_exports, {
|
|
22
|
+
colorRgba: () => colorRgba,
|
|
23
|
+
depth: () => depth,
|
|
24
|
+
effectEntry: () => effectEntry,
|
|
25
|
+
nodeId: () => nodeId,
|
|
26
|
+
nodeIds: () => nodeIds,
|
|
27
|
+
parentId: () => parentId,
|
|
28
|
+
xPos: () => xPos,
|
|
29
|
+
yPos: () => yPos
|
|
30
|
+
});
|
|
31
|
+
module.exports = __toCommonJS(schemas_exports);
|
|
32
|
+
var import_zod2 = require("zod");
|
|
33
|
+
|
|
34
|
+
// src/utils/coercion.ts
|
|
35
|
+
var import_zod = require("zod");
|
|
36
|
+
var flexBool = (inner) => import_zod.z.preprocess((v) => {
|
|
37
|
+
if (v === "true" || v === "1") return true;
|
|
38
|
+
if (v === "false" || v === "0") return false;
|
|
39
|
+
return v;
|
|
40
|
+
}, inner);
|
|
41
|
+
var flexJson = (inner) => import_zod.z.preprocess((v) => {
|
|
42
|
+
if (typeof v === "string") {
|
|
43
|
+
try {
|
|
44
|
+
return JSON.parse(v);
|
|
45
|
+
} catch {
|
|
46
|
+
return v;
|
|
47
|
+
}
|
|
48
|
+
}
|
|
49
|
+
return v;
|
|
50
|
+
}, inner);
|
|
51
|
+
|
|
52
|
+
// src/tools/schemas.ts
|
|
53
|
+
var nodeId = import_zod2.z.string().describe("Node ID");
|
|
54
|
+
var nodeIds = flexJson(import_zod2.z.array(import_zod2.z.string())).describe("Array of node IDs");
|
|
55
|
+
var parentId = import_zod2.z.string().optional().describe("Parent node ID. Omit to place on current page.");
|
|
56
|
+
var depth = import_zod2.z.coerce.number().optional().describe("Response detail: omit for id+name only. 0=properties + child stubs. N=recurse N levels. -1=unlimited.");
|
|
57
|
+
var xPos = import_zod2.z.coerce.number().optional().describe("X position (default: 0)");
|
|
58
|
+
var yPos = import_zod2.z.coerce.number().optional().describe("Y position (default: 0)");
|
|
59
|
+
function parseHex(hex) {
|
|
60
|
+
const m = hex.match(/^#?([0-9a-f]{3,8})$/i);
|
|
61
|
+
if (!m) return null;
|
|
62
|
+
let h = m[1];
|
|
63
|
+
if (h.length === 3) h = h[0] + h[0] + h[1] + h[1] + h[2] + h[2];
|
|
64
|
+
if (h.length === 4) h = h[0] + h[0] + h[1] + h[1] + h[2] + h[2] + h[3] + h[3];
|
|
65
|
+
if (h.length !== 6 && h.length !== 8) return null;
|
|
66
|
+
const r = parseInt(h.slice(0, 2), 16) / 255;
|
|
67
|
+
const g = parseInt(h.slice(2, 4), 16) / 255;
|
|
68
|
+
const b = parseInt(h.slice(4, 6), 16) / 255;
|
|
69
|
+
if (h.length === 8) return { r, g, b, a: parseInt(h.slice(6, 8), 16) / 255 };
|
|
70
|
+
return { r, g, b };
|
|
71
|
+
}
|
|
72
|
+
var colorRgba = import_zod2.z.preprocess((v) => {
|
|
73
|
+
if (typeof v === "string") return parseHex(v) ?? v;
|
|
74
|
+
return v;
|
|
75
|
+
}, import_zod2.z.object({
|
|
76
|
+
r: import_zod2.z.coerce.number().min(0).max(1),
|
|
77
|
+
g: import_zod2.z.coerce.number().min(0).max(1),
|
|
78
|
+
b: import_zod2.z.coerce.number().min(0).max(1),
|
|
79
|
+
a: import_zod2.z.coerce.number().min(0).max(1).optional()
|
|
80
|
+
})).describe('Hex "#FF0000" or {r,g,b,a?} with values 0-1.');
|
|
81
|
+
var effectEntry = import_zod2.z.object({
|
|
82
|
+
type: import_zod2.z.enum(["DROP_SHADOW", "INNER_SHADOW", "LAYER_BLUR", "BACKGROUND_BLUR"]),
|
|
83
|
+
color: flexJson(colorRgba).optional(),
|
|
84
|
+
offset: flexJson(import_zod2.z.object({ x: import_zod2.z.coerce.number(), y: import_zod2.z.coerce.number() })).optional(),
|
|
85
|
+
radius: import_zod2.z.coerce.number(),
|
|
86
|
+
spread: import_zod2.z.coerce.number().optional(),
|
|
87
|
+
visible: flexBool(import_zod2.z.boolean()).optional(),
|
|
88
|
+
blendMode: import_zod2.z.string().optional()
|
|
89
|
+
});
|
|
90
|
+
// Annotate the CommonJS export names for ESM import in node:
|
|
91
|
+
0 && (module.exports = {
|
|
92
|
+
colorRgba,
|
|
93
|
+
depth,
|
|
94
|
+
effectEntry,
|
|
95
|
+
nodeId,
|
|
96
|
+
nodeIds,
|
|
97
|
+
parentId,
|
|
98
|
+
xPos,
|
|
99
|
+
yPos
|
|
100
|
+
});
|
|
101
|
+
//# sourceMappingURL=schemas.cjs.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"sources":["../../src/tools/schemas.ts","../../src/utils/coercion.ts"],"sourcesContent":["import { z } from \"zod\";\nimport { flexJson, flexBool } from \"../utils/coercion\";\n\n// ─── Shared Zod Schema Fragments ────────────────────────────────\n// Import as: import * as S from \"./schemas\";\n\n/** Single node ID */\nexport const nodeId = z.string().describe(\"Node ID\");\n\n/** Array of node IDs */\nexport const nodeIds = flexJson(z.array(z.string())).describe(\"Array of node IDs\");\n\n/** Optional parent reference for creation tools */\nexport const parentId = z.string().optional()\n .describe(\"Parent node ID. Omit to place on current page.\");\n\n/**\n * Response depth — controls how much node detail is returned after an operation.\n * Omit for minimal response (id + name only).\n * 0 = node with full properties, children as stubs.\n * N = recurse N levels of children with full properties.\n * -1 = unlimited recursion.\n */\nexport const depth = z.coerce.number().optional()\n .describe(\"Response detail: omit for id+name only. 0=properties + child stubs. N=recurse N levels. -1=unlimited.\");\n\n/** X position for creation tools */\nexport const xPos = z.coerce.number().optional().describe(\"X position (default: 0)\");\n\n/** Y position for creation tools */\nexport const yPos = z.coerce.number().optional().describe(\"Y position (default: 0)\");\n\n/** Parse hex color string (#RGB, #RRGGBB, #RRGGBBAA) to {r,g,b,a} 0-1 */\nfunction parseHex(hex: string): { r: number; g: number; b: number; a?: number } | null {\n const m = hex.match(/^#?([0-9a-f]{3,8})$/i);\n if (!m) return null;\n let h = m[1];\n if (h.length === 3) h = h[0]+h[0]+h[1]+h[1]+h[2]+h[2];\n if (h.length === 4) h = h[0]+h[0]+h[1]+h[1]+h[2]+h[2]+h[3]+h[3];\n if (h.length !== 6 && h.length !== 8) return null;\n const r = parseInt(h.slice(0, 2), 16) / 255;\n const g = parseInt(h.slice(2, 4), 16) / 255;\n const b = parseInt(h.slice(4, 6), 16) / 255;\n if (h.length === 8) return { r, g, b, a: parseInt(h.slice(6, 8), 16) / 255 };\n return { r, g, b };\n}\n\n/** RGBA color — accepts {r,g,b,a?} object (0-1) or hex string (#RGB, #RRGGBB, #RRGGBBAA) */\nexport const colorRgba = z.preprocess((v) => {\n if (typeof v === \"string\") return parseHex(v) ?? v;\n return v;\n}, z.object({\n r: z.coerce.number().min(0).max(1),\n g: z.coerce.number().min(0).max(1),\n b: z.coerce.number().min(0).max(1),\n a: z.coerce.number().min(0).max(1).optional(),\n})).describe('Hex \"#FF0000\" or {r,g,b,a?} with values 0-1.');\n\n/** Single effect entry — shared by set_effects and styles create */\nexport const effectEntry = z.object({\n type: z.enum([\"DROP_SHADOW\", \"INNER_SHADOW\", \"LAYER_BLUR\", \"BACKGROUND_BLUR\"]),\n color: flexJson(colorRgba).optional(),\n offset: flexJson(z.object({ x: z.coerce.number(), y: z.coerce.number() })).optional(),\n radius: z.coerce.number(),\n spread: z.coerce.number().optional(),\n visible: flexBool(z.boolean()).optional(),\n blendMode: z.string().optional(),\n});\n","import { z } from \"zod\";\n\n// AI agents (Claude, GPT, etc.) frequently pass numbers as strings\n// (\"10\" instead of 10), booleans as strings (\"true\" instead of true),\n// and objects/arrays as JSON strings. These helpers add resilient\n// coercion so tools don't fail on valid-but-mistyped input.\n\n/** Coerce \"true\"/\"false\"/\"1\"/\"0\" strings to boolean */\nexport const flexBool = <T extends z.ZodTypeAny>(inner: T) =>\n z.preprocess((v) => {\n if (v === \"true\" || v === \"1\") return true;\n if (v === \"false\" || v === \"0\") return false;\n return v;\n }, inner);\n\n/** Coerce JSON strings to parsed values (for objects/arrays that agents may stringify) */\nexport const flexJson = <T extends z.ZodTypeAny>(inner: T) =>\n z.preprocess((v) => {\n if (typeof v === \"string\") {\n try {\n return JSON.parse(v);\n } catch {\n return v;\n }\n }\n return v;\n }, inner);\n\n/** Coerce numeric strings only when they're valid numbers (safe for use inside unions) */\nexport const flexNum = <T extends z.ZodTypeAny>(inner: T) =>\n z.preprocess((v) => {\n if (typeof v === \"string\") {\n const n = Number(v);\n if (!isNaN(n) && v.trim() !== \"\") return n;\n }\n return v;\n }, inner);\n"],"mappings":"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","names":["import_zod"]}
|
|
@@ -0,0 +1,52 @@
|
|
|
1
|
+
import { z } from 'zod';
|
|
2
|
+
|
|
3
|
+
/** Single node ID */
|
|
4
|
+
declare const nodeId: z.ZodString;
|
|
5
|
+
/** Array of node IDs */
|
|
6
|
+
declare const nodeIds: z.ZodPipe<z.ZodTransform<any, unknown>, z.ZodArray<z.ZodString>>;
|
|
7
|
+
/** Optional parent reference for creation tools */
|
|
8
|
+
declare const parentId: z.ZodOptional<z.ZodString>;
|
|
9
|
+
/**
|
|
10
|
+
* Response depth — controls how much node detail is returned after an operation.
|
|
11
|
+
* Omit for minimal response (id + name only).
|
|
12
|
+
* 0 = node with full properties, children as stubs.
|
|
13
|
+
* N = recurse N levels of children with full properties.
|
|
14
|
+
* -1 = unlimited recursion.
|
|
15
|
+
*/
|
|
16
|
+
declare const depth: z.ZodOptional<z.ZodCoercedNumber<unknown>>;
|
|
17
|
+
/** X position for creation tools */
|
|
18
|
+
declare const xPos: z.ZodOptional<z.ZodCoercedNumber<unknown>>;
|
|
19
|
+
/** Y position for creation tools */
|
|
20
|
+
declare const yPos: z.ZodOptional<z.ZodCoercedNumber<unknown>>;
|
|
21
|
+
/** RGBA color — accepts {r,g,b,a?} object (0-1) or hex string (#RGB, #RRGGBB, #RRGGBBAA) */
|
|
22
|
+
declare const colorRgba: z.ZodPipe<z.ZodTransform<unknown, unknown>, z.ZodObject<{
|
|
23
|
+
r: z.ZodCoercedNumber<unknown>;
|
|
24
|
+
g: z.ZodCoercedNumber<unknown>;
|
|
25
|
+
b: z.ZodCoercedNumber<unknown>;
|
|
26
|
+
a: z.ZodOptional<z.ZodCoercedNumber<unknown>>;
|
|
27
|
+
}, z.core.$strip>>;
|
|
28
|
+
/** Single effect entry — shared by set_effects and styles create */
|
|
29
|
+
declare const effectEntry: z.ZodObject<{
|
|
30
|
+
type: z.ZodEnum<{
|
|
31
|
+
DROP_SHADOW: "DROP_SHADOW";
|
|
32
|
+
INNER_SHADOW: "INNER_SHADOW";
|
|
33
|
+
LAYER_BLUR: "LAYER_BLUR";
|
|
34
|
+
BACKGROUND_BLUR: "BACKGROUND_BLUR";
|
|
35
|
+
}>;
|
|
36
|
+
color: z.ZodOptional<z.ZodPipe<z.ZodTransform<any, unknown>, z.ZodPipe<z.ZodTransform<unknown, unknown>, z.ZodObject<{
|
|
37
|
+
r: z.ZodCoercedNumber<unknown>;
|
|
38
|
+
g: z.ZodCoercedNumber<unknown>;
|
|
39
|
+
b: z.ZodCoercedNumber<unknown>;
|
|
40
|
+
a: z.ZodOptional<z.ZodCoercedNumber<unknown>>;
|
|
41
|
+
}, z.core.$strip>>>>;
|
|
42
|
+
offset: z.ZodOptional<z.ZodPipe<z.ZodTransform<any, unknown>, z.ZodObject<{
|
|
43
|
+
x: z.ZodCoercedNumber<unknown>;
|
|
44
|
+
y: z.ZodCoercedNumber<unknown>;
|
|
45
|
+
}, z.core.$strip>>>;
|
|
46
|
+
radius: z.ZodCoercedNumber<unknown>;
|
|
47
|
+
spread: z.ZodOptional<z.ZodCoercedNumber<unknown>>;
|
|
48
|
+
visible: z.ZodOptional<z.ZodPipe<z.ZodTransform<unknown, unknown>, z.ZodBoolean>>;
|
|
49
|
+
blendMode: z.ZodOptional<z.ZodString>;
|
|
50
|
+
}, z.core.$strip>;
|
|
51
|
+
|
|
52
|
+
export { colorRgba, depth, effectEntry, nodeId, nodeIds, parentId, xPos, yPos };
|
|
@@ -0,0 +1,52 @@
|
|
|
1
|
+
import { z } from 'zod';
|
|
2
|
+
|
|
3
|
+
/** Single node ID */
|
|
4
|
+
declare const nodeId: z.ZodString;
|
|
5
|
+
/** Array of node IDs */
|
|
6
|
+
declare const nodeIds: z.ZodPipe<z.ZodTransform<any, unknown>, z.ZodArray<z.ZodString>>;
|
|
7
|
+
/** Optional parent reference for creation tools */
|
|
8
|
+
declare const parentId: z.ZodOptional<z.ZodString>;
|
|
9
|
+
/**
|
|
10
|
+
* Response depth — controls how much node detail is returned after an operation.
|
|
11
|
+
* Omit for minimal response (id + name only).
|
|
12
|
+
* 0 = node with full properties, children as stubs.
|
|
13
|
+
* N = recurse N levels of children with full properties.
|
|
14
|
+
* -1 = unlimited recursion.
|
|
15
|
+
*/
|
|
16
|
+
declare const depth: z.ZodOptional<z.ZodCoercedNumber<unknown>>;
|
|
17
|
+
/** X position for creation tools */
|
|
18
|
+
declare const xPos: z.ZodOptional<z.ZodCoercedNumber<unknown>>;
|
|
19
|
+
/** Y position for creation tools */
|
|
20
|
+
declare const yPos: z.ZodOptional<z.ZodCoercedNumber<unknown>>;
|
|
21
|
+
/** RGBA color — accepts {r,g,b,a?} object (0-1) or hex string (#RGB, #RRGGBB, #RRGGBBAA) */
|
|
22
|
+
declare const colorRgba: z.ZodPipe<z.ZodTransform<unknown, unknown>, z.ZodObject<{
|
|
23
|
+
r: z.ZodCoercedNumber<unknown>;
|
|
24
|
+
g: z.ZodCoercedNumber<unknown>;
|
|
25
|
+
b: z.ZodCoercedNumber<unknown>;
|
|
26
|
+
a: z.ZodOptional<z.ZodCoercedNumber<unknown>>;
|
|
27
|
+
}, z.core.$strip>>;
|
|
28
|
+
/** Single effect entry — shared by set_effects and styles create */
|
|
29
|
+
declare const effectEntry: z.ZodObject<{
|
|
30
|
+
type: z.ZodEnum<{
|
|
31
|
+
DROP_SHADOW: "DROP_SHADOW";
|
|
32
|
+
INNER_SHADOW: "INNER_SHADOW";
|
|
33
|
+
LAYER_BLUR: "LAYER_BLUR";
|
|
34
|
+
BACKGROUND_BLUR: "BACKGROUND_BLUR";
|
|
35
|
+
}>;
|
|
36
|
+
color: z.ZodOptional<z.ZodPipe<z.ZodTransform<any, unknown>, z.ZodPipe<z.ZodTransform<unknown, unknown>, z.ZodObject<{
|
|
37
|
+
r: z.ZodCoercedNumber<unknown>;
|
|
38
|
+
g: z.ZodCoercedNumber<unknown>;
|
|
39
|
+
b: z.ZodCoercedNumber<unknown>;
|
|
40
|
+
a: z.ZodOptional<z.ZodCoercedNumber<unknown>>;
|
|
41
|
+
}, z.core.$strip>>>>;
|
|
42
|
+
offset: z.ZodOptional<z.ZodPipe<z.ZodTransform<any, unknown>, z.ZodObject<{
|
|
43
|
+
x: z.ZodCoercedNumber<unknown>;
|
|
44
|
+
y: z.ZodCoercedNumber<unknown>;
|
|
45
|
+
}, z.core.$strip>>>;
|
|
46
|
+
radius: z.ZodCoercedNumber<unknown>;
|
|
47
|
+
spread: z.ZodOptional<z.ZodCoercedNumber<unknown>>;
|
|
48
|
+
visible: z.ZodOptional<z.ZodPipe<z.ZodTransform<unknown, unknown>, z.ZodBoolean>>;
|
|
49
|
+
blendMode: z.ZodOptional<z.ZodString>;
|
|
50
|
+
}, z.core.$strip>;
|
|
51
|
+
|
|
52
|
+
export { colorRgba, depth, effectEntry, nodeId, nodeIds, parentId, xPos, yPos };
|
|
@@ -0,0 +1,70 @@
|
|
|
1
|
+
// src/tools/schemas.ts
|
|
2
|
+
import { z as z2 } from "zod";
|
|
3
|
+
|
|
4
|
+
// src/utils/coercion.ts
|
|
5
|
+
import { z } from "zod";
|
|
6
|
+
var flexBool = (inner) => z.preprocess((v) => {
|
|
7
|
+
if (v === "true" || v === "1") return true;
|
|
8
|
+
if (v === "false" || v === "0") return false;
|
|
9
|
+
return v;
|
|
10
|
+
}, inner);
|
|
11
|
+
var flexJson = (inner) => z.preprocess((v) => {
|
|
12
|
+
if (typeof v === "string") {
|
|
13
|
+
try {
|
|
14
|
+
return JSON.parse(v);
|
|
15
|
+
} catch {
|
|
16
|
+
return v;
|
|
17
|
+
}
|
|
18
|
+
}
|
|
19
|
+
return v;
|
|
20
|
+
}, inner);
|
|
21
|
+
|
|
22
|
+
// src/tools/schemas.ts
|
|
23
|
+
var nodeId = z2.string().describe("Node ID");
|
|
24
|
+
var nodeIds = flexJson(z2.array(z2.string())).describe("Array of node IDs");
|
|
25
|
+
var parentId = z2.string().optional().describe("Parent node ID. Omit to place on current page.");
|
|
26
|
+
var depth = z2.coerce.number().optional().describe("Response detail: omit for id+name only. 0=properties + child stubs. N=recurse N levels. -1=unlimited.");
|
|
27
|
+
var xPos = z2.coerce.number().optional().describe("X position (default: 0)");
|
|
28
|
+
var yPos = z2.coerce.number().optional().describe("Y position (default: 0)");
|
|
29
|
+
function parseHex(hex) {
|
|
30
|
+
const m = hex.match(/^#?([0-9a-f]{3,8})$/i);
|
|
31
|
+
if (!m) return null;
|
|
32
|
+
let h = m[1];
|
|
33
|
+
if (h.length === 3) h = h[0] + h[0] + h[1] + h[1] + h[2] + h[2];
|
|
34
|
+
if (h.length === 4) h = h[0] + h[0] + h[1] + h[1] + h[2] + h[2] + h[3] + h[3];
|
|
35
|
+
if (h.length !== 6 && h.length !== 8) return null;
|
|
36
|
+
const r = parseInt(h.slice(0, 2), 16) / 255;
|
|
37
|
+
const g = parseInt(h.slice(2, 4), 16) / 255;
|
|
38
|
+
const b = parseInt(h.slice(4, 6), 16) / 255;
|
|
39
|
+
if (h.length === 8) return { r, g, b, a: parseInt(h.slice(6, 8), 16) / 255 };
|
|
40
|
+
return { r, g, b };
|
|
41
|
+
}
|
|
42
|
+
var colorRgba = z2.preprocess((v) => {
|
|
43
|
+
if (typeof v === "string") return parseHex(v) ?? v;
|
|
44
|
+
return v;
|
|
45
|
+
}, z2.object({
|
|
46
|
+
r: z2.coerce.number().min(0).max(1),
|
|
47
|
+
g: z2.coerce.number().min(0).max(1),
|
|
48
|
+
b: z2.coerce.number().min(0).max(1),
|
|
49
|
+
a: z2.coerce.number().min(0).max(1).optional()
|
|
50
|
+
})).describe('Hex "#FF0000" or {r,g,b,a?} with values 0-1.');
|
|
51
|
+
var effectEntry = z2.object({
|
|
52
|
+
type: z2.enum(["DROP_SHADOW", "INNER_SHADOW", "LAYER_BLUR", "BACKGROUND_BLUR"]),
|
|
53
|
+
color: flexJson(colorRgba).optional(),
|
|
54
|
+
offset: flexJson(z2.object({ x: z2.coerce.number(), y: z2.coerce.number() })).optional(),
|
|
55
|
+
radius: z2.coerce.number(),
|
|
56
|
+
spread: z2.coerce.number().optional(),
|
|
57
|
+
visible: flexBool(z2.boolean()).optional(),
|
|
58
|
+
blendMode: z2.string().optional()
|
|
59
|
+
});
|
|
60
|
+
export {
|
|
61
|
+
colorRgba,
|
|
62
|
+
depth,
|
|
63
|
+
effectEntry,
|
|
64
|
+
nodeId,
|
|
65
|
+
nodeIds,
|
|
66
|
+
parentId,
|
|
67
|
+
xPos,
|
|
68
|
+
yPos
|
|
69
|
+
};
|
|
70
|
+
//# sourceMappingURL=schemas.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"sources":["../../src/tools/schemas.ts","../../src/utils/coercion.ts"],"sourcesContent":["import { z } from \"zod\";\nimport { flexJson, flexBool } from \"../utils/coercion\";\n\n// ─── Shared Zod Schema Fragments ────────────────────────────────\n// Import as: import * as S from \"./schemas\";\n\n/** Single node ID */\nexport const nodeId = z.string().describe(\"Node ID\");\n\n/** Array of node IDs */\nexport const nodeIds = flexJson(z.array(z.string())).describe(\"Array of node IDs\");\n\n/** Optional parent reference for creation tools */\nexport const parentId = z.string().optional()\n .describe(\"Parent node ID. Omit to place on current page.\");\n\n/**\n * Response depth — controls how much node detail is returned after an operation.\n * Omit for minimal response (id + name only).\n * 0 = node with full properties, children as stubs.\n * N = recurse N levels of children with full properties.\n * -1 = unlimited recursion.\n */\nexport const depth = z.coerce.number().optional()\n .describe(\"Response detail: omit for id+name only. 0=properties + child stubs. N=recurse N levels. -1=unlimited.\");\n\n/** X position for creation tools */\nexport const xPos = z.coerce.number().optional().describe(\"X position (default: 0)\");\n\n/** Y position for creation tools */\nexport const yPos = z.coerce.number().optional().describe(\"Y position (default: 0)\");\n\n/** Parse hex color string (#RGB, #RRGGBB, #RRGGBBAA) to {r,g,b,a} 0-1 */\nfunction parseHex(hex: string): { r: number; g: number; b: number; a?: number } | null {\n const m = hex.match(/^#?([0-9a-f]{3,8})$/i);\n if (!m) return null;\n let h = m[1];\n if (h.length === 3) h = h[0]+h[0]+h[1]+h[1]+h[2]+h[2];\n if (h.length === 4) h = h[0]+h[0]+h[1]+h[1]+h[2]+h[2]+h[3]+h[3];\n if (h.length !== 6 && h.length !== 8) return null;\n const r = parseInt(h.slice(0, 2), 16) / 255;\n const g = parseInt(h.slice(2, 4), 16) / 255;\n const b = parseInt(h.slice(4, 6), 16) / 255;\n if (h.length === 8) return { r, g, b, a: parseInt(h.slice(6, 8), 16) / 255 };\n return { r, g, b };\n}\n\n/** RGBA color — accepts {r,g,b,a?} object (0-1) or hex string (#RGB, #RRGGBB, #RRGGBBAA) */\nexport const colorRgba = z.preprocess((v) => {\n if (typeof v === \"string\") return parseHex(v) ?? v;\n return v;\n}, z.object({\n r: z.coerce.number().min(0).max(1),\n g: z.coerce.number().min(0).max(1),\n b: z.coerce.number().min(0).max(1),\n a: z.coerce.number().min(0).max(1).optional(),\n})).describe('Hex \"#FF0000\" or {r,g,b,a?} with values 0-1.');\n\n/** Single effect entry — shared by set_effects and styles create */\nexport const effectEntry = z.object({\n type: z.enum([\"DROP_SHADOW\", \"INNER_SHADOW\", \"LAYER_BLUR\", \"BACKGROUND_BLUR\"]),\n color: flexJson(colorRgba).optional(),\n offset: flexJson(z.object({ x: z.coerce.number(), y: z.coerce.number() })).optional(),\n radius: z.coerce.number(),\n spread: z.coerce.number().optional(),\n visible: flexBool(z.boolean()).optional(),\n blendMode: z.string().optional(),\n});\n","import { z } from \"zod\";\n\n// AI agents (Claude, GPT, etc.) frequently pass numbers as strings\n// (\"10\" instead of 10), booleans as strings (\"true\" instead of true),\n// and objects/arrays as JSON strings. These helpers add resilient\n// coercion so tools don't fail on valid-but-mistyped input.\n\n/** Coerce \"true\"/\"false\"/\"1\"/\"0\" strings to boolean */\nexport const flexBool = <T extends z.ZodTypeAny>(inner: T) =>\n z.preprocess((v) => {\n if (v === \"true\" || v === \"1\") return true;\n if (v === \"false\" || v === \"0\") return false;\n return v;\n }, inner);\n\n/** Coerce JSON strings to parsed values (for objects/arrays that agents may stringify) */\nexport const flexJson = <T extends z.ZodTypeAny>(inner: T) =>\n z.preprocess((v) => {\n if (typeof v === \"string\") {\n try {\n return JSON.parse(v);\n } catch {\n return v;\n }\n }\n return v;\n }, inner);\n\n/** Coerce numeric strings only when they're valid numbers (safe for use inside unions) */\nexport const flexNum = <T extends z.ZodTypeAny>(inner: T) =>\n z.preprocess((v) => {\n if (typeof v === \"string\") {\n const n = Number(v);\n if (!isNaN(n) && v.trim() !== \"\") return n;\n }\n return v;\n }, inner);\n"],"mappings":"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","names":["z","z"]}
|
|
@@ -0,0 +1,52 @@
|
|
|
1
|
+
var __defProp = Object.defineProperty;
|
|
2
|
+
var __getOwnPropDesc = Object.getOwnPropertyDescriptor;
|
|
3
|
+
var __getOwnPropNames = Object.getOwnPropertyNames;
|
|
4
|
+
var __hasOwnProp = Object.prototype.hasOwnProperty;
|
|
5
|
+
var __export = (target, all) => {
|
|
6
|
+
for (var name in all)
|
|
7
|
+
__defProp(target, name, { get: all[name], enumerable: true });
|
|
8
|
+
};
|
|
9
|
+
var __copyProps = (to, from, except, desc) => {
|
|
10
|
+
if (from && typeof from === "object" || typeof from === "function") {
|
|
11
|
+
for (let key of __getOwnPropNames(from))
|
|
12
|
+
if (!__hasOwnProp.call(to, key) && key !== except)
|
|
13
|
+
__defProp(to, key, { get: () => from[key], enumerable: !(desc = __getOwnPropDesc(from, key)) || desc.enumerable });
|
|
14
|
+
}
|
|
15
|
+
return to;
|
|
16
|
+
};
|
|
17
|
+
var __toCommonJS = (mod) => __copyProps(__defProp({}, "__esModule", { value: true }), mod);
|
|
18
|
+
|
|
19
|
+
// src/tools/types.ts
|
|
20
|
+
var types_exports = {};
|
|
21
|
+
__export(types_exports, {
|
|
22
|
+
mcpError: () => mcpError,
|
|
23
|
+
mcpJson: () => mcpJson
|
|
24
|
+
});
|
|
25
|
+
module.exports = __toCommonJS(types_exports);
|
|
26
|
+
var MAX_RESPONSE_CHARS = 5e4;
|
|
27
|
+
function mcpJson(data) {
|
|
28
|
+
const text = JSON.stringify(data);
|
|
29
|
+
if (text.length <= MAX_RESPONSE_CHARS) {
|
|
30
|
+
return { content: [{ type: "text", text }] };
|
|
31
|
+
}
|
|
32
|
+
return {
|
|
33
|
+
content: [{
|
|
34
|
+
type: "text",
|
|
35
|
+
text: JSON.stringify({
|
|
36
|
+
_error: "response_too_large",
|
|
37
|
+
_sizeKB: Math.round(text.length / 1024),
|
|
38
|
+
warning: "Response exceeds safe size. Use 'depth', 'fields', 'limit', or 'summaryOnly' parameters to reduce response size."
|
|
39
|
+
})
|
|
40
|
+
}]
|
|
41
|
+
};
|
|
42
|
+
}
|
|
43
|
+
function mcpError(prefix, error) {
|
|
44
|
+
const msg = error instanceof Error ? error.message : String(error);
|
|
45
|
+
return { content: [{ type: "text", text: `${prefix}: ${msg}` }] };
|
|
46
|
+
}
|
|
47
|
+
// Annotate the CommonJS export names for ESM import in node:
|
|
48
|
+
0 && (module.exports = {
|
|
49
|
+
mcpError,
|
|
50
|
+
mcpJson
|
|
51
|
+
});
|
|
52
|
+
//# sourceMappingURL=types.cjs.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"sources":["../../src/tools/types.ts"],"sourcesContent":["import type { McpServer } from \"@modelcontextprotocol/sdk/server/mcp.js\";\nimport type { z } from \"zod\";\n\n/** Function signature for sending commands to Figma via WebSocket */\nexport type SendCommandFn = (command: string, params?: unknown, timeoutMs?: number) => Promise<unknown>;\n\n/** Re-export McpServer type for tool files */\nexport type { McpServer };\n\n// ─── Tool Registry Types ────────────────────────────────────────\n\n/** Access tier for a tool */\nexport type ToolTier = \"read\" | \"create\" | \"edit\";\n\n/** Which tiers are enabled for this MCP session */\nexport interface Capabilities { create: boolean; edit: boolean }\n\n/** Declarative tool definition — replaces imperative registerMcpTools() */\nexport interface ToolDef {\n name: string;\n description: string;\n schema: Record<string, z.ZodTypeAny>\n | ((caps: Capabilities) => Record<string, z.ZodTypeAny>);\n tier: ToolTier;\n /** Figma command name. Defaults to name. */\n command?: string;\n /** sendCommand timeout in ms (default: 30 000) */\n timeout?: number;\n /** Pre-send validation (e.g. per-method item parsing for endpoints) */\n validate?: (params: any) => void;\n /** Custom response formatter. Default: mcpJson */\n formatResponse?: (result: unknown) => any;\n}\n\n/** Standard batch result from Figma handlers */\nexport interface BatchResult<T = unknown> {\n results: Array<T | \"ok\" | { error: string }>;\n warnings?: string[];\n /** Set when some items were deferred (e.g. font loading cap exceeded) */\n deferred?: string;\n}\n\n/** Max response size in characters (~12K tokens). Prevents LLM client-side truncation that corrupts JSON. */\nconst MAX_RESPONSE_CHARS = 50_000;\n\n/** Format a successful MCP response (JSON). Returns a clean error if response exceeds safe size. */\nexport function mcpJson(data: unknown) {\n const text = JSON.stringify(data);\n if (text.length <= MAX_RESPONSE_CHARS) {\n return { content: [{ type: \"text\" as const, text }] };\n }\n return {\n content: [{\n type: \"text\" as const,\n text: JSON.stringify({\n _error: \"response_too_large\",\n _sizeKB: Math.round(text.length / 1024),\n warning: \"Response exceeds safe size. Use 'depth', 'fields', 'limit', or 'summaryOnly' parameters to reduce response size.\",\n }),\n }],\n };\n}\n\n/** Format an error MCP response */\nexport function mcpError(prefix: string, error: unknown) {\n const msg = error instanceof Error ? error.message : String(error);\n return { content: [{ type: \"text\" as const, text: `${prefix}: ${msg}` }] };\n}\n"],"mappings":";;;;;;;;;;;;;;;;;;;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AA2CA,IAAM,qBAAqB;AAGpB,SAAS,QAAQ,MAAe;AACrC,QAAM,OAAO,KAAK,UAAU,IAAI;AAChC,MAAI,KAAK,UAAU,oBAAoB;AACrC,WAAO,EAAE,SAAS,CAAC,EAAE,MAAM,QAAiB,KAAK,CAAC,EAAE;AAAA,EACtD;AACA,SAAO;AAAA,IACL,SAAS,CAAC;AAAA,MACR,MAAM;AAAA,MACN,MAAM,KAAK,UAAU;AAAA,QACnB,QAAQ;AAAA,QACR,SAAS,KAAK,MAAM,KAAK,SAAS,IAAI;AAAA,QACtC,SAAS;AAAA,MACX,CAAC;AAAA,IACH,CAAC;AAAA,EACH;AACF;AAGO,SAAS,SAAS,QAAgB,OAAgB;AACvD,QAAM,MAAM,iBAAiB,QAAQ,MAAM,UAAU,OAAO,KAAK;AACjE,SAAO,EAAE,SAAS,CAAC,EAAE,MAAM,QAAiB,MAAM,GAAG,MAAM,KAAK,GAAG,GAAG,CAAC,EAAE;AAC3E;","names":[]}
|
|
@@ -0,0 +1,53 @@
|
|
|
1
|
+
export { McpServer } from '@modelcontextprotocol/sdk/server/mcp.js';
|
|
2
|
+
import { z } from 'zod';
|
|
3
|
+
|
|
4
|
+
/** Function signature for sending commands to Figma via WebSocket */
|
|
5
|
+
type SendCommandFn = (command: string, params?: unknown, timeoutMs?: number) => Promise<unknown>;
|
|
6
|
+
|
|
7
|
+
/** Access tier for a tool */
|
|
8
|
+
type ToolTier = "read" | "create" | "edit";
|
|
9
|
+
/** Which tiers are enabled for this MCP session */
|
|
10
|
+
interface Capabilities {
|
|
11
|
+
create: boolean;
|
|
12
|
+
edit: boolean;
|
|
13
|
+
}
|
|
14
|
+
/** Declarative tool definition — replaces imperative registerMcpTools() */
|
|
15
|
+
interface ToolDef {
|
|
16
|
+
name: string;
|
|
17
|
+
description: string;
|
|
18
|
+
schema: Record<string, z.ZodTypeAny> | ((caps: Capabilities) => Record<string, z.ZodTypeAny>);
|
|
19
|
+
tier: ToolTier;
|
|
20
|
+
/** Figma command name. Defaults to name. */
|
|
21
|
+
command?: string;
|
|
22
|
+
/** sendCommand timeout in ms (default: 30 000) */
|
|
23
|
+
timeout?: number;
|
|
24
|
+
/** Pre-send validation (e.g. per-method item parsing for endpoints) */
|
|
25
|
+
validate?: (params: any) => void;
|
|
26
|
+
/** Custom response formatter. Default: mcpJson */
|
|
27
|
+
formatResponse?: (result: unknown) => any;
|
|
28
|
+
}
|
|
29
|
+
/** Standard batch result from Figma handlers */
|
|
30
|
+
interface BatchResult<T = unknown> {
|
|
31
|
+
results: Array<T | "ok" | {
|
|
32
|
+
error: string;
|
|
33
|
+
}>;
|
|
34
|
+
warnings?: string[];
|
|
35
|
+
/** Set when some items were deferred (e.g. font loading cap exceeded) */
|
|
36
|
+
deferred?: string;
|
|
37
|
+
}
|
|
38
|
+
/** Format a successful MCP response (JSON). Returns a clean error if response exceeds safe size. */
|
|
39
|
+
declare function mcpJson(data: unknown): {
|
|
40
|
+
content: {
|
|
41
|
+
type: "text";
|
|
42
|
+
text: string;
|
|
43
|
+
}[];
|
|
44
|
+
};
|
|
45
|
+
/** Format an error MCP response */
|
|
46
|
+
declare function mcpError(prefix: string, error: unknown): {
|
|
47
|
+
content: {
|
|
48
|
+
type: "text";
|
|
49
|
+
text: string;
|
|
50
|
+
}[];
|
|
51
|
+
};
|
|
52
|
+
|
|
53
|
+
export { type BatchResult, type Capabilities, type SendCommandFn, type ToolDef, type ToolTier, mcpError, mcpJson };
|
|
@@ -0,0 +1,53 @@
|
|
|
1
|
+
export { McpServer } from '@modelcontextprotocol/sdk/server/mcp.js';
|
|
2
|
+
import { z } from 'zod';
|
|
3
|
+
|
|
4
|
+
/** Function signature for sending commands to Figma via WebSocket */
|
|
5
|
+
type SendCommandFn = (command: string, params?: unknown, timeoutMs?: number) => Promise<unknown>;
|
|
6
|
+
|
|
7
|
+
/** Access tier for a tool */
|
|
8
|
+
type ToolTier = "read" | "create" | "edit";
|
|
9
|
+
/** Which tiers are enabled for this MCP session */
|
|
10
|
+
interface Capabilities {
|
|
11
|
+
create: boolean;
|
|
12
|
+
edit: boolean;
|
|
13
|
+
}
|
|
14
|
+
/** Declarative tool definition — replaces imperative registerMcpTools() */
|
|
15
|
+
interface ToolDef {
|
|
16
|
+
name: string;
|
|
17
|
+
description: string;
|
|
18
|
+
schema: Record<string, z.ZodTypeAny> | ((caps: Capabilities) => Record<string, z.ZodTypeAny>);
|
|
19
|
+
tier: ToolTier;
|
|
20
|
+
/** Figma command name. Defaults to name. */
|
|
21
|
+
command?: string;
|
|
22
|
+
/** sendCommand timeout in ms (default: 30 000) */
|
|
23
|
+
timeout?: number;
|
|
24
|
+
/** Pre-send validation (e.g. per-method item parsing for endpoints) */
|
|
25
|
+
validate?: (params: any) => void;
|
|
26
|
+
/** Custom response formatter. Default: mcpJson */
|
|
27
|
+
formatResponse?: (result: unknown) => any;
|
|
28
|
+
}
|
|
29
|
+
/** Standard batch result from Figma handlers */
|
|
30
|
+
interface BatchResult<T = unknown> {
|
|
31
|
+
results: Array<T | "ok" | {
|
|
32
|
+
error: string;
|
|
33
|
+
}>;
|
|
34
|
+
warnings?: string[];
|
|
35
|
+
/** Set when some items were deferred (e.g. font loading cap exceeded) */
|
|
36
|
+
deferred?: string;
|
|
37
|
+
}
|
|
38
|
+
/** Format a successful MCP response (JSON). Returns a clean error if response exceeds safe size. */
|
|
39
|
+
declare function mcpJson(data: unknown): {
|
|
40
|
+
content: {
|
|
41
|
+
type: "text";
|
|
42
|
+
text: string;
|
|
43
|
+
}[];
|
|
44
|
+
};
|
|
45
|
+
/** Format an error MCP response */
|
|
46
|
+
declare function mcpError(prefix: string, error: unknown): {
|
|
47
|
+
content: {
|
|
48
|
+
type: "text";
|
|
49
|
+
text: string;
|
|
50
|
+
}[];
|
|
51
|
+
};
|
|
52
|
+
|
|
53
|
+
export { type BatchResult, type Capabilities, type SendCommandFn, type ToolDef, type ToolTier, mcpError, mcpJson };
|
|
@@ -0,0 +1,27 @@
|
|
|
1
|
+
// src/tools/types.ts
|
|
2
|
+
var MAX_RESPONSE_CHARS = 5e4;
|
|
3
|
+
function mcpJson(data) {
|
|
4
|
+
const text = JSON.stringify(data);
|
|
5
|
+
if (text.length <= MAX_RESPONSE_CHARS) {
|
|
6
|
+
return { content: [{ type: "text", text }] };
|
|
7
|
+
}
|
|
8
|
+
return {
|
|
9
|
+
content: [{
|
|
10
|
+
type: "text",
|
|
11
|
+
text: JSON.stringify({
|
|
12
|
+
_error: "response_too_large",
|
|
13
|
+
_sizeKB: Math.round(text.length / 1024),
|
|
14
|
+
warning: "Response exceeds safe size. Use 'depth', 'fields', 'limit', or 'summaryOnly' parameters to reduce response size."
|
|
15
|
+
})
|
|
16
|
+
}]
|
|
17
|
+
};
|
|
18
|
+
}
|
|
19
|
+
function mcpError(prefix, error) {
|
|
20
|
+
const msg = error instanceof Error ? error.message : String(error);
|
|
21
|
+
return { content: [{ type: "text", text: `${prefix}: ${msg}` }] };
|
|
22
|
+
}
|
|
23
|
+
export {
|
|
24
|
+
mcpError,
|
|
25
|
+
mcpJson
|
|
26
|
+
};
|
|
27
|
+
//# sourceMappingURL=types.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"sources":["../../src/tools/types.ts"],"sourcesContent":["import type { McpServer } from \"@modelcontextprotocol/sdk/server/mcp.js\";\nimport type { z } from \"zod\";\n\n/** Function signature for sending commands to Figma via WebSocket */\nexport type SendCommandFn = (command: string, params?: unknown, timeoutMs?: number) => Promise<unknown>;\n\n/** Re-export McpServer type for tool files */\nexport type { McpServer };\n\n// ─── Tool Registry Types ────────────────────────────────────────\n\n/** Access tier for a tool */\nexport type ToolTier = \"read\" | \"create\" | \"edit\";\n\n/** Which tiers are enabled for this MCP session */\nexport interface Capabilities { create: boolean; edit: boolean }\n\n/** Declarative tool definition — replaces imperative registerMcpTools() */\nexport interface ToolDef {\n name: string;\n description: string;\n schema: Record<string, z.ZodTypeAny>\n | ((caps: Capabilities) => Record<string, z.ZodTypeAny>);\n tier: ToolTier;\n /** Figma command name. Defaults to name. */\n command?: string;\n /** sendCommand timeout in ms (default: 30 000) */\n timeout?: number;\n /** Pre-send validation (e.g. per-method item parsing for endpoints) */\n validate?: (params: any) => void;\n /** Custom response formatter. Default: mcpJson */\n formatResponse?: (result: unknown) => any;\n}\n\n/** Standard batch result from Figma handlers */\nexport interface BatchResult<T = unknown> {\n results: Array<T | \"ok\" | { error: string }>;\n warnings?: string[];\n /** Set when some items were deferred (e.g. font loading cap exceeded) */\n deferred?: string;\n}\n\n/** Max response size in characters (~12K tokens). Prevents LLM client-side truncation that corrupts JSON. */\nconst MAX_RESPONSE_CHARS = 50_000;\n\n/** Format a successful MCP response (JSON). Returns a clean error if response exceeds safe size. */\nexport function mcpJson(data: unknown) {\n const text = JSON.stringify(data);\n if (text.length <= MAX_RESPONSE_CHARS) {\n return { content: [{ type: \"text\" as const, text }] };\n }\n return {\n content: [{\n type: \"text\" as const,\n text: JSON.stringify({\n _error: \"response_too_large\",\n _sizeKB: Math.round(text.length / 1024),\n warning: \"Response exceeds safe size. Use 'depth', 'fields', 'limit', or 'summaryOnly' parameters to reduce response size.\",\n }),\n }],\n };\n}\n\n/** Format an error MCP response */\nexport function mcpError(prefix: string, error: unknown) {\n const msg = error instanceof Error ? error.message : String(error);\n return { content: [{ type: \"text\" as const, text: `${prefix}: ${msg}` }] };\n}\n"],"mappings":";AA2CA,IAAM,qBAAqB;AAGpB,SAAS,QAAQ,MAAe;AACrC,QAAM,OAAO,KAAK,UAAU,IAAI;AAChC,MAAI,KAAK,UAAU,oBAAoB;AACrC,WAAO,EAAE,SAAS,CAAC,EAAE,MAAM,QAAiB,KAAK,CAAC,EAAE;AAAA,EACtD;AACA,SAAO;AAAA,IACL,SAAS,CAAC;AAAA,MACR,MAAM;AAAA,MACN,MAAM,KAAK,UAAU;AAAA,QACnB,QAAQ;AAAA,QACR,SAAS,KAAK,MAAM,KAAK,SAAS,IAAI;AAAA,QACtC,SAAS;AAAA,MACX,CAAC;AAAA,IACH,CAAC;AAAA,EACH;AACF;AAGO,SAAS,SAAS,QAAgB,OAAgB;AACvD,QAAM,MAAM,iBAAiB,QAAQ,MAAM,UAAU,OAAO,KAAK;AACjE,SAAO,EAAE,SAAS,CAAC,EAAE,MAAM,QAAiB,MAAM,GAAG,MAAM,KAAK,GAAG,GAAG,CAAC,EAAE;AAC3E;","names":[]}
|
|
@@ -0,0 +1,56 @@
|
|
|
1
|
+
var __defProp = Object.defineProperty;
|
|
2
|
+
var __getOwnPropDesc = Object.getOwnPropertyDescriptor;
|
|
3
|
+
var __getOwnPropNames = Object.getOwnPropertyNames;
|
|
4
|
+
var __hasOwnProp = Object.prototype.hasOwnProperty;
|
|
5
|
+
var __export = (target, all) => {
|
|
6
|
+
for (var name in all)
|
|
7
|
+
__defProp(target, name, { get: all[name], enumerable: true });
|
|
8
|
+
};
|
|
9
|
+
var __copyProps = (to, from, except, desc) => {
|
|
10
|
+
if (from && typeof from === "object" || typeof from === "function") {
|
|
11
|
+
for (let key of __getOwnPropNames(from))
|
|
12
|
+
if (!__hasOwnProp.call(to, key) && key !== except)
|
|
13
|
+
__defProp(to, key, { get: () => from[key], enumerable: !(desc = __getOwnPropDesc(from, key)) || desc.enumerable });
|
|
14
|
+
}
|
|
15
|
+
return to;
|
|
16
|
+
};
|
|
17
|
+
var __toCommonJS = (mod) => __copyProps(__defProp({}, "__esModule", { value: true }), mod);
|
|
18
|
+
|
|
19
|
+
// src/utils/coercion.ts
|
|
20
|
+
var coercion_exports = {};
|
|
21
|
+
__export(coercion_exports, {
|
|
22
|
+
flexBool: () => flexBool,
|
|
23
|
+
flexJson: () => flexJson,
|
|
24
|
+
flexNum: () => flexNum
|
|
25
|
+
});
|
|
26
|
+
module.exports = __toCommonJS(coercion_exports);
|
|
27
|
+
var import_zod = require("zod");
|
|
28
|
+
var flexBool = (inner) => import_zod.z.preprocess((v) => {
|
|
29
|
+
if (v === "true" || v === "1") return true;
|
|
30
|
+
if (v === "false" || v === "0") return false;
|
|
31
|
+
return v;
|
|
32
|
+
}, inner);
|
|
33
|
+
var flexJson = (inner) => import_zod.z.preprocess((v) => {
|
|
34
|
+
if (typeof v === "string") {
|
|
35
|
+
try {
|
|
36
|
+
return JSON.parse(v);
|
|
37
|
+
} catch {
|
|
38
|
+
return v;
|
|
39
|
+
}
|
|
40
|
+
}
|
|
41
|
+
return v;
|
|
42
|
+
}, inner);
|
|
43
|
+
var flexNum = (inner) => import_zod.z.preprocess((v) => {
|
|
44
|
+
if (typeof v === "string") {
|
|
45
|
+
const n = Number(v);
|
|
46
|
+
if (!isNaN(n) && v.trim() !== "") return n;
|
|
47
|
+
}
|
|
48
|
+
return v;
|
|
49
|
+
}, inner);
|
|
50
|
+
// Annotate the CommonJS export names for ESM import in node:
|
|
51
|
+
0 && (module.exports = {
|
|
52
|
+
flexBool,
|
|
53
|
+
flexJson,
|
|
54
|
+
flexNum
|
|
55
|
+
});
|
|
56
|
+
//# sourceMappingURL=coercion.cjs.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"sources":["../../src/utils/coercion.ts"],"sourcesContent":["import { z } from \"zod\";\n\n// AI agents (Claude, GPT, etc.) frequently pass numbers as strings\n// (\"10\" instead of 10), booleans as strings (\"true\" instead of true),\n// and objects/arrays as JSON strings. These helpers add resilient\n// coercion so tools don't fail on valid-but-mistyped input.\n\n/** Coerce \"true\"/\"false\"/\"1\"/\"0\" strings to boolean */\nexport const flexBool = <T extends z.ZodTypeAny>(inner: T) =>\n z.preprocess((v) => {\n if (v === \"true\" || v === \"1\") return true;\n if (v === \"false\" || v === \"0\") return false;\n return v;\n }, inner);\n\n/** Coerce JSON strings to parsed values (for objects/arrays that agents may stringify) */\nexport const flexJson = <T extends z.ZodTypeAny>(inner: T) =>\n z.preprocess((v) => {\n if (typeof v === \"string\") {\n try {\n return JSON.parse(v);\n } catch {\n return v;\n }\n }\n return v;\n }, inner);\n\n/** Coerce numeric strings only when they're valid numbers (safe for use inside unions) */\nexport const flexNum = <T extends z.ZodTypeAny>(inner: T) =>\n z.preprocess((v) => {\n if (typeof v === \"string\") {\n const n = Number(v);\n if (!isNaN(n) && v.trim() !== \"\") return n;\n }\n return v;\n }, inner);\n"],"mappings":";;;;;;;;;;;;;;;;;;;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA,iBAAkB;AAQX,IAAM,WAAW,CAAyB,UAC/C,aAAE,WAAW,CAAC,MAAM;AAClB,MAAI,MAAM,UAAU,MAAM,IAAK,QAAO;AACtC,MAAI,MAAM,WAAW,MAAM,IAAK,QAAO;AACvC,SAAO;AACT,GAAG,KAAK;AAGH,IAAM,WAAW,CAAyB,UAC/C,aAAE,WAAW,CAAC,MAAM;AAClB,MAAI,OAAO,MAAM,UAAU;AACzB,QAAI;AACF,aAAO,KAAK,MAAM,CAAC;AAAA,IACrB,QAAQ;AACN,aAAO;AAAA,IACT;AAAA,EACF;AACA,SAAO;AACT,GAAG,KAAK;AAGH,IAAM,UAAU,CAAyB,UAC9C,aAAE,WAAW,CAAC,MAAM;AAClB,MAAI,OAAO,MAAM,UAAU;AACzB,UAAM,IAAI,OAAO,CAAC;AAClB,QAAI,CAAC,MAAM,CAAC,KAAK,EAAE,KAAK,MAAM,GAAI,QAAO;AAAA,EAC3C;AACA,SAAO;AACT,GAAG,KAAK;","names":[]}
|
|
@@ -0,0 +1,10 @@
|
|
|
1
|
+
import { z } from 'zod';
|
|
2
|
+
|
|
3
|
+
/** Coerce "true"/"false"/"1"/"0" strings to boolean */
|
|
4
|
+
declare const flexBool: <T extends z.ZodTypeAny>(inner: T) => z.ZodPipe<z.ZodTransform<unknown, unknown>, T>;
|
|
5
|
+
/** Coerce JSON strings to parsed values (for objects/arrays that agents may stringify) */
|
|
6
|
+
declare const flexJson: <T extends z.ZodTypeAny>(inner: T) => z.ZodPipe<z.ZodTransform<any, unknown>, T>;
|
|
7
|
+
/** Coerce numeric strings only when they're valid numbers (safe for use inside unions) */
|
|
8
|
+
declare const flexNum: <T extends z.ZodTypeAny>(inner: T) => z.ZodPipe<z.ZodTransform<unknown, unknown>, T>;
|
|
9
|
+
|
|
10
|
+
export { flexBool, flexJson, flexNum };
|
|
@@ -0,0 +1,10 @@
|
|
|
1
|
+
import { z } from 'zod';
|
|
2
|
+
|
|
3
|
+
/** Coerce "true"/"false"/"1"/"0" strings to boolean */
|
|
4
|
+
declare const flexBool: <T extends z.ZodTypeAny>(inner: T) => z.ZodPipe<z.ZodTransform<unknown, unknown>, T>;
|
|
5
|
+
/** Coerce JSON strings to parsed values (for objects/arrays that agents may stringify) */
|
|
6
|
+
declare const flexJson: <T extends z.ZodTypeAny>(inner: T) => z.ZodPipe<z.ZodTransform<any, unknown>, T>;
|
|
7
|
+
/** Coerce numeric strings only when they're valid numbers (safe for use inside unions) */
|
|
8
|
+
declare const flexNum: <T extends z.ZodTypeAny>(inner: T) => z.ZodPipe<z.ZodTransform<unknown, unknown>, T>;
|
|
9
|
+
|
|
10
|
+
export { flexBool, flexJson, flexNum };
|
|
@@ -0,0 +1,30 @@
|
|
|
1
|
+
// src/utils/coercion.ts
|
|
2
|
+
import { z } from "zod";
|
|
3
|
+
var flexBool = (inner) => z.preprocess((v) => {
|
|
4
|
+
if (v === "true" || v === "1") return true;
|
|
5
|
+
if (v === "false" || v === "0") return false;
|
|
6
|
+
return v;
|
|
7
|
+
}, inner);
|
|
8
|
+
var flexJson = (inner) => z.preprocess((v) => {
|
|
9
|
+
if (typeof v === "string") {
|
|
10
|
+
try {
|
|
11
|
+
return JSON.parse(v);
|
|
12
|
+
} catch {
|
|
13
|
+
return v;
|
|
14
|
+
}
|
|
15
|
+
}
|
|
16
|
+
return v;
|
|
17
|
+
}, inner);
|
|
18
|
+
var flexNum = (inner) => z.preprocess((v) => {
|
|
19
|
+
if (typeof v === "string") {
|
|
20
|
+
const n = Number(v);
|
|
21
|
+
if (!isNaN(n) && v.trim() !== "") return n;
|
|
22
|
+
}
|
|
23
|
+
return v;
|
|
24
|
+
}, inner);
|
|
25
|
+
export {
|
|
26
|
+
flexBool,
|
|
27
|
+
flexJson,
|
|
28
|
+
flexNum
|
|
29
|
+
};
|
|
30
|
+
//# sourceMappingURL=coercion.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"sources":["../../src/utils/coercion.ts"],"sourcesContent":["import { z } from \"zod\";\n\n// AI agents (Claude, GPT, etc.) frequently pass numbers as strings\n// (\"10\" instead of 10), booleans as strings (\"true\" instead of true),\n// and objects/arrays as JSON strings. These helpers add resilient\n// coercion so tools don't fail on valid-but-mistyped input.\n\n/** Coerce \"true\"/\"false\"/\"1\"/\"0\" strings to boolean */\nexport const flexBool = <T extends z.ZodTypeAny>(inner: T) =>\n z.preprocess((v) => {\n if (v === \"true\" || v === \"1\") return true;\n if (v === \"false\" || v === \"0\") return false;\n return v;\n }, inner);\n\n/** Coerce JSON strings to parsed values (for objects/arrays that agents may stringify) */\nexport const flexJson = <T extends z.ZodTypeAny>(inner: T) =>\n z.preprocess((v) => {\n if (typeof v === \"string\") {\n try {\n return JSON.parse(v);\n } catch {\n return v;\n }\n }\n return v;\n }, inner);\n\n/** Coerce numeric strings only when they're valid numbers (safe for use inside unions) */\nexport const flexNum = <T extends z.ZodTypeAny>(inner: T) =>\n z.preprocess((v) => {\n if (typeof v === \"string\") {\n const n = Number(v);\n if (!isNaN(n) && v.trim() !== \"\") return n;\n }\n return v;\n }, inner);\n"],"mappings":";AAAA,SAAS,SAAS;AAQX,IAAM,WAAW,CAAyB,UAC/C,EAAE,WAAW,CAAC,MAAM;AAClB,MAAI,MAAM,UAAU,MAAM,IAAK,QAAO;AACtC,MAAI,MAAM,WAAW,MAAM,IAAK,QAAO;AACvC,SAAO;AACT,GAAG,KAAK;AAGH,IAAM,WAAW,CAAyB,UAC/C,EAAE,WAAW,CAAC,MAAM;AAClB,MAAI,OAAO,MAAM,UAAU;AACzB,QAAI;AACF,aAAO,KAAK,MAAM,CAAC;AAAA,IACrB,QAAQ;AACN,aAAO;AAAA,IACT;AAAA,EACF;AACA,SAAO;AACT,GAAG,KAAK;AAGH,IAAM,UAAU,CAAyB,UAC9C,EAAE,WAAW,CAAC,MAAM;AAClB,MAAI,OAAO,MAAM,UAAU;AACzB,UAAM,IAAI,OAAO,CAAC;AAClB,QAAI,CAAC,MAAM,CAAC,KAAK,EAAE,KAAK,MAAM,GAAI,QAAO;AAAA,EAC3C;AACA,SAAO;AACT,GAAG,KAAK;","names":[]}
|