@wix/agent-skills 1.22.0 → 1.24.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (45) hide show
  1. package/package.json +1 -1
  2. package/skills/wix-app/SKILL.md +12 -4
  3. package/skills/wix-app/references/APP_VALIDATION.md +16 -10
  4. package/skills/wix-app/references/EDITOR_REACT_COMPONENT.md +64 -50
  5. package/skills/wix-app/references/SDK_MODULE_MAP.md +2 -0
  6. package/skills/wix-app/references/dashboard-page/DRAFT_TEMPLATE.md +1 -1
  7. package/skills/wix-app/references/editor-react-component/ACCESSIBILITY.md +4 -3
  8. package/skills/wix-app/references/editor-react-component/ANIMATED-COMPONENTS.md +28 -25
  9. package/skills/wix-app/references/editor-react-component/BRANDED-COMPONENTS.md +8 -2
  10. package/skills/wix-app/references/editor-react-component/COMPONENT-CONTRACT.md +12 -14
  11. package/skills/wix-app/references/editor-react-component/CSS-GUIDELINES.md +4 -3
  12. package/skills/wix-app/references/editor-react-component/DESIGN-STATES.md +66 -9
  13. package/skills/wix-app/references/editor-react-component/EDITOR-EXTENSION-CONFIGURATION.md +25 -0
  14. package/skills/wix-app/references/editor-react-component/OVERFLOW.md +146 -0
  15. package/skills/wix-app/references/editor-react-component/PARTS.md +6 -0
  16. package/skills/wix-app/scripts/scan-a11y-eslint.cjs +25 -1
  17. package/skills/{wix-headless-fast → wix-headless-kit}/SKILL.md +96 -50
  18. package/skills/{wix-headless-fast → wix-headless-kit}/cold-start/bootstrap.mjs +2 -2
  19. package/skills/{wix-headless-fast → wix-headless-kit}/cold-start/cold-start.md +26 -31
  20. package/skills/wix-headless-kit/guides/capabilities.md +76 -0
  21. package/skills/{wix-headless-fast → wix-headless-kit}/guides/existing-site.md +3 -1
  22. package/skills/wix-headless-kit/guides/feedback.md +98 -0
  23. package/skills/wix-headless-kit/guides/migration.md +54 -0
  24. package/skills/{wix-headless-fast → wix-headless-kit}/guides/reference-mode.md +4 -1
  25. package/skills/{wix-headless-fast → wix-headless-kit}/install/AGENTS.md +6 -1
  26. package/skills/{wix-headless-fast → wix-headless-kit}/install/agents-md.mjs +5 -1
  27. package/skills/{wix-headless-fast → wix-headless-kit}/install/attach.mjs +14 -1
  28. package/skills/wix-headless-kit/install/check.mjs +87 -0
  29. package/skills/wix-headless-kit/install/context.mjs +169 -0
  30. package/skills/{wix-headless-fast → wix-headless-kit}/install/deploy.mjs +101 -23
  31. package/skills/{wix-headless-fast → wix-headless-kit}/install/setup.mjs +115 -41
  32. package/skills/{wix-headless-fast → wix-headless-kit}/install/templates.mjs +1 -1
  33. package/skills/wix-manage/SKILL.md +3 -3
  34. package/skills/wix-manage/references/app-installation/install-wix-apps.md +68 -2
  35. package/skills/wix-manage/references/cms/cms-dashboard-navigation.md +2 -2
  36. package/skills/wix-manage/references/cms/cms-data-items-crud.md +16 -16
  37. package/skills/wix-manage/references/cms/cms-publishing-flow.md +15 -15
  38. package/skills/wix-manage/references/cms/cms-schema-management.md +6 -6
  39. package/skills/wix-manage/references/contacts/bulk-label-and-unlabel-contacts.md +37 -4
  40. package/skills/wix-manage/references/ecommerce/ecom-pricing.md +29 -3
  41. package/skills/wix-manage/references/sites/query-sites.md +1 -8
  42. package/skills/wix-manage/references/sites/site-import.md +101 -37
  43. package/skills/wix-auth/SKILL.md +0 -12
  44. package/skills/wix-auth/references/device-flow.md +0 -140
  45. /package/skills/{wix-headless-fast → wix-headless-kit}/install/lock.mjs +0 -0
@@ -1,33 +1,42 @@
1
1
  // Set up the project in the current folder — one deterministic call from "the folder and the
2
- // brief" to "brand layer can start", for a folder that is NOT yet a Wix project:
2
+ // brief" to "brand layer can start". The folder decides (install/context.mjs folderShape, five file
3
+ // facts: wix.config.json, its site.outputDirectory, the migration variables in .env.local,
4
+ // package.json, index.html):
3
5
  //
4
- // node <SKILL_ROOT>/install/setup.mjs --vertical <storefront|bookings|…> \
6
+ // node <SKILL_ROOT>/install/setup.mjs --vertical <storefront|bookings|…>[,<vertical>…] \
5
7
  // [--plan plan.json] [--business-name "<Brand>"] [--stack astro|react|lib|static] \
6
8
  // [--subfolder [--folder-name <npm-safe-name>]]
7
9
  //
8
- // - `wix.config.json` present → refuses. The folder is already a Wix project; deploy.mjs adds
9
- // this skill's code or a solution to it, then one install, then the seed if there is content.
10
- // - a project but no `wix.config.json` (a package.json, or an index.html at the root) → CONNECT:
11
- // `npm create @wix/new@latest init` in place creates the site and the config, then deploy.
12
- // - otherwise (empty, or loose files such as a CSV or a brief) → CREATE: `wix create` with the
13
- // vertical's composed template (templates/<vertical>/project: the CLI's blank scaffold with the
14
- // vertical deployed and a lockfile), placed in the current directory (`--business-name` required).
10
+ // empty (or loose files: a CSV, a brief) → CREATE: `wix create` with the vertical's composed template
11
+ // (templates/<vertical>/project), placed in the current directory (`--business-name` required).
12
+ // a frontend, no wix.config.json (a package.json, or an index.html at the root) → ADOPT: `init` in
13
+ // place gives the project a new, empty site, then deploy. `--stack` required.
14
+ // CREATE and ADOPT are the two cases that seed: the run made the site, it is empty by construction,
15
+ // and the plan's content goes in (with --plan; without one the agent drafts a plan and seeds it, SKILL.md step 2).
16
+ // a config and no frontend, .env.local declaring a MIGRATION PREVIEW → MIGRATE: the composed template
17
+ // is copied in around the config, the code deploys with the parent's app as its client, the install
18
+ // starts. Nothing seeded: the parent owns its content.
19
+ // a config, index.html at the root, no package.json → PUBLISHED STATIC (a site published through the
20
+ // drop flow and downloaded): the config's site, no init; site/ becomes the upload, the REST layer
21
+ // deploys there, the pages move in (the agent's step). Nothing seeded.
22
+ // a config and a frontend (package.json, or index.html in the output folder) → refuses: iterate.
23
+ // a config and nothing else → refuses: attach.mjs's case.
15
24
  //
16
- // The script reads file markers only (wix.config.json, a package.json or index.html); everything
17
- // else is the agent's call: when connecting, `--stack` is required and comes from SKILL.md step 1,
18
- // and what the project needs for that stack on Wix hosting is prose there, not detection here. The
19
- // seed runs only when `--plan` is given: a brief that has not supplied any content gets no seed.
25
+ // Setup seeds only a site it created in this run. A site that existed before the run is never seeded
26
+ // by setup: the agent reads what the site holds (the vertical's read-site.mjs) and runs the seed module
27
+ // deliberately when the brief supplies or describes content. Seeds are additive and idempotent by name.
20
28
  //
21
29
  // Composes pieces that also remain individually runnable (deploy.mjs, the vertical's seed module)
22
30
  // to recover one failed step. Emits ONE JSON event per line and exits in ~35s with the two long
23
31
  // steps — the dependency install and the seed — running detached in the background (logs and
24
32
  // completion markers in the final event), so the caller can build the brand layer while they finish.
25
33
  import { spawn, spawnSync } from "node:child_process";
26
- import { existsSync, openSync, readFileSync, readdirSync, renameSync, rmSync, writeFileSync } from "node:fs";
34
+ import { cpSync, existsSync, openSync, readFileSync, readdirSync, renameSync, rmSync, writeFileSync } from "node:fs";
27
35
  import { basename, dirname, join, resolve } from "node:path";
28
36
  import { fileURLToPath } from "node:url";
29
37
  import { AGENT_CONFIG_FILES, writeAgentsMd } from "./agents-md.mjs";
30
38
  import { listVerticals, templatesDir } from "./templates.mjs";
39
+ import { folderShape, siteContext } from "./context.mjs";
31
40
 
32
41
  const SKILL_ROOT = resolve(dirname(fileURLToPath(import.meta.url)), "..");
33
42
 
@@ -45,7 +54,12 @@ const flag = (name) => {
45
54
  };
46
55
  const businessName = flag("business-name");
47
56
  const planPath = flag("plan");
48
- const vertical = flag("vertical");
57
+ // Every vertical the brief needs, comma-separated. The first one's composed template scaffolds the
58
+ // project and its seed runs from --plan; the others deploy in the same call so the ONE install covers
59
+ // them (adding a vertical after the install has started costs a second install). Their seeds run
60
+ // afterwards, each with its own plan, when the brief gives them content.
61
+ const verticals = (flag("vertical") ?? "").split(",").map((v) => v.trim()).filter(Boolean);
62
+ const vertical = verticals[0] ?? null;
49
63
  const stackFlag = flag("stack");
50
64
  // Opt-in: keep a CREATE's project in a subfolder instead of the current directory.
51
65
  const subfolder = argv.includes("--subfolder");
@@ -53,11 +67,11 @@ const subfolder = argv.includes("--subfolder");
53
67
  let TEMPLATES;
54
68
  try { TEMPLATES = templatesDir(); } catch (e) { fail("templates", e.message); }
55
69
  const knownVerticals = listVerticals(TEMPLATES);
56
- const usage = `usage: setup.mjs --vertical <${knownVerticals.join("|")}> [--plan plan.json] [--business-name "<Brand>"] [--stack astro|react|lib|static] [--subfolder]`;
70
+ const usage = `usage: setup.mjs --vertical <${knownVerticals.join("|")}>[,<vertical>…] [--plan plan.json] [--business-name "<Brand>"] [--stack astro|react|lib|static] [--subfolder]`;
57
71
  // --vertical is REQUIRED: a defaulted vertical deploys the wrong code and runs the wrong seed.
58
72
  if (!vertical) fail("args", usage);
59
- if (!knownVerticals.includes(vertical)) {
60
- fail("args", `unknown vertical "${vertical}" — shipped verticals: ${knownVerticals.join(", ")}`);
73
+ for (const v of verticals) {
74
+ if (!knownVerticals.includes(v)) fail("args", `unknown vertical "${v}" — shipped verticals: ${knownVerticals.join(", ")}`);
61
75
  }
62
76
  if (stackFlag && !["astro", "react", "lib", "static"].includes(stackFlag)) {
63
77
  fail("args", `unknown --stack "${stackFlag}" — astro, react, lib or static`);
@@ -67,17 +81,28 @@ if (planPath && !existsSync(planPath)) fail("args", `plan file not found: ${plan
67
81
  // ---- 0 · read the folder --------------------------------------------------------------------------
68
82
  const cwd = process.cwd();
69
83
  const has = (p) => existsSync(join(cwd, p));
84
+ const pkg = has("package.json") ? JSON.parse(readFileSync(join(cwd, "package.json"), "utf8")) : null;
85
+ let ctx = null;
86
+ let shape = folderShape(cwd).shape;
70
87
  if (has("wix.config.json")) {
71
- fail("place", "this folder is already a Wix project (wix.config.json): nothing to set up. deploy.mjs <vertical> adds this skill's code or a solution to it; then ONE npm install; then the vertical's seed module if there is content to create");
88
+ ctx = siteContext({ cwd }); // pulls .env.local when missing — where a migration is declared
89
+ shape = ctx.folder.shape;
90
+ if (shape !== "migration" && shape !== "published-static") {
91
+ fail("place", `this folder is already a Wix project (wix.config.json), shape "${shape}": nothing to set up. ${ctx.folder.next} (SKILL.md step 3)` + (ctx.pullError ? ` — note: env pull failed here (${ctx.pullError.slice(0, 120)})` : ""));
92
+ }
93
+ if (shape === "published-static" && stackFlag && stackFlag !== "static") {
94
+ fail("args", `a published static site (index.html beside wix.config.json, no package.json) is the static stack; --stack ${stackFlag} does not apply`);
95
+ }
72
96
  }
73
- const pkg = has("package.json") ? JSON.parse(readFileSync(join(cwd, "package.json"), "utf8")) : null;
74
- const hasProject = !!pkg || has("index.html");
75
- const mode = hasProject ? "connect" : "create";
76
- if (mode === "connect" && !stackFlag) {
77
- fail("args", "connecting a project on disk needs --stack astro|react|lib|static — the stack you resolved in SKILL.md step 1 for this project");
97
+ const mode = { migration: "migrate", "published-static": "published-static", project: "adopt", empty: "create" }[shape];
98
+ const migrating = mode === "migrate";
99
+ const publishedStatic = mode === "published-static";
100
+ const hasProject = shape === "project";
101
+ if (mode === "adopt" && !stackFlag) {
102
+ fail("args", "adopting a project on disk needs --stack astro|react|lib|static — the stack you resolved in SKILL.md step 1 for this project");
78
103
  }
79
- const stack = stackFlag ?? "astro";
80
- emit("folder", { mode, stack, project: hasProject ? (pkg?.name ?? basename(cwd)) : null });
104
+ const stack = publishedStatic ? "static" : (stackFlag ?? "astro");
105
+ emit("folder", { mode, shape, stack, project: hasProject ? (pkg?.name ?? basename(cwd)) : null, ...(ctx ? { deploySiteId: ctx.deploy.siteId, warnings: ctx.warnings } : {}), ...(migrating ? { migration: ctx.migration } : {}) });
81
106
 
82
107
  let projectDir = cwd;
83
108
  let folderName = null;
@@ -119,12 +144,39 @@ if (mode === "create") {
119
144
  fail("scaffold", (scaffold.stderr || scaffold.stdout || "scaffold produced no wix.config.json — is the Wix CLI logged in? (npx @wix/cli@latest whoami)").slice(-600));
120
145
  }
121
146
  }
147
+ } else if (mode === "migrate") {
148
+ // ---- 1 · a migration preview: the config and credentials came with the folder -------------------
149
+ // No site is created and nothing is provisioned: `wix.config.json` already names the deploy site
150
+ // and its app, `.env.local` the parent's. The download usually carries the CLI's blank Astro
151
+ // starter beside the config: then the project is kept and deploy below adds the vertical's code and
152
+ // dependencies into it, as for an adopted project. A bare config (no package.json) gets the
153
+ // vertical's composed template copied in around it on managed Astro; any other stack is code-only.
154
+ if (stack === "astro" && has("package.json")) {
155
+ emit("migration_project_kept", { folder: cwd, project: pkg?.name ?? basename(cwd) });
156
+ } else if (stack === "astro") {
157
+ const template = join(templatesDir({ need: `${vertical}/project` }), vertical, "project");
158
+ emit("scaffolding", { folder: cwd, template, from: "migration preview" });
159
+ cpSync(template, cwd, { recursive: true, force: false, errorOnExist: false });
160
+ const pkgPath = join(cwd, "package.json");
161
+ const scaffolded = JSON.parse(readFileSync(pkgPath, "utf8"));
162
+ scaffolded.name = basename(cwd).toLowerCase().replace(/[^a-z0-9-]+/g, "-").replace(/^-+|-+$/g, "") || "site";
163
+ writeFileSync(pkgPath, JSON.stringify(scaffolded, null, 2) + "\n");
164
+ }
165
+ const gi = join(cwd, ".gitignore");
166
+ const cur = existsSync(gi) ? readFileSync(gi, "utf8") : "";
167
+ if (!/\.env/.test(cur)) writeFileSync(gi, cur + "\n# local env (pulled from Wix)\n.env.local\n.env\n");
168
+ } else if (publishedStatic) {
169
+ // ---- 1 · a published static site: the config came with the folder, the site exists -------------
170
+ // No init: `wix.config.json` already names the site the pages are published on (and its app). The
171
+ // pages stay where they are; the static handling below points the upload at site/ and the `next`
172
+ // says to move them in.
173
+ emit("preparing", { folder: cwd, siteId: ctx.deploy.siteId, from: "published static site" });
122
174
  } else {
123
175
  // ---- 1 · init in place --------------------------------------------------------------------------
124
176
  // The CLI's `init` links the folder to a NEW site: creates the site and its OAuth app, writes
125
177
  // wix.config.json and .env.local, touches nothing else. Non-interactive under CI=1; the site is
126
178
  // named after the folder (rename it in the dashboard).
127
- emit("initializing", { folder: cwd });
179
+ emit("adopting", { folder: cwd });
128
180
  const init = spawnSync("npm", ["create", "@wix/new@latest", "--", "init"],
129
181
  { cwd, env: { ...process.env, CI: "1" }, encoding: "utf8", timeout: 300_000 });
130
182
  if (init.status !== 0 || !has("wix.config.json")) {
@@ -141,14 +193,17 @@ if (stack === "static") {
141
193
  wixConfig.site = { ...(wixConfig.site ?? {}), outputDirectory: `./${STATIC_OUT}` };
142
194
  writeFileSync(join(projectDir, "wix.config.json"), JSON.stringify(wixConfig, null, 2) + "\n");
143
195
  }
144
- emit(mode === "create" ? "scaffolded" : "connected", { folder: folderName ?? cwd, siteId, stack });
196
+ emit({ create: "scaffolded", migrate: "migration_preview", adopt: "adopted", "published-static": "prepared" }[mode], {
197
+ folder: folderName ?? cwd, stack,
198
+ ...(migrating ? { deploySiteId: ctx.deploy.siteId, contentSiteId: ctx.content.siteId } : { siteId }),
199
+ });
145
200
 
146
201
  // ---- 2 · deploy shipped code + deps ---------------------------------------------------------------
147
202
  // A CREATE from the composed template already holds the code and the lock: deploy adds nothing and
148
- // reports the project; a CONNECT gets the code and its dependencies here.
203
+ // reports the project; an ADOPT gets the code and its dependencies here.
149
204
  const deploy = spawnSync(
150
205
  "node",
151
- [join(SKILL_ROOT, "install", "deploy.mjs"), vertical, "--stack", stack, ...(stack === "static" ? ["--out", STATIC_OUT] : []), ...(planPath ? ["--plan", resolve(planPath)] : [])],
206
+ [join(SKILL_ROOT, "install", "deploy.mjs"), ...verticals, "--stack", stack, ...(stack === "static" ? ["--out", STATIC_OUT] : []), ...(planPath ? ["--plan", resolve(planPath)] : [])],
152
207
  { cwd: projectDir, encoding: "utf8", timeout: 60_000 },
153
208
  );
154
209
  if (deploy.status !== 0) fail("deploy", deploy.stderr || deploy.stdout);
@@ -189,7 +244,7 @@ if (mode === "create" && !subfolder && projectDir !== cwd) {
189
244
  // ---- 2d · the agent config files `wix create` would have written --------------------------------
190
245
  // Skipped by the CLI because of --skip-install. Fill-only: a project that has its own AGENTS.md
191
246
  // keeps it (the event says `kept`).
192
- emit("agent_configs", writeAgentsMd(projectDir, { skill: basename(SKILL_ROOT), stack }));
247
+ emit("agent_configs", writeAgentsMd(projectDir, { skill: basename(SKILL_ROOT), stack, ...(migrating ? { migration: { parentSiteId: ctx.migration.parentSiteId, deploySiteId: ctx.deploy.siteId } } : {}) }));
193
248
 
194
249
  // ---- 3 · start the dependency install, detached --------------------------------------------------
195
250
  // ONE install, here, for any project with a package.json (deploy patched it). The static stack has
@@ -209,13 +264,19 @@ if (stack !== "static" && existsSync(join(projectDir, "package.json"))) {
209
264
  emit("install_started", install);
210
265
  }
211
266
 
212
- // ---- 4 · start the seed, detached (only with a plan) ---------------------------------------------
267
+ // ---- 4 · start the seed, detached (a site this run created, with a plan) ---------------------------
213
268
  // The seed includes a Wix-side provisioning wait of unpredictable length (10-80s); running it in
214
269
  // the caller's foreground would idle the agent for exactly that long. Detach it like the install:
215
- // result JSON + exit-code marker land as files the caller syncs on before release. Seeding is
216
- // additive: it never deletes or overwrites what the site holds.
270
+ // result JSON + exit-code marker land as files the caller syncs on before release. Only a site this
271
+ // run created is seeded here; every other site existed before the run and is read first, then the
272
+ // agent runs the seed module itself when the brief supplies content. Seeds are additive and
273
+ // idempotent by name.
274
+ const madeTheSite = mode === "create" || mode === "adopt";
217
275
  let seed = null;
218
- if (planPath) {
276
+ if (planPath && !madeTheSite) {
277
+ emit("seed_skipped", { reason: `${mode}: the site existed before this run; setup seeds only a site it created. Read what the site holds (templates/${vertical}/seed/read-site.mjs), then run templates/${vertical}/seed/seed-*.mjs ${planPath} yourself when the brief supplies or describes content` });
278
+ }
279
+ if (planPath && madeTheSite) {
219
280
  const seedDir = join(TEMPLATES, vertical, "seed");
220
281
  const seedName = existsSync(seedDir)
221
282
  ? readdirSync(seedDir).find((f) => f.startsWith("seed-") && f.endsWith(".mjs"))
@@ -230,7 +291,7 @@ if (planPath) {
230
291
  );
231
292
  seedChild.unref();
232
293
  seed = { resultFile: "seed-result.json", log: "seed.log", doneMarker: ".seed-exit", success: "file contains 0" };
233
- emit("seeding_started", { vertical, ...seed });
294
+ emit("seeding_started", { vertical, ...seed, ...(verticals.length > 1 ? { note: `the plan seeds ${vertical}; the other verticals' seeds run afterwards, each with its own plan` } : {}) });
234
295
  }
235
296
 
236
297
  // ---- done ----------------------------------------------------------------------------------------
@@ -240,20 +301,33 @@ const release = {
240
301
  lib: "the project's own build, then npx @wix/cli@latest release of the build folder named in wix.config.json (SKILL.md step 1)",
241
302
  static: `npx @wix/cli@latest release — no build; it uploads ${STATIC_OUT}/ whole (wix.config.json site.outputDirectory), so the pages, styles and assets move into ${STATIC_OUT}/ first and import the modules from ./js/wix/ there; the root keeps the config, the plan, the seed output and the skills`,
242
303
  }[stack];
304
+ // On a migration preview the links and `siteId` are the PARENT's — the site whose content the pages
305
+ // show and whose dashboard manages it; `deploySiteId` is where `wix release` goes.
306
+ const others = verticals.slice(1);
243
307
  emit("ready_for_brand_layer", {
244
308
  mode,
309
+ shape,
245
310
  stack,
311
+ verticals,
246
312
  projectDir,
247
- siteId,
313
+ siteId: migrating ? ctx.content.siteId : siteId,
314
+ ...(migrating ? { deploySiteId: ctx.deploy.siteId, migration: { parentSiteId: ctx.migration.parentSiteId } } : {}),
248
315
  dashboardUrl: deployResult.dashboardUrl,
249
316
  productsUrl: deployResult.productsUrl,
250
317
  categoriesUrl: deployResult.categoriesUrl,
251
318
  install,
252
319
  seed,
253
320
  next:
254
- (planPath
255
- ? "theme + write the home page; "
256
- : "the site is new and empty — seed it (a plan per step 2, the vertical's seed module) or say so; theme + write the home page; ") +
321
+ (publishedStatic ? "a published static site: its pages are live on this site already and keep their URL; move index.html, the other pages, styles and assets into site/ (the root keeps the config, the plan, the seed output and the skills) and wire the solution into the page that needs it; " : "") +
322
+ (mode === "migrate"
323
+ ? "a migration preview: the site being migrated owns its content (read it with the vertical's read-site.mjs when the brief allows probing; never seed it); theme + write the home page; "
324
+ : madeTheSite
325
+ ? (planPath ? "theme + write the home page; " : "the site is new and empty and no plan was given, so nothing was seeded yet: seed it now (a plan per step 2 — the brief's content, or one drafted per the vertical's SEED.md — then the vertical's seed module), and name the placeholder content in the closing message; theme + write the home page; ")
326
+ : `nothing was seeded (setup seeds only a site it created): read what the site holds with templates/${vertical}/seed/read-site.mjs, then run templates/${vertical}/seed/seed-*.mjs <plan> when the brief supplies or describes content; theme + write the home page; `) +
327
+ (others.length && mode !== "migrate"
328
+ ? `${others.join(", ")} deployed too, no further install needed: run each one's seed module (templates/<vertical>/seed/) with its own plan when the brief gives it content (the members seed installs the Members Area app and needs no plan); `
329
+ : "") +
257
330
  (install || seed ? "then wait for the done markers" + (seed ? ", verify .seed-exit is 0 (else read seed.log and re-run the seed module)" : "") + "; " : "") +
258
- `then ${release}`,
331
+ `then ${release}` +
332
+ (mode === "migrate" ? "; the release is the PREVIEW on the deploy site — close with its URL and the parent's dashboard, say the original site is unchanged and that completing the migration is the user's next step in the Wix CLI once they approve" : ""),
259
333
  });
@@ -142,7 +142,7 @@ function fetchTemplates(cache) {
142
142
 
143
143
  // A sparse, shallow clone of templates/ at a ref (branch, tag, or commit id) into a temp dir.
144
144
  function cloneSparse(repo, ref) {
145
- const tmp = mkdtempSync(join(tmpdir(), "wix-headless-fast-templates-"));
145
+ const tmp = mkdtempSync(join(tmpdir(), "wix-headless-kit-templates-"));
146
146
  let r;
147
147
  if (ref && /^[0-9a-f]{40}$/i.test(ref)) {
148
148
  // a commit: shallow-fetch just it (GitHub serves any reachable commit by id)
@@ -163,7 +163,7 @@ Create and modify CMS collection structures. Covers listing collections, creatin
163
163
  Deletes multiple contacts using filter-based bulk delete. Covers safe deletion patterns, GDPR compliance, soft delete alternatives, and batch processing strategies.
164
164
 
165
165
  ### [Bulk Label and Unlabel Contacts](references/contacts/bulk-label-and-unlabel-contacts.md)
166
- Adds/removes labels from multiple contacts using Contacts API bulk operations. Covers label creation, contact filtering, batch processing, and rate limit handling.
166
+ Creates contact label definitions or adds/removes labels from matching contacts. Use Find or Create Label for label creation alone; use bulk labeling only when the user requests contact assignments.
167
167
 
168
168
  ### [Create a Contact](references/contacts/create-a-contact.md)
169
169
  Creates a contact with the Contacts API. Covers the minimum identifying fields, the single-object shape of `email` and `phone`, and adding a physical address with the ISO 3166-2 subdivision format required for state, region, and province codes.
@@ -211,7 +211,7 @@ Buy a domain through Wix or connect one the user already owns — intent, availa
211
211
  **Entry point for all eCommerce recommendation requests.** Unified skill that analyzes site data across ALL domains (discounts + shipping + gift cards), generates up to 5 cross-domain recommendations, and persists them to the tracking database. Covers discount strategies (seasonal, upsell, stock mover, bundling), shipping optimization (coverage gaps, free shipping, rate strategy, carrier backup), AND selling gift cards (denominations sized from the site's own AOV and catalog prices). Use this for business improvement requests about earning more from existing visitors. **Traffic acquisition (SEO, ads, social, content) is out of scope** — route "grow my traffic" to marketing.
212
212
 
213
213
  ### [Pricing & Promotions](references/ecommerce/ecom-pricing.md)
214
- **Dispatcher** — routes coupon/discount/sale/ribbon/bundle requests to the right leaf recipe (create coupon, create discount rule, troubleshoot discount-not-applying), and routes strategic "run a sale / boost sales" requests to `recommend-ecommerce-strategy`.
214
+ Routes discounts, coupons, sales and bundles to promotion recipes, and visual product ribbons to the Catalog Ribbons API. Load this dispatcher for mixed pricing/refund/payment/product-price/shipping requests to choose the appropriate APIs.
215
215
 
216
216
  ### [Shipping](references/ecommerce/ecom-shipping.md)
217
217
  **Dispatcher** — routes shipping-setup requests (rates, regions, pickup, free shipping, fix coverage, optimize rates) to the right leaf recipe. The Shipping Options + Delivery Profiles APIs have no public docs page; `ecom-shipping-api.md` is the authoritative inline reference.
@@ -422,7 +422,7 @@ List, count, and find the sites in a Wix account. Covers the namespace filter fo
422
422
  Probe a Wix site or account for full context in one call — installed apps by display name, locale, currency, timezone, and status. Account token + siteId targets one site; account token alone returns up to 10; site-scoped token alone returns the site it is scoped to.
423
423
 
424
424
  ### [Site Import](references/sites/site-import.md)
425
- Drive the Wix Site Import agent to migrate an existing store or site from another platform (Shopify, WooCommerce, Magento, or any URL) into Wix, or to import from CSV/TSV export files with no source site. Use this skill whenever the user wants to import, migrate, or clone a store/site into Wix, mentions moving off Shopify/WooCommerce/Magento, or gives a source store URL and asks to bring it into Wix. Covers starting the import, polling progress, answering the agent's mid-import questions, handling deploy/failure/auth-expiry states, and sending post-deploy follow-up changes.
425
+ Drive the Wix Site Import agent to migrate an existing store or site from another platform (Shopify, WooCommerce, Magento, or any URL) into Wix — as a brand-new site or into the user's existing one — or to import from CSV/TSV export files with no source site. Use this skill whenever the user wants to import, migrate, or clone a store/site into Wix, mentions moving off Shopify/WooCommerce/Magento, or gives a source store URL and asks to bring it into Wix. Covers starting the import, polling progress, answering the agent's mid-import questions, handling deploy/failure/auth-expiry states, and sending post-deploy follow-up changes.
426
426
 
427
427
  ### [Sites Dashboard Navigation](references/sites/sites-dashboard-navigation.md)
428
428
  "Builds direct links to the account-level sites pages on manage.wix.com — the My Sites list (all sites in the account) and each site's own dashboard. Pairs the site list with the Query Sites read API. Use when the user asks where something is in the Wix dashboard, wants a direct link to a dashboard page, or you need a dashboard URL to include with the result of an API operation."
@@ -107,15 +107,81 @@ Some common apps:
107
107
  - NEVER guess the `appDefId`. For Wix-built apps, use the table above. For any other app, resolve the ID using Step 0 (Search Market Listings).
108
108
  - The `tenantType` MUST be `SITE`
109
109
  - The `id` in tenant is the site's metaSiteId
110
+ - The endpoint, request body, and appDefId table above are complete and canonical for a listed Wix-built app — don't re-verify them with a separate REST/API doc search first; that's a redundant round-trip.
111
+ - Don't spend a call checking whether the app is already installed before installing it. If the task or the error you're handling already tells you it isn't installed (e.g. a fresh site, or a `*_NOT_INSTALLED` error), just call install directly.
110
112
 
111
113
  ---
112
114
 
113
115
  ## Error Handling
114
116
 
115
117
  ### App Not Installed Error
116
- If you receive an error indicating a required app is not installed, use this recipe to install it before proceeding.
118
+ If you receive an error indicating a required app is not installed (e.g. a `428` or a `*_NOT_INSTALLED` error code), install the app it names using its appDefId, then retry the call that failed. If the user's own request already implies this app is needed — i.e. doing what they asked requires a feature only that app provides — just install it as part of doing that task; don't stop to ask permission or name the app first. Confirm first only when the app isn't implied by anything the user asked for.
119
+
120
+ **Example** (install the missing app, then retry the call that surfaced the error — all in one script):
121
+ ```javascript
122
+ async function() {
123
+ const siteId = "<SITE_ID>";
124
+
125
+ await wix.request({
126
+ method: "POST",
127
+ url: "https://www.wixapis.com/apps-installer-service/v1/app-instance/install",
128
+ body: {
129
+ tenant: { tenantType: "SITE", id: siteId },
130
+ appInstance: { appDefId: "<APP_DEF_ID>" }
131
+ }
132
+ });
133
+
134
+ return await wix.request({
135
+ method: "<METHOD>",
136
+ url: "<ORIGINAL_URL_THAT_FAILED>",
137
+ body: { /* original request body */ }
138
+ });
139
+ }
140
+ ```
141
+
142
+ ### App-Dependent Call Fails Right After Install (Propagation Delay)
143
+ Installing an app and then immediately calling one of its own APIs — e.g. calling Set Multilingual Mode right after installing Wix Multilingual — can race the platform's install propagation, surfacing as a not-found error on the dependent call even though the install itself already succeeded.
144
+
145
+ **Example** (retry with backoff past the propagation delay instead of surfacing the error, all in one script):
146
+ ```javascript
147
+ async function() {
148
+ const siteId = "<SITE_ID>";
149
+
150
+ async function requestWithRetry(requestOptions, delaysMs = [1000, 2000, 4000]) {
151
+ let lastError;
152
+ try {
153
+ return await wix.request(requestOptions);
154
+ } catch (err) {
155
+ lastError = err;
156
+ }
157
+ for (const delayMs of delaysMs) {
158
+ await new Promise(resolve => setTimeout(resolve, delayMs));
159
+ try {
160
+ return await wix.request(requestOptions);
161
+ } catch (err) {
162
+ lastError = err;
163
+ }
164
+ }
165
+ throw lastError;
166
+ }
117
167
 
118
- If Locale Settings or Locales APIs return `428 MULTILINGUAL_NOT_INSTALLED`, install **Wix Multilingual** using appDefId `14d84998-ae09-1abf-c6fc-3f3cace5bf19`, then retry enabling multilingual mode or creating locales. Confirm with the user before installing unless they already explicitly asked you to install Wix Multilingual.
168
+ await wix.request({
169
+ method: "POST",
170
+ url: "https://www.wixapis.com/apps-installer-service/v1/app-instance/install",
171
+ body: {
172
+ tenant: { tenantType: "SITE", id: siteId },
173
+ appInstance: { appDefId: "14d84998-ae09-1abf-c6fc-3f3cace5bf19" }
174
+ }
175
+ });
176
+
177
+ return await requestWithRetry({
178
+ method: "POST",
179
+ url: "https://www.wixapis.com/locale-settings/v2/settings/mode",
180
+ body: { multilingualModeEnabled: true }
181
+ });
182
+ }
183
+ ```
184
+ Chain any further calls inside this same function through the same `requestWithRetry` helper, after the first one succeeds.
119
185
 
120
186
  ---
121
187
 
@@ -28,8 +28,8 @@ Fetch the entity via REST, then link the matching dashboard page. All calls use
28
28
 
29
29
  | Entity | Read API | Dashboard link |
30
30
  |---|---|---|
31
- | Collection (schema) | `GET /wix-data/v2/collections/{collectionId}` · `GET /wix-data/v2/collections` (list) | `wix-cms/data/{collectionId}` |
32
- | Data item | `POST /wix-data/v2/items/query` (body includes `dataCollectionId`) · `GET /wix-data/v2/items/{itemId}?dataCollectionId=...` | `wix-cms/data/{collectionId}` (the collection's items table) |
31
+ | Collection (schema) | `GET https://www.wixapis.com/wix-data/v2/collections/{collectionId}` · `GET https://www.wixapis.com/wix-data/v2/collections` (list) | `wix-cms/data/{collectionId}` |
32
+ | Data item | `POST https://www.wixapis.com/wix-data/v2/items/query` (body includes `dataCollectionId`) · `GET https://www.wixapis.com/wix-data/v2/items/{itemId}?dataCollectionId=...` | `wix-cms/data/{collectionId}` (the collection's items table) |
33
33
 
34
34
  Example — after creating a collection and inserting items:
35
35
 
@@ -25,8 +25,8 @@ This recipe covers basic Create, Read, Update, Delete (CRUD) operations for Wix
25
25
  Before inserting or updating items, you need to know the collection's field names and types. If you don't already know the schema:
26
26
 
27
27
  1. **Query existing items** - Fetch a few items to infer field names from the data
28
- 2. **Get collection schema** - Use `GET /collections/{dataCollectionId}` for full field definitions, **including `plugins`** — don't omit the `plugins` field when fetching or listing schemas
29
- 3. **List collections** - Use `GET /collections?fields=displayName,plugins` to see what collections exist (see [Schema Management](cms-schema-management.md))
28
+ 2. **Get collection schema** - Use `GET https://www.wixapis.com/wix-data/v2/collections/{dataCollectionId}` for full field definitions, **including `plugins`** — don't omit the `plugins` field when fetching or listing schemas
29
+ 3. **List collections** - Use `GET https://www.wixapis.com/wix-data/v2/collections?fields=displayName,plugins` to see what collections exist (see [Schema Management](cms-schema-management.md))
30
30
 
31
31
  It may be, that user refers to schema by its `displayName` rather than `id`, if collection is not found list all collections to find the right `id` (`dataCollectionId`) to use.
32
32
 
@@ -36,7 +36,7 @@ It may be, that user refers to schema by its `displayName` rather than `id`, if
36
36
 
37
37
  ## Insert Data Item
38
38
 
39
- **Endpoint**: `POST /wix-data/v2/items`
39
+ **Endpoint**: `POST https://www.wixapis.com/wix-data/v2/items`
40
40
 
41
41
  **Request Body**:
42
42
  ```json
@@ -73,7 +73,7 @@ It may be, that user refers to schema by its `displayName` rather than `id`, if
73
73
 
74
74
  ## Bulk Insert Items
75
75
 
76
- **Endpoint**: `POST /wix-data/v2/bulk/items/insert`
76
+ **Endpoint**: `POST https://www.wixapis.com/wix-data/v2/bulk/items/insert`
77
77
 
78
78
  **Request Body**:
79
79
  ```json
@@ -108,7 +108,7 @@ It may be, that user refers to schema by its `displayName` rather than `id`, if
108
108
 
109
109
  ## Query Data Items
110
110
 
111
- **Endpoint**: `POST /wix-data/v2/items/query`
111
+ **Endpoint**: `POST https://www.wixapis.com/wix-data/v2/items/query`
112
112
 
113
113
  **Basic Query**:
114
114
  ```json
@@ -163,7 +163,7 @@ It may be, that user refers to schema by its `displayName` rather than `id`, if
163
163
 
164
164
  ## Get Single Item
165
165
 
166
- **Endpoint**: `GET /wix-data/v2/items/{itemId}?dataCollectionId={collectionId}`
166
+ **Endpoint**: `GET https://www.wixapis.com/wix-data/v2/items/{itemId}?dataCollectionId={collectionId}`
167
167
 
168
168
  ```bash
169
169
  curl -X GET \
@@ -173,7 +173,7 @@ curl -X GET \
173
173
 
174
174
  ## Update Data Item
175
175
 
176
- **Endpoint**: `PUT /wix-data/v2/items/{itemId}`
176
+ **Endpoint**: `PUT https://www.wixapis.com/wix-data/v2/items/{itemId}`
177
177
 
178
178
  **Request Body**:
179
179
  ```json
@@ -192,7 +192,7 @@ curl -X GET \
192
192
 
193
193
  ## Patch Data Item (Partial Update - Single Item)
194
194
 
195
- **Endpoint**: `PATCH /wix-data/v2/items/{dataItemId}`
195
+ **Endpoint**: `PATCH https://www.wixapis.com/wix-data/v2/items/{dataItemId}`
196
196
 
197
197
  Unlike Update, this only modifies the specified fields — all other fields remain unchanged.
198
198
 
@@ -229,7 +229,7 @@ Unlike Update, this only modifies the specified fields — all other fields rema
229
229
 
230
230
  ## Bulk Update Items
231
231
 
232
- **Endpoint**: `POST /wix-data/v2/bulk/items/update`
232
+ **Endpoint**: `POST https://www.wixapis.com/wix-data/v2/bulk/items/update`
233
233
 
234
234
  > **Important**: Use `id` (not `_id`) at the element level. The `data` object should NOT contain `_id`.
235
235
 
@@ -259,7 +259,7 @@ Unlike Update, this only modifies the specified fields — all other fields rema
259
259
 
260
260
  ## Bulk Patch Items (Partial Update)
261
261
 
262
- **Endpoint**: `POST /wix-data/v2/bulk/items/patch`
262
+ **Endpoint**: `POST https://www.wixapis.com/wix-data/v2/bulk/items/patch`
263
263
 
264
264
  Unlike bulk update, this only modifies the specified fields - other fields remain unchanged. **Use this for partial updates.**
265
265
 
@@ -330,15 +330,15 @@ Unlike bulk update, this only modifies the specified fields - other fields remai
330
330
  >
331
331
  > **For MULTI_REFERENCE operations (add speakers, assign tags, link categories, etc.):**
332
332
  > **READ [CMS References & Relationships](cms-references-and-relationships.md)** for the exact endpoints and request bodies:
333
- > - `POST /wix-data/v2/bulk/items/insert-references` - add references
334
- > - `POST /wix-data/v2/items/replace-references` - replace all references
335
- > - `POST /wix-data/v2/bulk/items/remove-references` - remove references
333
+ > - `POST https://www.wixapis.com/wix-data/v2/bulk/items/insert-references` - add references
334
+ > - `POST https://www.wixapis.com/wix-data/v2/items/replace-references` - replace all references
335
+ > - `POST https://www.wixapis.com/wix-data/v2/bulk/items/remove-references` - remove references
336
336
  >
337
337
  > Error `WDE0303` occurs when attempting to set multi-reference fields via data operations.
338
338
 
339
339
  ## Delete Data Item
340
340
 
341
- **Endpoint**: `DELETE /wix-data/v2/items/{itemId}?dataCollectionId={collectionId}`
341
+ **Endpoint**: `DELETE https://www.wixapis.com/wix-data/v2/items/{itemId}?dataCollectionId={collectionId}`
342
342
 
343
343
  ```bash
344
344
  curl -X DELETE \
@@ -348,7 +348,7 @@ curl -X DELETE \
348
348
 
349
349
  ## Bulk Delete Items
350
350
 
351
- **Endpoint**: `POST /wix-data/v2/bulk/items/remove`
351
+ **Endpoint**: `POST https://www.wixapis.com/wix-data/v2/bulk/items/remove`
352
352
 
353
353
  ```json
354
354
  {
@@ -452,7 +452,7 @@ POST https://www.wixapis.com/apps-installer-service/v1/app-instance/install
452
452
  }
453
453
  ```
454
454
 
455
- After the installation succeeds, retry the original `POST /wix-data/v2/items` request. If the
455
+ After the installation succeeds, retry the original `POST https://www.wixapis.com/wix-data/v2/items` request. If the
456
456
  user only asks what the error means or how to fix it, explain this installation step and ask for
457
457
  confirmation before performing the install.
458
458
 
@@ -68,7 +68,7 @@ Reads target a specific surface — there is no merged view:
68
68
  - **Published items**: query the published collection (`articles`).
69
69
  - **Drafts**: query the drafts collection resolved from `draftItemsPluginOptions.draftsCollectionId` (e.g. `articles__drafts`).
70
70
 
71
- **Endpoint**: `POST /wix-data/v2/items/query`
71
+ **Endpoint**: `POST https://www.wixapis.com/wix-data/v2/items/query`
72
72
 
73
73
  ```json
74
74
  {
@@ -92,7 +92,7 @@ Reads target a specific surface — there is no merged view:
92
92
 
93
93
  Insert into the **drafts** collection. The item starts as **DRAFT**.
94
94
 
95
- **Endpoint**: `POST /wix-data/v2/items`
95
+ **Endpoint**: `POST https://www.wixapis.com/wix-data/v2/items`
96
96
 
97
97
  ```json
98
98
  {
@@ -117,7 +117,7 @@ Editing a live item does **not** overwrite the live copy — it stages a **pendi
117
117
 
118
118
  Replaces the published item's data with the draft's content; the draft is then deleted. Pass the **published** collection id.
119
119
 
120
- **Endpoint**: `POST /wix-data/v2/items/publish-draft`
120
+ **Endpoint**: `POST https://www.wixapis.com/wix-data/v2/items/publish-draft`
121
121
 
122
122
  ```bash
123
123
  curl -X POST \
@@ -147,7 +147,7 @@ curl -X POST \
147
147
 
148
148
  Retracts a published item back to draft state. Pass the **published** collection id.
149
149
 
150
- **Endpoint**: `POST /wix-data/v2/items/unpublish`
150
+ **Endpoint**: `POST https://www.wixapis.com/wix-data/v2/items/unpublish`
151
151
 
152
152
  ```bash
153
153
  curl -X POST \
@@ -198,7 +198,7 @@ curl -X DELETE 'https://www.wixapis.com/wix-data/v2/items/<id>?dataCollectionId=
198
198
 
199
199
  **Enable** — add the Draft Items plugin (requires collection-management permission). Use the dedicated endpoint; the Draft Items plugin cannot be added through the generic add-plugin call.
200
200
 
201
- **Endpoint**: `POST /wix-data/v2/collections/add-draft-items-plugin`
201
+ **Endpoint**: `POST https://www.wixapis.com/wix-data/v2/collections/add-draft-items-plugin`
202
202
 
203
203
  ```bash
204
204
  curl -X POST 'https://www.wixapis.com/wix-data/v2/collections/add-draft-items-plugin' \
@@ -219,7 +219,7 @@ curl -X POST 'https://www.wixapis.com/wix-data/v2/collections/add-draft-items-pl
219
219
 
220
220
  **Disable** — remove the plugin:
221
221
 
222
- **Endpoint**: `POST /wix-data/v2/collections/delete-draft-items-plugin`
222
+ **Endpoint**: `POST https://www.wixapis.com/wix-data/v2/collections/delete-draft-items-plugin`
223
223
 
224
224
  ```bash
225
225
  curl -X POST 'https://www.wixapis.com/wix-data/v2/collections/delete-draft-items-plugin' \
@@ -252,17 +252,17 @@ At the REST level, every read/author/publish/unpublish call here goes through th
252
252
  | Collection state | Desired action | API call | Permission needed |
253
253
  |------------------|----------------|----------|-------------------|
254
254
  | Draft Items plugin absent | Any write | Normal insert/update — writes go live immediately | Write Data Items |
255
- | Draft Items enabled | Detect workflow | `GET /collections/{id}` → inspect plugins for the Draft Items plugin; read `draftItemsPluginOptions.draftsCollectionId` | (read) |
256
- | Draft Items enabled | Read published items | `POST /items/query` on the published id | read |
257
- | Draft Items enabled | Read drafts | `POST /items/query` on the drafts collection id | read |
255
+ | Draft Items enabled | Detect workflow | `GET https://www.wixapis.com/wix-data/v2/collections/{id}` → inspect plugins for the Draft Items plugin; read `draftItemsPluginOptions.draftsCollectionId` | (read) |
256
+ | Draft Items enabled | Read published items | `POST https://www.wixapis.com/wix-data/v2/items/query` on the published id | read |
257
+ | Draft Items enabled | Read drafts | `POST https://www.wixapis.com/wix-data/v2/items/query` on the drafts collection id | read |
258
258
  | PUBLISHED | Edit into a pending draft (→ CHANGED) | Create the draft (`createDataItemDraft`), then edit it on the drafts collection | Write Data Items |
259
- | — | Create new draft (→ DRAFT) | `POST /items` on the drafts collection | Write Data Items |
260
- | DRAFT / CHANGED | Publish (→ PUBLISHED) | `POST /items/publish-draft` (published id) | Write Data Items |
261
- | PUBLISHED / CHANGED | Unpublish, keep as draft (→ DRAFT) | `POST /items/unpublish` `copyToDraft:true` | Write Data Items |
262
- | PUBLISHED / CHANGED | Unpublish, discard | `POST /items/unpublish` `copyToDraft:false` | Write Data Items |
263
- | CHANGED | Revert to live version (discard edit) | `DELETE /items/{id}?dataCollectionId=<drafts id>` | Write Data Items |
259
+ | — | Create new draft (→ DRAFT) | `POST https://www.wixapis.com/wix-data/v2/items` on the drafts collection | Write Data Items |
260
+ | DRAFT / CHANGED | Publish (→ PUBLISHED) | `POST https://www.wixapis.com/wix-data/v2/items/publish-draft` (published id) | Write Data Items |
261
+ | PUBLISHED / CHANGED | Unpublish, keep as draft (→ DRAFT) | `POST https://www.wixapis.com/wix-data/v2/items/unpublish` `copyToDraft:true` | Write Data Items |
262
+ | PUBLISHED / CHANGED | Unpublish, discard | `POST https://www.wixapis.com/wix-data/v2/items/unpublish` `copyToDraft:false` | Write Data Items |
263
+ | CHANGED | Revert to live version (discard edit) | `DELETE https://www.wixapis.com/wix-data/v2/items/{id}?dataCollectionId=<drafts id>` | Write Data Items |
264
264
  | any | Delete entirely (both versions) | Delete on the published id (+ drafts id if a draft exists) | Write Data Items |
265
- | plain, no plugin | Enable workflow | `POST /collections/add-draft-items-plugin` | Manage Data Collections |
265
+ | plain, no plugin | Enable workflow | `POST https://www.wixapis.com/wix-data/v2/collections/add-draft-items-plugin` | Manage Data Collections |
266
266
 
267
267
  ---
268
268