@genart-dev/mcp-server 0.1.2 → 0.2.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/index.cjs +387 -23
- package/dist/index.cjs.map +1 -1
- package/dist/index.js +383 -14
- package/dist/index.js.map +1 -1
- package/dist/lib.cjs +398 -34
- package/dist/lib.cjs.map +1 -1
- package/dist/lib.js +388 -19
- package/dist/lib.js.map +1 -1
- package/package.json +10 -9
package/dist/index.cjs
CHANGED
|
@@ -657,10 +657,40 @@ async function createSketch(state, input) {
|
|
|
657
657
|
const adapter = registry4.resolve(rendererType);
|
|
658
658
|
algorithm = adapter.getAlgorithmTemplate();
|
|
659
659
|
}
|
|
660
|
+
let resolvedComponents;
|
|
661
|
+
if (input.components && Object.keys(input.components).length > 0) {
|
|
662
|
+
const shorthand = {};
|
|
663
|
+
for (const [name, value] of Object.entries(input.components)) {
|
|
664
|
+
if (typeof value === "string") {
|
|
665
|
+
shorthand[name] = value;
|
|
666
|
+
} else if (value.version) {
|
|
667
|
+
shorthand[name] = value.version;
|
|
668
|
+
} else if (value.code) {
|
|
669
|
+
if (!resolvedComponents) resolvedComponents = {};
|
|
670
|
+
resolvedComponents[name] = {
|
|
671
|
+
...value.version ? { version: value.version } : {},
|
|
672
|
+
code: value.code,
|
|
673
|
+
...value.exports ? { exports: value.exports } : {}
|
|
674
|
+
};
|
|
675
|
+
}
|
|
676
|
+
}
|
|
677
|
+
if (Object.keys(shorthand).length > 0) {
|
|
678
|
+
const resolved = (0, import_core3.resolveComponents)(shorthand, rendererType);
|
|
679
|
+
if (!resolvedComponents) resolvedComponents = {};
|
|
680
|
+
for (const rc of resolved) {
|
|
681
|
+
resolvedComponents[rc.name] = {
|
|
682
|
+
version: rc.version,
|
|
683
|
+
code: rc.code,
|
|
684
|
+
exports: [...rc.exports]
|
|
685
|
+
};
|
|
686
|
+
}
|
|
687
|
+
}
|
|
688
|
+
}
|
|
660
689
|
const seed = input.seed ?? Math.floor(Math.random() * 1e5);
|
|
661
690
|
const ts = now2();
|
|
691
|
+
const hasComponents = resolvedComponents && Object.keys(resolvedComponents).length > 0;
|
|
662
692
|
const sketch = {
|
|
663
|
-
genart: "1.1",
|
|
693
|
+
genart: hasComponents ? "1.2" : "1.1",
|
|
664
694
|
id: input.id,
|
|
665
695
|
title: input.title,
|
|
666
696
|
created: ts,
|
|
@@ -674,6 +704,7 @@ async function createSketch(state, input) {
|
|
|
674
704
|
...input.philosophy ? { philosophy: input.philosophy } : {},
|
|
675
705
|
...input.themes && input.themes.length > 0 ? { themes: input.themes } : {},
|
|
676
706
|
...input.skills && input.skills.length > 0 ? { skills: input.skills } : {},
|
|
707
|
+
...hasComponents ? { components: resolvedComponents } : {},
|
|
677
708
|
...input.agent ? { agent: input.agent } : {},
|
|
678
709
|
...input.model ? { model: input.model } : {}
|
|
679
710
|
};
|
|
@@ -857,10 +888,44 @@ async function updateAlgorithm(state, input) {
|
|
|
857
888
|
);
|
|
858
889
|
}
|
|
859
890
|
}
|
|
891
|
+
let resolvedComponents;
|
|
892
|
+
if (input.components && Object.keys(input.components).length > 0) {
|
|
893
|
+
const renderer = def.renderer.type;
|
|
894
|
+
const shorthand = {};
|
|
895
|
+
for (const [name, value] of Object.entries(input.components)) {
|
|
896
|
+
if (typeof value === "string") {
|
|
897
|
+
shorthand[name] = value;
|
|
898
|
+
} else if (value.version) {
|
|
899
|
+
shorthand[name] = value.version;
|
|
900
|
+
} else if (value.code) {
|
|
901
|
+
if (!resolvedComponents) resolvedComponents = {};
|
|
902
|
+
resolvedComponents[name] = {
|
|
903
|
+
...value.version ? { version: value.version } : {},
|
|
904
|
+
code: value.code,
|
|
905
|
+
...value.exports ? { exports: value.exports } : {}
|
|
906
|
+
};
|
|
907
|
+
}
|
|
908
|
+
}
|
|
909
|
+
if (Object.keys(shorthand).length > 0) {
|
|
910
|
+
const resolved = (0, import_core3.resolveComponents)(shorthand, renderer);
|
|
911
|
+
if (!resolvedComponents) resolvedComponents = {};
|
|
912
|
+
for (const rc of resolved) {
|
|
913
|
+
resolvedComponents[rc.name] = {
|
|
914
|
+
version: rc.version,
|
|
915
|
+
code: rc.code,
|
|
916
|
+
exports: [...rc.exports]
|
|
917
|
+
};
|
|
918
|
+
}
|
|
919
|
+
}
|
|
920
|
+
}
|
|
921
|
+
const updated = ["algorithm"];
|
|
922
|
+
const hasNewComponents = resolvedComponents && Object.keys(resolvedComponents).length > 0;
|
|
923
|
+
if (hasNewComponents) updated.push("components");
|
|
860
924
|
const newDef = {
|
|
861
925
|
...def,
|
|
862
926
|
modified: now2(),
|
|
863
927
|
algorithm: input.algorithm,
|
|
928
|
+
...hasNewComponents ? { genart: "1.2", components: resolvedComponents } : {},
|
|
864
929
|
...input.agent ? { agent: input.agent } : {},
|
|
865
930
|
...input.model ? { model: input.model } : {}
|
|
866
931
|
};
|
|
@@ -874,7 +939,7 @@ async function updateAlgorithm(state, input) {
|
|
|
874
939
|
}
|
|
875
940
|
state.emitMutation("sketch:updated", {
|
|
876
941
|
id: input.sketchId,
|
|
877
|
-
updated
|
|
942
|
+
updated
|
|
878
943
|
});
|
|
879
944
|
return {
|
|
880
945
|
success: true,
|
|
@@ -882,6 +947,7 @@ async function updateAlgorithm(state, input) {
|
|
|
882
947
|
renderer: def.renderer.type,
|
|
883
948
|
algorithmLength: input.algorithm.length,
|
|
884
949
|
validationPassed,
|
|
950
|
+
...hasNewComponents ? { componentsUpdated: true } : {},
|
|
885
951
|
fileContent: json
|
|
886
952
|
};
|
|
887
953
|
}
|
|
@@ -2179,9 +2245,216 @@ ${guidelines}`,
|
|
|
2179
2245
|
};
|
|
2180
2246
|
}
|
|
2181
2247
|
|
|
2182
|
-
// src/tools/
|
|
2248
|
+
// src/tools/components.ts
|
|
2183
2249
|
var import_promises7 = require("fs/promises");
|
|
2184
2250
|
var import_core8 = require("@genart-dev/core");
|
|
2251
|
+
var VALID_RENDERERS2 = [
|
|
2252
|
+
"p5",
|
|
2253
|
+
"three",
|
|
2254
|
+
"glsl",
|
|
2255
|
+
"canvas2d",
|
|
2256
|
+
"svg"
|
|
2257
|
+
];
|
|
2258
|
+
var RENDERER_TARGET = {
|
|
2259
|
+
p5: "js",
|
|
2260
|
+
three: "js",
|
|
2261
|
+
canvas2d: "js",
|
|
2262
|
+
svg: "js",
|
|
2263
|
+
glsl: "glsl"
|
|
2264
|
+
};
|
|
2265
|
+
async function listComponents(_state, input) {
|
|
2266
|
+
let entries = Object.values(import_core8.COMPONENT_REGISTRY);
|
|
2267
|
+
if (input.renderer) {
|
|
2268
|
+
const renderer = input.renderer;
|
|
2269
|
+
const target = RENDERER_TARGET[renderer];
|
|
2270
|
+
if (!target) {
|
|
2271
|
+
throw new Error(
|
|
2272
|
+
`Unknown renderer type: '${input.renderer}'. Valid types: ${VALID_RENDERERS2.join(", ")}`
|
|
2273
|
+
);
|
|
2274
|
+
}
|
|
2275
|
+
entries = entries.filter(
|
|
2276
|
+
(e) => e.target === target && (e.renderers.length === 0 || e.renderers.includes(renderer))
|
|
2277
|
+
);
|
|
2278
|
+
}
|
|
2279
|
+
if (input.category) {
|
|
2280
|
+
const cat = input.category;
|
|
2281
|
+
entries = entries.filter((e) => e.category === cat);
|
|
2282
|
+
}
|
|
2283
|
+
entries.sort((a, b) => {
|
|
2284
|
+
const catCmp = a.category.localeCompare(b.category);
|
|
2285
|
+
if (catCmp !== 0) return catCmp;
|
|
2286
|
+
return a.name.localeCompare(b.name);
|
|
2287
|
+
});
|
|
2288
|
+
const components = entries.map((e) => ({
|
|
2289
|
+
name: e.name,
|
|
2290
|
+
version: e.version,
|
|
2291
|
+
category: e.category,
|
|
2292
|
+
target: e.target,
|
|
2293
|
+
exports: [...e.exports],
|
|
2294
|
+
dependencies: [...e.dependencies],
|
|
2295
|
+
description: e.description
|
|
2296
|
+
}));
|
|
2297
|
+
return {
|
|
2298
|
+
count: components.length,
|
|
2299
|
+
components
|
|
2300
|
+
};
|
|
2301
|
+
}
|
|
2302
|
+
async function addComponent(state, input) {
|
|
2303
|
+
const loaded = state.requireSketch(input.sketchId);
|
|
2304
|
+
const def = loaded.definition;
|
|
2305
|
+
const renderer = def.renderer.type;
|
|
2306
|
+
const entry = import_core8.COMPONENT_REGISTRY[input.component];
|
|
2307
|
+
if (!entry) {
|
|
2308
|
+
throw new Error(`Unknown component: "${input.component}"`);
|
|
2309
|
+
}
|
|
2310
|
+
const target = RENDERER_TARGET[renderer];
|
|
2311
|
+
if (entry.target !== target) {
|
|
2312
|
+
throw new Error(
|
|
2313
|
+
`Component "${input.component}" has target "${entry.target}" but renderer "${renderer}" requires target "${target}"`
|
|
2314
|
+
);
|
|
2315
|
+
}
|
|
2316
|
+
if (entry.renderers.length > 0 && !entry.renderers.includes(renderer)) {
|
|
2317
|
+
throw new Error(
|
|
2318
|
+
`Component "${input.component}" is not compatible with renderer "${renderer}". Compatible: ${entry.renderers.join(", ")}`
|
|
2319
|
+
);
|
|
2320
|
+
}
|
|
2321
|
+
const existingComponents = {};
|
|
2322
|
+
if (def.components) {
|
|
2323
|
+
for (const [name, value] of Object.entries(def.components)) {
|
|
2324
|
+
if (typeof value === "string") {
|
|
2325
|
+
existingComponents[name] = value;
|
|
2326
|
+
} else if (value.version) {
|
|
2327
|
+
existingComponents[name] = value.version;
|
|
2328
|
+
}
|
|
2329
|
+
}
|
|
2330
|
+
}
|
|
2331
|
+
if (existingComponents[input.component]) {
|
|
2332
|
+
throw new Error(
|
|
2333
|
+
`Component "${input.component}" is already present in sketch "${input.sketchId}"`
|
|
2334
|
+
);
|
|
2335
|
+
}
|
|
2336
|
+
existingComponents[input.component] = input.version ?? "^1.0.0";
|
|
2337
|
+
const resolved = (0, import_core8.resolveComponents)(existingComponents, renderer);
|
|
2338
|
+
const resolvedRecord = {};
|
|
2339
|
+
for (const rc of resolved) {
|
|
2340
|
+
resolvedRecord[rc.name] = {
|
|
2341
|
+
version: rc.version,
|
|
2342
|
+
code: rc.code,
|
|
2343
|
+
exports: [...rc.exports]
|
|
2344
|
+
};
|
|
2345
|
+
}
|
|
2346
|
+
const previousNames = new Set(
|
|
2347
|
+
def.components ? Object.keys(def.components) : []
|
|
2348
|
+
);
|
|
2349
|
+
const added = resolved.map((rc) => rc.name).filter((name) => !previousNames.has(name));
|
|
2350
|
+
const newDef = {
|
|
2351
|
+
...def,
|
|
2352
|
+
genart: "1.2",
|
|
2353
|
+
modified: (/* @__PURE__ */ new Date()).toISOString(),
|
|
2354
|
+
components: resolvedRecord
|
|
2355
|
+
};
|
|
2356
|
+
state.sketches.set(input.sketchId, {
|
|
2357
|
+
definition: newDef,
|
|
2358
|
+
path: loaded.path
|
|
2359
|
+
});
|
|
2360
|
+
const json = (0, import_core8.serializeGenart)(newDef);
|
|
2361
|
+
if (!state.remoteMode) {
|
|
2362
|
+
await (0, import_promises7.writeFile)(loaded.path, json, "utf-8");
|
|
2363
|
+
}
|
|
2364
|
+
state.emitMutation("sketch:updated", {
|
|
2365
|
+
id: input.sketchId,
|
|
2366
|
+
updated: ["components"]
|
|
2367
|
+
});
|
|
2368
|
+
return {
|
|
2369
|
+
success: true,
|
|
2370
|
+
sketchId: input.sketchId,
|
|
2371
|
+
components: resolvedRecord,
|
|
2372
|
+
added,
|
|
2373
|
+
fileContent: json
|
|
2374
|
+
};
|
|
2375
|
+
}
|
|
2376
|
+
async function removeComponent(state, input) {
|
|
2377
|
+
const loaded = state.requireSketch(input.sketchId);
|
|
2378
|
+
const def = loaded.definition;
|
|
2379
|
+
if (!def.components || !def.components[input.component]) {
|
|
2380
|
+
throw new Error(
|
|
2381
|
+
`Component "${input.component}" is not present in sketch "${input.sketchId}"`
|
|
2382
|
+
);
|
|
2383
|
+
}
|
|
2384
|
+
const remaining = { ...def.components };
|
|
2385
|
+
delete remaining[input.component];
|
|
2386
|
+
for (const [name, value] of Object.entries(remaining)) {
|
|
2387
|
+
const entry = import_core8.COMPONENT_REGISTRY[name];
|
|
2388
|
+
if (entry && entry.dependencies.includes(input.component)) {
|
|
2389
|
+
throw new Error(
|
|
2390
|
+
`Cannot remove "${input.component}": component "${name}" depends on it`
|
|
2391
|
+
);
|
|
2392
|
+
}
|
|
2393
|
+
}
|
|
2394
|
+
let warning;
|
|
2395
|
+
const removedValue = def.components[input.component];
|
|
2396
|
+
const exports2 = typeof removedValue === "string" ? import_core8.COMPONENT_REGISTRY[input.component]?.exports ?? [] : removedValue.exports ?? [];
|
|
2397
|
+
const usedExports = exports2.filter((exp) => def.algorithm.includes(exp));
|
|
2398
|
+
if (usedExports.length > 0) {
|
|
2399
|
+
warning = `Algorithm may reference these exports from "${input.component}": ${usedExports.join(", ")}. Review your algorithm after removal.`;
|
|
2400
|
+
}
|
|
2401
|
+
const removed = [input.component];
|
|
2402
|
+
const neededDeps = /* @__PURE__ */ new Set();
|
|
2403
|
+
for (const name of Object.keys(remaining)) {
|
|
2404
|
+
const entry = import_core8.COMPONENT_REGISTRY[name];
|
|
2405
|
+
if (entry) {
|
|
2406
|
+
collectTransitiveDeps(name, neededDeps);
|
|
2407
|
+
}
|
|
2408
|
+
}
|
|
2409
|
+
for (const name of Object.keys(remaining)) {
|
|
2410
|
+
if (!neededDeps.has(name) && !isDirectComponent(name, remaining)) {
|
|
2411
|
+
delete remaining[name];
|
|
2412
|
+
removed.push(name);
|
|
2413
|
+
}
|
|
2414
|
+
}
|
|
2415
|
+
const hasRemaining = Object.keys(remaining).length > 0;
|
|
2416
|
+
const newDef = {
|
|
2417
|
+
...def,
|
|
2418
|
+
modified: (/* @__PURE__ */ new Date()).toISOString(),
|
|
2419
|
+
...hasRemaining ? { components: remaining } : { components: void 0 }
|
|
2420
|
+
};
|
|
2421
|
+
state.sketches.set(input.sketchId, {
|
|
2422
|
+
definition: newDef,
|
|
2423
|
+
path: loaded.path
|
|
2424
|
+
});
|
|
2425
|
+
const json = (0, import_core8.serializeGenart)(newDef);
|
|
2426
|
+
if (!state.remoteMode) {
|
|
2427
|
+
await (0, import_promises7.writeFile)(loaded.path, json, "utf-8");
|
|
2428
|
+
}
|
|
2429
|
+
state.emitMutation("sketch:updated", {
|
|
2430
|
+
id: input.sketchId,
|
|
2431
|
+
updated: ["components"]
|
|
2432
|
+
});
|
|
2433
|
+
return {
|
|
2434
|
+
success: true,
|
|
2435
|
+
sketchId: input.sketchId,
|
|
2436
|
+
removed,
|
|
2437
|
+
...warning ? { warning } : {},
|
|
2438
|
+
fileContent: json
|
|
2439
|
+
};
|
|
2440
|
+
}
|
|
2441
|
+
function collectTransitiveDeps(name, deps) {
|
|
2442
|
+
const entry = import_core8.COMPONENT_REGISTRY[name];
|
|
2443
|
+
if (!entry) return;
|
|
2444
|
+
deps.add(name);
|
|
2445
|
+
for (const dep of entry.dependencies) {
|
|
2446
|
+
if (!deps.has(dep)) {
|
|
2447
|
+
collectTransitiveDeps(dep, deps);
|
|
2448
|
+
}
|
|
2449
|
+
}
|
|
2450
|
+
}
|
|
2451
|
+
function isDirectComponent(name, components) {
|
|
2452
|
+
return name in components;
|
|
2453
|
+
}
|
|
2454
|
+
|
|
2455
|
+
// src/tools/capture.ts
|
|
2456
|
+
var import_promises8 = require("fs/promises");
|
|
2457
|
+
var import_core9 = require("@genart-dev/core");
|
|
2185
2458
|
|
|
2186
2459
|
// src/capture/headless.ts
|
|
2187
2460
|
var cachedModule = null;
|
|
@@ -2275,7 +2548,7 @@ async function captureHtmlMulti(options) {
|
|
|
2275
2548
|
}
|
|
2276
2549
|
|
|
2277
2550
|
// src/tools/capture.ts
|
|
2278
|
-
var registry2 = (0,
|
|
2551
|
+
var registry2 = (0, import_core9.createDefaultRegistry)();
|
|
2279
2552
|
function applyOverrides(sketch, overrides) {
|
|
2280
2553
|
if (overrides.seed === void 0 && overrides.params === void 0) {
|
|
2281
2554
|
return sketch;
|
|
@@ -2356,7 +2629,7 @@ async function buildScreenshotMetadata(state, multi, info) {
|
|
|
2356
2629
|
previewPath: info.previewPath
|
|
2357
2630
|
};
|
|
2358
2631
|
if (!state.remoteMode) {
|
|
2359
|
-
await (0,
|
|
2632
|
+
await (0, import_promises8.writeFile)(info.previewPath, multi.previewPng);
|
|
2360
2633
|
metadata.savedPreviewTo = info.previewPath;
|
|
2361
2634
|
}
|
|
2362
2635
|
return metadata;
|
|
@@ -2417,15 +2690,15 @@ async function captureBatch(state, input) {
|
|
|
2417
2690
|
|
|
2418
2691
|
// src/tools/export.ts
|
|
2419
2692
|
var import_fs = require("fs");
|
|
2420
|
-
var
|
|
2693
|
+
var import_promises9 = require("fs/promises");
|
|
2421
2694
|
var import_path9 = require("path");
|
|
2422
2695
|
var import_archiver = __toESM(require("archiver"), 1);
|
|
2423
|
-
var
|
|
2424
|
-
var registry3 = (0,
|
|
2696
|
+
var import_core10 = require("@genart-dev/core");
|
|
2697
|
+
var registry3 = (0, import_core10.createDefaultRegistry)();
|
|
2425
2698
|
async function validateOutputPath(outputPath) {
|
|
2426
2699
|
const parentDir = (0, import_path9.dirname)(outputPath);
|
|
2427
2700
|
try {
|
|
2428
|
-
const s = await (0,
|
|
2701
|
+
const s = await (0, import_promises9.stat)(parentDir);
|
|
2429
2702
|
if (!s.isDirectory()) {
|
|
2430
2703
|
throw new Error(`Parent directory does not exist: ${parentDir}`);
|
|
2431
2704
|
}
|
|
@@ -2434,7 +2707,7 @@ async function validateOutputPath(outputPath) {
|
|
|
2434
2707
|
throw new Error(`Parent directory does not exist: ${parentDir}`);
|
|
2435
2708
|
}
|
|
2436
2709
|
try {
|
|
2437
|
-
await (0,
|
|
2710
|
+
await (0, import_promises9.stat)(outputPath);
|
|
2438
2711
|
throw new Error(
|
|
2439
2712
|
`File already exists at ${outputPath}. Delete it first or use a different path.`
|
|
2440
2713
|
);
|
|
@@ -2489,7 +2762,7 @@ async function exportHtml(sketch, outputPath) {
|
|
|
2489
2762
|
const adapter = registry3.resolve(sketch.renderer.type);
|
|
2490
2763
|
const html = adapter.generateStandaloneHTML(sketch);
|
|
2491
2764
|
const content = Buffer.from(html, "utf-8");
|
|
2492
|
-
await (0,
|
|
2765
|
+
await (0, import_promises9.writeFile)(outputPath, content);
|
|
2493
2766
|
return {
|
|
2494
2767
|
success: true,
|
|
2495
2768
|
sketchId: sketch.id,
|
|
@@ -2505,7 +2778,7 @@ async function exportPng(sketch, input) {
|
|
|
2505
2778
|
const width = input.width ?? sketch.canvas.width;
|
|
2506
2779
|
const height = input.height ?? sketch.canvas.height;
|
|
2507
2780
|
const result = await captureHtml({ html, width, height });
|
|
2508
|
-
await (0,
|
|
2781
|
+
await (0, import_promises9.writeFile)(input.outputPath, result.bytes);
|
|
2509
2782
|
return {
|
|
2510
2783
|
success: true,
|
|
2511
2784
|
sketchId: sketch.id,
|
|
@@ -2520,7 +2793,7 @@ async function exportSvg(sketch, input) {
|
|
|
2520
2793
|
const height = input.height ?? sketch.canvas.height;
|
|
2521
2794
|
if (sketch.renderer.type === "svg") {
|
|
2522
2795
|
const content2 = Buffer.from(sketch.algorithm, "utf-8");
|
|
2523
|
-
await (0,
|
|
2796
|
+
await (0, import_promises9.writeFile)(input.outputPath, content2);
|
|
2524
2797
|
return {
|
|
2525
2798
|
success: true,
|
|
2526
2799
|
sketchId: sketch.id,
|
|
@@ -2542,7 +2815,7 @@ async function exportSvg(sketch, input) {
|
|
|
2542
2815
|
href="data:image/png;base64,${b64}"/>
|
|
2543
2816
|
</svg>`;
|
|
2544
2817
|
const content = Buffer.from(svg, "utf-8");
|
|
2545
|
-
await (0,
|
|
2818
|
+
await (0, import_promises9.writeFile)(input.outputPath, content);
|
|
2546
2819
|
return {
|
|
2547
2820
|
success: true,
|
|
2548
2821
|
sketchId: sketch.id,
|
|
@@ -2555,7 +2828,7 @@ async function exportSvg(sketch, input) {
|
|
|
2555
2828
|
}
|
|
2556
2829
|
async function exportAlgorithm(sketch, outputPath) {
|
|
2557
2830
|
const content = Buffer.from(sketch.algorithm, "utf-8");
|
|
2558
|
-
await (0,
|
|
2831
|
+
await (0, import_promises9.writeFile)(outputPath, content);
|
|
2559
2832
|
return {
|
|
2560
2833
|
success: true,
|
|
2561
2834
|
sketchId: sketch.id,
|
|
@@ -2570,7 +2843,7 @@ async function exportZip(sketch, input) {
|
|
|
2570
2843
|
const width = input.width ?? sketch.canvas.width;
|
|
2571
2844
|
const height = input.height ?? sketch.canvas.height;
|
|
2572
2845
|
const html = adapter.generateStandaloneHTML(sketch);
|
|
2573
|
-
const genartJson = (0,
|
|
2846
|
+
const genartJson = (0, import_core10.serializeGenart)(sketch);
|
|
2574
2847
|
const algorithm = sketch.algorithm;
|
|
2575
2848
|
const algExt = algorithmExtension(sketch.renderer.type);
|
|
2576
2849
|
const captureResult = await captureHtml({ html, width, height });
|
|
@@ -2587,7 +2860,7 @@ async function exportZip(sketch, input) {
|
|
|
2587
2860
|
archive.append(genartJson, { name: `${sketch.id}.genart` });
|
|
2588
2861
|
await archive.finalize();
|
|
2589
2862
|
await finished;
|
|
2590
|
-
const s = await (0,
|
|
2863
|
+
const s = await (0, import_promises9.stat)(input.outputPath);
|
|
2591
2864
|
return {
|
|
2592
2865
|
success: true,
|
|
2593
2866
|
sketchId: sketch.id,
|
|
@@ -2605,7 +2878,7 @@ async function exportZip(sketch, input) {
|
|
|
2605
2878
|
}
|
|
2606
2879
|
|
|
2607
2880
|
// src/resources/index.ts
|
|
2608
|
-
var
|
|
2881
|
+
var import_core11 = require("@genart-dev/core");
|
|
2609
2882
|
function registerResources(server, state) {
|
|
2610
2883
|
registerSkillsResource(server);
|
|
2611
2884
|
registerCanvasPresetsResource(server);
|
|
@@ -2613,7 +2886,7 @@ function registerResources(server, state) {
|
|
|
2613
2886
|
registerRenderersResource(server);
|
|
2614
2887
|
}
|
|
2615
2888
|
function registerSkillsResource(server) {
|
|
2616
|
-
const skillRegistry = (0,
|
|
2889
|
+
const skillRegistry = (0, import_core11.createDefaultSkillRegistry)();
|
|
2617
2890
|
server.resource(
|
|
2618
2891
|
"skills",
|
|
2619
2892
|
"genart://skills",
|
|
@@ -2664,7 +2937,7 @@ function registerCanvasPresetsResource(server) {
|
|
|
2664
2937
|
mimeType: "application/json",
|
|
2665
2938
|
text: JSON.stringify(
|
|
2666
2939
|
{
|
|
2667
|
-
presets:
|
|
2940
|
+
presets: import_core11.CANVAS_PRESETS.map((p) => ({
|
|
2668
2941
|
id: p.id,
|
|
2669
2942
|
label: p.label,
|
|
2670
2943
|
category: p.category,
|
|
@@ -2721,7 +2994,7 @@ function registerGalleryResource(server, state) {
|
|
|
2721
2994
|
);
|
|
2722
2995
|
}
|
|
2723
2996
|
function registerRenderersResource(server) {
|
|
2724
|
-
const registry4 = (0,
|
|
2997
|
+
const registry4 = (0, import_core11.createDefaultRegistry)();
|
|
2725
2998
|
server.resource(
|
|
2726
2999
|
"renderers",
|
|
2727
3000
|
"genart://renderers",
|
|
@@ -3103,6 +3376,7 @@ function createServer(state) {
|
|
|
3103
3376
|
);
|
|
3104
3377
|
registerWorkspaceTools(server, state);
|
|
3105
3378
|
registerSketchTools(server, state);
|
|
3379
|
+
registerComponentTools(server, state);
|
|
3106
3380
|
registerSelectionTools(server, state);
|
|
3107
3381
|
registerParameterTools(server, state);
|
|
3108
3382
|
registerArrangementTools(server, state);
|
|
@@ -3206,7 +3480,7 @@ function registerWorkspaceTools(server, state) {
|
|
|
3206
3480
|
function registerSketchTools(server, state) {
|
|
3207
3481
|
server.tool(
|
|
3208
3482
|
"create_sketch",
|
|
3209
|
-
|
|
3483
|
+
'Create a new .genart sketch file from metadata, parameters, and algorithm. IMPORTANT: Do not embed common utilities (PRNG, noise, easing, color math, vector ops) inline in the algorithm. Instead, declare them as components: { "prng": "^1.0.0", "noise-2d": "^1.0.0" }. Then use the exported functions directly in your algorithm (e.g., mulberry32, fbm2D). Use list_components to see all available components for the current renderer.',
|
|
3210
3484
|
{
|
|
3211
3485
|
id: import_zod2.z.string().describe("URL-safe kebab-case identifier"),
|
|
3212
3486
|
title: import_zod2.z.string().describe("Human-readable title"),
|
|
@@ -3244,6 +3518,16 @@ function registerSketchTools(server, state) {
|
|
|
3244
3518
|
algorithm: import_zod2.z.string().optional().describe("Algorithm source code (default: renderer template). For p5: must be `function sketch(p, state) { ... }` in instance mode. State provides: state.WIDTH, state.HEIGHT, state.SEED (number), state.PARAMS (keyed by param key), state.COLORS (keyed by color key, hex strings). Use p5 instance methods (p.createCanvas, p.background, etc)."),
|
|
3245
3519
|
seed: import_zod2.z.number().optional().describe("Initial random seed (default: random)"),
|
|
3246
3520
|
skills: import_zod2.z.array(import_zod2.z.string()).optional().describe("Design skill references"),
|
|
3521
|
+
components: import_zod2.z.record(
|
|
3522
|
+
import_zod2.z.union([
|
|
3523
|
+
import_zod2.z.string(),
|
|
3524
|
+
import_zod2.z.object({
|
|
3525
|
+
version: import_zod2.z.string().optional(),
|
|
3526
|
+
code: import_zod2.z.string().optional(),
|
|
3527
|
+
exports: import_zod2.z.array(import_zod2.z.string()).optional()
|
|
3528
|
+
})
|
|
3529
|
+
])
|
|
3530
|
+
).optional().describe('Component dependencies. Use list_components to see available. Keys are component names, values are semver ranges (e.g. "^1.0.0") or objects with version/code/exports.'),
|
|
3247
3531
|
addToWorkspace: import_zod2.z.string().optional().describe("Path to workspace to add sketch to after creation"),
|
|
3248
3532
|
agent: import_zod2.z.string().optional().describe("Your CLI agent name (e.g. 'claude-code', 'codex-cli', 'gemini-cli', 'opencode', 'kiro')"),
|
|
3249
3533
|
model: import_zod2.z.string().optional().describe("Your AI model identifier (e.g. 'claude-opus-4-6', 'gpt-4o', 'gemini-2.5-pro')")
|
|
@@ -3323,11 +3607,21 @@ function registerSketchTools(server, state) {
|
|
|
3323
3607
|
);
|
|
3324
3608
|
server.tool(
|
|
3325
3609
|
"update_algorithm",
|
|
3326
|
-
"Replace the algorithm source code of a sketch",
|
|
3610
|
+
"Replace the algorithm source code of a sketch. If adding/changing components, pass them in the components field alongside the algorithm.",
|
|
3327
3611
|
{
|
|
3328
3612
|
sketchId: import_zod2.z.string().describe("ID of the sketch to update"),
|
|
3329
3613
|
algorithm: import_zod2.z.string().describe("New algorithm source code. For p5: must be `function sketch(p, state) { ... }` in instance mode. State provides: state.WIDTH, state.HEIGHT, state.SEED, state.PARAMS (keyed by param key), state.COLORS (keyed by color key)."),
|
|
3330
3614
|
validate: import_zod2.z.boolean().optional().describe("Run renderer-specific validation before saving (default: true)"),
|
|
3615
|
+
components: import_zod2.z.record(
|
|
3616
|
+
import_zod2.z.union([
|
|
3617
|
+
import_zod2.z.string(),
|
|
3618
|
+
import_zod2.z.object({
|
|
3619
|
+
version: import_zod2.z.string().optional(),
|
|
3620
|
+
code: import_zod2.z.string().optional(),
|
|
3621
|
+
exports: import_zod2.z.array(import_zod2.z.string()).optional()
|
|
3622
|
+
})
|
|
3623
|
+
])
|
|
3624
|
+
).optional().describe("Component dependencies to resolve alongside the algorithm update. Use list_components to see available."),
|
|
3331
3625
|
agent: import_zod2.z.string().optional().describe("Your CLI agent name (e.g. 'claude-code', 'codex-cli', 'gemini-cli', 'opencode', 'kiro')"),
|
|
3332
3626
|
model: import_zod2.z.string().optional().describe("Your AI model identifier (e.g. 'claude-opus-4-6', 'gpt-4o', 'gemini-2.5-pro')")
|
|
3333
3627
|
},
|
|
@@ -3423,6 +3717,76 @@ function registerSketchTools(server, state) {
|
|
|
3423
3717
|
}
|
|
3424
3718
|
);
|
|
3425
3719
|
}
|
|
3720
|
+
function registerComponentTools(server, state) {
|
|
3721
|
+
server.tool(
|
|
3722
|
+
"list_components",
|
|
3723
|
+
"List available reusable components from the registry, filtered by renderer and/or category. Components provide common utilities (PRNG, noise, easing, color math, etc.) that can be declared as dependencies instead of inlining code in the algorithm.",
|
|
3724
|
+
{
|
|
3725
|
+
renderer: import_zod2.z.enum(["p5", "three", "glsl", "canvas2d", "svg"]).optional().describe("Filter by renderer compatibility"),
|
|
3726
|
+
category: import_zod2.z.enum([
|
|
3727
|
+
"randomness",
|
|
3728
|
+
"noise",
|
|
3729
|
+
"math",
|
|
3730
|
+
"easing",
|
|
3731
|
+
"color",
|
|
3732
|
+
"vector",
|
|
3733
|
+
"geometry",
|
|
3734
|
+
"grid",
|
|
3735
|
+
"particle",
|
|
3736
|
+
"physics",
|
|
3737
|
+
"distribution",
|
|
3738
|
+
"pattern",
|
|
3739
|
+
"sdf",
|
|
3740
|
+
"transform",
|
|
3741
|
+
"animation",
|
|
3742
|
+
"string",
|
|
3743
|
+
"data-structure",
|
|
3744
|
+
"imaging"
|
|
3745
|
+
]).optional().describe("Filter by component category")
|
|
3746
|
+
},
|
|
3747
|
+
async (args) => {
|
|
3748
|
+
try {
|
|
3749
|
+
const result = await listComponents(state, args);
|
|
3750
|
+
return jsonResult(result);
|
|
3751
|
+
} catch (e) {
|
|
3752
|
+
return toolError(e instanceof Error ? e.message : String(e));
|
|
3753
|
+
}
|
|
3754
|
+
}
|
|
3755
|
+
);
|
|
3756
|
+
server.tool(
|
|
3757
|
+
"add_component",
|
|
3758
|
+
"Add a component dependency to an existing sketch. Resolves the component and any transitive dependencies from the registry, validates renderer compatibility, and writes the resolved form to the sketch file.",
|
|
3759
|
+
{
|
|
3760
|
+
sketchId: import_zod2.z.string().describe("ID of the sketch to add the component to"),
|
|
3761
|
+
component: import_zod2.z.string().describe("Component name (e.g. 'prng', 'noise-2d', 'glsl-noise')"),
|
|
3762
|
+
version: import_zod2.z.string().optional().describe("Version range (default: '^1.0.0')")
|
|
3763
|
+
},
|
|
3764
|
+
async (args) => {
|
|
3765
|
+
try {
|
|
3766
|
+
const result = await addComponent(state, args);
|
|
3767
|
+
return jsonResult(result);
|
|
3768
|
+
} catch (e) {
|
|
3769
|
+
return toolError(e instanceof Error ? e.message : String(e));
|
|
3770
|
+
}
|
|
3771
|
+
}
|
|
3772
|
+
);
|
|
3773
|
+
server.tool(
|
|
3774
|
+
"remove_component",
|
|
3775
|
+
"Remove a component dependency from a sketch. Checks for dependent components and warns if the algorithm references the component's exports.",
|
|
3776
|
+
{
|
|
3777
|
+
sketchId: import_zod2.z.string().describe("ID of the sketch to remove the component from"),
|
|
3778
|
+
component: import_zod2.z.string().describe("Component name to remove")
|
|
3779
|
+
},
|
|
3780
|
+
async (args) => {
|
|
3781
|
+
try {
|
|
3782
|
+
const result = await removeComponent(state, args);
|
|
3783
|
+
return jsonResult(result);
|
|
3784
|
+
} catch (e) {
|
|
3785
|
+
return toolError(e instanceof Error ? e.message : String(e));
|
|
3786
|
+
}
|
|
3787
|
+
}
|
|
3788
|
+
);
|
|
3789
|
+
}
|
|
3426
3790
|
function registerSelectionTools(server, state) {
|
|
3427
3791
|
server.tool(
|
|
3428
3792
|
"get_selection",
|