@calibrate-ds/cli 0.1.7 → 0.1.9
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/dist/commands/bridge.d.ts +3 -0
- package/dist/commands/bridge.d.ts.map +1 -0
- package/dist/commands/bridge.js +62 -0
- package/dist/commands/bridge.js.map +1 -0
- package/dist/commands/generate-components.d.ts.map +1 -1
- package/dist/commands/generate-components.js +31 -1
- package/dist/commands/generate-components.js.map +1 -1
- package/dist/commands/init.d.ts.map +1 -1
- package/dist/commands/init.js +4 -1
- package/dist/commands/init.js.map +1 -1
- package/dist/commands/mcp.d.ts +4 -0
- package/dist/commands/mcp.d.ts.map +1 -0
- package/dist/commands/mcp.js +29 -0
- package/dist/commands/mcp.js.map +1 -0
- package/dist/commands/verify.d.ts +6 -0
- package/dist/commands/verify.d.ts.map +1 -0
- package/dist/commands/verify.js +280 -0
- package/dist/commands/verify.js.map +1 -0
- package/dist/index.js +56 -0
- package/dist/index.js.map +1 -1
- package/dist/mcp/registry.d.ts +20 -0
- package/dist/mcp/registry.d.ts.map +1 -0
- package/dist/mcp/registry.js +8 -0
- package/dist/mcp/registry.js.map +1 -0
- package/dist/mcp/server.d.ts +4 -0
- package/dist/mcp/server.d.ts.map +1 -0
- package/dist/mcp/server.js +70 -0
- package/dist/mcp/server.js.map +1 -0
- package/dist/mcp/tools/action-tools.d.ts +3 -0
- package/dist/mcp/tools/action-tools.d.ts.map +1 -0
- package/dist/mcp/tools/action-tools.js +235 -0
- package/dist/mcp/tools/action-tools.js.map +1 -0
- package/dist/mcp/tools/component-tools.d.ts +9 -0
- package/dist/mcp/tools/component-tools.d.ts.map +1 -0
- package/dist/mcp/tools/component-tools.js +129 -0
- package/dist/mcp/tools/component-tools.js.map +1 -0
- package/dist/mcp/tools/governance-tools.d.ts +3 -0
- package/dist/mcp/tools/governance-tools.d.ts.map +1 -0
- package/dist/mcp/tools/governance-tools.js +180 -0
- package/dist/mcp/tools/governance-tools.js.map +1 -0
- package/dist/mcp/tools/info-tools.d.ts +3 -0
- package/dist/mcp/tools/info-tools.d.ts.map +1 -0
- package/dist/mcp/tools/info-tools.js +87 -0
- package/dist/mcp/tools/info-tools.js.map +1 -0
- package/dist/mcp/tools/token-tools.d.ts +3 -0
- package/dist/mcp/tools/token-tools.d.ts.map +1 -0
- package/dist/mcp/tools/token-tools.js +60 -0
- package/dist/mcp/tools/token-tools.js.map +1 -0
- package/dist/mcp/tools/verify-tool.d.ts +3 -0
- package/dist/mcp/tools/verify-tool.d.ts.map +1 -0
- package/dist/mcp/tools/verify-tool.js +82 -0
- package/dist/mcp/tools/verify-tool.js.map +1 -0
- package/package.json +6 -5
|
@@ -0,0 +1,129 @@
|
|
|
1
|
+
import * as fs from "node:fs/promises";
|
|
2
|
+
import * as path from "node:path";
|
|
3
|
+
import { z } from "zod";
|
|
4
|
+
import { getComponentContext } from "@calibrate-ds/core";
|
|
5
|
+
function toSlug(name) {
|
|
6
|
+
return name.toLowerCase().trim().replace(/[^a-z0-9]+/g, "-").replace(/^-+|-+$/g, "");
|
|
7
|
+
}
|
|
8
|
+
function findComponent(snapshot, query) {
|
|
9
|
+
const q = query.toLowerCase();
|
|
10
|
+
const slug = toSlug(query);
|
|
11
|
+
return snapshot.components.find((c) => c.name.toLowerCase() === q || toSlug(c.name) === slug || c.id === query);
|
|
12
|
+
}
|
|
13
|
+
export async function loadBridge(workspaceRoot) {
|
|
14
|
+
try {
|
|
15
|
+
const raw = await fs.readFile(path.join(workspaceRoot, "ptb-bridge.json"), "utf-8");
|
|
16
|
+
return JSON.parse(raw);
|
|
17
|
+
}
|
|
18
|
+
catch {
|
|
19
|
+
return [];
|
|
20
|
+
}
|
|
21
|
+
}
|
|
22
|
+
export const componentTools = {
|
|
23
|
+
name: "component",
|
|
24
|
+
register(server, getContext) {
|
|
25
|
+
server.tool("get_component", "Get the full design context for a component by name. Returns variant axes, token bindings, state contract, interaction contract, implementation hints, and the render tree.", { name: z.string().describe("Component display name, e.g. 'Button' or 'Notification Item'") }, async ({ name }) => {
|
|
26
|
+
let ctx;
|
|
27
|
+
try {
|
|
28
|
+
ctx = await getContext();
|
|
29
|
+
}
|
|
30
|
+
catch (e) {
|
|
31
|
+
return { content: [{ type: "text", text: e.message }] };
|
|
32
|
+
}
|
|
33
|
+
const comp = findComponent(ctx.snapshot, name);
|
|
34
|
+
if (!comp) {
|
|
35
|
+
const available = ctx.snapshot.components.map((c) => c.name).slice(0, 15).join(", ");
|
|
36
|
+
return { content: [{ type: "text", text: `Component '${name}' not found.\nAvailable (first 15): ${available}` }] };
|
|
37
|
+
}
|
|
38
|
+
try {
|
|
39
|
+
const context = await getComponentContext(comp.id, ctx.snapshot, ctx.config);
|
|
40
|
+
if (!context)
|
|
41
|
+
return { content: [{ type: "text", text: `Could not build context for '${name}'.` }] };
|
|
42
|
+
return { content: [{ type: "text", text: JSON.stringify(context, null, 2) }] };
|
|
43
|
+
}
|
|
44
|
+
catch (e) {
|
|
45
|
+
return { content: [{ type: "text", text: `Error building context: ${e.message}` }] };
|
|
46
|
+
}
|
|
47
|
+
});
|
|
48
|
+
server.tool("list_components", "List all components in the design system. Returns name, kind, category, variant axis count, and Figma node ID for each.", async () => {
|
|
49
|
+
let ctx;
|
|
50
|
+
try {
|
|
51
|
+
ctx = await getContext();
|
|
52
|
+
}
|
|
53
|
+
catch (e) {
|
|
54
|
+
return { content: [{ type: "text", text: e.message }] };
|
|
55
|
+
}
|
|
56
|
+
const items = ctx.snapshot.components.map((c) => ({
|
|
57
|
+
name: c.name,
|
|
58
|
+
slug: toSlug(c.name),
|
|
59
|
+
kind: c.kind?.value ?? "unknown",
|
|
60
|
+
category: c.categoryPath ?? "unclassified",
|
|
61
|
+
variantAxes: c.variantAxes?.map((a) => a.name) ?? [],
|
|
62
|
+
nodeId: c.designToolNodeId ?? null,
|
|
63
|
+
}));
|
|
64
|
+
return { content: [{ type: "text", text: JSON.stringify(items, null, 2) }] };
|
|
65
|
+
});
|
|
66
|
+
server.tool("get_component_slots", "Get the instance-swap slots for a component — the insertion points where child components (e.g. icons) go. Returns each slot name, its default value, and the list of valid components for that slot (preferredValues from Figma).", { name: z.string().describe("Component name, e.g. 'BtnWeb'") }, async ({ name }) => {
|
|
67
|
+
let ctx;
|
|
68
|
+
try {
|
|
69
|
+
ctx = await getContext();
|
|
70
|
+
}
|
|
71
|
+
catch (e) {
|
|
72
|
+
return { content: [{ type: "text", text: e.message }] };
|
|
73
|
+
}
|
|
74
|
+
const comp = findComponent(ctx.snapshot, name);
|
|
75
|
+
if (!comp) {
|
|
76
|
+
return { content: [{ type: "text", text: `Component '${name}' not found.` }] };
|
|
77
|
+
}
|
|
78
|
+
const instanceProps = (comp.properties ?? []).filter((p) => p.type === "instance");
|
|
79
|
+
if (instanceProps.length === 0) {
|
|
80
|
+
return { content: [{ type: "text", text: `'${comp.name}' has no instance-swap slots.` }] };
|
|
81
|
+
}
|
|
82
|
+
const slots = instanceProps.map((p) => ({
|
|
83
|
+
slotName: p.name,
|
|
84
|
+
defaultValue: p.defaultValue ?? null,
|
|
85
|
+
preferredValues: p.preferredValues ?? [],
|
|
86
|
+
hasConstrainedValues: (p.preferredValues?.length ?? 0) > 0,
|
|
87
|
+
}));
|
|
88
|
+
return { content: [{ type: "text", text: JSON.stringify({ component: comp.name, slots }, null, 2) }] };
|
|
89
|
+
});
|
|
90
|
+
server.tool("find_component_by_figma_node", "Find a design system component by its Figma node ID. Returns the component definition plus Symbol Bridge export/file info if registered.", { nodeId: z.string().describe("Figma node ID, e.g. '123:456'") }, async ({ nodeId }) => {
|
|
91
|
+
let ctx;
|
|
92
|
+
try {
|
|
93
|
+
ctx = await getContext();
|
|
94
|
+
}
|
|
95
|
+
catch (e) {
|
|
96
|
+
return { content: [{ type: "text", text: e.message }] };
|
|
97
|
+
}
|
|
98
|
+
const comp = ctx.snapshot.components.find((c) => c.designToolNodeId === nodeId);
|
|
99
|
+
if (!comp) {
|
|
100
|
+
return { content: [{ type: "text", text: `No component found for Figma node '${nodeId}'.` }] };
|
|
101
|
+
}
|
|
102
|
+
const bridge = await loadBridge(ctx.workspaceRoot);
|
|
103
|
+
const entry = bridge.find((b) => b.nodeId === nodeId);
|
|
104
|
+
const result = {
|
|
105
|
+
componentName: comp.name,
|
|
106
|
+
nodeId,
|
|
107
|
+
kind: comp.kind?.value ?? "unknown",
|
|
108
|
+
category: comp.categoryPath ?? "unclassified",
|
|
109
|
+
};
|
|
110
|
+
if (entry) {
|
|
111
|
+
result.exportName = entry.componentName;
|
|
112
|
+
result.filePath = entry.filePath;
|
|
113
|
+
}
|
|
114
|
+
try {
|
|
115
|
+
const context = await getComponentContext(comp.id, ctx.snapshot, ctx.config);
|
|
116
|
+
if (context?.variantAxes?.length) {
|
|
117
|
+
result.variantAxes = context.variantAxes.map((a) => ({
|
|
118
|
+
name: a.name,
|
|
119
|
+
options: a.options,
|
|
120
|
+
default: context.component.defaultVariantSelection?.[a.name] ?? a.options[0],
|
|
121
|
+
}));
|
|
122
|
+
}
|
|
123
|
+
}
|
|
124
|
+
catch { /* non-fatal */ }
|
|
125
|
+
return { content: [{ type: "text", text: JSON.stringify(result, null, 2) }] };
|
|
126
|
+
});
|
|
127
|
+
},
|
|
128
|
+
};
|
|
129
|
+
//# sourceMappingURL=component-tools.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"component-tools.js","sourceRoot":"","sources":["../../../src/mcp/tools/component-tools.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,MAAM,kBAAkB,CAAC;AACvC,OAAO,KAAK,IAAI,MAAM,WAAW,CAAC;AAClC,OAAO,EAAE,CAAC,EAAE,MAAM,KAAK,CAAC;AACxB,OAAO,EAAE,mBAAmB,EAAE,MAAM,oBAAoB,CAAC;AAUzD,SAAS,MAAM,CAAC,IAAY;IACxB,OAAO,IAAI,CAAC,WAAW,EAAE,CAAC,IAAI,EAAE,CAAC,OAAO,CAAC,aAAa,EAAE,GAAG,CAAC,CAAC,OAAO,CAAC,UAAU,EAAE,EAAE,CAAC,CAAC;AACzF,CAAC;AAED,SAAS,aAAa,CAAC,QAA2B,EAAE,KAAa;IAC7D,MAAM,CAAC,GAAG,KAAK,CAAC,WAAW,EAAE,CAAC;IAC9B,MAAM,IAAI,GAAG,MAAM,CAAC,KAAK,CAAC,CAAC;IAC3B,OAAO,QAAQ,CAAC,UAAU,CAAC,IAAI,CAC3B,CAAC,CAAC,EAAE,EAAE,CAAC,CAAC,CAAC,IAAI,CAAC,WAAW,EAAE,KAAK,CAAC,IAAI,MAAM,CAAC,CAAC,CAAC,IAAI,CAAC,KAAK,IAAI,IAAI,CAAC,CAAC,EAAE,KAAK,KAAK,CACjF,CAAC;AACN,CAAC;AAED,MAAM,CAAC,KAAK,UAAU,UAAU,CAAC,aAAqB;IAClD,IAAI,CAAC;QACD,MAAM,GAAG,GAAG,MAAM,EAAE,CAAC,QAAQ,CAAC,IAAI,CAAC,IAAI,CAAC,aAAa,EAAE,iBAAiB,CAAC,EAAE,OAAO,CAAC,CAAC;QACpF,OAAO,IAAI,CAAC,KAAK,CAAC,GAAG,CAAkB,CAAC;IAC5C,CAAC;IAAC,MAAM,CAAC;QACL,OAAO,EAAE,CAAC;IACd,CAAC;AACL,CAAC;AAED,MAAM,CAAC,MAAM,cAAc,GAAiB;IACxC,IAAI,EAAE,WAAW;IACjB,QAAQ,CAAC,MAAM,EAAE,UAAU;QAEvB,MAAM,CAAC,IAAI,CACP,eAAe,EACf,6KAA6K,EAC7K,EAAE,IAAI,EAAE,CAAC,CAAC,MAAM,EAAE,CAAC,QAAQ,CAAC,8DAA8D,CAAC,EAAE,EAC7F,KAAK,EAAE,EAAE,IAAI,EAAE,EAAE,EAAE;YACf,IAAI,GAAe,CAAC;YACpB,IAAI,CAAC;gBAAC,GAAG,GAAG,MAAM,UAAU,EAAE,CAAC;YAAC,CAAC;YAAC,OAAO,CAAM,EAAE,CAAC;gBAC9C,OAAO,EAAE,OAAO,EAAE,CAAC,EAAE,IAAI,EAAE,MAAe,EAAE,IAAI,EAAE,CAAC,CAAC,OAAO,EAAE,CAAC,EAAE,CAAC;YACrE,CAAC;YACD,MAAM,IAAI,GAAG,aAAa,CAAC,GAAG,CAAC,QAAQ,EAAE,IAAI,CAAC,CAAC;YAC/C,IAAI,CAAC,IAAI,EAAE,CAAC;gBACR,MAAM,SAAS,GAAG,GAAG,CAAC,QAAQ,CAAC,UAAU,CAAC,GAAG,CAAC,CAAC,CAAC,EAAE,EAAE,CAAC,CAAC,CAAC,IAAI,CAAC,CAAC,KAAK,CAAC,CAAC,EAAE,EAAE,CAAC,CAAC,IAAI,CAAC,IAAI,CAAC,CAAC;gBACrF,OAAO,EAAE,OAAO,EAAE,CAAC,EAAE,IAAI,EAAE,MAAe,EAAE,IAAI,EAAE,cAAc,IAAI,uCAAuC,SAAS,EAAE,EAAE,CAAC,EAAE,CAAC;YAChI,CAAC;YACD,IAAI,CAAC;gBACD,MAAM,OAAO,GAAG,MAAM,mBAAmB,CAAC,IAAI,CAAC,EAAE,EAAE,GAAG,CAAC,QAAQ,EAAE,GAAG,CAAC,MAAM,CAAC,CAAC;gBAC7E,IAAI,CAAC,OAAO;oBAAE,OAAO,EAAE,OAAO,EAAE,CAAC,EAAE,IAAI,EAAE,MAAe,EAAE,IAAI,EAAE,gCAAgC,IAAI,IAAI,EAAE,CAAC,EAAE,CAAC;gBAC9G,OAAO,EAAE,OAAO,EAAE,CAAC,EAAE,IAAI,EAAE,MAAe,EAAE,IAAI,EAAE,IAAI,CAAC,SAAS,CAAC,OAAO,EAAE,IAAI,EAAE,CAAC,CAAC,EAAE,CAAC,EAAE,CAAC;YAC5F,CAAC;YAAC,OAAO,CAAM,EAAE,CAAC;gBACd,OAAO,EAAE,OAAO,EAAE,CAAC,EAAE,IAAI,EAAE,MAAe,EAAE,IAAI,EAAE,2BAA2B,CAAC,CAAC,OAAO,EAAE,EAAE,CAAC,EAAE,CAAC;YAClG,CAAC;QACL,CAAC,CACJ,CAAC;QAEF,MAAM,CAAC,IAAI,CACP,iBAAiB,EACjB,yHAAyH,EACzH,KAAK,IAAI,EAAE;YACP,IAAI,GAAe,CAAC;YACpB,IAAI,CAAC;gBAAC,GAAG,GAAG,MAAM,UAAU,EAAE,CAAC;YAAC,CAAC;YAAC,OAAO,CAAM,EAAE,CAAC;gBAC9C,OAAO,EAAE,OAAO,EAAE,CAAC,EAAE,IAAI,EAAE,MAAe,EAAE,IAAI,EAAE,CAAC,CAAC,OAAO,EAAE,CAAC,EAAE,CAAC;YACrE,CAAC;YACD,MAAM,KAAK,GAAG,GAAG,CAAC,QAAQ,CAAC,UAAU,CAAC,GAAG,CAAC,CAAC,CAAC,EAAE,EAAE,CAAC,CAAC;gBAC9C,IAAI,EAAE,CAAC,CAAC,IAAI;gBACZ,IAAI,EAAE,MAAM,CAAC,CAAC,CAAC,IAAI,CAAC;gBACpB,IAAI,EAAE,CAAC,CAAC,IAAI,EAAE,KAAK,IAAI,SAAS;gBAChC,QAAQ,EAAE,CAAC,CAAC,YAAY,IAAI,cAAc;gBAC1C,WAAW,EAAE,CAAC,CAAC,WAAW,EAAE,GAAG,CAAC,CAAC,CAAC,EAAE,EAAE,CAAC,CAAC,CAAC,IAAI,CAAC,IAAI,EAAE;gBACpD,MAAM,EAAG,CAAS,CAAC,gBAAgB,IAAI,IAAI;aAC9C,CAAC,CAAC,CAAC;YACJ,OAAO,EAAE,OAAO,EAAE,CAAC,EAAE,IAAI,EAAE,MAAe,EAAE,IAAI,EAAE,IAAI,CAAC,SAAS,CAAC,KAAK,EAAE,IAAI,EAAE,CAAC,CAAC,EAAE,CAAC,EAAE,CAAC;QAC1F,CAAC,CACJ,CAAC;QAEF,MAAM,CAAC,IAAI,CACP,qBAAqB,EACrB,oOAAoO,EACpO,EAAE,IAAI,EAAE,CAAC,CAAC,MAAM,EAAE,CAAC,QAAQ,CAAC,+BAA+B,CAAC,EAAE,EAC9D,KAAK,EAAE,EAAE,IAAI,EAAE,EAAE,EAAE;YACf,IAAI,GAAe,CAAC;YACpB,IAAI,CAAC;gBAAC,GAAG,GAAG,MAAM,UAAU,EAAE,CAAC;YAAC,CAAC;YAAC,OAAO,CAAM,EAAE,CAAC;gBAC9C,OAAO,EAAE,OAAO,EAAE,CAAC,EAAE,IAAI,EAAE,MAAe,EAAE,IAAI,EAAE,CAAC,CAAC,OAAO,EAAE,CAAC,EAAE,CAAC;YACrE,CAAC;YACD,MAAM,IAAI,GAAG,aAAa,CAAC,GAAG,CAAC,QAAQ,EAAE,IAAI,CAAC,CAAC;YAC/C,IAAI,CAAC,IAAI,EAAE,CAAC;gBACR,OAAO,EAAE,OAAO,EAAE,CAAC,EAAE,IAAI,EAAE,MAAe,EAAE,IAAI,EAAE,cAAc,IAAI,cAAc,EAAE,CAAC,EAAE,CAAC;YAC5F,CAAC;YACD,MAAM,aAAa,GAAG,CAAC,IAAI,CAAC,UAAU,IAAI,EAAE,CAAC,CAAC,MAAM,CAAC,CAAC,CAAM,EAAE,EAAE,CAAC,CAAC,CAAC,IAAI,KAAK,UAAU,CAAC,CAAC;YACxF,IAAI,aAAa,CAAC,MAAM,KAAK,CAAC,EAAE,CAAC;gBAC7B,OAAO,EAAE,OAAO,EAAE,CAAC,EAAE,IAAI,EAAE,MAAe,EAAE,IAAI,EAAE,IAAI,IAAI,CAAC,IAAI,+BAA+B,EAAE,CAAC,EAAE,CAAC;YACxG,CAAC;YACD,MAAM,KAAK,GAAG,aAAa,CAAC,GAAG,CAAC,CAAC,CAAM,EAAE,EAAE,CAAC,CAAC;gBACzC,QAAQ,EAAE,CAAC,CAAC,IAAI;gBAChB,YAAY,EAAE,CAAC,CAAC,YAAY,IAAI,IAAI;gBACpC,eAAe,EAAE,CAAC,CAAC,eAAe,IAAI,EAAE;gBACxC,oBAAoB,EAAE,CAAC,CAAC,CAAC,eAAe,EAAE,MAAM,IAAI,CAAC,CAAC,GAAG,CAAC;aAC7D,CAAC,CAAC,CAAC;YACJ,OAAO,EAAE,OAAO,EAAE,CAAC,EAAE,IAAI,EAAE,MAAe,EAAE,IAAI,EAAE,IAAI,CAAC,SAAS,CAAC,EAAE,SAAS,EAAE,IAAI,CAAC,IAAI,EAAE,KAAK,EAAE,EAAE,IAAI,EAAE,CAAC,CAAC,EAAE,CAAC,EAAE,CAAC;QACpH,CAAC,CACJ,CAAC;QAEF,MAAM,CAAC,IAAI,CACP,8BAA8B,EAC9B,0IAA0I,EAC1I,EAAE,MAAM,EAAE,CAAC,CAAC,MAAM,EAAE,CAAC,QAAQ,CAAC,+BAA+B,CAAC,EAAE,EAChE,KAAK,EAAE,EAAE,MAAM,EAAE,EAAE,EAAE;YACjB,IAAI,GAAe,CAAC;YACpB,IAAI,CAAC;gBAAC,GAAG,GAAG,MAAM,UAAU,EAAE,CAAC;YAAC,CAAC;YAAC,OAAO,CAAM,EAAE,CAAC;gBAC9C,OAAO,EAAE,OAAO,EAAE,CAAC,EAAE,IAAI,EAAE,MAAe,EAAE,IAAI,EAAE,CAAC,CAAC,OAAO,EAAE,CAAC,EAAE,CAAC;YACrE,CAAC;YACD,MAAM,IAAI,GAAG,GAAG,CAAC,QAAQ,CAAC,UAAU,CAAC,IAAI,CAAC,CAAC,CAAC,EAAE,EAAE,CAAE,CAAS,CAAC,gBAAgB,KAAK,MAAM,CAAC,CAAC;YACzF,IAAI,CAAC,IAAI,EAAE,CAAC;gBACR,OAAO,EAAE,OAAO,EAAE,CAAC,EAAE,IAAI,EAAE,MAAe,EAAE,IAAI,EAAE,sCAAsC,MAAM,IAAI,EAAE,CAAC,EAAE,CAAC;YAC5G,CAAC;YACD,MAAM,MAAM,GAAG,MAAM,UAAU,CAAC,GAAG,CAAC,aAAa,CAAC,CAAC;YACnD,MAAM,KAAK,GAAG,MAAM,CAAC,IAAI,CAAC,CAAC,CAAC,EAAE,EAAE,CAAC,CAAC,CAAC,MAAM,KAAK,MAAM,CAAC,CAAC;YAEtD,MAAM,MAAM,GAA4B;gBACpC,aAAa,EAAE,IAAI,CAAC,IAAI;gBACxB,MAAM;gBACN,IAAI,EAAE,IAAI,CAAC,IAAI,EAAE,KAAK,IAAI,SAAS;gBACnC,QAAQ,EAAE,IAAI,CAAC,YAAY,IAAI,cAAc;aAChD,CAAC;YACF,IAAI,KAAK,EAAE,CAAC;gBACR,MAAM,CAAC,UAAU,GAAG,KAAK,CAAC,aAAa,CAAC;gBACxC,MAAM,CAAC,QAAQ,GAAG,KAAK,CAAC,QAAQ,CAAC;YACrC,CAAC;YACD,IAAI,CAAC;gBACD,MAAM,OAAO,GAAG,MAAM,mBAAmB,CAAC,IAAI,CAAC,EAAE,EAAE,GAAG,CAAC,QAAQ,EAAE,GAAG,CAAC,MAAM,CAAC,CAAC;gBAC7E,IAAI,OAAO,EAAE,WAAW,EAAE,MAAM,EAAE,CAAC;oBAC/B,MAAM,CAAC,WAAW,GAAG,OAAO,CAAC,WAAW,CAAC,GAAG,CAAC,CAAC,CAAC,EAAE,EAAE,CAAC,CAAC;wBACjD,IAAI,EAAE,CAAC,CAAC,IAAI;wBACZ,OAAO,EAAE,CAAC,CAAC,OAAO;wBAClB,OAAO,EAAG,OAAO,CAAC,SAAiB,CAAC,uBAAuB,EAAE,CAAC,CAAC,CAAC,IAAI,CAAC,IAAI,CAAC,CAAC,OAAO,CAAC,CAAC,CAAC;qBACxF,CAAC,CAAC,CAAC;gBACR,CAAC;YACL,CAAC;YAAC,MAAM,CAAC,CAAC,eAAe,CAAC,CAAC;YAE3B,OAAO,EAAE,OAAO,EAAE,CAAC,EAAE,IAAI,EAAE,MAAe,EAAE,IAAI,EAAE,IAAI,CAAC,SAAS,CAAC,MAAM,EAAE,IAAI,EAAE,CAAC,CAAC,EAAE,CAAC,EAAE,CAAC;QAC3F,CAAC,CACJ,CAAC;IACN,CAAC;CACJ,CAAC"}
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"governance-tools.d.ts","sourceRoot":"","sources":["../../../src/mcp/tools/governance-tools.ts"],"names":[],"mappings":"AAGA,OAAO,KAAK,EAAE,YAAY,EAAc,MAAM,gBAAgB,CAAC;AAgB/D,eAAO,MAAM,eAAe,EAAE,YAmL7B,CAAC"}
|
|
@@ -0,0 +1,180 @@
|
|
|
1
|
+
import * as fs from "node:fs/promises";
|
|
2
|
+
import * as path from "node:path";
|
|
3
|
+
import { z } from "zod";
|
|
4
|
+
function toSlug(name) {
|
|
5
|
+
return name.toLowerCase().trim().replace(/[^a-z0-9]+/g, "-").replace(/^-+|-+$/g, "");
|
|
6
|
+
}
|
|
7
|
+
async function loadLock(workspaceRoot) {
|
|
8
|
+
try {
|
|
9
|
+
const raw = await fs.readFile(path.join(workspaceRoot, "ptb.lock"), "utf-8");
|
|
10
|
+
return JSON.parse(raw);
|
|
11
|
+
}
|
|
12
|
+
catch {
|
|
13
|
+
return null;
|
|
14
|
+
}
|
|
15
|
+
}
|
|
16
|
+
export const governanceTools = {
|
|
17
|
+
name: "governance",
|
|
18
|
+
register(server, getContext) {
|
|
19
|
+
server.tool("is_stale", "Check which components are stale (design changed since last stamp), ready (stamped and current), or unstamped (never implemented). Use this to understand the current health of the design system.", async () => {
|
|
20
|
+
let ctx;
|
|
21
|
+
try {
|
|
22
|
+
ctx = await getContext();
|
|
23
|
+
}
|
|
24
|
+
catch (e) {
|
|
25
|
+
return { content: [{ type: "text", text: e.message }] };
|
|
26
|
+
}
|
|
27
|
+
const lock = await loadLock(ctx.workspaceRoot);
|
|
28
|
+
if (!lock) {
|
|
29
|
+
return { content: [{ type: "text", text: "No ptb.lock found. Run 'ptb export context' first." }] };
|
|
30
|
+
}
|
|
31
|
+
const stale = [];
|
|
32
|
+
const ready = [];
|
|
33
|
+
const unstamped = [];
|
|
34
|
+
for (const [slug, entry] of Object.entries(lock.components)) {
|
|
35
|
+
if (!entry.stampedHash) {
|
|
36
|
+
unstamped.push({ name: entry.displayName, slug, assignedTo: entry.assignedTo ?? null });
|
|
37
|
+
}
|
|
38
|
+
else if (entry.stampedHash !== entry.designHash) {
|
|
39
|
+
stale.push({
|
|
40
|
+
name: entry.displayName,
|
|
41
|
+
slug,
|
|
42
|
+
stampedAt: entry.stampedAt ?? null,
|
|
43
|
+
stampedBy: entry.stampedBy ?? null,
|
|
44
|
+
assignedTo: entry.assignedTo ?? null,
|
|
45
|
+
});
|
|
46
|
+
}
|
|
47
|
+
else {
|
|
48
|
+
ready.push({
|
|
49
|
+
name: entry.displayName,
|
|
50
|
+
slug,
|
|
51
|
+
stampedAt: entry.stampedAt ?? null,
|
|
52
|
+
stampedBy: entry.stampedBy ?? null,
|
|
53
|
+
});
|
|
54
|
+
}
|
|
55
|
+
}
|
|
56
|
+
const summary = {
|
|
57
|
+
total: ready.length + stale.length + unstamped.length,
|
|
58
|
+
ready: ready.length,
|
|
59
|
+
stale: stale.length,
|
|
60
|
+
unstamped: unstamped.length,
|
|
61
|
+
components: { ready, stale, unstamped },
|
|
62
|
+
};
|
|
63
|
+
return { content: [{ type: "text", text: JSON.stringify(summary, null, 2) }] };
|
|
64
|
+
});
|
|
65
|
+
server.tool("what_uses", "Find all components that depend on a given component. Useful for understanding blast radius before changing a component.", { name: z.string().describe("Component name to search for usages, e.g. 'Toggle' or 'Avatar'") }, async ({ name }) => {
|
|
66
|
+
let ctx;
|
|
67
|
+
try {
|
|
68
|
+
ctx = await getContext();
|
|
69
|
+
}
|
|
70
|
+
catch (e) {
|
|
71
|
+
return { content: [{ type: "text", text: e.message }] };
|
|
72
|
+
}
|
|
73
|
+
const q = name.toLowerCase();
|
|
74
|
+
const slug = toSlug(name);
|
|
75
|
+
const target = ctx.snapshot.components.find((c) => c.name.toLowerCase() === q || toSlug(c.name) === slug || c.id === name);
|
|
76
|
+
if (!target) {
|
|
77
|
+
return { content: [{ type: "text", text: `Component '${name}' not found in snapshot.` }] };
|
|
78
|
+
}
|
|
79
|
+
// Check both the id and designToolNodeId for reverse-dependency lookup
|
|
80
|
+
const targetIds = new Set([target.id, target.designToolNodeId].filter(Boolean));
|
|
81
|
+
const users = ctx.snapshot.components
|
|
82
|
+
.filter((c) => {
|
|
83
|
+
if (c.id === target.id)
|
|
84
|
+
return false;
|
|
85
|
+
const deps = c.dependencies ?? [];
|
|
86
|
+
if (deps.some((id) => targetIds.has(id)))
|
|
87
|
+
return true;
|
|
88
|
+
const instances = c.dependencyInstances ?? [];
|
|
89
|
+
return instances.some((di) => targetIds.has(di.componentId));
|
|
90
|
+
})
|
|
91
|
+
.map((c) => ({
|
|
92
|
+
name: c.name,
|
|
93
|
+
kind: c.kind?.value ?? "unknown",
|
|
94
|
+
category: c.categoryPath ?? "unclassified",
|
|
95
|
+
}));
|
|
96
|
+
// Also check model-level dependency edges
|
|
97
|
+
const modelEdges = (ctx.snapshot.dependencies ?? [])
|
|
98
|
+
.filter((e) => targetIds.has(e.targetId))
|
|
99
|
+
.map((e) => {
|
|
100
|
+
const src = ctx.snapshot.components.find((c) => c.id === e.sourceId);
|
|
101
|
+
return src ? { name: src.name, kind: src.kind?.value ?? "unknown", via: e.type } : null;
|
|
102
|
+
})
|
|
103
|
+
.filter(Boolean);
|
|
104
|
+
const merged = [...users];
|
|
105
|
+
for (const edge of modelEdges) {
|
|
106
|
+
if (!merged.find((u) => u.name === edge.name))
|
|
107
|
+
merged.push(edge);
|
|
108
|
+
}
|
|
109
|
+
if (merged.length === 0) {
|
|
110
|
+
return { content: [{ type: "text", text: `No other components depend on '${target.name}'.` }] };
|
|
111
|
+
}
|
|
112
|
+
return { content: [{ type: "text", text: JSON.stringify({ target: target.name, usedBy: merged }, null, 2) }] };
|
|
113
|
+
});
|
|
114
|
+
server.tool("coverage_summary", "Get a high-level coverage report for the whole design system: how many components are ready, stale, or unimplemented. Grouped by category.", async () => {
|
|
115
|
+
let ctx;
|
|
116
|
+
try {
|
|
117
|
+
ctx = await getContext();
|
|
118
|
+
}
|
|
119
|
+
catch (e) {
|
|
120
|
+
return { content: [{ type: "text", text: e.message }] };
|
|
121
|
+
}
|
|
122
|
+
const lock = await loadLock(ctx.workspaceRoot);
|
|
123
|
+
if (!lock) {
|
|
124
|
+
return { content: [{ type: "text", text: "No ptb.lock found. Run 'ptb export context' first." }] };
|
|
125
|
+
}
|
|
126
|
+
const byCategory = {};
|
|
127
|
+
const getOrCreate = (cat) => {
|
|
128
|
+
if (!byCategory[cat])
|
|
129
|
+
byCategory[cat] = { ready: 0, stale: 0, unstamped: 0 };
|
|
130
|
+
return byCategory[cat];
|
|
131
|
+
};
|
|
132
|
+
for (const [slug, entry] of Object.entries(lock.components)) {
|
|
133
|
+
const comp = ctx.snapshot.components.find((c) => toSlug(c.name) === slug);
|
|
134
|
+
const cat = comp?.categoryPath ?? "unclassified";
|
|
135
|
+
const bucket = getOrCreate(cat);
|
|
136
|
+
if (!entry.stampedHash)
|
|
137
|
+
bucket.unstamped++;
|
|
138
|
+
else if (entry.stampedHash !== entry.designHash)
|
|
139
|
+
bucket.stale++;
|
|
140
|
+
else
|
|
141
|
+
bucket.ready++;
|
|
142
|
+
}
|
|
143
|
+
const total = Object.values(lock.components);
|
|
144
|
+
const summary = {
|
|
145
|
+
total: total.length,
|
|
146
|
+
ready: total.filter((e) => e.stampedHash && e.stampedHash === e.designHash).length,
|
|
147
|
+
stale: total.filter((e) => e.stampedHash && e.stampedHash !== e.designHash).length,
|
|
148
|
+
unstamped: total.filter((e) => !e.stampedHash).length,
|
|
149
|
+
byCategory,
|
|
150
|
+
};
|
|
151
|
+
return { content: [{ type: "text", text: JSON.stringify(summary, null, 2) }] };
|
|
152
|
+
});
|
|
153
|
+
server.tool("token_impact", "Find all components that use a specific design token. Useful for understanding which components will be affected when a token value changes.", { tokenName: z.string().describe("Token name or CSS variable, e.g. 'colors.brand.900' or '--ptb-colors-brand-900'") }, async ({ tokenName }) => {
|
|
154
|
+
let ctx;
|
|
155
|
+
try {
|
|
156
|
+
ctx = await getContext();
|
|
157
|
+
}
|
|
158
|
+
catch (e) {
|
|
159
|
+
return { content: [{ type: "text", text: e.message }] };
|
|
160
|
+
}
|
|
161
|
+
const query = tokenName.replace(/^--/, "").toLowerCase();
|
|
162
|
+
const affected = [];
|
|
163
|
+
for (const comp of ctx.snapshot.components) {
|
|
164
|
+
const bindings = comp.tokenBindings ?? [];
|
|
165
|
+
const matches = bindings.filter((b) => {
|
|
166
|
+
const name = (b.tokenName ?? b.cssVar ?? b.variableName ?? "").toLowerCase();
|
|
167
|
+
return name.includes(query);
|
|
168
|
+
});
|
|
169
|
+
if (matches.length > 0) {
|
|
170
|
+
affected.push({ component: comp.name, category: comp.categoryPath, bindings: matches });
|
|
171
|
+
}
|
|
172
|
+
}
|
|
173
|
+
if (affected.length === 0) {
|
|
174
|
+
return { content: [{ type: "text", text: `No components found using token '${tokenName}'.` }] };
|
|
175
|
+
}
|
|
176
|
+
return { content: [{ type: "text", text: JSON.stringify({ tokenName, affectedComponents: affected }, null, 2) }] };
|
|
177
|
+
});
|
|
178
|
+
},
|
|
179
|
+
};
|
|
180
|
+
//# sourceMappingURL=governance-tools.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"governance-tools.js","sourceRoot":"","sources":["../../../src/mcp/tools/governance-tools.ts"],"names":[],"mappings":"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"}
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"info-tools.d.ts","sourceRoot":"","sources":["../../../src/mcp/tools/info-tools.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,YAAY,EAAE,MAAM,gBAAgB,CAAC;AAsEnD,eAAO,MAAM,SAAS,EAAE,YA6BvB,CAAC"}
|
|
@@ -0,0 +1,87 @@
|
|
|
1
|
+
const CHANGELOG = {
|
|
2
|
+
"0.1.9": {
|
|
3
|
+
summary: "Write-action MCP tools, preferred values for instance-swap slots, and upgrade notices.",
|
|
4
|
+
highlights: [
|
|
5
|
+
"New MCP tool: run_scan — scan Figma and update snapshot without leaving the IDE",
|
|
6
|
+
"New MCP tool: generate_components — scaffold typed React shells from snapshot",
|
|
7
|
+
"New MCP tool: generate_tokens — regenerate CSS token files",
|
|
8
|
+
"New MCP tool: export_context — export .ptb/context/ files and update ptb.lock",
|
|
9
|
+
"New MCP tool: stamp_component — mark component as implemented",
|
|
10
|
+
"New MCP tool: assign_component — assign component to a developer",
|
|
11
|
+
"New MCP tool: get_component_slots — returns only instance-swap slots with preferredValues (valid icon names)",
|
|
12
|
+
"Scanner now captures Figma preferredValues for INSTANCE_SWAP properties (resolved to component names)",
|
|
13
|
+
"Post-upgrade notice: prints what's new when ptb version changes",
|
|
14
|
+
],
|
|
15
|
+
},
|
|
16
|
+
"0.1.8": {
|
|
17
|
+
summary: "Full MCP server (11 tools), Symbol Bridge, and --cwd fix.",
|
|
18
|
+
highlights: [
|
|
19
|
+
"MCP server: ptb mcp starts an MCP stdio server for AI IDEs",
|
|
20
|
+
"11 MCP tools: get_component, list_components, get_component_slots, find_component_by_figma_node, is_stale, what_uses, coverage_summary, token_impact, list_themes, get_token, get_verify_report",
|
|
21
|
+
"Symbol Bridge (ptb-bridge.json): maps Figma node IDs to exported component symbols",
|
|
22
|
+
"--cwd flag and PTB_WORKSPACE env var for MCP server CWD resolution",
|
|
23
|
+
"MCP roots auto-detect: uses MCP client workspace roots when available",
|
|
24
|
+
],
|
|
25
|
+
},
|
|
26
|
+
"0.1.7": {
|
|
27
|
+
summary: "Verify command and Storybook integration.",
|
|
28
|
+
highlights: [
|
|
29
|
+
"ptb verify component <name>: pixel-diffs Figma vs Storybook render",
|
|
30
|
+
"AI visual feedback via Claude Vision",
|
|
31
|
+
"Auto-detect Storybook on localhost:6006",
|
|
32
|
+
],
|
|
33
|
+
},
|
|
34
|
+
"0.1.6": {
|
|
35
|
+
summary: "AI layer, document command, and CI integration.",
|
|
36
|
+
highlights: [
|
|
37
|
+
"ptb implement component <name>: AI-writes component from design context",
|
|
38
|
+
"ptb document component <name>: generates MDX docs and Storybook stories",
|
|
39
|
+
"ptb document system: generates CLAUDE.md and components.md",
|
|
40
|
+
"ptb ci setup: generates GitHub Actions workflow for freshness checks",
|
|
41
|
+
"ptb ai setup/use/remove: multi-provider AI config (Claude, OpenAI)",
|
|
42
|
+
],
|
|
43
|
+
},
|
|
44
|
+
};
|
|
45
|
+
const UPGRADE_CHECKLIST = {
|
|
46
|
+
"0.1.9": [
|
|
47
|
+
"Re-run `ptb scan` (or use the new `run_scan` MCP tool) to capture preferredValues on instance-swap slots",
|
|
48
|
+
"Re-run `ptb export context` (or `export_context` MCP tool) to refresh .ptb/context/ with slot data",
|
|
49
|
+
"Update your MCP config to pick up 6 new write-action tools — restart your IDE's MCP server",
|
|
50
|
+
"No breaking changes to ptb.config.json or ptb.lock",
|
|
51
|
+
],
|
|
52
|
+
"0.1.8": [
|
|
53
|
+
"Add `ptb mcp` to your IDE's MCP server config (see README for Claude Code / Cursor / Windsurf examples)",
|
|
54
|
+
"Run `ptb bridge add` or re-run `ptb generate-components` to populate ptb-bridge.json",
|
|
55
|
+
"If MCP server can't find ptb.config.json, add --cwd to your IDE's MCP args",
|
|
56
|
+
"No breaking changes to ptb.config.json or ptb.lock",
|
|
57
|
+
],
|
|
58
|
+
"0.1.7": [
|
|
59
|
+
"Ensure Storybook is running on localhost:6006 for `ptb verify` to work",
|
|
60
|
+
"No breaking changes",
|
|
61
|
+
],
|
|
62
|
+
"0.1.6": [
|
|
63
|
+
"Run `ptb ai setup` to configure an AI provider for implement/document commands",
|
|
64
|
+
"No breaking changes to ptb.config.json or ptb.lock",
|
|
65
|
+
],
|
|
66
|
+
};
|
|
67
|
+
export const infoTools = {
|
|
68
|
+
name: "info",
|
|
69
|
+
register(server) {
|
|
70
|
+
server.tool("get_changelog", "Show what changed in recent PTB versions. Returns a summary and highlights for each release.", async () => {
|
|
71
|
+
const entries = Object.entries(CHANGELOG).map(([v, c]) => ({
|
|
72
|
+
version: v,
|
|
73
|
+
summary: c.summary,
|
|
74
|
+
highlights: c.highlights,
|
|
75
|
+
}));
|
|
76
|
+
return { content: [{ type: "text", text: JSON.stringify(entries, null, 2) }] };
|
|
77
|
+
});
|
|
78
|
+
server.tool("get_upgrade_checklist", "Get the upgrade checklist for a specific PTB version — what to do after updating.", async () => {
|
|
79
|
+
const entries = Object.entries(UPGRADE_CHECKLIST).map(([v, steps]) => ({
|
|
80
|
+
version: v,
|
|
81
|
+
steps,
|
|
82
|
+
}));
|
|
83
|
+
return { content: [{ type: "text", text: JSON.stringify(entries, null, 2) }] };
|
|
84
|
+
});
|
|
85
|
+
},
|
|
86
|
+
};
|
|
87
|
+
//# sourceMappingURL=info-tools.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"info-tools.js","sourceRoot":"","sources":["../../../src/mcp/tools/info-tools.ts"],"names":[],"mappings":"AAEA,MAAM,SAAS,GAA8D;IACzE,OAAO,EAAE;QACL,OAAO,EAAE,wFAAwF;QACjG,UAAU,EAAE;YACR,iFAAiF;YACjF,+EAA+E;YAC/E,4DAA4D;YAC5D,+EAA+E;YAC/E,+DAA+D;YAC/D,kEAAkE;YAClE,8GAA8G;YAC9G,uGAAuG;YACvG,iEAAiE;SACpE;KACJ;IACD,OAAO,EAAE;QACL,OAAO,EAAE,2DAA2D;QACpE,UAAU,EAAE;YACR,4DAA4D;YAC5D,iMAAiM;YACjM,oFAAoF;YACpF,oEAAoE;YACpE,uEAAuE;SAC1E;KACJ;IACD,OAAO,EAAE;QACL,OAAO,EAAE,2CAA2C;QACpD,UAAU,EAAE;YACR,oEAAoE;YACpE,sCAAsC;YACtC,yCAAyC;SAC5C;KACJ;IACD,OAAO,EAAE;QACL,OAAO,EAAE,iDAAiD;QAC1D,UAAU,EAAE;YACR,yEAAyE;YACzE,yEAAyE;YACzE,4DAA4D;YAC5D,sEAAsE;YACtE,oEAAoE;SACvE;KACJ;CACJ,CAAC;AAEF,MAAM,iBAAiB,GAA6B;IAChD,OAAO,EAAE;QACL,0GAA0G;QAC1G,oGAAoG;QACpG,4FAA4F;QAC5F,oDAAoD;KACvD;IACD,OAAO,EAAE;QACL,yGAAyG;QACzG,sFAAsF;QACtF,4EAA4E;QAC5E,oDAAoD;KACvD;IACD,OAAO,EAAE;QACL,wEAAwE;QACxE,qBAAqB;KACxB;IACD,OAAO,EAAE;QACL,gFAAgF;QAChF,oDAAoD;KACvD;CACJ,CAAC;AAEF,MAAM,CAAC,MAAM,SAAS,GAAiB;IACnC,IAAI,EAAE,MAAM;IACZ,QAAQ,CAAC,MAAM;QAEX,MAAM,CAAC,IAAI,CACP,eAAe,EACf,8FAA8F,EAC9F,KAAK,IAAI,EAAE;YACP,MAAM,OAAO,GAAG,MAAM,CAAC,OAAO,CAAC,SAAS,CAAC,CAAC,GAAG,CAAC,CAAC,CAAC,CAAC,EAAE,CAAC,CAAC,EAAE,EAAE,CAAC,CAAC;gBACvD,OAAO,EAAE,CAAC;gBACV,OAAO,EAAE,CAAC,CAAC,OAAO;gBAClB,UAAU,EAAE,CAAC,CAAC,UAAU;aAC3B,CAAC,CAAC,CAAC;YACJ,OAAO,EAAE,OAAO,EAAE,CAAC,EAAE,IAAI,EAAE,MAAe,EAAE,IAAI,EAAE,IAAI,CAAC,SAAS,CAAC,OAAO,EAAE,IAAI,EAAE,CAAC,CAAC,EAAE,CAAC,EAAE,CAAC;QAC5F,CAAC,CACJ,CAAC;QAEF,MAAM,CAAC,IAAI,CACP,uBAAuB,EACvB,mFAAmF,EACnF,KAAK,IAAI,EAAE;YACP,MAAM,OAAO,GAAG,MAAM,CAAC,OAAO,CAAC,iBAAiB,CAAC,CAAC,GAAG,CAAC,CAAC,CAAC,CAAC,EAAE,KAAK,CAAC,EAAE,EAAE,CAAC,CAAC;gBACnE,OAAO,EAAE,CAAC;gBACV,KAAK;aACR,CAAC,CAAC,CAAC;YACJ,OAAO,EAAE,OAAO,EAAE,CAAC,EAAE,IAAI,EAAE,MAAe,EAAE,IAAI,EAAE,IAAI,CAAC,SAAS,CAAC,OAAO,EAAE,IAAI,EAAE,CAAC,CAAC,EAAE,CAAC,EAAE,CAAC;QAC5F,CAAC,CACJ,CAAC;IACN,CAAC;CACJ,CAAC"}
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"token-tools.d.ts","sourceRoot":"","sources":["../../../src/mcp/tools/token-tools.ts"],"names":[],"mappings":"AACA,OAAO,KAAK,EAAE,YAAY,EAAc,MAAM,gBAAgB,CAAC;AAG/D,eAAO,MAAM,UAAU,EAAE,YAgExB,CAAC"}
|
|
@@ -0,0 +1,60 @@
|
|
|
1
|
+
import { z } from "zod";
|
|
2
|
+
export const tokenTools = {
|
|
3
|
+
name: "token",
|
|
4
|
+
register(server, getContext) {
|
|
5
|
+
server.tool("list_themes", "List all token collections (themes) in the design system. Returns each collection's name and a sample of its tokens.", async () => {
|
|
6
|
+
let ctx;
|
|
7
|
+
try {
|
|
8
|
+
ctx = await getContext();
|
|
9
|
+
}
|
|
10
|
+
catch (e) {
|
|
11
|
+
return { content: [{ type: "text", text: e.message }] };
|
|
12
|
+
}
|
|
13
|
+
const collections = ctx.snapshot.tokens ?? [];
|
|
14
|
+
if (collections.length === 0) {
|
|
15
|
+
return { content: [{ type: "text", text: "No token collections found in snapshot." }] };
|
|
16
|
+
}
|
|
17
|
+
const summary = collections.map((col) => ({
|
|
18
|
+
name: col.name,
|
|
19
|
+
tokenCount: col.tokens?.length ?? 0,
|
|
20
|
+
sampleTokens: (col.tokens ?? []).slice(0, 5).map((t) => ({
|
|
21
|
+
name: t.name,
|
|
22
|
+
cssVar: t.cssVar ?? t.codeNames?.css ?? null,
|
|
23
|
+
value: t.resolvedValue ?? t.value ?? null,
|
|
24
|
+
})),
|
|
25
|
+
}));
|
|
26
|
+
return { content: [{ type: "text", text: JSON.stringify(summary, null, 2) }] };
|
|
27
|
+
});
|
|
28
|
+
server.tool("get_token", "Look up a design token by name or path. Returns resolved value, CSS variable, and which collection it belongs to.", { path: z.string().describe("Token name or partial path, e.g. 'brand.900', 'spacing.4', or 'border-radius'") }, async ({ path: tokenPath }) => {
|
|
29
|
+
let ctx;
|
|
30
|
+
try {
|
|
31
|
+
ctx = await getContext();
|
|
32
|
+
}
|
|
33
|
+
catch (e) {
|
|
34
|
+
return { content: [{ type: "text", text: e.message }] };
|
|
35
|
+
}
|
|
36
|
+
const query = tokenPath.toLowerCase();
|
|
37
|
+
const matches = [];
|
|
38
|
+
for (const col of (ctx.snapshot.tokens ?? [])) {
|
|
39
|
+
for (const token of col.tokens ?? []) {
|
|
40
|
+
const name = (token.name ?? "").toLowerCase();
|
|
41
|
+
const cssVar = (token.cssVar ?? token.codeNames?.css ?? "").toLowerCase();
|
|
42
|
+
if (name.includes(query) || cssVar.includes(query)) {
|
|
43
|
+
matches.push({
|
|
44
|
+
collection: col.name,
|
|
45
|
+
name: token.name,
|
|
46
|
+
cssVar: token.cssVar ?? token.codeNames?.css ?? null,
|
|
47
|
+
resolvedValue: token.resolvedValue ?? token.value ?? null,
|
|
48
|
+
valueType: token.valueType ?? null,
|
|
49
|
+
});
|
|
50
|
+
}
|
|
51
|
+
}
|
|
52
|
+
}
|
|
53
|
+
if (matches.length === 0) {
|
|
54
|
+
return { content: [{ type: "text", text: `No tokens found matching '${tokenPath}'.` }] };
|
|
55
|
+
}
|
|
56
|
+
return { content: [{ type: "text", text: JSON.stringify(matches, null, 2) }] };
|
|
57
|
+
});
|
|
58
|
+
},
|
|
59
|
+
};
|
|
60
|
+
//# sourceMappingURL=token-tools.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"token-tools.js","sourceRoot":"","sources":["../../../src/mcp/tools/token-tools.ts"],"names":[],"mappings":"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"}
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"verify-tool.d.ts","sourceRoot":"","sources":["../../../src/mcp/tools/verify-tool.ts"],"names":[],"mappings":"AAGA,OAAO,KAAK,EAAE,YAAY,EAAc,MAAM,gBAAgB,CAAC;AAO/D,eAAO,MAAM,UAAU,EAAE,YA8ExB,CAAC"}
|
|
@@ -0,0 +1,82 @@
|
|
|
1
|
+
import * as fs from "node:fs/promises";
|
|
2
|
+
import * as path from "node:path";
|
|
3
|
+
import { z } from "zod";
|
|
4
|
+
function toSlug(name) {
|
|
5
|
+
return name.toLowerCase().trim().replace(/[^a-z0-9]+/g, "-").replace(/^-+|-+$/g, "");
|
|
6
|
+
}
|
|
7
|
+
export const verifyTool = {
|
|
8
|
+
name: "verify",
|
|
9
|
+
register(server, getContext) {
|
|
10
|
+
server.tool("get_verify_report", "Retrieve the latest visual verification report for a component. Shows pixel match score, AI-detected visual differences, and paths to screenshots. Run 'ptb verify component <name>' first to generate or refresh the report.", { name: z.string().describe("Component name, e.g. 'Button'") }, async ({ name }) => {
|
|
11
|
+
let ctx;
|
|
12
|
+
try {
|
|
13
|
+
ctx = await getContext();
|
|
14
|
+
}
|
|
15
|
+
catch (e) {
|
|
16
|
+
return { content: [{ type: "text", text: e.message }] };
|
|
17
|
+
}
|
|
18
|
+
const slug = toSlug(name);
|
|
19
|
+
const reportPath = path.join(ctx.metadataDir, "verify", slug, "report.json");
|
|
20
|
+
try {
|
|
21
|
+
const raw = await fs.readFile(reportPath, "utf-8");
|
|
22
|
+
const report = JSON.parse(raw);
|
|
23
|
+
const summary = {
|
|
24
|
+
component: report.componentName,
|
|
25
|
+
checkedAt: report.checkedAt,
|
|
26
|
+
pixelMatchScore: report.pixelMatch?.score ?? null,
|
|
27
|
+
assessment: report.aiFeedback?.overallAssessment ?? null,
|
|
28
|
+
summary: report.aiFeedback?.summary ?? null,
|
|
29
|
+
differences: report.aiFeedback?.differences ?? [],
|
|
30
|
+
screenshots: report.screenshots,
|
|
31
|
+
};
|
|
32
|
+
return { content: [{ type: "text", text: JSON.stringify(summary, null, 2) }] };
|
|
33
|
+
}
|
|
34
|
+
catch {
|
|
35
|
+
return {
|
|
36
|
+
content: [{
|
|
37
|
+
type: "text",
|
|
38
|
+
text: `No verify report found for '${name}'.\nRun: ptb verify component ${name}`,
|
|
39
|
+
}],
|
|
40
|
+
};
|
|
41
|
+
}
|
|
42
|
+
});
|
|
43
|
+
server.tool("list_verify_reports", "List all components that have been visually verified, with their latest pixel match scores and assessment.", async () => {
|
|
44
|
+
let ctx;
|
|
45
|
+
try {
|
|
46
|
+
ctx = await getContext();
|
|
47
|
+
}
|
|
48
|
+
catch (e) {
|
|
49
|
+
return { content: [{ type: "text", text: e.message }] };
|
|
50
|
+
}
|
|
51
|
+
const verifyDir = path.join(ctx.metadataDir, "verify");
|
|
52
|
+
let slugDirs;
|
|
53
|
+
try {
|
|
54
|
+
slugDirs = await fs.readdir(verifyDir);
|
|
55
|
+
}
|
|
56
|
+
catch {
|
|
57
|
+
return { content: [{ type: "text", text: "No verify reports found. Run 'ptb verify component <name>' to generate one." }] };
|
|
58
|
+
}
|
|
59
|
+
const reports = [];
|
|
60
|
+
for (const slug of slugDirs) {
|
|
61
|
+
const reportPath = path.join(verifyDir, slug, "report.json");
|
|
62
|
+
try {
|
|
63
|
+
const raw = await fs.readFile(reportPath, "utf-8");
|
|
64
|
+
const report = JSON.parse(raw);
|
|
65
|
+
reports.push({
|
|
66
|
+
component: report.componentName,
|
|
67
|
+
slug,
|
|
68
|
+
checkedAt: report.checkedAt,
|
|
69
|
+
score: report.pixelMatch?.score ?? null,
|
|
70
|
+
assessment: report.aiFeedback?.overallAssessment ?? null,
|
|
71
|
+
});
|
|
72
|
+
}
|
|
73
|
+
catch { /* skip malformed */ }
|
|
74
|
+
}
|
|
75
|
+
if (reports.length === 0) {
|
|
76
|
+
return { content: [{ type: "text", text: "No valid verify reports found." }] };
|
|
77
|
+
}
|
|
78
|
+
return { content: [{ type: "text", text: JSON.stringify(reports, null, 2) }] };
|
|
79
|
+
});
|
|
80
|
+
},
|
|
81
|
+
};
|
|
82
|
+
//# sourceMappingURL=verify-tool.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"verify-tool.js","sourceRoot":"","sources":["../../../src/mcp/tools/verify-tool.ts"],"names":[],"mappings":"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"}
|