@wix/agent-skills 1.15.0 → 1.15.1

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 (61) hide show
  1. package/README.md +8 -0
  2. package/package.json +1 -1
  3. package/skills/wix-app/references/DATA_COLLECTION.md +5 -3
  4. package/skills/wix-app/references/EDITOR_REACT_COMPONENT.md +2 -0
  5. package/skills/wix-app/references/STORES_VERSIONING.md +9 -211
  6. package/skills/wix-app/references/backend-event/COMMON-EVENTS.md +5 -0
  7. package/skills/wix-app/references/editor-react-component/ANIMATED-COMPONENTS.md +151 -0
  8. package/skills/wix-app/references/editor-react-component/COMPONENT-PREVIEW.md +57 -0
  9. package/skills/wix-app/references/editor-react-component/CSS-GUIDELINES.md +6 -0
  10. package/skills/wix-app/references/editor-react-component/REACT-GUIDELINES.md +3 -1
  11. package/skills/wix-app/references/stores/CATEGORIES.md +22 -0
  12. package/skills/wix-app/references/stores/GET_PRODUCT.md +99 -0
  13. package/skills/wix-app/references/stores/INVENTORY.md +37 -0
  14. package/skills/wix-app/references/stores/QUERY.md +87 -0
  15. package/skills/wix-app/references/stores/WRITE.md +55 -0
  16. package/skills/wix-headless/SKILL.md +6 -1
  17. package/skills/wix-headless/entry/bootstrap.mjs +2 -2
  18. package/skills/wix-headless/entry/skill.md +0 -2
  19. package/skills/wix-headless/references/CAPABILITIES.md +6 -4
  20. package/skills/wix-headless/references/DISCOVERY.md +1 -1
  21. package/skills/wix-headless/references/FEEDBACK.md +16 -5
  22. package/skills/wix-headless/references/SDK_HANDOFF.md +2 -0
  23. package/skills/wix-headless/references/SEED.md +3 -1
  24. package/skills/wix-headless/references/SETUP.md +1 -1
  25. package/skills/wix-headless/references/inline-recipes/how-to-code-restaurant-reservations.md +42 -2
  26. package/skills/wix-headless/references/inline-recipes/setup-bookings.md +5 -1
  27. package/skills/wix-headless/references/inline-recipes/setup-forms.md +1 -1
  28. package/skills/wix-headless/references/inline-recipes/setup-online-store.md +21 -5
  29. package/skills/wix-headless/references/inline-recipes/setup-portfolio.md +3 -1
  30. package/skills/wix-headless/references/inline-recipes/setup-restaurant-experiences.md +73 -0
  31. package/skills/wix-headless/references/inline-recipes/setup-restaurant-orders.md +38 -2
  32. package/skills/wix-headless/references/inline-recipes/setup-restaurant-reservations.md +20 -1
  33. package/skills/wix-headless/references/inline-recipes/setup-restaurants.md +1 -1
  34. package/skills/wix-headless/references/managed/CONNECT.md +1 -1
  35. package/skills/wix-headless/references/managed/CREATE.md +1 -1
  36. package/skills/wix-headless/references/managed/DEPLOYMENT.md +22 -0
  37. package/skills/wix-headless/references/self-managed/DEPLOYMENT.md +8 -0
  38. package/skills/wix-headless/references/stripe/DEPLOYMENT.md +8 -0
  39. package/skills/wix-manage/SKILL.md +8 -5
  40. package/skills/wix-manage/references/analytics/query-site-analytics.md +66 -9
  41. package/skills/wix-manage/references/app-installation/install-wix-apps.md +3 -0
  42. package/skills/wix-manage/references/bookings/create-booking-service-from-prompt.md +6 -5
  43. package/skills/wix-manage/references/bookings/create-course-service.md +30 -5
  44. package/skills/wix-manage/references/bookings/diagnose-availability-issues.md +76 -42
  45. package/skills/wix-manage/references/cms/cms-schema-management.md +6 -0
  46. package/skills/wix-manage/references/get-paid/how-to-setup-wix-payments.md +30 -7
  47. package/skills/wix-manage/references/marketing/create-and-publish-social-post.md +225 -144
  48. package/skills/wix-manage/references/marketing/generate-and-publish-marketing-plan.md +19 -10
  49. package/skills/wix-manage/references/sites/site-import.md +270 -0
  50. package/skills/wix-manage/references/stores/create-product-from-image.md +8 -6
  51. package/skills/wix-manage/references/stores/create-product-with-options-catalog-v3.md +16 -10
  52. package/skills/wix-vibe-headless/SKILL.md +6 -0
  53. package/skills/wix-vibe-headless/platforms/README.md +22 -0
  54. package/skills/wix-vibe-headless/platforms/base44.md +142 -0
  55. package/skills/wix-vibe-headless/platforms/generic.md +87 -0
  56. package/skills/wix-vibe-headless/references/bookings/INSTRUCTIONS.md +5 -1
  57. package/skills/wix-vibe-headless/references/bookings/wix-bookings-services.js +3 -1
  58. package/skills/wix-vibe-headless/references/events/wix-events-browse.js +2 -1
  59. package/skills/wix-vibe-headless/references/portfolio/wix-portfolio.js +84 -55
  60. package/skills/wix-vibe-headless/references/storefront/INSTRUCTIONS.md +11 -2
  61. package/skills/wix-vibe-headless/references/storefront/wix-store-catalog.js +5 -1
@@ -0,0 +1,87 @@
1
+ # Wix Managed Headless — build instructions
2
+
3
+ You are building a **Wix Managed** headless site. The business to build, and your Wix client id
4
+ and metasite id, are given in your initial prompt. Follow the steps below.
5
+
6
+ ## STEP 0 — Install the Wix skills locally
7
+
8
+ Install three skills — they land under `.agents/skills/` as:
9
+ - **`wix-vibe-headless`** — the client build guide: how to build the frontend against the Wix
10
+ APIs. This is your main source of truth (STEP 1).
11
+ - **`wix-headless`** — a broad skill for building full Wix apps with the Wix SDK packages, **most
12
+ of which does not apply to how you build here**. Use it **only** as a seeding/admin recipe
13
+ reference — its `references/SEED.md` and `references/inline-recipes/`, for STEP 2. **Ignore
14
+ everything else in it** — in particular do **not** follow its authentication / `@wix/cli` /
15
+ "managed project" setup (e.g. anything under `references/managed/`, such as `AUTHENTICATION.md`).
16
+ That is **not** how auth works here — auth is handled per STEP 2 below.
17
+ - **`wix-docs`** — a **fallback**: how to search and read the Wix API reference docs, for anything
18
+ the seeding recipes above don't cover.
19
+
20
+ Install them so you can read them from files as you go (fetching skill docs over the web
21
+ truncates or summarises large files).
22
+
23
+ **Run the Skills CLI** — this is the install path to use:
24
+ ```bash
25
+ CI=1 npx skills@latest add wix/skills/skills/wix-headless --yes
26
+ CI=1 npx skills@latest add wix/skills/skills/wix-vibe-headless --yes
27
+ CI=1 npx skills@latest add wix/skills/skills/wix-docs --yes
28
+ ```
29
+
30
+ **Only if the CLI above actually errors** (not on a guess), fall back to curl + gzip — download
31
+ each bundle and extract it into `.agents/skills/wix-<name>/`:
32
+ ```bash
33
+ for s in headless vibe-headless docs; do
34
+ mkdir -p ".agents/skills/wix-$s"
35
+ curl -s "https://www.wix.com/skills/$s.tgz" | tar xz -C ".agents/skills/wix-$s" --strip-components=1
36
+ done
37
+ ```
38
+
39
+ ## STEP 1 — Build the client
40
+
41
+ Read `.agents/skills/wix-vibe-headless/SKILL.md` and follow it **exactly** — it is the single
42
+ source of truth for how the client app is built against the Wix APIs (over the public
43
+ `WIX_CLIENT_ID`, which is a buyer/visitor-facing credential, safe in the frontend). To save time,
44
+ prefer copying the ready-made files the `wix-vibe-headless` skill provides (e.g. the Wix client
45
+ setup) and adapting them over re-generating them from scratch.
46
+
47
+ ## STEP 2 — Seed and manage the business
48
+
49
+ Seed the site with real content by following the `wix-headless` skill's `references/SEED.md`
50
+ (`.agents/skills/wix-headless/references/SEED.md`). Where its seed recipes don't cover what you
51
+ need, fall back to the `wix-docs` skill to search and read the relevant Wix API docs.
52
+
53
+ **Seeding is additive.** You may clean up the app install's **obvious default sample/mock data**
54
+ right after a fresh install, but the site may already hold **real content** (a prior run, or
55
+ owner-added) — if what's there isn't obviously install sample data, or you're unsure, **do not
56
+ delete or overwrite it without the user's explicit ask or approval** (ask first).
57
+
58
+ These management/admin calls need **elevated Wix credentials** — the public client id is not
59
+ enough. If you don't already have a way to authenticate them, either **connect your platform's
60
+ Wix connector** (if it has one) or **ask the user for a Wix API key / token** and store it in your
61
+ platform's built-in **connector / secrets (env) manager** — never hardcode or commit it. **Once
62
+ the connector is connected (or the API key is in place), you can make Wix REST admin calls
63
+ directly** — authenticate each call with that credential (the `wix-docs` skill covers Wix API-key
64
+ auth). Or, if the user prefers, tell them they can add this content themselves in the Wix
65
+ dashboard instead.
66
+
67
+ Authenticate admin calls with **only** that connector/API key. Do **not** install or run the Wix
68
+ CLI (`@wix/cli`), do a device-login, or follow `wix-headless`'s `references/managed/AUTHENTICATION.md`
69
+ — that managed-project auth flow does not apply here.
70
+
71
+ Management/admin operations (seeding, `wix-headless`, `wix-docs`) are **separate from the
72
+ client** — the client is built solely per the `wix-vibe-headless` skill.
73
+
74
+ If possible, run STEP 1 and STEP 2 in parallel — building the client and seeding the business
75
+ are independent. Within each, also parallelize independent work (API calls, seeding multiple
76
+ entities) to finish faster.
77
+
78
+ ## Later admin requests
79
+
80
+ For any later admin/management request, work the same way as STEP 2: check the `wix-headless`
81
+ skill's inline recipes first (`.agents/skills/wix-headless/references/inline-recipes/`) and fall
82
+ back to the `wix-docs` skill where the operation isn't documented there.
83
+
84
+ ## When done
85
+
86
+ After the site is built and seeded, ask the user to open this URL to complete the setup in Wix
87
+ (substitute the metasite id you were given): `https://manage.wix.com/dashboard/{metaSiteId}`
@@ -58,7 +58,11 @@ the full API reference for anything not shown.
58
58
  ## How to wire it (UI is the project's choice)
59
59
  - **Service list** — `queryServices()` for the listing (visitor-visible services only). Render
60
60
  `name`, `tagLine`, the image via `mediaUrl(service.media?.items?.[0]?.image)`, and the price
61
- from `payment.fixed.price.formattedValue` (already includes the currency). Pass the returned
61
+ from `payment.fixed.price`. `value` + `currency` are always present; `formattedValue` is
62
+ **optional** (it may be missing), so don't depend on it — build the price from `value`+`currency`
63
+ and use `formattedValue` only when present. e.g. `new Intl.NumberFormat(undefined, { style:
64
+ 'currency', currency }).format(Number(value))`. (Rendering `formattedValue` alone leaves the price
65
+ blank — or your "Varies" fallback — whenever it's absent.) Pass the returned
62
66
  `nextOffset` back as `offset` to load the next page. Books **APPOINTMENT and CLASS** services
63
67
  (see the slot picker below); COURSE is whole-course enrollment and out of scope.
64
68
  - **Service detail** — `getService(serviceId)` keyed off the URL/route; returns null on miss —
@@ -12,7 +12,9 @@ import { wixApiRequest } from "./wix-client.js";
12
12
  * media.items {array} — [{ image: { id, url, width, height, altText } }]
13
13
  * (url may be a bare Wix media handle — pass through mediaUrl() before rendering),
14
14
  * payment.rateType "FIXED"|"CUSTOM"|"VARIED"|"NO_FEE"|"SUBSCRIPTION",
15
- * payment.fixed.price { value, currency, formattedValue },
15
+ * payment.fixed.price { value, currency, formattedValue } — value + currency are always
16
+ * present; formattedValue is optional (may be missing), so format the price from
17
+ * value+currency and use formattedValue only when present,
16
18
  * payment.options { online, inPerson, deposit, pricingPlan },
17
19
  * schedule.id {string}, onlineBooking.enabled {boolean},
18
20
  * category { id, name }, staffMemberIds {string[]}, locations {array},
@@ -24,7 +24,8 @@ import { wixApiRequest } from "./wix-client.js";
24
24
  * type {string} — "RSVP"|"TICKETING"|"EXTERNAL"|"NONE",
25
25
  * status {string} — only OPEN_* statuses accept new registrations,
26
26
  * rsvp.responseType — "YES_AND_NO" allows a "NO" reply,
27
- * tickets.currency, tickets.lowestPrice, tickets.soldOut,
27
+ * tickets.lowestPrice {object} — money { value, currency, formattedValue }; render
28
+ * formattedValue, not the object (see "Money/price fields" in SKILL.md). tickets.soldOut {boolean},
28
29
  * external.url — link out when type === "EXTERNAL",
29
30
  * eventPageUrl {object} — { base, path } (URLS fieldset) — needed for getTicketCheckoutUrl,
30
31
  * form {object} — registration form controls (FORM fieldset),
@@ -36,23 +36,31 @@ const PROJECTS_QUERY_URL = "/portfolio/v1/projects/query";
36
36
  * @returns {Promise<{ collections: object[], nextCursor: string|null }>}
37
37
  */
38
38
  export async function queryCollections({ limit = 100, cursor } = {}) {
39
- const res = await wixApiRequest(COLLECTIONS_QUERY_URL, {
40
- method: "POST",
41
- body: {
42
- includePageUrl: true,
43
- query: cursor
44
- ? { cursorPaging: { limit, cursor } }
45
- : {
46
- filter: { hidden: false },
47
- sort: [{ fieldName: "sortOrder", order: "ASC" }],
48
- cursorPaging: { limit },
49
- },
50
- },
51
- });
52
- return {
53
- collections: res?.collections ?? [],
54
- nextCursor: res?.metadata?.cursors?.next ?? null,
55
- };
39
+ try {
40
+ const res = await wixApiRequest(COLLECTIONS_QUERY_URL, {
41
+ method: "POST",
42
+ body: {
43
+ includePageUrl: true,
44
+ query: cursor
45
+ ? { cursorPaging: { limit, cursor } }
46
+ : {
47
+ filter: { hidden: false },
48
+ sort: [{ fieldName: "sortOrder", order: "ASC" }],
49
+ cursorPaging: { limit },
50
+ },
51
+ },
52
+ });
53
+ return {
54
+ collections: res?.collections ?? [],
55
+ nextCursor: res?.metadata?.cursors?.next ?? null,
56
+ };
57
+ } catch (err) {
58
+ // Degrade to an empty page instead of rethrowing: an uncaught read would leave a
59
+ // component's `loading` flag stuck true and hang the gallery on a spinner. Empty
60
+ // renders the same empty state as a genuinely empty backend.
61
+ console.error("queryCollections failed:", err);
62
+ return { collections: [], nextCursor: null };
63
+ }
56
64
  }
57
65
 
58
66
  /**
@@ -79,11 +87,18 @@ export async function getCollectionBySlug(slug) {
79
87
  * @returns {Promise<number>}
80
88
  */
81
89
  export async function countCollections() {
82
- const res = await wixApiRequest(COLLECTIONS_QUERY_URL, {
83
- method: "POST",
84
- body: { query: { filter: { hidden: false }, cursorPaging: { limit: 100 } } },
85
- });
86
- return res?.metadata?.total ?? (res?.collections?.length ?? 0);
90
+ try {
91
+ const res = await wixApiRequest(COLLECTIONS_QUERY_URL, {
92
+ method: "POST",
93
+ body: { query: { filter: { hidden: false }, cursorPaging: { limit: 100 } } },
94
+ });
95
+ return res?.metadata?.total ?? (res?.collections?.length ?? 0);
96
+ } catch (err) {
97
+ // On failure treat as empty (0) rather than rethrowing — a thrown count would hang
98
+ // the empty-state check; 0 falls through to the "add collections" prompt.
99
+ console.error("countCollections failed:", err);
100
+ return 0;
101
+ }
87
102
  }
88
103
 
89
104
  /**
@@ -93,23 +108,30 @@ export async function countCollections() {
93
108
  * @returns {Promise<{ projects: object[], nextCursor: string|null }>}
94
109
  */
95
110
  export async function queryProjects({ limit = 100, cursor } = {}) {
96
- const res = await wixApiRequest(PROJECTS_QUERY_URL, {
97
- method: "POST",
98
- body: {
99
- includePageUrl: true,
100
- query: cursor
101
- ? { cursorPaging: { limit, cursor } }
102
- : {
103
- filter: { hidden: false },
104
- sort: [{ fieldName: "createdDate", order: "DESC" }],
105
- cursorPaging: { limit },
106
- },
107
- },
108
- });
109
- return {
110
- projects: res?.projects ?? [],
111
- nextCursor: res?.metadata?.cursors?.next ?? null,
112
- };
111
+ try {
112
+ const res = await wixApiRequest(PROJECTS_QUERY_URL, {
113
+ method: "POST",
114
+ body: {
115
+ includePageUrl: true,
116
+ query: cursor
117
+ ? { cursorPaging: { limit, cursor } }
118
+ : {
119
+ filter: { hidden: false },
120
+ sort: [{ fieldName: "createdDate", order: "DESC" }],
121
+ cursorPaging: { limit },
122
+ },
123
+ },
124
+ });
125
+ return {
126
+ projects: res?.projects ?? [],
127
+ nextCursor: res?.metadata?.cursors?.next ?? null,
128
+ };
129
+ } catch (err) {
130
+ // Degrade to an empty page instead of rethrowing (see queryCollections) — an uncaught
131
+ // read hangs the gallery on an infinite spinner; empty renders the empty state instead.
132
+ console.error("queryProjects failed:", err);
133
+ return { projects: [], nextCursor: null };
134
+ }
113
135
  }
114
136
 
115
137
  /**
@@ -121,22 +143,29 @@ export async function queryProjects({ limit = 100, cursor } = {}) {
121
143
  * @returns {Promise<{ projects: object[], nextCursor: string|null }>}
122
144
  */
123
145
  export async function queryProjectsByCollection(collectionId, { limit = 100, cursor } = {}) {
124
- const res = await wixApiRequest(PROJECTS_QUERY_URL, {
125
- method: "POST",
126
- body: {
127
- includePageUrl: true,
128
- query: cursor
129
- ? { cursorPaging: { limit, cursor } }
130
- : {
131
- filter: { hidden: false, collectionIds: { $hasSome: [collectionId] } },
132
- cursorPaging: { limit },
133
- },
134
- },
135
- });
136
- return {
137
- projects: res?.projects ?? [],
138
- nextCursor: res?.metadata?.cursors?.next ?? null,
139
- };
146
+ try {
147
+ const res = await wixApiRequest(PROJECTS_QUERY_URL, {
148
+ method: "POST",
149
+ body: {
150
+ includePageUrl: true,
151
+ query: cursor
152
+ ? { cursorPaging: { limit, cursor } }
153
+ : {
154
+ filter: { hidden: false, collectionIds: { $hasSome: [collectionId] } },
155
+ cursorPaging: { limit },
156
+ },
157
+ },
158
+ });
159
+ return {
160
+ projects: res?.projects ?? [],
161
+ nextCursor: res?.metadata?.cursors?.next ?? null,
162
+ };
163
+ } catch (err) {
164
+ // Degrade to an empty page instead of rethrowing (see queryCollections) — an uncaught
165
+ // read hangs the collection page on an infinite spinner; empty renders the empty state.
166
+ console.error("queryProjectsByCollection failed:", err);
167
+ return { projects: [], nextCursor: null };
168
+ }
140
169
  }
141
170
 
142
171
  /**
@@ -50,8 +50,9 @@ reference for anything not shown.
50
50
 
51
51
  ## How to wire it (UI is the project's choice)
52
52
  - **Product grid** — `queryProducts()` for the listing (visible products only); pass
53
- `nextCursor` back as `cursor` to load the next page. Render fields directly from the Wix
54
- product object (see the `Product` typedef in `wix-store.js` for key fields). For price, use
53
+ `nextCursor` back as `cursor` to load the next page. Render most fields directly from the Wix
54
+ product object (see the `Product` typedef in `wix-store-catalog.js` for key fields) — the one
55
+ exception is `plainDescription`, which is HTML (see PDP below). For price, use
55
56
  `actualPriceRange.minValue.formattedAmount` (already includes the currency symbol) — no
56
57
  manual formatting needed.
57
58
  - **PDP** — `getProductBySlug(slug)` keyed off the URL slug; returns null on miss — show
@@ -65,6 +66,10 @@ reference for anything not shown.
65
66
  **mandatory** modifier (e.g. "gift wrap?") whose control isn't rendered can never be added: the
66
67
  buyer can't satisfy the requirement, so `add-to-cart` returns 200 with an **empty** `lineItems`
67
68
  and the add silently no-ops.
69
+ Render `product.plainDescription` as **HTML** — despite the name it contains markup (`<p>`,
70
+ `<br>`, `<strong>`), so `dangerouslySetInnerHTML={{ __html: product.plainDescription }}` (React)
71
+ or `el.innerHTML = product.plainDescription`, never as a plain text node (that shows raw `<p>`
72
+ tags). Strip tags only for plain-text contexts (SEO/meta description, a truncated card teaser).
68
73
  - **Gate the Add-to-cart button** — disable it only until the requirements the product *actually
69
74
  has* are met, computed from the product object (never assume every product has options or
70
75
  modifiers): if `product.options` is non-empty, a variant must resolve from the selections; every
@@ -86,6 +91,10 @@ reference for anything not shown.
86
91
  - **Categories** — `queryCategories()` for a category menu; `getCategoryBySlug(slug)` for
87
92
  a category landing page. Pass `category.id` to `queryProductsByCategory(categoryId, { limit?, cursor? })`
88
93
  to list only the products in that category; paginate exactly like `queryProducts`.
94
+ `queryCategories()` includes Wix's auto-created **"All Products" system category** (`slug:
95
+ "all-products"`) — it mirrors the full catalog, so drop it from the category menu
96
+ (`categories.filter(c => c.slug !== "all-products")`). Filter by that slug, not by name (renames/
97
+ localizes) or `visible` (it's `visible: true` like any other).
89
98
  - **Cart** — `addToCart(catalogItemId, variantId?, qty?, { modifierChoices?, customTextFields? }?)`,
90
99
  `updateCartItemQuantity(lineItemId, qty)`, `removeFromCart(lineItemId)`.
91
100
  - `variantId` (`variantsInfo.variants[].id` from `getProductBySlug`) — required for products with
@@ -20,7 +20,9 @@ import { wixApiRequest } from "./wix-client.js";
20
20
  * modifiers {array} — non-variant customizations (engraving, gift wrap):
21
21
  * [{ id, name, mandatory, modifierRenderType "TEXT_CHOICES"|"FREE_TEXT",
22
22
  * key, choicesSettings.choices, freeTextSettings.key }],
23
- * plainDescription {string} — HTML product description,
23
+ * plainDescription {string} — product description as an HTML string (contains <p>, <br>,
24
+ * <strong>…) despite the "plain" name — NOT plain text. Render with innerHTML /
25
+ * dangerouslySetInnerHTML; strip tags only for plain-text contexts (meta description, teaser),
24
26
  * variantsInfo.variants {array} — returned only by getProductBySlug:
25
27
  * [{ id, visible, choices [{ optionChoiceIds: { optionId, choiceId } }],
26
28
  * price: { actualPrice, compareAtPrice }, media, inventoryStatus: { inStock } }]
@@ -28,6 +30,8 @@ import { wixApiRequest } from "./wix-client.js";
28
30
  * match all selected { optionId, choiceId } pairs, then pass variant.id to addToCart.
29
31
  *
30
32
  * Category: { id, name, slug, visible, description, image, itemCounter, parentCategory.id }
33
+ * NB: queryCategories includes the auto-created system category { slug: "all-products" } —
34
+ * filter it out of a category menu (see INSTRUCTIONS.md). `visible` does not flag it.
31
35
  * Full model: https://dev.wix.com/docs/api-reference/business-solutions/stores/catalog-v3/categories
32
36
  */
33
37