@substrate-kit/cli 0.1.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.
Files changed (93) hide show
  1. package/dist/cli.d.ts +3 -0
  2. package/dist/cli.d.ts.map +1 -0
  3. package/dist/cli.js +101 -0
  4. package/dist/cli.js.map +1 -0
  5. package/dist/commands/add.d.ts +6 -0
  6. package/dist/commands/add.d.ts.map +1 -0
  7. package/dist/commands/add.js +311 -0
  8. package/dist/commands/add.js.map +1 -0
  9. package/dist/commands/browse.d.ts +2 -0
  10. package/dist/commands/browse.d.ts.map +1 -0
  11. package/dist/commands/browse.js +25 -0
  12. package/dist/commands/browse.js.map +1 -0
  13. package/dist/commands/create.d.ts +9 -0
  14. package/dist/commands/create.d.ts.map +1 -0
  15. package/dist/commands/create.js +414 -0
  16. package/dist/commands/create.js.map +1 -0
  17. package/dist/commands/docs.d.ts +4 -0
  18. package/dist/commands/docs.d.ts.map +1 -0
  19. package/dist/commands/docs.js +155 -0
  20. package/dist/commands/docs.js.map +1 -0
  21. package/dist/commands/init.d.ts +6 -0
  22. package/dist/commands/init.d.ts.map +1 -0
  23. package/dist/commands/init.js +134 -0
  24. package/dist/commands/init.js.map +1 -0
  25. package/dist/commands/variables.d.ts +4 -0
  26. package/dist/commands/variables.d.ts.map +1 -0
  27. package/dist/commands/variables.js +111 -0
  28. package/dist/commands/variables.js.map +1 -0
  29. package/dist/index.d.ts +3 -0
  30. package/dist/index.d.ts.map +1 -0
  31. package/dist/index.js +5 -0
  32. package/dist/index.js.map +1 -0
  33. package/dist/mcp/registry.d.ts +3 -0
  34. package/dist/mcp/registry.d.ts.map +1 -0
  35. package/dist/mcp/registry.js +43 -0
  36. package/dist/mcp/registry.js.map +1 -0
  37. package/dist/mcp/server.d.ts +3 -0
  38. package/dist/mcp/server.d.ts.map +1 -0
  39. package/dist/mcp/server.js +39 -0
  40. package/dist/mcp/server.js.map +1 -0
  41. package/dist/mcp/tools/get-component.d.ts +17 -0
  42. package/dist/mcp/tools/get-component.d.ts.map +1 -0
  43. package/dist/mcp/tools/get-component.js +23 -0
  44. package/dist/mcp/tools/get-component.js.map +1 -0
  45. package/dist/mcp/tools/install.d.ts +10 -0
  46. package/dist/mcp/tools/install.d.ts.map +1 -0
  47. package/dist/mcp/tools/install.js +40 -0
  48. package/dist/mcp/tools/install.js.map +1 -0
  49. package/dist/mcp/tools/search.d.ts +11 -0
  50. package/dist/mcp/tools/search.d.ts.map +1 -0
  51. package/dist/mcp/tools/search.js +30 -0
  52. package/dist/mcp/tools/search.js.map +1 -0
  53. package/dist/mcp/tools/theme.d.ts +10 -0
  54. package/dist/mcp/tools/theme.d.ts.map +1 -0
  55. package/dist/mcp/tools/theme.js +37 -0
  56. package/dist/mcp/tools/theme.js.map +1 -0
  57. package/dist/mcp/types.d.ts +31 -0
  58. package/dist/mcp/types.d.ts.map +1 -0
  59. package/dist/mcp/types.js +2 -0
  60. package/dist/mcp/types.js.map +1 -0
  61. package/dist/utils/detect-pm.d.ts +5 -0
  62. package/dist/utils/detect-pm.d.ts.map +1 -0
  63. package/dist/utils/detect-pm.js +20 -0
  64. package/dist/utils/detect-pm.js.map +1 -0
  65. package/dist/utils/fs.d.ts +7 -0
  66. package/dist/utils/fs.d.ts.map +1 -0
  67. package/dist/utils/fs.js +52 -0
  68. package/dist/utils/fs.js.map +1 -0
  69. package/dist/utils/logger.d.ts +10 -0
  70. package/dist/utils/logger.d.ts.map +1 -0
  71. package/dist/utils/logger.js +15 -0
  72. package/dist/utils/logger.js.map +1 -0
  73. package/dist/utils/shell.d.ts +7 -0
  74. package/dist/utils/shell.d.ts.map +1 -0
  75. package/dist/utils/shell.js +28 -0
  76. package/dist/utils/shell.js.map +1 -0
  77. package/package.json +37 -0
  78. package/skills/3d-scene/SKILL.md +172 -0
  79. package/skills/animation/SKILL.md +194 -0
  80. package/skills/canvas-2d/SKILL.md +132 -0
  81. package/skills/composing-panels/SKILL.md +309 -0
  82. package/skills/create-custom-tool/SKILL.md +157 -0
  83. package/skills/data-visualisation/SKILL.md +228 -0
  84. package/skills/image-generation/SKILL.md +211 -0
  85. package/skills/scaffold-playground/SKILL.md +141 -0
  86. package/skills/substrate-canvas/SKILL.md +217 -0
  87. package/skills/substrate-controls/SKILL.md +242 -0
  88. package/skills/substrate-feedback/SKILL.md +219 -0
  89. package/skills/substrate-interaction/SKILL.md +286 -0
  90. package/skills/substrate-nodes/SKILL.md +208 -0
  91. package/skills/substrate-scaffold/SKILL.md +206 -0
  92. package/skills/theming/SKILL.md +117 -0
  93. package/skills/wire-interactions/SKILL.md +155 -0
@@ -0,0 +1,134 @@
1
+ import { join } from "node:path";
2
+ import { copyDir, exists, writeFile, resolveSkillsDir, listDirs, } from "../utils/fs.js";
3
+ import { log } from "../utils/logger.js";
4
+ function claudeMd() {
5
+ return `# Substrate
6
+
7
+ This project uses [Substrate](https://substrate.georgedrury.co.uk) — a creative app framework that provides scaffold (toolbar, panels, panes, stores, shortcuts) around different surface types.
8
+
9
+ ## Skills
10
+
11
+ Substrate skills are installed in \`.claude/skills/\`. They are organised into two groups:
12
+
13
+ ### Surface guides (how to build)
14
+
15
+ - **scaffold-playground** — bootstrapping a new playground
16
+ - **canvas-2d** / **3d-scene** / **animation** / **image-generation** / **data-visualisation** — surface-specific architecture
17
+ - **composing-panels** / **wire-interactions** / **create-custom-tool** / **theming** — workflow guides
18
+
19
+ ### Component reference (what to use)
20
+
21
+ - **substrate-scaffold** — Toolbar, Panel, Pane, DocumentTabs, StatusBar, ZoomControls, Breadcrumbs, Resizer
22
+ - **substrate-controls** — NumberInput, Slider, NumberSlider, Select, Toggle, TextArea, ColourPicker, ActionControls
23
+ - **substrate-canvas** — useViewport, useSelection, useDragReorder, snap, boundingBox, hit testing
24
+ - **substrate-nodes** — Node cards, typed ports, port colour theming
25
+ - **substrate-feedback** — Toast, ProgressBar, Badge, EmptyState, CommandPalette, ContextMenu, ShortcutOverlay
26
+ - **substrate-interaction** — useUndoable, useClipboard, createKeyboardShortcuts, HistoryControls, LayerList, TreeList
27
+
28
+ ## Install components
29
+
30
+ \`\`\`bash
31
+ # Core scaffold
32
+ npx substrate-kit add design-canvas toolbar panel pane action slider
33
+
34
+ # Surface components
35
+ npx substrate-kit add surface timeline gallery colour-picker easing-curve-editor
36
+ \`\`\`
37
+
38
+ ## Registry
39
+
40
+ Components are installed from \`substrate.georgedrury.co.uk/r/\` via the shadcn CLI.
41
+ `;
42
+ }
43
+ function componentsJson() {
44
+ return JSON.stringify({
45
+ $schema: "https://ui.shadcn.com/schema.json",
46
+ style: "new-york",
47
+ rsc: true,
48
+ tsx: true,
49
+ tailwind: {
50
+ config: "",
51
+ css: "app/globals.css",
52
+ baseColor: "neutral",
53
+ cssVariables: true,
54
+ },
55
+ aliases: {
56
+ components: "@/components",
57
+ utils: "@/lib/utils",
58
+ ui: "@/components/ui",
59
+ lib: "@/lib",
60
+ hooks: "@/hooks",
61
+ },
62
+ }, null, 2);
63
+ }
64
+ export async function init(options = {}) {
65
+ const cwd = process.cwd();
66
+ const { force = false, skipComponentsJson = false } = options;
67
+ log.title("Initialising Substrate");
68
+ // 1. Copy skills
69
+ const skillsSource = resolveSkillsDir();
70
+ const skillsDest = join(cwd, ".claude", "skills");
71
+ const skillNames = listDirs(skillsSource);
72
+ if (skillNames.length === 0) {
73
+ log.error("No skills found in the bundled skills directory");
74
+ process.exit(1);
75
+ }
76
+ let copiedCount = 0;
77
+ let skippedCount = 0;
78
+ for (const skillName of skillNames) {
79
+ const dest = join(skillsDest, skillName);
80
+ if (exists(dest) && !force) {
81
+ skippedCount++;
82
+ continue;
83
+ }
84
+ copyDir(join(skillsSource, skillName), dest);
85
+ copiedCount++;
86
+ log.step(`Installed skill: ${skillName}`);
87
+ }
88
+ if (copiedCount > 0) {
89
+ log.success(`Installed ${copiedCount} skill${copiedCount === 1 ? "" : "s"}`);
90
+ }
91
+ if (skippedCount > 0) {
92
+ log.warn(`Skipped ${skippedCount} existing skill${skippedCount === 1 ? "" : "s"} (use --force to overwrite)`);
93
+ }
94
+ // 2. Generate CLAUDE.md
95
+ const claudeMdPath = join(cwd, "CLAUDE.md");
96
+ if (exists(claudeMdPath) && !force) {
97
+ log.warn("CLAUDE.md already exists (use --force to overwrite)");
98
+ }
99
+ else {
100
+ writeFile(claudeMdPath, claudeMd());
101
+ log.success("Created CLAUDE.md");
102
+ }
103
+ // 3. Write components.json
104
+ if (!skipComponentsJson) {
105
+ const componentsJsonPath = join(cwd, "components.json");
106
+ if (exists(componentsJsonPath) && !force) {
107
+ log.warn("components.json already exists (use --force to overwrite)");
108
+ }
109
+ else {
110
+ writeFile(componentsJsonPath, componentsJson());
111
+ log.success("Created components.json");
112
+ }
113
+ }
114
+ // 4. Write .mcp.json
115
+ const mcpJsonPath = join(cwd, ".mcp.json");
116
+ if (exists(mcpJsonPath) && !force) {
117
+ log.warn(".mcp.json already exists (use --force to overwrite)");
118
+ }
119
+ else {
120
+ const mcpConfig = {
121
+ mcpServers: {
122
+ substrate: {
123
+ command: "npx",
124
+ args: ["-y", "@substrate-kit/cli", "mcp"],
125
+ },
126
+ },
127
+ };
128
+ writeFile(mcpJsonPath, JSON.stringify(mcpConfig, null, 2) + "\n");
129
+ log.success("Created .mcp.json (Substrate MCP server registered)");
130
+ }
131
+ log.blank();
132
+ log.info("Substrate is ready. Claude can now use the skills for creative app development.");
133
+ }
134
+ //# sourceMappingURL=init.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"init.js","sourceRoot":"","sources":["../../src/commands/init.ts"],"names":[],"mappings":"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"}
@@ -0,0 +1,4 @@
1
+ export declare function variables(component: string | undefined, options: {
2
+ all?: boolean;
3
+ }): Promise<void>;
4
+ //# sourceMappingURL=variables.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"variables.d.ts","sourceRoot":"","sources":["../../src/commands/variables.ts"],"names":[],"mappings":"AAmEA,wBAAsB,SAAS,CAC9B,SAAS,EAAE,MAAM,GAAG,SAAS,EAC7B,OAAO,EAAE;IAAE,GAAG,CAAC,EAAE,OAAO,CAAA;CAAE,GACxB,OAAO,CAAC,IAAI,CAAC,CAuEf"}
@@ -0,0 +1,111 @@
1
+ import { readFileSync, existsSync } from "node:fs";
2
+ import { join, dirname } from "node:path";
3
+ import { fileURLToPath } from "node:url";
4
+ import { log } from "../utils/logger.js";
5
+ const __dirname = dirname(fileURLToPath(import.meta.url));
6
+ const REGISTRY_URL = "https://substrate.georgedrury.co.uk/registry.json";
7
+ async function loadRegistry() {
8
+ const localPath = join(process.cwd(), "registry.json");
9
+ if (existsSync(localPath)) {
10
+ try {
11
+ return JSON.parse(readFileSync(localPath, "utf-8"));
12
+ }
13
+ catch {
14
+ /* fall through */
15
+ }
16
+ }
17
+ try {
18
+ const res = await fetch(REGISTRY_URL);
19
+ if (res.ok)
20
+ return (await res.json());
21
+ }
22
+ catch {
23
+ /* fall through */
24
+ }
25
+ const bundledPaths = [
26
+ join(__dirname, "..", "..", "registry.json"),
27
+ join(__dirname, "..", "..", "..", "registry.json"),
28
+ ];
29
+ for (const p of bundledPaths) {
30
+ if (existsSync(p)) {
31
+ try {
32
+ return JSON.parse(readFileSync(p, "utf-8"));
33
+ }
34
+ catch {
35
+ /* fall through */
36
+ }
37
+ }
38
+ }
39
+ return null;
40
+ }
41
+ function extractOverrideKeys(item) {
42
+ const theme = item.cssVars?.theme;
43
+ if (!theme)
44
+ return [];
45
+ const keys = [];
46
+ for (const value of Object.values(theme)) {
47
+ const match = value.match(/^var\(--([^,)]+)/);
48
+ if (match)
49
+ keys.push(`--${match[1]}`);
50
+ }
51
+ return keys;
52
+ }
53
+ export async function variables(component, options) {
54
+ const registry = await loadRegistry();
55
+ if (!registry) {
56
+ log.error("Could not load the component registry");
57
+ process.exit(1);
58
+ }
59
+ if (options.all) {
60
+ const withVars = registry.items
61
+ .map((item) => ({ item, keys: extractOverrideKeys(item) }))
62
+ .filter(({ keys }) => keys.length > 0)
63
+ .sort((a, b) => a.item.name.localeCompare(b.item.name));
64
+ if (withVars.length === 0) {
65
+ log.info("No components have theme variables");
66
+ return;
67
+ }
68
+ log.blank();
69
+ log.info(`${withVars.length} components with theme variables:`);
70
+ log.blank();
71
+ for (const { item, keys } of withVars) {
72
+ console.log(` ${item.name}`);
73
+ for (const key of keys) {
74
+ console.log(` ${key}`);
75
+ }
76
+ console.log();
77
+ }
78
+ return;
79
+ }
80
+ if (!component) {
81
+ log.error("Provide a component name, e.g. substrate variables panel");
82
+ log.info("Use --all to list every component's variables");
83
+ process.exit(1);
84
+ }
85
+ const item = registry.items.find((i) => i.name.toLowerCase() === component.toLowerCase());
86
+ if (!item) {
87
+ log.error(`Component "${component}" not found`);
88
+ const query = component.toLowerCase();
89
+ const suggestions = registry.items
90
+ .filter((i) => i.name.toLowerCase().includes(query))
91
+ .slice(0, 5);
92
+ if (suggestions.length > 0) {
93
+ log.info("Did you mean:");
94
+ for (const s of suggestions) {
95
+ console.log(` ${s.name}`);
96
+ }
97
+ }
98
+ process.exit(1);
99
+ }
100
+ const keys = extractOverrideKeys(item);
101
+ if (keys.length === 0) {
102
+ log.info("No theme variables — this component uses base theme values only");
103
+ return;
104
+ }
105
+ log.blank();
106
+ for (const key of keys) {
107
+ console.log(` ${key}`);
108
+ }
109
+ log.blank();
110
+ }
111
+ //# sourceMappingURL=variables.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"variables.js","sourceRoot":"","sources":["../../src/commands/variables.ts"],"names":[],"mappings":"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"}
@@ -0,0 +1,3 @@
1
+ #!/usr/bin/env node
2
+ export {};
3
+ //# sourceMappingURL=index.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../src/index.ts"],"names":[],"mappings":""}
package/dist/index.js ADDED
@@ -0,0 +1,5 @@
1
+ #!/usr/bin/env node
2
+ import { createCli } from "./cli.js";
3
+ const program = createCli();
4
+ program.parse();
5
+ //# sourceMappingURL=index.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"index.js","sourceRoot":"","sources":["../src/index.ts"],"names":[],"mappings":";AAEA,OAAO,EAAE,SAAS,EAAE,MAAM,UAAU,CAAA;AAEpC,MAAM,OAAO,GAAG,SAAS,EAAE,CAAA;AAC3B,OAAO,CAAC,KAAK,EAAE,CAAA"}
@@ -0,0 +1,3 @@
1
+ import type { Registry } from "./types.js";
2
+ export declare function loadRegistry(): Promise<Registry>;
3
+ //# sourceMappingURL=registry.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"registry.d.ts","sourceRoot":"","sources":["../../src/mcp/registry.ts"],"names":[],"mappings":"AAGA,OAAO,KAAK,EAAE,QAAQ,EAAE,MAAM,YAAY,CAAA;AAK1C,wBAAsB,YAAY,IAAI,OAAO,CAAC,QAAQ,CAAC,CAmCtD"}
@@ -0,0 +1,43 @@
1
+ import { readFileSync, existsSync } from "node:fs";
2
+ import { join, dirname } from "node:path";
3
+ import { fileURLToPath } from "node:url";
4
+ const __dirname = dirname(fileURLToPath(import.meta.url));
5
+ const REGISTRY_URL = "https://substrate.georgedrury.co.uk/registry.json";
6
+ export async function loadRegistry() {
7
+ // Try local
8
+ const localPath = join(process.cwd(), "registry.json");
9
+ if (existsSync(localPath)) {
10
+ try {
11
+ return JSON.parse(readFileSync(localPath, "utf-8"));
12
+ }
13
+ catch {
14
+ /* fall through */
15
+ }
16
+ }
17
+ // Try remote
18
+ try {
19
+ const res = await fetch(REGISTRY_URL);
20
+ if (res.ok)
21
+ return (await res.json());
22
+ }
23
+ catch {
24
+ /* fall through */
25
+ }
26
+ // Try bundled
27
+ const bundledPaths = [
28
+ join(__dirname, "..", "..", "registry.json"),
29
+ join(__dirname, "..", "..", "..", "registry.json"),
30
+ ];
31
+ for (const p of bundledPaths) {
32
+ if (existsSync(p)) {
33
+ try {
34
+ return JSON.parse(readFileSync(p, "utf-8"));
35
+ }
36
+ catch {
37
+ /* fall through */
38
+ }
39
+ }
40
+ }
41
+ throw new Error("Could not load Substrate registry");
42
+ }
43
+ //# sourceMappingURL=registry.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"registry.js","sourceRoot":"","sources":["../../src/mcp/registry.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,YAAY,EAAE,UAAU,EAAE,MAAM,SAAS,CAAA;AAClD,OAAO,EAAE,IAAI,EAAE,OAAO,EAAE,MAAM,WAAW,CAAA;AACzC,OAAO,EAAE,aAAa,EAAE,MAAM,UAAU,CAAA;AAGxC,MAAM,SAAS,GAAG,OAAO,CAAC,aAAa,CAAC,MAAM,CAAC,IAAI,CAAC,GAAG,CAAC,CAAC,CAAA;AACzD,MAAM,YAAY,GAAG,mDAAmD,CAAA;AAExE,MAAM,CAAC,KAAK,UAAU,YAAY;IACjC,YAAY;IACZ,MAAM,SAAS,GAAG,IAAI,CAAC,OAAO,CAAC,GAAG,EAAE,EAAE,eAAe,CAAC,CAAA;IACtD,IAAI,UAAU,CAAC,SAAS,CAAC,EAAE,CAAC;QAC3B,IAAI,CAAC;YACJ,OAAO,IAAI,CAAC,KAAK,CAAC,YAAY,CAAC,SAAS,EAAE,OAAO,CAAC,CAAC,CAAA;QACpD,CAAC;QAAC,MAAM,CAAC;YACR,kBAAkB;QACnB,CAAC;IACF,CAAC;IAED,aAAa;IACb,IAAI,CAAC;QACJ,MAAM,GAAG,GAAG,MAAM,KAAK,CAAC,YAAY,CAAC,CAAA;QACrC,IAAI,GAAG,CAAC,EAAE;YAAE,OAAO,CAAC,MAAM,GAAG,CAAC,IAAI,EAAE,CAAa,CAAA;IAClD,CAAC;IAAC,MAAM,CAAC;QACR,kBAAkB;IACnB,CAAC;IAED,cAAc;IACd,MAAM,YAAY,GAAG;QACpB,IAAI,CAAC,SAAS,EAAE,IAAI,EAAE,IAAI,EAAE,eAAe,CAAC;QAC5C,IAAI,CAAC,SAAS,EAAE,IAAI,EAAE,IAAI,EAAE,IAAI,EAAE,eAAe,CAAC;KAClD,CAAA;IACD,KAAK,MAAM,CAAC,IAAI,YAAY,EAAE,CAAC;QAC9B,IAAI,UAAU,CAAC,CAAC,CAAC,EAAE,CAAC;YACnB,IAAI,CAAC;gBACJ,OAAO,IAAI,CAAC,KAAK,CAAC,YAAY,CAAC,CAAC,EAAE,OAAO,CAAC,CAAC,CAAA;YAC5C,CAAC;YAAC,MAAM,CAAC;gBACR,kBAAkB;YACnB,CAAC;QACF,CAAC;IACF,CAAC;IAED,MAAM,IAAI,KAAK,CAAC,mCAAmC,CAAC,CAAA;AACrD,CAAC"}
@@ -0,0 +1,3 @@
1
+ #!/usr/bin/env node
2
+ export declare function startServer(): Promise<void>;
3
+ //# sourceMappingURL=server.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"server.d.ts","sourceRoot":"","sources":["../../src/mcp/server.ts"],"names":[],"mappings":";AAWA,wBAAsB,WAAW,IAAI,OAAO,CAAC,IAAI,CAAC,CA+CjD"}
@@ -0,0 +1,39 @@
1
+ #!/usr/bin/env node
2
+ import { McpServer } from "@modelcontextprotocol/sdk/server/mcp.js";
3
+ import { StdioServerTransport } from "@modelcontextprotocol/sdk/server/stdio.js";
4
+ import { z } from "zod";
5
+ import { loadRegistry } from "./registry.js";
6
+ import { handleSearch } from "./tools/search.js";
7
+ import { handleGetComponent } from "./tools/get-component.js";
8
+ import { handleInstall } from "./tools/install.js";
9
+ import { handleGetThemeVariables } from "./tools/theme.js";
10
+ export async function startServer() {
11
+ const registry = await loadRegistry();
12
+ const server = new McpServer({
13
+ name: "substrate",
14
+ version: "0.1.0",
15
+ });
16
+ server.tool("search_components", "Search the Substrate component registry by keyword, category, or description. Returns matching components with name, description, and category.", {
17
+ query: z.string().optional().describe("Free-text search against component name, title, and description"),
18
+ category: z.string().optional().describe("Filter by category: substrate, ui, canvas, lib, store"),
19
+ }, async (args) => handleSearch(registry, args));
20
+ server.tool("get_component", "Get full details for a specific Substrate component including CSS variables, dependencies, usage example, and lineage.", {
21
+ name: z.string().describe("Component name (e.g. design-canvas, toolbar, panel)"),
22
+ }, async (args) => handleGetComponent(registry, args));
23
+ server.tool("install_components", "Install one or more Substrate components from substrate.georgedrury.co.uk into the current project. Runs shadcn add behind the scenes.", {
24
+ components: z.array(z.string()).describe("Component names to install (e.g. ['design-canvas', 'toolbar', 'panel'])"),
25
+ }, async (args) => handleInstall(registry, args));
26
+ server.tool("get_theme_variables", "Get the CSS variable map for Substrate components, showing the full fallback chain. Useful for building or customising themes.", {
27
+ components: z.array(z.string()).optional().describe("Component names to get variables for (omit for all)"),
28
+ }, async (args) => handleGetThemeVariables(registry, args));
29
+ const transport = new StdioServerTransport();
30
+ await server.connect(transport);
31
+ }
32
+ const isDirectRun = process.argv[1]?.includes("mcp/server");
33
+ if (isDirectRun) {
34
+ startServer().catch((err) => {
35
+ console.error("Failed to start Substrate MCP server:", err);
36
+ process.exit(1);
37
+ });
38
+ }
39
+ //# sourceMappingURL=server.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"server.js","sourceRoot":"","sources":["../../src/mcp/server.ts"],"names":[],"mappings":";AAEA,OAAO,EAAE,SAAS,EAAE,MAAM,yCAAyC,CAAA;AACnE,OAAO,EAAE,oBAAoB,EAAE,MAAM,2CAA2C,CAAA;AAChF,OAAO,EAAE,CAAC,EAAE,MAAM,KAAK,CAAA;AACvB,OAAO,EAAE,YAAY,EAAE,MAAM,eAAe,CAAA;AAC5C,OAAO,EAAE,YAAY,EAAE,MAAM,mBAAmB,CAAA;AAChD,OAAO,EAAE,kBAAkB,EAAE,MAAM,0BAA0B,CAAA;AAC7D,OAAO,EAAE,aAAa,EAAE,MAAM,oBAAoB,CAAA;AAClD,OAAO,EAAE,uBAAuB,EAAE,MAAM,kBAAkB,CAAA;AAE1D,MAAM,CAAC,KAAK,UAAU,WAAW;IAC/B,MAAM,QAAQ,GAAG,MAAM,YAAY,EAAE,CAAA;IAErC,MAAM,MAAM,GAAG,IAAI,SAAS,CAAC;QAC3B,IAAI,EAAE,WAAW;QACjB,OAAO,EAAE,OAAO;KACjB,CAAC,CAAA;IAEF,MAAM,CAAC,IAAI,CACT,mBAAmB,EACnB,iJAAiJ,EACjJ;QACE,KAAK,EAAE,CAAC,CAAC,MAAM,EAAE,CAAC,QAAQ,EAAE,CAAC,QAAQ,CAAC,iEAAiE,CAAC;QACxG,QAAQ,EAAE,CAAC,CAAC,MAAM,EAAE,CAAC,QAAQ,EAAE,CAAC,QAAQ,CAAC,uDAAuD,CAAC;KAClG,EACD,KAAK,EAAE,IAAI,EAAE,EAAE,CAAC,YAAY,CAAC,QAAQ,EAAE,IAA6C,CAAC,CACtF,CAAA;IAED,MAAM,CAAC,IAAI,CACT,eAAe,EACf,wHAAwH,EACxH;QACE,IAAI,EAAE,CAAC,CAAC,MAAM,EAAE,CAAC,QAAQ,CAAC,qDAAqD,CAAC;KACjF,EACD,KAAK,EAAE,IAAI,EAAE,EAAE,CAAC,kBAAkB,CAAC,QAAQ,EAAE,IAAwB,CAAC,CACvE,CAAA;IAED,MAAM,CAAC,IAAI,CACT,oBAAoB,EACpB,wIAAwI,EACxI;QACE,UAAU,EAAE,CAAC,CAAC,KAAK,CAAC,CAAC,CAAC,MAAM,EAAE,CAAC,CAAC,QAAQ,CAAC,yEAAyE,CAAC;KACpH,EACD,KAAK,EAAE,IAAI,EAAE,EAAE,CAAC,aAAa,CAAC,QAAQ,EAAE,IAAgC,CAAC,CAC1E,CAAA;IAED,MAAM,CAAC,IAAI,CACT,qBAAqB,EACrB,gIAAgI,EAChI;QACE,UAAU,EAAE,CAAC,CAAC,KAAK,CAAC,CAAC,CAAC,MAAM,EAAE,CAAC,CAAC,QAAQ,EAAE,CAAC,QAAQ,CAAC,qDAAqD,CAAC;KAC3G,EACD,KAAK,EAAE,IAAI,EAAE,EAAE,CAAC,uBAAuB,CAAC,QAAQ,EAAE,IAAiC,CAAC,CACrF,CAAA;IAED,MAAM,SAAS,GAAG,IAAI,oBAAoB,EAAE,CAAA;IAC5C,MAAM,MAAM,CAAC,OAAO,CAAC,SAAS,CAAC,CAAA;AACjC,CAAC;AAED,MAAM,WAAW,GAAG,OAAO,CAAC,IAAI,CAAC,CAAC,CAAC,EAAE,QAAQ,CAAC,YAAY,CAAC,CAAA;AAC3D,IAAI,WAAW,EAAE,CAAC;IAChB,WAAW,EAAE,CAAC,KAAK,CAAC,CAAC,GAAG,EAAE,EAAE;QAC1B,OAAO,CAAC,KAAK,CAAC,uCAAuC,EAAE,GAAG,CAAC,CAAA;QAC3D,OAAO,CAAC,IAAI,CAAC,CAAC,CAAC,CAAA;IACjB,CAAC,CAAC,CAAA;AACJ,CAAC"}
@@ -0,0 +1,17 @@
1
+ import type { Registry } from "../types.js";
2
+ export declare function handleGetComponent(registry: Registry, args: {
3
+ name: string;
4
+ }): Promise<{
5
+ content: {
6
+ type: "text";
7
+ text: string;
8
+ }[];
9
+ isError: boolean;
10
+ } | {
11
+ content: {
12
+ type: "text";
13
+ text: string;
14
+ }[];
15
+ isError?: undefined;
16
+ }>;
17
+ //# sourceMappingURL=get-component.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"get-component.d.ts","sourceRoot":"","sources":["../../../src/mcp/tools/get-component.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,QAAQ,EAAE,MAAM,aAAa,CAAA;AAE3C,wBAAsB,kBAAkB,CACtC,QAAQ,EAAE,QAAQ,EAClB,IAAI,EAAE;IAAE,IAAI,EAAE,MAAM,CAAA;CAAE;;;;;;;;;;;;GA0BvB"}
@@ -0,0 +1,23 @@
1
+ export async function handleGetComponent(registry, args) {
2
+ const item = registry.items.find((i) => i.name.toLowerCase() === args.name.toLowerCase());
3
+ if (!item) {
4
+ return {
5
+ content: [
6
+ {
7
+ type: "text",
8
+ text: `Component "${args.name}" not found. Available: ${registry.items.map((i) => i.name).join(", ")}`,
9
+ },
10
+ ],
11
+ isError: true,
12
+ };
13
+ }
14
+ return {
15
+ content: [
16
+ {
17
+ type: "text",
18
+ text: JSON.stringify(item, null, 2),
19
+ },
20
+ ],
21
+ };
22
+ }
23
+ //# sourceMappingURL=get-component.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"get-component.js","sourceRoot":"","sources":["../../../src/mcp/tools/get-component.ts"],"names":[],"mappings":"AAEA,MAAM,CAAC,KAAK,UAAU,kBAAkB,CACtC,QAAkB,EAClB,IAAsB;IAEtB,MAAM,IAAI,GAAG,QAAQ,CAAC,KAAK,CAAC,IAAI,CAC9B,CAAC,CAAC,EAAE,EAAE,CAAC,CAAC,CAAC,IAAI,CAAC,WAAW,EAAE,KAAK,IAAI,CAAC,IAAI,CAAC,WAAW,EAAE,CACxD,CAAA;IAED,IAAI,CAAC,IAAI,EAAE,CAAC;QACV,OAAO;YACL,OAAO,EAAE;gBACP;oBACE,IAAI,EAAE,MAAe;oBACrB,IAAI,EAAE,cAAc,IAAI,CAAC,IAAI,2BAA2B,QAAQ,CAAC,KAAK,CAAC,GAAG,CAAC,CAAC,CAAC,EAAE,EAAE,CAAC,CAAC,CAAC,IAAI,CAAC,CAAC,IAAI,CAAC,IAAI,CAAC,EAAE;iBACvG;aACF;YACD,OAAO,EAAE,IAAI;SACd,CAAA;IACH,CAAC;IAED,OAAO;QACL,OAAO,EAAE;YACP;gBACE,IAAI,EAAE,MAAe;gBACrB,IAAI,EAAE,IAAI,CAAC,SAAS,CAAC,IAAI,EAAE,IAAI,EAAE,CAAC,CAAC;aACpC;SACF;KACF,CAAA;AACH,CAAC"}
@@ -0,0 +1,10 @@
1
+ import type { Registry } from "../types.js";
2
+ export declare function handleInstall(registry: Registry, args: {
3
+ components: string[];
4
+ }): Promise<{
5
+ content: {
6
+ type: "text";
7
+ text: string;
8
+ }[];
9
+ }>;
10
+ //# sourceMappingURL=install.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"install.d.ts","sourceRoot":"","sources":["../../../src/mcp/tools/install.ts"],"names":[],"mappings":"AACA,OAAO,KAAK,EAAE,QAAQ,EAAE,MAAM,aAAa,CAAA;AAI3C,wBAAsB,aAAa,CAClC,QAAQ,EAAE,QAAQ,EAClB,IAAI,EAAE;IAAE,UAAU,EAAE,MAAM,EAAE,CAAA;CAAE;;;;;GAuC9B"}
@@ -0,0 +1,40 @@
1
+ import { execSync } from "node:child_process";
2
+ const REGISTRY_BASE = "https://substrate.georgedrury.co.uk/r";
3
+ export async function handleInstall(registry, args) {
4
+ const results = [];
5
+ for (const name of args.components) {
6
+ const item = registry.items.find((i) => i.name === name);
7
+ if (!item) {
8
+ results.push({
9
+ name,
10
+ status: "not_found",
11
+ error: `Component "${name}" not in registry`,
12
+ });
13
+ continue;
14
+ }
15
+ const url = `${REGISTRY_BASE}/${name}`;
16
+ try {
17
+ execSync(`npx shadcn@latest add ${url}`, {
18
+ encoding: "utf-8",
19
+ stdio: "pipe",
20
+ });
21
+ results.push({ name, status: "installed" });
22
+ }
23
+ catch (err) {
24
+ results.push({
25
+ name,
26
+ status: "failed",
27
+ error: err instanceof Error ? err.message : String(err),
28
+ });
29
+ }
30
+ }
31
+ return {
32
+ content: [
33
+ {
34
+ type: "text",
35
+ text: JSON.stringify(results, null, 2),
36
+ },
37
+ ],
38
+ };
39
+ }
40
+ //# sourceMappingURL=install.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"install.js","sourceRoot":"","sources":["../../../src/mcp/tools/install.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,QAAQ,EAAE,MAAM,oBAAoB,CAAA;AAG7C,MAAM,aAAa,GAAG,uCAAuC,CAAA;AAE7D,MAAM,CAAC,KAAK,UAAU,aAAa,CAClC,QAAkB,EAClB,IAA8B;IAE9B,MAAM,OAAO,GAA4D,EAAE,CAAA;IAE3E,KAAK,MAAM,IAAI,IAAI,IAAI,CAAC,UAAU,EAAE,CAAC;QACpC,MAAM,IAAI,GAAG,QAAQ,CAAC,KAAK,CAAC,IAAI,CAAC,CAAC,CAAC,EAAE,EAAE,CAAC,CAAC,CAAC,IAAI,KAAK,IAAI,CAAC,CAAA;QACxD,IAAI,CAAC,IAAI,EAAE,CAAC;YACX,OAAO,CAAC,IAAI,CAAC;gBACZ,IAAI;gBACJ,MAAM,EAAE,WAAW;gBACnB,KAAK,EAAE,cAAc,IAAI,mBAAmB;aAC5C,CAAC,CAAA;YACF,SAAQ;QACT,CAAC;QAED,MAAM,GAAG,GAAG,GAAG,aAAa,IAAI,IAAI,EAAE,CAAA;QACtC,IAAI,CAAC;YACJ,QAAQ,CAAC,yBAAyB,GAAG,EAAE,EAAE;gBACxC,QAAQ,EAAE,OAAO;gBACjB,KAAK,EAAE,MAAM;aACb,CAAC,CAAA;YACF,OAAO,CAAC,IAAI,CAAC,EAAE,IAAI,EAAE,MAAM,EAAE,WAAW,EAAE,CAAC,CAAA;QAC5C,CAAC;QAAC,OAAO,GAAG,EAAE,CAAC;YACd,OAAO,CAAC,IAAI,CAAC;gBACZ,IAAI;gBACJ,MAAM,EAAE,QAAQ;gBAChB,KAAK,EAAE,GAAG,YAAY,KAAK,CAAC,CAAC,CAAC,GAAG,CAAC,OAAO,CAAC,CAAC,CAAC,MAAM,CAAC,GAAG,CAAC;aACvD,CAAC,CAAA;QACH,CAAC;IACF,CAAC;IAED,OAAO;QACN,OAAO,EAAE;YACR;gBACC,IAAI,EAAE,MAAe;gBACrB,IAAI,EAAE,IAAI,CAAC,SAAS,CAAC,OAAO,EAAE,IAAI,EAAE,CAAC,CAAC;aACtC;SACD;KACD,CAAA;AACF,CAAC"}
@@ -0,0 +1,11 @@
1
+ import type { Registry } from "../types.js";
2
+ export declare function handleSearch(registry: Registry, args: {
3
+ query?: string;
4
+ category?: string;
5
+ }): Promise<{
6
+ content: {
7
+ type: "text";
8
+ text: string;
9
+ }[];
10
+ }>;
11
+ //# sourceMappingURL=search.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"search.d.ts","sourceRoot":"","sources":["../../../src/mcp/tools/search.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,QAAQ,EAAE,MAAM,aAAa,CAAA;AAE3C,wBAAsB,YAAY,CAChC,QAAQ,EAAE,QAAQ,EAClB,IAAI,EAAE;IAAE,KAAK,CAAC,EAAE,MAAM,CAAC;IAAC,QAAQ,CAAC,EAAE,MAAM,CAAA;CAAE;;;;;GAsC5C"}
@@ -0,0 +1,30 @@
1
+ export async function handleSearch(registry, args) {
2
+ let items = registry.items;
3
+ if (args.category) {
4
+ const cat = args.category.toLowerCase();
5
+ items = items.filter((i) => (i.categories || []).some((c) => c.toLowerCase() === cat));
6
+ }
7
+ if (args.query) {
8
+ const q = args.query.toLowerCase();
9
+ items = items.filter((i) => i.name.includes(q) ||
10
+ (i.title || "").toLowerCase().includes(q) ||
11
+ (i.description || "").toLowerCase().includes(q) ||
12
+ (i.categories || []).some((c) => c.toLowerCase().includes(q)));
13
+ }
14
+ const results = items.map((i) => ({
15
+ name: i.name,
16
+ title: i.title,
17
+ description: i.description,
18
+ categories: i.categories,
19
+ install: `substrate add ${i.name}`,
20
+ }));
21
+ return {
22
+ content: [
23
+ {
24
+ type: "text",
25
+ text: JSON.stringify(results, null, 2),
26
+ },
27
+ ],
28
+ };
29
+ }
30
+ //# sourceMappingURL=search.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"search.js","sourceRoot":"","sources":["../../../src/mcp/tools/search.ts"],"names":[],"mappings":"AAEA,MAAM,CAAC,KAAK,UAAU,YAAY,CAChC,QAAkB,EAClB,IAA2C;IAE3C,IAAI,KAAK,GAAG,QAAQ,CAAC,KAAK,CAAA;IAE1B,IAAI,IAAI,CAAC,QAAQ,EAAE,CAAC;QAClB,MAAM,GAAG,GAAG,IAAI,CAAC,QAAQ,CAAC,WAAW,EAAE,CAAA;QACvC,KAAK,GAAG,KAAK,CAAC,MAAM,CAAC,CAAC,CAAC,EAAE,EAAE,CACzB,CAAC,CAAC,CAAC,UAAU,IAAI,EAAE,CAAC,CAAC,IAAI,CAAC,CAAC,CAAC,EAAE,EAAE,CAAC,CAAC,CAAC,WAAW,EAAE,KAAK,GAAG,CAAC,CAC1D,CAAA;IACH,CAAC;IAED,IAAI,IAAI,CAAC,KAAK,EAAE,CAAC;QACf,MAAM,CAAC,GAAG,IAAI,CAAC,KAAK,CAAC,WAAW,EAAE,CAAA;QAClC,KAAK,GAAG,KAAK,CAAC,MAAM,CAClB,CAAC,CAAC,EAAE,EAAE,CACJ,CAAC,CAAC,IAAI,CAAC,QAAQ,CAAC,CAAC,CAAC;YAClB,CAAC,CAAC,CAAC,KAAK,IAAI,EAAE,CAAC,CAAC,WAAW,EAAE,CAAC,QAAQ,CAAC,CAAC,CAAC;YACzC,CAAC,CAAC,CAAC,WAAW,IAAI,EAAE,CAAC,CAAC,WAAW,EAAE,CAAC,QAAQ,CAAC,CAAC,CAAC;YAC/C,CAAC,CAAC,CAAC,UAAU,IAAI,EAAE,CAAC,CAAC,IAAI,CAAC,CAAC,CAAC,EAAE,EAAE,CAAC,CAAC,CAAC,WAAW,EAAE,CAAC,QAAQ,CAAC,CAAC,CAAC,CAAC,CAChE,CAAA;IACH,CAAC;IAED,MAAM,OAAO,GAAG,KAAK,CAAC,GAAG,CAAC,CAAC,CAAC,EAAE,EAAE,CAAC,CAAC;QAChC,IAAI,EAAE,CAAC,CAAC,IAAI;QACZ,KAAK,EAAE,CAAC,CAAC,KAAK;QACd,WAAW,EAAE,CAAC,CAAC,WAAW;QAC1B,UAAU,EAAE,CAAC,CAAC,UAAU;QACxB,OAAO,EAAE,iBAAiB,CAAC,CAAC,IAAI,EAAE;KACnC,CAAC,CAAC,CAAA;IAEH,OAAO;QACL,OAAO,EAAE;YACP;gBACE,IAAI,EAAE,MAAe;gBACrB,IAAI,EAAE,IAAI,CAAC,SAAS,CAAC,OAAO,EAAE,IAAI,EAAE,CAAC,CAAC;aACvC;SACF;KACF,CAAA;AACH,CAAC"}
@@ -0,0 +1,10 @@
1
+ import type { Registry } from "../types.js";
2
+ export declare function handleGetThemeVariables(registry: Registry, args: {
3
+ components?: string[];
4
+ }): Promise<{
5
+ content: {
6
+ type: "text";
7
+ text: string;
8
+ }[];
9
+ }>;
10
+ //# sourceMappingURL=theme.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"theme.d.ts","sourceRoot":"","sources":["../../../src/mcp/tools/theme.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,QAAQ,EAAgB,MAAM,aAAa,CAAA;AAazD,wBAAsB,uBAAuB,CAC3C,QAAQ,EAAE,QAAQ,EAClB,IAAI,EAAE;IAAE,UAAU,CAAC,EAAE,MAAM,EAAE,CAAA;CAAE;;;;;GA2BhC"}
@@ -0,0 +1,37 @@
1
+ function extractOverrideKeys(item) {
2
+ const theme = item.cssVars?.theme;
3
+ if (!theme)
4
+ return [];
5
+ const keys = [];
6
+ for (const value of Object.values(theme)) {
7
+ const match = value.match(/^var\(--([^,)]+)/);
8
+ if (match)
9
+ keys.push(`--${match[1]}`);
10
+ }
11
+ return keys;
12
+ }
13
+ export async function handleGetThemeVariables(registry, args) {
14
+ let items = registry.items;
15
+ if (args.components && args.components.length > 0) {
16
+ const names = new Set(args.components.map((n) => n.toLowerCase()));
17
+ items = items.filter((i) => names.has(i.name.toLowerCase()));
18
+ }
19
+ const result = {};
20
+ for (const item of items) {
21
+ if (!item.cssVars)
22
+ continue;
23
+ result[item.name] = {
24
+ cssVars: item.cssVars,
25
+ overrideKeys: extractOverrideKeys(item),
26
+ };
27
+ }
28
+ return {
29
+ content: [
30
+ {
31
+ type: "text",
32
+ text: JSON.stringify(result, null, 2),
33
+ },
34
+ ],
35
+ };
36
+ }
37
+ //# sourceMappingURL=theme.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"theme.js","sourceRoot":"","sources":["../../../src/mcp/tools/theme.ts"],"names":[],"mappings":"AAEA,SAAS,mBAAmB,CAAC,IAAkB;IAC7C,MAAM,KAAK,GAAG,IAAI,CAAC,OAAO,EAAE,KAAK,CAAA;IACjC,IAAI,CAAC,KAAK;QAAE,OAAO,EAAE,CAAA;IACrB,MAAM,IAAI,GAAa,EAAE,CAAA;IACzB,KAAK,MAAM,KAAK,IAAI,MAAM,CAAC,MAAM,CAAC,KAAK,CAAC,EAAE,CAAC;QACzC,MAAM,KAAK,GAAG,KAAK,CAAC,KAAK,CAAC,kBAAkB,CAAC,CAAA;QAC7C,IAAI,KAAK;YAAE,IAAI,CAAC,IAAI,CAAC,KAAK,KAAK,CAAC,CAAC,CAAC,EAAE,CAAC,CAAA;IACvC,CAAC;IACD,OAAO,IAAI,CAAA;AACb,CAAC;AAED,MAAM,CAAC,KAAK,UAAU,uBAAuB,CAC3C,QAAkB,EAClB,IAA+B;IAE/B,IAAI,KAAK,GAAG,QAAQ,CAAC,KAAK,CAAA;IAE1B,IAAI,IAAI,CAAC,UAAU,IAAI,IAAI,CAAC,UAAU,CAAC,MAAM,GAAG,CAAC,EAAE,CAAC;QAClD,MAAM,KAAK,GAAG,IAAI,GAAG,CAAC,IAAI,CAAC,UAAU,CAAC,GAAG,CAAC,CAAC,CAAC,EAAE,EAAE,CAAC,CAAC,CAAC,WAAW,EAAE,CAAC,CAAC,CAAA;QAClE,KAAK,GAAG,KAAK,CAAC,MAAM,CAAC,CAAC,CAAC,EAAE,EAAE,CAAC,KAAK,CAAC,GAAG,CAAC,CAAC,CAAC,IAAI,CAAC,WAAW,EAAE,CAAC,CAAC,CAAA;IAC9D,CAAC;IAED,MAAM,MAAM,GAAoF,EAAE,CAAA;IAElG,KAAK,MAAM,IAAI,IAAI,KAAK,EAAE,CAAC;QACzB,IAAI,CAAC,IAAI,CAAC,OAAO;YAAE,SAAQ;QAC3B,MAAM,CAAC,IAAI,CAAC,IAAI,CAAC,GAAG;YAClB,OAAO,EAAE,IAAI,CAAC,OAAO;YACrB,YAAY,EAAE,mBAAmB,CAAC,IAAI,CAAC;SACxC,CAAA;IACH,CAAC;IAED,OAAO;QACL,OAAO,EAAE;YACP;gBACE,IAAI,EAAE,MAAe;gBACrB,IAAI,EAAE,IAAI,CAAC,SAAS,CAAC,MAAM,EAAE,IAAI,EAAE,CAAC,CAAC;aACtC;SACF;KACF,CAAA;AACH,CAAC"}