@wix/agent-skills 1.7.0 → 1.8.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.
- package/README.md +3 -7
- package/package.json +1 -1
- package/skills/wix-app/SKILL.md +2 -0
- package/skills/wix-app/references/STORES_VERSIONING.md +1 -0
- package/skills/wix-design-system/SKILL.md +4 -0
- package/skills/wix-headless/SKILL.md +55 -32
- package/skills/wix-headless/references/BUILD-astro.md +246 -0
- package/skills/wix-headless/references/BUILD-own-build.md +167 -0
- package/skills/wix-headless/references/BUILD.md +50 -252
- package/skills/wix-headless/references/DESIGN_SYSTEM.md +94 -34
- package/skills/wix-headless/references/DISCOVERY-connect.md +55 -0
- package/skills/wix-headless/references/DISCOVERY-create.md +238 -0
- package/skills/wix-headless/references/DISCOVERY.md +41 -422
- package/skills/wix-headless/references/PLAN-connect.md +19 -0
- package/skills/wix-headless/references/PLAN-create.md +17 -0
- package/skills/wix-headless/references/PLAN.md +37 -27
- package/skills/wix-headless/references/SEED.md +27 -18
- package/skills/wix-headless/references/SETUP.md +32 -213
- package/skills/wix-headless/references/astro/blog/BLOG_PAGES.md +5 -4
- package/skills/wix-headless/references/astro/bookings/COMPONENTS.md +337 -0
- package/skills/wix-headless/references/astro/bookings/SERVICES_PAGES.md +428 -0
- package/skills/wix-headless/references/astro/cms/CMS_FOUNDATIONS.md +5 -5
- package/skills/wix-headless/references/astro/cms/FAQ_KNOWLEDGE_BASE.md +10 -10
- package/skills/wix-headless/references/astro/cms/PORTFOLIO.md +12 -13
- package/skills/wix-headless/references/astro/cms/RESOURCE_LIBRARY.md +10 -12
- package/skills/wix-headless/references/astro/cms/TEAM_DIRECTORY.md +8 -8
- package/skills/wix-headless/references/astro/designer/INSTRUCTIONS.md +50 -27
- package/skills/wix-headless/references/astro/ecom/CART_PAGES.md +7 -8
- package/skills/wix-headless/references/astro/ecom/CART_WIRING.md +5 -5
- package/skills/wix-headless/references/astro/ecom/COMPONENTS_CSS.md +3 -3
- package/skills/wix-headless/references/astro/forms/CONTACT_FORM.md +5 -19
- package/skills/wix-headless/references/astro/gift-cards/COMPONENTS.md +2 -2
- package/skills/wix-headless/references/astro/gift-cards/PAGES.md +1 -1
- package/skills/wix-headless/references/astro/stores/BACK_IN_STOCK.md +6 -6
- package/skills/wix-headless/references/astro/stores/CATEGORY_PAGES.md +4 -4
- package/skills/wix-headless/references/astro/stores/COMPONENTS_CSS.md +3 -3
- package/skills/wix-headless/references/astro/stores/HOME_AND_NAV.md +3 -3
- package/skills/wix-headless/references/astro/stores/PRODUCT_PAGES.md +9 -9
- package/skills/wix-headless/references/astro/stores/SHARED_WIRING.md +5 -4
- package/skills/wix-headless/references/astro/templates/Footer.astro +1 -1
- package/skills/wix-headless/references/astro/templates/Layout.astro +1 -1
- package/skills/wix-headless/references/astro/templates/Navigation.astro +1 -1
- package/skills/wix-headless/references/astro/templates/astro.config.mjs +1 -1
- package/skills/wix-headless/references/astro/templates/bookings/AvailabilityCalendar.tsx +218 -0
- package/skills/wix-headless/references/astro/templates/bookings/BookingForm.tsx +194 -0
- package/skills/wix-headless/references/astro/templates/bookings/ManageBooking.tsx +84 -0
- package/skills/wix-headless/references/astro/templates/bookings/SeoTags.astro +25 -0
- package/skills/wix-headless/references/astro/templates/bookings/ServiceBookingFlow.tsx +50 -0
- package/skills/wix-headless/references/astro/templates/bookings/ServiceCard.astro +45 -0
- package/skills/wix-headless/references/astro/templates/bookings/api/confirm-booking.ts +34 -0
- package/skills/wix-headless/references/astro/templates/bookings/api/waitlist.ts +74 -0
- package/skills/wix-headless/references/astro/templates/bookings/booking-confirmation.astro +111 -0
- package/skills/wix-headless/references/astro/templates/bookings/components-bookings.css +413 -0
- package/skills/wix-headless/references/astro/templates/bookings/manage-booking.astro +76 -0
- package/skills/wix-headless/references/astro/templates/bookings/services/[slug].astro +81 -0
- package/skills/wix-headless/references/astro/templates/bookings/services/index.astro +65 -0
- package/skills/wix-headless/references/astro/templates/global.css +2 -2
- package/skills/wix-headless/references/astro/templates/index.astro +1 -1
- package/skills/wix-headless/references/blog/BLOG_CONTENT.md +19 -9
- package/skills/wix-headless/references/blog/INSTRUCTIONS.md +3 -3
- package/skills/wix-headless/references/bookings/INSTRUCTIONS.md +106 -0
- package/skills/wix-headless/references/bookings/SERVICES_DATA.md +295 -0
- package/skills/wix-headless/references/cms/CMS_FOUNDATIONS.md +4 -2
- package/skills/wix-headless/references/cms/INSTRUCTIONS.md +27 -1
- package/skills/wix-headless/references/commands/known-apps.json +2 -1
- package/skills/wix-headless/references/custom/CONNECTION_PLAN.md +142 -0
- package/skills/wix-headless/references/custom/INSTRUCTIONS.md +71 -21
- package/skills/wix-headless/references/custom/blog/WIRING.md +52 -0
- package/skills/wix-headless/references/custom/bookings/WIRING.md +88 -0
- package/skills/wix-headless/references/custom/cms/WIRING.md +97 -0
- package/skills/wix-headless/references/custom/ecom/WIRING.md +67 -0
- package/skills/wix-headless/references/custom/forms/WIRING.md +101 -0
- package/skills/wix-headless/references/custom/stores/WIRING.md +80 -0
- package/skills/wix-headless/references/ecom/INSTRUCTIONS.md +5 -5
- package/skills/wix-headless/references/forms/INSTRUCTIONS.md +2 -2
- package/skills/wix-headless/references/gift-cards/INSTRUCTIONS.md +3 -3
- package/skills/wix-headless/references/images/INSTRUCTIONS.md +16 -15
- package/skills/wix-headless/references/seed-recipes.md +2 -2
- package/skills/wix-headless/references/shared/AGENTS_MD.md +47 -0
- package/skills/wix-headless/references/shared/AUTHENTICATION.md +3 -5
- package/skills/wix-headless/references/shared/DESIGN_MD.md +85 -0
- package/skills/wix-headless/references/shared/IMAGE_GENERATION.md +29 -28
- package/skills/wix-headless/references/shared/IMPLEMENTER.md +87 -27
- package/skills/wix-headless/references/shared/PRODUCTION_SHARP_EDGES.md +2 -2
- package/skills/wix-headless/references/shared/RETURN_CONTRACT.md +24 -313
- package/skills/wix-headless/references/shared/STYLING.md +8 -18
- package/skills/wix-headless/references/stores/INSTRUCTIONS.md +39 -9
- package/skills/wix-headless/references/stores/PRODUCT_CATALOG_DATA.md +17 -14
- package/skills/wix-headless/references/verticals/_schema.json +1 -1
- package/skills/wix-headless/references/verticals/_schema.md +3 -3
- package/skills/wix-headless/references/verticals/blog.md +1 -1
- package/skills/wix-headless/references/verticals/bookings.md +41 -0
- package/skills/wix-headless/references/verticals/cms.md +1 -1
- package/skills/wix-headless/references/verticals/ecom.md +2 -2
- package/skills/wix-headless/references/verticals/gift-cards.md +1 -1
- package/skills/wix-headless/references/verticals/stores.md +1 -1
- package/skills/wix-headless/scripts/check-manifest.mjs +143 -6
- package/skills/wix-headless/scripts/compose.mjs +540 -0
- package/skills/wix-headless/scripts/emit-design-tokens.mjs +128 -51
- package/skills/wix-headless/scripts/flatten.sh +61 -0
- package/skills/wix-headless/scripts/generate-images.mjs +242 -0
- package/skills/wix-headless/scripts/scaffold.sh +47 -16
- package/skills/wix-headless/scripts/write-decorative-json.mjs +62 -0
- package/skills/wix-manage/SKILL.md +1 -1
- package/skills/wix-manage/references/blog/how-to-create-blog-posts.md +1 -1
- package/skills/wix-manage/references/cms/cms-data-items-crud.md +1 -1
- package/skills/wix-manage/references/cms/cms-references-and-relationships.md +1 -1
- package/skills/wix-manage/references/cms/cms-schema-management.md +1 -1
- package/skills/wix-manage/references/domains/domain-search-and-purchase.md +10 -7
- package/skills/wix-manage/references/forms/create-form.md +49 -1
- package/skills/wix-manage/references/stores/bulk-create-products-with-options.md +1 -1
- package/skills/wix-manage/references/stores/setup-online-store-catalog-v3.md +1 -1
- package/skills/wix-headless/references/astro/COMPOSE.md +0 -142
- package/skills/wix-headless/scripts/finalize-run-json.mjs +0 -141
- package/skills/wix-headless/scripts/init-site-json.mjs +0 -101
- package/skills/wix-headless/scripts/preview.sh +0 -45
- package/skills/wix-headless/scripts/release.sh +0 -73
|
@@ -0,0 +1,62 @@
|
|
|
1
|
+
#!/usr/bin/env node
|
|
2
|
+
// Write the decorative slot→URL map to src/decorative-images.json for a
|
|
3
|
+
// framework-SPA (`own`) frontend. This is the `own`-branch analog of
|
|
4
|
+
// patch-decorative-slots.mjs (which injects <img> into .astro source) — but
|
|
5
|
+
// instead of patching framework source, the generated SPA *imports* this JSON
|
|
6
|
+
// and its hero/about components read it, with a themed-block fallback when a
|
|
7
|
+
// slot is empty/absent. This avoids fragile JSX/Vue/Svelte string-patching and
|
|
8
|
+
// mirrors how the SPA already imports .wix/design-tokens.css.
|
|
9
|
+
//
|
|
10
|
+
// It is called twice in the `own` flow (BUILD-own-build.md):
|
|
11
|
+
// 1. At bootstrap, with EMPTY stdin → writes `{}` (placeholder), so the app
|
|
12
|
+
// builds + renders themed blocks even if Image Phase 1 never runs.
|
|
13
|
+
// 2. At the seed gate (ai-generated only), with Image Phase 1's data.slots
|
|
14
|
+
// piped in → OVERWRITES the file with the real URLs. This MUST happen
|
|
15
|
+
// before `npm run build` (Vite resolves the JSON import at build time).
|
|
16
|
+
//
|
|
17
|
+
// Writes to src/decorative-images.json (inside the Vite root, so it is always
|
|
18
|
+
// importable — unlike .wix/, which may sit outside the bundler root).
|
|
19
|
+
//
|
|
20
|
+
// Usage:
|
|
21
|
+
// echo '{"hero":"https://...","about":"https://..."}' \
|
|
22
|
+
// | node write-decorative-json.mjs <project-dir>
|
|
23
|
+
// : | node write-decorative-json.mjs <project-dir> # placeholder {}
|
|
24
|
+
|
|
25
|
+
import { readFileSync, writeFileSync, mkdirSync } from "node:fs";
|
|
26
|
+
import { join } from "node:path";
|
|
27
|
+
|
|
28
|
+
const projectDir = process.argv[2] ?? process.cwd();
|
|
29
|
+
|
|
30
|
+
let slots = {};
|
|
31
|
+
if (!process.stdin.isTTY) {
|
|
32
|
+
const raw = readFileSync(0, "utf8").trim();
|
|
33
|
+
if (raw) {
|
|
34
|
+
try {
|
|
35
|
+
slots = JSON.parse(raw);
|
|
36
|
+
} catch (e) {
|
|
37
|
+
console.error(JSON.stringify({ status: "error", reason: `stdin is not valid JSON (${e.message})` }));
|
|
38
|
+
process.exit(2);
|
|
39
|
+
}
|
|
40
|
+
if (!slots || typeof slots !== "object" || Array.isArray(slots)) {
|
|
41
|
+
console.error(JSON.stringify({ status: "error", reason: "expected a JSON object mapping slot keys to URLs" }));
|
|
42
|
+
process.exit(2);
|
|
43
|
+
}
|
|
44
|
+
}
|
|
45
|
+
}
|
|
46
|
+
|
|
47
|
+
// Drop empty/falsy URLs so the component's themed-block fallback kicks in.
|
|
48
|
+
const clean = {};
|
|
49
|
+
for (const [k, v] of Object.entries(slots)) {
|
|
50
|
+
if (typeof v === "string" && v.trim()) clean[k] = v.trim();
|
|
51
|
+
}
|
|
52
|
+
|
|
53
|
+
const srcDir = join(projectDir, "src");
|
|
54
|
+
mkdirSync(srcDir, { recursive: true });
|
|
55
|
+
const dest = join(srcDir, "decorative-images.json");
|
|
56
|
+
writeFileSync(dest, JSON.stringify(clean, null, 2) + "\n");
|
|
57
|
+
|
|
58
|
+
console.log(JSON.stringify({
|
|
59
|
+
status: Object.keys(clean).length ? "ok" : "placeholder",
|
|
60
|
+
file: dest,
|
|
61
|
+
slots: Object.keys(clean),
|
|
62
|
+
}, null, 2));
|
|
@@ -6,7 +6,7 @@ compatibility: Requires Wix REST API access (API key or OAuth).
|
|
|
6
6
|
|
|
7
7
|
# Management Recipes Index
|
|
8
8
|
|
|
9
|
-
> **Standard call shape for every curl example across these recipes.** The `<AUTH>` placeholder in example curls is shorthand for the `Authorization` header only;
|
|
9
|
+
> **Standard call shape for every curl example across these recipes.** The `<AUTH>` placeholder in example curls is shorthand for the `Authorization` header only; body-bearing calls also need `Content-Type: application/json`.
|
|
10
10
|
|
|
11
11
|
## What Are Management Recipes?
|
|
12
12
|
|
|
@@ -5,7 +5,7 @@ description: Creates and publishes blog posts using Blog Posts API. Covers Ricos
|
|
|
5
5
|
|
|
6
6
|
**Article: Create and Publish Blog Posts with Rich Content and Images**
|
|
7
7
|
|
|
8
|
-
> **Standard call shape (every curl below).** The `<AUTH>` placeholder is shorthand for `Authorization: Bearer <TOKEN>` only.
|
|
8
|
+
> **Standard call shape (every curl below).** The `<AUTH>` placeholder is shorthand for `Authorization: Bearer <TOKEN>` only. Body-bearing requests also need `Content-Type: application/json`.
|
|
9
9
|
|
|
10
10
|
---
|
|
11
11
|
|
|
@@ -4,7 +4,7 @@ description: "Add, query, update, and delete items in CMS collections. Use this
|
|
|
4
4
|
---
|
|
5
5
|
# CMS Data Items CRUD
|
|
6
6
|
|
|
7
|
-
> **Standard call shape (every curl below).** The `<AUTH>` placeholder is shorthand for `Authorization: Bearer <TOKEN>` only.
|
|
7
|
+
> **Standard call shape (every curl below).** The `<AUTH>` placeholder is shorthand for `Authorization: Bearer <TOKEN>` only. Body-bearing requests also need `Content-Type: application/json`.
|
|
8
8
|
|
|
9
9
|
This recipe covers basic Create, Read, Update, Delete (CRUD) operations for Wix CMS data items.
|
|
10
10
|
|
|
@@ -4,7 +4,7 @@ description: "Add, replace, or remove items from MULTI_REFERENCE fields. Use ins
|
|
|
4
4
|
---
|
|
5
5
|
# CMS References & Relationships
|
|
6
6
|
|
|
7
|
-
> **Standard call shape (every curl below).** The `<AUTH>` placeholder is shorthand for `Authorization: Bearer <TOKEN>` only.
|
|
7
|
+
> **Standard call shape (every curl below).** The `<AUTH>` placeholder is shorthand for `Authorization: Bearer <TOKEN>` only. Body-bearing requests also need `Content-Type: application/json`.
|
|
8
8
|
|
|
9
9
|
This recipe covers linking CMS collections together using reference fields.
|
|
10
10
|
|
|
@@ -4,7 +4,7 @@ description: Create and modify CMS collection structures. Covers listing collect
|
|
|
4
4
|
---
|
|
5
5
|
# CMS Schema Management
|
|
6
6
|
|
|
7
|
-
> **Standard call shape (every curl below).** The `<AUTH>` placeholder is shorthand for `Authorization: Bearer <TOKEN>` only.
|
|
7
|
+
> **Standard call shape (every curl below).** The `<AUTH>` placeholder is shorthand for `Authorization: Bearer <TOKEN>` only. Body-bearing requests also need `Content-Type: application/json`.
|
|
8
8
|
|
|
9
9
|
This recipe covers managing the structure (schema) of Wix CMS collections using the REST API.
|
|
10
10
|
|
|
@@ -218,13 +218,18 @@ Replace `{domain}` with the chosen domain (e.g. `mybakery.com`).
|
|
|
218
218
|
```json
|
|
219
219
|
{
|
|
220
220
|
"domainRegistrationIntent": {
|
|
221
|
-
"registrantContact": {
|
|
221
|
+
"registrantContact": {
|
|
222
|
+
"firstName": "...", "lastName": "...", "email": "...", "phone": "...",
|
|
223
|
+
"streetAddress": "...", "city": "...", "country": "...", "postalCode": "..."
|
|
224
|
+
},
|
|
222
225
|
"adminContact": { ... },
|
|
223
226
|
"techContact": { ... }
|
|
224
227
|
}
|
|
225
228
|
}
|
|
226
229
|
```
|
|
227
230
|
|
|
231
|
+
> Address fields are **flat** on each contact (`streetAddress`, `city`, `country`, `postalCode`) — there is no nested `address` sub-object.
|
|
232
|
+
|
|
228
233
|
- **If contacts exist**: Show the info and explicitly ask "Should I use these details, or would you like to register with different info?" Wait for the user to confirm before proceeding to Step 3. Do NOT skip this confirmation.
|
|
229
234
|
- **If contacts are empty**: Ask the user for: first name, last name, email, phone number, street address, city, country, and postal code. The user can provide country as a full name (e.g. "Israel", "United States") -- convert it to the 2-letter ISO country code (e.g. "IL", "US") before sending to the API. Wait for them to provide all fields before proceeding.
|
|
230
235
|
|
|
@@ -249,12 +254,10 @@ Body:
|
|
|
249
254
|
"lastName": "Smith",
|
|
250
255
|
"email": "john@email.com",
|
|
251
256
|
"phone": "+1.5551234567",
|
|
252
|
-
"
|
|
253
|
-
|
|
254
|
-
|
|
255
|
-
|
|
256
|
-
"postalCode": "10001"
|
|
257
|
-
}
|
|
257
|
+
"streetAddress": "123 Main St",
|
|
258
|
+
"city": "New York",
|
|
259
|
+
"country": "US",
|
|
260
|
+
"postalCode": "10001"
|
|
258
261
|
},
|
|
259
262
|
"adminContact": { ... same as registrant ... },
|
|
260
263
|
"techContact": { ... same as registrant ... }
|
|
@@ -4,7 +4,7 @@ description: Creates a form with fields (name, email, etc.) using the Form Schem
|
|
|
4
4
|
---
|
|
5
5
|
# RECIPE: Create a Wix Form
|
|
6
6
|
|
|
7
|
-
> **Standard call shape (every curl below).** The `<AUTH>` placeholder is shorthand for `Authorization: Bearer <TOKEN>` only.
|
|
7
|
+
> **Standard call shape (every curl below).** The `<AUTH>` placeholder is shorthand for `Authorization: Bearer <TOKEN>` only. Body-bearing requests also need `Content-Type: application/json`.
|
|
8
8
|
|
|
9
9
|
Create a form on a Wix site that appears in the Forms & Submissions dashboard. The form collects visitor information (e.g., name, email) and can automatically upsert contacts on submission.
|
|
10
10
|
|
|
@@ -217,6 +217,7 @@ Verify the form in the dashboard: `https://manage.wix.com/dashboard/{siteId}/for
|
|
|
217
217
|
- **CRITICAL: The `identifier` must be a recognized Wix value.** Custom identifiers like `"product_name"` or `"color_preference"` will cause the field to be silently dropped from the form — no error is thrown. For any generic/custom text field, use `"TEXT_INPUT"` as the identifier and set the display name via the `label` property in `textInputOptions`.
|
|
218
218
|
- For plain text fields, use `"format": "UNKNOWN_FORMAT"`. For email fields, use `"format": "EMAIL"`. For phone fields, use `"format": "PHONE"`. Valid format values: `UNKNOWN_FORMAT`, `DATE`, `TIME`, `DATE_TIME`, `EMAIL`, `URL`, `UUID`, `PHONE`, `URI`, `HOSTNAME`, `COLOR_HEX`, `CURRENCY`, `LANGUAGE`, `DATE_OPTIONAL_TIME`.
|
|
219
219
|
- The submit button is a `DISPLAY` field with `identifier: "SUBMIT_BUTTON"`.
|
|
220
|
+
- **Build the complete form in one call — do not create throwaway "test" forms to probe field shapes.** A site has a **low form cap (~4 forms)**; iterative probing hits the cap (`maximum number of forms reached`), forcing you to `GET` the form list and `DELETE` the test forms before the real create can succeed. Assemble all fields (including any RADIO_GROUP/DROPDOWN per § "Choice fields") and POST once.
|
|
220
221
|
|
|
221
222
|
### Field Types Reference
|
|
222
223
|
|
|
@@ -228,9 +229,54 @@ Verify the form in the dashboard: `https://manage.wix.com/dashboard/{siteId}/for
|
|
|
228
229
|
| `CONTACTS_EMAIL` | `TEXT_INPUT` | `EMAIL` | Contact email |
|
|
229
230
|
| `CONTACTS_PHONE` | `TEXT_INPUT` | `PHONE` | Contact phone |
|
|
230
231
|
| `SUBMIT_BUTTON` | N/A (`DISPLAY` field) | N/A | Submit button |
|
|
232
|
+
| `TEXT_INPUT` | `RADIO_GROUP` | `UNKNOWN_FORMAT` | Single-choice from a fixed list (radio buttons) — see § "Choice fields" |
|
|
233
|
+
| `TEXT_INPUT` | `DROPDOWN` | `UNKNOWN_FORMAT` | Single-choice from a fixed list (dropdown) — same shape as RADIO_GROUP |
|
|
231
234
|
|
|
232
235
|
> **Note:** `LONG_TEXT_INPUT` is not supported as a `componentType` via REST — it throws `INVALID_ARGUMENT`. Use `TEXT_INPUT` for all text fields.
|
|
233
236
|
|
|
237
|
+
### Choice fields (RADIO_GROUP / DROPDOWN)
|
|
238
|
+
|
|
239
|
+
A single-choice field (radio buttons or a dropdown — e.g. an RSVP "Will you attend?") is a **`STRING` input field**, not a separate field type. It uses `identifier: "TEXT_INPUT"`, `inputType: "STRING"`, and sets `componentType` to `RADIO_GROUP` (or `DROPDOWN`) **inside `stringOptions`**. Two things must agree or the field breaks:
|
|
240
|
+
|
|
241
|
+
1. **`stringOptions.validation.enum`** must list every option `value` (an empty `enum` is for free-text only).
|
|
242
|
+
2. **`stringOptions.radioGroupOptions.options[]`** carries the rendered choices — each option needs its own **UUID `id`**, a `value`, and a `label`. (For `DROPDOWN`, use `dropdownOptions` with the same `{id, value, label}` shape.)
|
|
243
|
+
|
|
244
|
+
> **CRITICAL — silent fallback to TEXT_INPUT.** If `radioGroupOptions` is missing/malformed (wrong key like `choices` instead of `options`, an option missing its `id`, or an empty `validation.enum`), the API does **not** error — it silently creates the field as a plain `TEXT_INPUT`. If a choice field renders as a text box, this is why. Build it correctly on the first call; do not probe.
|
|
245
|
+
|
|
246
|
+
```json
|
|
247
|
+
{
|
|
248
|
+
"id": "a1b2c3d4-1002-4e00-8001-000000000002",
|
|
249
|
+
"hidden": false,
|
|
250
|
+
"identifier": "TEXT_INPUT",
|
|
251
|
+
"fieldType": "INPUT",
|
|
252
|
+
"inputOptions": {
|
|
253
|
+
"target": "attending_0002",
|
|
254
|
+
"pii": false,
|
|
255
|
+
"required": true,
|
|
256
|
+
"inputType": "STRING",
|
|
257
|
+
"readOnly": false,
|
|
258
|
+
"stringOptions": {
|
|
259
|
+
"validation": {
|
|
260
|
+
"format": "UNKNOWN_FORMAT",
|
|
261
|
+
"enum": ["Joyfully accepts", "Regretfully declines"]
|
|
262
|
+
},
|
|
263
|
+
"componentType": "RADIO_GROUP",
|
|
264
|
+
"radioGroupOptions": {
|
|
265
|
+
"label": "Will you attend?",
|
|
266
|
+
"showLabel": true,
|
|
267
|
+
"numberOfColumns": "ONE",
|
|
268
|
+
"options": [
|
|
269
|
+
{ "id": "c3d4e5f6-3001-4a00-8001-000000000001", "value": "Joyfully accepts", "label": "Joyfully accepts" },
|
|
270
|
+
{ "id": "c3d4e5f6-3001-4a00-8001-000000000002", "value": "Regretfully declines", "label": "Regretfully declines" }
|
|
271
|
+
]
|
|
272
|
+
}
|
|
273
|
+
}
|
|
274
|
+
}
|
|
275
|
+
}
|
|
276
|
+
```
|
|
277
|
+
|
|
278
|
+
`numberOfColumns` is a string enum (`"ONE"`, `"TWO"`, `"THREE"`) controlling the radio layout — omit it and the field still works (defaults to one column).
|
|
279
|
+
|
|
234
280
|
### Layout
|
|
235
281
|
|
|
236
282
|
The `steps[].layout.large.items` array controls how fields are positioned:
|
|
@@ -252,6 +298,8 @@ The Wix Forms app (appDefId: `14ce1214-b278-a7e4-1373-00cebd1bef7c`) must be ins
|
|
|
252
298
|
|---|---|---|
|
|
253
299
|
| `Unrecognized value passed for enum` | Invalid `componentType` value (e.g., `LONG_TEXT_INPUT`) | Use only `componentType` values from the schema: `TEXT_INPUT`, `RADIO_GROUP`, `DROPDOWN`, `DATE_TIME`, `PHONE_INPUT`, `DATE_INPUT`, `TIME_INPUT`, `DATE_PICKER`, `PASSWORD` |
|
|
254
300
|
| Field silently missing from created form | Custom `identifier` value (e.g., `"product_name"`) | Use a recognized identifier like `TEXT_INPUT` and set display name via `label` |
|
|
301
|
+
| Choice field rendered as a plain text box | `radioGroupOptions`/`dropdownOptions` malformed (wrong key, option missing `id`, empty `validation.enum`) — API silently falls back to `TEXT_INPUT` | Match the § "Choice fields" shape exactly: `componentType` in `stringOptions`, `options[]` each with a UUID `id`, and `validation.enum` listing all option values |
|
|
302
|
+
| `maximum number of forms reached` / form-cap error | Sites cap at ~4 forms; reached by creating throwaway test forms | `GET form-schema-service/v4/forms` then `DELETE` the unwanted forms; build the real form in one call (don't probe) |
|
|
255
303
|
| `Permissions for given namespace not found` | `wix.form_app.form` namespace not active | Ensure the Wix Forms app is installed; try creating a form through the UI first to activate the namespace |
|
|
256
304
|
| `missing installed app` | Wix Forms app not installed | Install app `14ce1214-b278-a7e4-1373-00cebd1bef7c` via the [Install Wix Apps](../app-installation/install-wix-apps.md) recipe |
|
|
257
305
|
|
|
@@ -4,7 +4,7 @@ description: Uses bulk products endpoint to create multiple products with invent
|
|
|
4
4
|
---
|
|
5
5
|
# RECIPE: Business Recipe - Bulk Creating Wix Store Products with inventory and options
|
|
6
6
|
|
|
7
|
-
> **Standard call shape (every curl below).** The `<AUTH>` placeholder is shorthand for `Authorization: Bearer <TOKEN>` only.
|
|
7
|
+
> **Standard call shape (every curl below).** The `<AUTH>` placeholder is shorthand for `Authorization: Bearer <TOKEN>` only. Body-bearing requests also need `Content-Type: application/json`.
|
|
8
8
|
|
|
9
9
|
Learn how to create multiple Wix store products with customizable options like colors, sizes, or other variants in a single bulk operation, allowing efficient creation of product catalogs.
|
|
10
10
|
|
|
@@ -4,7 +4,7 @@ description: Initializes a Stores catalog with Catalog V3 Products API, bulk pro
|
|
|
4
4
|
---
|
|
5
5
|
**RECIPE**: Business Recipe – Initial Setup for a Wix Online Store (Catalog V3)
|
|
6
6
|
|
|
7
|
-
> **Standard call shape (every curl below).** The `<AUTH>` placeholder is shorthand for `Authorization: Bearer <TOKEN>` only.
|
|
7
|
+
> **Standard call shape (every curl below).** The `<AUTH>` placeholder is shorthand for `Authorization: Bearer <TOKEN>` only. Body-bearing requests also need `Content-Type: application/json`.
|
|
8
8
|
|
|
9
9
|
A concise checklist for preparing any new Wix site that uses the Online Stores app with Catalog V3.
|
|
10
10
|
**Notice** that this recipe is **NOT** meant for coding purposes and is **ONLY** meant for initial catalog setup.
|
|
@@ -1,142 +0,0 @@
|
|
|
1
|
-
---
|
|
2
|
-
name: design-system-composer
|
|
3
|
-
description: "The Composer role of the wix-headless design-system phase. Applies the Designer's framework-agnostic design spec to the astro frontend by SUBSTITUTING into pinned skeletons at references/astro/templates/ — it does not re-author the fixed bulk. Maps semantic token values to the @theme vocabulary, writes the 6 design-system files (global.css, astro.config.mjs, Layout.astro, Navigation.astro, Footer.astro, index.astro), and owns the component-CSS token contract (every var(--token) a components-<pack>.css references must resolve). Returns a manifest."
|
|
4
|
-
---
|
|
5
|
-
|
|
6
|
-
# Composer — how the design becomes code
|
|
7
|
-
|
|
8
|
-
You are the **Composer**. The Designer already decided *what the brand looks like* and returned it as a framework-agnostic spec. Your job is *how that becomes code* for the **astro** frontend: you map the spec onto the framework's token vocabulary and **substitute it into pinned skeletons**. You do **not** re-author the fixed bulk — the View-Transitions script, the view-transition / `.nav-progress` CSS, the `@utility btn` family, the `process.env` fix, the markers — all of that is literal in the skeletons. Read a skeleton, fill its `{{…}}` slots, write the file. Substitute; do not re-write.
|
|
9
|
-
|
|
10
|
-
This is deterministic work against pinned templates, so it is fast and low-variance. The whole reason the rewrite-from-scratch failure mode (which roughly doubled the old design-system wall) is gone is that you never regenerate the bulk.
|
|
11
|
-
|
|
12
|
-
> **Framework:** astro only. The skeletons live at `<SKILL_ROOT>/references/astro/templates/`. Custom (non-astro) frontends never reach the Composer — they route to the not-available-yet stub (`references/custom/INSTRUCTIONS.md`) before the build flow runs. If your prompt ever names a non-astro frontend, return `status: "failed"` with `errors: [{code: "FRONTEND_NOT_SUPPORTED"}]` — do not improvise a second framework.
|
|
13
|
-
|
|
14
|
-
## Self-Loading
|
|
15
|
-
|
|
16
|
-
1. Read `<SKILL_ROOT>/references/shared/RETURN_CONTRACT.md` — structured-return format.
|
|
17
|
-
2. Read `<SKILL_ROOT>/references/shared/STYLING.md` — the three styling categories and, in particular, § "Required tokens — the component-CSS template contract" (the token set you must guarantee). You own that contract now.
|
|
18
|
-
|
|
19
|
-
No REST calls, no MCP — this is frontend-only work.
|
|
20
|
-
|
|
21
|
-
**Do NOT `Read .wix/site.json`.** Every input is inlined in your prompt.
|
|
22
|
-
|
|
23
|
-
## Inputs (entirely from your prompt)
|
|
24
|
-
|
|
25
|
-
- **`designTokens`** — the Designer's spec (`colors`, `fonts`, `spacing`, `radii`, `containers`), bare-key form.
|
|
26
|
-
- **`shell`** — brand-voice strings: `heroHeadline`, `heroSub`, `footerTagline`, `navBrandMark`.
|
|
27
|
-
- **Brand** — `{ name, description }`.
|
|
28
|
-
- **Navigation links** — JSON array of `{href, label}`. Use labels **verbatim**.
|
|
29
|
-
- **Loaded packs**, **Packs with components**, **Disabled packs** — comma-joined lists.
|
|
30
|
-
- **Project directory** — the scaffold subdir (CWD).
|
|
31
|
-
|
|
32
|
-
## What you write (the 6 files)
|
|
33
|
-
|
|
34
|
-
Read each skeleton from `<SKILL_ROOT>/references/astro/templates/`, substitute, write to the project. The fixed bulk in every skeleton is literal — change only the documented `{{…}}` slots.
|
|
35
|
-
|
|
36
|
-
> **Read skeletons by file, never the directory (`EISDIR`).** `Read <SKILL_ROOT>/references/astro/templates/` fails with `EISDIR: illegal operation on a directory` and costs a wasted recovery round-trip. Read each of the six by its exact path: `<SKILL_ROOT>/references/astro/templates/global.css`, `…/astro.config.mjs`, `…/Layout.astro`, `…/Navigation.astro`, `…/Footer.astro`, `…/index.astro` (issue the six `Read`s as one concurrent batch). If you must discover them first, `Glob` the directory (`…/templates/*`) — never `Read` it.
|
|
37
|
-
|
|
38
|
-
**Pre-write: scaffold may still be in flight.** A scaffold file you need (`Layout.astro` stub, `astro.config.mjs`) may not yet be present. Before reading one, if a `Read` returns "file does not exist", wait 5 s and retry, cap 6 attempts (~30 s). The 6-attempt cap is hard — do not check a 7th time; return `status: "failed"` with `errors: [{code: "SCAFFOLD_NOT_COMPLETE"}]` immediately on attempt 6's miss. (Reading the *skeletons* under `<SKILL_ROOT>` never needs this — they are always present.)
|
|
39
|
-
|
|
40
|
-
**Read each destination before you overwrite it.** The scaffold ships stubs for several of your six targets (today: `src/layouts/Layout.astro`, `src/pages/index.astro`, `astro.config.mjs`). The harness **blocks a `Write` to an existing file you have not `Read` this run** (`File has not been read yet`). So your batched reads must include the *destination* project paths for any file the scaffold created — not only the `<SKILL_ROOT>` skeletons. Practically: in the same concurrent batch, `Read` both the skeleton and the destination for `Layout.astro`, `index.astro`, and `astro.config.mjs` (the latter you read anyway to merge); `global.css`, `Navigation.astro`, and `Footer.astro` are net-new, so a destination read isn't required (but is harmless if the scaffold happens to ship them).
|
|
41
|
-
|
|
42
|
-
### Token contract (do this first — it gates everything)
|
|
43
|
-
|
|
44
|
-
Map the Designer's `designTokens` into the `@theme` palette that goes in `global.css`, and **guarantee every required token resolves**. Per `STYLING.md` § "Required tokens", the `components-<pack>.css` templates reference a fixed set via `var(--token)`. Your `@theme` MUST declare all of:
|
|
45
|
-
|
|
46
|
-
- `--color-{paper,paper-warm,ink,mute,rule,accent}` (required), `--color-{ink-soft,cream,error}` (recommended).
|
|
47
|
-
- `--font-{display,body}`.
|
|
48
|
-
- the full `--spacing-{2xs,xs,sm,md,lg,xl,2xl,3xl,4xl}` scale.
|
|
49
|
-
- `--radius-{sm,md}` (required), `--radius-{lg,xl}` (recommended).
|
|
50
|
-
- a **container scale** separate from spacing: `--container-{prose,md,3xl,6xl}` minimum.
|
|
51
|
-
|
|
52
|
-
If the Designer's spec is missing a required role, **derive** a sensible value (e.g. `ink-soft` ≈ `ink` lightened, `paper-warm` ≈ `paper` warmed) rather than dropping the token — a missing required token renders components unstyled. Map each group with the fixed prefix: `colors.<k>` → `--color-<k>`, `fonts.<k>` → `--font-<k>`, `spacing.<k>` → `--spacing-<k>`, `radii.<k>` → `--radius-<k>`, `containers.<k>` → `--container-<k>`.
|
|
53
|
-
|
|
54
|
-
> **Container ≠ spacing.** Tailwind v4 maps `max-w-3xl` → `var(--container-3xl)`, not `var(--spacing-3xl)`. Never set a `--container-*` to a spacing value — a reading column is ~`42rem`, not `5rem`, or pages collapse to one word per line.
|
|
55
|
-
|
|
56
|
-
### 1. `global.css`
|
|
57
|
-
|
|
58
|
-
Substitute the `{{theme}}` block in the skeleton with the `@theme` palette you built above — every `--color-*`, `--font-*`, `--spacing-*`, `--container-*`, `--radius-*` line. **Everything else in the skeleton is literal** (the `@utility container-reading`/`btn`, base layer, button family, decorative + site-shell + view-transition + nav-submenu + category-rail CSS). Do not add component-specific classes (`.product-card`, `.cart-summary`, …) — those live in `components-<pack>.css`, owned by Phase 3.
|
|
59
|
-
|
|
60
|
-
### 2. `astro.config.mjs`
|
|
61
|
-
|
|
62
|
-
This is a **merge, not a clobber** — the scaffold's config varies. Read the scaffold's `astro.config.mjs` and apply exactly two mutations (the skeleton shows the target shape):
|
|
63
|
-
1. Register the Tailwind v4 Vite plugin: `import tailwindcss from "@tailwindcss/vite";` and merge `tailwindcss()` into `vite.plugins` (preserve any existing `vite` settings — `server.allowedHosts`, etc.).
|
|
64
|
-
2. Fix the bare `process.env` line (`const isBuild = process.env.NODE_ENV == "production";`) to the `globalThis` guard so strict `tsc --noEmit` passes without `@types/node`.
|
|
65
|
-
|
|
66
|
-
### 3. `Layout.astro`
|
|
67
|
-
|
|
68
|
-
Fully replace the scaffold stub. Substitute:
|
|
69
|
-
- `{{components-css-imports}}` — one `import '../styles/components-<pack>.css';` per pack in **"Packs with components"**, in that order. Packs without components (e.g. `cms`) get **no** import — importing a file no agent writes breaks the build. If "Packs with components" is empty, remove the placeholder line entirely.
|
|
70
|
-
- `{{fonts.googleHref}}` — the Google Fonts stylesheet href for the chosen `display` + `body` families (e.g. `https://fonts.googleapis.com/css2?family=Fraunces:ital,opsz,wght@...&family=Inter:wght@400;500;600&display=swap`). If both fonts are system fonts, remove the `<link rel="stylesheet">` line.
|
|
71
|
-
- `{{brand.name}}` — the default `<title>`.
|
|
72
|
-
|
|
73
|
-
The View-Transitions `<script>`, the `nav-progress` div, the `ClientRouter`, the `Props` interface, and the `hasSeoTags` pattern are **literal** — keep them.
|
|
74
|
-
|
|
75
|
-
### 4. `Navigation.astro`
|
|
76
|
-
|
|
77
|
-
Substitute `{{shell.navBrandMark}}` and `{{nav.links}}` (one `<li class="site-nav-item"><a href={href}>{label}</a></li>` per inlined nav link, labels **verbatim** — no editorial rebrands like "Journal" for `/about`). Keep the `<!-- nav:links -->` marker, the empty `<div class="nav-actions">`, the `transition:persist`, and the hamburger literal. Do **not** add `/products`, cart, login, or account links — packs splice those at the marker in Phase 4.
|
|
78
|
-
|
|
79
|
-
### 5. `Footer.astro`
|
|
80
|
-
|
|
81
|
-
Substitute `{{brand.name}}`, `{{shell.footerTagline}}`, and `{{nav.links}}` (mirror/subset of the same array, labels verbatim). Keep `transition:persist` literal.
|
|
82
|
-
|
|
83
|
-
### 6. `index.astro`
|
|
84
|
-
|
|
85
|
-
Substitute `{{shell.heroHeadline}}`, `{{shell.heroSub}}`, `{{brand.name}}`, and `{{home-markers}}`. For `{{home-markers}}`, emit one `<!-- home:<pack> -->` marker per **loaded pack that contributes a home section** (today: `stores`, `gift-cards`). Emit a marker **only** for such packs — never one no pack will fill (no `<!-- home:cms -->`; CMS owns brand-story directly, which the skeleton already renders). Keep the hero + brand-story structure and both `data-decorative-slot` placeholders literal and **empty** (the orchestrator injects `<img>` after Image Phase 1).
|
|
86
|
-
|
|
87
|
-
## Disabled-pack discipline
|
|
88
|
-
|
|
89
|
-
A pack in **"Disabled packs"** (today: only `gift-cards`) ships dormant. Its `<!-- home:<pack> -->` / `<!-- nav:links -->` markers are the **only** acceptable touchpoints. Do **not** add hero CTAs, footer links, brand-story callouts, or any other entry point pointing at a disabled pack's route — users click through to a feature that does not exist yet. Treat disabled packs as code-only: they appear in your marker emission, never in visible UI you author.
|
|
90
|
-
|
|
91
|
-
## Self-checks before returning
|
|
92
|
-
|
|
93
|
-
1. **Component-CSS imports.** For every pack in "Packs with components", grep your written `Layout.astro` for `components-<pack>.css`. If any is missing, add it. If unrecoverable, return `status: "partial"` with `errors: [{code: "MISSING_COMPONENT_CSS_IMPORT", pack: "<name>"}]`. (The orchestrator also re-verifies this after you return — at the seed gate — but catch it here.)
|
|
94
|
-
2. **Required-token coverage.** Confirm every required token from the contract above is present in the `@theme` block you wrote. A missing one renders components unstyled.
|
|
95
|
-
3. **Container vs spacing.** Confirm no `--container-*` was set to a spacing value.
|
|
96
|
-
4. **Marker hygiene.** No marker emitted for a pack that does not contribute; both decorative slots present and empty.
|
|
97
|
-
|
|
98
|
-
If a check fails and you cannot fix it, return `status: "partial"` with the specific `errors` code rather than shipping silently.
|
|
99
|
-
|
|
100
|
-
## Return contract
|
|
101
|
-
|
|
102
|
-
A single fenced JSON block per `<SKILL_ROOT>/references/shared/RETURN_CONTRACT.md`, last content in your message — a manifest of what you wrote:
|
|
103
|
-
|
|
104
|
-
```json
|
|
105
|
-
{
|
|
106
|
-
"status": "complete",
|
|
107
|
-
"phase": "compose",
|
|
108
|
-
"data": {
|
|
109
|
-
"filesWritten": [
|
|
110
|
-
"src/styles/global.css",
|
|
111
|
-
"astro.config.mjs",
|
|
112
|
-
"src/layouts/Layout.astro",
|
|
113
|
-
"src/components/Navigation.astro",
|
|
114
|
-
"src/components/Footer.astro",
|
|
115
|
-
"src/pages/index.astro"
|
|
116
|
-
],
|
|
117
|
-
"componentCssImports": ["stores", "ecom"],
|
|
118
|
-
"homeMarkers": ["home:stores"],
|
|
119
|
-
"tokensApplied": { "colors": 9, "spacing": 9, "containers": 4, "radii": 2, "fonts": 2 }
|
|
120
|
-
},
|
|
121
|
-
"files": [ "...same as filesWritten..." ]
|
|
122
|
-
}
|
|
123
|
-
```
|
|
124
|
-
|
|
125
|
-
No trailing prose after the closing fence.
|
|
126
|
-
|
|
127
|
-
## Anti-patterns
|
|
128
|
-
|
|
129
|
-
| WRONG | CORRECT |
|
|
130
|
-
|---|---|
|
|
131
|
-
| Re-author the View-Transitions script, btn family, or view-transition CSS | Keep the skeleton bulk literal; substitute only `{{…}}` slots |
|
|
132
|
-
| Rewrite `global.css` from scratch to "clean it up" | Substitute `{{theme}}`; the rest is pinned (this is the variance win) |
|
|
133
|
-
| Overwrite `astro.config.mjs` with the skeleton verbatim | Merge the two mutations into the scaffold's own config |
|
|
134
|
-
| `import '../styles/components-cms.css'` (cms has no components) | One import only per pack in "Packs with components" |
|
|
135
|
-
| Drop a required token because the Designer omitted it | Derive a sensible value — required tokens must resolve |
|
|
136
|
-
| Set `--container-3xl` to `--spacing-3xl`'s value | Containers are widths (~`42rem`+), a separate axis from spacing |
|
|
137
|
-
| Coin label rebrands ("Journal" → /about) or add `/products`/cart links | Nav labels verbatim; packs splice their links at the marker |
|
|
138
|
-
| Add a hero CTA / footer link to a disabled-pack route | Disabled packs are code-only — markers are the sole touchpoint |
|
|
139
|
-
| Emit `<!-- home:cms -->` or a marker for a non-contributing pack | One marker per contributing loaded pack only |
|
|
140
|
-
| `Read <SKILL_ROOT>/references/astro/templates/` (the directory) | `EISDIR` — Read each of the six skeletons by its exact file path (batch the six Reads); `Glob` if you must discover them |
|
|
141
|
-
| `Read .wix/site.json` for brand/tokens | Every input is inlined in your prompt |
|
|
142
|
-
| Branch to a non-astro / custom frontend | astro only; return `FRONTEND_NOT_SUPPORTED` otherwise |
|
|
@@ -1,141 +0,0 @@
|
|
|
1
|
-
#!/usr/bin/env node
|
|
2
|
-
// Finalize and write .wix/run.json at the end of the build.
|
|
3
|
-
//
|
|
4
|
-
// The orchestrator collects agent returns, timings, and outcome data over the
|
|
5
|
-
// run. This script takes the orchestrator's draft as a JSON blob via stdin,
|
|
6
|
-
// runs the timing-completeness gate (every required phase MUST have non-null
|
|
7
|
-
// seconds, otherwise emit MISSING_TIMING errors), computes totalSeconds from
|
|
8
|
-
// started/ended, writes the canonical .wix/run.json, and prints the perf
|
|
9
|
-
// one-liner the orchestrator shows in the final message.
|
|
10
|
-
//
|
|
11
|
-
// Usage:
|
|
12
|
-
// echo "$DRAFT_JSON" | node finalize-run-json.mjs <project-dir>
|
|
13
|
-
//
|
|
14
|
-
// Input shape (via stdin):
|
|
15
|
-
// {
|
|
16
|
-
// "run": { started, ended, brand, prompt, verticals, packs },
|
|
17
|
-
// "outcome": { build, previewUrl, dashboardUrl, ... },
|
|
18
|
-
// "phases": [ { phase, status, seconds, data?, errors? }, ... ],
|
|
19
|
-
// "recoveries": [ ... ], // optional; from manifest-check script outputs
|
|
20
|
-
// "errors": [ ... ], // optional; from agent returns / orchestrator
|
|
21
|
-
// "notes": [ ... ], // optional
|
|
22
|
-
// "requiredPhases": ["scaffold","app-install-Wix Stores","env-pull",...]
|
|
23
|
-
// }
|
|
24
|
-
//
|
|
25
|
-
// `requiredPhases` is the orchestrator's set of skill-invoked phases that MUST
|
|
26
|
-
// have a captured duration (scaffold, every app-install-*, env-pull,
|
|
27
|
-
// seed-utilities, npm-install, build, release|preview, etc.). The set is
|
|
28
|
-
// run-specific (number of app-install-* depends on loaded packs), so the
|
|
29
|
-
// orchestrator passes it in rather than the script guessing.
|
|
30
|
-
//
|
|
31
|
-
// Output:
|
|
32
|
-
// - Writes .wix/run.json (full shape, with timing-completeness gate applied).
|
|
33
|
-
// - Prints to stdout: a JSON object with { perfLine, missingTiming, totalSeconds }.
|
|
34
|
-
|
|
35
|
-
import { writeFileSync, mkdirSync, readFileSync } from "node:fs";
|
|
36
|
-
import { join } from "node:path";
|
|
37
|
-
|
|
38
|
-
const projectDir = process.argv[2];
|
|
39
|
-
|
|
40
|
-
if (!projectDir) {
|
|
41
|
-
console.error("usage: cat draft.json | finalize-run-json.mjs <project-dir>");
|
|
42
|
-
process.exit(2);
|
|
43
|
-
}
|
|
44
|
-
|
|
45
|
-
let draft;
|
|
46
|
-
try {
|
|
47
|
-
draft = JSON.parse(readFileSync(0, "utf8"));
|
|
48
|
-
} catch (e) {
|
|
49
|
-
console.error(`finalize-run-json: stdin is not valid JSON (${e.message})`);
|
|
50
|
-
process.exit(2);
|
|
51
|
-
}
|
|
52
|
-
|
|
53
|
-
const run = draft.run ?? {};
|
|
54
|
-
const phases = Array.isArray(draft.phases) ? [...draft.phases] : [];
|
|
55
|
-
const errors = Array.isArray(draft.errors) ? [...draft.errors] : [];
|
|
56
|
-
const recoveries = Array.isArray(draft.recoveries) ? draft.recoveries : [];
|
|
57
|
-
const notes = Array.isArray(draft.notes) ? draft.notes : [];
|
|
58
|
-
const outcome = draft.outcome ?? {};
|
|
59
|
-
const requiredPhases = Array.isArray(draft.requiredPhases) ? draft.requiredPhases : [];
|
|
60
|
-
|
|
61
|
-
// ---- 1. Timing completeness gate ------------------------------------------
|
|
62
|
-
const phasesByName = new Map();
|
|
63
|
-
for (const p of phases) {
|
|
64
|
-
phasesByName.set(p.phase, p);
|
|
65
|
-
}
|
|
66
|
-
|
|
67
|
-
const missingTiming = [];
|
|
68
|
-
|
|
69
|
-
for (const required of requiredPhases) {
|
|
70
|
-
const existing = phasesByName.get(required);
|
|
71
|
-
if (!existing) {
|
|
72
|
-
// Missing entry entirely.
|
|
73
|
-
const entry = { phase: required, status: "unknown", seconds: null };
|
|
74
|
-
phases.push(entry);
|
|
75
|
-
phasesByName.set(required, entry);
|
|
76
|
-
errors.push({ code: "MISSING_TIMING", phase: required });
|
|
77
|
-
missingTiming.push(required);
|
|
78
|
-
} else if (existing.seconds === null || existing.seconds === undefined) {
|
|
79
|
-
existing.seconds = null;
|
|
80
|
-
if (!errors.some((e) => e.code === "MISSING_TIMING" && e.phase === required)) {
|
|
81
|
-
errors.push({ code: "MISSING_TIMING", phase: required });
|
|
82
|
-
}
|
|
83
|
-
missingTiming.push(required);
|
|
84
|
-
}
|
|
85
|
-
}
|
|
86
|
-
|
|
87
|
-
// ---- 2. totalSeconds derivation -------------------------------------------
|
|
88
|
-
if (!run.totalSeconds && run.started && run.ended) {
|
|
89
|
-
const started = Date.parse(run.started);
|
|
90
|
-
const ended = Date.parse(run.ended);
|
|
91
|
-
if (!Number.isNaN(started) && !Number.isNaN(ended) && ended >= started) {
|
|
92
|
-
run.totalSeconds = Math.round((ended - started) / 1000);
|
|
93
|
-
}
|
|
94
|
-
}
|
|
95
|
-
|
|
96
|
-
// ---- 3. Compose final shape -----------------------------------------------
|
|
97
|
-
const final = {
|
|
98
|
-
version: "1.0",
|
|
99
|
-
run,
|
|
100
|
-
outcome,
|
|
101
|
-
phases,
|
|
102
|
-
...(recoveries.length > 0 ? { recoveries } : {}),
|
|
103
|
-
...(errors.length > 0 ? { errors } : {}),
|
|
104
|
-
...(notes.length > 0 ? { notes } : { notes: [] }),
|
|
105
|
-
};
|
|
106
|
-
|
|
107
|
-
const wixDir = join(projectDir, ".wix");
|
|
108
|
-
mkdirSync(wixDir, { recursive: true });
|
|
109
|
-
const runJsonPath = join(wixDir, "run.json");
|
|
110
|
-
writeFileSync(runJsonPath, JSON.stringify(final, null, 2) + "\n");
|
|
111
|
-
|
|
112
|
-
// ---- 4. Perf one-liner ----------------------------------------------------
|
|
113
|
-
// Format: "Built in <Nm Ss> — design-system <n>s · images (phase 1 + phase 2) <n>s · build+release <n>s"
|
|
114
|
-
const fmtSeconds = (sec) => (sec === null || sec === undefined ? "–" : `${sec}s`);
|
|
115
|
-
const fmtTotal = (sec) => {
|
|
116
|
-
if (sec === null || sec === undefined) return "–";
|
|
117
|
-
const m = Math.floor(sec / 60);
|
|
118
|
-
const s = sec % 60;
|
|
119
|
-
return `${m}m ${s}s`;
|
|
120
|
-
};
|
|
121
|
-
const phaseSeconds = (name) => {
|
|
122
|
-
const p = phasesByName.get(name);
|
|
123
|
-
return p && p.seconds !== null && p.seconds !== undefined ? p.seconds : null;
|
|
124
|
-
};
|
|
125
|
-
const designSystem = phaseSeconds("design-system");
|
|
126
|
-
const img1 = phaseSeconds("image-phase-1-decorative");
|
|
127
|
-
const img2 = phaseSeconds("image-phase-2-entity");
|
|
128
|
-
const imgTotal = img1 !== null && img2 !== null ? img1 + img2 : null;
|
|
129
|
-
const build = phaseSeconds("build");
|
|
130
|
-
const release = phaseSeconds("release") ?? phaseSeconds("preview");
|
|
131
|
-
const buildPlusRelease = build !== null && release !== null ? build + release : null;
|
|
132
|
-
|
|
133
|
-
const perfLine = `Built in ${fmtTotal(run.totalSeconds)} — design-system ${fmtSeconds(designSystem)} · images (phase 1 + phase 2) ${fmtSeconds(imgTotal)} · build+release ${fmtSeconds(buildPlusRelease)}`;
|
|
134
|
-
|
|
135
|
-
console.log(JSON.stringify({
|
|
136
|
-
status: missingTiming.length > 0 ? "partial" : "ok",
|
|
137
|
-
path: runJsonPath,
|
|
138
|
-
totalSeconds: run.totalSeconds ?? null,
|
|
139
|
-
missingTiming,
|
|
140
|
-
perfLine,
|
|
141
|
-
}, null, 2));
|