@genart-dev/mcp-server 0.4.1 → 0.4.3

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/lib.cjs CHANGED
@@ -2445,30 +2445,17 @@ function isDirectComponent(name, components) {
2445
2445
 
2446
2446
  // src/tools/capture.ts
2447
2447
  var import_promises6 = require("fs/promises");
2448
+ var import_path8 = require("path");
2448
2449
  var import_core8 = require("@genart-dev/core");
2449
2450
 
2450
2451
  // src/capture/headless.ts
2451
- var cachedModule = null;
2452
- async function loadPuppeteer() {
2453
- if (!cachedModule) {
2454
- try {
2455
- const mod = await import("puppeteer");
2456
- cachedModule = mod.default ?? mod;
2457
- } catch {
2458
- throw new Error(
2459
- "Puppeteer is required for screenshot capture. Install it with: npm install puppeteer"
2460
- );
2461
- }
2462
- }
2463
- return cachedModule;
2464
- }
2452
+ var import_puppeteer = __toESM(require("puppeteer"), 1);
2465
2453
  var browserInstance = null;
2466
2454
  async function getBrowser() {
2467
2455
  if (browserInstance && browserInstance.connected) {
2468
2456
  return browserInstance;
2469
2457
  }
2470
- const puppeteer = await loadPuppeteer();
2471
- browserInstance = await puppeteer.launch({
2458
+ browserInstance = await import_puppeteer.default.launch({
2472
2459
  headless: true,
2473
2460
  executablePath: process.env.PUPPETEER_EXECUTABLE_PATH || void 0,
2474
2461
  args: [
@@ -2561,8 +2548,9 @@ function generateSketchHtml(sketch, opts) {
2561
2548
  }
2562
2549
  return adapter.generateStandaloneHTML(effective);
2563
2550
  }
2564
- function derivePreviewPath(sketchPath) {
2565
- return sketchPath.replace(/\.genart$/, ".png");
2551
+ function deriveSnapshotPath(sketchPath, sketchId, seed) {
2552
+ const wsDir = (0, import_path8.dirname)(sketchPath);
2553
+ return (0, import_path8.join)(wsDir, "snapshots", `${sketchId}-${seed}-preview.png`);
2566
2554
  }
2567
2555
  async function captureScreenshot(state, input) {
2568
2556
  state.requireWorkspace();
@@ -2595,11 +2583,12 @@ async function captureScreenshot(state, input) {
2595
2583
  height,
2596
2584
  inlineSize
2597
2585
  });
2598
- const previewPath = derivePreviewPath(loaded.path);
2586
+ const effectiveSeed = input.seed ?? sketch.state.seed;
2587
+ const previewPath = deriveSnapshotPath(loaded.path, sketchId, effectiveSeed);
2599
2588
  const metadata = await buildScreenshotMetadata(state, multi, {
2600
2589
  target,
2601
2590
  sketchId,
2602
- seed: input.seed ?? sketch.state.seed,
2591
+ seed: effectiveSeed,
2603
2592
  previewPath
2604
2593
  });
2605
2594
  const previewJpegBase64 = Buffer.from(multi.inlineJpeg).toString("base64");
@@ -2620,8 +2609,10 @@ async function buildScreenshotMetadata(state, multi, info) {
2620
2609
  previewPath: info.previewPath
2621
2610
  };
2622
2611
  if (!state.remoteMode) {
2612
+ await (0, import_promises6.mkdir)((0, import_path8.dirname)(info.previewPath), { recursive: true });
2623
2613
  await (0, import_promises6.writeFile)(info.previewPath, multi.previewPng);
2624
2614
  metadata.savedPreviewTo = info.previewPath;
2615
+ metadata.previewWritten = true;
2625
2616
  }
2626
2617
  return metadata;
2627
2618
  }
@@ -2650,11 +2641,12 @@ async function captureBatch(state, input) {
2650
2641
  height,
2651
2642
  inlineSize
2652
2643
  });
2653
- const previewPath = derivePreviewPath(loaded.path);
2644
+ const effectiveSeed = input.seed ?? sketch.state.seed;
2645
+ const previewPath = deriveSnapshotPath(loaded.path, id, effectiveSeed);
2654
2646
  const itemMetadata = await buildScreenshotMetadata(state, multi, {
2655
2647
  target: "sketch",
2656
2648
  sketchId: id,
2657
- seed: input.seed ?? sketch.state.seed,
2649
+ seed: effectiveSeed,
2658
2650
  previewPath
2659
2651
  });
2660
2652
  items.push({
@@ -3014,7 +3006,7 @@ function gatherRelevantSkills(aspects) {
3014
3006
 
3015
3007
  // src/tools/series.ts
3016
3008
  var import_promises7 = require("fs/promises");
3017
- var import_path8 = require("path");
3009
+ var import_path9 = require("path");
3018
3010
  var import_core10 = require("@genart-dev/core");
3019
3011
  function now6() {
3020
3012
  return (/* @__PURE__ */ new Date()).toISOString();
@@ -3177,7 +3169,7 @@ async function seriesSummary(state, input) {
3177
3169
  for (const file of series.sketchFiles) {
3178
3170
  let found = false;
3179
3171
  for (const [id, loaded] of state.sketches) {
3180
- if ((0, import_path8.basename)(loaded.path) === file) {
3172
+ if ((0, import_path9.basename)(loaded.path) === file) {
3181
3173
  const def = loaded.definition;
3182
3174
  sketchInfos.push({
3183
3175
  id,
@@ -3291,18 +3283,18 @@ async function promoteSketch(state, input) {
3291
3283
  ...input.agent ? { agent: input.agent } : {},
3292
3284
  ...input.model ? { model: input.model } : {}
3293
3285
  };
3294
- const sourceDir = (0, import_path8.dirname)(source.path);
3295
- const newPath = (0, import_path8.resolve)(sourceDir, `${newId}.genart`);
3286
+ const sourceDir = (0, import_path9.dirname)(source.path);
3287
+ const newPath = (0, import_path9.resolve)(sourceDir, `${newId}.genart`);
3296
3288
  const json = (0, import_core10.serializeGenart)(promotedDef);
3297
3289
  if (!state.remoteMode) {
3298
3290
  await (0, import_promises7.writeFile)(newPath, json, "utf-8");
3299
3291
  }
3300
3292
  state.sketches.set(newId, { definition: promotedDef, path: newPath });
3301
3293
  const sourceRef = ws.sketches.find(
3302
- (s) => s.file === (0, import_path8.basename)(source.path)
3294
+ (s) => s.file === (0, import_path9.basename)(source.path)
3303
3295
  );
3304
3296
  const position = sourceRef ? { x: sourceRef.position.x, y: sourceRef.position.y + sourceDef.canvas.height + 200 } : { x: 0, y: 0 };
3305
- const file = (0, import_path8.basename)(newPath);
3297
+ const file = (0, import_path9.basename)(newPath);
3306
3298
  state.workspace = {
3307
3299
  ...ws,
3308
3300
  modified: ts,
@@ -3362,7 +3354,7 @@ function countBy(items) {
3362
3354
 
3363
3355
  // src/tools/reference.ts
3364
3356
  var import_promises8 = require("fs/promises");
3365
- var import_path9 = require("path");
3357
+ var import_path10 = require("path");
3366
3358
  var import_core11 = require("@genart-dev/core");
3367
3359
  var import_promises9 = require("fs/promises");
3368
3360
  function now7() {
@@ -3387,7 +3379,7 @@ var IMAGE_EXTENSIONS = /* @__PURE__ */ new Set([
3387
3379
  ".svg"
3388
3380
  ]);
3389
3381
  function isImageFile(path) {
3390
- return IMAGE_EXTENSIONS.has((0, import_path9.extname)(path).toLowerCase());
3382
+ return IMAGE_EXTENSIONS.has((0, import_path10.extname)(path).toLowerCase());
3391
3383
  }
3392
3384
  var VALID_REFERENCE_TYPES = [
3393
3385
  "image",
@@ -3403,7 +3395,7 @@ async function addReference(state, input) {
3403
3395
  `Not a recognized image file: ${input.image}. Supported: ${[...IMAGE_EXTENSIONS].join(", ")}`
3404
3396
  );
3405
3397
  }
3406
- const id = input.id ?? (0, import_path9.basename)(input.image, (0, import_path9.extname)(input.image)).toLowerCase().replace(/[^a-z0-9]+/g, "-").replace(/^-|-$/g, "");
3398
+ const id = input.id ?? (0, import_path10.basename)(input.image, (0, import_path10.extname)(input.image)).toLowerCase().replace(/[^a-z0-9]+/g, "-").replace(/^-|-$/g, "");
3407
3399
  if (!id) {
3408
3400
  throw new Error("Could not derive a valid ID from the image filename");
3409
3401
  }
@@ -3414,15 +3406,15 @@ async function addReference(state, input) {
3414
3406
  `Invalid reference type: '${refType}'. Valid types: ${VALID_REFERENCE_TYPES.join(", ")}`
3415
3407
  );
3416
3408
  }
3417
- const workspaceDir = (0, import_path9.dirname)(state.workspacePath);
3418
- const refsDir = (0, import_path9.resolve)(workspaceDir, "references");
3409
+ const workspaceDir = (0, import_path10.dirname)(state.workspacePath);
3410
+ const refsDir = (0, import_path10.resolve)(workspaceDir, "references");
3419
3411
  await (0, import_promises8.mkdir)(refsDir, { recursive: true });
3420
- const ext = (0, import_path9.extname)(input.image);
3412
+ const ext = (0, import_path10.extname)(input.image);
3421
3413
  const destFilename = `${id}${ext}`;
3422
- const destPath = (0, import_path9.resolve)(refsDir, destFilename);
3414
+ const destPath = (0, import_path10.resolve)(refsDir, destFilename);
3423
3415
  const relativePath = `references/${destFilename}`;
3424
3416
  if (!state.remoteMode) {
3425
- await (0, import_promises8.copyFile)((0, import_path9.resolve)(input.image), destPath);
3417
+ await (0, import_promises8.copyFile)((0, import_path10.resolve)(input.image), destPath);
3426
3418
  }
3427
3419
  const ref = {
3428
3420
  id,
@@ -3504,12 +3496,12 @@ async function addReference(state, input) {
3504
3496
  async function analyzeReference(state, input) {
3505
3497
  state.requireWorkspace();
3506
3498
  const { ref, location } = findReference(state, input.referenceId, input.seriesId, input.sketchId);
3507
- const workspaceDir = (0, import_path9.dirname)(state.workspacePath);
3508
- const imagePath = (0, import_path9.resolve)(workspaceDir, ref.path);
3499
+ const workspaceDir = (0, import_path10.dirname)(state.workspacePath);
3500
+ const imagePath = (0, import_path10.resolve)(workspaceDir, ref.path);
3509
3501
  let previewJpegBase64;
3510
3502
  try {
3511
3503
  const imageBuffer = await (0, import_promises8.readFile)(imagePath);
3512
- const ext = (0, import_path9.extname)(ref.path).toLowerCase();
3504
+ const ext = (0, import_path10.extname)(ref.path).toLowerCase();
3513
3505
  const mimeMap = {
3514
3506
  ".png": "image/png",
3515
3507
  ".jpg": "image/jpeg",
@@ -3664,8 +3656,8 @@ async function extractPalette(state, input) {
3664
3656
  input.sketchId
3665
3657
  );
3666
3658
  const count = input.count ?? 6;
3667
- const workspaceDir = (0, import_path9.dirname)(state.workspacePath);
3668
- const imagePath = (0, import_path9.resolve)(workspaceDir, ref.path);
3659
+ const workspaceDir = (0, import_path10.dirname)(state.workspacePath);
3660
+ const imagePath = (0, import_path10.resolve)(workspaceDir, ref.path);
3669
3661
  let previewJpegBase64;
3670
3662
  try {
3671
3663
  const imageBuffer = await (0, import_promises8.readFile)(imagePath);
@@ -3741,12 +3733,12 @@ function findReference(state, referenceId, seriesId, sketchId) {
3741
3733
  // src/tools/export.ts
3742
3734
  var import_fs = require("fs");
3743
3735
  var import_promises10 = require("fs/promises");
3744
- var import_path10 = require("path");
3736
+ var import_path11 = require("path");
3745
3737
  var import_archiver = __toESM(require("archiver"), 1);
3746
3738
  var import_core12 = require("@genart-dev/core");
3747
3739
  var registry4 = (0, import_core12.createDefaultRegistry)();
3748
3740
  async function validateOutputPath(outputPath) {
3749
- const parentDir = (0, import_path10.dirname)(outputPath);
3741
+ const parentDir = (0, import_path11.dirname)(outputPath);
3750
3742
  try {
3751
3743
  const s = await (0, import_promises10.stat)(parentDir);
3752
3744
  if (!s.isDirectory()) {
@@ -5012,20 +5004,24 @@ async function initializePluginRegistry() {
5012
5004
  await registry5.register(import_plugin_trace.default);
5013
5005
  return registry5;
5014
5006
  }
5015
- function createServer(state) {
5007
+ function createServer(state, options) {
5008
+ const captureOnly = options?.captureOnly ?? false;
5016
5009
  const server = new import_mcp.McpServer(
5017
5010
  {
5018
- name: "@genart/mcp-server",
5011
+ name: captureOnly ? "@genart/mcp-capture" : "@genart/mcp-server",
5019
5012
  version: "0.4.0"
5020
5013
  },
5021
5014
  {
5022
5015
  capabilities: {
5023
5016
  tools: {},
5024
- resources: {},
5025
- prompts: {}
5017
+ ...!captureOnly && { resources: {}, prompts: {} }
5026
5018
  }
5027
5019
  }
5028
5020
  );
5021
+ if (captureOnly) {
5022
+ registerCaptureTools(server, state);
5023
+ return server;
5024
+ }
5029
5025
  const registryReady = initializePluginRegistry().then((registry5) => {
5030
5026
  state.pluginRegistry = registry5;
5031
5027
  registerPluginMcpTools(server, registry5, state);
@@ -5042,7 +5038,9 @@ function createServer(state) {
5042
5038
  registerSnapshotTools(server, state);
5043
5039
  registerKnowledgeTools(server, state);
5044
5040
  registerDesignTools(server, state);
5045
- registerCaptureTools(server, state);
5041
+ if (!state.remoteMode) {
5042
+ registerCaptureTools(server, state);
5043
+ }
5046
5044
  registerCritiqueTools(server, state);
5047
5045
  registerSeriesTools(server, state);
5048
5046
  registerReferenceTools(server, state);
@@ -5752,7 +5750,7 @@ function registerSnapshotTools(server, state) {
5752
5750
  function registerCaptureTools(server, state) {
5753
5751
  server.tool(
5754
5752
  "capture_screenshot",
5755
- "Capture a screenshot of a sketch. Returns metadata as text + a small inline JPEG image for visual review. In remote mode, metadata includes previewFileContent (base64 PNG) to Write locally.",
5753
+ "Capture a screenshot of a sketch. Returns metadata as text + a small inline JPEG image for visual review. In local mode, writes a full-res PNG to snapshots/<sketchId>-<seed>-preview.png next to the workspace. The savedPreviewTo path in metadata points to the file on disk.",
5756
5754
  {
5757
5755
  target: import_zod2.z.enum(["selected", "sketch"]).optional().describe("What to capture (default: selected)"),
5758
5756
  sketchId: import_zod2.z.string().optional().describe("Required when target is 'sketch'"),
@@ -5765,6 +5763,7 @@ function registerCaptureTools(server, state) {
5765
5763
  async (args) => {
5766
5764
  try {
5767
5765
  const result = await captureScreenshot(state, args);
5766
+ console.error(`[capture_screenshot] jpeg base64 length: ${result.previewJpegBase64.length}, metadata: ${JSON.stringify(result.metadata)}`);
5768
5767
  return {
5769
5768
  content: [
5770
5769
  { type: "text", text: JSON.stringify(result.metadata, null, 2) },
@@ -5772,6 +5771,7 @@ function registerCaptureTools(server, state) {
5772
5771
  ]
5773
5772
  };
5774
5773
  } catch (e) {
5774
+ console.error(`[capture_screenshot] error: ${e instanceof Error ? e.message : String(e)}`);
5775
5775
  return toolError(e instanceof Error ? e.message : String(e));
5776
5776
  }
5777
5777
  }
@@ -6413,7 +6413,7 @@ function registerKnowledgeTools(server, state) {
6413
6413
  // src/state.ts
6414
6414
  var import_events = require("events");
6415
6415
  var import_promises11 = require("fs/promises");
6416
- var import_path11 = require("path");
6416
+ var import_path12 = require("path");
6417
6417
 
6418
6418
  // src/sidecar.ts
6419
6419
  function isSidecarMode() {
@@ -6470,7 +6470,7 @@ var EditorState = class extends import_events.EventEmitter {
6470
6470
  }
6471
6471
  /** Resolve a file path, respecting the sandbox basePath when set. */
6472
6472
  resolvePath(file) {
6473
- if ((0, import_path11.isAbsolute)(file)) {
6473
+ if ((0, import_path12.isAbsolute)(file)) {
6474
6474
  if (this.basePath && !file.startsWith(this.basePath)) {
6475
6475
  throw new Error(`Path escapes sandbox: ${file}`);
6476
6476
  }
@@ -6478,10 +6478,10 @@ var EditorState = class extends import_events.EventEmitter {
6478
6478
  }
6479
6479
  if ((file.startsWith("~/") || file === "~") && !this.basePath) {
6480
6480
  const home = process.env.HOME ?? process.env.USERPROFILE ?? "";
6481
- return (0, import_path11.resolve)(home, file.slice(2));
6481
+ return (0, import_path12.resolve)(home, file.slice(2));
6482
6482
  }
6483
6483
  const base = this.basePath ?? process.cwd();
6484
- const resolved = (0, import_path11.resolve)(base, file);
6484
+ const resolved = (0, import_path12.resolve)(base, file);
6485
6485
  if (this.basePath && !resolved.startsWith(this.basePath)) {
6486
6486
  throw new Error(`Path escapes sandbox: ${resolved}`);
6487
6487
  }
@@ -6489,7 +6489,7 @@ var EditorState = class extends import_events.EventEmitter {
6489
6489
  }
6490
6490
  /** Resolve a sketch file reference (relative to workspace dir) to an absolute path. */
6491
6491
  resolveSketchPath(file) {
6492
- if ((0, import_path11.isAbsolute)(file)) {
6492
+ if ((0, import_path12.isAbsolute)(file)) {
6493
6493
  if (this.basePath && !file.startsWith(this.basePath)) {
6494
6494
  throw new Error(`Path escapes sandbox: ${file}`);
6495
6495
  }
@@ -6497,11 +6497,11 @@ var EditorState = class extends import_events.EventEmitter {
6497
6497
  }
6498
6498
  if (!this.workspacePath) {
6499
6499
  if (this.basePath) {
6500
- return (0, import_path11.resolve)(this.basePath, file);
6500
+ return (0, import_path12.resolve)(this.basePath, file);
6501
6501
  }
6502
6502
  throw new Error("No workspace is currently open");
6503
6503
  }
6504
- const resolved = (0, import_path11.resolve)((0, import_path11.dirname)(this.workspacePath), file);
6504
+ const resolved = (0, import_path12.resolve)((0, import_path12.dirname)(this.workspacePath), file);
6505
6505
  if (this.basePath && !resolved.startsWith(this.basePath)) {
6506
6506
  throw new Error(`Path escapes sandbox: ${resolved}`);
6507
6507
  }