@wix/agent-skills 1.16.0 → 1.16.2

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 (94) hide show
  1. package/package.json +1 -1
  2. package/skills/wix-app/SKILL.md +72 -8
  3. package/skills/wix-app/references/CODE_QUALITY.md +0 -1
  4. package/skills/wix-app/references/DASHBOARD_MODAL.md +21 -14
  5. package/skills/wix-app/references/DASHBOARD_PAGE.md +30 -184
  6. package/skills/wix-app/references/EDITOR_REACT_COMPONENT.md +19 -3
  7. package/skills/wix-app/references/WIX_PATTERNS_DOCS.md +172 -0
  8. package/skills/wix-app/references/dashboard-page/WDS_LAYOUT.md +187 -0
  9. package/skills/wix-app/references/editor-react-component/A11Y-REVIEW.md +12 -7
  10. package/skills/wix-app/references/editor-react-component/ANIMATED-COMPONENTS.md +31 -2
  11. package/skills/wix-app/references/editor-react-component/COMPONENT-API.md +6 -1
  12. package/skills/wix-app/references/editor-react-component/COMPONENT-CONFIGURATION.md +60 -0
  13. package/skills/wix-app/references/editor-react-component/DIRECTIONALITY.md +6 -6
  14. package/skills/wix-app/references/editor-react-component/FUNCTION-HANDLERS.md +167 -0
  15. package/skills/wix-app/references/editor-react-component/REACT-GUIDELINES.md +2 -2
  16. package/skills/wix-app/references/editor-react-component/SITE-CONTEXT-HOOKS.md +187 -0
  17. package/skills/wix-app/scripts/scan-a11y-code.cjs +777 -0
  18. package/skills/wix-app/scripts/scan-a11y-eslint.cjs +201 -0
  19. package/skills/wix-base44-connector/SKILL.md +185 -0
  20. package/skills/wix-base44-connector/scripts/utils.js +212 -0
  21. package/skills/wix-design-system/SKILL.md +19 -15
  22. package/skills/wix-docs/SKILL.md +75 -1
  23. package/skills/wix-headless/references/CAPABILITIES.md +16 -3
  24. package/skills/wix-headless/references/SDK_HANDOFF.md +1 -1
  25. package/skills/wix-headless/references/SEED.md +1 -1
  26. package/skills/wix-headless/references/inline-recipes/how-to-code-forms.md +560 -102
  27. package/skills/wix-headless/references/inline-recipes/setup-forms.md +210 -143
  28. package/skills/wix-manage/SKILL.md +20 -17
  29. package/skills/wix-manage/references/accessibility/scan-site-accessibility.md +98 -0
  30. package/skills/wix-manage/references/analytics/analytics-dashboard-navigation.md +1 -2
  31. package/skills/wix-manage/references/domains/domain-search-purchase-and-connect.md +2603 -0
  32. package/skills/wix-manage/references/events/create-wix-event.md +112 -90
  33. package/skills/wix-manage/references/events/manage-wix-events.md +33 -94
  34. package/skills/wix-manage/references/sites/create-headless-site.md +1 -0
  35. package/skills/wix-manage/references/sites/manage-oauth-apps.md +154 -0
  36. package/skills/wix-manage/references/sites/read-site-context.md +125 -0
  37. package/skills/wix-manage/references/sites/site-import.md +67 -15
  38. package/skills/wix-manage/references/stores/create-product-catalog-v3.md +273 -0
  39. package/skills/wix-replatform/resources/rp-target-wix/lib/wix-writers.js +1 -1
  40. package/skills/wix-vibe-headless/SKILL.md +2 -1
  41. package/skills/wix-vibe-headless/install/deploy.cjs +63 -3
  42. package/skills/wix-vibe-headless/platforms/base44-ecom-light-seed.md +104 -0
  43. package/skills/wix-vibe-headless/platforms/base44-ecom-light.md +74 -0
  44. package/skills/wix-vibe-headless/platforms/base44.md +15 -40
  45. package/skills/wix-vibe-headless/references/blog/INSTRUCTIONS.md +7 -11
  46. package/skills/wix-vibe-headless/references/blog/seed/SEED.md +1 -1
  47. package/skills/wix-vibe-headless/references/bookings/INSTRUCTIONS.md +7 -11
  48. package/skills/wix-vibe-headless/references/bookings/seed/SEED.md +1 -1
  49. package/skills/wix-vibe-headless/references/cms/INSTRUCTIONS.md +1 -2
  50. package/skills/wix-vibe-headless/references/events/INSTRUCTIONS.md +7 -12
  51. package/skills/wix-vibe-headless/references/events/seed/SEED.md +1 -1
  52. package/skills/wix-vibe-headless/references/members/INSTRUCTIONS.md +7 -11
  53. package/skills/wix-vibe-headless/references/portfolio/INSTRUCTIONS.md +7 -11
  54. package/skills/wix-vibe-headless/references/portfolio/seed/SEED.md +1 -1
  55. package/skills/wix-vibe-headless/references/pricing-plans/INSTRUCTIONS.md +7 -11
  56. package/skills/wix-vibe-headless/references/pricing-plans/seed/SEED.md +1 -1
  57. package/skills/wix-vibe-headless/references/restaurants/INSTRUCTIONS.md +7 -11
  58. package/skills/wix-vibe-headless/references/restaurants/seed/SEED.md +1 -1
  59. package/skills/wix-vibe-headless/references/shared/app/components/WixManageBanner.jsx +1 -1
  60. package/skills/wix-vibe-headless/references/shared/app/rest/wix-config.js +5 -3
  61. package/skills/wix-vibe-headless/references/storefront/INSTRUCTIONS.md +75 -13
  62. package/skills/wix-vibe-headless/references/storefront/app/components/ProductCard.jsx +29 -86
  63. package/skills/wix-vibe-headless/references/storefront/app/components/ProductGrid.jsx +3 -8
  64. package/skills/wix-vibe-headless/references/storefront/app/components/VariantPicker.jsx +78 -105
  65. package/skills/wix-vibe-headless/references/storefront/app/hooks/useProductCard.js +92 -0
  66. package/skills/wix-vibe-headless/references/storefront/app/hooks/useVariantOptions.js +76 -0
  67. package/skills/wix-vibe-headless/references/storefront/seed/SEED.md +1 -1
  68. package/skills/wix-vibe-headless/references/storefront/seed/seed-store.js +44 -5
  69. package/skills/wix-app/references/AUTO_PATTERNS_DASHBOARD.md +0 -326
  70. package/skills/wix-app/references/auto-patterns-dashboard/action-cell.md +0 -115
  71. package/skills/wix-app/references/auto-patterns-dashboard/app-config-structure.md +0 -264
  72. package/skills/wix-app/references/auto-patterns-dashboard/app-context.md +0 -37
  73. package/skills/wix-app/references/auto-patterns-dashboard/bulk-actions.md +0 -86
  74. package/skills/wix-app/references/auto-patterns-dashboard/collection-page-actions.md +0 -119
  75. package/skills/wix-app/references/auto-patterns-dashboard/collection-page.md +0 -103
  76. package/skills/wix-app/references/auto-patterns-dashboard/custom-actions-override.md +0 -76
  77. package/skills/wix-app/references/auto-patterns-dashboard/custom-columns-override.md +0 -82
  78. package/skills/wix-app/references/auto-patterns-dashboard/custom-components-override.md +0 -89
  79. package/skills/wix-app/references/auto-patterns-dashboard/custom-header-override.md +0 -124
  80. package/skills/wix-app/references/auto-patterns-dashboard/custom-sections-override.md +0 -91
  81. package/skills/wix-app/references/auto-patterns-dashboard/custom-slots-override.md +0 -71
  82. package/skills/wix-app/references/auto-patterns-dashboard/entity-page-actions.md +0 -70
  83. package/skills/wix-app/references/auto-patterns-dashboard/entity-page-view-actions.md +0 -73
  84. package/skills/wix-app/references/auto-patterns-dashboard/entity-page.md +0 -98
  85. package/skills/wix-app/references/auto-patterns-dashboard/example-patterns.json +0 -278
  86. package/skills/wix-app/references/auto-patterns-dashboard/pages-configuration.md +0 -94
  87. package/skills/wix-app/references/auto-patterns-dashboard/resolved-action.md +0 -43
  88. package/skills/wix-app/references/auto-patterns-dashboard/sdk-utilities.md +0 -66
  89. package/skills/wix-app/references/auto-patterns-dashboard/views.md +0 -76
  90. package/skills/wix-app/scripts/generate-auto-patterns.js +0 -510
  91. package/skills/wix-manage/references/domains/domain-search-and-purchase.md +0 -437
  92. package/skills/wix-manage/references/stores/create-product-from-image.md +0 -1031
  93. package/skills/wix-manage/references/stores/create-product-with-options-catalog-v3.md +0 -623
  94. package/skills/wix-manage/references/stores/setup-online-store-catalog-v3.md +0 -106
@@ -0,0 +1,125 @@
1
+ ---
2
+ name: "Read Account or Site Context"
3
+ description: 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.
4
+ ---
5
+ # Read Account or Site Context
6
+
7
+ Returns a site's name, URL, status, locale/region, and all installed apps with human-readable display names.
8
+
9
+ ---
10
+
11
+ ## Markdown endpoint (recommended)
12
+
13
+ **Endpoint**: `POST https://www.wixapis.com/_api/dynamic-context/v1/dynamic-context/markdown`
14
+
15
+ Returns `{ "markdown": "..." }`.
16
+
17
+ ### Account token + siteId — one specific site
18
+
19
+ ```bash
20
+ curl -X POST \
21
+ 'https://www.wixapis.com/_api/dynamic-context/v1/dynamic-context/markdown' \
22
+ -H 'Authorization: <AUTH>' \
23
+ -H 'Content-Type: application/json' \
24
+ -d '{"siteId": "<metaSiteId>"}'
25
+ ```
26
+
27
+ Response:
28
+
29
+ ```
30
+ ## 1. Acme Store
31
+
32
+ **ID**: `<metaSiteId>`
33
+ **URL**: [https://example.wixsite.com/acme](https://example.wixsite.com/acme)
34
+ **Status**: Published
35
+ **Editor Type**: Editorless
36
+ **Created**: Aug 14, 2026, 05:21 · **Updated**: Aug 17, 2026, 20:44
37
+ **Velo**: Enabled
38
+
39
+ ### Properties
40
+
41
+ **Locale & Region**
42
+ - Language: **en**
43
+ - Country: **US**
44
+ - Timezone: **America/New_York**
45
+ - Currency: **USD**
46
+
47
+ ### Apps
48
+
49
+ - **Wix Stores** (ID: `215238eb-22a5-4c36-9e7b-e7c08025e04e`) — Catalog app version: **V3**
50
+ - **Wix Bookings** (ID: `13d21c63-b5ec-5912-8397-c3a5ddb27a97`)
51
+ - **Wix Blog** (ID: `14bcded7-0066-7c35-14d7-466cb3f09103`)
52
+ ```
53
+
54
+ ### Without siteId
55
+
56
+ ```bash
57
+ curl -X POST \
58
+ 'https://www.wixapis.com/_api/dynamic-context/v1/dynamic-context/markdown' \
59
+ -H 'Authorization: <AUTH>' \
60
+ -H 'Content-Type: application/json' \
61
+ -d '{}'
62
+ ```
63
+
64
+ - **Account token**: returns up to 10 sites. If the account has more: `_Showing 10 sites (more available)_` — call again with a specific `siteId`.
65
+ - **Site-scoped token** (e.g. the Wix connector in Base44): returns the one site the token is scoped to.
66
+
67
+ ---
68
+
69
+ ## JSON endpoint
70
+
71
+ **Endpoint**: `POST https://www.wixapis.com/_api/dynamic-context/v1/dynamic-context`
72
+
73
+ Same request shape. `installedApps` contains raw `appId` UUIDs — extract only what you need:
74
+
75
+ ```javascript
76
+ const res = await fetch(
77
+ "https://www.wixapis.com/_api/dynamic-context/v1/dynamic-context",
78
+ {
79
+ method: "POST",
80
+ headers: { Authorization: `Bearer ${accessToken}`, "Content-Type": "application/json" },
81
+ body: JSON.stringify({ siteId: metaSiteId }),
82
+ }
83
+ );
84
+ const { sites } = await res.json();
85
+ const site = sites[0];
86
+
87
+ const KNOWN_APPS = {
88
+ stores: "215238eb-22a5-4c36-9e7b-e7c08025e04e",
89
+ bookings: "13d21c63-b5ec-5912-8397-c3a5ddb27a97",
90
+ blog: "14bcded7-0066-7c35-14d7-466cb3f09103",
91
+ events: "140603ad-af8d-84a5-2c80-a0f60cb47351",
92
+ pricingPlans: "1522827f-c56c-a5c9-2ac9-00f9e6ae12d3",
93
+ restaurants: "13e8d036-5516-6f75-e025-2aca3b5d7930",
94
+ };
95
+
96
+ const appById = Object.fromEntries(
97
+ (site.installedApps ?? []).map((a) => [a.appId, a])
98
+ );
99
+
100
+ const context = {
101
+ id: site.id,
102
+ name: site.displayName,
103
+ url: site.url,
104
+ currency: site.properties?.paymentCurrency,
105
+ locale: `${site.properties?.locale?.languageCode}-${site.properties?.locale?.country}`,
106
+ timezone: site.properties?.timeZone,
107
+ hasStores: !!appById[KNOWN_APPS.stores],
108
+ storesCatalogV: appById[KNOWN_APPS.stores]?.catalogVersion ?? null, // "V3" | "V1" | null
109
+ hasBookings: !!appById[KNOWN_APPS.bookings],
110
+ hasBlog: !!appById[KNOWN_APPS.blog],
111
+ hasEvents: !!appById[KNOWN_APPS.events],
112
+ hasPricingPlans: !!appById[KNOWN_APPS.pricingPlans],
113
+ hasRestaurants: !!appById[KNOWN_APPS.restaurants],
114
+ };
115
+ ```
116
+
117
+ ---
118
+
119
+ ## API Reference
120
+
121
+ - [Get Dynamic Context — markdown](https://dev.wix.com/docs/api-reference/tools/dynamic-site-context/get-dynamic-context-markdown)
122
+ - [Get Dynamic Context — JSON](https://dev.wix.com/docs/api-reference/tools/dynamic-site-context/get-dynamic-context)
123
+ - [Query Sites](https://dev.wix.com/docs/api-reference/account-level/sites/sites/query-sites) — for paginating or filtering the full site list
124
+ - [Get Installed Apps](https://dev.wix.com/docs/api-reference/business-management/app-installation/app-installation/get-installed-apps) — raw app instances with fields not in the context snapshot
125
+ - [Get Site Properties](https://dev.wix.com/docs/api-reference/business-management/site-properties/properties/get-site-properties) — full properties including business description, address, social links
@@ -1,6 +1,6 @@
1
1
  ---
2
2
  name: "Site Import"
3
- description: Drive the Wix Site Import agent to migrate an existing store or site from another platform (Shopify, WooCommerce, Magento, or any URL) into Wix. 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.
3
+ description: 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.
4
4
  ---
5
5
 
6
6
  # Site Import
@@ -54,7 +54,20 @@ Example — Start:
54
54
 
55
55
  ```
56
56
  POST https://www.wixapis.com/site-import/v1/imports
57
- Body: { "request": "Import https://example-store.com into a new Wix site" }
57
+ Body: {
58
+ "request": "Import https://example-store.com into a new Wix site",
59
+ "source_url": "https://example-store.com"
60
+ }
61
+ ```
62
+
63
+ Example — Start from exported files (no source site, FILE run):
64
+
65
+ ```
66
+ POST https://www.wixapis.com/site-import/v1/imports
67
+ Body: {
68
+ "request": "Import these product export files into a new Wix site",
69
+ "fileUrls": ["https://example.com/exports/products.csv"]
70
+ }
58
71
  ```
59
72
 
60
73
  Example — Poll:
@@ -96,7 +109,8 @@ and act only on the user's explicit yes.
96
109
 
97
110
  This creates real infrastructure and writes to the user's Wix account. Before
98
111
  calling **Start**, confirm:
99
- - The source URL and platform are correct
112
+ - The source URL and platform are correct — or, for a file-only import, the
113
+ export file URL(s) are correct
100
114
  - The user understands it runs for up to ~60 minutes and may ask questions mid-way
101
115
 
102
116
  Also confirm before calling **Cancel** — it's irreversible.
@@ -107,7 +121,7 @@ You are the user experience; the API is plumbing. Keep the protocol invisible:
107
121
 
108
122
  - **Show the `importId` once, right after Start succeeds** — e.g. "Your import
109
123
  ID is `abc123` — keep it handy." Never show raw JSON, HTTP codes, artifact
110
- ids, or `sourcePlatform`/`sourceConfidence` values.
124
+ ids, or `sourcePlatform`/`sourceConfidence`/`destinationSiteId` values.
111
125
  - **Write for a non-technical audience.** No jargon: no "endpoint", "API",
112
126
  "poll", "HTTP", "rate limit", "JSON". Translate events into plain outcomes —
113
127
  "the source store limits how fast it can be read" not "hit rate limit (429)".
@@ -148,12 +162,37 @@ You are the user experience; the API is plumbing. Keep the protocol invisible:
148
162
  **Single `importId` for the whole import — assigned at Start, never changes.**
149
163
 
150
164
  1. **Start** — `POST /v1/imports`
151
- Body: `{"request": "<natural language; MUST include the source store URL>"}`
152
- Returns: `importId`, `sourcePlatform`, `sourceConfidence`.
153
- One import per store at a time: if the same user re-starts for the same store,
154
- the server returns the existing `importId` (no new import is created). If a
155
- different user on the account already owns an import for that store, Start
156
- returns `409 { "code": "IMPORT_IN_PROGRESS" }` — tell the user and stop.
165
+ Body: `{"request": "<natural language; MUST include the source store URL when crawling a live site>", "source_url": "<the source store URL>", "fileUrls": ["<CSV/TSV export URL>", ...]}`
166
+ `request` is required (1–20000 chars). `source_url` and `fileUrls` are both
167
+ optional, but send whichever applies — never leave both out with no way to
168
+ identify what to import:
169
+ - **`source_url`** — send it whenever the user names a site to crawl. It's
170
+ the identity the service uses to select which migration the request joins,
171
+ not just an extra hint.
172
+ - **`fileUrls`** — send it when the user has CSV/TSV export file(s) to import
173
+ instead of crawling a live site. Setting it makes this a **FILE run**: no
174
+ source site is probed and no source credentials are requested, even if
175
+ `source_url` is also present — `source_url` only changes what the
176
+ migration is keyed on (see below), it does not add a crawl on top of the
177
+ file import. Up to 20 URLs, http/https only (ports 80/443), each ≤2048
178
+ chars. If `source_url` is absent, the file set itself is the migration
179
+ identity — re-sending the same URLs continues the same migration; a
180
+ different set starts a new one. If a URL isn't reachable, the whole call
181
+ is rejected with `INVALID_FILE_URL` (nothing is silently dropped).
182
+ - A request with neither `source_url` nor a URL/site identifiable in
183
+ `request`, and no `fileUrls`, is rejected with `SITE_UNIDENTIFIED`.
184
+ Returns: `importId`, `sourcePlatform`, `sourceConfidence`, `destinationSiteId`.
185
+ `sourcePlatform` comes back as `CSV` for a FILE run (no site was probed, so
186
+ `sourceConfidence` is meaningless there). `destinationSiteId` is the id of
187
+ the Wix site being imported into — returned as soon as Start succeeds,
188
+ even before a source is confirmed.
189
+ **One import per store at a time, keyed on `source_url`** (or the file set
190
+ when there's no `source_url`): re-starting with the same identity continues
191
+ the SAME migration (server returns the existing `importId`, no new import
192
+ created). A different identity always starts an independent migration, even
193
+ for the same user. If a different user on the account already owns an
194
+ import for that identity, Start returns
195
+ `409 { "code": "IMPORT_IN_PROGRESS" }` — tell the user and stop.
157
196
 
158
197
  2. **Poll** — `GET /v1/imports/{importId}?includeRecentActivity=true`
159
198
  Returns: `status`, `deployUrl`, `message`, `options[]` (only when
@@ -230,13 +269,26 @@ the user has no way to open a file.
230
269
  - Never invent a `deployUrl` — only report the one returned with `DEPLOYED`.
231
270
  - Treat `NEEDS_INPUT` and `AUTH_EXPIRED` as normal conversation turns, not
232
271
  errors.
233
- - **Site Import is in limited rollout.** If Start returns `404` or `403` with
234
- `"code": "NOT_ENABLED"`, tell the user plainly that site import isn't
235
- supported on their account yet and they can contact Wix support — then stop.
236
- Do not retry or fall back to another site-creation tool.
272
+ - **Site Import is in limited rollout, with no self-service enablement path.**
273
+ If Start returns `404` or `403` with `"code": "NOT_ENABLED"`, tell the user
274
+ plainly that site import isn't available on their account yet — then stop.
275
+ **Do not tell them to "contact Wix support"**: this API is unlisted and
276
+ ALPHA, Wix Support has no visibility into it or way to grant access, and the
277
+ public "importing a site created outside of Wix" help-center article is an
278
+ unrelated, long-stalled feature-request page — sending a user to either is a
279
+ dead end. If a Wix feedback tool is available in your environment, you may
280
+ offer to send feedback noting their interest; that is the only channel that
281
+ reaches the team. Do not retry or fall back to another site-creation tool.
237
282
  - Any other `403` on Start means the caller is not authorized — tell the user
238
283
  and stop. Do not probe other endpoints to diagnose this. A `400` means a
239
- required field is missing (`request`/`message` must be 1–20000 chars).
284
+ required field is missing (`request`/`message` must be 1–20000 chars),
285
+ `source_url` exceeds 2048 chars, or `fileUrls` has more than 20 entries or
286
+ one over 2048 chars. A request with no identifiable site (no `source_url`
287
+ and no URL in `request`) and no `fileUrls` is rejected with
288
+ `SITE_UNIDENTIFIED` — ask the user for the store URL or export file(s) and
289
+ retry. A `fileUrls` entry that isn't a reachable http/https URL rejects the
290
+ whole call with `INVALID_FILE_URL` — tell the user which link failed and ask
291
+ for a working one.
240
292
  - Requesting an unknown id in `artifactIds` is silently ignored — not an error.
241
293
  A document simply may not exist yet on an earlier turn.
242
294
  - **The user cannot open files.** If a message mentions a document by filename,
@@ -0,0 +1,273 @@
1
+ ---
2
+ name: "Create Product (Catalog V3)"
3
+ description: Mandatory first recipe for every Wix Stores Catalog V3 create-product request. Before any mutation, require an explicit name and price for every product; an absent price is never 0. If no product is identified, offer both image-upload and text-description paths and stop. If name or price is missing, ask or offer a suggestion and stop. When both are present, create from the supplied details without requiring optional enrichment. Covers single/bulk creation, inventory, physical/digital products, images, options, variants, SKUs, and validation.
4
+ ---
5
+
6
+ # Create Product (Catalog V3)
7
+
8
+ Use this recipe for one or multiple Catalog V3 products. Catalog V1 remains supported through [Create Product (Catalog V1)](create-product-catalog-v1.md).
9
+
10
+ > [!IMPORTANT]
11
+ > **Apply the no-product gate first.** A vague request such as “I’d like to add a new product” does not identify a product. Respond only:
12
+ >
13
+ > **“What product would you like to create? You can upload up to 3 images and I’ll generate the product information from them, or describe the product in text.”**
14
+ >
15
+ > Then end the turn. Do not ask for name, price, product type, options, SEO, inventory, or any other structured field yet. Do not replace the image-or-text choice with a checklist, form, or questionnaire. Reading this recipe must be the final tool call in that turn.
16
+
17
+ Canonical example:
18
+
19
+ - User: “For my Wix store, I’d like to add a new product.”
20
+ - Assistant: “What product would you like to create? You can upload up to 3 images and I’ll generate the product information from them, or describe the product in text.”
21
+ - Result: **Stop. Do not request structured product fields yet.**
22
+
23
+ ## Preflight: respond and return before mutation
24
+
25
+ Name and price are mandatory **workflow inputs for every product**, even when the API schema accepts an omitted price or initializes it to zero. Evaluate the cases below in order. When a case says **RETURN**, end the turn immediately: do not call a create endpoint, do not continue to examples, and do not create first and ask afterward.
26
+
27
+ 1. **No product identified:** Respond only: “What product would you like to create? You can upload up to 3 images and I’ll generate the product information from them, or describe the product in text.” **RETURN.** Do not replace the two paths with a form, checklist, questionnaire, text-only prompt, or requests for name, price, type, options, SEO, or inventory.
28
+ 2. **Any product lacks an explicit name or price:** Ask for all missing mandatory values in one question and offer to suggest them. When only price is missing, respond only: “What price should I set for [product name]? I can suggest one if you’d like.” **RETURN.**
29
+ 3. **Every name and price is known:** Creation may continue. Options, variations, description, SEO, info sections, type, SKU, inventory, and images are optional. Use them when supplied or requested; do not ask the user to resolve them before creation.
30
+
31
+ “Create it,” “create it now,” “for my store, create,” or similar mutation language does not satisfy a missing price. A usable price must be either explicitly supplied by the user or a suggestion the user accepted. Treat `0` as supplied only when the user explicitly requests a free or zero-priced product.
32
+
33
+ Before every create call, assert both conditions:
34
+
35
+ - Every product has a non-empty name from the user or an accepted suggestion.
36
+ - Every variant has a price from the user or an accepted suggestion; no price came from an API default, placeholder, example, or assumption.
37
+
38
+ If any product is missing a price, **do not call the API**. Ask for the missing price, using the product's supplied name when available, and offer to suggest one. Never put `"amount": "0"` in the request unless the user explicitly chose a zero price.
39
+
40
+ ## Core flow
41
+
42
+ 1. Apply the preflight. When it says **RETURN**, make no API call in that turn.
43
+ 2. Send site-scoped calls with `Authorization`, `wix-site-id`, and `Content-Type: application/json`.
44
+ 3. If the catalog version is unknown, run:
45
+
46
+ ```bash
47
+ curl --request GET \
48
+ --url 'https://www.wixapis.com/stores/v3/provision/version' \
49
+ --header 'Authorization: <AUTH>' \
50
+ --header 'wix-site-id: <SITE_ID>' \
51
+ --header 'Content-Type: application/json'
52
+ ```
53
+
54
+ Continue here only for `V3_CATALOG`; use the V1 recipe for `V1_CATALOG`.
55
+ 4. Resolve each product's supplied type, variants, SKUs, inventory intent, and images after its mandatory name and variant price are known. Do not invent optional attributes the user did not supply or request.
56
+ 5. Choose the endpoint, build the products, upload any images, create, and validate every result. Continue until all requested products succeed or report the exact failed items.
57
+
58
+ ## Choose the endpoint
59
+
60
+ | Request | No inventory | Quantity or in-stock state |
61
+ |---|---|---|
62
+ | One product | `POST /stores/v3/products` | `POST /stores/v3/products-with-inventory` |
63
+ | Multiple products | `POST /stores/v3/bulk/products/create` | `POST /stores/v3/bulk/products-with-inventory/create` |
64
+
65
+ - Bulk endpoints accept 1–100 products, so a compatible bulk endpoint is also valid for one product.
66
+ - For multiple products requested as one batch, send one bulk call. Use the with-inventory endpoint when any product needs inventory; include `inventoryItem` only on tracked variants.
67
+ - Never send `inventoryItem` to a no-inventory endpoint. Do not invent inventory.
68
+ - Digital products normally use a no-inventory endpoint.
69
+ - Per bulk request, allow at most 100 products, 100 total options, 100 modifiers, 100 info sections, and 1000 variants. Split larger input into compliant batches.
70
+
71
+ ## Build each product
72
+
73
+ | Concern | Rule |
74
+ |---|---|
75
+ | Type | `PHYSICAL` uses product- and variant-level `physicalProperties`; `DIGITAL` omits physical properties and inventory. |
76
+ | Variants | Include at least one. Price, SKU, barcode, inventory, and digital file are variant-level fields. |
77
+ | Price | Use a string in `price.actualPrice.amount`; add `compareAtPrice` only when supplied. |
78
+ | SKU | Preserve supplied strings exactly, including `#`, punctuation, and leading zeroes. Keep variant SKUs unique unless explicitly requested otherwise. |
79
+ | Options | Define non-empty choices and create every requested Cartesian combination. Each variant references one choice from every option through `optionChoiceNames`. |
80
+ | Text | Prefer `plainDescription` for unformatted copy. Use `description` only for a valid Ricos document. |
81
+ | Media | Up to 3 images are supported per product. Preserve their supplied order in `media.itemsInfo.items`; `media.main` is read-only. |
82
+
83
+ This inventory-aware physical product is the reusable shape. Remove `inventoryItem` when using a no-inventory endpoint; remove `media` when no image was supplied.
84
+
85
+ ```json
86
+ {
87
+ "name": "Canvas Tee",
88
+ "productType": "PHYSICAL",
89
+ "physicalProperties": {},
90
+ "media": {"itemsInfo": {"items": [{
91
+ "url": "https://static.wixstatic.com/media/example.jpg",
92
+ "altText": "Canvas Tee"
93
+ }]}},
94
+ "options": [{
95
+ "name": "Size",
96
+ "optionRenderType": "TEXT_CHOICES",
97
+ "choicesSettings": {"choices": [
98
+ {"choiceType": "CHOICE_TEXT", "name": "Small"},
99
+ {"choiceType": "CHOICE_TEXT", "name": "Large"}
100
+ ]}
101
+ }],
102
+ "variantsInfo": {"variants": [
103
+ {
104
+ "choices": [{"optionChoiceNames": {
105
+ "optionName": "Size", "choiceName": "Small", "renderType": "TEXT_CHOICES"
106
+ }}],
107
+ "sku": "TEE-001-S",
108
+ "price": {
109
+ "actualPrice": {"amount": "18.50"},
110
+ "compareAtPrice": {"amount": "22.00"}
111
+ },
112
+ "inventoryItem": {"quantity": 13},
113
+ "physicalProperties": {},
114
+ "visible": true
115
+ },
116
+ {
117
+ "choices": [{"optionChoiceNames": {
118
+ "optionName": "Size", "choiceName": "Large", "renderType": "TEXT_CHOICES"
119
+ }}],
120
+ "sku": "TEE-001-L",
121
+ "price": {"actualPrice": {"amount": "18.50"}},
122
+ "inventoryItem": {"inStock": true},
123
+ "physicalProperties": {},
124
+ "visible": true
125
+ }
126
+ ]}
127
+ }
128
+ ```
129
+
130
+ For a color option, use `SWATCH_CHOICES`; each choice uses `choiceType: ONE_COLOR` and `colorCode`, and the variant reference uses `renderType: SWATCH_CHOICES`.
131
+
132
+ A digital product uses the smaller shape below. Add the supplied variant-level digital file only when one was provided.
133
+
134
+ ```json
135
+ {
136
+ "name": "Focus Planner PDF",
137
+ "productType": "DIGITAL",
138
+ "variantsInfo": {"variants": [{
139
+ "sku": "PDF-FOCUS-01",
140
+ "price": {"actualPrice": {"amount": "9.99"}},
141
+ "visible": true
142
+ }]}
143
+ }
144
+ ```
145
+
146
+ ### Generated descriptions and SEO
147
+
148
+ - When copy is generated from an image, every factual claim must be user-supplied or directly visible. Preserve user-supplied facts such as a stated material; do not reject them merely because the image alone cannot prove them. Color, shape, and visible decoration may come from the image. Dimensions, capacity, care instructions, durability, compatibility, performance, and any material the user did not identify must be omitted. For example, never write “dishwasher safe” or “microwave safe” unless the user supplied that fact. Omit uncertain claims instead of turning them into marketing language.
149
+ - Use `plainDescription` unless formatting is required. SEO tags use `seoData.tags`.
150
+ - For formatted bullets, the Ricos node is `BULLETED_LIST`, not `BULLET_LIST`, and its data field is `bulletedListData`:
151
+
152
+ ```json
153
+ {
154
+ "description": {"nodes": [{
155
+ "type": "BULLETED_LIST",
156
+ "nodes": [{"type": "LIST_ITEM", "nodes": [{
157
+ "type": "PARAGRAPH",
158
+ "nodes": [{"type": "TEXT", "textData": {"text": "Visible blue glaze"}}],
159
+ "paragraphData": {}
160
+ }]}],
161
+ "bulletedListData": {}
162
+ }]}
163
+ }
164
+ ```
165
+
166
+ ## Add images
167
+
168
+ Skip this step when no image was supplied. Prefer the available dedicated Wix image-upload capability and upload all attachments and public image URLs together. Do not reconstruct that capability inside a general API-execution call. When no dedicated uploader is available, use `POST /site-media/v1/files/import` with the external URL in the body field named exactly `url`—not `importUrl`:
169
+
170
+ ```json
171
+ {"url":"https://example.com/product.jpg","mimeType":"image/jpeg","displayName":"Product.jpg","mediaType":"IMAGE"}
172
+ ```
173
+
174
+ A successful upload that returns the matching `wixstatic.com` URL may be used in product media while asynchronous processing is `PENDING`; do not treat `PENDING` alone as a failure. Stop if the upload reports `FAILED`. Poll `GET /site-media/v1/files/get-file-by-id?fileId=<FILE_ID>` until `file.operationStatus` is `READY` only when the workflow needs guaranteed processing, image metadata, transformations, or independent proof that the asset is ready. A pending URL proves submission, not completed processing, so do not describe it as ready or fully verified unless a later response proves that. Do not use a thumbnail URL or reuse the original external URL after upload.
175
+
176
+ Track every upload as its own product-to-file record. A poll or timeout fallback may return only that file's URL—never another product's URL. If an upload fails, retry the same asset through another supported transfer method when possible; never silently replace it with a different image. If the exact asset cannot be preserved, create only products whose requested images uploaded successfully and report every blocked product and failed source exactly; for a single required-image product, make no product-create call.
177
+
178
+ ## Wrap the request
179
+
180
+ Use the chosen product object directly in either envelope:
181
+
182
+ ```json
183
+ {"product": PRODUCT}
184
+ ```
185
+
186
+ ```json
187
+ {"products": [PRODUCT_1, PRODUCT_2], "returnEntity": true}
188
+ ```
189
+
190
+ The first is for single endpoints; the second is for bulk endpoints. If the user supplies only a SKU pattern for variants, generate a stable unique SKU per combination and preserve the mapping in the result.
191
+
192
+ For one product when the user supplied no quantity, stock state, or inventory-tracking request, the complete direct path is `POST /stores/v3/products` with `{"product": PRODUCT}`. Do not infer `inStock: true`, add `inventoryItem`, or choose `/products-with-inventory`; physical product type does not imply inventory. If it has ready images, add `"fields": ["MEDIA_ITEMS_INFO"]` to the same no-inventory request.
193
+
194
+ For one physical product with inventory, the complete direct path is one `POST /stores/v3/products-with-inventory` call with `{"product": PRODUCT}`. Put `inventoryItem` on its priced variant. If it has ready images, add `"fields": ["MEDIA_ITEMS_INFO"]` to that same request. The product shape, envelope, endpoint, and validation paths are complete here: do not search another recipe or schema, probe an alternate endpoint, or make a post-create read unless the projected create response does not prove requested media.
195
+
196
+ ### Request projected media when validating images
197
+
198
+ `media.itemsInfo.items` is a projected response field. Creating a product with media does not guarantee that the create response—or an ordinary Get Product call—returns the gallery. To receive it, pass `"MEDIA_ITEMS_INFO"` in the request-level `fields` array.
199
+
200
+ For a single create with images:
201
+
202
+ ```json
203
+ {"product": PRODUCT_WITH_MEDIA, "fields": ["MEDIA_ITEMS_INFO"]}
204
+ ```
205
+
206
+ For a bulk create with images:
207
+
208
+ ```json
209
+ {
210
+ "products": [PRODUCT_1, PRODUCT_2],
211
+ "returnEntity": true,
212
+ "fields": ["MEDIA_ITEMS_INFO"]
213
+ }
214
+ ```
215
+
216
+ If the create result still does not prove the stored gallery, make at most one read-only verification call:
217
+
218
+ ```http
219
+ GET /stores/v3/products/<PRODUCT_ID>?fields=MEDIA_ITEMS_INFO
220
+ ```
221
+
222
+ Inspect `product.media.itemsInfo.items` from that projected response. Do not interpret an omitted `itemsInfo` as lost media, search the Update Product schema, or PATCH the same media merely to retrieve it. A PATCH is appropriate only when a projected response proves the stored media is actually wrong.
223
+
224
+ ## Validate before reporting success
225
+
226
+ | Endpoint result | Required checks |
227
+ |---|---|
228
+ | Single, no inventory | Require `product.id`; report only response-backed fields as verified. For images, request `MEDIA_ITEMS_INFO` on create or use one projected Get Product verification call. |
229
+ | Single, with inventory | Require `product.id`; inspect `inventoryResults.results`, item metadata, and top-level error. |
230
+ | Bulk, no inventory | Inspect every `results[].itemMetadata`; with `returnEntity: true`, the created entity is `results[].item`, not `results[].product`. Reconcile `bulkActionMetadata.totalSuccesses` and `totalFailures` with the requested count. |
231
+ | Bulk, with inventory | Use the exact two-sibling response paths below. Inspect every product and inventory result, both bulk metadata objects, item metadata, and the inventory error before reporting success. |
232
+
233
+ `POST /stores/v3/bulk/products-with-inventory/create` does **not** return the same flat envelope as `/stores/v3/bulk/products/create`. Its response has two top-level sibling objects:
234
+
235
+ ```json
236
+ {
237
+ "productResults": {
238
+ "results": [{"itemMetadata": {}, "item": {}}],
239
+ "bulkActionMetadata": {}
240
+ },
241
+ "inventoryResults": {
242
+ "results": [{"itemMetadata": {}, "item": {}}],
243
+ "bulkActionMetadata": {},
244
+ "error": null
245
+ }
246
+ }
247
+ ```
248
+
249
+ Before claiming that an inventory-aware bulk create succeeded:
250
+
251
+ 1. Inspect every `productResults.results[]` entry and require `itemMetadata.success`; with `returnEntity: true`, read the product from `item`.
252
+ 2. Reconcile `productResults.bulkActionMetadata.totalSuccesses`, `totalFailures`, and `undetailedFailures` with the requested product count.
253
+ 3. Separately inspect every top-level `inventoryResults.results[]` entry and require `itemMetadata.success`; with `returnEntity: true`, read the inventory entity from `item`.
254
+ 4. Reconcile `inventoryResults.bulkActionMetadata.totalSuccesses`, `totalFailures`, and `undetailedFailures` with the expected inventory-item count, and inspect `inventoryResults.error`.
255
+
256
+ The inventory error check is mandatory even when every item and metadata count succeeded. Explicitly read the sibling field—for example, normalize `inventoryResults.error ?? null`—and report success only when it is absent or null. Do not infer that value from HTTP 200, item metadata, or bulk metadata.
257
+
258
+ For `POST /stores/v3/products-with-inventory`, inspect the returned `product.id`, every `inventoryResults.results[].itemMetadata`, and top-level `inventoryResults.error` directly from the create response. Do not issue inventory queries, product searches, Get Product calls, or PATCH calls merely to reconfirm values already proven by that response. If item success proves the inventory write but the response omits the requested quantity, report the quantity as submitted; if the user needs it independently verified, make one targeted inventory read using the returned product ID without first fetching the product again. The only other allowed extra read is the single projected media verification described above when requested images are not present in the projected create result. GET and HEAD requests must not include a request body.
259
+
260
+ Never read `productResults.inventoryResults`: that path does not exist. A successful product result or HTTP 200 does not prove inventory creation succeeded.
261
+
262
+ Retry only failed transient items, not successful products. If a requested field is absent from the response, call it submitted rather than API-verified; never echo the request as proof that it was stored.
263
+
264
+ `product.visible: true` proves catalog visibility, not that an unpublished site is live. Say “created” or “visible in the catalog”; say “live” only when site publication is independently confirmed.
265
+
266
+ ## Failure guide
267
+
268
+ - Inventory missing: use the with-inventory endpoint and include `inventoryItem` on each tracked variant.
269
+ - Multiple requested products sent separately: use one compatible bulk call unless they cannot form a compliant batch or specific failed items are being retried.
270
+ - `variantsInfo must not be empty`: include at least one priced variant per product.
271
+ - Option/variant mismatch: create every requested combination and reference every option once per variant.
272
+ - Media not visible: use the uploaded `wixstatic.com` URL in `media.itemsInfo.items`; do not set `media.main`.
273
+ - Digital product rejected: omit physical properties and inventory; keep price, SKU, and any supplied digital file on the variant.
@@ -324,7 +324,7 @@ function applySafeModeToRequestBody(body, safeModeOptions) {
324
324
  // media import, Contacts manage/schema, and Members manage.
325
325
  //
326
326
  // Auth scheme normalization: Wix API keys (`IST.…`) are sent RAW in the Authorization
327
- // header; OAuth access tokens (e.g. a Wix CLI token from `npx @wix/cli token --site …`)
327
+ // header; OAuth access tokens (e.g. a Wix CLI token from `npx @wix/cli@latest token --site …`)
328
328
  // must be sent as `Bearer <token>`. Detect and prefix so both credential kinds work.
329
329
  function authHeaderValue(token) {
330
330
  const t = String(token).trim();
@@ -149,7 +149,8 @@ installed, not what the business is about. Never default to store/bookings on si
149
149
  `INSTRUCTIONS.md`.
150
150
  3. **Ensure the vertical's files are in place** — copy `references/<vertical>/app/` and
151
151
  `references/shared/app/` into the app's `src/`, and set `WIX_CLIENT_ID` in `wix-config.js`. (Where
152
- and how they get there is your platform's call — see its instructions.)
152
+ and how they get there is your platform's call — see its instructions. On base44 the install step
153
+ writes and verifies `wix-config.js` for you, so there's nothing to set by hand.)
153
154
  4. **Wire the shipped client** following the vertical's INSTRUCTIONS: the components are themed by
154
155
  base44's design tokens (`src/index.css` — shadcn palette, already set by the design phase), so
155
156
  there's no re-skin step; just wire routes + header/footer through the Layout. The UI ships as
@@ -1,6 +1,8 @@
1
1
  // Post-install deploy — run by base44.md STEP 1 with the vertical(s) the app needs:
2
- // node deploy.cjs <vertical> [<vertical> …]
2
+ // node deploy.cjs <vertical> [<vertical> …] --client-id <id> --metasite-id <id>
3
3
  // (storefront | bookings | blog | cms | portfolio | pricing-plans | events | members)
4
+ // Pass the two ids from the prompt and this writes src/rest/wix-config.js for you — see WRITE below.
5
+ // Retyping those ids into the file by hand is how a storefront ships with a dead client id.
4
6
  // ONE mechanism: recursively copy `app/` -> /app/src. The shared transport (app/rest/wix-client.js,
5
7
  // wix-config.js) is copied always; then each named vertical's app/ (its UI + app/rest/ helpers).
6
8
  // Deploy every vertical the app actually uses, in one call or across several — an app that needs both
@@ -13,9 +15,10 @@
13
15
  // No vertical arg -> deploys just the shared transport; re-run with the vertical(s) once known.
14
16
  // NOTE: .cjs on purpose — the app is an ESM package ("type":"module"); a .js here would load as ESM
15
17
  // and require()/module.exports would throw.
16
- const { existsSync, cpSync, readFileSync } = require('fs');
18
+ const { existsSync, cpSync, readFileSync, writeFileSync } = require('fs');
17
19
 
18
20
  const REF = '/app/.agents/skills/wix-vibe-headless/references';
21
+ const WIX_CONFIG = '/app/src/rest/wix-config.js';
19
22
  const VERTICALS = ['storefront', 'bookings', 'blog', 'cms', 'portfolio', 'pricing-plans', 'events', 'members', 'restaurants'];
20
23
 
21
24
  // force:false + errorOnExist:false — fill in only files that AREN'T there yet; never overwrite.
@@ -66,11 +69,55 @@ function replaceMembersAuthLeftovers() {
66
69
  return result;
67
70
  }
68
71
 
72
+ // --- WRITE the credentials ----------------------------------------------------------------------
73
+ //
74
+ // The two ids arrive as flags so this script writes them once, character-for-character, instead of a
75
+ // later hand-edit of the placeholder file.
76
+ //
77
+ // An id already in the file wins; the flags only fill what is unset. A host that writes this file
78
+ // at app creation (Base44) has each id as an exact value rather than a copy read out of a prompt.
79
+ // Per id, so a host that resolved one but not the other still gets the gap filled.
80
+ //
81
+ // This briefly worked the other way round for WIX_METASITE_ID, while Base44 could write a different
82
+ // site than the business: it shared one field between the launch and a metasite it provisions per
83
+ // app, and the launch's id lost. Fixed on that side, and the ids it stores now verify against the
84
+ // site each launch came from, so the file is trusted again.
85
+ function readWixConfig() {
86
+ if (!existsSync(WIX_CONFIG)) return {};
87
+ const src = readFileSync(WIX_CONFIG, 'utf8');
88
+ const pick = (name) => {
89
+ const v = (src.match(new RegExp(`${name}\\s*=\\s*["']([^"']*)["']`)) || [])[1] || '';
90
+ return v.startsWith('<') ? '' : v; // the shipped file's `<YOUR-…>` placeholders count as unset
91
+ };
92
+ return { clientId: pick('WIX_CLIENT_ID'), metaSiteId: pick('WIX_METASITE_ID') };
93
+ }
94
+
95
+ function writeWixConfig(clientId, metaSiteId) {
96
+ const body = [
97
+ '// Wix credentials — written by the skill\'s deploy step from the ids in your prompt.',
98
+ '// Safe to commit: WIX_CLIENT_ID is a public, buyer-facing id (it only mints anonymous visitor',
99
+ '// tokens); WIX_METASITE_ID just identifies the site.',
100
+ `export const WIX_CLIENT_ID = "${clientId}";`,
101
+ `export const WIX_METASITE_ID = "${metaSiteId}";`,
102
+ '',
103
+ ].join('\n');
104
+ writeFileSync(WIX_CONFIG, body);
105
+ }
106
+
69
107
  // --- main ---------------------------------------------------------------------------------------
70
108
 
71
109
  // Accept one or many: `deploy.cjs members cms`. Duplicates collapse; order is preserved so the
72
110
  // first vertical listed wins any same-path file (the copy never overwrites).
73
- const requested = [...new Set(process.argv.slice(2))];
111
+ const argv = process.argv.slice(2);
112
+ const flag = (name) => {
113
+ const i = argv.indexOf(`--${name}`);
114
+ return i !== -1 && argv[i + 1] && !argv[i + 1].startsWith('--') ? argv[i + 1] : null;
115
+ };
116
+ const clientId = flag('client-id');
117
+ const metaSiteId = flag('metasite-id');
118
+ // Verticals are the positional args — drop the flags and their values.
119
+ const flagArgs = new Set(['--client-id', '--metasite-id', clientId, metaSiteId].filter(Boolean));
120
+ const requested = [...new Set(argv.filter((a) => !flagArgs.has(a)))];
74
121
  const deployed = { verticals: [] };
75
122
 
76
123
  // Shared transport — always (app/rest/wix-client.js, wix-config.js -> src/rest/).
@@ -92,4 +139,17 @@ if (!requested.length) {
92
139
  deployed.note = 'no vertical given — deployed the shared transport only; re-run: node deploy.cjs <vertical> [<vertical> …]';
93
140
  }
94
141
 
142
+ const onDisk = readWixConfig();
143
+ const finalClientId = onDisk.clientId || clientId;
144
+ const finalMetaSiteId = onDisk.metaSiteId || metaSiteId;
145
+
146
+ if (!finalClientId || !finalMetaSiteId) {
147
+ deployed.wixConfig = 'skipped — no ids provided';
148
+ } else if (finalClientId === onDisk.clientId && finalMetaSiteId === onDisk.metaSiteId) {
149
+ deployed.wixConfig = 'already_set';
150
+ } else {
151
+ writeWixConfig(finalClientId, finalMetaSiteId);
152
+ deployed.wixConfig = 'written';
153
+ }
154
+
95
155
  console.log(JSON.stringify(deployed));