@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/index.cjs CHANGED
@@ -2744,30 +2744,17 @@ function isDirectComponent(name, components) {
2744
2744
 
2745
2745
  // src/tools/capture.ts
2746
2746
  var import_promises8 = require("fs/promises");
2747
+ var import_path9 = require("path");
2747
2748
  var import_core9 = require("@genart-dev/core");
2748
2749
 
2749
2750
  // src/capture/headless.ts
2750
- var cachedModule = null;
2751
- async function loadPuppeteer() {
2752
- if (!cachedModule) {
2753
- try {
2754
- const mod = await import("puppeteer");
2755
- cachedModule = mod.default ?? mod;
2756
- } catch {
2757
- throw new Error(
2758
- "Puppeteer is required for screenshot capture. Install it with: npm install puppeteer"
2759
- );
2760
- }
2761
- }
2762
- return cachedModule;
2763
- }
2751
+ var import_puppeteer = __toESM(require("puppeteer"), 1);
2764
2752
  var browserInstance = null;
2765
2753
  async function getBrowser() {
2766
2754
  if (browserInstance && browserInstance.connected) {
2767
2755
  return browserInstance;
2768
2756
  }
2769
- const puppeteer = await loadPuppeteer();
2770
- browserInstance = await puppeteer.launch({
2757
+ browserInstance = await import_puppeteer.default.launch({
2771
2758
  headless: true,
2772
2759
  executablePath: process.env.PUPPETEER_EXECUTABLE_PATH || void 0,
2773
2760
  args: [
@@ -2860,8 +2847,9 @@ function generateSketchHtml(sketch, opts) {
2860
2847
  }
2861
2848
  return adapter.generateStandaloneHTML(effective);
2862
2849
  }
2863
- function derivePreviewPath(sketchPath) {
2864
- return sketchPath.replace(/\.genart$/, ".png");
2850
+ function deriveSnapshotPath(sketchPath, sketchId, seed) {
2851
+ const wsDir = (0, import_path9.dirname)(sketchPath);
2852
+ return (0, import_path9.join)(wsDir, "snapshots", `${sketchId}-${seed}-preview.png`);
2865
2853
  }
2866
2854
  async function captureScreenshot(state, input) {
2867
2855
  state.requireWorkspace();
@@ -2894,11 +2882,12 @@ async function captureScreenshot(state, input) {
2894
2882
  height,
2895
2883
  inlineSize
2896
2884
  });
2897
- const previewPath = derivePreviewPath(loaded.path);
2885
+ const effectiveSeed = input.seed ?? sketch.state.seed;
2886
+ const previewPath = deriveSnapshotPath(loaded.path, sketchId, effectiveSeed);
2898
2887
  const metadata = await buildScreenshotMetadata(state, multi, {
2899
2888
  target,
2900
2889
  sketchId,
2901
- seed: input.seed ?? sketch.state.seed,
2890
+ seed: effectiveSeed,
2902
2891
  previewPath
2903
2892
  });
2904
2893
  const previewJpegBase64 = Buffer.from(multi.inlineJpeg).toString("base64");
@@ -2919,8 +2908,10 @@ async function buildScreenshotMetadata(state, multi, info) {
2919
2908
  previewPath: info.previewPath
2920
2909
  };
2921
2910
  if (!state.remoteMode) {
2911
+ await (0, import_promises8.mkdir)((0, import_path9.dirname)(info.previewPath), { recursive: true });
2922
2912
  await (0, import_promises8.writeFile)(info.previewPath, multi.previewPng);
2923
2913
  metadata.savedPreviewTo = info.previewPath;
2914
+ metadata.previewWritten = true;
2924
2915
  }
2925
2916
  return metadata;
2926
2917
  }
@@ -2949,11 +2940,12 @@ async function captureBatch(state, input) {
2949
2940
  height,
2950
2941
  inlineSize
2951
2942
  });
2952
- const previewPath = derivePreviewPath(loaded.path);
2943
+ const effectiveSeed = input.seed ?? sketch.state.seed;
2944
+ const previewPath = deriveSnapshotPath(loaded.path, id, effectiveSeed);
2953
2945
  const itemMetadata = await buildScreenshotMetadata(state, multi, {
2954
2946
  target: "sketch",
2955
2947
  sketchId: id,
2956
- seed: input.seed ?? sketch.state.seed,
2948
+ seed: effectiveSeed,
2957
2949
  previewPath
2958
2950
  });
2959
2951
  items.push({
@@ -3313,7 +3305,7 @@ function gatherRelevantSkills(aspects) {
3313
3305
 
3314
3306
  // src/tools/series.ts
3315
3307
  var import_promises9 = require("fs/promises");
3316
- var import_path9 = require("path");
3308
+ var import_path10 = require("path");
3317
3309
  var import_core11 = require("@genart-dev/core");
3318
3310
  function now6() {
3319
3311
  return (/* @__PURE__ */ new Date()).toISOString();
@@ -3476,7 +3468,7 @@ async function seriesSummary(state, input) {
3476
3468
  for (const file of series.sketchFiles) {
3477
3469
  let found = false;
3478
3470
  for (const [id, loaded] of state.sketches) {
3479
- if ((0, import_path9.basename)(loaded.path) === file) {
3471
+ if ((0, import_path10.basename)(loaded.path) === file) {
3480
3472
  const def = loaded.definition;
3481
3473
  sketchInfos.push({
3482
3474
  id,
@@ -3590,18 +3582,18 @@ async function promoteSketch(state, input) {
3590
3582
  ...input.agent ? { agent: input.agent } : {},
3591
3583
  ...input.model ? { model: input.model } : {}
3592
3584
  };
3593
- const sourceDir = (0, import_path9.dirname)(source.path);
3594
- const newPath = (0, import_path9.resolve)(sourceDir, `${newId}.genart`);
3585
+ const sourceDir = (0, import_path10.dirname)(source.path);
3586
+ const newPath = (0, import_path10.resolve)(sourceDir, `${newId}.genart`);
3595
3587
  const json = (0, import_core11.serializeGenart)(promotedDef);
3596
3588
  if (!state.remoteMode) {
3597
3589
  await (0, import_promises9.writeFile)(newPath, json, "utf-8");
3598
3590
  }
3599
3591
  state.sketches.set(newId, { definition: promotedDef, path: newPath });
3600
3592
  const sourceRef = ws.sketches.find(
3601
- (s) => s.file === (0, import_path9.basename)(source.path)
3593
+ (s) => s.file === (0, import_path10.basename)(source.path)
3602
3594
  );
3603
3595
  const position = sourceRef ? { x: sourceRef.position.x, y: sourceRef.position.y + sourceDef.canvas.height + 200 } : { x: 0, y: 0 };
3604
- const file = (0, import_path9.basename)(newPath);
3596
+ const file = (0, import_path10.basename)(newPath);
3605
3597
  state.workspace = {
3606
3598
  ...ws,
3607
3599
  modified: ts,
@@ -3661,7 +3653,7 @@ function countBy(items) {
3661
3653
 
3662
3654
  // src/tools/reference.ts
3663
3655
  var import_promises10 = require("fs/promises");
3664
- var import_path10 = require("path");
3656
+ var import_path11 = require("path");
3665
3657
  var import_core12 = require("@genart-dev/core");
3666
3658
  var import_promises11 = require("fs/promises");
3667
3659
  function now7() {
@@ -3686,7 +3678,7 @@ var IMAGE_EXTENSIONS = /* @__PURE__ */ new Set([
3686
3678
  ".svg"
3687
3679
  ]);
3688
3680
  function isImageFile(path) {
3689
- return IMAGE_EXTENSIONS.has((0, import_path10.extname)(path).toLowerCase());
3681
+ return IMAGE_EXTENSIONS.has((0, import_path11.extname)(path).toLowerCase());
3690
3682
  }
3691
3683
  var VALID_REFERENCE_TYPES = [
3692
3684
  "image",
@@ -3702,7 +3694,7 @@ async function addReference(state, input) {
3702
3694
  `Not a recognized image file: ${input.image}. Supported: ${[...IMAGE_EXTENSIONS].join(", ")}`
3703
3695
  );
3704
3696
  }
3705
- const id = input.id ?? (0, import_path10.basename)(input.image, (0, import_path10.extname)(input.image)).toLowerCase().replace(/[^a-z0-9]+/g, "-").replace(/^-|-$/g, "");
3697
+ const id = input.id ?? (0, import_path11.basename)(input.image, (0, import_path11.extname)(input.image)).toLowerCase().replace(/[^a-z0-9]+/g, "-").replace(/^-|-$/g, "");
3706
3698
  if (!id) {
3707
3699
  throw new Error("Could not derive a valid ID from the image filename");
3708
3700
  }
@@ -3713,15 +3705,15 @@ async function addReference(state, input) {
3713
3705
  `Invalid reference type: '${refType}'. Valid types: ${VALID_REFERENCE_TYPES.join(", ")}`
3714
3706
  );
3715
3707
  }
3716
- const workspaceDir = (0, import_path10.dirname)(state.workspacePath);
3717
- const refsDir = (0, import_path10.resolve)(workspaceDir, "references");
3708
+ const workspaceDir = (0, import_path11.dirname)(state.workspacePath);
3709
+ const refsDir = (0, import_path11.resolve)(workspaceDir, "references");
3718
3710
  await (0, import_promises10.mkdir)(refsDir, { recursive: true });
3719
- const ext = (0, import_path10.extname)(input.image);
3711
+ const ext = (0, import_path11.extname)(input.image);
3720
3712
  const destFilename = `${id}${ext}`;
3721
- const destPath = (0, import_path10.resolve)(refsDir, destFilename);
3713
+ const destPath = (0, import_path11.resolve)(refsDir, destFilename);
3722
3714
  const relativePath = `references/${destFilename}`;
3723
3715
  if (!state.remoteMode) {
3724
- await (0, import_promises10.copyFile)((0, import_path10.resolve)(input.image), destPath);
3716
+ await (0, import_promises10.copyFile)((0, import_path11.resolve)(input.image), destPath);
3725
3717
  }
3726
3718
  const ref = {
3727
3719
  id,
@@ -3803,12 +3795,12 @@ async function addReference(state, input) {
3803
3795
  async function analyzeReference(state, input) {
3804
3796
  state.requireWorkspace();
3805
3797
  const { ref, location } = findReference(state, input.referenceId, input.seriesId, input.sketchId);
3806
- const workspaceDir = (0, import_path10.dirname)(state.workspacePath);
3807
- const imagePath = (0, import_path10.resolve)(workspaceDir, ref.path);
3798
+ const workspaceDir = (0, import_path11.dirname)(state.workspacePath);
3799
+ const imagePath = (0, import_path11.resolve)(workspaceDir, ref.path);
3808
3800
  let previewJpegBase64;
3809
3801
  try {
3810
3802
  const imageBuffer = await (0, import_promises10.readFile)(imagePath);
3811
- const ext = (0, import_path10.extname)(ref.path).toLowerCase();
3803
+ const ext = (0, import_path11.extname)(ref.path).toLowerCase();
3812
3804
  const mimeMap = {
3813
3805
  ".png": "image/png",
3814
3806
  ".jpg": "image/jpeg",
@@ -3963,8 +3955,8 @@ async function extractPalette(state, input) {
3963
3955
  input.sketchId
3964
3956
  );
3965
3957
  const count = input.count ?? 6;
3966
- const workspaceDir = (0, import_path10.dirname)(state.workspacePath);
3967
- const imagePath = (0, import_path10.resolve)(workspaceDir, ref.path);
3958
+ const workspaceDir = (0, import_path11.dirname)(state.workspacePath);
3959
+ const imagePath = (0, import_path11.resolve)(workspaceDir, ref.path);
3968
3960
  let previewJpegBase64;
3969
3961
  try {
3970
3962
  const imageBuffer = await (0, import_promises10.readFile)(imagePath);
@@ -4040,12 +4032,12 @@ function findReference(state, referenceId, seriesId, sketchId) {
4040
4032
  // src/tools/export.ts
4041
4033
  var import_fs = require("fs");
4042
4034
  var import_promises12 = require("fs/promises");
4043
- var import_path11 = require("path");
4035
+ var import_path12 = require("path");
4044
4036
  var import_archiver = __toESM(require("archiver"), 1);
4045
4037
  var import_core13 = require("@genart-dev/core");
4046
4038
  var registry4 = (0, import_core13.createDefaultRegistry)();
4047
4039
  async function validateOutputPath(outputPath) {
4048
- const parentDir = (0, import_path11.dirname)(outputPath);
4040
+ const parentDir = (0, import_path12.dirname)(outputPath);
4049
4041
  try {
4050
4042
  const s = await (0, import_promises12.stat)(parentDir);
4051
4043
  if (!s.isDirectory()) {
@@ -5311,20 +5303,24 @@ async function initializePluginRegistry() {
5311
5303
  await registry5.register(import_plugin_trace.default);
5312
5304
  return registry5;
5313
5305
  }
5314
- function createServer(state) {
5306
+ function createServer(state, options) {
5307
+ const captureOnly = options?.captureOnly ?? false;
5315
5308
  const server = new import_mcp.McpServer(
5316
5309
  {
5317
- name: "@genart/mcp-server",
5310
+ name: captureOnly ? "@genart/mcp-capture" : "@genart/mcp-server",
5318
5311
  version: "0.4.0"
5319
5312
  },
5320
5313
  {
5321
5314
  capabilities: {
5322
5315
  tools: {},
5323
- resources: {},
5324
- prompts: {}
5316
+ ...!captureOnly && { resources: {}, prompts: {} }
5325
5317
  }
5326
5318
  }
5327
5319
  );
5320
+ if (captureOnly) {
5321
+ registerCaptureTools(server, state);
5322
+ return server;
5323
+ }
5328
5324
  const registryReady = initializePluginRegistry().then((registry5) => {
5329
5325
  state.pluginRegistry = registry5;
5330
5326
  registerPluginMcpTools(server, registry5, state);
@@ -5341,7 +5337,9 @@ function createServer(state) {
5341
5337
  registerSnapshotTools(server, state);
5342
5338
  registerKnowledgeTools(server, state);
5343
5339
  registerDesignTools(server, state);
5344
- registerCaptureTools(server, state);
5340
+ if (!state.remoteMode) {
5341
+ registerCaptureTools(server, state);
5342
+ }
5345
5343
  registerCritiqueTools(server, state);
5346
5344
  registerSeriesTools(server, state);
5347
5345
  registerReferenceTools(server, state);
@@ -6051,7 +6049,7 @@ function registerSnapshotTools(server, state) {
6051
6049
  function registerCaptureTools(server, state) {
6052
6050
  server.tool(
6053
6051
  "capture_screenshot",
6054
- "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.",
6052
+ "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.",
6055
6053
  {
6056
6054
  target: import_zod2.z.enum(["selected", "sketch"]).optional().describe("What to capture (default: selected)"),
6057
6055
  sketchId: import_zod2.z.string().optional().describe("Required when target is 'sketch'"),
@@ -6064,6 +6062,7 @@ function registerCaptureTools(server, state) {
6064
6062
  async (args) => {
6065
6063
  try {
6066
6064
  const result = await captureScreenshot(state, args);
6065
+ console.error(`[capture_screenshot] jpeg base64 length: ${result.previewJpegBase64.length}, metadata: ${JSON.stringify(result.metadata)}`);
6067
6066
  return {
6068
6067
  content: [
6069
6068
  { type: "text", text: JSON.stringify(result.metadata, null, 2) },
@@ -6071,6 +6070,7 @@ function registerCaptureTools(server, state) {
6071
6070
  ]
6072
6071
  };
6073
6072
  } catch (e) {
6073
+ console.error(`[capture_screenshot] error: ${e instanceof Error ? e.message : String(e)}`);
6074
6074
  return toolError(e instanceof Error ? e.message : String(e));
6075
6075
  }
6076
6076
  }
@@ -6711,14 +6711,17 @@ function registerKnowledgeTools(server, state) {
6711
6711
 
6712
6712
  // src/index.ts
6713
6713
  async function main() {
6714
- const sidecar = isSidecarMode();
6715
- if (sidecar) {
6714
+ const captureOnly = process.argv.includes("--capture-only");
6715
+ const sidecar = !captureOnly && isSidecarMode();
6716
+ if (captureOnly) {
6717
+ console.error("[genart-mcp] Starting in capture-only mode");
6718
+ } else if (sidecar) {
6716
6719
  console.error("[genart-mcp] Starting in sidecar mode");
6717
6720
  } else {
6718
6721
  console.error("[genart-mcp] Starting in stdio mode");
6719
6722
  }
6720
6723
  const state = new EditorState();
6721
- const server = createServer(state);
6724
+ const server = createServer(state, { captureOnly });
6722
6725
  const transport = new import_stdio.StdioServerTransport();
6723
6726
  await server.connect(transport);
6724
6727
  console.error("[genart-mcp] Server connected and ready");