webstudio 0.274.3 → 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.3";
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-ByApfd6J.js")).createFramework();
8992
- const createReactRouterFramework = async () => (await import("./framework-react-router-D1HMM2Nm.js")).createFramework();
8993
- const createVikeSsgFramework = async () => (await import("./framework-vike-ssg-BGhpJT5M.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(
@@ -9077,6 +9094,25 @@ const generateRedirectsModule = (pageRedirects) => {
9077
9094
  export const redirects = ${JSON.stringify(redirects, null, 2)};
9078
9095
  `;
9079
9096
  };
9097
+ const generateRedirectFallbackRoute = (runtime) => {
9098
+ const loaderFunctionArgs = runtime === "react-router" ? "react-router" : "@remix-run/server-runtime";
9099
+ return `
9100
+ import { type LoaderFunctionArgs } from ${JSON.stringify(loaderFunctionArgs)};
9101
+ import { redirectRequest } from "../redirect-url";
9102
+ // @todo think about how to make __generated__ typeable
9103
+ // @ts-ignore
9104
+ import { redirects } from "../__generated__/$resources.redirects";
9105
+
9106
+ export const loader = ({ request }: LoaderFunctionArgs) => {
9107
+ const redirectResponse = redirectRequest(request, redirects);
9108
+ if (redirectResponse !== undefined) {
9109
+ return redirectResponse;
9110
+ }
9111
+
9112
+ throw new Response("Not Found", { status: 404 });
9113
+ };
9114
+ `;
9115
+ };
9080
9116
  const prebuild = async (options) => {
9081
9117
  var _a3, _b2, _c, _d, _e, _f, _g, _h, _i, _j;
9082
9118
  if (options.template.length === 0) {
@@ -9492,6 +9528,14 @@ Please check webstudio --help for more details`
9492
9528
  join(generatedDir, "$resources.redirects.ts"),
9493
9529
  generateRedirectsModule(pages2.redirects)
9494
9530
  );
9531
+ if (pages2.redirects !== void 0 && pages2.redirects.length > 0) {
9532
+ await createFileIfNotExists(
9533
+ join(routesDir, "$.tsx"),
9534
+ generateRedirectFallbackRoute(
9535
+ options.template.includes("react-router") ? "react-router" : "remix"
9536
+ )
9537
+ );
9538
+ }
9495
9539
  if (options.assets === true && siteData.assets.length > 0) {
9496
9540
  const downloading = spinner();
9497
9541
  downloading.start("Downloading fonts and images");
@@ -10880,6 +10924,10 @@ class StdioServerTransport {
10880
10924
  });
10881
10925
  }
10882
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];
10883
10931
  const isRecord = (value2) => typeof value2 === "object" && value2 !== null;
10884
10932
  const isScreenshotBrowser = (value2) => typeof value2 === "string" && screenshotBrowserChoices.includes(value2);
10885
10933
  const getRequestParams = (request) => isRecord(request) && isRecord(request.params) ? request.params : {};
@@ -10917,13 +10965,34 @@ const getOperationInputSchema = (operation) => {
10917
10965
  properties: Object.fromEntries(
10918
10966
  operation.inputFields.map((field) => [
10919
10967
  field,
10920
- {
10921
- description: `Public API input field \`${field}\`.`
10922
- }
10968
+ getOperationInputFieldSchema(operation, field)
10923
10969
  ])
10924
10970
  )
10925
10971
  };
10926
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
+ };
10927
10996
  const screenshotInputSchema = {
10928
10997
  ...emptyInputSchema,
10929
10998
  description: "Capture a visual screenshot for AI vision review. Pass { url } for any URL or { path } after preview.start.",
@@ -11089,6 +11158,53 @@ const mcpArgumentExamples = {
11089
11158
  text: "Launch faster"
11090
11159
  }
11091
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
+ ],
11092
11208
  "update-styles": [
11093
11209
  {
11094
11210
  updates: [
@@ -11100,6 +11216,11 @@ const mcpArgumentExamples = {
11100
11216
  ]
11101
11217
  }
11102
11218
  ],
11219
+ "delete-styles": [
11220
+ {
11221
+ deletions: [{ instanceId: "instance-id", property: "box-shadow" }]
11222
+ }
11223
+ ],
11103
11224
  "apply-patch": [
11104
11225
  {
11105
11226
  baseVersion: 12,
@@ -11635,12 +11756,15 @@ const filterCapabilities = (tools) => {
11635
11756
  tools: capability.tools.filter((tool) => names.has(tool))
11636
11757
  })).filter((capability) => capability.tools.length > 0);
11637
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.';
11638
11761
  const getMetaIndex = (tools, guidance) => {
11639
11762
  const names = new Set(tools.map((tool) => tool.name));
11640
11763
  const canVerifyVisually = ["preview.start", "screenshot"].every(
11641
11764
  (tool) => names.has(tool)
11642
11765
  );
11643
11766
  return {
11767
+ readThisFirst: startupGuidance,
11644
11768
  startHere: ["meta.index", "meta.guide", "status", "permissions"].filter(
11645
11769
  (tool) => names.has(tool)
11646
11770
  ),
@@ -11654,6 +11778,7 @@ const getMetaIndex = (tools, guidance) => {
11654
11778
  "Operate on the configured project only.",
11655
11779
  "Read ids before writing.",
11656
11780
  "Prefer semantic tools over apply-patch.",
11781
+ valuesVsBindingsRule,
11657
11782
  "Use status/refresh when cached data may be stale.",
11658
11783
  guidance == null ? void 0 : guidance.visualVerificationRule
11659
11784
  ].filter((rule) => rule !== void 0),
@@ -11677,6 +11802,7 @@ const getMetaGuide = (brief, tools, guidance) => {
11677
11802
  matches.some((tool) => tool.annotations.localCapable) ? "Call refresh if cached namespaces may be stale." : void 0,
11678
11803
  "Use focused read tools to collect ids and current values.",
11679
11804
  "Use the smallest semantic mutation tool that matches the requested change.",
11805
+ valuesVsBindingsRule,
11680
11806
  "Use apply-patch only when no semantic mutation tool fits.",
11681
11807
  canVerifyVisually && guidance !== void 0 ? guidance.getVisionWorkflowSummary({ includeDiff: canDiffScreenshots }) : void 0
11682
11808
  ].filter(Boolean),
@@ -11703,7 +11829,7 @@ const getMoreTools = (brief, tools) => ({
11703
11829
  mcpExamples: tool.mcpExamples ?? [],
11704
11830
  cliRequiredOptions: tool.cliRequiredOptions ?? [],
11705
11831
  cliExamples: tool.cliExamples ?? [],
11706
- 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}`,
11707
11833
  annotations: tool.annotations
11708
11834
  }))
11709
11835
  });
@@ -11933,8 +12059,8 @@ const createProjectSessionMcpCore = ({
11933
12059
  guidance
11934
12060
  }) => {
11935
12061
  let session;
11936
- const operationCommands = new Set(
11937
- operations.map((operation) => operation.command)
12062
+ const operationByCommand = new Map(
12063
+ operations.map((operation) => [operation.command, operation])
11938
12064
  );
11939
12065
  const listTools = () => listProjectSessionMcpTools(operations, {
11940
12066
  includeImport: importProject2 !== void 0,
@@ -12039,12 +12165,14 @@ const createProjectSessionMcpCore = ({
12039
12165
  if (name2 === "preview.status" && getPreviewStatus !== void 0) {
12040
12166
  return toMetaResult(await getPreviewStatus());
12041
12167
  }
12042
- if (operationCommands.has(name2) === false) {
12168
+ const operation = operationByCommand.get(name2);
12169
+ if (operation === void 0) {
12043
12170
  throw new Error(`Unknown MCP tool "${name2}".`);
12044
12171
  }
12172
+ const operationInput = wrapMcpRootArrayInput(operation, input2);
12045
12173
  const envelope = await executeOperation({
12046
12174
  command: name2,
12047
- input: input2,
12175
+ input: operationInput,
12048
12176
  dryRun
12049
12177
  });
12050
12178
  return toCallResult(envelope);
@@ -12107,7 +12235,7 @@ const createProjectSessionMcpServer = async ({
12107
12235
  tools: {},
12108
12236
  resources: {}
12109
12237
  },
12110
- 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
12111
12239
  }
12112
12240
  );
12113
12241
  server.setRequestHandler(ListToolsRequestSchema, async () => ({
@@ -12174,13 +12302,110 @@ const createMcpStdioTransport = async ({
12174
12302
  return new StdioServerTransport(stdin2, stdout2);
12175
12303
  };
12176
12304
  const cliDocs = {
12177
- "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',
12178
- "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',
12179
- "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",
12180
- "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",
12181
- "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": {}
12182
12405
  };
12183
12406
  const readCliDoc = (name2) => cliDocs[name2];
12407
+ const readCliDocTitle = (name2) => cliDocTitles[name2];
12408
+ const readCliDocSections = (name2) => cliDocSections[name2];
12184
12409
  const mcpVisionMarkdown = readCliDoc("mcp-vision");
12185
12410
  const getSection = (markdown, heading) => {
12186
12411
  const lines = markdown.split(/\r?\n/);
@@ -12242,6 +12467,14 @@ const createRuntimeMutation = ({
12242
12467
  invalidatesNamespaces,
12243
12468
  noop: payload.length === 0
12244
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
+ });
12245
12478
  const traverseAssetStyleValue = (value2, callback) => {
12246
12479
  callback(value2);
12247
12480
  if (value2.type === "tuple" || value2.type === "layers") {
@@ -12749,6 +12982,15 @@ const deleteAssets = (state, input2) => {
12749
12982
  invalidatesNamespaces: ["assets"]
12750
12983
  });
12751
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
+ };
12752
12994
  const getRequiredDataSources = (state) => {
12753
12995
  if (state.dataSources === void 0) {
12754
12996
  return throwBuilderRuntimeError(
@@ -12830,6 +13072,24 @@ const listDataVariables = (state, input2 = {}) => serializeDataVariables({
12830
13072
  dataSources: getRequiredDataSources(state),
12831
13073
  scopeInstanceId: input2.scopeInstanceId
12832
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
+ });
12833
13093
  const validateDataVariableNameWithSources = ({
12834
13094
  dataSources,
12835
13095
  name: name2,
@@ -13430,8 +13690,40 @@ const findResource = (resources, resourceId2) => {
13430
13690
  }
13431
13691
  }
13432
13692
  };
13433
- const resourceFieldsInput = resource.omit({ id: true }).extend({ control: z.enum(["system", "graphql"]).optional() });
13434
- 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
+ });
13435
13727
  const createResourceValue = ({
13436
13728
  id,
13437
13729
  control,
@@ -13454,14 +13746,7 @@ const createResourceValue = ({
13454
13746
  const getResourceExpressionErrors = (fields) => {
13455
13747
  const errors = [];
13456
13748
  const validate = (name2, expression) => {
13457
- if (expression === void 0) {
13458
- return;
13459
- }
13460
- for (const diagnostic of lintExpression({ expression })) {
13461
- if (diagnostic.severity === "error") {
13462
- errors.push(`${name2}: ${diagnostic.message}`);
13463
- }
13464
- }
13749
+ errors.push(...getNamedExpressionErrors(name2, expression));
13465
13750
  };
13466
13751
  validate("url", fields.url);
13467
13752
  validate("body", fields.body);
@@ -14342,7 +14627,7 @@ const createPageValue = ({
14342
14627
  pageId: pageId2,
14343
14628
  name: name2,
14344
14629
  path: path2,
14345
- title = name2,
14630
+ title = JSON.stringify(name2),
14346
14631
  rootInstanceId,
14347
14632
  meta = {}
14348
14633
  }) => ({
@@ -14359,13 +14644,29 @@ const emptyStringRemovesMetaFields = /* @__PURE__ */ new Set([
14359
14644
  "socialImageAssetId",
14360
14645
  "socialImageUrl"
14361
14646
  ]);
14647
+ const pageMetaExpressionFields = [
14648
+ "description",
14649
+ "language",
14650
+ "redirect",
14651
+ "socialImageUrl",
14652
+ "status",
14653
+ "content"
14654
+ ];
14362
14655
  const normalizePageMetaValue = (name2, value2) => {
14363
14656
  if (value2 === "" && emptyStringRemovesMetaFields.has(name2)) {
14364
14657
  return void 0;
14365
14658
  }
14366
14659
  return value2;
14367
14660
  };
14368
- 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({
14369
14670
  description: z.string().optional(),
14370
14671
  language: z.string().optional(),
14371
14672
  redirect: z.string().optional(),
@@ -14378,13 +14679,72 @@ const pageMetaInput = z.object({
14378
14679
  auth: pageAuth.optional(),
14379
14680
  custom: z.array(z.object({ property: z.string(), content: z.string() })).optional()
14380
14681
  });
14381
- 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({
14382
14708
  name: z.string().min(1).optional(),
14383
14709
  path: z.string().optional(),
14384
14710
  title: z.string().optional(),
14385
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(),
14386
14722
  meta: pageMetaInput.optional()
14387
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
+ });
14388
14748
  const pageMetaToPatchValue = (meta) => {
14389
14749
  const result = {};
14390
14750
  for (const [name2, value2] of Object.entries(meta)) {
@@ -14489,6 +14849,10 @@ const createPage = (state, input2, context) => {
14489
14849
  const pages2 = getRequiredPages(state);
14490
14850
  const parentFolderId = input2.parentFolderId ?? pages2.rootFolderId;
14491
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
+ }
14492
14856
  const pageId2 = input2.pageId ?? context.createId();
14493
14857
  if (pages2.pages.has(pageId2)) {
14494
14858
  return throwBuilderRuntimeError("CONFLICT", "Page id already exists");
@@ -14531,6 +14895,10 @@ const updatePage = (state, input2) => {
14531
14895
  if (page2 === void 0) {
14532
14896
  return throwBuilderRuntimeError("NOT_FOUND", "Page not found");
14533
14897
  }
14898
+ const expressionErrors = getPageExpressionErrors(input2.values);
14899
+ if (expressionErrors.length > 0) {
14900
+ return throwBuilderRuntimeError("BAD_REQUEST", expressionErrors.join("\n"));
14901
+ }
14534
14902
  if ((input2.values.path !== void 0 || input2.values.parentFolderId !== void 0) && isPathAvailable({
14535
14903
  pages: pages2,
14536
14904
  path: input2.values.path ?? page2.path,
@@ -14816,7 +15184,25 @@ const createPropBindingFromInput = ({
14816
15184
  type: binding.type,
14817
15185
  value: binding.value
14818
15186
  });
14819
- 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({
14820
15206
  propId: z.string().optional(),
14821
15207
  instanceId: z.string(),
14822
15208
  name: z.string(),
@@ -14836,8 +15222,10 @@ z.object({
14836
15222
  ]),
14837
15223
  value: z.unknown(),
14838
15224
  required: z.boolean().optional()
15225
+ }).superRefine((value2, context) => {
15226
+ addExpressionIssues(context, getPropValueErrors(value2), ["value"]);
14839
15227
  });
14840
- z.object({
15228
+ const propBindingInput = z.object({
14841
15229
  propId: z.string().optional(),
14842
15230
  instanceId: z.string(),
14843
15231
  name: z.string(),
@@ -14856,16 +15244,25 @@ z.object({
14856
15244
  )
14857
15245
  })
14858
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)
14859
15265
  });
14860
- const getPropValueErrors = ({
14861
- type: type2,
14862
- value: value2
14863
- }) => {
14864
- if (type2 !== "expression") {
14865
- return [];
14866
- }
14867
- return lintExpression({ expression: String(value2) }).filter((diagnostic) => diagnostic.severity === "error").map((diagnostic) => diagnostic.message);
14868
- };
14869
15266
  const createMissingId = () => {
14870
15267
  throw new Error("createId is required when propId is not provided.");
14871
15268
  };
@@ -15318,6 +15715,44 @@ const createStyleClonePayload = ({
15318
15715
  (change) => change.patches.length === 0 ? [] : [change]
15319
15716
  );
15320
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
+ });
15321
15756
  const getRequiredInstances = (state) => {
15322
15757
  if (state.instances === void 0) {
15323
15758
  return throwBuilderRuntimeError(
@@ -16066,7 +16501,7 @@ const getTextContentErrors = ({
16066
16501
  if (type2 === "text") {
16067
16502
  return [];
16068
16503
  }
16069
- return lintExpression({ expression: value2 }).filter((diagnostic) => diagnostic.severity === "error").map((diagnostic) => diagnostic.message);
16504
+ return getExpressionErrors(value2);
16070
16505
  };
16071
16506
  const createTextContentUpdatePayload = ({
16072
16507
  instanceId: instanceId2,
@@ -17248,6 +17683,20 @@ const insertWebstudioFragmentCopy = ({
17248
17683
  }
17249
17684
  return newDataIds;
17250
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
+ });
17251
17700
  const contentModePageMetaFields = /* @__PURE__ */ new Set([
17252
17701
  "description",
17253
17702
  "title",
@@ -17745,7 +18194,7 @@ const getRequiredBreakpoints = (state) => {
17745
18194
  }
17746
18195
  return state.breakpoints;
17747
18196
  };
17748
- z.object({
18197
+ const projectSettingsUpdateInput = z.object({
17749
18198
  meta: z.record(z.unknown()).optional(),
17750
18199
  compiler: z.record(z.unknown()).optional()
17751
18200
  });
@@ -17851,16 +18300,24 @@ const listRedirects = (state) => ({
17851
18300
  redirects: getRequiredPages(state).redirects ?? []
17852
18301
  });
17853
18302
  const redirectStatusInput = z.enum(["301", "302"]);
17854
- z.object({
18303
+ const redirectFieldsInput = z.object({
17855
18304
  old: z.string(),
17856
18305
  new: z.string(),
17857
18306
  status: redirectStatusInput.optional()
17858
18307
  });
17859
- z.object({
18308
+ const redirectUpdateFieldsInput = z.object({
17860
18309
  old: z.string().optional(),
17861
18310
  new: z.string().optional(),
17862
18311
  status: redirectStatusInput.nullable().optional()
17863
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
+ });
17864
18321
  const findRedirectIndex = (redirects, oldPath) => redirects.findIndex((redirect) => redirect.old === oldPath);
17865
18322
  const parseRedirect = (input2) => {
17866
18323
  const result = pageRedirect.safeParse(input2);
@@ -17952,19 +18409,27 @@ const deleteRedirect = (state, input2) => {
17952
18409
  const listBreakpoints = (state) => ({
17953
18410
  breakpoints: Array.from(getRequiredBreakpoints(state).values())
17954
18411
  });
17955
- z.object({
18412
+ const breakpointFieldsInput = z.object({
17956
18413
  id: z.string(),
17957
18414
  label: z.string(),
17958
18415
  minWidth: z.number().optional(),
17959
18416
  maxWidth: z.number().optional(),
17960
18417
  condition: z.string().optional()
17961
18418
  });
17962
- z.object({
18419
+ const breakpointUpdateFieldsInput = z.object({
17963
18420
  label: z.string().optional(),
17964
18421
  minWidth: z.number().nullable().optional(),
17965
18422
  maxWidth: z.number().nullable().optional(),
17966
18423
  condition: z.string().nullable().optional()
17967
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
+ });
17968
18433
  const parseBreakpoint = (input2) => {
17969
18434
  const result = breakpoint.safeParse(input2);
17970
18435
  if (result.success === false) {
@@ -28869,7 +29334,7 @@ const withDefaultBreakpoint = (input2, breakpoint2) => ({
28869
29334
  ...input2,
28870
29335
  breakpoint: input2.breakpoint ?? breakpoint2
28871
29336
  });
28872
- z.object({
29337
+ const styleUpdateInput = z.object({
28873
29338
  instanceId: z.string(),
28874
29339
  property: z.string(),
28875
29340
  value: z.unknown(),
@@ -28878,13 +29343,30 @@ z.object({
28878
29343
  listed: z.boolean().optional(),
28879
29344
  createLocalIfMissing: z.boolean().optional()
28880
29345
  });
28881
- z.object({
29346
+ const styleDeleteInput = z.object({
28882
29347
  instanceId: z.string(),
28883
29348
  property: z.string(),
28884
29349
  breakpoint: z.string().optional(),
28885
29350
  state: z.string().optional()
28886
29351
  });
28887
- 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({
28888
29370
  property: z.string(),
28889
29371
  fromValue: z.unknown(),
28890
29372
  toValue: z.unknown(),
@@ -28943,7 +29425,19 @@ const getDefinedCssVariableNames = (styles) => {
28943
29425
  }
28944
29426
  return names;
28945
29427
  };
28946
- 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
+ });
28947
29441
  const validateCssVariableNameWithStyles = ({
28948
29442
  name: name2,
28949
29443
  styles,
@@ -29227,12 +29721,37 @@ const designTokenStyleInput = z.object({
29227
29721
  breakpoint: z.string().optional(),
29228
29722
  state: z.string().optional()
29229
29723
  });
29230
- z.object({
29724
+ const designTokenCreateInput = z.object({
29231
29725
  tokenId: z.string().optional(),
29232
29726
  name: z.string().min(1),
29233
29727
  styles: z.record(z.unknown()).optional(),
29234
29728
  declarations: z.array(designTokenStyleInput).optional()
29235
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
+ });
29236
29755
  const createTokenStyleSource = ({
29237
29756
  id,
29238
29757
  name: name2,
@@ -30287,15 +30806,11 @@ const builderRuntimeOperations = [
30287
30806
  ),
30288
30807
  runtimeOperation(
30289
30808
  "pages.create",
30290
- ({ state, input: input2, context }) => createPage(
30291
- state,
30292
- input2,
30293
- context
30294
- )
30809
+ ({ state, input: input2, context }) => createPage(state, pageCreateInput.parse(input2), context)
30295
30810
  ),
30296
30811
  runtimeOperation(
30297
30812
  "pages.update",
30298
- ({ state, input: input2 }) => updatePage(state, input2)
30813
+ ({ state, input: input2 }) => updatePage(state, pageUpdateInput.parse(input2))
30299
30814
  ),
30300
30815
  runtimeOperation(
30301
30816
  "projectSettings.get",
@@ -30305,7 +30820,7 @@ const builderRuntimeOperations = [
30305
30820
  "projectSettings.update",
30306
30821
  ({ state, input: input2 }) => updateProjectSettings(
30307
30822
  state,
30308
- input2
30823
+ projectSettingsUpdateInput.parse(input2)
30309
30824
  )
30310
30825
  ),
30311
30826
  runtimeOperation(
@@ -30316,21 +30831,21 @@ const builderRuntimeOperations = [
30316
30831
  "redirects.create",
30317
30832
  ({ state, input: input2 }) => createRedirect(
30318
30833
  state,
30319
- input2
30834
+ redirectCreateInput.parse(input2)
30320
30835
  )
30321
30836
  ),
30322
30837
  runtimeOperation(
30323
30838
  "redirects.update",
30324
30839
  ({ state, input: input2 }) => updateRedirect(
30325
30840
  state,
30326
- input2
30841
+ redirectUpdateInput.parse(input2)
30327
30842
  )
30328
30843
  ),
30329
30844
  runtimeOperation(
30330
30845
  "redirects.delete",
30331
30846
  ({ state, input: input2 }) => deleteRedirect(
30332
30847
  state,
30333
- input2
30848
+ redirectDeleteInput.parse(input2)
30334
30849
  )
30335
30850
  ),
30336
30851
  runtimeOperation(
@@ -30341,32 +30856,32 @@ const builderRuntimeOperations = [
30341
30856
  "breakpoints.create",
30342
30857
  ({ state, input: input2 }) => createBreakpoint(
30343
30858
  state,
30344
- input2
30859
+ breakpointCreateInput.parse(input2)
30345
30860
  )
30346
30861
  ),
30347
30862
  runtimeOperation(
30348
30863
  "breakpoints.update",
30349
30864
  ({ state, input: input2 }) => updateBreakpoint(
30350
30865
  state,
30351
- input2
30866
+ breakpointUpdateInput.parse(input2)
30352
30867
  )
30353
30868
  ),
30354
30869
  runtimeOperation(
30355
30870
  "breakpoints.delete",
30356
30871
  ({ state, input: input2 }) => deleteBreakpoint(
30357
30872
  state,
30358
- input2
30873
+ breakpointDeleteInput.parse(input2)
30359
30874
  )
30360
30875
  ),
30361
30876
  runtimeOperation(
30362
30877
  "pages.delete",
30363
- ({ state, input: input2 }) => deletePage(state, input2)
30878
+ ({ state, input: input2 }) => deletePage(state, pageDeleteInput.parse(input2))
30364
30879
  ),
30365
30880
  runtimeOperation(
30366
30881
  "pages.duplicate",
30367
30882
  ({ state, input: input2, context }) => duplicatePage(
30368
30883
  state,
30369
- input2,
30884
+ pageDuplicateInput.parse(input2),
30370
30885
  context
30371
30886
  )
30372
30887
  ),
@@ -30378,7 +30893,7 @@ const builderRuntimeOperations = [
30378
30893
  "pageTemplates.createPage",
30379
30894
  ({ state, input: input2, context }) => createPageFromTemplate(
30380
30895
  state,
30381
- input2,
30896
+ pageTemplateCreatePageInput.parse(input2),
30382
30897
  context
30383
30898
  )
30384
30899
  ),
@@ -30388,19 +30903,15 @@ const builderRuntimeOperations = [
30388
30903
  ),
30389
30904
  runtimeOperation(
30390
30905
  "folders.create",
30391
- ({ state, input: input2, context }) => createFolder(
30392
- state,
30393
- input2,
30394
- context
30395
- )
30906
+ ({ state, input: input2, context }) => createFolder(state, folderCreateInput.parse(input2), context)
30396
30907
  ),
30397
30908
  runtimeOperation(
30398
30909
  "folders.update",
30399
- ({ state, input: input2 }) => updateFolder(state, input2)
30910
+ ({ state, input: input2 }) => updateFolder(state, folderUpdateInput.parse(input2))
30400
30911
  ),
30401
30912
  runtimeOperation(
30402
30913
  "folders.delete",
30403
- ({ state, input: input2 }) => deleteFolder(state, input2)
30914
+ ({ state, input: input2 }) => deleteFolder(state, folderDeleteInput.parse(input2))
30404
30915
  ),
30405
30916
  runtimeOperation(
30406
30917
  "instances.list",
@@ -30420,22 +30931,19 @@ const builderRuntimeOperations = [
30420
30931
  "instances.append",
30421
30932
  ({ state, input: input2, context }) => appendInstances(
30422
30933
  state,
30423
- input2,
30934
+ appendInstancesInput.parse(input2),
30424
30935
  context
30425
30936
  )
30426
30937
  ),
30427
30938
  runtimeOperation(
30428
30939
  "instances.move",
30429
- ({ state, input: input2 }) => moveInstances(
30430
- state,
30431
- input2
30432
- )
30940
+ ({ state, input: input2 }) => moveInstances(state, moveInstancesInput.parse(input2))
30433
30941
  ),
30434
30942
  runtimeOperation(
30435
30943
  "instances.clone",
30436
30944
  ({ state, input: input2, context }) => cloneInstance(
30437
30945
  state,
30438
- input2,
30946
+ cloneInstanceInput.parse(input2),
30439
30947
  context
30440
30948
  )
30441
30949
  ),
@@ -30443,28 +30951,20 @@ const builderRuntimeOperations = [
30443
30951
  "instances.delete",
30444
30952
  ({ state, input: input2 }) => deleteInstances(
30445
30953
  state,
30446
- input2
30954
+ deleteInstancesInput.parse(input2)
30447
30955
  )
30448
30956
  ),
30449
30957
  runtimeOperation(
30450
30958
  "instances.updateProps",
30451
- ({ state, input: input2, context }) => updateProps(
30452
- state,
30453
- input2,
30454
- context
30455
- )
30959
+ ({ state, input: input2, context }) => updateProps(state, propUpdatesInput.parse(input2), context)
30456
30960
  ),
30457
30961
  runtimeOperation(
30458
30962
  "instances.deleteProps",
30459
- ({ state, input: input2 }) => deleteProps(state, input2)
30963
+ ({ state, input: input2 }) => deleteProps(state, propDeletionsInput.parse(input2))
30460
30964
  ),
30461
30965
  runtimeOperation(
30462
30966
  "instances.bindProps",
30463
- ({ state, input: input2, context }) => bindProps(
30464
- state,
30465
- input2,
30466
- context
30467
- )
30967
+ ({ state, input: input2, context }) => bindProps(state, propBindingsInput.parse(input2), context)
30468
30968
  ),
30469
30969
  runtimeOperation(
30470
30970
  "instances.listTexts",
@@ -30477,7 +30977,7 @@ const builderRuntimeOperations = [
30477
30977
  "instances.updateText",
30478
30978
  ({ state, input: input2 }) => updateTextInstance(
30479
30979
  state,
30480
- input2
30980
+ updateTextInstanceInput.parse(input2)
30481
30981
  )
30482
30982
  ),
30483
30983
  runtimeOperation(
@@ -30491,7 +30991,7 @@ const builderRuntimeOperations = [
30491
30991
  "styles.updateDeclarations",
30492
30992
  ({ state, input: input2, context }) => updateStyleDeclarations(
30493
30993
  state,
30494
- input2,
30994
+ styleUpdateDeclarationsInput.parse(input2),
30495
30995
  context
30496
30996
  )
30497
30997
  ),
@@ -30499,15 +30999,12 @@ const builderRuntimeOperations = [
30499
30999
  "styles.deleteDeclarations",
30500
31000
  ({ state, input: input2 }) => deleteStyleDeclarations(
30501
31001
  state,
30502
- input2
31002
+ styleDeleteDeclarationsInput.parse(input2)
30503
31003
  )
30504
31004
  ),
30505
31005
  runtimeOperation(
30506
31006
  "styles.replaceValues",
30507
- ({ state, input: input2 }) => replaceStyleValues(
30508
- state,
30509
- input2
30510
- )
31007
+ ({ state, input: input2 }) => replaceStyleValues(state, styleReplaceInput.parse(input2))
30511
31008
  ),
30512
31009
  runtimeOperation(
30513
31010
  "designTokens.list",
@@ -30520,7 +31017,7 @@ const builderRuntimeOperations = [
30520
31017
  "designTokens.create",
30521
31018
  ({ state, input: input2, context }) => createDesignTokens(
30522
31019
  state,
30523
- input2,
31020
+ designTokenCreateManyInput.parse(input2),
30524
31021
  context
30525
31022
  )
30526
31023
  ),
@@ -30528,35 +31025,29 @@ const builderRuntimeOperations = [
30528
31025
  "designTokens.updateStyles",
30529
31026
  ({ state, input: input2 }) => updateDesignTokenStyles(
30530
31027
  state,
30531
- input2
31028
+ designTokenStyleUpdatesInput.parse(input2)
30532
31029
  )
30533
31030
  ),
30534
31031
  runtimeOperation(
30535
31032
  "designTokens.deleteStyles",
30536
31033
  ({ state, input: input2 }) => deleteDesignTokenStyles(
30537
31034
  state,
30538
- input2
31035
+ designTokenStyleDeletionsInput.parse(input2)
30539
31036
  )
30540
31037
  ),
30541
31038
  runtimeOperation(
30542
31039
  "designTokens.attach",
30543
- ({ state, input: input2 }) => attachDesignToken(
30544
- state,
30545
- input2
30546
- )
31040
+ ({ state, input: input2 }) => attachDesignToken(state, designTokenAttachInput.parse(input2))
30547
31041
  ),
30548
31042
  runtimeOperation(
30549
31043
  "designTokens.detach",
30550
- ({ state, input: input2 }) => detachDesignToken(
30551
- state,
30552
- input2
30553
- )
31044
+ ({ state, input: input2 }) => detachDesignToken(state, designTokenDetachInput.parse(input2))
30554
31045
  ),
30555
31046
  runtimeOperation(
30556
31047
  "designTokens.extract",
30557
31048
  ({ state, input: input2, context }) => extractDesignToken(
30558
31049
  state,
30559
- input2,
31050
+ designTokenExtractInput.parse(input2),
30560
31051
  context
30561
31052
  )
30562
31053
  ),
@@ -30571,22 +31062,19 @@ const builderRuntimeOperations = [
30571
31062
  "cssVariables.define",
30572
31063
  ({ state, input: input2, context }) => defineCssVariables(
30573
31064
  state,
30574
- input2,
31065
+ cssVariableDefineInput.parse(input2),
30575
31066
  context
30576
31067
  )
30577
31068
  ),
30578
31069
  runtimeOperation(
30579
31070
  "cssVariables.delete",
30580
- ({ state, input: input2 }) => deleteCssVariables(
30581
- state,
30582
- input2
30583
- )
31071
+ ({ state, input: input2 }) => deleteCssVariables(state, cssVariableDeleteInput.parse(input2))
30584
31072
  ),
30585
31073
  runtimeOperation(
30586
31074
  "cssVariables.rewriteRefs",
30587
31075
  ({ state, input: input2 }) => rewriteCssVariableRefs(
30588
31076
  state,
30589
- input2
31077
+ cssVariableRewriteRefsInput.parse(input2)
30590
31078
  )
30591
31079
  ),
30592
31080
  runtimeOperation(
@@ -30600,23 +31088,17 @@ const builderRuntimeOperations = [
30600
31088
  "variables.create",
30601
31089
  ({ state, input: input2, context }) => createDataVariable(
30602
31090
  state,
30603
- input2,
31091
+ dataVariableCreateInput.parse(input2),
30604
31092
  context
30605
31093
  )
30606
31094
  ),
30607
31095
  runtimeOperation(
30608
31096
  "variables.update",
30609
- ({ state, input: input2 }) => updateDataVariable(
30610
- state,
30611
- input2
30612
- )
31097
+ ({ state, input: input2 }) => updateDataVariable(state, dataVariableUpdateInput.parse(input2))
30613
31098
  ),
30614
31099
  runtimeOperation(
30615
31100
  "variables.delete",
30616
- ({ state, input: input2 }) => deleteDataVariable(
30617
- state,
30618
- input2
30619
- )
31101
+ ({ state, input: input2 }) => deleteDataVariable(state, dataVariableDeleteInput.parse(input2))
30620
31102
  ),
30621
31103
  runtimeOperation(
30622
31104
  "resources.list",
@@ -30624,25 +31106,15 @@ const builderRuntimeOperations = [
30624
31106
  ),
30625
31107
  runtimeOperation(
30626
31108
  "resources.create",
30627
- ({ state, input: input2, context }) => createResource(
30628
- state,
30629
- input2,
30630
- context
30631
- )
31109
+ ({ state, input: input2, context }) => createResource(state, resourceCreateInput.parse(input2), context)
30632
31110
  ),
30633
31111
  runtimeOperation(
30634
31112
  "resources.update",
30635
- ({ state, input: input2 }) => updateResource(
30636
- state,
30637
- input2
30638
- )
31113
+ ({ state, input: input2 }) => updateResource(state, resourceUpdateInput.parse(input2))
30639
31114
  ),
30640
31115
  runtimeOperation(
30641
31116
  "resources.delete",
30642
- ({ state, input: input2 }) => deleteResource(
30643
- state,
30644
- input2
30645
- )
31117
+ ({ state, input: input2 }) => deleteResource(state, resourceDeleteInput.parse(input2))
30646
31118
  ),
30647
31119
  runtimeOperation(
30648
31120
  "assets.list",
@@ -30657,17 +31129,11 @@ const builderRuntimeOperations = [
30657
31129
  ),
30658
31130
  runtimeOperation(
30659
31131
  "assets.replace",
30660
- ({ state, input: input2 }) => replaceAsset(
30661
- state,
30662
- input2
30663
- )
31132
+ ({ state, input: input2 }) => replaceAsset(state, assetReplaceInput.parse(input2))
30664
31133
  ),
30665
31134
  runtimeOperation(
30666
31135
  "assets.delete",
30667
- ({ state, input: input2 }) => deleteAssets(
30668
- state,
30669
- input2
30670
- )
31136
+ ({ state, input: input2 }) => deleteAssets(state, assetDeleteInput.parse(input2))
30671
31137
  )
30672
31138
  ];
30673
31139
  const builderRuntimeOperationById = new Map(
@@ -34435,127 +34901,128 @@ const manualReplacements = {
34435
34901
  const apiManual = renderMarkdownTemplate(apiManualMarkdown, manualReplacements);
34436
34902
  const llmManual = renderMarkdownTemplate(llmManualMarkdown, manualReplacements);
34437
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
+ };
34438
34917
  const topics = {
34439
34918
  api: {
34440
34919
  manual: apiManual,
34441
- json: {
34442
- topic: "api",
34443
- title: "Webstudio API CLI Manual",
34444
- workflows: [
34445
- "webstudio init --link <api-share-link> --json",
34446
- "webstudio permissions --json",
34447
- "webstudio schema api --json",
34448
- "webstudio publish deploy --target production --json",
34449
- "webstudio domains list --json",
34450
- "webstudio mcp"
34451
- ],
34452
- taskRecipes,
34453
- useCaseScenarios,
34454
- knownGaps: knownCliGaps,
34455
- topLevelCommands: topLevelCommandCatalog,
34456
- apiCommandsByArea,
34457
- mcpOnlyCommands: mcpOnlyCommandCatalog,
34458
- inputFileShapes,
34459
- mcpArgumentExamples,
34460
- commands: commandCatalog,
34461
- readCommands,
34462
- writeCommands,
34463
- mutationNamespaces: buildPatchNamespaces,
34464
- sessionBehavior: {
34465
- localReads: "Use compatible cached namespaces and fetch only missing or stale namespaces.",
34466
- localMutations: "Build patches locally, commit with the cached build version, and update local state only after remote commit succeeds.",
34467
- serverOnly: "Run remotely and invalidate/refetch namespaces declared by the public operation catalog.",
34468
- refreshFlag: "Use --refresh to refresh required namespaces before local-capable commands.",
34469
- 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
+ }
34470
34952
  },
34471
- safetyRules: [
34472
- "Always pass --json.",
34473
- "Never pass project ids; commands use the configured project.",
34474
- "Read ids before writing.",
34475
- "Prefer semantic MCP write tools over apply-patch.",
34476
- "For MCP apply-patch, read the latest version with MCP snapshot before writing.",
34477
- "Reuse ids from MCP snapshot output when updating existing records.",
34478
- "Generate new unique ids when adding records.",
34479
- "Regenerate the patch after a version conflict."
34480
- ]
34481
- }
34953
+ apiDocSections
34954
+ )
34482
34955
  },
34483
34956
  llm: {
34484
34957
  manual: llmManual,
34485
- json: {
34486
- topic: "llm",
34487
- title: "Webstudio CLI Manual for LLMs",
34488
- discovery: [
34489
- "webstudio schema api --json",
34490
- "webstudio permissions --json",
34491
- "webstudio mcp",
34492
- "MCP tool: status",
34493
- "MCP resource: webstudio://project/tools"
34494
- ],
34495
- taskRecipes,
34496
- useCaseScenarios,
34497
- knownGaps: knownCliGaps,
34498
- topLevelCommands: topLevelCommandCatalog,
34499
- apiCommandsByArea,
34500
- mcpOnlyCommands: mcpOnlyCommandCatalog,
34501
- inputFileShapes,
34502
- mcpArgumentExamples,
34503
- commands: commandCatalog,
34504
- readCommands,
34505
- writeCommands,
34506
- sessionBehavior: [
34507
- "Read meta.session.source and meta.session.namespaces to understand whether data came from local cache, remote refresh, dry-run, or server-only execution.",
34508
- "Use --refresh before a local-capable command when the cached snapshot may be stale.",
34509
- "A mutation is durable only when meta.session.committed is true."
34510
- ],
34511
- writes: [
34512
- "Use MCP tools for fine-grained project edits.",
34513
- "Use top-level CLI only for link/sync/build/publish/domains/permissions/discovery workflows."
34514
- ],
34515
- rules: [
34516
- "Always pass --json.",
34517
- "Never guess ids for existing records. Read them first.",
34518
- "Use the configured project only.",
34519
- "Regenerate patches after VERSION_CONFLICT.",
34520
- "Use stdout JSON as the contract."
34521
- ]
34522
- }
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
+ )
34523
34995
  },
34524
34996
  mcp: {
34525
34997
  manual: mcpManual,
34526
- json: {
34527
- topic: "mcp",
34528
- title: "Webstudio MCP Manual",
34529
- startup: [
34530
- "webstudio init --link <api-share-link> --json",
34531
- "webstudio permissions --json",
34532
- "webstudio mcp"
34533
- ],
34534
- discovery: [
34535
- "tools/list",
34536
- "resources/list",
34537
- "meta.index",
34538
- "meta.guide",
34539
- "meta.get_more_tools"
34540
- ],
34541
- resources: [
34542
- "webstudio://project/status",
34543
- "webstudio://project/tools",
34544
- "webstudio://project/guide"
34545
- ],
34546
- rules: [
34547
- "stdout is reserved for MCP JSON-RPC while the server is running.",
34548
- "Operate on the configured project only.",
34549
- "Read ids before writing.",
34550
- "Prefer semantic tools over apply-patch.",
34551
- "Use status and refresh when cached namespaces may be stale.",
34552
- "A mutation is durable only when meta.session.committed is true.",
34553
- "For visual/design work, verify the rendered result with vision before finishing."
34554
- ],
34555
- visionVerificationLoop: [...mcpVisionVerificationLoop],
34556
- mcpArgumentExamples,
34557
- screenshotVerification: screenshotVerificationSummary
34558
- }
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
+ )
34559
35026
  }
34560
35027
  };
34561
35028
  const man = (options) => {
@@ -39371,6 +39838,10 @@ const captureScreenshotWithBrowserInstall = async (options, dependencies2 = defa
39371
39838
  return captureScreenshot(options, dependencies2);
39372
39839
  }
39373
39840
  };
39841
+ const prepareMcpProjectSession = async (session) => {
39842
+ await session.initialize();
39843
+ await session.markStale(builderNamespaces);
39844
+ };
39374
39845
  const mcpOptions = (yargs) => yargs.example(
39375
39846
  "$0 mcp",
39376
39847
  "Run a local MCP server over stdio for the configured Webstudio project"
@@ -39380,13 +39851,7 @@ const mcpOptions = (yargs) => yargs.example(
39380
39851
  ).example(
39381
39852
  "MCP tool: meta.guide",
39382
39853
  "Ask for the recommended workflow and relevant tools"
39383
- ).epilogue(
39384
- [
39385
- "Plain `webstudio mcp` starts the stdio MCP server.",
39386
- "After startup, MCP clients discover capabilities with tools/list, resources/list, meta.index, meta.guide, and meta.get_more_tools.",
39387
- "stdout is reserved for MCP JSON-RPC messages while the server is running."
39388
- ].join("\n")
39389
- );
39854
+ ).epilogue(readCliDoc("mcp-startup-epilogue"));
39390
39855
  const mcp = async () => {
39391
39856
  const connection = await resolveApiConnection();
39392
39857
  const apiConnection = {
@@ -39404,6 +39869,7 @@ const mcp = async () => {
39404
39869
  }
39405
39870
  };
39406
39871
  const session = createCliProjectSession({ connection: apiConnection });
39872
+ await prepareMcpProjectSession(session);
39407
39873
  const preview2 = createPreviewController({ host: "127.0.0.1", port: 5173 });
39408
39874
  await connectProjectSessionMcpServer({
39409
39875
  operations: publicApiOperations,