@wix/agent-skills 1.19.0 → 1.19.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.
- package/package.json +1 -1
- package/skills/wix-app/SKILL.md +33 -31
- package/skills/wix-app/references/DASHBOARD_PAGE.md +6 -10
- package/skills/wix-app/references/EDITOR_REACT_COMPONENT.md +17 -8
- package/skills/wix-app/references/WIX_PATTERNS_DOCS.md +53 -131
- package/skills/wix-app/references/dashboard-page/UX_SUCCESS_MODEL.md +1 -2
- package/skills/wix-app/references/editor-react-component/ACCESSIBILITY.md +88 -73
- package/skills/wix-app/references/editor-react-component/ANIMATED-COMPONENTS.md +46 -22
- package/skills/wix-app/references/editor-react-component/COMPONENT-CONTRACT.md +20 -6
- package/skills/wix-app/references/editor-react-component/CSS-GUIDELINES.md +9 -0
- package/skills/wix-app/references/editor-react-component/FUNCTION-HANDLERS.md +71 -31
- package/skills/wix-app/references/editor-react-component/PARTS.md +5 -2
- package/skills/wix-app/references/editor-react-component/REACT-GUIDELINES.md +4 -5
- package/skills/wix-app/scripts/pkg-root.cjs +73 -0
- package/skills/wix-app/scripts/scan-a11y-code.cjs +310 -40
- package/skills/wix-app/scripts/scan-a11y-eslint.cjs +118 -24
- package/skills/wix-app/scripts/scan-a11y-render.cjs +551 -0
- package/skills/wix-app/scripts/scan-a11y-review.cjs +373 -0
- package/skills/wix-base44-connector/SKILL.md +67 -43
- package/skills/wix-base44-connector/scripts/utils.cjs +39 -3
- package/skills/wix-docs/SKILL.md +47 -20
- package/skills/wix-headless/SKILL.md +1 -0
- package/skills/wix-headless/entry/bootstrap.mjs +106 -50
- package/skills/wix-headless/entry/skill.md +5 -3
- package/skills/wix-headless/references/CAPABILITIES.md +7 -2
- package/skills/wix-headless/references/SDK_HANDOFF.md +2 -1
- package/skills/wix-headless/references/inline-recipes/experience-store.md +48 -0
- package/skills/wix-headless/references/inline-recipes/how-to-code-a-store.md +350 -114
- package/skills/wix-headless/references/inline-recipes/how-to-code-members-astro.md +1 -1
- package/skills/wix-headless/references/managed/AUTHENTICATION.md +25 -5
- package/skills/wix-headless/references/managed/CREATE.md +5 -0
- package/skills/wix-headless-fast/SKILL.md +25 -7
- package/skills/wix-headless-fast/entry/skill.md +23 -14
- package/skills/wix-headless-fast/install/fast-path.mjs +48 -5
- package/skills/wix-headless-fast/install/pin-agents-md.mjs +57 -0
- package/skills/wix-headless-fast/references/shared/CUSTOM_OPERATIONS.md +3 -3
- package/skills/wix-headless-fast/references/storefront/INSTRUCTIONS.md +204 -35
- package/skills/wix-headless-fast/references/storefront/app/hooks/storefront/useShop.ts +146 -36
- package/skills/wix-headless-fast/references/storefront/app/wix/storefront/cart-store.ts +8 -2
- package/skills/wix-headless-fast/references/storefront/app/wix/storefront/catalog.ts +95 -20
- package/skills/wix-headless-fast/references/storefront/seed/SEED.md +21 -2
- package/skills/wix-headless-fast/references/storefront/seed/seed-store.mjs +104 -18
- package/skills/wix-manage/SKILL.md +16 -10
- package/skills/wix-manage/references/bookings/create-and-update-booking-services.md +4 -1
- package/skills/wix-manage/references/bookings/create-appointment-service.md +3 -1
- package/skills/wix-manage/references/bookings/create-class-service.md +3 -1
- package/skills/wix-manage/references/bookings/create-course-service.md +4 -2
- package/skills/wix-manage/references/bookings/end-to-end-booking-flow.md +68 -3
- package/skills/wix-manage/references/ecommerce/pricing-promotions/ecom-pricing-flow-seasonal-promotion.md +1 -1
- package/skills/wix-manage/references/google-ads/billing-and-payment.md +3 -3
- package/skills/wix-manage/references/google-ads/create-performance-max-campaign.md +8 -8
- package/skills/wix-manage/references/google-ads/get-campaign-suggestions.md +4 -4
- package/skills/wix-manage/references/google-ads/google-ads-dashboard-navigation.md +1 -1
- package/skills/wix-manage/references/google-ads/install-and-create-account.md +9 -9
- package/skills/wix-manage/references/google-ads/manage-campaign-success-guide.md +108 -14
- package/skills/wix-manage/references/google-ads/query-campaign-analytics.md +7 -7
- package/skills/wix-manage/references/seo/manage-content-plan.md +182 -136
- package/skills/wix-manage/references/seo/manage-google-search-console.md +272 -0
- package/skills/wix-manage/references/sites/upload-static-site.md +283 -0
- package/skills/wix-manage/references/stores/change-store-currency.md +1 -1
- package/skills/wix-vibe-headless/platforms/base44-ecom-light-seed-with-install.md +3 -1
- package/skills/wix-vibe-headless/platforms/base44-ecom-light-seed.md +3 -1
- package/skills/wix-vibe-headless/platforms/base44-ecom-light.md +1 -1
- package/skills/wix-vibe-headless/references/storefront/INSTRUCTIONS.md +69 -27
- package/skills/wix-vibe-headless/references/storefront/app/components/CartDrawer.jsx +32 -14
- package/skills/wix-vibe-headless/references/storefront/app/context/CartContext.jsx +14 -3
- package/skills/wix-vibe-headless/references/storefront/app/hooks/useProductCard.js +41 -35
- package/skills/wix-vibe-headless/references/storefront/app/hooks/useProductDetail.js +77 -30
- package/skills/wix-vibe-headless/references/storefront/app/rest/wix-store-cart.js +31 -2
- package/skills/wix-vibe-headless/references/storefront/app/rest/wix-store-catalog.js +31 -6
- package/skills/wix-app/references/dashboard-page/COLLECTION_TOOLKIT.md +0 -80
- package/skills/wix-app/references/dashboard-page/ENTITY_PAGE_TOOLKIT.md +0 -140
- package/skills/wix-app/references/dashboard-page/PATTERNS_BUNDLE_READING.md +0 -112
- package/skills/wix-headless-fast/references/storefront/app/components/storefront/ProductCard.tsx +0 -100
- package/skills/wix-headless-fast/references/storefront/app/components/storefront/ProductDetailView.tsx +0 -130
- package/skills/wix-headless-fast/references/storefront/app/components/storefront/ProductGrid.tsx +0 -48
- package/skills/wix-headless-fast/references/storefront/app/components/storefront/ShopView.tsx +0 -66
- package/skills/wix-headless-fast/references/storefront/app/components/storefront/VariantPicker.tsx +0 -103
- package/skills/wix-headless-fast/references/storefront/app-astro/pages/products/[slug].astro +0 -56
- package/skills/wix-headless-fast/references/storefront/app-astro/pages/shop.astro +0 -23
package/skills/wix-docs/SKILL.md
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
---
|
|
2
2
|
name: wix-docs
|
|
3
|
-
description: "Look up the Wix API/SDK documentation to confirm an exact endpoint, HTTP method, request/response shape, field, enum, or error before writing Wix code — never guess a Wix API from memory. A lookup is a short flow: find the right page, then read it. Two ways: (1) plain `curl` (zero dependencies) — find a page by **semantic search** (`POST /mcp-docs-search/v1/docs/search`, natural-language `{ search_term, document_type }`, incl. the SKILLS recipe corpus for multi-step workflows) **or by browsing** a docs portal as a menu — a structured, typed, counted browse of the REST, SDK, CLI, Build Apps, and Headless portals (`POST /mcp-docs-search/v1/docs/menu/browse`), or the `.md` menu tree from the `llms.txt` root for any surface — then read the page by appending `.md` to its URL; (2) the Wix MCP doc tools when present. Triggers: look up a Wix API, find the Wix endpoint/method, confirm a Wix request body or field, verify a Wix API shape, explore Wix docs, which Wix API do I call, read a Wix method schema."
|
|
3
|
+
description: "Look up the Wix API/SDK documentation to confirm an exact endpoint, HTTP method, request/response shape, field, enum, or error before writing Wix code — never guess a Wix API from memory. A lookup is a short flow: find the right page, then read it. Two ways: (1) plain `curl` (zero dependencies) — find a page by **semantic search** (`POST /mcp-docs-search/v1/docs/search`, natural-language `{ search_term, document_type(s) }`, incl. the SKILLS recipe corpus for multi-step workflows) **or by browsing** a docs portal as a menu — a structured, typed, counted browse of the REST, SDK, CLI, Build Apps, and Headless portals (`POST /mcp-docs-search/v1/docs/menu/browse`), or the `.md` menu tree from the `llms.txt` root for any surface — then read the page by appending `.md` to its URL; (2) the Wix MCP doc tools when present. Triggers: look up a Wix API, find the Wix endpoint/method, confirm a Wix request body or field, verify a Wix API shape, explore Wix docs, which Wix API do I call, read a Wix method schema."
|
|
4
4
|
---
|
|
5
5
|
|
|
6
6
|
# Wix Docs — look up the Wix API/SDK documentation
|
|
@@ -15,11 +15,11 @@ or the Wix MCP doc tools if your agent has them (Lane 2). Either way, route by w
|
|
|
15
15
|
know:
|
|
16
16
|
|
|
17
17
|
- **You have a docs URL** → just read it (§2). Don't re-search for a page you can already name.
|
|
18
|
-
- **A multi-step workflow** ("take a booking from service setup to payment") →
|
|
19
|
-
|
|
20
|
-
cross-step gotchas, and the one bundled endpoint that does
|
|
21
|
-
method page states. No relevant recipe
|
|
22
|
-
from verified per-method contracts.
|
|
18
|
+
- **A multi-step workflow** ("take a booking from service setup to payment") → include the **recipe**
|
|
19
|
+
corpus in the search: `document_types: ["SKILLS", …]` alongside the API corpus the steps live in
|
|
20
|
+
(§1A). A recipe carries step ordering, cross-step gotchas, and the one bundled endpoint that does
|
|
21
|
+
the whole job — things no single method page states. No relevant recipe comes back → assemble the
|
|
22
|
+
workflow from the verified per-method contracts in the same result set.
|
|
23
23
|
- **One specific operation, field, or enum** → search its API corpus (`REST` / `SDK`), then read or
|
|
24
24
|
schema-check what you land on.
|
|
25
25
|
|
|
@@ -34,12 +34,21 @@ Three ways to reach the right page — use whichever fits.
|
|
|
34
34
|
|
|
35
35
|
**A. Semantic search.** Describe what you want in natural language ("let a customer book an
|
|
36
36
|
appointment"), not just keywords; hits come back ranked by relevance. Same `POST` body for both
|
|
37
|
-
variants: `search_term` (required, 1–500), `document_type` (
|
|
38
|
-
`
|
|
39
|
-
|
|
40
|
-
|
|
41
|
-
|
|
42
|
-
|
|
37
|
+
variants: `search_term` (required, 1–500), **one** of `document_type` (a single corpus) or
|
|
38
|
+
`document_types` (an array — several corpora in one ranked call); `maximum_results` (1–20, def 15,
|
|
39
|
+
counted across the combined result set), `lines_in_each_result` (0–200, def 20; `0` = no per-hit
|
|
40
|
+
line cap). Corpora: `REST` (default) · `SDK` · `SKILLS` · `WIX_HEADLESS` · `BUSINESS_SOLUTIONS` ·
|
|
41
|
+
`VELO` · `WDS` · `BUILD_APPS` · `CLI` · `OVERVIEW`. `SKILLS` is the dedicated **recipe corpus** —
|
|
42
|
+
multi-step workflow pages a single-API search does not return; `OVERVIEW` is platform orientation
|
|
43
|
+
(which development approach, which API family).
|
|
44
|
+
|
|
45
|
+
**Search the corpora a question actually spans, in one call.** The service ranks them together and
|
|
46
|
+
interleaves the hits, so they compete on relevance instead of you guessing which to try first —
|
|
47
|
+
and one round trip replaces several. There's no fixed combination: pick by the question. Passing
|
|
48
|
+
both `document_type` and `document_types` is an error (*"Pass either document_type or
|
|
49
|
+
document_types, not both"*), and an unknown corpus name is rejected with the valid list.
|
|
50
|
+
|
|
51
|
+
Two variants — pick by what you're doing:
|
|
43
52
|
|
|
44
53
|
**`/docs/search/markdown` → read it (start here).** Returns JSON with a single `content` field
|
|
45
54
|
holding one LLM-ready markdown string (extract it with `jq -r '.content'`) where each hit is a
|
|
@@ -58,26 +67,44 @@ curl -sS -X POST 'https://www.wixapis.com/mcp-docs-search/v1/docs/search/markdow
|
|
|
58
67
|
| jq -r '.content' # no jq? → python3 -c 'import sys,json;print(json.load(sys.stdin)["content"])'
|
|
59
68
|
```
|
|
60
69
|
|
|
61
|
-
|
|
70
|
+
A question that spans a workflow and its individual calls asks for both corpora at once — the
|
|
71
|
+
recipe and the per-method contracts arrive in one ranked list:
|
|
62
72
|
|
|
63
73
|
```bash
|
|
64
74
|
curl -sS -X POST 'https://www.wixapis.com/mcp-docs-search/v1/docs/search/markdown' \
|
|
65
75
|
-H 'Content-Type: application/json' \
|
|
66
|
-
--data-raw '{"search_term":"end to end booking flow","
|
|
76
|
+
--data-raw '{"search_term":"end to end booking flow","document_types":["SKILLS","REST"],"maximum_results":6}' \
|
|
67
77
|
| jq -r '.content'
|
|
68
78
|
```
|
|
69
79
|
|
|
70
80
|
**`/docs/search` (JSON) → route on it.** Returns `{ results: [ { title, url, content,
|
|
71
|
-
relevance_score, … } ] }` — structured hits. Use it when you want to **pick/route
|
|
72
|
-
grab a hit's `url` to read that page (§2) or feed it to the schema query (§C).
|
|
73
|
-
|
|
81
|
+
relevance_score, kb_name, … } ] }` — structured hits. Use it when you want to **pick/route
|
|
82
|
+
programmatically**: grab a hit's `url` to read that page (§2) or feed it to the schema query (§C).
|
|
83
|
+
|
|
84
|
+
**`kb_name` tells you what each hit is** — every hit carries one, and the kind decides what you can
|
|
85
|
+
do with it: only a method page has a schema to pull (§C); an article or recipe is read as prose (§2).
|
|
86
|
+
|
|
87
|
+
The request can't make that split for you. **A corpus mixes kinds** — searching the API reference
|
|
88
|
+
returns method pages *and* the prose around them — and no corpus returns method pages alone. So
|
|
89
|
+
pick corpora with `document_types`, then separate the kinds on the way out with `kb_name`. Two
|
|
90
|
+
things not to do instead: don't infer the kind from the presence of a `url` (every hit has one,
|
|
91
|
+
articles and recipes included), and don't infer it from the corpus you asked for.
|
|
92
|
+
|
|
93
|
+
Most values name their kind (`…_METHODS_…` for method pages, `…_DOCS_…` for prose, `SKILLS_KB_ID`
|
|
94
|
+
for recipes) but not all do — the SDK's method index is `API_REFERENCE_SDK_KB_ID`. So list the
|
|
95
|
+
labels your search actually returned, then act on those, rather than pattern-matching the name or
|
|
96
|
+
hard-coding a list of ids.
|
|
74
97
|
|
|
75
98
|
```bash
|
|
99
|
+
# see what came back — label, title, url
|
|
76
100
|
curl -sS -X POST 'https://www.wixapis.com/mcp-docs-search/v1/docs/search' \
|
|
77
101
|
-H 'Content-Type: application/json' \
|
|
78
|
-
--data-raw '{"search_term":"
|
|
79
|
-
| jq -r '.results[] |
|
|
80
|
-
# no jq? → python3 -c 'import sys,json;[print(r["title"],r
|
|
102
|
+
--data-raw '{"search_term":"end to end booking flow","document_types":["REST","SKILLS","WIX_HEADLESS"],"maximum_results":10}' \
|
|
103
|
+
| jq -r '.results[] | "\(.kb_name)\t\(.title)\t\(.url)"'
|
|
104
|
+
# no jq? → python3 -c 'import sys,json;[print(r.get("kb_name"),r["title"],r.get("url")) for r in json.load(sys.stdin)["results"]]'
|
|
105
|
+
|
|
106
|
+
# then take the kind you need, by the label you just saw
|
|
107
|
+
… | jq -r '.results[] | select(.kb_name == "REST_METHODS_KB_ID") | "\(.title)\t\(.url)"'
|
|
81
108
|
```
|
|
82
109
|
|
|
83
110
|
**B. Browse the docs tree as a menu.** Two ways: the **structured browse endpoint** for the
|
|
@@ -124,6 +124,7 @@ Compute `<SKILL_ROOT>` from this file (`<SKILL_ROOT>/SKILL.md` — strip `/SKILL
|
|
|
124
124
|
| Image generation (opt-in; agnostic) | `<SKILL_ROOT>/references/IMAGE_GENERATION.md` |
|
|
125
125
|
| Design — fallback visual quality bar for the built frontend, when the user gave no design direction of their own (managed **create** only) | `<SKILL_ROOT>/references/DESIGN.md` |
|
|
126
126
|
| Content — fallback copy quality bar for the built frontend, when the user gave no copy/voice direction of their own (managed **create** only) | `<SKILL_ROOT>/references/CONTENT.md` |
|
|
127
|
+
| Experience overlays — a vertical's own design + copy bar on top of DESIGN/CONTENT (optional per vertical; read when that vertical is loaded) | `<SKILL_ROOT>/references/inline-recipes/experience-<vertical>.md` (today: `experience-store.md`) |
|
|
127
128
|
| AI features — text/chat + embeddings (opt-in; agnostic) | `<SKILL_ROOT>/references/AI_FEATURES.md` |
|
|
128
129
|
| Feedback — relay the user's headless-experience feedback to Wix (opt-in; user-approved) | `<SKILL_ROOT>/references/FEEDBACK.md` |
|
|
129
130
|
| **Authentication** — obtain `$TOKEN`/`$SITE_ID`/`clientId` (project-type-specific) | `<TYPE_DIR>/AUTHENTICATION.md` |
|
|
@@ -1,6 +1,8 @@
|
|
|
1
1
|
#!/usr/bin/env node
|
|
2
2
|
import { spawn, spawnSync } from 'node:child_process';
|
|
3
|
-
import
|
|
3
|
+
import { existsSync, mkdirSync, openSync, readFileSync, writeFileSync } from 'node:fs';
|
|
4
|
+
import { tmpdir } from 'node:os';
|
|
5
|
+
import { join } from 'node:path';
|
|
4
6
|
|
|
5
7
|
// ── tiny event protocol (one JSON object per line) ───────────────────────────
|
|
6
8
|
const emit = (event, extra = {}) =>
|
|
@@ -24,6 +26,12 @@ const WIX = [bin('npx'), '-y', '@wix/cli@latest']; // run the CLI via npx — no
|
|
|
24
26
|
// Respect an existing value so a known runner (claude, cursor, …) keeps its name.
|
|
25
27
|
const AGENT_ENV = { ...process.env, AI_AGENT: process.env.AI_AGENT || 'wix-headless-skill' };
|
|
26
28
|
|
|
29
|
+
// Where the detached login parks its output between runs. It has to outlive this
|
|
30
|
+
// process, so it can't be a pipe and can't live in the project.
|
|
31
|
+
const STATE_DIR = join(tmpdir(), 'wix-headless-login');
|
|
32
|
+
const LOG = join(STATE_DIR, 'login.log');
|
|
33
|
+
const PIDFILE = join(STATE_DIR, 'login.pid');
|
|
34
|
+
|
|
27
35
|
// run a command, capture stdout+stderr (combined), return {status, out}
|
|
28
36
|
function capture(cmd, args, opts = {}) {
|
|
29
37
|
const r = spawnSync(cmd, args, { encoding: 'utf8', shell: isWin, env: AGENT_ENV, ...opts });
|
|
@@ -41,60 +49,108 @@ function checkCli() {
|
|
|
41
49
|
}
|
|
42
50
|
|
|
43
51
|
// ── 2. Reuse an existing session, or start device login ──────────────────────
|
|
44
|
-
|
|
45
|
-
const r = capture(WIX[0], [...WIX.slice(1), 'whoami']);
|
|
46
|
-
if (r.status !== 0) return false;
|
|
47
|
-
emit('logged_in');
|
|
48
|
-
return true;
|
|
49
|
-
}
|
|
52
|
+
const hasExistingSession = () => capture(WIX[0], [...WIX.slice(1), 'whoami']).status === 0;
|
|
50
53
|
|
|
51
|
-
function
|
|
52
|
-
|
|
53
|
-
|
|
54
|
-
|
|
55
|
-
|
|
56
|
-
|
|
57
|
-
|
|
58
|
-
// a guess. Keep only the tail so a chatty CLI can't blow up memory, and draining
|
|
59
|
-
// stderr also avoids the pipe filling up and stalling the child.
|
|
60
|
-
let diag = '';
|
|
61
|
-
const collect = (chunk) => {
|
|
62
|
-
diag = (diag + chunk).slice(-2000);
|
|
63
|
-
};
|
|
64
|
-
child.stderr?.on('data', collect);
|
|
65
|
-
rl.on('line', (line) => {
|
|
66
|
-
const t = line.trim();
|
|
67
|
-
if (!t) return;
|
|
68
|
-
// In agent mode the CLI emits {event:"awaiting_user"|"success"|"logged_in", ...}
|
|
69
|
-
// — pass those straight through so the agent can relay the device code.
|
|
54
|
+
function loginEvents() {
|
|
55
|
+
if (!existsSync(LOG)) return [];
|
|
56
|
+
return readFileSync(LOG, 'utf8')
|
|
57
|
+
.split('\n')
|
|
58
|
+
.map((l) => l.trim())
|
|
59
|
+
.filter(Boolean)
|
|
60
|
+
.map((l) => {
|
|
70
61
|
try {
|
|
71
|
-
|
|
72
|
-
if (ev && ev.event) {
|
|
73
|
-
process.stdout.write(t + '\n');
|
|
74
|
-
if (ev.event === 'success' || ev.event === 'logged_in') {
|
|
75
|
-
loggedIn = true;
|
|
76
|
-
resolve();
|
|
77
|
-
}
|
|
78
|
-
return;
|
|
79
|
-
}
|
|
80
|
-
collect(line + '\n'); // JSON, but not an event — keep for diagnostics
|
|
62
|
+
return JSON.parse(l);
|
|
81
63
|
} catch {
|
|
82
|
-
|
|
83
|
-
}
|
|
84
|
-
})
|
|
85
|
-
|
|
86
|
-
|
|
87
|
-
|
|
88
|
-
|
|
89
|
-
|
|
90
|
-
|
|
91
|
-
|
|
92
|
-
|
|
93
|
-
|
|
94
|
-
|
|
64
|
+
return null; // non-JSON CLI chatter
|
|
65
|
+
}
|
|
66
|
+
})
|
|
67
|
+
.filter((e) => e && e.event);
|
|
68
|
+
}
|
|
69
|
+
|
|
70
|
+
const alive = (pid) => {
|
|
71
|
+
try {
|
|
72
|
+
process.kill(pid, 0);
|
|
73
|
+
return true;
|
|
74
|
+
} catch {
|
|
75
|
+
return false;
|
|
76
|
+
}
|
|
77
|
+
};
|
|
78
|
+
|
|
79
|
+
// A login this machine started earlier may still be waiting on the browser. Reuse
|
|
80
|
+
// its code instead of minting a second one — a new login invalidates nothing, but
|
|
81
|
+
// it hands the user a different code than the one already on their screen.
|
|
82
|
+
function pendingLogin() {
|
|
83
|
+
if (!existsSync(PIDFILE)) return null;
|
|
84
|
+
let state;
|
|
85
|
+
try {
|
|
86
|
+
state = JSON.parse(readFileSync(PIDFILE, 'utf8'));
|
|
87
|
+
} catch {
|
|
88
|
+
return null;
|
|
89
|
+
}
|
|
90
|
+
if (!state.pid || !alive(state.pid)) return null;
|
|
91
|
+
const ev = loginEvents().find((e) => e.event === 'awaiting_user');
|
|
92
|
+
if (!ev) return null;
|
|
93
|
+
// Don't hand back a code that's about to expire mid-typing.
|
|
94
|
+
const ageSeconds = Math.round((Date.now() - state.startedAt) / 1000);
|
|
95
|
+
if (ageSeconds > (ev.expiresInSeconds ?? 600) - 60) return null;
|
|
96
|
+
return ev;
|
|
97
|
+
}
|
|
98
|
+
|
|
99
|
+
// Detach so the login keeps polling after this process exits. stdio goes to a
|
|
100
|
+
// file, not a pipe: a pipe dies with the parent, and the CLI would get EPIPE.
|
|
101
|
+
function startLogin() {
|
|
102
|
+
mkdirSync(STATE_DIR, { recursive: true });
|
|
103
|
+
writeFileSync(LOG, '');
|
|
104
|
+
const out = openSync(LOG, 'a');
|
|
105
|
+
const child = spawn(WIX[0], [...WIX.slice(1), 'login'], {
|
|
106
|
+
detached: true,
|
|
107
|
+
stdio: ['ignore', out, out],
|
|
108
|
+
env: AGENT_ENV,
|
|
109
|
+
shell: isWin,
|
|
110
|
+
});
|
|
111
|
+
child.on('error', (e) => fail('login_failed', { detail: String(e) }));
|
|
112
|
+
writeFileSync(PIDFILE, JSON.stringify({ pid: child.pid, startedAt: Date.now() }));
|
|
113
|
+
child.unref();
|
|
114
|
+
}
|
|
115
|
+
|
|
116
|
+
async function waitForCode(timeoutMs = 60000) {
|
|
117
|
+
const deadline = Date.now() + timeoutMs;
|
|
118
|
+
while (Date.now() < deadline) {
|
|
119
|
+
const events = loginEvents();
|
|
120
|
+
const ev = events.find((e) => e.event === 'awaiting_user');
|
|
121
|
+
if (ev) return ev;
|
|
122
|
+
const bad = events.find((e) => e.event === 'login_failed');
|
|
123
|
+
if (bad) fail('login_failed', bad);
|
|
124
|
+
await new Promise((r) => setTimeout(r, 500));
|
|
125
|
+
}
|
|
126
|
+
const detail = existsSync(LOG) ? readFileSync(LOG, 'utf8').trim().slice(-1500) : '';
|
|
127
|
+
fail('login_failed', {
|
|
128
|
+
detail: detail || `wix login produced no device code within ${timeoutMs / 1000}s.`,
|
|
129
|
+
});
|
|
130
|
+
}
|
|
131
|
+
|
|
132
|
+
// The next move is the user's, so hand the code back and exit rather than holding
|
|
133
|
+
// the caller open for a browser round-trip. `message` is the sentence to relay.
|
|
134
|
+
function surrenderTo(ev) {
|
|
135
|
+
emit('awaiting_user', {
|
|
136
|
+
...ev,
|
|
137
|
+
message:
|
|
138
|
+
`To connect your Wix account, open ${ev.verificationUri} and enter the code ` +
|
|
139
|
+
`${ev.userCode}. Tell me once you're done and I'll continue.`,
|
|
95
140
|
});
|
|
141
|
+
process.exit(0);
|
|
96
142
|
}
|
|
97
143
|
|
|
98
144
|
// ── main ────────────────────────────────────────────────────────────────────
|
|
99
145
|
checkCli();
|
|
100
|
-
|
|
146
|
+
|
|
147
|
+
if (hasExistingSession()) {
|
|
148
|
+
emit('logged_in');
|
|
149
|
+
process.exit(0);
|
|
150
|
+
}
|
|
151
|
+
|
|
152
|
+
const pending = pendingLogin();
|
|
153
|
+
if (pending) surrenderTo(pending);
|
|
154
|
+
|
|
155
|
+
startLogin();
|
|
156
|
+
surrenderTo(await waitForCode());
|
|
@@ -36,9 +36,9 @@ If that errors (Node not installed) or prints a version below 20.11, install or
|
|
|
36
36
|
|
|
37
37
|
## Phase 1 — Run the bootstrap (deterministic)
|
|
38
38
|
|
|
39
|
-
Download the bootstrap script, then run it. It verifies the Wix CLI and handles login, emitting **one JSON event per line** on stdout. **Run it
|
|
39
|
+
Download the bootstrap script, then run it — an ordinary foreground command that exits on its own within seconds. It verifies the Wix CLI and handles login, emitting **one JSON event per line** on stdout. **Run it and relay its events to the user.**
|
|
40
40
|
|
|
41
|
-
The script is safe and inspectable: it only checks the Wix CLI via `npx` and drives `wix login` (a device-code flow) — no other network calls,
|
|
41
|
+
The script is safe and inspectable: it only checks the Wix CLI via `npx` and drives `wix login` (a device-code flow) — no other network calls, and the only files it writes are the login's own output and pid under the OS temp dir. Read it first if your sandbox flags externally-downloaded code — either at the URL below or after downloading; both are the same file.
|
|
42
42
|
|
|
43
43
|
```bash
|
|
44
44
|
# macOS/Linux:
|
|
@@ -56,10 +56,12 @@ The script emits one JSON object per line:
|
|
|
56
56
|
| Event | What to do |
|
|
57
57
|
|---|---|
|
|
58
58
|
| `cli_ok` | Wix CLI reachable — continue. |
|
|
59
|
-
| `awaiting_user` (`verificationUri`, `userCode`) |
|
|
59
|
+
| `awaiting_user` (`verificationUri`, `userCode`, `message`) | The script has exited and the next step is the user's. Send them `message` as-is; the login keeps running on its own. |
|
|
60
60
|
| `logged_in` / `success` | Login done — continue. |
|
|
61
61
|
| `cli_unreachable` / `login_failed` (with `detail`) | Stop and show the user the `detail`. **Do not** improvise a parallel setup by hand. |
|
|
62
62
|
|
|
63
|
+
On `awaiting_user`, run the script again once the user says they've logged in: it reports `logged_in` and you continue. Re-running while they're still in the browser is harmless — it returns the same code rather than issuing a new one.
|
|
64
|
+
|
|
63
65
|
## Phase 2 — Install the skill and hand off
|
|
64
66
|
|
|
65
67
|
Install the Wix Headless skills (`CI=1` forces plain non-interactive CLI output — keep it on every Wix CLI command):
|
|
@@ -23,8 +23,13 @@ The verticals the skill operates end-to-end today: **stores · blog · cms · fo
|
|
|
23
23
|
|
|
24
24
|
### stores — sell products
|
|
25
25
|
- **Intent:** sell / shop / products / catalog / merch / store.
|
|
26
|
-
- **Required site features:** a
|
|
27
|
-
- **Implementation checklist:**
|
|
26
|
+
- **Required site features:** a homepage that sells (what the store offers, real products, one clear shopping action); a shop / category gallery with sort, the filters the catalog supports, and paging; a page per product; categories to browse by; a cart the shopper can review and edit, opening as a side drawer after every add; checkout reachable directly from that cart.
|
|
27
|
+
- **Implementation checklist:**
|
|
28
|
+
- *Homepage:* say what the store sells in the first screen; real products from the catalog under truthful headings — never a repeat of the shop page, never a heading like "Best Sellers" without data behind it.
|
|
29
|
+
- *Gallery:* a real product — image, name, price, link — visible in the first screen before any scrolling; a result count; loading, empty-catalog, no-results-for-these-filters, and error states that look different from each other.
|
|
30
|
+
- *Product page:* in the first screen, the product image, name, price, the first choice to make, and the buy button — disabled with a plain reason until every choice is made; every ribbon the merchant set; the current price and, when there is one, the labelled original price; a gallery of every product image; options with unavailable choices marked; quantity; the full description and information sections; pre-order, subscriptions, and notify-me only when the catalog has them.
|
|
31
|
+
- *Cart:* each line's image, name, chosen options, quantity (editable) and price; subtotal and discounts as Wix calculates them; "shipping and taxes calculated at checkout" rather than invented numbers; survives a reload; checkout from the drawer.
|
|
32
|
+
- *Everywhere:* availability / out-of-stock shown truthfully; each product linked to its category; no reviews, ratings, scarcity, or delivery promises the merchant didn't supply; no Wix IDs or technical words in shopper-facing text.
|
|
28
33
|
|
|
29
34
|
### blog — publish posts
|
|
30
35
|
- **Intent:** blog / posts / articles / publication / news.
|
|
@@ -36,7 +36,7 @@ Before implementing a capability, Read the local recipe linked in its row.
|
|
|
36
36
|
|
|
37
37
|
| Capability | Package(s) | Required recipe |
|
|
38
38
|
|---|---|---|
|
|
39
|
-
| stores | `@wix/stores` (+ `@wix/ecom`, `@wix/redirects` for cart/checkout) | `how-to-code-a-store.md` — Catalog V3
|
|
39
|
+
| stores | `@wix/stores` + `@wix/categories` (+ `@wix/ecom`, `@wix/redirects` for cart/checkout) | `how-to-code-a-store.md` — Catalog V3 gallery (sort/filter/paging), product page (variants, prices, ribbons), Cart V2 + checkout, and what a complete storefront shows. |
|
|
40
40
|
| blog | `@wix/blog` (+ `@wix/ricos` to render `richContent`; **`@wix/comments` + `@wix/members`** when the blog has comments/members; `@wix/blog` `likes` when the site has members) | `how-to-code-a-blog.md` — Blog V3 read/render + member features (likes, comments). Supplement: <https://dev.wix.com/docs/sdk/business-solutions/blog.md>. |
|
|
41
41
|
| cms | `@wix/data` | `how-to-code-cms.md` — `items.query` read contract. |
|
|
42
42
|
| forms | `@wix/forms` | `how-to-code-forms.md` — schema-driven render (read the live form schema, visitor token/no elevate) + Form Submissions v4 write contract. |
|
|
@@ -77,6 +77,7 @@ Everything else the host resolves live from the queries in §3. (Static platform
|
|
|
77
77
|
For each loaded capability, carry its **Required site features** and **Implementation checklist** from `references/CAPABILITIES.md` into the guide — in plain product language, lightly tailored to what was seeded. **This is the build spec, not optional polish:** the host should build every *required feature* and cover every *checklist* item. For example, a blog must show the **author** (name + photo), the publish date and reading time, the cover image, and the **full formatted content** (not flattened text) — a posts-list-plus-plain-text-body is incomplete. The host maps these onto its own components using the packages/docs in §3 and the seeded schema in §4.
|
|
78
78
|
|
|
79
79
|
- State them as the *what* (product behaviour), not the *how* (no component code, no API calls) — the host owns the build.
|
|
80
|
+
- **When a loaded vertical ships an experience overlay** (`references/inline-recipes/experience-<vertical>.md`; today `experience-store.md`), point the host at it alongside the checklist — it is that vertical's design and copy bar (surfaces, first-viewport rules, truthful copy), read after the general `DESIGN.md`/`CONTENT.md`.
|
|
80
81
|
- If a *required feature* depends on backend support that **Seed** enabled (e.g., comments), note it's available so the host wires it. If Seed could **not** enable it, say so plainly rather than implying the site is complete.
|
|
81
82
|
- **When pricing-plans is loaded, `login / account / gated content` is a *required* feature, not optional polish** — a plans grid with no way to log in and subscribe is incomplete (subscribing requires a member; §5 member-auth note). Point the host at the matching `how-to-code-members-*.md` recipe. For the other verticals, a "my …" surface (my orders / my bookings / my registrations) is a member-gated *enhancement* — list it only if the run's intent calls for an account view, and flag it needs the same login mechanism.
|
|
82
83
|
- **Curation / hero / nav must come from a LIVE query, never a pinned slug/id.** A "featured" or "latest" item, a hero, and every nav/category bar must be driven by a query — "next upcoming" (`queryEvents` filtered to `UPCOMING`/`STARTED`, sorted by start date), "newest" (`queryPosts`), `queryCategories`, etc. — resolved at request time. A pinned "featured event" slug not only fails to rotate as the owner adds content, it can go **stale/past**. Even a **single-item** site (one event, one product) must drive its homepage from the *listing query*, not a hardcoded lone slug — so a second item the owner adds later surfaces automatically instead of staying invisible.
|
|
@@ -0,0 +1,48 @@
|
|
|
1
|
+
---
|
|
2
|
+
name: "Storefront Experience"
|
|
3
|
+
description: The storefront's own design and copy bar, on top of DESIGN.md and CONTENT.md — how to derive a store's direction from its catalog, what the homepage, gallery, product page, and cart must show, the overlay contract, truthful commerce copy, and image discipline. Read when building or wiring a store frontend; the API contract lives in how-to-code-a-store.md.
|
|
4
|
+
---
|
|
5
|
+
**EXPERIENCE OVERLAY**: What makes a storefront good — read after `DESIGN.md` and `CONTENT.md`
|
|
6
|
+
|
|
7
|
+
`DESIGN.md` and `CONTENT.md` are the floor for every site. This file adds what is specific to a store. It is the *what* of a good storefront — the API *how* is `how-to-code-a-store.md`. The wiring is necessary, not sufficient: a store whose calls all work but whose homepage repeats the shop page, whose first screen shows no product, or whose cart hides checkout behind a page is not done.
|
|
8
|
+
|
|
9
|
+
**These are defaults for when the brief doesn't say otherwise.** Whatever the user asked for in their prompt — a layout, a page they don't want, a cart page instead of a drawer, a specific look — wins over any line here.
|
|
10
|
+
|
|
11
|
+
## 1 · Design from the catalog, not from the category
|
|
12
|
+
|
|
13
|
+
Before choosing tokens, **look at the catalog**: the categories and their depth, the assortment size, the media (count, aspect ratios, background consistency, focal points), the options and price points, the ribbons and sales. Then write the store's direction as a few lines, held with the design tokens:
|
|
14
|
+
|
|
15
|
+
- a **one-sentence thesis** — the offer, the shopper, the character;
|
|
16
|
+
- **three traits**;
|
|
17
|
+
- an **avoid-list** of the stereotypes this store would fall into by default: "premium" does not mean dark, serif, minimal; "kids" does not mean primary colors; a bakery is not automatically cream and script. Keep the conventions of the store's own vertical that genuinely help shoppers compare and choose;
|
|
18
|
+
- one **signature decision** that makes the store recognizable with the logo hidden, backed by real content — a product form, a material, the category structure, a typographic move;
|
|
19
|
+
- a **media treatment** per placement (product, category, hero, fallback): frame ratio, `cover`/`contain`, focal behavior.
|
|
20
|
+
|
|
21
|
+
Two stores with the same vertical and different catalogs should look nothing alike. Never ask the user for a reference store; if they supply one, take only portable principles (hierarchy, image prominence, rhythm, density), never its layout, palette, typefaces, or taxonomy.
|
|
22
|
+
|
|
23
|
+
**Audit the media before giving it a role.** Never stretch an image, enlarge a thumbnail into a hero, or crop the product away; give every image a stable aspect ratio and `object-fit` so the grid doesn't jump. When hero-scale media is absent, compose the hero from typography, a product tile, or a collage of what exists. Product photography informs compatible backgrounds and contrast; it does not automatically dictate the UI's dominant color.
|
|
24
|
+
|
|
25
|
+
## 2 · The surfaces and their bar
|
|
26
|
+
|
|
27
|
+
- **Global shell:** category navigation from the live tree (a curated menu is fine, but every product-bearing category stays reachable); a persistent cart control with a live count; a footer sized to the real destinations. Announcement, shipping, and returns text only from the merchant.
|
|
28
|
+
- **Homepage — a merchandising surface, not the shop page again.** Say what the store sells and give one dominant shopping action in the first viewport; real products from live queries under truthful headings; category discovery when the taxonomy is meaningful. Don't reuse the same first product as hero, first card, and feature. No section exists to fill space — a claim-dependent module with no truthful source is omitted.
|
|
29
|
+
- **Gallery — a discovery surface.** Title, result count, sort, the filters the catalog supports, paging; in its default state a **real product card — image, name, price, link — is inside the first viewport**, also on a short desktop window. Skeletons while loading, a distinct "no results for these filters" with a reset, an honest empty catalog, a recoverable error. Filters that stay visible with the results commit immediately; filters in a sheet stage changes until Apply.
|
|
30
|
+
- **Product page — a complete purchase decision.** In the first viewport at mobile, tablet, and desktop: a recognizable product image, name, price, the first required choice (or a control that jumps to it), and the buy action with its neutral disabled reason. Then every ribbon, the full description and info sections, a gallery of **every** image, quantity, and — when the catalog has them — subscriptions, preorder, group navigation, notify-me. A sticky buy region must never cover a control.
|
|
31
|
+
- **Cart — a side drawer by default**, opened after every successful add and from the header: image, name, the chosen options and text, quantity editing with pending and failure states, line prices, the calculated subtotal and discount, "shipping and taxes calculated at checkout", and checkout **from the drawer**. Persists across navigation and refresh. A separate cart page is optional, never a mandatory step before checkout.
|
|
32
|
+
- **Quick add** anchors to its card (an inline or attached panel; a bottom sheet on mobile); a centered dialog is the exception for a demonstrably large configuration, not the default. Its first view shows identity, price, the first required choice, and the action.
|
|
33
|
+
|
|
34
|
+
## 3 · Overlays (cart drawer, quick add, mobile nav, filter sheet)
|
|
35
|
+
|
|
36
|
+
Mount at the document root — a `position: fixed` panel inside a header with a `transform`, `filter`, or `backdrop-filter` gets clipped. Full-viewport scrim; background scroll locked and inert; the panel scrolls independently with Close and the primary action always reachable; focus moves in and is trapped while modal; Escape closes; focus returns to the trigger on close (or moves to a successor surface when one overlay opens another). Verify this in the browser — CSS alone doesn't prove it.
|
|
37
|
+
|
|
38
|
+
## 4 · Truthful commerce copy
|
|
39
|
+
|
|
40
|
+
- **Claims come from the merchant or the data, never from the page's need for a section.** No invented reviews, ratings, "X people bought this", scarcity, delivery promises, certifications, guarantees, or payment/trust badges.
|
|
41
|
+
- **Labels match their source.** "Best Sellers" needs sales data or a category the merchant named that way; the catalog's default order is not a ranking. "Featured" or the category's real name is always safe.
|
|
42
|
+
- **Write for shoppers, not implementers.** No Wix IDs, API names, "catalog", "current catalog", "headless", or integration words in headings, labels, buttons, or empty states.
|
|
43
|
+
- **Prices tell the truth.** A ribbon is a label, never proof of a discount; a struck price is labelled ("was") and shown only when it is real and higher; a range never gets a lone struck minimum; savings are never computed in the client.
|
|
44
|
+
- **Operational text is the merchant's.** A cart says "shipping and taxes calculated at checkout" rather than a number nobody configured.
|
|
45
|
+
|
|
46
|
+
## 5 · Images
|
|
47
|
+
|
|
48
|
+
Responsive delivery (`srcset` + `sizes` from scaled Wix media candidates — `how-to-code-a-store.md` § Rendering product images), stable aspect ratios with `width`/`height`, lazy loading below the fold, meaningful `alt` text from the catalog's `altText` or the product name. Failed images get a visible fallback, never a broken icon.
|