webstudio 0.274.4 → 0.274.5

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.
@@ -5205,7 +5205,7 @@ const publicApiOperationDocumentation = [
5205
5205
  description: "Update page settings and metadata",
5206
5206
  requiredOptions: ["page", "json"],
5207
5207
  examples: [
5208
- 'webstudio update-page --page page-id --title Pricing --description "Pricing plans" --json'
5208
+ 'webstudio update-page --page page-id --title "\\"Pricing\\"" --description "\\"Pricing plans\\"" --json'
5209
5209
  ]
5210
5210
  },
5211
5211
  {
@@ -5378,7 +5378,7 @@ const publicApiOperationDocumentation = [
5378
5378
  },
5379
5379
  {
5380
5380
  command: "update-props",
5381
- description: "Create or update element props; editor tokens are limited to content-mode props",
5381
+ description: "Create or update direct element prop values; use this for fixed strings, numbers, booleans, JSON, assets, pages, parameters, and resources. Editor tokens are limited to content-mode props",
5382
5382
  requiredOptions: ["input", "json"],
5383
5383
  examples: ["webstudio update-props --input props.json --json"]
5384
5384
  },
@@ -5390,7 +5390,7 @@ const publicApiOperationDocumentation = [
5390
5390
  },
5391
5391
  {
5392
5392
  command: "bind-props",
5393
- description: "Bind element props to expressions, parameters, resources, or actions",
5393
+ description: "Bind element props to dynamic expressions, parameters, resources, or actions. Do not use for fixed string values; use update-props instead",
5394
5394
  requiredOptions: ["input", "json"],
5395
5395
  examples: ["webstudio bind-props --input bindings.json --json"]
5396
5396
  },
@@ -6123,6 +6123,7 @@ const withDefaultPermit = (operation) => {
6123
6123
  permit: operation.permit ?? (operation.method === "query" ? "view" : "build"),
6124
6124
  description: documentation.description,
6125
6125
  inputFields: inputFieldsLookup[operation.command] ?? [],
6126
+ inputFieldTypes: operation.inputFieldTypes ?? {},
6126
6127
  requiredOptions: documentation.requiredOptions,
6127
6128
  examples: documentation.examples,
6128
6129
  localCapable: runtimeOperation2 !== void 0,
@@ -6352,14 +6353,16 @@ const publicApiOperationInputs = [
6352
6353
  id: "instances.append",
6353
6354
  method: "mutation",
6354
6355
  path: "api.instances.append",
6355
- client: "appendInstance"
6356
+ client: "appendInstance",
6357
+ inputFieldTypes: { children: "array" }
6356
6358
  },
6357
6359
  {
6358
6360
  command: "move-instance",
6359
6361
  id: "instances.move",
6360
6362
  method: "mutation",
6361
6363
  path: "api.instances.move",
6362
- client: "moveInstance"
6364
+ client: "moveInstance",
6365
+ inputFieldTypes: { moves: "array" }
6363
6366
  },
6364
6367
  {
6365
6368
  command: "clone-instance",
@@ -6373,7 +6376,8 @@ const publicApiOperationInputs = [
6373
6376
  id: "instances.delete",
6374
6377
  method: "mutation",
6375
6378
  path: "api.instances.delete",
6376
- client: "deleteInstance"
6379
+ client: "deleteInstance",
6380
+ inputFieldTypes: { instanceIds: "array" }
6377
6381
  },
6378
6382
  {
6379
6383
  command: "update-props",
@@ -6381,7 +6385,8 @@ const publicApiOperationInputs = [
6381
6385
  method: "mutation",
6382
6386
  path: "api.instances.updateProps",
6383
6387
  client: "updateProps",
6384
- permit: "edit"
6388
+ permit: "edit",
6389
+ inputFieldTypes: { updates: "array" }
6385
6390
  },
6386
6391
  {
6387
6392
  command: "delete-props",
@@ -6389,14 +6394,16 @@ const publicApiOperationInputs = [
6389
6394
  method: "mutation",
6390
6395
  path: "api.instances.deleteProps",
6391
6396
  client: "deleteProps",
6392
- permit: "edit"
6397
+ permit: "edit",
6398
+ inputFieldTypes: { deletions: "array" }
6393
6399
  },
6394
6400
  {
6395
6401
  command: "bind-props",
6396
6402
  id: "instances.bindProps",
6397
6403
  method: "mutation",
6398
6404
  path: "api.instances.bindProps",
6399
- client: "bindProps"
6405
+ client: "bindProps",
6406
+ inputFieldTypes: { bindings: "array" }
6400
6407
  },
6401
6408
  {
6402
6409
  command: "list-texts",
@@ -6425,14 +6432,16 @@ const publicApiOperationInputs = [
6425
6432
  id: "styles.updateDeclarations",
6426
6433
  method: "mutation",
6427
6434
  path: "api.styles.updateDeclarations",
6428
- client: "updateStyleDeclarations"
6435
+ client: "updateStyleDeclarations",
6436
+ inputFieldTypes: { updates: "array" }
6429
6437
  },
6430
6438
  {
6431
6439
  command: "delete-styles",
6432
6440
  id: "styles.deleteDeclarations",
6433
6441
  method: "mutation",
6434
6442
  path: "api.styles.deleteDeclarations",
6435
- client: "deleteStyleDeclarations"
6443
+ client: "deleteStyleDeclarations",
6444
+ inputFieldTypes: { deletions: "array" }
6436
6445
  },
6437
6446
  {
6438
6447
  command: "replace-styles",
@@ -6453,42 +6462,48 @@ const publicApiOperationInputs = [
6453
6462
  id: "designTokens.create",
6454
6463
  method: "mutation",
6455
6464
  path: "api.designTokens.create",
6456
- client: "createDesignTokens"
6465
+ client: "createDesignTokens",
6466
+ inputFieldTypes: { tokens: "array" }
6457
6467
  },
6458
6468
  {
6459
6469
  command: "update-design-token-styles",
6460
6470
  id: "designTokens.updateStyles",
6461
6471
  method: "mutation",
6462
6472
  path: "api.designTokens.updateStyles",
6463
- client: "updateDesignTokenStyles"
6473
+ client: "updateDesignTokenStyles",
6474
+ inputFieldTypes: { updates: "array" }
6464
6475
  },
6465
6476
  {
6466
6477
  command: "delete-design-token-styles",
6467
6478
  id: "designTokens.deleteStyles",
6468
6479
  method: "mutation",
6469
6480
  path: "api.designTokens.deleteStyles",
6470
- client: "deleteDesignTokenStyles"
6481
+ client: "deleteDesignTokenStyles",
6482
+ inputFieldTypes: { deletions: "array" }
6471
6483
  },
6472
6484
  {
6473
6485
  command: "attach-design-token",
6474
6486
  id: "designTokens.attach",
6475
6487
  method: "mutation",
6476
6488
  path: "api.designTokens.attach",
6477
- client: "attachDesignToken"
6489
+ client: "attachDesignToken",
6490
+ inputFieldTypes: { instanceIds: "array" }
6478
6491
  },
6479
6492
  {
6480
6493
  command: "detach-design-token",
6481
6494
  id: "designTokens.detach",
6482
6495
  method: "mutation",
6483
6496
  path: "api.designTokens.detach",
6484
- client: "detachDesignToken"
6497
+ client: "detachDesignToken",
6498
+ inputFieldTypes: { instanceIds: "array" }
6485
6499
  },
6486
6500
  {
6487
6501
  command: "extract-design-token",
6488
6502
  id: "designTokens.extract",
6489
6503
  method: "mutation",
6490
6504
  path: "api.designTokens.extract",
6491
- client: "extractDesignToken"
6505
+ client: "extractDesignToken",
6506
+ inputFieldTypes: { instanceIds: "array", removeLocalProps: "array" }
6492
6507
  },
6493
6508
  {
6494
6509
  command: "list-css-variables",
@@ -6509,7 +6524,8 @@ const publicApiOperationInputs = [
6509
6524
  id: "cssVariables.delete",
6510
6525
  method: "mutation",
6511
6526
  path: "api.cssVariables.delete",
6512
- client: "deleteCssVariables"
6527
+ client: "deleteCssVariables",
6528
+ inputFieldTypes: { names: "array" }
6513
6529
  },
6514
6530
  {
6515
6531
  command: "rewrite-css-variable-refs",
@@ -6683,7 +6699,8 @@ const publicApiOperationInputs = [
6683
6699
  id: "assets.delete",
6684
6700
  method: "mutation",
6685
6701
  path: "api.assets.delete",
6686
- client: "deleteAssets"
6702
+ client: "deleteAssets",
6703
+ inputFieldTypes: { assetIdsOrPrefixes: "array" }
6687
6704
  }
6688
6705
  ];
6689
6706
  const publicApiOperations = publicApiOperationInputs.map(withDefaultPermit);
@@ -7635,7 +7652,7 @@ class HandledCliError extends Error {
7635
7652
  }
7636
7653
  const isHandledCliError = (error) => error instanceof HandledCliError;
7637
7654
  const name$N = "webstudio";
7638
- const version = "0.274.4";
7655
+ const version = "0.274.5";
7639
7656
  const description = "Webstudio CLI";
7640
7657
  const author = "Webstudio <github@webstudio.is>";
7641
7658
  const homepage = "https://webstudio.is";
@@ -7643,11 +7660,11 @@ const type = "module";
7643
7660
  const bin = { "webstudio-cli": "./bin.js", "webstudio": "./bin.js" };
7644
7661
  const imports = { "#cli": { "webstudio": "./src/cli.ts", "default": "./lib/cli.js" } };
7645
7662
  const files = ["lib/*", "templates/*", "bin.js", "!*.{test,stories}.*"];
7646
- const scripts = { "typecheck": "tsgo --noEmit", "generate-docs": "node scripts/generate-docs.mjs", "build": "pnpm generate-docs && rm -rf lib && vite build", "test": "vitest run" };
7663
+ const scripts = { "typecheck": "tsgo --noEmit", "generate-docs": "tsx scripts/generate-docs.ts", "build": "pnpm generate-docs && rm -rf lib && vite build", "test": "vitest run" };
7647
7664
  const license = "AGPL-3.0-or-later";
7648
7665
  const engines = { "node": ">=22" };
7649
7666
  const dependencies = { "@clack/prompts": "^0.10.0", "@emotion/hash": "^0.9.2", "@trpc/client": "^10.45.2", "@webstudio-is/http-client": "workspace:*", "@webstudio-is/project-migrations": "workspace:*", "@webstudio-is/protocol": "workspace:*", "acorn": "^8.14.1", "acorn-walk": "^8.3.4", "change-case": "^5.4.4", "chrome-launcher": "^1.2.1", "deepmerge": "^4.3.1", "env-paths": "^3.0.0", "fast-deep-equal": "^3.1.3", "immer": "^10.1.1", "nanoid": "^5.1.5", "p-limit": "^6.2.0", "parse5": "7.3.0", "picocolors": "^1.1.1", "reserved-identifiers": "^1.0.0", "tinyexec": "^0.3.2", "tus-js-client": "^4.3.1", "warn-once": "^0.1.1", "yargs": "^17.7.2", "zod": "^3.24.2" };
7650
- const devDependencies = { "@cloudflare/vite-plugin": "^1.1.0", "@netlify/vite-plugin-react-router": "^1.0.1", "@react-router/dev": "^7.5.3", "@react-router/fs-routes": "^7.5.3", "@remix-run/cloudflare": "^2.16.5", "@remix-run/cloudflare-pages": "^2.16.5", "@remix-run/dev": "^2.16.5", "@remix-run/node": "^2.16.5", "@remix-run/react": "^2.16.5", "@remix-run/server-runtime": "^2.16.5", "@types/react": "^18.2.70", "@types/react-dom": "^18.2.25", "@types/yargs": "^17.0.33", "@vercel/react-router": "^1.1.0", "@vitejs/plugin-react": "^4.4.1", "@webstudio-is/css-engine": "workspace:*", "@webstudio-is/image": "workspace:*", "@webstudio-is/project-build": "workspace:*", "@webstudio-is/react-sdk": "workspace:*", "@webstudio-is/sdk": "workspace:*", "@webstudio-is/sdk-components-animation": "workspace:*", "@webstudio-is/sdk-components-react": "workspace:*", "@webstudio-is/sdk-components-react-radix": "workspace:*", "@webstudio-is/sdk-components-react-remix": "workspace:*", "@webstudio-is/sdk-components-react-router": "workspace:*", "@webstudio-is/tsconfig": "workspace:*", "@webstudio-is/wsauth": "workspace:*", "h3": "^1.15.1", "ipx": "^3.0.3", "isbot": "^5.1.25", "prettier": "3.5.3", "react": "18.3.0-canary-14898b6a9-20240318", "react-dom": "18.3.0-canary-14898b6a9-20240318", "react-router": "^7.5.3", "ts-expect": "^1.3.0", "vike": "^0.4.229", "vite": "^6.3.4", "vitest": "^3.1.2", "wrangler": "^3.63.2" };
7667
+ const devDependencies = { "@cloudflare/vite-plugin": "^1.1.0", "@netlify/vite-plugin-react-router": "^1.0.1", "@react-router/dev": "^7.5.3", "@react-router/fs-routes": "^7.5.3", "@remix-run/cloudflare": "^2.16.5", "@remix-run/cloudflare-pages": "^2.16.5", "@remix-run/dev": "^2.16.5", "@remix-run/node": "^2.16.5", "@remix-run/react": "^2.16.5", "@remix-run/server-runtime": "^2.16.5", "@types/mdast": "^4.0.4", "@types/react": "^18.2.70", "@types/react-dom": "^18.2.25", "@types/yargs": "^17.0.33", "@vercel/react-router": "^1.1.0", "@vitejs/plugin-react": "^4.4.1", "@webstudio-is/css-engine": "workspace:*", "@webstudio-is/image": "workspace:*", "@webstudio-is/project-build": "workspace:*", "@webstudio-is/react-sdk": "workspace:*", "@webstudio-is/sdk": "workspace:*", "@webstudio-is/sdk-components-animation": "workspace:*", "@webstudio-is/sdk-components-react": "workspace:*", "@webstudio-is/sdk-components-react-radix": "workspace:*", "@webstudio-is/sdk-components-react-remix": "workspace:*", "@webstudio-is/sdk-components-react-router": "workspace:*", "@webstudio-is/tsconfig": "workspace:*", "@webstudio-is/wsauth": "workspace:*", "h3": "^1.15.1", "ipx": "^3.0.3", "isbot": "^5.1.25", "mdast-util-directive": "^3.1.0", "mdast-util-from-markdown": "^2.0.3", "mdast-util-to-string": "^4.0.0", "micromark-extension-directive": "^4.0.0", "prettier": "3.5.3", "react": "18.3.0-canary-14898b6a9-20240318", "react-dom": "18.3.0-canary-14898b6a9-20240318", "react-router": "^7.5.3", "ts-expect": "^1.3.0", "vike": "^0.4.229", "vite": "^6.3.4", "vitest": "^3.1.2", "wrangler": "^3.63.2" };
7651
7668
  const packageJson = {
7652
7669
  name: name$N,
7653
7670
  version,
@@ -8988,9 +9005,9 @@ const htmlToJsx = (html2) => {
8988
9005
  }
8989
9006
  return result;
8990
9007
  };
8991
- const createRemixFramework = async () => (await import("./framework-remix-B0x9qavm.js")).createFramework();
8992
- const createReactRouterFramework = async () => (await import("./framework-react-router-C6Ra_yxB.js")).createFramework();
8993
- const createVikeSsgFramework = async () => (await import("./framework-vike-ssg-CPpMMlL7.js")).createFramework();
9008
+ const createRemixFramework = async () => (await import("./framework-remix-DPrszLh-.js")).createFramework();
9009
+ const createReactRouterFramework = async () => (await import("./framework-react-router-D_ph8aB5.js")).createFramework();
9010
+ const createVikeSsgFramework = async () => (await import("./framework-vike-ssg-BvV5cdbB.js")).createFramework();
8994
9011
  const mergeJsonInto = async (sourcePath, destinationPath) => {
8995
9012
  const sourceJson = await readFile(sourcePath, "utf8");
8996
9013
  const destinationJson = await readFile(destinationPath, "utf8").catch(
@@ -10907,6 +10924,10 @@ class StdioServerTransport {
10907
10924
  });
10908
10925
  }
10909
10926
  }
10927
+ const projectBuildDocs = {
10928
+ "mcp-startup-guidance": "Before editing a Webstudio project, read `webstudio://project/guide` and `webstudio://project/tools`, or call `meta.index` and `meta.guide`. Follow the guide: read ids and Builder breakpoints first, prefer semantic tools over `apply-patch`, use direct value tools for fixed text/props, use bindings only for dynamic expressions/resources/actions, quote fixed text for expression-backed fields such as page metadata and resource URLs, put page/resource update fields under `values`, do not edit generated files for normal content/design changes, and use `preview.start` plus screenshot/vision for visual work.\n"
10929
+ };
10930
+ const readProjectBuildDoc = (name2) => projectBuildDocs[name2];
10910
10931
  const isRecord = (value2) => typeof value2 === "object" && value2 !== null;
10911
10932
  const isScreenshotBrowser = (value2) => typeof value2 === "string" && screenshotBrowserChoices.includes(value2);
10912
10933
  const getRequestParams = (request) => isRecord(request) && isRecord(request.params) ? request.params : {};
@@ -10944,13 +10965,34 @@ const getOperationInputSchema = (operation) => {
10944
10965
  properties: Object.fromEntries(
10945
10966
  operation.inputFields.map((field) => [
10946
10967
  field,
10947
- {
10948
- description: `Public API input field \`${field}\`.`
10949
- }
10968
+ getOperationInputFieldSchema(operation, field)
10950
10969
  ])
10951
10970
  )
10952
10971
  };
10953
10972
  };
10973
+ const getOperationInputFieldSchema = (operation, field) => {
10974
+ var _a3;
10975
+ const description2 = `Public API input field \`${field}\`.`;
10976
+ if (((_a3 = operation.inputFieldTypes) == null ? void 0 : _a3[field]) === "array") {
10977
+ return {
10978
+ type: "array",
10979
+ description: description2,
10980
+ items: {}
10981
+ };
10982
+ }
10983
+ return { description: description2 };
10984
+ };
10985
+ const wrapMcpRootArrayInput = (operation, input2) => {
10986
+ var _a3;
10987
+ if (Array.isArray(input2) === false || operation.inputFields.length !== 1) {
10988
+ return input2;
10989
+ }
10990
+ const [field] = operation.inputFields;
10991
+ if (field !== void 0 && ((_a3 = operation.inputFieldTypes) == null ? void 0 : _a3[field]) === "array") {
10992
+ return { [field]: input2 };
10993
+ }
10994
+ return input2;
10995
+ };
10954
10996
  const screenshotInputSchema = {
10955
10997
  ...emptyInputSchema,
10956
10998
  description: "Capture a visual screenshot for AI vision review. Pass { url } for any URL or { path } after preview.start.",
@@ -11116,6 +11158,53 @@ const mcpArgumentExamples = {
11116
11158
  text: "Launch faster"
11117
11159
  }
11118
11160
  ],
11161
+ "update-page": [
11162
+ {
11163
+ pageId: "page-id",
11164
+ values: {
11165
+ title: '"Pricing"',
11166
+ meta: {
11167
+ description: '"Pricing plans"'
11168
+ }
11169
+ }
11170
+ }
11171
+ ],
11172
+ "update-props": [
11173
+ {
11174
+ updates: [
11175
+ {
11176
+ instanceId: "button-id",
11177
+ name: "aria-label",
11178
+ type: "string",
11179
+ value: "Open menu"
11180
+ }
11181
+ ]
11182
+ }
11183
+ ],
11184
+ "bind-props": [
11185
+ {
11186
+ bindings: [
11187
+ {
11188
+ instanceId: "link-id",
11189
+ name: "href",
11190
+ binding: { type: "expression", value: "currentPost.url" }
11191
+ }
11192
+ ]
11193
+ }
11194
+ ],
11195
+ "create-resource": [
11196
+ {
11197
+ name: "Posts",
11198
+ method: "get",
11199
+ url: '"https://api.example.com/posts"'
11200
+ }
11201
+ ],
11202
+ "update-resource": [
11203
+ {
11204
+ resourceId: "resource-id",
11205
+ values: { url: '"https://api.example.com/posts"' }
11206
+ }
11207
+ ],
11119
11208
  "update-styles": [
11120
11209
  {
11121
11210
  updates: [
@@ -11127,6 +11216,11 @@ const mcpArgumentExamples = {
11127
11216
  ]
11128
11217
  }
11129
11218
  ],
11219
+ "delete-styles": [
11220
+ {
11221
+ deletions: [{ instanceId: "instance-id", property: "box-shadow" }]
11222
+ }
11223
+ ],
11130
11224
  "apply-patch": [
11131
11225
  {
11132
11226
  baseVersion: 12,
@@ -11662,12 +11756,15 @@ const filterCapabilities = (tools) => {
11662
11756
  tools: capability.tools.filter((tool) => names.has(tool))
11663
11757
  })).filter((capability) => capability.tools.length > 0);
11664
11758
  };
11759
+ const startupGuidance = readProjectBuildDoc("mcp-startup-guidance").trim();
11760
+ const valuesVsBindingsRule = 'Use direct value tools for fixed text/props. Use bindings only for dynamic expressions, parameters, resources, or actions. Expression-backed fixed strings such as page metadata and resource URLs must be quoted JavaScript string literal expressions, for example "\\"Pricing\\"". Page and resource updates put changed fields under values.';
11665
11761
  const getMetaIndex = (tools, guidance) => {
11666
11762
  const names = new Set(tools.map((tool) => tool.name));
11667
11763
  const canVerifyVisually = ["preview.start", "screenshot"].every(
11668
11764
  (tool) => names.has(tool)
11669
11765
  );
11670
11766
  return {
11767
+ readThisFirst: startupGuidance,
11671
11768
  startHere: ["meta.index", "meta.guide", "status", "permissions"].filter(
11672
11769
  (tool) => names.has(tool)
11673
11770
  ),
@@ -11681,6 +11778,7 @@ const getMetaIndex = (tools, guidance) => {
11681
11778
  "Operate on the configured project only.",
11682
11779
  "Read ids before writing.",
11683
11780
  "Prefer semantic tools over apply-patch.",
11781
+ valuesVsBindingsRule,
11684
11782
  "Use status/refresh when cached data may be stale.",
11685
11783
  guidance == null ? void 0 : guidance.visualVerificationRule
11686
11784
  ].filter((rule) => rule !== void 0),
@@ -11704,6 +11802,7 @@ const getMetaGuide = (brief, tools, guidance) => {
11704
11802
  matches.some((tool) => tool.annotations.localCapable) ? "Call refresh if cached namespaces may be stale." : void 0,
11705
11803
  "Use focused read tools to collect ids and current values.",
11706
11804
  "Use the smallest semantic mutation tool that matches the requested change.",
11805
+ valuesVsBindingsRule,
11707
11806
  "Use apply-patch only when no semantic mutation tool fits.",
11708
11807
  canVerifyVisually && guidance !== void 0 ? guidance.getVisionWorkflowSummary({ includeDiff: canDiffScreenshots }) : void 0
11709
11808
  ].filter(Boolean),
@@ -11730,7 +11829,7 @@ const getMoreTools = (brief, tools) => ({
11730
11829
  mcpExamples: tool.mcpExamples ?? [],
11731
11830
  cliRequiredOptions: tool.cliRequiredOptions ?? [],
11732
11831
  cliExamples: tool.cliExamples ?? [],
11733
- inputNote: "MCP tool arguments are public API input objects. Examples show intent, but do not imply MCP flag names.",
11832
+ inputNote: `MCP tool arguments are public API input objects. Examples show intent, but do not imply MCP flag names. ${valuesVsBindingsRule}`,
11734
11833
  annotations: tool.annotations
11735
11834
  }))
11736
11835
  });
@@ -11960,8 +12059,8 @@ const createProjectSessionMcpCore = ({
11960
12059
  guidance
11961
12060
  }) => {
11962
12061
  let session;
11963
- const operationCommands = new Set(
11964
- operations.map((operation) => operation.command)
12062
+ const operationByCommand = new Map(
12063
+ operations.map((operation) => [operation.command, operation])
11965
12064
  );
11966
12065
  const listTools = () => listProjectSessionMcpTools(operations, {
11967
12066
  includeImport: importProject2 !== void 0,
@@ -12066,12 +12165,14 @@ const createProjectSessionMcpCore = ({
12066
12165
  if (name2 === "preview.status" && getPreviewStatus !== void 0) {
12067
12166
  return toMetaResult(await getPreviewStatus());
12068
12167
  }
12069
- if (operationCommands.has(name2) === false) {
12168
+ const operation = operationByCommand.get(name2);
12169
+ if (operation === void 0) {
12070
12170
  throw new Error(`Unknown MCP tool "${name2}".`);
12071
12171
  }
12172
+ const operationInput = wrapMcpRootArrayInput(operation, input2);
12072
12173
  const envelope = await executeOperation({
12073
12174
  command: name2,
12074
- input: input2,
12175
+ input: operationInput,
12075
12176
  dryRun
12076
12177
  });
12077
12178
  return toCallResult(envelope);
@@ -12134,7 +12235,7 @@ const createProjectSessionMcpServer = async ({
12134
12235
  tools: {},
12135
12236
  resources: {}
12136
12237
  },
12137
- instructions: "Use meta.index, meta.guide, and meta.get_more_tools to discover Webstudio project capabilities. Read ids before writing and prefer semantic tools over apply-patch."
12238
+ instructions: startupGuidance
12138
12239
  }
12139
12240
  );
12140
12241
  server.setRequestHandler(ListToolsRequestSchema, async () => ({
@@ -12201,13 +12302,110 @@ const createMcpStdioTransport = async ({
12201
12302
  return new StdioServerTransport(stdin2, stdout2);
12202
12303
  };
12203
12304
  const cliDocs = {
12204
- "api-use-cases": '# CLI API Use Cases\n\n## Link/configure one project\n\nCommands:\n\n- webstudio init --link <api-share-link> --json\n\nNotes:\n\n- Writes local project id and global origin/token config.\n\n## Import synced project bundle into another project\n\nCommands:\n\n- webstudio sync\n- webstudio import --to <destination-share-link>\n- MCP tool: import {"to":"<destination-share-link>"}\n\nNotes:\n\n- Imports local `.webstudio/data.json` into the destination project.\n- Destination share link must allow build/import access.\n- Use `--skip-assets` only when asset rows and files should not be imported.\n\n## Identify current token\n\nCommands:\n\n- MCP tool: whoami {}\n\n## Check token permissions\n\nCommands:\n\n- webstudio permissions --json\n\n## Inspect project/build/version\n\nCommands:\n\n- MCP tool: inspect {}\n- MCP tool: snapshot {"include":["pages","instances","styles"]}\n\n## Discover CLI/API capabilities\n\nCommands:\n\n- webstudio schema api --json\n- webstudio man api --json\n- webstudio man llm --json\n- webstudio man mcp --json\n- MCP tool: meta.index {}\n- MCP tool: meta.guide {"brief":"Create a pricing page"}\n- MCP tool: meta.get_more_tools {"brief":"update-styles"}\n\nNotes:\n\n- Use `tools/list` for machine-readable MCP tool schemas.\n- Use `resources/list` and `resources/read` for longer MCP resources such as `webstudio://project/tools` and `webstudio://project/guide`.\n\n## Inspect and refresh MCP session cache\n\nCommands:\n\n- MCP tool: status {}\n- MCP tool: refresh {"namespaces":["pages","instances","styles"]}\n- MCP tool: reset-session {}\n\nNotes:\n\n- Use status before a task to understand the cached ProjectSession state.\n- Use refresh when project data may have changed outside the current MCP session.\n- Use reset-session when local cached state is corrupt or incompatible.\n\n## Visually verify rendered work with AI vision\n\nCommands:\n\n- MCP tool: preview.start {"host":"127.0.0.1","port":5173}\n- MCP tool: preview.status {}\n- MCP tool: screenshot {"path":"/","output":"current.png","viewport":{"width":1440,"height":900},"waitUntil":"load","waitForTimeout":250}\n- MCP tool: screenshot.diff {"baselinePath":"before.png","currentPath":"current.png","outputDir":".webstudio/screenshots"}\n- MCP tool: vision.install-ocr {"confirm":true}\n\nNotes:\n\n- Use this after page/content/style mutations and after generated project files are current so a vision-capable AI can see what was actually built.\n- Use waitForSelector when the rendered app has a reliable ready marker, waitUntil:"networkidle" for network-heavy pages, and waitForTimeout only for final visual settling.\n- For a fresh checkout, copied fixture, or newly generated app, run npm install or pnpm install in the generated project before preview.start or webstudio preview.\n- If preview fails with a missing generated-app command/package such as react-router or vite, install the generated app dependencies and retry.\n- When a baseline exists, use screenshot.diff to get changed regions, OCR textAnalysis, and diff artifact paths before deciding whether the result matches.\n- If screenshot.diff reports OCR unavailable and the user agrees to install it, call vision.install-ocr {"confirm":true}; otherwise continue with pixel diff and visual inspection.\n- Compare the PNG, OCR text evidence, and diff artifacts against the user\'s intent for layout, typography, colors, spacing, imagery, and responsive framing; then iterate with focused mutations.\n- Root CLI equivalent: webstudio preview --template ssg, then webstudio screenshot <url> --output current.png.\n\n## List pages\n\nCommands:\n\n- MCP tool: list-pages {"includeFolders":true}\n\n## Read page by id\n\nCommands:\n\n- MCP tool: get-page {"pageId":"<pageId>"}\n\n## Read page by path\n\nCommands:\n\n- MCP tool: get-page-by-path {"path":"/pricing"}\n\n## Create page\n\nCommands:\n\n- MCP tool: create-page {"name":"Pricing","path":"/pricing"}\n\n## Update page settings/metadata\n\nCommands:\n\n- MCP tool: update-page {"pageId":"<pageId>","title":"Pricing","description":"Plans","status":"200"}\n- MCP tool: update-page {"pageId":"<pageId>","auth":{"login":"<login>","password":"<password>"}}\n\n## Read project settings\n\nCommands:\n\n- MCP tool: get-project-settings {}\n\n## Update project settings\n\nCommands:\n\n- MCP tool: update-project-settings {"settings":"project-settings.json contents"}\n\n## List redirects\n\nCommands:\n\n- MCP tool: list-redirects {}\n\n## Create redirect\n\nCommands:\n\n- MCP tool: create-redirect {"oldPath":"/old","newPath":"/new","status":301}\n\n## Update redirect\n\nCommands:\n\n- MCP tool: update-redirect {"oldPath":"/old","newPath":"/newer","status":302}\n- MCP tool: update-redirect {"oldPath":"/old","status":null}\n\n## Delete redirect\n\nCommands:\n\n- MCP tool: delete-redirect {"oldPath":"/old"}\n\n## List breakpoints\n\nCommands:\n\n- MCP tool: list-breakpoints {}\n\n## Create breakpoint\n\nCommands:\n\n- MCP tool: create-breakpoint {"breakpointId":"tablet","label":"Tablet","maxWidth":991}\n\n## Update breakpoint\n\nCommands:\n\n- MCP tool: update-breakpoint {"breakpointId":"tablet","label":"Tablet","maxWidth":1023}\n- MCP tool: update-breakpoint {"breakpointId":"tablet","condition":null,"minWidth":768}\n- MCP tool: update-breakpoint {"breakpointId":"tablet","minWidth":null,"maxWidth":null,"condition":"(hover: hover)"}\n\n## Delete breakpoint\n\nCommands:\n\n- MCP tool: delete-breakpoint {"breakpointId":"tablet","confirm":true}\n\n## Duplicate page\n\nCommands:\n\n- MCP tool: duplicate-page {"pageId":"<pageId>","name":"Pricing Copy","path":"/pricing-copy"}\n\n## List page templates\n\nCommands:\n\n- MCP tool: list-page-templates {}\n\n## Create page from template\n\nCommands:\n\n- MCP tool: create-page-from-template {"templateId":"<templateId>","name":"Landing","path":"/landing"}\n\n## Delete page\n\nCommands:\n\n- MCP tool: delete-page {"pageId":"<pageId>"}\n\n## List folders\n\nCommands:\n\n- MCP tool: list-folders {"includePages":true}\n\n## Create folder\n\nCommands:\n\n- MCP tool: create-folder {"name":"Blog","slug":"blog"}\n\n## Update folder\n\nCommands:\n\n- MCP tool: update-folder {"folderId":"<folderId>","name":"Blog","slug":"blog"}\n\n## Delete folder\n\nCommands:\n\n- MCP tool: delete-folder {"folderId":"<folderId>"}\n\n## List element instances\n\nCommands:\n\n- MCP tool: list-instances {"pagePath":"/","maxDepth":3}\n\n## Inspect one element instance\n\nCommands:\n\n- MCP tool: inspect-instance {"instanceId":"<instanceId>","include":["props","styles","children"]}\n\n## Append/prepend/replace child elements\n\nCommands:\n\n- MCP tool: append-instance {"parentInstanceId":"<instanceId>","children":"children.json contents"}\n\n## Move elements\n\nCommands:\n\n- MCP tool: move-instance {"moves":"moves.json contents"}\n\n## Clone element subtree\n\nCommands:\n\n- MCP tool: clone-instance {"sourceInstanceId":"<instanceId>","parentInstanceId":"<targetParentId>"}\n\n## Delete element subtree\n\nCommands:\n\n- MCP tool: delete-instance {"instanceId":"<instanceId>"}\n\n## List text/expression children\n\nCommands:\n\n- MCP tool: list-texts {"pagePath":"/"}\n\n## Update text child\n\nCommands:\n\n- MCP tool: update-text {"instanceId":"<instanceId>","childIndex":0,"text":"Launch faster"}\n\n## Update props\n\nCommands:\n\n- MCP tool: update-props {"updates":"props.json contents"}\n\n## Delete props\n\nCommands:\n\n- MCP tool: delete-props {"deletions":"props.json contents"}\n\n## Bind props to expressions/resources/actions\n\nCommands:\n\n- MCP tool: bind-props {"bindings":"bindings.json contents"}\n\n## Read styles\n\nCommands:\n\n- MCP tool: get-styles {"instanceId":"<instanceId>","includeTokens":true}\n\n## Update local styles\n\nCommands:\n\n- MCP tool: update-styles {"updates":"styles.json contents"}\n\n## Delete local styles\n\nCommands:\n\n- MCP tool: delete-styles {"deletions":"styles.json contents"}\n\n## Replace matching style values\n\nCommands:\n\n- MCP tool: replace-styles {"replacements":"replace.json contents"}\n\n## List design tokens\n\nCommands:\n\n- MCP tool: list-design-tokens {"withUsage":true}\n\n## Create design tokens\n\nCommands:\n\n- MCP tool: create-design-token {"tokens":"tokens.json contents"}\n\n## Update design token styles\n\nCommands:\n\n- MCP tool: update-design-token-styles {"styleSourceId":"<tokenId>","updates":"styles.json contents"}\n\n## Delete design token styles\n\nCommands:\n\n- MCP tool: delete-design-token-styles {"styleSourceId":"<tokenId>","deletions":"styles.json contents"}\n\n## Attach design token to instances\n\nCommands:\n\n- MCP tool: attach-design-token {"styleSourceId":"<tokenId>","instanceIds":"instances.json contents"}\n\n## Detach design token from instances\n\nCommands:\n\n- MCP tool: detach-design-token {"styleSourceId":"<tokenId>","instanceIds":"instances.json contents"}\n\n## Extract design token from local styles\n\nCommands:\n\n- MCP tool: extract-design-token {"token":"token.json contents"}\n\n## List CSS variables\n\nCommands:\n\n- MCP tool: list-css-variables {"withUsage":true}\n\n## Define CSS variables\n\nCommands:\n\n- MCP tool: define-css-variable {"variables":"vars.json contents"}\n\n## Delete CSS variables\n\nCommands:\n\n- MCP tool: delete-css-variable {"names":"names.json contents","confirm":true}\n\n## Rewrite CSS variable references\n\nCommands:\n\n- MCP tool: rewrite-css-variable-refs {"variables":"variables.json contents"}\n\n## List data variables\n\nCommands:\n\n- MCP tool: list-variables {}\n\n## Create data variable\n\nCommands:\n\n- MCP tool: create-variable {"scopeInstanceId":"<instanceId>","name":"title","value":{"type":"string","value":"Hello"}}\n\n## Update data variable\n\nCommands:\n\n- MCP tool: update-variable {"variableId":"<variableId>","value":{"type":"json","value":{"count":1}}}\n\n## Delete data variable\n\nCommands:\n\n- MCP tool: delete-variable {"variableId":"<variableId>"}\n\n## List resources\n\nCommands:\n\n- MCP tool: list-resources {}\n\n## Create resource\n\nCommands:\n\n- MCP tool: create-resource {"name":"Posts","method":"get","url":"https://api.example.com/posts"}\n\n## Update resource\n\nCommands:\n\n- MCP tool: update-resource {"resourceId":"<resourceId>","url":"https://api.example.com/posts"}\n\n## Delete resource\n\nCommands:\n\n- MCP tool: delete-resource {"resourceId":"<resourceId>"}\n\n## List assets\n\nCommands:\n\n- MCP tool: list-assets {"withUsage":true}\n\n## Upload one asset\n\nCommands:\n\n- MCP tool: upload-asset {"asset":"asset.json contents","assetsDir":".webstudio/assets"}\n\n## Upload asset batch\n\nCommands:\n\n- MCP tool: upload-assets {"assets":"assets.json contents","assetsDir":".webstudio/assets"}\n\n## Find asset usage\n\nCommands:\n\n- MCP tool: find-asset-usage {"assetId":"<assetId>"}\n\n## Replace asset references\n\nCommands:\n\n- MCP tool: replace-asset {"fromAssetId":"<oldAssetId>","toAssetId":"<newAssetId>","confirm":true}\n\n## Delete assets\n\nCommands:\n\n- MCP tool: delete-asset {"assetId":"<assetId>","confirm":true}\n\n## Publish project\n\nCommands:\n\n- webstudio publish deploy --target production --json\n\n## List publishes\n\nCommands:\n\n- webstudio publish list --json\n\n## Check publish job\n\nCommands:\n\n- webstudio publish status --job <buildId> --json\n\n## Unpublish\n\nCommands:\n\n- webstudio publish unpublish --target production --confirm --json\n\n## List domains\n\nCommands:\n\n- webstudio domains list --json\n\n## Create domain\n\nCommands:\n\n- webstudio domains create --domain example.com --json\n\n## Update domain\n\nCommands:\n\n- webstudio domains update --domain-id <domainId> --domain www.example.com --json\n\n## Delete domain\n\nCommands:\n\n- webstudio domains delete --domain-id <domainId> --confirm --json\n\n## Verify domain\n\nCommands:\n\n- webstudio domains verify --domain-id <domainId> --json\n\n## Make arbitrary store-level changes\n\nCommands:\n\n- MCP tool: inspect {}\n- MCP tool: snapshot {"include":["<namespace>"]}\n- MCP tool: apply-patch {"baseVersion":"<version>","transactions":"patch.json contents"}\n\nNotes:\n\n- Use only when no semantic command exists.\n\n## Manage marketplace metadata\n\nCommands:\n\n- MCP tool: snapshot {"include":["marketplaceProduct"]}\n- MCP tool: apply-patch {"baseVersion":"<version>","transactions":"patch.json contents"}\n\nPatch namespaces:\n\n- marketplaceProduct\n\n## Search and inspect safely\n\nCommands:\n\n- MCP tool: list-instances {"pagePath":"/","maxDepth":5}\n- MCP tool: inspect-instance {"instanceId":"<instanceId>","include":["props","styles","children"]}\n- MCP tool: list-texts {"pagePath":"/"}\n- MCP tool: list-assets {"withUsage":true}\n- MCP tool: find-asset-usage {"assetId":"<assetId>"}\n- MCP tool: snapshot {"include":["pages","instances","props","resources","assets"]}\n\nNotes:\n\n- Use this for finding elements by label, type, href/resource patterns, HTML snippets, missing accessibility metadata, or asset usage.\n\n## Refactor targeted content\n\nCommands:\n\n- MCP tool: list-instances {"pagePath":"/"}\n- MCP tool: list-texts {"pagePath":"/"}\n- MCP tool: update-text {"instanceId":"<instanceId>","childIndex":0,"text":"Launch faster"}\n- MCP tool: update-props {"updates":"props.json contents"}\n- MCP tool: update-page {"pageId":"<pageId>","title":"Pricing","description":"Plans"}\n- MCP tool: update-resource {"resourceId":"<resourceId>","url":"https://api.example.com/posts"}\n- MCP tool: replace-asset {"fromAssetId":"<oldAssetId>","toAssetId":"<newAssetId>","confirm":true}\n- MCP tool: replace-styles {"replacements":"replace.json contents"}\n- MCP tool: rewrite-css-variable-refs {"variables":"variables.json contents"}\n\nNotes:\n\n- Use focused reads first, then mutate only matching instances, props, metadata, resource URLs, assets, or style references.\n\n## Optimize existing project\n\nCommands:\n\n- MCP tool: list-pages {"includeFolders":true}\n- MCP tool: update-page {"pageId":"<pageId>","title":"Pricing","description":"Plans"}\n- MCP tool: update-props {"updates":"props.json contents"}\n- MCP tool: list-breakpoints {}\n- MCP tool: update-breakpoint {"breakpointId":"tablet","maxWidth":1023}\n- MCP tool: get-styles {"instanceId":"<instanceId>","includeTokens":true}\n- MCP tool: update-styles {"updates":"styles.json contents"}\n- MCP tool: attach-design-token {"styleSourceId":"<tokenId>","instanceIds":"instances.json contents"}\n- MCP tool: update-project-settings {"settings":"project-settings.json contents"}\n\nNotes:\n\n- Use this for SEO metadata, accessibility labels, responsive behavior, token consistency, and project settings.\n\n## Connect external data\n\nCommands:\n\n- MCP tool: create-variable {"scopeInstanceId":"<instanceId>","name":"title","value":{"type":"string","value":"Hello"}}\n- MCP tool: create-resource {"name":"Posts","method":"get","url":"https://api.example.com/posts"}\n- MCP tool: update-resource {"resourceId":"<resourceId>","url":"https://api.example.com/posts"}\n- MCP tool: bind-props {"bindings":"bindings.json contents"}\n- MCP tool: append-instance {"parentInstanceId":"<instanceId>","children":"children.json contents"}\n\nNotes:\n\n- Use this for CMS sections, blog listings, Ghost/headless CMS pages, n8n-style integrations, and API URLs built from variables.\n\n## Support dynamic runtime behavior\n\nCommands:\n\n- MCP tool: append-instance {"parentInstanceId":"<instanceId>","children":"children.json contents"}\n- MCP tool: update-props {"updates":"props.json contents"}\n- MCP tool: bind-props {"bindings":"bindings.json contents"}\n- MCP tool: create-resource {"name":"Seats","method":"get","url":"https://api.example.com/seats"}\n- MCP tool: snapshot {"include":["instances","props","resources"]}\n- MCP tool: apply-patch {"baseVersion":"<version>","transactions":"patch.json contents"}\n\nNotes:\n\n- Use existing scripts/resources for behavior, then move presentational structure into editable Webstudio instances where possible.\n- There is no dedicated semantic command yet for converting script-generated UI into editable Webstudio structure.\n\n## Build authenticated pages\n\nCommands:\n\n- MCP tool: create-page {"name":"Account","path":"/account"}\n- MCP tool: update-page {"pageId":"<pageId>","auth":{"login":"<login>","password":"<password>"}}\n- MCP tool: create-resource {"name":"Session","method":"get","url":"https://api.example.com/session"}\n- MCP tool: create-variable {"scopeInstanceId":"<instanceId>","name":"user","value":{"type":"json","value":{}}}\n- MCP tool: update-props {"updates":"props.json contents"}\n- MCP tool: bind-props {"bindings":"bindings.json contents"}\n\nNotes:\n\n- Basic auth is semantic today. Provider-specific Supabase/Firebase setup still requires manual resources, props, embeds, or patches.\n\n## Generate from design input\n\nCommands:\n\n- MCP tool: create-page {"name":"Landing","path":"/landing"}\n- MCP tool: create-design-token {"tokens":"tokens.json contents"}\n- MCP tool: define-css-variable {"variables":"vars.json contents"}\n- MCP tool: append-instance {"parentInstanceId":"<instanceId>","children":"children.json contents"}\n- MCP tool: update-styles {"updates":"styles.json contents"}\n- MCP tool: preview.start {"host":"127.0.0.1","port":5173}\n- MCP tool: screenshot {"path":"/","output":"current.png","viewport":{"width":1440,"height":900},"waitUntil":"load","waitForTimeout":250}\n\nNotes:\n\n- Use this after external design interpretation. There is no dedicated import command for Figma, screenshots, Inception output, or design.md yet.\n\n## Cross-project maintenance\n\nCommands:\n\n- webstudio init --link <api-share-link> --json\n- webstudio permissions --json\n- webstudio mcp\n\nNotes:\n\n- Public API and CLI intentionally operate on one configured project at a time. Use an external script to loop over projects.\n\n# Known CLI Gaps\n\n## General project search and audit\n\nMissing:\nNo single semantic command searches across instance labels, props, hrefs, resource URLs, HTML embeds, asset references, and missing accessibility metadata.\n\nCurrent fallback:\nUse focused MCP reads such as list-instances, list-texts, list-assets, find-asset-usage, and snapshot.\n\nSuggested commands:\n\n- search-project\n- audit-accessibility\n- find-prop-usage\n\n## Save and manage page templates\n\nMissing:\nCLI can list page templates and create pages from existing templates, but cannot save a page as a template or update/delete templates semantically.\n\nCurrent fallback:\nUse MCP snapshot and apply-patch only when the template data model is understood.\n\nSuggested commands:\n\n- create-page-template\n- update-page-template\n- delete-page-template\n\n## Semantic marketplace metadata\n\nMissing:\nMarketplace metadata is only available through MCP snapshot/apply-patch, not dedicated semantic commands.\n\nCurrent fallback:\nUse MCP snapshot --include marketplaceProduct and apply-patch.\n\nSuggested commands:\n\n- get-marketplace\n- update-marketplace\n\n## Provider-specific authenticated pages\n\nMissing:\nCLI supports page basic auth and generic resources/props/embeds, but not guided Supabase/Firebase auth setup.\n\nCurrent fallback:\nCreate the page, resources, variables, props, and embeds manually with existing MCP semantic tools.\n\nSuggested commands:\n\n- setup-auth-page\n\n## Dynamic script/runtime integration helpers\n\nMissing:\nCLI can manipulate props/resources/embeds, but has no semantic workflow for converting script-generated UI into editable Webstudio structures.\n\nCurrent fallback:\nUse MCP append-instance, props, resources, and raw patch where necessary.\n\nSuggested commands:\n\n- integrate-runtime-ui\n\n## Generate from design input\n\nMissing:\nNo command imports Figma, screenshots, Inception output, or design.md and turns it into pages/tokens/layout.\n\nCurrent fallback:\nUse external generation, then apply semantic CLI commands or apply-patch.\n\nSuggested commands:\n\n- generate-from-design\n\n## Built-in cross-project maintenance\n\nMissing:\nPublic API and CLI intentionally operate on one configured project at a time; there is no built-in multi-project discovery or loop runner.\n\nCurrent fallback:\nRun the CLI from an external script that reconfigures one project/session at a time.\n\nSuggested commands:\n\n- none\n',
12205
- "manual-api": '# Webstudio API CLI Manual\n\nThe API commands operate on the single project configured by:\n\n- .webstudio/config.json: projectId\n- global Webstudio config: origin and token\n\nRules:\n\n- Always pass --json.\n- Never pass a project id. Commands use configured project only.\n- Read ids before writing. Do not invent ids for existing records.\n- stdout is one JSON object. stderr is diagnostics.\n- Prefer MCP semantic tools for detailed project edits. Use MCP apply-patch only when no semantic tool exists.\n\n## Start\n\n{{start}}\n\n## Read First\n\n{{readFirst}}\n\n## Project Session Cache\n\n- CLI commands use one local ProjectSession snapshot for the configured project.\n- Local-capable reads use cached namespaces when compatible and fetch only missing or stale namespaces.\n- Local-capable mutations build patches from the local snapshot, then commit with the cached build version.\n- Successful mutation commits update the local snapshot only after the remote commit succeeds.\n- Server-only commands run remotely and invalidate/refetch namespaces declared by the operation catalog.\n- Use --refresh on local-capable commands to refresh required namespaces before running.\n- Successful JSON responses include meta.session with operationId, buildId, version, source, committed, compatibility, namespace freshness, and diagnostics.\n\n## CLI Capability Inventory\n\n### Top-Level Commands\n\n{{topLevelCapabilityIndex}}\n\n### High-Level API Commands By Area\n\n{{apiCapabilityIndex}}\n\n### MCP-Only Operations\n\nThese are intentionally exposed through `webstudio mcp`, not as top-level shell commands:\n\n{{mcpOnlyCommandIndex}}\n\n## Task Recipes\n\n{{taskRecipeIndex}}\n\n## Use Case Index\n\n{{useCaseIndex}}\n\n## Known CLI Gaps\n\n{{knownCliGapIndex}}\n\n## Input File Shapes\n\n{{inputFileShapeIndex}}\n\n## Raw Patch Fallback\n\napply-patch accepts either BuildPatchTransaction[] or { "transactions": BuildPatchTransaction[] }.\n\nEach transaction has:\n\n{\n"id": "unique-client-transaction-id",\n"payload": [\n{\n"namespace": "pages",\n"patches": [\n{ "op": "replace", "path": ["meta", "siteName"], "value": "New Site" }\n]\n}\n]\n}\n\nPatch paths are JSON-patch-like paths into Builder store data. Map-like namespaces use ids as the first path item.\n\nSupported namespaces:\n\n- pages: site metadata, redirects, page records, folders, compiler settings\n- instances: element instances and children, including text/expression children\n- props: element props, bindings, page references, resource bindings\n- styles: CSS declarations keyed by style declaration key\n- styleSources: local style sources and reusable design tokens\n- styleSourceSelections: instance-to-style-source connections\n- dataSources: data variables, parameters, and resource data sources\n- resources: data resource definitions\n- assets: project asset records handled by the existing asset patch path\n- breakpoints: responsive breakpoints\n- marketplaceProduct: marketplace metadata\n\nCommit raw patch:\n\nMCP tool: apply-patch\n\n## Raw Patch Examples\n\nRename the site:\n\n[\n{\n"id": "tx-site-name",\n"payload": [\n{\n"namespace": "pages",\n"patches": [\n{ "op": "add", "path": ["meta", "siteName"], "value": "Acme Studio" }\n]\n}\n]\n}\n]\n\nUpdate page title metadata:\n\n[\n{\n"id": "tx-page-title",\n"payload": [\n{\n"namespace": "pages",\n"patches": [\n{ "op": "replace", "path": ["pages", "page-id", "meta", "title"], "value": "Pricing" }\n]\n}\n]\n}\n]\n\nUpdate a text child on an element:\n\n[\n{\n"id": "tx-text",\n"payload": [\n{\n"namespace": "instances",\n"patches": [\n{ "op": "replace", "path": ["instance-id", "children", 0, "value"], "value": "Launch faster" }\n]\n}\n]\n}\n]\n\nCreate a data variable:\n\n[\n{\n"id": "tx-variable",\n"payload": [\n{\n"namespace": "dataSources",\n"patches": [\n{\n"op": "add",\n"path": ["variable-id"],\n"value": {\n"type": "variable",\n"id": "variable-id",\n"scopeInstanceId": "instance-id",\n"name": "headline",\n"value": { "type": "string", "value": "Launch faster" }\n}\n}\n]\n}\n]\n}\n]\n\nCreate a design token:\n\n[\n{\n"id": "tx-token",\n"payload": [\n{\n"namespace": "styleSources",\n"patches": [\n{ "op": "add", "path": ["token-id"], "value": { "type": "token", "id": "token-id", "name": "Brand Primary" } }\n]\n},\n{\n"namespace": "styles",\n"patches": [\n{\n"op": "add",\n"path": ["token-id:base:color:"],\n"value": {\n"styleSourceId": "token-id",\n"breakpointId": "base",\n"property": "color",\n"value": { "type": "keyword", "value": "red" }\n}\n}\n]\n}\n]\n}\n]\n\n## Safety Rules\n\n- For MCP apply-patch, read the latest version with MCP snapshot before writing.\n- Reuse ids from MCP snapshot output when updating existing records.\n- Generate new unique ids when adding records.\n- If apply-patch reports a version conflict, read the latest build and regenerate the patch.\n- Prefer semantic MCP read tools for discovery, then use MCP snapshot for exact patch paths.\n\n## Command Index\n\n{{commandIndex}}\n',
12206
- "manual-llm": "# Webstudio CLI Manual for LLMs\n\nUse this order. Stop only when a command returns ok:false.\n\n## Always\n\n1. webstudio permissions --json\n2. webstudio mcp\n3. Read MCP resource webstudio://project/tools.\n4. Pick focused MCP read tool.\n5. Pick semantic MCP write tool.\n\n## Pick Read Command\n\n{{readFirst}}\n\n## Pick Write Command\n\n{{taskRecipeIndex}}\n\n## Raw Patch Only If Needed\n\n1. Use MCP tool: snapshot.\n2. Write BuildPatchTransaction[].\n3. Use MCP tool: apply-patch.\n\n## MCP Argument Examples\n\nMCP tools receive JSON argument objects, not CLI flags. Use these shapes:\n\n{{mcpArgumentExampleIndex}}\n\n## Rules\n\n- Never guess ids for existing records. Read them first.\n- Never use project ids from user input. Commands use the configured project.\n- Use --refresh before a local-capable command when cached data may be stale.\n- On VERSION_CONFLICT, read MCP snapshot again, regenerate the patch, then retry.\n- Treat stdout JSON as the API contract and stderr as diagnostics.\n- Confirm destructive commands with --confirm only when user requested deletion/unpublish/replacement.\n- Use webstudio schema api --json for machine-readable command metadata.\n\n## Known Gaps\n\n{{knownCliGapIndex}}\n",
12207
- "manual-mcp": "# Webstudio MCP Manual\n\n`webstudio mcp` starts a stdio MCP server for the configured project.\n\n## Startup\n\n1. Configure a project with `webstudio init --link <api-share-link> --json`.\n2. Check capabilities with `webstudio permissions --json`.\n3. Start the server with `webstudio mcp`.\n\nWhile the server is running, stdout is reserved for MCP JSON-RPC messages. Do not print human text from the server process.\n\n## Discovery\n\nUse MCP itself after startup:\n\n- `tools/list`: machine-readable available tools\n- `resources/list`: available longer JSON resources\n- `meta.index`: concise capability catalog\n- `meta.guide`: workflow for a user goal\n- `meta.get_more_tools`: detailed params, examples, namespaces, and local/server behavior\n\nUseful resources:\n\n- `webstudio://project/status`: current ProjectSession status\n- `webstudio://project/tools`: operation catalog\n- `webstudio://project/guide`: concise discovery guide\n\n## Core Rules\n\n- Operate on the configured project only.\n- Read ids before writing.\n- Prefer semantic tools over `apply-patch`.\n- Use `status` and `refresh` when cached namespaces may be stale.\n- A mutation is durable only when `meta.session.committed` is true.\n- For visual/design work, verify the rendered result with vision before finishing.\n\n## Vision Verification Loop\n\nVision-capable AI can use MCP to see what it is building:\n\n{{mcpVisionVerificationLoopMarkdown}}\n\nGenerated app setup:\n\n{{mcpGeneratedAppDependencyNotes}}\n\n## MCP Argument Examples\n\nMCP tools receive JSON argument objects:\n\n{{mcpArgumentExampleIndex}}\n\n## Screenshot Verification\n\n{{screenshotVerificationSummary}}\n",
12208
- "mcp-vision": '# MCP Vision Verification\n\n## Generated App Dependency Notes\n\n- For a fresh checkout, copied fixture, or newly generated app, run npm install or pnpm install in the generated project before preview.start or webstudio preview.\n- If preview fails with a missing generated-app command/package such as react-router or vite, install the generated app dependencies and retry.\n\n## Visual Verification Rule\n\nFor visual/design work, use preview.start and screenshot after generated project files are current and generated app dependencies are installed so vision can inspect the rendered result before finishing. When a baseline exists, use screenshot.diff to get pixel regions, OCR text changes, and diff PNG artifacts.\n\n## Vision Verification Loop\n\n- Make focused page/content/style changes with semantic MCP tools.\n- Make sure generated project files are current and generated app dependencies are installed, then call preview.start once to keep the generated site running.\n- {{dependency-notes}}\n- Call screenshot with { path: "/" } or the changed page path. Use waitForSelector when the page has a reliable ready marker, waitUntil:"networkidle" for network-heavy pages, and waitForTimeout only for final visual settling.\n- {{diff}} When a baseline PNG exists, call screenshot.diff with baselinePath, currentPath, and outputDir.\n- {{diff}} Read screenshot.diff textAnalysis: it reports OCR status plus text that appeared, disappeared, moved, changed content, or changed font/style geometry. If OCR is unavailable, ask the user for permission to install Tesseract, then call vision.install-ocr with { "confirm": true }, or rely on visual inspection.\n- Inspect the PNG and any diff artifacts with vision, then compare layout, OCR text evidence, color, spacing, imagery, and responsive framing against the user intent.\n- If the screenshot does not match, apply another focused mutation and repeat screenshot verification.\n\n## Workflow Summary With Diff\n\nFor visual/design work, make sure generated project files are current and generated app dependencies are installed, call preview.start, then screenshot({ path }); use screenshot.diff when a baseline exists, then inspect pixel regions, OCR textAnalysis, and PNG/diff artifacts with vision before finishing.\n\n## Workflow Summary Without Diff\n\nFor visual/design work, make sure generated project files are current and generated app dependencies are installed, call preview.start, then screenshot({ path }); inspect the PNG with vision before finishing.\n\n## Screenshot Verification Summary\n\nInside MCP, prefer preview.start plus screenshot({ path: "/" }) after generated project files are current and generated app dependencies are installed, so the preview server stays running for fast repeated checks. Screenshot waits for load by default, then fonts and two layout frames; pass waitForSelector for app readiness, waitUntil:"networkidle" for network-heavy pages, and waitForTimeout for final settling. When a baseline exists, use screenshot.diff for changed regions, OCR textAnalysis, and diff artifacts. Outside MCP, use webstudio preview and webstudio screenshot <url> --output current.png.\n\n## Screenshot Diff Evidence\n\n- Pixel evidence: total mismatch, changed regions, dominant color/luminance direction, diffPath, and contextDiffPath.\n- OCR evidence: textAnalysis.status, provider, and changes for appeared/disappeared/content_changed/moved/font_changed text.\n- OCR dependency: screenshot.diff uses the system tesseract binary when available. If missing, it returns ocr_unavailable_tesseract_not_found_or_failed and still returns pixel evidence.\n- OCR install: MCP cannot prompt. Ask the user first; if they agree, call vision.install-ocr with { "confirm": true }. If automatic install is unavailable, follow the returned installUrl.\n- Final judgment: OCR and pixel diff are evidence. A vision-capable model must still inspect screenshots/diff artifacts and compare the rendered result to user intent.\n'
12305
+ "api-use-cases": '# CLI API Use Cases\n\n## Link/configure one project\n\nCommands:\n\n- webstudio init --link <api-share-link> --json\n\nNotes:\n\n- Writes local project id and global origin/token config.\n\n## Import synced project bundle into another project\n\nCommands:\n\n- webstudio sync\n- webstudio import --to <destination-share-link>\n- MCP tool: import {"to":"<destination-share-link>"}\n\nNotes:\n\n- Imports local `.webstudio/data.json` into the destination project.\n- Destination share link must allow build/import access.\n- Use `--skip-assets` only when asset rows and files should not be imported.\n\n## Identify current token\n\nCommands:\n\n- MCP tool: whoami {}\n\n## Check token permissions\n\nCommands:\n\n- webstudio permissions --json\n\n## Inspect project/build/version\n\nCommands:\n\n- MCP tool: inspect {}\n- MCP tool: snapshot {"include":["pages","instances","styles"]}\n\n## Discover CLI/API capabilities\n\nCommands:\n\n- webstudio schema api --json\n- webstudio man api --json\n- webstudio man llm --json\n- webstudio man mcp --json\n- MCP tool: meta.index {}\n- MCP tool: meta.guide {"brief":"Create a pricing page"}\n- MCP tool: meta.get_more_tools {"brief":"update-styles"}\n\nNotes:\n\n- Use `tools/list` for machine-readable MCP tool schemas.\n- Use `resources/list` and `resources/read` for longer MCP resources such as `webstudio://project/tools` and `webstudio://project/guide`.\n\n## Inspect and refresh MCP session cache\n\nCommands:\n\n- MCP tool: status {}\n- MCP tool: refresh {"namespaces":["pages","instances","styles"]}\n- MCP tool: reset-session {}\n\nNotes:\n\n- Use status before a task to understand the cached ProjectSession state.\n- Use refresh when project data may have changed outside the current MCP session.\n- Use reset-session when local cached state is corrupt or incompatible.\n\n## Visually verify rendered work with AI vision\n\nCommands:\n\n- MCP tool: preview.start {"host":"127.0.0.1","port":5173}\n- MCP tool: preview.status {}\n- MCP tool: screenshot {"path":"/","output":"current.png","viewport":{"width":1440,"height":900},"waitUntil":"load","waitForTimeout":250}\n- MCP tool: screenshot.diff {"baselinePath":"before.png","currentPath":"current.png","outputDir":".webstudio/screenshots"}\n- MCP tool: vision.install-ocr {"confirm":true}\n\nNotes:\n\n- Use this after page/content/style mutations and after generated project files are current so a vision-capable AI can see what was actually built.\n- Use waitForSelector when the rendered app has a reliable ready marker, waitUntil:"networkidle" for network-heavy pages, and waitForTimeout only for final visual settling.\n- For a fresh checkout, copied fixture, or newly generated app, run npm install or pnpm install in the generated project before preview.start or webstudio preview.\n- If preview fails with a missing generated-app command/package such as react-router or vite, install the generated app dependencies and retry.\n- When a baseline exists, use screenshot.diff to get changed regions, OCR textAnalysis, and diff artifact paths before deciding whether the result matches.\n- If screenshot.diff reports OCR unavailable and the user agrees to install it, call vision.install-ocr {"confirm":true}; otherwise continue with pixel diff and visual inspection.\n- Compare the PNG, OCR text evidence, and diff artifacts against the user\'s intent for layout, typography, colors, spacing, imagery, and responsive framing; then iterate with focused mutations.\n- Root CLI equivalent: webstudio preview --template ssg, then webstudio screenshot <url> --output current.png.\n\n## List pages\n\nCommands:\n\n- MCP tool: list-pages {"includeFolders":true}\n\n## Read page by id\n\nCommands:\n\n- MCP tool: get-page {"pageId":"<pageId>"}\n\n## Read page by path\n\nCommands:\n\n- MCP tool: get-page-by-path {"path":"/pricing"}\n\n## Create page\n\nCommands:\n\n- MCP tool: create-page {"name":"Pricing","path":"/pricing"}\n\n## Update page settings/metadata\n\nCommands:\n\n- MCP tool: update-page {"pageId":"<pageId>","values":{"title":"\\"Pricing\\"","meta":{"description":"\\"Plans\\"","status":"200"}}}\n- MCP tool: update-page {"pageId":"<pageId>","values":{"meta":{"auth":{"login":"<login>","password":"<password>"}}}}\n\nNotes:\n\n- Page title and metadata text fields are expression-backed. For fixed text, send a quoted JavaScript string literal expression such as `"\\"Pricing\\""`.\n\n## Read project settings\n\nCommands:\n\n- MCP tool: get-project-settings {}\n\n## Update project settings\n\nCommands:\n\n- MCP tool: update-project-settings {"settings":"project-settings.json contents"}\n\n## List redirects\n\nCommands:\n\n- MCP tool: list-redirects {}\n\n## Create redirect\n\nCommands:\n\n- MCP tool: create-redirect {"oldPath":"/old","newPath":"/new","status":301}\n\n## Update redirect\n\nCommands:\n\n- MCP tool: update-redirect {"oldPath":"/old","newPath":"/newer","status":302}\n- MCP tool: update-redirect {"oldPath":"/old","status":null}\n\n## Delete redirect\n\nCommands:\n\n- MCP tool: delete-redirect {"oldPath":"/old"}\n\n## List breakpoints\n\nCommands:\n\n- MCP tool: list-breakpoints {}\n\n## Create breakpoint\n\nCommands:\n\n- MCP tool: create-breakpoint {"breakpointId":"tablet","label":"Tablet","maxWidth":991}\n\n## Update breakpoint\n\nCommands:\n\n- MCP tool: update-breakpoint {"breakpointId":"tablet","label":"Tablet","maxWidth":1023}\n- MCP tool: update-breakpoint {"breakpointId":"tablet","condition":null,"minWidth":768}\n- MCP tool: update-breakpoint {"breakpointId":"tablet","minWidth":null,"maxWidth":null,"condition":"(hover: hover)"}\n\n## Delete breakpoint\n\nCommands:\n\n- MCP tool: delete-breakpoint {"breakpointId":"tablet","confirm":true}\n\n## Duplicate page\n\nCommands:\n\n- MCP tool: duplicate-page {"pageId":"<pageId>","name":"Pricing Copy","path":"/pricing-copy"}\n\n## List page templates\n\nCommands:\n\n- MCP tool: list-page-templates {}\n\n## Create page from template\n\nCommands:\n\n- MCP tool: create-page-from-template {"templateId":"<templateId>","name":"Landing","path":"/landing"}\n\n## Delete page\n\nCommands:\n\n- MCP tool: delete-page {"pageId":"<pageId>"}\n\n## List folders\n\nCommands:\n\n- MCP tool: list-folders {"includePages":true}\n\n## Create folder\n\nCommands:\n\n- MCP tool: create-folder {"name":"Blog","slug":"blog"}\n\n## Update folder\n\nCommands:\n\n- MCP tool: update-folder {"folderId":"<folderId>","name":"Blog","slug":"blog"}\n\n## Delete folder\n\nCommands:\n\n- MCP tool: delete-folder {"folderId":"<folderId>"}\n\n## List element instances\n\nCommands:\n\n- MCP tool: list-instances {"pagePath":"/","maxDepth":3}\n\n## Inspect one element instance\n\nCommands:\n\n- MCP tool: inspect-instance {"instanceId":"<instanceId>","include":["props","styles","children"]}\n\n## Append/prepend/replace child elements\n\nCommands:\n\n- MCP tool: append-instance {"parentInstanceId":"<instanceId>","children":"children.json contents"}\n\n## Move elements\n\nCommands:\n\n- MCP tool: move-instance {"moves":"moves.json contents"}\n\n## Clone element subtree\n\nCommands:\n\n- MCP tool: clone-instance {"sourceInstanceId":"<instanceId>","parentInstanceId":"<targetParentId>"}\n\n## Delete element subtree\n\nCommands:\n\n- MCP tool: delete-instance {"instanceId":"<instanceId>"}\n\n## List text/expression children\n\nCommands:\n\n- MCP tool: list-texts {"pagePath":"/"}\n\n## Update text child\n\nCommands:\n\n- MCP tool: update-text {"instanceId":"<instanceId>","childIndex":0,"text":"Launch faster"}\n\n## Update props\n\nCommands:\n\n- MCP tool: update-props {"updates":"props.json contents"}\n\nNotes:\n\n- Use this for fixed prop values such as `aria-label`, `alt`, `id`, static `href`, and other direct string/number/boolean/json prop values.\n- Do not use bindings just to set static text.\n\n## Delete props\n\nCommands:\n\n- MCP tool: delete-props {"deletions":"props.json contents"}\n\n## Bind props to expressions/resources/actions\n\nCommands:\n\n- MCP tool: bind-props {"bindings":"bindings.json contents"}\n\nNotes:\n\n- Use this only when the prop should remain dynamic: expression, parameter, resource, or action binding.\n- For a fixed string value, use `update-props` with `type:"string"` and a direct `value` instead.\n\n## Read styles\n\nCommands:\n\n- MCP tool: get-styles {"instanceId":"<instanceId>","includeTokens":true}\n\n## Update local styles\n\nCommands:\n\n- MCP tool: update-styles {"updates":"styles.json contents"}\n\n## Delete local styles\n\nCommands:\n\n- MCP tool: delete-styles {"deletions":"styles.json contents"}\n\n## Replace matching style values\n\nCommands:\n\n- MCP tool: replace-styles {"replacements":"replace.json contents"}\n\n## List design tokens\n\nCommands:\n\n- MCP tool: list-design-tokens {"withUsage":true}\n\n## Create design tokens\n\nCommands:\n\n- MCP tool: create-design-token {"tokens":"tokens.json contents"}\n\n## Update design token styles\n\nCommands:\n\n- MCP tool: update-design-token-styles {"styleSourceId":"<tokenId>","updates":"styles.json contents"}\n\n## Delete design token styles\n\nCommands:\n\n- MCP tool: delete-design-token-styles {"styleSourceId":"<tokenId>","deletions":"styles.json contents"}\n\n## Attach design token to instances\n\nCommands:\n\n- MCP tool: attach-design-token {"styleSourceId":"<tokenId>","instanceIds":"instances.json contents"}\n\n## Detach design token from instances\n\nCommands:\n\n- MCP tool: detach-design-token {"styleSourceId":"<tokenId>","instanceIds":"instances.json contents"}\n\n## Extract design token from local styles\n\nCommands:\n\n- MCP tool: extract-design-token {"token":"token.json contents"}\n\n## List CSS variables\n\nCommands:\n\n- MCP tool: list-css-variables {"withUsage":true}\n\n## Define CSS variables\n\nCommands:\n\n- MCP tool: define-css-variable {"variables":"vars.json contents"}\n\n## Delete CSS variables\n\nCommands:\n\n- MCP tool: delete-css-variable {"names":"names.json contents","confirm":true}\n\n## Rewrite CSS variable references\n\nCommands:\n\n- MCP tool: rewrite-css-variable-refs {"variables":"variables.json contents"}\n\n## List data variables\n\nCommands:\n\n- MCP tool: list-variables {}\n\n## Create data variable\n\nCommands:\n\n- MCP tool: create-variable {"scopeInstanceId":"<instanceId>","name":"title","value":{"type":"string","value":"Hello"}}\n\n## Update data variable\n\nCommands:\n\n- MCP tool: update-variable {"variableId":"<variableId>","value":{"type":"json","value":{"count":1}}}\n\n## Delete data variable\n\nCommands:\n\n- MCP tool: delete-variable {"variableId":"<variableId>"}\n\n## List resources\n\nCommands:\n\n- MCP tool: list-resources {}\n\n## Create resource\n\nCommands:\n\n- MCP tool: create-resource {"name":"Posts","method":"get","url":"\\"https://api.example.com/posts\\""}\n\n## Update resource\n\nCommands:\n\n- MCP tool: update-resource {"resourceId":"<resourceId>","values":{"url":"\\"https://api.example.com/posts\\""}}\n\n## Delete resource\n\nCommands:\n\n- MCP tool: delete-resource {"resourceId":"<resourceId>"}\n\n## List assets\n\nCommands:\n\n- MCP tool: list-assets {"withUsage":true}\n\n## Upload one asset\n\nCommands:\n\n- MCP tool: upload-asset {"asset":"asset.json contents","assetsDir":".webstudio/assets"}\n\n## Upload asset batch\n\nCommands:\n\n- MCP tool: upload-assets {"assets":"assets.json contents","assetsDir":".webstudio/assets"}\n\n## Find asset usage\n\nCommands:\n\n- MCP tool: find-asset-usage {"assetId":"<assetId>"}\n\n## Replace asset references\n\nCommands:\n\n- MCP tool: replace-asset {"fromAssetId":"<oldAssetId>","toAssetId":"<newAssetId>","confirm":true}\n\n## Delete assets\n\nCommands:\n\n- MCP tool: delete-asset {"assetId":"<assetId>","confirm":true}\n\n## Publish project\n\nCommands:\n\n- webstudio publish deploy --target production --json\n\n## List publishes\n\nCommands:\n\n- webstudio publish list --json\n\n## Check publish job\n\nCommands:\n\n- webstudio publish status --job <buildId> --json\n\n## Unpublish\n\nCommands:\n\n- webstudio publish unpublish --target production --confirm --json\n\n## List domains\n\nCommands:\n\n- webstudio domains list --json\n\n## Create domain\n\nCommands:\n\n- webstudio domains create --domain example.com --json\n\n## Update domain\n\nCommands:\n\n- webstudio domains update --domain-id <domainId> --domain www.example.com --json\n\n## Delete domain\n\nCommands:\n\n- webstudio domains delete --domain-id <domainId> --confirm --json\n\n## Verify domain\n\nCommands:\n\n- webstudio domains verify --domain-id <domainId> --json\n\n## Make arbitrary store-level changes\n\nCommands:\n\n- MCP tool: inspect {}\n- MCP tool: snapshot {"include":["<namespace>"]}\n- MCP tool: apply-patch {"baseVersion":"<version>","transactions":"patch.json contents"}\n\nNotes:\n\n- Use only when no semantic command exists.\n\n## Manage marketplace metadata\n\nCommands:\n\n- MCP tool: snapshot {"include":["marketplaceProduct"]}\n- MCP tool: apply-patch {"baseVersion":"<version>","transactions":"patch.json contents"}\n\nPatch namespaces:\n\n- marketplaceProduct\n\n## Search and inspect safely\n\nCommands:\n\n- MCP tool: list-instances {"pagePath":"/","maxDepth":5}\n- MCP tool: inspect-instance {"instanceId":"<instanceId>","include":["props","styles","children"]}\n- MCP tool: list-texts {"pagePath":"/"}\n- MCP tool: list-assets {"withUsage":true}\n- MCP tool: find-asset-usage {"assetId":"<assetId>"}\n- MCP tool: snapshot {"include":["pages","instances","props","resources","assets"]}\n\nNotes:\n\n- Use this for finding elements by label, type, href/resource patterns, HTML snippets, missing accessibility metadata, or asset usage.\n\n## Refactor targeted content\n\nCommands:\n\n- MCP tool: list-instances {"pagePath":"/"}\n- MCP tool: list-texts {"pagePath":"/"}\n- MCP tool: update-text {"instanceId":"<instanceId>","childIndex":0,"text":"Launch faster"}\n- MCP tool: update-props {"updates":"props.json contents"}\n- MCP tool: update-page {"pageId":"<pageId>","values":{"title":"\\"Pricing\\"","meta":{"description":"\\"Plans\\""}}}\n- MCP tool: update-resource {"resourceId":"<resourceId>","values":{"url":"\\"https://api.example.com/posts\\""}}\n- MCP tool: replace-asset {"fromAssetId":"<oldAssetId>","toAssetId":"<newAssetId>","confirm":true}\n- MCP tool: replace-styles {"replacements":"replace.json contents"}\n- MCP tool: rewrite-css-variable-refs {"variables":"variables.json contents"}\n\nNotes:\n\n- Use focused reads first, then mutate only matching instances, props, metadata, resource URLs, assets, or style references.\n\n## Optimize existing project\n\nCommands:\n\n- MCP tool: list-pages {"includeFolders":true}\n- MCP tool: update-page {"pageId":"<pageId>","values":{"title":"\\"Pricing\\"","meta":{"description":"\\"Plans\\""}}}\n- MCP tool: update-props {"updates":"props.json contents"}\n- MCP tool: list-breakpoints {}\n- MCP tool: update-breakpoint {"breakpointId":"tablet","maxWidth":1023}\n- MCP tool: get-styles {"instanceId":"<instanceId>","includeTokens":true}\n- MCP tool: update-styles {"updates":"styles.json contents"}\n- MCP tool: attach-design-token {"styleSourceId":"<tokenId>","instanceIds":"instances.json contents"}\n- MCP tool: update-project-settings {"settings":"project-settings.json contents"}\n\nNotes:\n\n- Use this for SEO metadata, accessibility labels, responsive behavior, token consistency, and project settings.\n\n## Connect external data\n\nCommands:\n\n- MCP tool: create-variable {"scopeInstanceId":"<instanceId>","name":"title","value":{"type":"string","value":"Hello"}}\n- MCP tool: create-resource {"name":"Posts","method":"get","url":"\\"https://api.example.com/posts\\""}\n- MCP tool: update-resource {"resourceId":"<resourceId>","values":{"url":"\\"https://api.example.com/posts\\""}}\n- MCP tool: bind-props {"bindings":"bindings.json contents"}\n- MCP tool: append-instance {"parentInstanceId":"<instanceId>","children":"children.json contents"}\n\nNotes:\n\n- Use this for CMS sections, blog listings, Ghost/headless CMS pages, n8n-style integrations, and API URLs built from variables.\n\n## Support dynamic runtime behavior\n\nCommands:\n\n- MCP tool: append-instance {"parentInstanceId":"<instanceId>","children":"children.json contents"}\n- MCP tool: update-props {"updates":"props.json contents"}\n- MCP tool: bind-props {"bindings":"bindings.json contents"}\n- MCP tool: create-resource {"name":"Seats","method":"get","url":"\\"https://api.example.com/seats\\""}\n- MCP tool: snapshot {"include":["instances","props","resources"]}\n- MCP tool: apply-patch {"baseVersion":"<version>","transactions":"patch.json contents"}\n\nNotes:\n\n- Use existing scripts/resources for behavior, then move presentational structure into editable Webstudio instances where possible.\n- There is no dedicated semantic command yet for converting script-generated UI into editable Webstudio structure.\n\n## Build authenticated pages\n\nCommands:\n\n- MCP tool: create-page {"name":"Account","path":"/account"}\n- MCP tool: update-page {"pageId":"<pageId>","values":{"meta":{"auth":{"login":"<login>","password":"<password>"}}}}\n- MCP tool: create-resource {"name":"Session","method":"get","url":"\\"https://api.example.com/session\\""}\n- MCP tool: create-variable {"scopeInstanceId":"<instanceId>","name":"user","value":{"type":"json","value":{}}}\n- MCP tool: update-props {"updates":"props.json contents"}\n- MCP tool: bind-props {"bindings":"bindings.json contents"}\n\nNotes:\n\n- Basic auth is semantic today. Provider-specific Supabase/Firebase setup still requires manual resources, props, embeds, or patches.\n\n## Generate from design input\n\nCommands:\n\n- MCP tool: create-page {"name":"Landing","path":"/landing"}\n- MCP tool: create-design-token {"tokens":"tokens.json contents"}\n- MCP tool: define-css-variable {"variables":"vars.json contents"}\n- MCP tool: append-instance {"parentInstanceId":"<instanceId>","children":"children.json contents"}\n- MCP tool: update-styles {"updates":"styles.json contents"}\n- MCP tool: preview.start {"host":"127.0.0.1","port":5173}\n- MCP tool: screenshot {"path":"/","output":"current.png","viewport":{"width":1440,"height":900},"waitUntil":"load","waitForTimeout":250}\n\nNotes:\n\n- Use this after external design interpretation. There is no dedicated import command for Figma, screenshots, Inception output, or design.md yet.\n\n## Cross-project maintenance\n\nCommands:\n\n- webstudio init --link <api-share-link> --json\n- webstudio permissions --json\n- webstudio mcp\n\nNotes:\n\n- Public API and CLI intentionally operate on one configured project at a time. Use an external script to loop over projects.\n\n# Known CLI Gaps\n\n## General project search and audit\n\nMissing:\nNo single semantic command searches across instance labels, props, hrefs, resource URLs, HTML embeds, asset references, and missing accessibility metadata.\n\nCurrent fallback:\nUse focused MCP reads such as list-instances, list-texts, list-assets, find-asset-usage, and snapshot.\n\nSuggested commands:\n\n- search-project\n- audit-accessibility\n- find-prop-usage\n\n## Save and manage page templates\n\nMissing:\nCLI can list page templates and create pages from existing templates, but cannot save a page as a template or update/delete templates semantically.\n\nCurrent fallback:\nUse MCP snapshot and apply-patch only when the template data model is understood.\n\nSuggested commands:\n\n- create-page-template\n- update-page-template\n- delete-page-template\n\n## Semantic marketplace metadata\n\nMissing:\nMarketplace metadata is only available through MCP snapshot/apply-patch, not dedicated semantic commands.\n\nCurrent fallback:\nUse MCP snapshot --include marketplaceProduct and apply-patch.\n\nSuggested commands:\n\n- get-marketplace\n- update-marketplace\n\n## Provider-specific authenticated pages\n\nMissing:\nCLI supports page basic auth and generic resources/props/embeds, but not guided Supabase/Firebase auth setup.\n\nCurrent fallback:\nCreate the page, resources, variables, props, and embeds manually with existing MCP semantic tools.\n\nSuggested commands:\n\n- setup-auth-page\n\n## Dynamic script/runtime integration helpers\n\nMissing:\nCLI can manipulate props/resources/embeds, but has no semantic workflow for converting script-generated UI into editable Webstudio structures.\n\nCurrent fallback:\nUse MCP append-instance, props, resources, and raw patch where necessary.\n\nSuggested commands:\n\n- integrate-runtime-ui\n\n## Generate from design input\n\nMissing:\nNo command imports Figma, screenshots, Inception output, or design.md and turns it into pages/tokens/layout.\n\nCurrent fallback:\nUse external generation, then apply semantic CLI commands or apply-patch.\n\nSuggested commands:\n\n- generate-from-design\n\n## Built-in cross-project maintenance\n\nMissing:\nPublic API and CLI intentionally operate on one configured project at a time; there is no built-in multi-project discovery or loop runner.\n\nCurrent fallback:\nRun the CLI from an external script that reconfigures one project/session at a time.\n\nSuggested commands:\n\n- none\n',
12306
+ "manual-api": '# Webstudio API CLI Manual\n\nThe API commands operate on the single project configured by:\n\n- .webstudio/config.json: projectId\n- global Webstudio config: origin and token\n\n- Pass --json to API/discovery commands that support it. Do not add --json to top-level commands unless their help/schema documents it.\n- Never pass a project id. Commands use configured project only.\n- Read ids before writing. Do not invent ids for existing records.\n- stdout is one JSON object. stderr is diagnostics.\n- Prefer MCP semantic tools for detailed project edits. Use MCP apply-patch only when no semantic tool exists.\n\n## Start\n\n{{start}}\n\n## Read First\n\n{{readFirst}}\n\n## Project Session Cache\n\n- CLI commands use one local ProjectSession snapshot for the configured project.\n- Local-capable reads use cached namespaces when compatible and fetch only missing or stale namespaces.\n- Local-capable mutations build patches from the local snapshot, then commit with the cached build version.\n- Successful mutation commits update the local snapshot only after the remote commit succeeds.\n- Server-only commands run remotely and invalidate/refetch namespaces declared by the operation catalog.\n- Use --refresh on local-capable commands to refresh required namespaces before running.\n- Successful JSON responses include meta.session with operationId, buildId, version, source, committed, compatibility, namespace freshness, and diagnostics.\n\n## CLI Capability Inventory\n\n### Top-Level Commands\n\n{{topLevelCapabilityIndex}}\n\n### High-Level API Commands By Area\n\n{{apiCapabilityIndex}}\n\n### MCP-Only Operations\n\nThese are intentionally exposed through `webstudio mcp`, not as top-level shell commands:\n\n{{mcpOnlyCommandIndex}}\n\n## Task Recipes\n\n{{taskRecipeIndex}}\n\n## Use Case Index\n\n{{useCaseIndex}}\n\n## Known CLI Gaps\n\n{{knownCliGapIndex}}\n\n## Input File Shapes\n\n{{inputFileShapeIndex}}\n\n## Raw Patch Fallback\n\napply-patch accepts either BuildPatchTransaction[] or { "transactions": BuildPatchTransaction[] }.\n\nEach transaction has:\n\n{\n"id": "unique-client-transaction-id",\n"payload": [\n{\n"namespace": "pages",\n"patches": [\n{ "op": "replace", "path": ["meta", "siteName"], "value": "New Site" }\n]\n}\n]\n}\n\nPatch paths are JSON-patch-like paths into Builder store data. Map-like namespaces use ids as the first path item.\n\nSupported namespaces:\n\n- pages: site metadata, redirects, page records, folders, compiler settings\n- instances: element instances and children, including text/expression children\n- props: element props, bindings, page references, resource bindings\n- styles: CSS declarations keyed by style declaration key\n- styleSources: local style sources and reusable design tokens\n- styleSourceSelections: instance-to-style-source connections\n- dataSources: data variables, parameters, and resource data sources\n- resources: data resource definitions\n- assets: project asset records handled by the existing asset patch path\n- breakpoints: responsive breakpoints\n- marketplaceProduct: marketplace metadata\n\nCommit raw patch:\n\nMCP tool: apply-patch\n\n## Raw Patch Examples\n\nRename the site:\n\n[\n{\n"id": "tx-site-name",\n"payload": [\n{\n"namespace": "pages",\n"patches": [\n{ "op": "add", "path": ["meta", "siteName"], "value": "Acme Studio" }\n]\n}\n]\n}\n]\n\nUpdate page title metadata:\n\n[\n{\n"id": "tx-page-title",\n"payload": [\n{\n"namespace": "pages",\n"patches": [\n{ "op": "replace", "path": ["pages", "page-id", "meta", "title"], "value": "Pricing" }\n]\n}\n]\n}\n]\n\nUpdate a text child on an element:\n\n[\n{\n"id": "tx-text",\n"payload": [\n{\n"namespace": "instances",\n"patches": [\n{ "op": "replace", "path": ["instance-id", "children", 0, "value"], "value": "Launch faster" }\n]\n}\n]\n}\n]\n\nCreate a data variable:\n\n[\n{\n"id": "tx-variable",\n"payload": [\n{\n"namespace": "dataSources",\n"patches": [\n{\n"op": "add",\n"path": ["variable-id"],\n"value": {\n"type": "variable",\n"id": "variable-id",\n"scopeInstanceId": "instance-id",\n"name": "headline",\n"value": { "type": "string", "value": "Launch faster" }\n}\n}\n]\n}\n]\n}\n]\n\nCreate a design token:\n\n[\n{\n"id": "tx-token",\n"payload": [\n{\n"namespace": "styleSources",\n"patches": [\n{ "op": "add", "path": ["token-id"], "value": { "type": "token", "id": "token-id", "name": "Brand Primary" } }\n]\n},\n{\n"namespace": "styles",\n"patches": [\n{\n"op": "add",\n"path": ["token-id:base:color:"],\n"value": {\n"styleSourceId": "token-id",\n"breakpointId": "base",\n"property": "color",\n"value": { "type": "keyword", "value": "red" }\n}\n}\n]\n}\n]\n}\n]\n\n## Safety Rules\n\n- For MCP apply-patch, read the latest version with MCP snapshot before writing.\n- Reuse ids from MCP snapshot output when updating existing records.\n- Generate new unique ids when adding records.\n- If apply-patch reports a version conflict, read the latest build and regenerate the patch.\n- Prefer semantic MCP read tools for discovery, then use MCP snapshot for exact patch paths.\n\n## Command Index\n\n{{commandIndex}}\n',
12307
+ "manual-llm": '# Webstudio CLI Manual for LLMs\n\nUse this order. Stop only when a command returns ok:false.\n\n## Always\n\n1. webstudio permissions --json\n2. webstudio mcp\n3. Read MCP resource webstudio://project/tools.\n4. Pick focused MCP read tool.\n5. Pick semantic MCP write tool.\n\n## LLM Implementation Process\n\nUse this process for user requests that change Webstudio content, layout, styles, assets, pages, redirects, resources, or publishing state:\n\n1. Discover capabilities with `webstudio man llm --json`, `webstudio schema api --json`, and MCP `meta.index` or `webstudio://project/tools`.\n2. Inspect current project state with semantic reads such as `list-pages`, `get-page-by-path`, `list-instances`, `inspect-instance`, `get-styles`, `list-assets`, `list-breakpoints`, and `snapshot` only when needed.\n3. Mutate the Webstudio project with semantic MCP write tools first. Prefer `append-instance`, `update-text`, `update-props`, `update-styles`, `upload-asset`, `create-page`, and page/project settings tools over raw patches.\n4. Use `apply-patch` only when no semantic tool covers the required change, and only after reading the latest snapshot/version.\n5. For visual/design work, regenerate or preview the generated app, capture a screenshot, inspect it with vision, and iterate before final response.\n6. Report what changed and what verification ran.\n\n## Visual Design Workflow\n\nFor requests involving visible HTML/CSS, layout, typography, colors, imagery, responsive behavior, or screenshots:\n\n1. Read editable Webstudio structure first: pages, instances, props, styles, breakpoints, assets, and relevant text.\n2. Do not use generated route/component files as the source of truth for editable content.\n3. Make edits through Webstudio semantic commands/MCP tools so the result stays editable in Builder and survives the next `webstudio build`.\n4. Keep generated project files current, start preview, and capture the changed page with `screenshot`.\n5. Use `screenshot.diff` when a baseline exists and inspect screenshot/diff artifacts with vision before finishing.\n6. If vision or screenshot tooling is unavailable, state that explicitly and explain what fallback verification was used.\n\n## Responsive Verification Workflow\n\nFor responsive page work, use Builder breakpoints as the source of truth:\n\n1. Read breakpoints with `list-breakpoints` before deciding responsive behavior.\n2. Apply responsive styles with existing Builder breakpoint ids; do not invent CSS media queries or breakpoint names when Webstudio breakpoint data exists.\n3. Pick screenshot viewport widths from the project breakpoints: include a desktop width, each defined max-width or min-width edge, and a narrow mobile width.\n4. Capture each viewport with `screenshot`, for example `{"path":"/","output":"home-375.png","viewport":{"width":375,"height":812}}` and `{"path":"/","output":"home-1440.png","viewport":{"width":1440,"height":900}}`.\n5. Inspect every viewport screenshot with vision before finishing, checking layout, overflow, hidden content, text wrapping, and breakpoint-specific style changes.\n6. If any viewport fails, update styles through semantic Webstudio tools and repeat screenshots for the affected breakpoints.\n\n## Generated Files Guardrails\n\n- Do not edit `app/__generated__`, generated route files, generated page files, generated CSS, or build output for normal Webstudio content/design requests.\n- Do not replace generated page components with handcrafted app code unless the user explicitly asks for code-only export customization.\n- Generated files are build artifacts and may be overwritten by `webstudio build`.\n- If a task truly requires generated app customization, keep it outside `app/__generated__` where possible and explain that it is not editable Webstudio content.\n\n## Values vs Bindings\n\n- Use direct value tools for fixed content. For visible text, use `update-text` with plain `text`. For static props such as `aria-label`, `alt`, `id`, `class`, `href`, or button labels stored as props, use `update-props` with the prop\'s direct type/value.\n- Use `bind-props` only when the prop must stay dynamic: an expression, parameter, resource result, or action. Do not use `bind-props` just to set a fixed string.\n- Direct prop string example: `{"updates":[{"instanceId":"button-id","name":"aria-label","type":"string","value":"Open menu"}]}`.\n- Expression binding example: `{"bindings":[{"instanceId":"link-id","name":"href","binding":{"type":"expression","value":"currentPost.url"}}]}`.\n- Page metadata fields such as `title`, `description`, `language`, `redirect`, `status`, and custom meta content are expression-backed strings. For fixed text, pass a JavaScript string literal expression with JSON quoting, for example `JSON.stringify("Pricing | Acme")` in code or `"\\"Pricing | Acme\\""` in JSON. Never pass raw multi-word text such as `"Pricing | Acme"` as an expression.\n- Page metadata update example: use `update-page` with `{"pageId":"page-id","values":{"title":"\\"Pricing | Acme\\"","meta":{"description":"\\"Plans for teams\\""}}}`.\n- Resource URL, header, search-param, and body fields are also expression-backed. For a fixed URL, use a string literal expression such as `"\\"https://api.example.com/items\\""`.\n- Resource update example: use `update-resource` with `{"resourceId":"resource-id","values":{"url":"\\"https://api.example.com/items\\""}}`.\n\n## Pick Read Command\n\n{{readFirst}}\n\n## Pick Write Command\n\n{{taskRecipeIndex}}\n\n## Raw Patch Only If Needed\n\n1. Use MCP tool: snapshot.\n2. Write BuildPatchTransaction[].\n3. Use MCP tool: apply-patch.\n\n## MCP Argument Examples\n\nMCP tools receive JSON argument objects, not CLI flags. Use these shapes:\n\n{{mcpArgumentExampleIndex}}\n\n## Rules\n\n- Never guess ids for existing records. Read them first.\n- Never use project ids from user input. Commands use the configured project.\n- Use --refresh before a local-capable command when cached data may be stale.\n- Pass --json only to commands whose help/schema documents it. Do not add --json to top-level commands such as sync unless supported.\n- On VERSION_CONFLICT, read MCP snapshot again, regenerate the patch, then retry.\n- Treat stdout JSON as the API contract and stderr as diagnostics.\n- For visual/design work, verify the rendered result with vision before finishing.\n- Do not edit generated files for normal Webstudio content/design requests.\n- Use direct values for static strings and bindings only for dynamic expressions/resources/actions.\n- For expression-backed fields that need fixed text, encode the fixed text as a quoted JavaScript string literal expression.\n- Confirm destructive commands with --confirm only when user requested deletion/unpublish/replacement.\n- Use webstudio schema api --json for machine-readable command metadata.\n\n## Known Gaps\n\n{{knownCliGapIndex}}\n',
12308
+ "manual-mcp": "# Webstudio MCP Manual\n\n`webstudio mcp` starts a stdio MCP server for the configured project.\n\n## Startup\n\n1. Configure a project with `webstudio init --link <api-share-link> --json`.\n2. Check capabilities with `webstudio permissions --json`.\n3. Start the server with `webstudio mcp`.\n4. In the MCP client, read `webstudio://project/guide` before editing, or call `meta.index` and `meta.guide`.\n\nWhile the server is running, stdout is reserved for MCP JSON-RPC messages. Do not print human text from the server process.\n\n## Discovery\n\nUse MCP itself after startup:\n\n- `tools/list`: machine-readable available tools\n- `resources/list`: available longer JSON resources\n- `meta.index`: concise capability catalog\n- `meta.guide`: workflow for a user goal\n- `meta.get_more_tools`: detailed params, examples, namespaces, and local/server behavior\n\nUseful resources:\n\n- `webstudio://project/status`: current ProjectSession status\n- `webstudio://project/tools`: operation catalog\n- `webstudio://project/guide`: concise discovery guide\n\n## Core Rules\n\n- stdout is reserved for MCP JSON-RPC while the server is running.\n- Operate on the configured project only.\n- Read ids before writing.\n- Prefer semantic tools over `apply-patch`.\n- Use `status` and `refresh` when cached namespaces may be stale.\n- A mutation is durable only when `meta.session.committed` is true.\n- For visual/design work, verify the rendered result with vision before finishing.\n\n## Vision Verification Loop\n\nVision-capable AI can use MCP to see what it is building:\n\n{{mcpVisionVerificationLoopMarkdown}}\n\nGenerated app setup:\n\n{{mcpGeneratedAppDependencyNotes}}\n\n## MCP Argument Examples\n\nMCP tools receive JSON argument objects:\n\n{{mcpArgumentExampleIndex}}\n\n## Screenshot Verification\n\n{{screenshotVerificationSummary}}\n",
12309
+ "mcp-startup-epilogue": "Plain `webstudio mcp` starts the stdio MCP server.\n\nStartup marks cached ProjectSession data stale so MCP tools read the current Builder dev build.\n\nAfter startup, read MCP resource `webstudio://project/guide` before editing.\n\nAfter startup, MCP clients discover capabilities with `tools/list`, `resources/list`, `meta.index`, `meta.guide`, and `meta.get_more_tools`.\n\nstdout is reserved for MCP JSON-RPC messages while the server is running.\n",
12310
+ "mcp-vision": '# MCP Vision Verification\n\n## Generated App Dependency Notes\n\n- For a fresh checkout, copied fixture, or newly generated app, run npm install or pnpm install in the generated project before preview.start or webstudio preview.\n- If preview fails with a missing generated-app command/package such as react-router or vite, install the generated app dependencies and retry.\n\n## Visual Verification Rule\n\nFor visual/design work, use preview.start and screenshot after generated project files are current and generated app dependencies are installed so vision can inspect the rendered result before finishing. When a baseline exists, use screenshot.diff to get pixel regions, OCR text changes, and diff PNG artifacts.\n\n## Vision Verification Loop\n\n- Make focused page/content/style changes with semantic MCP tools.\n- Make sure generated project files are current and generated app dependencies are installed, then call preview.start once to keep the generated site running.\n- {{dependency-notes}}\n- For responsive work, call list-breakpoints first, then capture screenshots at viewport widths based on the Builder breakpoints plus a narrow mobile and desktop width.\n- Call screenshot with { path: "/" } or the changed page path and viewport such as { width: 375, height: 812 } and { width: 1440, height: 900 }. Use waitForSelector when the page has a reliable ready marker, waitUntil:"networkidle" for network-heavy pages, and waitForTimeout only for final visual settling.\n- {{diff}} When a baseline PNG exists, call screenshot.diff with baselinePath, currentPath, and outputDir.\n- {{diff}} Read screenshot.diff textAnalysis: it reports OCR status plus text that appeared, disappeared, moved, changed content, or changed font/style geometry. If OCR is unavailable, ask the user for permission to install Tesseract, then call vision.install-ocr with { "confirm": true }, or rely on visual inspection.\n- Inspect every viewport PNG and any diff artifacts with vision, then compare layout, OCR text evidence, color, spacing, imagery, and responsive framing against the user intent.\n- If the screenshot does not match, apply another focused mutation and repeat screenshot verification.\n\n## Workflow Summary With Diff\n\nFor visual/design work, make sure generated project files are current and generated app dependencies are installed, call preview.start, then screenshot({ path, viewport }); for responsive work, use list-breakpoints and capture the changed page at Builder breakpoint widths plus mobile and desktop widths; use screenshot.diff when a baseline exists, then inspect pixel regions, OCR textAnalysis, and PNG/diff artifacts with vision before finishing.\n\n## Workflow Summary Without Diff\n\nFor visual/design work, make sure generated project files are current and generated app dependencies are installed, call preview.start, then screenshot({ path, viewport }); for responsive work, use list-breakpoints and capture the changed page at Builder breakpoint widths plus mobile and desktop widths; inspect every PNG with vision before finishing.\n\n## Screenshot Verification Summary\n\nInside MCP, prefer preview.start plus screenshot({ path: "/", viewport }) after generated project files are current and generated app dependencies are installed, so the preview server stays running for fast repeated checks. For responsive work, read list-breakpoints and capture viewport widths from Builder breakpoint edges plus mobile and desktop widths before using vision. Screenshot waits for load by default, then fonts and two layout frames; pass waitForSelector for app readiness, waitUntil:"networkidle" for network-heavy pages, and waitForTimeout for final settling. When a baseline exists, use screenshot.diff for changed regions, OCR textAnalysis, and diff artifacts. Outside MCP, use webstudio preview and webstudio screenshot <url> --output current.png.\n\n## Screenshot Diff Evidence\n\n- Pixel evidence: total mismatch, changed regions, dominant color/luminance direction, diffPath, and contextDiffPath.\n- OCR evidence: textAnalysis.status, provider, and changes for appeared/disappeared/content_changed/moved/font_changed text.\n- OCR dependency: screenshot.diff uses the system tesseract binary when available. If missing, it returns ocr_unavailable_tesseract_not_found_or_failed and still returns pixel evidence.\n- OCR install: MCP cannot prompt. Ask the user first; if they agree, call vision.install-ocr with { "confirm": true }. If automatic install is unavailable, follow the returned installUrl.\n- Final judgment: OCR and pixel diff are evidence. A vision-capable model must still inspect screenshots/diff artifacts and compare the rendered result to user intent.\n'
12311
+ };
12312
+ const cliDocTitles = {
12313
+ "api-use-cases": "CLI API Use Cases",
12314
+ "manual-api": "Webstudio API CLI Manual",
12315
+ "manual-llm": "Webstudio CLI Manual for LLMs",
12316
+ "manual-mcp": "Webstudio MCP Manual",
12317
+ "mcp-startup-epilogue": "mcp-startup-epilogue",
12318
+ "mcp-vision": "MCP Vision Verification"
12319
+ };
12320
+ const cliDocSections = {
12321
+ "api-use-cases": {},
12322
+ "manual-api": {
12323
+ safetyRules: [
12324
+ "Pass --json to API/discovery commands that support it. Do not add --json to top-level commands unless their help/schema documents it.",
12325
+ "Never pass a project id. Commands use configured project only.",
12326
+ "Read ids before writing. Do not invent ids for existing records.",
12327
+ "stdout is one JSON object. stderr is diagnostics.",
12328
+ "Prefer MCP semantic tools for detailed project edits. Use MCP apply-patch only when no semantic tool exists.",
12329
+ "For MCP apply-patch, read the latest version with MCP snapshot before writing.",
12330
+ "Reuse ids from MCP snapshot output when updating existing records.",
12331
+ "Generate new unique ids when adding records.",
12332
+ "If apply-patch reports a version conflict, read the latest build and regenerate the patch.",
12333
+ "Prefer semantic MCP read tools for discovery, then use MCP snapshot for exact patch paths."
12334
+ ]
12335
+ },
12336
+ "manual-llm": {
12337
+ implementationProcess: [
12338
+ "Discover capabilities with webstudio man llm --json, webstudio schema api --json, and MCP meta.index or webstudio://project/tools.",
12339
+ "Inspect current project state with semantic reads such as list-pages, get-page-by-path, list-instances, inspect-instance, get-styles, list-assets, list-breakpoints, and snapshot only when needed.",
12340
+ "Mutate the Webstudio project with semantic MCP write tools first. Prefer append-instance, update-text, update-props, update-styles, upload-asset, create-page, and page/project settings tools over raw patches.",
12341
+ "Use apply-patch only when no semantic tool covers the required change, and only after reading the latest snapshot/version.",
12342
+ "For visual/design work, regenerate or preview the generated app, capture a screenshot, inspect it with vision, and iterate before final response.",
12343
+ "Report what changed and what verification ran."
12344
+ ],
12345
+ visualDesignWorkflow: [
12346
+ "Read editable Webstudio structure first: pages, instances, props, styles, breakpoints, assets, and relevant text.",
12347
+ "Do not use generated route/component files as the source of truth for editable content.",
12348
+ "Make edits through Webstudio semantic commands/MCP tools so the result stays editable in Builder and survives the next webstudio build.",
12349
+ "Keep generated project files current, start preview, and capture the changed page with screenshot.",
12350
+ "Use screenshot.diff when a baseline exists and inspect screenshot/diff artifacts with vision before finishing.",
12351
+ "If vision or screenshot tooling is unavailable, state that explicitly and explain what fallback verification was used."
12352
+ ],
12353
+ responsiveVerification: [
12354
+ "Read breakpoints with list-breakpoints before deciding responsive behavior.",
12355
+ "Apply responsive styles with existing Builder breakpoint ids; do not invent CSS media queries or breakpoint names when Webstudio breakpoint data exists.",
12356
+ "Pick screenshot viewport widths from the project breakpoints: include a desktop width, each defined max-width or min-width edge, and a narrow mobile width.",
12357
+ 'Capture each viewport with screenshot, for example {"path":"/","output":"home-375.png","viewport":{"width":375,"height":812}} and {"path":"/","output":"home-1440.png","viewport":{"width":1440,"height":900}}.',
12358
+ "Inspect every viewport screenshot with vision before finishing, checking layout, overflow, hidden content, text wrapping, and breakpoint-specific style changes.",
12359
+ "If any viewport fails, update styles through semantic Webstudio tools and repeat screenshots for the affected breakpoints."
12360
+ ],
12361
+ generatedFileGuardrails: [
12362
+ "Do not edit app/__generated__, generated route files, generated page files, generated CSS, or build output for normal Webstudio content/design requests.",
12363
+ "Do not replace generated page components with handcrafted app code unless the user explicitly asks for code-only export customization.",
12364
+ "Generated files are build artifacts and may be overwritten by webstudio build.",
12365
+ "If a task truly requires generated app customization, keep it outside app/__generated__ where possible and explain that it is not editable Webstudio content."
12366
+ ],
12367
+ valuesVsBindings: [
12368
+ "Use direct value tools for fixed content. For visible text, use update-text with plain text. For static props such as aria-label, alt, id, class, href, or button labels stored as props, use update-props with the prop's direct type/value.",
12369
+ "Use bind-props only when the prop must stay dynamic: an expression, parameter, resource result, or action. Do not use bind-props just to set a fixed string.",
12370
+ 'Direct prop string example: {"updates":[{"instanceId":"button-id","name":"aria-label","type":"string","value":"Open menu"}]}.',
12371
+ 'Expression binding example: {"bindings":[{"instanceId":"link-id","name":"href","binding":{"type":"expression","value":"currentPost.url"}}]}.',
12372
+ 'Page metadata fields such as title, description, language, redirect, status, and custom meta content are expression-backed strings. For fixed text, pass a JavaScript string literal expression with JSON quoting, for example JSON.stringify("Pricing | Acme") in code or "\\"Pricing | Acme\\"" in JSON. Never pass raw multi-word text such as "Pricing | Acme" as an expression.',
12373
+ 'Page metadata update example: use update-page with {"pageId":"page-id","values":{"title":"\\"Pricing | Acme\\"","meta":{"description":"\\"Plans for teams\\""}}}.',
12374
+ 'Resource URL, header, search-param, and body fields are also expression-backed. For a fixed URL, use a string literal expression such as "\\"https://api.example.com/items\\"".',
12375
+ 'Resource update example: use update-resource with {"resourceId":"resource-id","values":{"url":"\\"https://api.example.com/items\\""}}.'
12376
+ ],
12377
+ rules: [
12378
+ "Never guess ids for existing records. Read them first.",
12379
+ "Never use project ids from user input. Commands use the configured project.",
12380
+ "Use --refresh before a local-capable command when cached data may be stale.",
12381
+ "Pass --json only to commands whose help/schema documents it. Do not add --json to top-level commands such as sync unless supported.",
12382
+ "On VERSION_CONFLICT, read MCP snapshot again, regenerate the patch, then retry.",
12383
+ "Treat stdout JSON as the API contract and stderr as diagnostics.",
12384
+ "For visual/design work, verify the rendered result with vision before finishing.",
12385
+ "Do not edit generated files for normal Webstudio content/design requests.",
12386
+ "Use direct values for static strings and bindings only for dynamic expressions/resources/actions.",
12387
+ "For expression-backed fields that need fixed text, encode the fixed text as a quoted JavaScript string literal expression.",
12388
+ "Confirm destructive commands with --confirm only when user requested deletion/unpublish/replacement.",
12389
+ "Use webstudio schema api --json for machine-readable command metadata."
12390
+ ]
12391
+ },
12392
+ "manual-mcp": {
12393
+ rules: [
12394
+ "stdout is reserved for MCP JSON-RPC while the server is running.",
12395
+ "Operate on the configured project only.",
12396
+ "Read ids before writing.",
12397
+ "Prefer semantic tools over apply-patch.",
12398
+ "Use status and refresh when cached namespaces may be stale.",
12399
+ "A mutation is durable only when meta.session.committed is true.",
12400
+ "For visual/design work, verify the rendered result with vision before finishing."
12401
+ ]
12402
+ },
12403
+ "mcp-startup-epilogue": {},
12404
+ "mcp-vision": {}
12209
12405
  };
12210
12406
  const readCliDoc = (name2) => cliDocs[name2];
12407
+ const readCliDocTitle = (name2) => cliDocTitles[name2];
12408
+ const readCliDocSections = (name2) => cliDocSections[name2];
12211
12409
  const mcpVisionMarkdown = readCliDoc("mcp-vision");
12212
12410
  const getSection = (markdown, heading) => {
12213
12411
  const lines = markdown.split(/\r?\n/);
@@ -12269,6 +12467,14 @@ const createRuntimeMutation = ({
12269
12467
  invalidatesNamespaces,
12270
12468
  noop: payload.length === 0
12271
12469
  });
12470
+ const assetReplaceInput = z.object({
12471
+ fromAssetId: z.string(),
12472
+ toAssetId: z.string()
12473
+ });
12474
+ const assetDeleteInput = z.object({
12475
+ assetIdsOrPrefixes: z.array(z.string()).min(1),
12476
+ force: z.boolean().optional()
12477
+ });
12272
12478
  const traverseAssetStyleValue = (value2, callback) => {
12273
12479
  callback(value2);
12274
12480
  if (value2.type === "tuple" || value2.type === "layers") {
@@ -12776,6 +12982,15 @@ const deleteAssets = (state, input2) => {
12776
12982
  invalidatesNamespaces: ["assets"]
12777
12983
  });
12778
12984
  };
12985
+ const getExpressionErrors = (expression) => lintExpression({ expression }).filter((diagnostic) => diagnostic.severity === "error").map((diagnostic) => diagnostic.message);
12986
+ const getNamedExpressionErrors = (name2, expression) => {
12987
+ if (expression === void 0) {
12988
+ return [];
12989
+ }
12990
+ return getExpressionErrors(expression).map(
12991
+ (message) => `${name2}: ${message}`
12992
+ );
12993
+ };
12779
12994
  const getRequiredDataSources = (state) => {
12780
12995
  if (state.dataSources === void 0) {
12781
12996
  return throwBuilderRuntimeError(
@@ -12857,6 +13072,24 @@ const listDataVariables = (state, input2 = {}) => serializeDataVariables({
12857
13072
  dataSources: getRequiredDataSources(state),
12858
13073
  scopeInstanceId: input2.scopeInstanceId
12859
13074
  });
13075
+ const dataVariableValueInput = dataSourceVariableValue;
13076
+ const dataVariableCreateInput = z.object({
13077
+ dataSourceId: z.string().optional(),
13078
+ scopeInstanceId: z.string(),
13079
+ name: z.string().min(1),
13080
+ value: dataVariableValueInput
13081
+ });
13082
+ const dataVariableUpdateInput = z.object({
13083
+ dataSourceId: z.string(),
13084
+ values: z.object({
13085
+ scopeInstanceId: z.string().optional(),
13086
+ name: z.string().min(1).optional(),
13087
+ value: dataVariableValueInput.optional()
13088
+ })
13089
+ });
13090
+ const dataVariableDeleteInput = z.object({
13091
+ dataSourceId: z.string()
13092
+ });
12860
13093
  const validateDataVariableNameWithSources = ({
12861
13094
  dataSources,
12862
13095
  name: name2,
@@ -13457,8 +13690,40 @@ const findResource = (resources, resourceId2) => {
13457
13690
  }
13458
13691
  }
13459
13692
  };
13460
- const resourceFieldsInput = resource.omit({ id: true }).extend({ control: z.enum(["system", "graphql"]).optional() });
13461
- resourceFieldsInput.partial();
13693
+ const addExpressionIssues$2 = (context, errors) => {
13694
+ for (const message of errors) {
13695
+ context.addIssue({
13696
+ code: z.ZodIssueCode.custom,
13697
+ message
13698
+ });
13699
+ }
13700
+ };
13701
+ const resourceFieldsInputBase = resource.omit({ id: true }).extend({ control: z.enum(["system", "graphql"]).optional() });
13702
+ const resourceFieldsInput = resourceFieldsInputBase.superRefine(
13703
+ (fields, context) => {
13704
+ addExpressionIssues$2(context, getResourceExpressionErrors(fields));
13705
+ }
13706
+ );
13707
+ const resourceFieldsUpdateInput = resourceFieldsInputBase.partial().superRefine((fields, context) => {
13708
+ addExpressionIssues$2(context, getResourceExpressionErrors(fields));
13709
+ });
13710
+ const resourceCreateInput = z.object({
13711
+ resourceId: z.string().optional(),
13712
+ resource: resourceFieldsInput,
13713
+ dataSourceId: z.string().optional(),
13714
+ scopeInstanceId: z.string().optional(),
13715
+ dataSourceName: z.string().optional()
13716
+ });
13717
+ const resourceUpdateInput = z.object({
13718
+ resourceId: z.string(),
13719
+ values: resourceFieldsUpdateInput,
13720
+ dataSourceName: z.string().optional(),
13721
+ scopeInstanceId: z.string().optional()
13722
+ });
13723
+ const resourceDeleteInput = z.object({
13724
+ resourceId: z.string(),
13725
+ force: z.boolean().optional()
13726
+ });
13462
13727
  const createResourceValue = ({
13463
13728
  id,
13464
13729
  control,
@@ -13481,14 +13746,7 @@ const createResourceValue = ({
13481
13746
  const getResourceExpressionErrors = (fields) => {
13482
13747
  const errors = [];
13483
13748
  const validate = (name2, expression) => {
13484
- if (expression === void 0) {
13485
- return;
13486
- }
13487
- for (const diagnostic of lintExpression({ expression })) {
13488
- if (diagnostic.severity === "error") {
13489
- errors.push(`${name2}: ${diagnostic.message}`);
13490
- }
13491
- }
13749
+ errors.push(...getNamedExpressionErrors(name2, expression));
13492
13750
  };
13493
13751
  validate("url", fields.url);
13494
13752
  validate("body", fields.body);
@@ -14369,7 +14627,7 @@ const createPageValue = ({
14369
14627
  pageId: pageId2,
14370
14628
  name: name2,
14371
14629
  path: path2,
14372
- title = name2,
14630
+ title = JSON.stringify(name2),
14373
14631
  rootInstanceId,
14374
14632
  meta = {}
14375
14633
  }) => ({
@@ -14386,13 +14644,29 @@ const emptyStringRemovesMetaFields = /* @__PURE__ */ new Set([
14386
14644
  "socialImageAssetId",
14387
14645
  "socialImageUrl"
14388
14646
  ]);
14647
+ const pageMetaExpressionFields = [
14648
+ "description",
14649
+ "language",
14650
+ "redirect",
14651
+ "socialImageUrl",
14652
+ "status",
14653
+ "content"
14654
+ ];
14389
14655
  const normalizePageMetaValue = (name2, value2) => {
14390
14656
  if (value2 === "" && emptyStringRemovesMetaFields.has(name2)) {
14391
14657
  return void 0;
14392
14658
  }
14393
14659
  return value2;
14394
14660
  };
14395
- const pageMetaInput = z.object({
14661
+ const addExpressionIssues$1 = (context, errors) => {
14662
+ for (const message of errors) {
14663
+ context.addIssue({
14664
+ code: z.ZodIssueCode.custom,
14665
+ message
14666
+ });
14667
+ }
14668
+ };
14669
+ const pageMetaInputBase = z.object({
14396
14670
  description: z.string().optional(),
14397
14671
  language: z.string().optional(),
14398
14672
  redirect: z.string().optional(),
@@ -14405,13 +14679,72 @@ const pageMetaInput = z.object({
14405
14679
  auth: pageAuth.optional(),
14406
14680
  custom: z.array(z.object({ property: z.string(), content: z.string() })).optional()
14407
14681
  });
14408
- z.object({
14682
+ const getPageExpressionErrors = (input2) => {
14683
+ const errors = [];
14684
+ errors.push(...getNamedExpressionErrors("title", input2.title));
14685
+ if (input2.meta !== void 0) {
14686
+ for (const name2 of pageMetaExpressionFields) {
14687
+ const expression = input2.meta[name2];
14688
+ if (expression === "" && emptyStringRemovesMetaFields.has(name2)) {
14689
+ continue;
14690
+ }
14691
+ errors.push(...getNamedExpressionErrors(`meta.${name2}`, expression));
14692
+ }
14693
+ for (const [index, customMeta] of (input2.meta.custom ?? []).entries()) {
14694
+ errors.push(
14695
+ ...getNamedExpressionErrors(
14696
+ `meta.custom.${index}.content`,
14697
+ customMeta.content
14698
+ )
14699
+ );
14700
+ }
14701
+ }
14702
+ return errors;
14703
+ };
14704
+ const pageMetaInput = pageMetaInputBase.superRefine((meta, context) => {
14705
+ addExpressionIssues$1(context, getPageExpressionErrors({ meta }));
14706
+ });
14707
+ const pageFieldsInput = z.object({
14409
14708
  name: z.string().min(1).optional(),
14410
14709
  path: z.string().optional(),
14411
14710
  title: z.string().optional(),
14412
14711
  parentFolderId: z.string().optional(),
14712
+ meta: pageMetaInputBase.optional()
14713
+ }).superRefine((fields, context) => {
14714
+ addExpressionIssues$1(context, getPageExpressionErrors(fields));
14715
+ });
14716
+ const pageCreateInput = z.object({
14717
+ pageId: z.string().optional(),
14718
+ name: z.string().min(1),
14719
+ path: z.string(),
14720
+ title: z.string().optional(),
14721
+ parentFolderId: z.string().optional(),
14413
14722
  meta: pageMetaInput.optional()
14414
14723
  });
14724
+ const pageUpdateInput = z.object({
14725
+ pageId: z.string(),
14726
+ values: pageFieldsInput
14727
+ });
14728
+ const pageDeleteInput = z.object({
14729
+ pageId: z.string()
14730
+ });
14731
+ const folderCreateInput = z.object({
14732
+ folderId: z.string().optional(),
14733
+ name: z.string().min(1),
14734
+ slug: z.string(),
14735
+ parentFolderId: z.string().optional()
14736
+ });
14737
+ const folderUpdateInput = z.object({
14738
+ folderId: z.string(),
14739
+ values: z.object({
14740
+ name: z.string().min(1).optional(),
14741
+ slug: z.string().optional(),
14742
+ parentFolderId: z.string().optional()
14743
+ })
14744
+ });
14745
+ const folderDeleteInput = z.object({
14746
+ folderId: z.string()
14747
+ });
14415
14748
  const pageMetaToPatchValue = (meta) => {
14416
14749
  const result = {};
14417
14750
  for (const [name2, value2] of Object.entries(meta)) {
@@ -14516,6 +14849,10 @@ const createPage = (state, input2, context) => {
14516
14849
  const pages2 = getRequiredPages(state);
14517
14850
  const parentFolderId = input2.parentFolderId ?? pages2.rootFolderId;
14518
14851
  const parentFolder = getFolderOrThrow(pages2, parentFolderId);
14852
+ const expressionErrors = getPageExpressionErrors(input2);
14853
+ if (expressionErrors.length > 0) {
14854
+ return throwBuilderRuntimeError("BAD_REQUEST", expressionErrors.join("\n"));
14855
+ }
14519
14856
  const pageId2 = input2.pageId ?? context.createId();
14520
14857
  if (pages2.pages.has(pageId2)) {
14521
14858
  return throwBuilderRuntimeError("CONFLICT", "Page id already exists");
@@ -14558,6 +14895,10 @@ const updatePage = (state, input2) => {
14558
14895
  if (page2 === void 0) {
14559
14896
  return throwBuilderRuntimeError("NOT_FOUND", "Page not found");
14560
14897
  }
14898
+ const expressionErrors = getPageExpressionErrors(input2.values);
14899
+ if (expressionErrors.length > 0) {
14900
+ return throwBuilderRuntimeError("BAD_REQUEST", expressionErrors.join("\n"));
14901
+ }
14561
14902
  if ((input2.values.path !== void 0 || input2.values.parentFolderId !== void 0) && isPathAvailable({
14562
14903
  pages: pages2,
14563
14904
  path: input2.values.path ?? page2.path,
@@ -14843,7 +15184,25 @@ const createPropBindingFromInput = ({
14843
15184
  type: binding.type,
14844
15185
  value: binding.value
14845
15186
  });
14846
- z.object({
15187
+ const getPropValueErrors = ({
15188
+ type: type2,
15189
+ value: value2
15190
+ }) => {
15191
+ if (type2 !== "expression") {
15192
+ return [];
15193
+ }
15194
+ return getExpressionErrors(String(value2));
15195
+ };
15196
+ const addExpressionIssues = (context, errors, path2 = []) => {
15197
+ for (const message of errors) {
15198
+ context.addIssue({
15199
+ code: z.ZodIssueCode.custom,
15200
+ message,
15201
+ path: path2
15202
+ });
15203
+ }
15204
+ };
15205
+ const propValueInput = z.object({
14847
15206
  propId: z.string().optional(),
14848
15207
  instanceId: z.string(),
14849
15208
  name: z.string(),
@@ -14863,8 +15222,10 @@ z.object({
14863
15222
  ]),
14864
15223
  value: z.unknown(),
14865
15224
  required: z.boolean().optional()
15225
+ }).superRefine((value2, context) => {
15226
+ addExpressionIssues(context, getPropValueErrors(value2), ["value"]);
14866
15227
  });
14867
- z.object({
15228
+ const propBindingInput = z.object({
14868
15229
  propId: z.string().optional(),
14869
15230
  instanceId: z.string(),
14870
15231
  name: z.string(),
@@ -14883,16 +15244,25 @@ z.object({
14883
15244
  )
14884
15245
  })
14885
15246
  ])
15247
+ }).superRefine((value2, context) => {
15248
+ addExpressionIssues(
15249
+ context,
15250
+ getPropValueErrors({
15251
+ type: value2.binding.type,
15252
+ value: value2.binding.value
15253
+ }),
15254
+ ["binding", "value"]
15255
+ );
15256
+ });
15257
+ const propUpdatesInput = z.object({
15258
+ updates: z.array(propValueInput).min(1)
15259
+ });
15260
+ const propBindingsInput = z.object({
15261
+ bindings: z.array(propBindingInput).min(1)
15262
+ });
15263
+ const propDeletionsInput = z.object({
15264
+ deletions: z.array(z.object({ instanceId: z.string(), name: z.string() })).min(1)
14886
15265
  });
14887
- const getPropValueErrors = ({
14888
- type: type2,
14889
- value: value2
14890
- }) => {
14891
- if (type2 !== "expression") {
14892
- return [];
14893
- }
14894
- return lintExpression({ expression: String(value2) }).filter((diagnostic) => diagnostic.severity === "error").map((diagnostic) => diagnostic.message);
14895
- };
14896
15266
  const createMissingId = () => {
14897
15267
  throw new Error("createId is required when propId is not provided.");
14898
15268
  };
@@ -15345,6 +15715,44 @@ const createStyleClonePayload = ({
15345
15715
  (change) => change.patches.length === 0 ? [] : [change]
15346
15716
  );
15347
15717
  };
15718
+ const insertIndexInput = z.number().int().nonnegative();
15719
+ const appendInstancesInput = z.object({
15720
+ parentInstanceId: z.string(),
15721
+ mode: z.enum(["append", "prepend", "replace"]).optional(),
15722
+ insertIndex: insertIndexInput.optional(),
15723
+ children: z.array(
15724
+ z.object({
15725
+ instanceId: z.string().optional(),
15726
+ component: z.string().optional(),
15727
+ tag: z.string(),
15728
+ label: z.string().optional(),
15729
+ text: z.string().optional()
15730
+ })
15731
+ ).min(1)
15732
+ });
15733
+ const moveInstancesInput = z.object({
15734
+ moves: z.array(
15735
+ z.object({
15736
+ instanceId: z.string(),
15737
+ parentInstanceId: z.string(),
15738
+ insertIndex: insertIndexInput.optional()
15739
+ })
15740
+ ).min(1)
15741
+ });
15742
+ const cloneInstanceInput = z.object({
15743
+ sourceInstanceId: z.string(),
15744
+ targetParentInstanceId: z.string().optional(),
15745
+ insertIndex: insertIndexInput.optional()
15746
+ });
15747
+ const deleteInstancesInput = z.object({
15748
+ instanceIds: z.array(z.string()).min(1)
15749
+ });
15750
+ const updateTextInstanceInput = z.object({
15751
+ instanceId: z.string(),
15752
+ childIndex: z.number().int().nonnegative(),
15753
+ text: z.string(),
15754
+ mode: z.enum(["text", "expression"]).optional()
15755
+ });
15348
15756
  const getRequiredInstances = (state) => {
15349
15757
  if (state.instances === void 0) {
15350
15758
  return throwBuilderRuntimeError(
@@ -16093,7 +16501,7 @@ const getTextContentErrors = ({
16093
16501
  if (type2 === "text") {
16094
16502
  return [];
16095
16503
  }
16096
- return lintExpression({ expression: value2 }).filter((diagnostic) => diagnostic.severity === "error").map((diagnostic) => diagnostic.message);
16504
+ return getExpressionErrors(value2);
16097
16505
  };
16098
16506
  const createTextContentUpdatePayload = ({
16099
16507
  instanceId: instanceId2,
@@ -17275,6 +17683,20 @@ const insertWebstudioFragmentCopy = ({
17275
17683
  }
17276
17684
  return newDataIds;
17277
17685
  };
17686
+ const pageDuplicateInput = z.object({
17687
+ projectId: z.string(),
17688
+ pageId: z.string(),
17689
+ parentFolderId: z.string().optional(),
17690
+ name: z.string().min(1).optional(),
17691
+ path: z.string().optional()
17692
+ });
17693
+ const pageTemplateCreatePageInput = z.object({
17694
+ projectId: z.string(),
17695
+ templateId: z.string(),
17696
+ parentFolderId: z.string().optional(),
17697
+ name: z.string().min(1),
17698
+ path: z.string()
17699
+ });
17278
17700
  const contentModePageMetaFields = /* @__PURE__ */ new Set([
17279
17701
  "description",
17280
17702
  "title",
@@ -17772,7 +18194,7 @@ const getRequiredBreakpoints = (state) => {
17772
18194
  }
17773
18195
  return state.breakpoints;
17774
18196
  };
17775
- z.object({
18197
+ const projectSettingsUpdateInput = z.object({
17776
18198
  meta: z.record(z.unknown()).optional(),
17777
18199
  compiler: z.record(z.unknown()).optional()
17778
18200
  });
@@ -17878,16 +18300,24 @@ const listRedirects = (state) => ({
17878
18300
  redirects: getRequiredPages(state).redirects ?? []
17879
18301
  });
17880
18302
  const redirectStatusInput = z.enum(["301", "302"]);
17881
- z.object({
18303
+ const redirectFieldsInput = z.object({
17882
18304
  old: z.string(),
17883
18305
  new: z.string(),
17884
18306
  status: redirectStatusInput.optional()
17885
18307
  });
17886
- z.object({
18308
+ const redirectUpdateFieldsInput = z.object({
17887
18309
  old: z.string().optional(),
17888
18310
  new: z.string().optional(),
17889
18311
  status: redirectStatusInput.nullable().optional()
17890
18312
  });
18313
+ const redirectCreateInput = redirectFieldsInput;
18314
+ const redirectUpdateInput = z.object({
18315
+ old: z.string(),
18316
+ values: redirectUpdateFieldsInput
18317
+ });
18318
+ const redirectDeleteInput = z.object({
18319
+ old: z.string()
18320
+ });
17891
18321
  const findRedirectIndex = (redirects, oldPath) => redirects.findIndex((redirect) => redirect.old === oldPath);
17892
18322
  const parseRedirect = (input2) => {
17893
18323
  const result = pageRedirect.safeParse(input2);
@@ -17979,19 +18409,27 @@ const deleteRedirect = (state, input2) => {
17979
18409
  const listBreakpoints = (state) => ({
17980
18410
  breakpoints: Array.from(getRequiredBreakpoints(state).values())
17981
18411
  });
17982
- z.object({
18412
+ const breakpointFieldsInput = z.object({
17983
18413
  id: z.string(),
17984
18414
  label: z.string(),
17985
18415
  minWidth: z.number().optional(),
17986
18416
  maxWidth: z.number().optional(),
17987
18417
  condition: z.string().optional()
17988
18418
  });
17989
- z.object({
18419
+ const breakpointUpdateFieldsInput = z.object({
17990
18420
  label: z.string().optional(),
17991
18421
  minWidth: z.number().nullable().optional(),
17992
18422
  maxWidth: z.number().nullable().optional(),
17993
18423
  condition: z.string().nullable().optional()
17994
18424
  });
18425
+ const breakpointCreateInput = breakpointFieldsInput;
18426
+ const breakpointUpdateInput = z.object({
18427
+ breakpointId: z.string(),
18428
+ values: breakpointUpdateFieldsInput
18429
+ });
18430
+ const breakpointDeleteInput = z.object({
18431
+ breakpointId: z.string()
18432
+ });
17995
18433
  const parseBreakpoint = (input2) => {
17996
18434
  const result = breakpoint.safeParse(input2);
17997
18435
  if (result.success === false) {
@@ -28896,7 +29334,7 @@ const withDefaultBreakpoint = (input2, breakpoint2) => ({
28896
29334
  ...input2,
28897
29335
  breakpoint: input2.breakpoint ?? breakpoint2
28898
29336
  });
28899
- z.object({
29337
+ const styleUpdateInput = z.object({
28900
29338
  instanceId: z.string(),
28901
29339
  property: z.string(),
28902
29340
  value: z.unknown(),
@@ -28905,13 +29343,30 @@ z.object({
28905
29343
  listed: z.boolean().optional(),
28906
29344
  createLocalIfMissing: z.boolean().optional()
28907
29345
  });
28908
- z.object({
29346
+ const styleDeleteInput = z.object({
28909
29347
  instanceId: z.string(),
28910
29348
  property: z.string(),
28911
29349
  breakpoint: z.string().optional(),
28912
29350
  state: z.string().optional()
28913
29351
  });
28914
- z.object({
29352
+ const jsonArrayStringInput = (value2) => {
29353
+ if (typeof value2 !== "string") {
29354
+ return value2;
29355
+ }
29356
+ try {
29357
+ return JSON.parse(value2);
29358
+ } catch {
29359
+ return value2;
29360
+ }
29361
+ };
29362
+ const jsonArrayInput = (item) => z.preprocess(jsonArrayStringInput, z.array(item).min(1));
29363
+ const styleUpdateDeclarationsInput = z.object({
29364
+ updates: jsonArrayInput(styleUpdateInput)
29365
+ });
29366
+ const styleDeleteDeclarationsInput = z.object({
29367
+ deletions: jsonArrayInput(styleDeleteInput)
29368
+ });
29369
+ const styleReplaceInput = z.object({
28915
29370
  property: z.string(),
28916
29371
  fromValue: z.unknown(),
28917
29372
  toValue: z.unknown(),
@@ -28970,7 +29425,19 @@ const getDefinedCssVariableNames = (styles) => {
28970
29425
  }
28971
29426
  return names;
28972
29427
  };
28973
- z.union([z.string(), styleValue]);
29428
+ const cssVariableValueInput = z.union([z.string(), styleValue]);
29429
+ const cssVariableDefineInput = z.object({
29430
+ vars: z.record(cssVariableValueInput),
29431
+ overwrite: z.boolean().optional()
29432
+ });
29433
+ const cssVariableDeleteInput = z.object({
29434
+ names: z.array(z.string()).min(1),
29435
+ force: z.boolean().optional()
29436
+ });
29437
+ const cssVariableRewriteRefsInput = z.object({
29438
+ map: z.record(z.string()),
29439
+ scopeRegex: z.string().optional()
29440
+ });
28974
29441
  const validateCssVariableNameWithStyles = ({
28975
29442
  name: name2,
28976
29443
  styles,
@@ -29254,12 +29721,37 @@ const designTokenStyleInput = z.object({
29254
29721
  breakpoint: z.string().optional(),
29255
29722
  state: z.string().optional()
29256
29723
  });
29257
- z.object({
29724
+ const designTokenCreateInput = z.object({
29258
29725
  tokenId: z.string().optional(),
29259
29726
  name: z.string().min(1),
29260
29727
  styles: z.record(z.unknown()).optional(),
29261
29728
  declarations: z.array(designTokenStyleInput).optional()
29262
29729
  });
29730
+ const designTokenCreateManyInput = z.object({
29731
+ tokens: jsonArrayInput(designTokenCreateInput)
29732
+ });
29733
+ const designTokenStyleUpdatesInput = z.object({
29734
+ designTokenId: z.string(),
29735
+ updates: jsonArrayInput(designTokenStyleInput)
29736
+ });
29737
+ const designTokenStyleDeletionsInput = z.object({
29738
+ designTokenId: z.string(),
29739
+ deletions: jsonArrayInput(styleDeleteInput.omit({ instanceId: true }))
29740
+ });
29741
+ const designTokenAttachInput = z.object({
29742
+ designTokenId: z.string(),
29743
+ instanceIds: z.array(z.string()).min(1),
29744
+ position: z.enum(["before-local", "after-local"]).optional()
29745
+ });
29746
+ const designTokenDetachInput = z.object({
29747
+ designTokenId: z.string(),
29748
+ instanceIds: z.array(z.string()).min(1)
29749
+ });
29750
+ const designTokenExtractInput = z.object({
29751
+ instanceIds: z.array(z.string()).min(1),
29752
+ name: z.string().min(1),
29753
+ removeLocalProps: z.array(z.string()).optional()
29754
+ });
29263
29755
  const createTokenStyleSource = ({
29264
29756
  id,
29265
29757
  name: name2,
@@ -30314,15 +30806,11 @@ const builderRuntimeOperations = [
30314
30806
  ),
30315
30807
  runtimeOperation(
30316
30808
  "pages.create",
30317
- ({ state, input: input2, context }) => createPage(
30318
- state,
30319
- input2,
30320
- context
30321
- )
30809
+ ({ state, input: input2, context }) => createPage(state, pageCreateInput.parse(input2), context)
30322
30810
  ),
30323
30811
  runtimeOperation(
30324
30812
  "pages.update",
30325
- ({ state, input: input2 }) => updatePage(state, input2)
30813
+ ({ state, input: input2 }) => updatePage(state, pageUpdateInput.parse(input2))
30326
30814
  ),
30327
30815
  runtimeOperation(
30328
30816
  "projectSettings.get",
@@ -30332,7 +30820,7 @@ const builderRuntimeOperations = [
30332
30820
  "projectSettings.update",
30333
30821
  ({ state, input: input2 }) => updateProjectSettings(
30334
30822
  state,
30335
- input2
30823
+ projectSettingsUpdateInput.parse(input2)
30336
30824
  )
30337
30825
  ),
30338
30826
  runtimeOperation(
@@ -30343,21 +30831,21 @@ const builderRuntimeOperations = [
30343
30831
  "redirects.create",
30344
30832
  ({ state, input: input2 }) => createRedirect(
30345
30833
  state,
30346
- input2
30834
+ redirectCreateInput.parse(input2)
30347
30835
  )
30348
30836
  ),
30349
30837
  runtimeOperation(
30350
30838
  "redirects.update",
30351
30839
  ({ state, input: input2 }) => updateRedirect(
30352
30840
  state,
30353
- input2
30841
+ redirectUpdateInput.parse(input2)
30354
30842
  )
30355
30843
  ),
30356
30844
  runtimeOperation(
30357
30845
  "redirects.delete",
30358
30846
  ({ state, input: input2 }) => deleteRedirect(
30359
30847
  state,
30360
- input2
30848
+ redirectDeleteInput.parse(input2)
30361
30849
  )
30362
30850
  ),
30363
30851
  runtimeOperation(
@@ -30368,32 +30856,32 @@ const builderRuntimeOperations = [
30368
30856
  "breakpoints.create",
30369
30857
  ({ state, input: input2 }) => createBreakpoint(
30370
30858
  state,
30371
- input2
30859
+ breakpointCreateInput.parse(input2)
30372
30860
  )
30373
30861
  ),
30374
30862
  runtimeOperation(
30375
30863
  "breakpoints.update",
30376
30864
  ({ state, input: input2 }) => updateBreakpoint(
30377
30865
  state,
30378
- input2
30866
+ breakpointUpdateInput.parse(input2)
30379
30867
  )
30380
30868
  ),
30381
30869
  runtimeOperation(
30382
30870
  "breakpoints.delete",
30383
30871
  ({ state, input: input2 }) => deleteBreakpoint(
30384
30872
  state,
30385
- input2
30873
+ breakpointDeleteInput.parse(input2)
30386
30874
  )
30387
30875
  ),
30388
30876
  runtimeOperation(
30389
30877
  "pages.delete",
30390
- ({ state, input: input2 }) => deletePage(state, input2)
30878
+ ({ state, input: input2 }) => deletePage(state, pageDeleteInput.parse(input2))
30391
30879
  ),
30392
30880
  runtimeOperation(
30393
30881
  "pages.duplicate",
30394
30882
  ({ state, input: input2, context }) => duplicatePage(
30395
30883
  state,
30396
- input2,
30884
+ pageDuplicateInput.parse(input2),
30397
30885
  context
30398
30886
  )
30399
30887
  ),
@@ -30405,7 +30893,7 @@ const builderRuntimeOperations = [
30405
30893
  "pageTemplates.createPage",
30406
30894
  ({ state, input: input2, context }) => createPageFromTemplate(
30407
30895
  state,
30408
- input2,
30896
+ pageTemplateCreatePageInput.parse(input2),
30409
30897
  context
30410
30898
  )
30411
30899
  ),
@@ -30415,19 +30903,15 @@ const builderRuntimeOperations = [
30415
30903
  ),
30416
30904
  runtimeOperation(
30417
30905
  "folders.create",
30418
- ({ state, input: input2, context }) => createFolder(
30419
- state,
30420
- input2,
30421
- context
30422
- )
30906
+ ({ state, input: input2, context }) => createFolder(state, folderCreateInput.parse(input2), context)
30423
30907
  ),
30424
30908
  runtimeOperation(
30425
30909
  "folders.update",
30426
- ({ state, input: input2 }) => updateFolder(state, input2)
30910
+ ({ state, input: input2 }) => updateFolder(state, folderUpdateInput.parse(input2))
30427
30911
  ),
30428
30912
  runtimeOperation(
30429
30913
  "folders.delete",
30430
- ({ state, input: input2 }) => deleteFolder(state, input2)
30914
+ ({ state, input: input2 }) => deleteFolder(state, folderDeleteInput.parse(input2))
30431
30915
  ),
30432
30916
  runtimeOperation(
30433
30917
  "instances.list",
@@ -30447,22 +30931,19 @@ const builderRuntimeOperations = [
30447
30931
  "instances.append",
30448
30932
  ({ state, input: input2, context }) => appendInstances(
30449
30933
  state,
30450
- input2,
30934
+ appendInstancesInput.parse(input2),
30451
30935
  context
30452
30936
  )
30453
30937
  ),
30454
30938
  runtimeOperation(
30455
30939
  "instances.move",
30456
- ({ state, input: input2 }) => moveInstances(
30457
- state,
30458
- input2
30459
- )
30940
+ ({ state, input: input2 }) => moveInstances(state, moveInstancesInput.parse(input2))
30460
30941
  ),
30461
30942
  runtimeOperation(
30462
30943
  "instances.clone",
30463
30944
  ({ state, input: input2, context }) => cloneInstance(
30464
30945
  state,
30465
- input2,
30946
+ cloneInstanceInput.parse(input2),
30466
30947
  context
30467
30948
  )
30468
30949
  ),
@@ -30470,28 +30951,20 @@ const builderRuntimeOperations = [
30470
30951
  "instances.delete",
30471
30952
  ({ state, input: input2 }) => deleteInstances(
30472
30953
  state,
30473
- input2
30954
+ deleteInstancesInput.parse(input2)
30474
30955
  )
30475
30956
  ),
30476
30957
  runtimeOperation(
30477
30958
  "instances.updateProps",
30478
- ({ state, input: input2, context }) => updateProps(
30479
- state,
30480
- input2,
30481
- context
30482
- )
30959
+ ({ state, input: input2, context }) => updateProps(state, propUpdatesInput.parse(input2), context)
30483
30960
  ),
30484
30961
  runtimeOperation(
30485
30962
  "instances.deleteProps",
30486
- ({ state, input: input2 }) => deleteProps(state, input2)
30963
+ ({ state, input: input2 }) => deleteProps(state, propDeletionsInput.parse(input2))
30487
30964
  ),
30488
30965
  runtimeOperation(
30489
30966
  "instances.bindProps",
30490
- ({ state, input: input2, context }) => bindProps(
30491
- state,
30492
- input2,
30493
- context
30494
- )
30967
+ ({ state, input: input2, context }) => bindProps(state, propBindingsInput.parse(input2), context)
30495
30968
  ),
30496
30969
  runtimeOperation(
30497
30970
  "instances.listTexts",
@@ -30504,7 +30977,7 @@ const builderRuntimeOperations = [
30504
30977
  "instances.updateText",
30505
30978
  ({ state, input: input2 }) => updateTextInstance(
30506
30979
  state,
30507
- input2
30980
+ updateTextInstanceInput.parse(input2)
30508
30981
  )
30509
30982
  ),
30510
30983
  runtimeOperation(
@@ -30518,7 +30991,7 @@ const builderRuntimeOperations = [
30518
30991
  "styles.updateDeclarations",
30519
30992
  ({ state, input: input2, context }) => updateStyleDeclarations(
30520
30993
  state,
30521
- input2,
30994
+ styleUpdateDeclarationsInput.parse(input2),
30522
30995
  context
30523
30996
  )
30524
30997
  ),
@@ -30526,15 +30999,12 @@ const builderRuntimeOperations = [
30526
30999
  "styles.deleteDeclarations",
30527
31000
  ({ state, input: input2 }) => deleteStyleDeclarations(
30528
31001
  state,
30529
- input2
31002
+ styleDeleteDeclarationsInput.parse(input2)
30530
31003
  )
30531
31004
  ),
30532
31005
  runtimeOperation(
30533
31006
  "styles.replaceValues",
30534
- ({ state, input: input2 }) => replaceStyleValues(
30535
- state,
30536
- input2
30537
- )
31007
+ ({ state, input: input2 }) => replaceStyleValues(state, styleReplaceInput.parse(input2))
30538
31008
  ),
30539
31009
  runtimeOperation(
30540
31010
  "designTokens.list",
@@ -30547,7 +31017,7 @@ const builderRuntimeOperations = [
30547
31017
  "designTokens.create",
30548
31018
  ({ state, input: input2, context }) => createDesignTokens(
30549
31019
  state,
30550
- input2,
31020
+ designTokenCreateManyInput.parse(input2),
30551
31021
  context
30552
31022
  )
30553
31023
  ),
@@ -30555,35 +31025,29 @@ const builderRuntimeOperations = [
30555
31025
  "designTokens.updateStyles",
30556
31026
  ({ state, input: input2 }) => updateDesignTokenStyles(
30557
31027
  state,
30558
- input2
31028
+ designTokenStyleUpdatesInput.parse(input2)
30559
31029
  )
30560
31030
  ),
30561
31031
  runtimeOperation(
30562
31032
  "designTokens.deleteStyles",
30563
31033
  ({ state, input: input2 }) => deleteDesignTokenStyles(
30564
31034
  state,
30565
- input2
31035
+ designTokenStyleDeletionsInput.parse(input2)
30566
31036
  )
30567
31037
  ),
30568
31038
  runtimeOperation(
30569
31039
  "designTokens.attach",
30570
- ({ state, input: input2 }) => attachDesignToken(
30571
- state,
30572
- input2
30573
- )
31040
+ ({ state, input: input2 }) => attachDesignToken(state, designTokenAttachInput.parse(input2))
30574
31041
  ),
30575
31042
  runtimeOperation(
30576
31043
  "designTokens.detach",
30577
- ({ state, input: input2 }) => detachDesignToken(
30578
- state,
30579
- input2
30580
- )
31044
+ ({ state, input: input2 }) => detachDesignToken(state, designTokenDetachInput.parse(input2))
30581
31045
  ),
30582
31046
  runtimeOperation(
30583
31047
  "designTokens.extract",
30584
31048
  ({ state, input: input2, context }) => extractDesignToken(
30585
31049
  state,
30586
- input2,
31050
+ designTokenExtractInput.parse(input2),
30587
31051
  context
30588
31052
  )
30589
31053
  ),
@@ -30598,22 +31062,19 @@ const builderRuntimeOperations = [
30598
31062
  "cssVariables.define",
30599
31063
  ({ state, input: input2, context }) => defineCssVariables(
30600
31064
  state,
30601
- input2,
31065
+ cssVariableDefineInput.parse(input2),
30602
31066
  context
30603
31067
  )
30604
31068
  ),
30605
31069
  runtimeOperation(
30606
31070
  "cssVariables.delete",
30607
- ({ state, input: input2 }) => deleteCssVariables(
30608
- state,
30609
- input2
30610
- )
31071
+ ({ state, input: input2 }) => deleteCssVariables(state, cssVariableDeleteInput.parse(input2))
30611
31072
  ),
30612
31073
  runtimeOperation(
30613
31074
  "cssVariables.rewriteRefs",
30614
31075
  ({ state, input: input2 }) => rewriteCssVariableRefs(
30615
31076
  state,
30616
- input2
31077
+ cssVariableRewriteRefsInput.parse(input2)
30617
31078
  )
30618
31079
  ),
30619
31080
  runtimeOperation(
@@ -30627,23 +31088,17 @@ const builderRuntimeOperations = [
30627
31088
  "variables.create",
30628
31089
  ({ state, input: input2, context }) => createDataVariable(
30629
31090
  state,
30630
- input2,
31091
+ dataVariableCreateInput.parse(input2),
30631
31092
  context
30632
31093
  )
30633
31094
  ),
30634
31095
  runtimeOperation(
30635
31096
  "variables.update",
30636
- ({ state, input: input2 }) => updateDataVariable(
30637
- state,
30638
- input2
30639
- )
31097
+ ({ state, input: input2 }) => updateDataVariable(state, dataVariableUpdateInput.parse(input2))
30640
31098
  ),
30641
31099
  runtimeOperation(
30642
31100
  "variables.delete",
30643
- ({ state, input: input2 }) => deleteDataVariable(
30644
- state,
30645
- input2
30646
- )
31101
+ ({ state, input: input2 }) => deleteDataVariable(state, dataVariableDeleteInput.parse(input2))
30647
31102
  ),
30648
31103
  runtimeOperation(
30649
31104
  "resources.list",
@@ -30651,25 +31106,15 @@ const builderRuntimeOperations = [
30651
31106
  ),
30652
31107
  runtimeOperation(
30653
31108
  "resources.create",
30654
- ({ state, input: input2, context }) => createResource(
30655
- state,
30656
- input2,
30657
- context
30658
- )
31109
+ ({ state, input: input2, context }) => createResource(state, resourceCreateInput.parse(input2), context)
30659
31110
  ),
30660
31111
  runtimeOperation(
30661
31112
  "resources.update",
30662
- ({ state, input: input2 }) => updateResource(
30663
- state,
30664
- input2
30665
- )
31113
+ ({ state, input: input2 }) => updateResource(state, resourceUpdateInput.parse(input2))
30666
31114
  ),
30667
31115
  runtimeOperation(
30668
31116
  "resources.delete",
30669
- ({ state, input: input2 }) => deleteResource(
30670
- state,
30671
- input2
30672
- )
31117
+ ({ state, input: input2 }) => deleteResource(state, resourceDeleteInput.parse(input2))
30673
31118
  ),
30674
31119
  runtimeOperation(
30675
31120
  "assets.list",
@@ -30684,17 +31129,11 @@ const builderRuntimeOperations = [
30684
31129
  ),
30685
31130
  runtimeOperation(
30686
31131
  "assets.replace",
30687
- ({ state, input: input2 }) => replaceAsset(
30688
- state,
30689
- input2
30690
- )
31132
+ ({ state, input: input2 }) => replaceAsset(state, assetReplaceInput.parse(input2))
30691
31133
  ),
30692
31134
  runtimeOperation(
30693
31135
  "assets.delete",
30694
- ({ state, input: input2 }) => deleteAssets(
30695
- state,
30696
- input2
30697
- )
31136
+ ({ state, input: input2 }) => deleteAssets(state, assetDeleteInput.parse(input2))
30698
31137
  )
30699
31138
  ];
30700
31139
  const builderRuntimeOperationById = new Map(
@@ -34462,127 +34901,128 @@ const manualReplacements = {
34462
34901
  const apiManual = renderMarkdownTemplate(apiManualMarkdown, manualReplacements);
34463
34902
  const llmManual = renderMarkdownTemplate(llmManualMarkdown, manualReplacements);
34464
34903
  const mcpManual = renderMarkdownTemplate(mcpManualMarkdown, manualReplacements);
34904
+ const apiDocSections = readCliDocSections("manual-api");
34905
+ const llmDocSections = readCliDocSections("manual-llm");
34906
+ const mcpDocSections = readCliDocSections("manual-mcp");
34907
+ const mergeDocSections = (topic, json, sections) => {
34908
+ for (const fieldName of Object.keys(sections)) {
34909
+ if (Object.hasOwn(json, fieldName)) {
34910
+ throw new Error(
34911
+ `Doc metadata field "${fieldName}" conflicts with ${topic} manual JSON`
34912
+ );
34913
+ }
34914
+ }
34915
+ return { ...json, ...sections };
34916
+ };
34465
34917
  const topics = {
34466
34918
  api: {
34467
34919
  manual: apiManual,
34468
- json: {
34469
- topic: "api",
34470
- title: "Webstudio API CLI Manual",
34471
- workflows: [
34472
- "webstudio init --link <api-share-link> --json",
34473
- "webstudio permissions --json",
34474
- "webstudio schema api --json",
34475
- "webstudio publish deploy --target production --json",
34476
- "webstudio domains list --json",
34477
- "webstudio mcp"
34478
- ],
34479
- taskRecipes,
34480
- useCaseScenarios,
34481
- knownGaps: knownCliGaps,
34482
- topLevelCommands: topLevelCommandCatalog,
34483
- apiCommandsByArea,
34484
- mcpOnlyCommands: mcpOnlyCommandCatalog,
34485
- inputFileShapes,
34486
- mcpArgumentExamples,
34487
- commands: commandCatalog,
34488
- readCommands,
34489
- writeCommands,
34490
- mutationNamespaces: buildPatchNamespaces,
34491
- sessionBehavior: {
34492
- localReads: "Use compatible cached namespaces and fetch only missing or stale namespaces.",
34493
- localMutations: "Build patches locally, commit with the cached build version, and update local state only after remote commit succeeds.",
34494
- serverOnly: "Run remotely and invalidate/refetch namespaces declared by the public operation catalog.",
34495
- refreshFlag: "Use --refresh to refresh required namespaces before local-capable commands.",
34496
- metadata: "Successful command JSON includes meta.session with operationId, buildId, version, source, committed, compatibility, namespace metadata, and diagnostics."
34920
+ json: mergeDocSections(
34921
+ "api",
34922
+ {
34923
+ topic: "api",
34924
+ title: readCliDocTitle("manual-api"),
34925
+ workflows: [
34926
+ "webstudio init --link <api-share-link> --json",
34927
+ "webstudio permissions --json",
34928
+ "webstudio schema api --json",
34929
+ "webstudio publish deploy --target production --json",
34930
+ "webstudio domains list --json",
34931
+ "webstudio mcp"
34932
+ ],
34933
+ taskRecipes,
34934
+ useCaseScenarios,
34935
+ knownGaps: knownCliGaps,
34936
+ topLevelCommands: topLevelCommandCatalog,
34937
+ apiCommandsByArea,
34938
+ mcpOnlyCommands: mcpOnlyCommandCatalog,
34939
+ inputFileShapes,
34940
+ mcpArgumentExamples,
34941
+ commands: commandCatalog,
34942
+ readCommands,
34943
+ writeCommands,
34944
+ mutationNamespaces: buildPatchNamespaces,
34945
+ sessionBehavior: {
34946
+ localReads: "Use compatible cached namespaces and fetch only missing or stale namespaces.",
34947
+ localMutations: "Build patches locally, commit with the cached build version, and update local state only after remote commit succeeds.",
34948
+ serverOnly: "Run remotely and invalidate/refetch namespaces declared by the public operation catalog.",
34949
+ refreshFlag: "Use --refresh to refresh required namespaces before local-capable commands.",
34950
+ metadata: "Successful command JSON includes meta.session with operationId, buildId, version, source, committed, compatibility, namespace metadata, and diagnostics."
34951
+ }
34497
34952
  },
34498
- safetyRules: [
34499
- "Always pass --json.",
34500
- "Never pass project ids; commands use the configured project.",
34501
- "Read ids before writing.",
34502
- "Prefer semantic MCP write tools over apply-patch.",
34503
- "For MCP apply-patch, read the latest version with MCP snapshot before writing.",
34504
- "Reuse ids from MCP snapshot output when updating existing records.",
34505
- "Generate new unique ids when adding records.",
34506
- "Regenerate the patch after a version conflict."
34507
- ]
34508
- }
34953
+ apiDocSections
34954
+ )
34509
34955
  },
34510
34956
  llm: {
34511
34957
  manual: llmManual,
34512
- json: {
34513
- topic: "llm",
34514
- title: "Webstudio CLI Manual for LLMs",
34515
- discovery: [
34516
- "webstudio schema api --json",
34517
- "webstudio permissions --json",
34518
- "webstudio mcp",
34519
- "MCP tool: status",
34520
- "MCP resource: webstudio://project/tools"
34521
- ],
34522
- taskRecipes,
34523
- useCaseScenarios,
34524
- knownGaps: knownCliGaps,
34525
- topLevelCommands: topLevelCommandCatalog,
34526
- apiCommandsByArea,
34527
- mcpOnlyCommands: mcpOnlyCommandCatalog,
34528
- inputFileShapes,
34529
- mcpArgumentExamples,
34530
- commands: commandCatalog,
34531
- readCommands,
34532
- writeCommands,
34533
- sessionBehavior: [
34534
- "Read meta.session.source and meta.session.namespaces to understand whether data came from local cache, remote refresh, dry-run, or server-only execution.",
34535
- "Use --refresh before a local-capable command when the cached snapshot may be stale.",
34536
- "A mutation is durable only when meta.session.committed is true."
34537
- ],
34538
- writes: [
34539
- "Use MCP tools for fine-grained project edits.",
34540
- "Use top-level CLI only for link/sync/build/publish/domains/permissions/discovery workflows."
34541
- ],
34542
- rules: [
34543
- "Always pass --json.",
34544
- "Never guess ids for existing records. Read them first.",
34545
- "Use the configured project only.",
34546
- "Regenerate patches after VERSION_CONFLICT.",
34547
- "Use stdout JSON as the contract."
34548
- ]
34549
- }
34958
+ json: mergeDocSections(
34959
+ "llm",
34960
+ {
34961
+ topic: "llm",
34962
+ title: readCliDocTitle("manual-llm"),
34963
+ discovery: [
34964
+ "webstudio schema api --json",
34965
+ "webstudio permissions --json",
34966
+ "webstudio mcp",
34967
+ "MCP tool: status",
34968
+ "MCP resource: webstudio://project/tools"
34969
+ ],
34970
+ taskRecipes,
34971
+ useCaseScenarios,
34972
+ knownGaps: knownCliGaps,
34973
+ topLevelCommands: topLevelCommandCatalog,
34974
+ apiCommandsByArea,
34975
+ mcpOnlyCommands: mcpOnlyCommandCatalog,
34976
+ inputFileShapes,
34977
+ mcpArgumentExamples,
34978
+ commands: commandCatalog,
34979
+ readCommands,
34980
+ writeCommands,
34981
+ sessionBehavior: [
34982
+ "Read meta.session.source and meta.session.namespaces to understand whether data came from local cache, remote refresh, dry-run, or server-only execution.",
34983
+ "Use --refresh before a local-capable command when the cached snapshot may be stale.",
34984
+ "A mutation is durable only when meta.session.committed is true."
34985
+ ],
34986
+ writes: [
34987
+ "Use MCP tools for fine-grained project edits.",
34988
+ "Use top-level CLI only for link/sync/build/publish/domains/permissions/discovery workflows."
34989
+ ],
34990
+ visionVerificationLoop: [...mcpVisionVerificationLoop],
34991
+ screenshotVerification: screenshotVerificationSummary
34992
+ },
34993
+ llmDocSections
34994
+ )
34550
34995
  },
34551
34996
  mcp: {
34552
34997
  manual: mcpManual,
34553
- json: {
34554
- topic: "mcp",
34555
- title: "Webstudio MCP Manual",
34556
- startup: [
34557
- "webstudio init --link <api-share-link> --json",
34558
- "webstudio permissions --json",
34559
- "webstudio mcp"
34560
- ],
34561
- discovery: [
34562
- "tools/list",
34563
- "resources/list",
34564
- "meta.index",
34565
- "meta.guide",
34566
- "meta.get_more_tools"
34567
- ],
34568
- resources: [
34569
- "webstudio://project/status",
34570
- "webstudio://project/tools",
34571
- "webstudio://project/guide"
34572
- ],
34573
- rules: [
34574
- "stdout is reserved for MCP JSON-RPC while the server is running.",
34575
- "Operate on the configured project only.",
34576
- "Read ids before writing.",
34577
- "Prefer semantic tools over apply-patch.",
34578
- "Use status and refresh when cached namespaces may be stale.",
34579
- "A mutation is durable only when meta.session.committed is true.",
34580
- "For visual/design work, verify the rendered result with vision before finishing."
34581
- ],
34582
- visionVerificationLoop: [...mcpVisionVerificationLoop],
34583
- mcpArgumentExamples,
34584
- screenshotVerification: screenshotVerificationSummary
34585
- }
34998
+ json: mergeDocSections(
34999
+ "mcp",
35000
+ {
35001
+ topic: "mcp",
35002
+ title: readCliDocTitle("manual-mcp"),
35003
+ startup: [
35004
+ "webstudio init --link <api-share-link> --json",
35005
+ "webstudio permissions --json",
35006
+ "webstudio mcp"
35007
+ ],
35008
+ discovery: [
35009
+ "tools/list",
35010
+ "resources/list",
35011
+ "meta.index",
35012
+ "meta.guide",
35013
+ "meta.get_more_tools"
35014
+ ],
35015
+ resources: [
35016
+ "webstudio://project/status",
35017
+ "webstudio://project/tools",
35018
+ "webstudio://project/guide"
35019
+ ],
35020
+ visionVerificationLoop: [...mcpVisionVerificationLoop],
35021
+ mcpArgumentExamples,
35022
+ screenshotVerification: screenshotVerificationSummary
35023
+ },
35024
+ mcpDocSections
35025
+ )
34586
35026
  }
34587
35027
  };
34588
35028
  const man = (options) => {
@@ -39411,14 +39851,7 @@ const mcpOptions = (yargs) => yargs.example(
39411
39851
  ).example(
39412
39852
  "MCP tool: meta.guide",
39413
39853
  "Ask for the recommended workflow and relevant tools"
39414
- ).epilogue(
39415
- [
39416
- "Plain `webstudio mcp` starts the stdio MCP server.",
39417
- "Startup marks cached ProjectSession data stale so MCP tools read the current Builder dev build.",
39418
- "After startup, MCP clients discover capabilities with tools/list, resources/list, meta.index, meta.guide, and meta.get_more_tools.",
39419
- "stdout is reserved for MCP JSON-RPC messages while the server is running."
39420
- ].join("\n")
39421
- );
39854
+ ).epilogue(readCliDoc("mcp-startup-epilogue"));
39422
39855
  const mcp = async () => {
39423
39856
  const connection = await resolveApiConnection();
39424
39857
  const apiConnection = {