@wix/agent-skills 1.6.0 → 1.7.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 +2 -2
- package/package.json +1 -1
- package/skills/wix-app/SKILL.md +49 -42
- package/skills/wix-app/references/BACKEND_EVENT.md +10 -65
- package/skills/wix-app/references/CUSTOM_ELEMENT_WIDGET.md +101 -406
- package/skills/wix-app/references/DASHBOARD_MENU_PLUGIN.md +14 -111
- package/skills/wix-app/references/DASHBOARD_MODAL.md +56 -205
- package/skills/wix-app/references/DASHBOARD_PAGE.md +19 -98
- package/skills/wix-app/references/DASHBOARD_PLUGIN.md +6 -108
- package/skills/wix-app/references/DATA_COLLECTION.md +113 -198
- package/skills/wix-app/references/EMBEDDED_SCRIPT.md +41 -268
- package/skills/wix-app/references/EXTENSION_REGISTRATION.md +27 -76
- package/skills/wix-app/references/SERVICE_PLUGIN.md +35 -188
- package/skills/wix-app/references/SITE_PLUGIN.md +8 -92
- package/skills/wix-app/references/backend-event/COMMON-EVENTS.md +0 -44
- package/skills/wix-app/references/custom-element-widget/SETTINGS_PANEL.md +19 -330
- package/skills/wix-app/references/dashboard-menu-plugin/bookings-slots.md +0 -12
- package/skills/wix-app/references/dashboard-menu-plugin/ecommerce-slots.md +7 -0
- package/skills/wix-app/references/dashboard-menu-plugin/restaurants-slots.md +0 -12
- package/skills/wix-app/references/dashboard-plugin/SLOTS.md +3 -15
- package/skills/wix-app/references/service-plugin/ADDITIONAL-FEES.md +2 -18
- package/skills/wix-app/references/service-plugin/BOOKINGS-STAFF-SORTING.md +2 -42
- package/skills/wix-app/references/service-plugin/DISCOUNT-TRIGGERS.md +1 -11
- package/skills/wix-app/references/service-plugin/GIFT-CARDS.md +1 -11
- package/skills/wix-app/references/service-plugin/PAYMENT-SETTINGS.md +2 -40
- package/skills/wix-app/references/service-plugin/SHIPPING-RATES.md +2 -19
- package/skills/wix-app/references/service-plugin/VALIDATIONS.md +2 -18
- package/skills/wix-app/references/site-plugin/SLOTS.md +17 -68
- package/skills/wix-headless/SKILL.md +111 -389
- package/skills/wix-headless/references/BUILD.md +307 -0
- package/skills/wix-headless/references/DESIGN_SYSTEM.md +115 -0
- package/skills/wix-headless/references/DISCOVERY.md +237 -112
- package/skills/wix-headless/references/PLAN.md +82 -0
- package/skills/wix-headless/references/SEED.md +205 -0
- package/skills/wix-headless/references/SETUP.md +140 -134
- package/skills/wix-headless/references/astro/COMPOSE.md +142 -0
- package/skills/wix-headless/references/{blog → astro/blog}/BLOG_PAGES.md +1 -1
- package/skills/wix-headless/references/{blog → astro/blog}/BLOG_SETUP.md +2 -2
- package/skills/wix-headless/references/astro/cms/CMS_FOUNDATIONS.md +214 -0
- package/skills/wix-headless/references/{cms → astro/cms}/FAQ_KNOWLEDGE_BASE.md +6 -4
- package/skills/wix-headless/references/{cms → astro/cms}/PORTFOLIO.md +5 -5
- package/skills/wix-headless/references/{cms → astro/cms}/RESOURCE_LIBRARY.md +5 -5
- package/skills/wix-headless/references/{cms → astro/cms}/TEAM_DIRECTORY.md +5 -5
- package/skills/wix-headless/references/astro/designer/INSTRUCTIONS.md +331 -0
- package/skills/wix-headless/references/{ecom → astro/ecom}/CART_PAGES.md +1 -1
- package/skills/wix-headless/references/{ecom → astro/ecom}/CART_WIRING.md +1 -1
- package/skills/wix-headless/references/{ecom → astro/ecom}/COMPONENTS_CSS.md +3 -3
- package/skills/wix-headless/references/{forms → astro/forms}/CONTACT_FORM.md +13 -13
- package/skills/wix-headless/references/{gift-cards → astro/gift-cards}/COMPONENTS.md +1 -1
- package/skills/wix-headless/references/{gift-cards → astro/gift-cards}/PAGES.md +1 -1
- package/skills/wix-headless/references/{stores → astro/stores}/BACK_IN_STOCK.md +1 -1
- package/skills/wix-headless/references/{stores → astro/stores}/CATEGORY_PAGES.md +12 -13
- package/skills/wix-headless/references/{stores → astro/stores}/COMPONENTS_CSS.md +4 -4
- package/skills/wix-headless/references/{stores → astro/stores}/HOME_AND_NAV.md +11 -9
- package/skills/wix-headless/references/{stores → astro/stores}/PRODUCT_PAGES.md +5 -3
- package/skills/wix-headless/references/{stores → astro/stores}/SHARED_WIRING.md +3 -3
- package/skills/wix-headless/references/astro/templates/Footer.astro +27 -0
- package/skills/wix-headless/references/astro/templates/Layout.astro +132 -0
- package/skills/wix-headless/references/astro/templates/Navigation.astro +38 -0
- package/skills/wix-headless/references/astro/templates/astro.config.mjs +41 -0
- package/skills/wix-headless/references/astro/templates/ecom/components-ecom.css +302 -0
- package/skills/wix-headless/references/astro/templates/global.css +286 -0
- package/skills/wix-headless/references/astro/templates/index.astro +56 -0
- package/skills/wix-headless/{templates → references/astro/templates}/stores/back-in-stock.ts +1 -1
- package/skills/wix-headless/{templates → references/astro/templates}/stores/components-stores.css +138 -33
- package/skills/wix-headless/references/blog/BLOG_CONTENT.md +10 -11
- package/skills/wix-headless/references/blog/INSTRUCTIONS.md +5 -5
- package/skills/wix-headless/references/cms/CMS_FOUNDATIONS.md +31 -230
- package/skills/wix-headless/references/cms/INSTRUCTIONS.md +13 -8
- package/skills/wix-headless/references/custom/INSTRUCTIONS.md +38 -0
- package/skills/wix-headless/references/ecom/INSTRUCTIONS.md +10 -10
- package/skills/wix-headless/references/forms/INSTRUCTIONS.md +5 -5
- package/skills/wix-headless/references/gift-cards/INSTRUCTIONS.md +11 -11
- package/skills/wix-headless/references/images/INSTRUCTIONS.md +47 -50
- package/skills/wix-headless/references/seed-recipes.md +49 -0
- package/skills/wix-headless/references/shared/AUTHENTICATION.md +110 -0
- package/skills/wix-headless/references/shared/BUILD_NOISE.md +2 -2
- package/skills/wix-headless/references/shared/DOCS_SEARCH.md +41 -0
- package/skills/wix-headless/references/shared/IMAGE_GENERATION.md +17 -17
- package/skills/wix-headless/references/shared/IMPLEMENTER.md +20 -29
- package/skills/wix-headless/references/shared/PRODUCTION_SHARP_EDGES.md +1 -1
- package/skills/wix-headless/references/shared/RETURN_CONTRACT.md +25 -16
- package/skills/wix-headless/references/shared/STYLING.md +47 -10
- package/skills/wix-headless/references/stores/INSTRUCTIONS.md +25 -25
- package/skills/wix-headless/references/stores/PRODUCT_CATALOG_DATA.md +17 -17
- package/skills/wix-headless/references/verticals/_schema.json +31 -117
- package/skills/wix-headless/references/verticals/_schema.md +60 -150
- package/skills/wix-headless/references/verticals/blog.md +5 -99
- package/skills/wix-headless/references/verticals/cms.md +9 -100
- package/skills/wix-headless/references/verticals/ecom.md +5 -76
- package/skills/wix-headless/references/verticals/forms.md +5 -85
- package/skills/wix-headless/references/verticals/gift-cards.md +6 -103
- package/skills/wix-headless/references/verticals/stores.md +10 -144
- package/skills/wix-headless/scripts/check-manifest.mjs +5 -5
- package/skills/wix-headless/scripts/emit-design-tokens.mjs +29 -23
- package/skills/wix-headless/scripts/init-site-json.mjs +59 -21
- package/skills/wix-headless/scripts/patch-decorative-slots.mjs +67 -43
- package/skills/wix-headless/scripts/plan-entity-image-waves.mjs +3 -3
- package/skills/wix-headless/scripts/preview.sh +3 -3
- package/skills/wix-headless/scripts/release.sh +4 -4
- package/skills/wix-headless/scripts/scaffold.sh +75 -20
- package/skills/wix-headless/scripts/seed-utilities.sh +50 -12
- package/skills/wix-manage/SKILL.md +4 -8
- package/skills/wix-manage/references/blog/how-to-create-blog-posts.md +2 -0
- package/skills/wix-manage/references/cms/cms-data-items-crud.md +4 -0
- package/skills/wix-manage/references/cms/cms-references-and-relationships.md +2 -0
- package/skills/wix-manage/references/cms/cms-schema-management.md +4 -0
- package/skills/wix-manage/references/ecommerce/api-shipping.md +443 -0
- package/skills/wix-manage/references/ecommerce/flow-add-free-shipping.md +5 -6
- package/skills/wix-manage/references/ecommerce/flow-fix-coverage-gaps.md +4 -5
- package/skills/wix-manage/references/ecommerce/flow-optimize-shipping-rates.md +4 -5
- package/skills/wix-manage/references/ecommerce/goal-increase-aov.md +1 -1
- package/skills/wix-manage/references/ecommerce/goal-reduce-cart-abandonment.md +1 -2
- package/skills/wix-manage/references/ecommerce/guardrail-shipping-health.md +2 -2
- package/skills/wix-manage/references/ecommerce/recipe-apply-shipping-recommendations.md +4 -5
- package/skills/wix-manage/references/ecommerce/recommend-ecommerce-strategy.md +7 -7
- package/skills/wix-manage/references/ecommerce/setup-discount-rules.md +209 -72
- package/skills/wix-manage/references/ecommerce/setup-store-pickup-location.md +9 -10
- package/skills/wix-manage/references/ecommerce/skill-graph.md +4 -4
- package/skills/wix-manage/references/forms/create-form.md +2 -0
- package/skills/wix-manage/references/stores/bulk-create-products-with-options.md +2 -0
- package/skills/wix-manage/references/stores/create-product-from-image.md +91 -38
- package/skills/wix-manage/references/stores/setup-online-store-catalog-v3.md +2 -0
- package/skills/wix-app/references/custom-element-widget/default-thumbnail.png +0 -0
- package/skills/wix-app/references/data-collection/extension-template.ts +0 -107
- package/skills/wix-headless/references/ORCHESTRATION.md +0 -269
- package/skills/wix-headless/references/commands/install-app.md +0 -42
- package/skills/wix-headless/references/commands/mcp-bootstrap.md +0 -28
- package/skills/wix-headless/references/designer/INSTRUCTIONS.md +0 -828
- package/skills/wix-headless/references/shared/MCP_PREFIX.md +0 -105
- package/skills/wix-headless/scripts/copy-utility-templates.mjs +0 -153
- package/skills/wix-headless/templates/ecom/components-ecom.css +0 -215
- package/skills/wix-manage/references/events/list-events.md +0 -203
- /package/skills/wix-headless/{templates → references/astro/templates}/ecom/CartBadge.tsx +0 -0
- /package/skills/wix-headless/{templates → references/astro/templates}/ecom/CartView.tsx +0 -0
- /package/skills/wix-headless/{templates → references/astro/templates}/ecom/cart.astro +0 -0
- /package/skills/wix-headless/{templates → references/astro/templates}/ecom/discounts.ts +0 -0
- /package/skills/wix-headless/{templates → references/astro/templates}/ecom/thank-you.astro +0 -0
- /package/skills/wix-headless/{templates → references/astro/templates}/gift-cards/GiftCardPurchase.tsx +0 -0
- /package/skills/wix-headless/{templates → references/astro/templates}/gift-cards/_home-teaser-snippet.astro +0 -0
- /package/skills/wix-headless/{templates → references/astro/templates}/gift-cards/_nav-snippet.astro +0 -0
- /package/skills/wix-headless/{templates → references/astro/templates}/gift-cards/components-gift-cards.css +0 -0
- /package/skills/wix-headless/{templates → references/astro/templates}/gift-cards/gift-cards.astro +0 -0
- /package/skills/wix-headless/{templates → references/astro/templates}/gift-cards/gift-cards.ts +0 -0
- /package/skills/wix-headless/{templates → references/astro/templates}/stores/AddToCartButton.tsx +0 -0
- /package/skills/wix-headless/{templates → references/astro/templates}/stores/BackInStockForm.tsx +0 -0
- /package/skills/wix-headless/{templates → references/astro/templates}/stores/CategoryRail.astro +0 -0
- /package/skills/wix-headless/{templates → references/astro/templates}/stores/ProductCard.astro +0 -0
- /package/skills/wix-headless/{templates → references/astro/templates}/stores/ProductPurchase.tsx +0 -0
- /package/skills/wix-headless/{templates → references/astro/templates}/stores/SeoTags.astro +0 -0
- /package/skills/wix-headless/{templates → references/astro/templates}/stores/categories.ts +0 -0
- /package/skills/wix-headless/{templates → references/astro/templates}/stores/category/[slug].astro +0 -0
- /package/skills/wix-headless/{templates → references/astro/templates}/stores/products/[slug].astro +0 -0
- /package/skills/wix-headless/{templates → references/astro/templates}/stores/products/index.astro +0 -0
|
@@ -3,7 +3,7 @@
|
|
|
3
3
|
//
|
|
4
4
|
// Verifies that every file declared in each loaded pack's `creates:` array
|
|
5
5
|
// for the named phase exists on disk. If a file is missing, attempts to
|
|
6
|
-
// recover by copying the canonical template from <SKILL_ROOT>/templates/<pack>/.
|
|
6
|
+
// recover by copying the canonical template from <SKILL_ROOT>/references/astro/templates/<pack>/.
|
|
7
7
|
// Outputs a JSON summary of present / recovered / errored files.
|
|
8
8
|
//
|
|
9
9
|
// Usage (both modes work):
|
|
@@ -26,7 +26,7 @@
|
|
|
26
26
|
// `creates:` array.
|
|
27
27
|
// - For each `creates:` entry where phase matches:
|
|
28
28
|
// * If file exists in the project → "present"
|
|
29
|
-
// * If missing AND a template exists at `templates/<pack>/<tail>`
|
|
29
|
+
// * If missing AND a template exists at `references/astro/templates/<pack>/<tail>`
|
|
30
30
|
// (where <tail> is the path under src/pages/ for page files, or the
|
|
31
31
|
// basename for everything else) → copy/fetch it; record as "recovered".
|
|
32
32
|
// * Otherwise → record as "missing" with a remediation hint.
|
|
@@ -101,12 +101,12 @@ if (phase !== "components" && phase !== "pages") {
|
|
|
101
101
|
const packs = packsCsv.split(",").map((p) => p.trim()).filter(Boolean);
|
|
102
102
|
|
|
103
103
|
// Map a `creates:` file path to its template path (relative to skill root).
|
|
104
|
-
// Heuristic: `src/pages/<X>` preserves <X> under templates/<pack>/;
|
|
105
|
-
// else uses basename only.
|
|
104
|
+
// Heuristic: `src/pages/<X>` preserves <X> under references/astro/templates/<pack>/;
|
|
105
|
+
// everything else uses basename only.
|
|
106
106
|
function templateRelPath(packName, srcPath) {
|
|
107
107
|
const pagesMatch = srcPath.match(/^src\/pages\/(.+)$/);
|
|
108
108
|
const tail = pagesMatch ? pagesMatch[1] : basename(srcPath);
|
|
109
|
-
return `templates/${packName}/${tail}`;
|
|
109
|
+
return `references/astro/templates/${packName}/${tail}`;
|
|
110
110
|
}
|
|
111
111
|
|
|
112
112
|
// Parse `creates:` block from a vertical pack's markdown frontmatter.
|
|
@@ -1,45 +1,58 @@
|
|
|
1
1
|
#!/usr/bin/env node
|
|
2
|
-
// Generate .wix/design-tokens.css and .wix/site.d.ts deterministically from
|
|
3
|
-
//
|
|
4
|
-
// after the Phase 2 Design System agent
|
|
2
|
+
// Generate .wix/design-tokens.css and .wix/site.d.ts deterministically from a
|
|
3
|
+
// designTokens JSON payload piped in on stdin. Invoked by the wix-headless
|
|
4
|
+
// skill orchestrator immediately after the Phase 2 Design System agent
|
|
5
|
+
// returns — the orchestrator pipes designerReturn.data.designTokens directly,
|
|
6
|
+
// no site.json round-trip.
|
|
5
7
|
//
|
|
6
8
|
// Why a script (not agent work): both files are pure projections of the
|
|
7
9
|
// designTokens JSON — no judgment, no brand-context dependence. An LLM
|
|
8
10
|
// emitting them is wasted tokens AND a drift risk (malformed :root blocks,
|
|
9
11
|
// missing token groups, divergent .d.ts skeletons).
|
|
12
|
+
//
|
|
13
|
+
// Usage:
|
|
14
|
+
// echo '<designTokens-json>' | node emit-design-tokens.mjs <project-dir>
|
|
10
15
|
|
|
11
16
|
import { readFileSync, writeFileSync, mkdirSync } from "node:fs";
|
|
12
17
|
import { join } from "node:path";
|
|
13
18
|
|
|
14
19
|
const projectDir = process.argv[2] ?? process.cwd();
|
|
15
|
-
const sitePath = join(projectDir, ".wix/site.json");
|
|
16
20
|
|
|
17
|
-
|
|
21
|
+
if (process.stdin.isTTY) {
|
|
22
|
+
console.error("emit-design-tokens: expected designTokens JSON on stdin (pipe in the designer's data.designTokens block)");
|
|
23
|
+
process.exit(2);
|
|
24
|
+
}
|
|
25
|
+
|
|
26
|
+
let tokens;
|
|
18
27
|
try {
|
|
19
|
-
|
|
28
|
+
const raw = readFileSync(0, "utf8").trim();
|
|
29
|
+
if (!raw) {
|
|
30
|
+
console.error("emit-design-tokens: stdin was empty — pass the designTokens JSON object");
|
|
31
|
+
process.exit(2);
|
|
32
|
+
}
|
|
33
|
+
tokens = JSON.parse(raw);
|
|
20
34
|
} catch (e) {
|
|
21
|
-
console.error(`emit-design-tokens:
|
|
22
|
-
process.exit(
|
|
35
|
+
console.error(`emit-design-tokens: stdin is not valid JSON (${e.message})`);
|
|
36
|
+
process.exit(2);
|
|
23
37
|
}
|
|
24
38
|
|
|
25
|
-
|
|
26
|
-
|
|
27
|
-
|
|
28
|
-
process.exit(1);
|
|
39
|
+
if (!tokens || typeof tokens !== "object" || Array.isArray(tokens) || Object.keys(tokens).length === 0) {
|
|
40
|
+
console.error("emit-design-tokens: designTokens payload must be a non-empty JSON object");
|
|
41
|
+
process.exit(2);
|
|
29
42
|
}
|
|
30
43
|
|
|
31
44
|
const wixDir = join(projectDir, ".wix");
|
|
32
45
|
mkdirSync(wixDir, { recursive: true });
|
|
33
46
|
|
|
34
|
-
// .wix/design-tokens.css ----------------------------------------------------
|
|
35
47
|
const PREFIX = {
|
|
36
48
|
colors: "--color-",
|
|
37
49
|
fonts: "--font-",
|
|
38
50
|
radii: "--radius-",
|
|
39
51
|
spacing: "--spacing-",
|
|
52
|
+
containers: "--container-",
|
|
40
53
|
};
|
|
41
54
|
|
|
42
|
-
const cssLines = ["/* Generated
|
|
55
|
+
const cssLines = ["/* Generated by emit-design-tokens.mjs. Do not edit. */", ":root {"];
|
|
43
56
|
for (const [group, prefix] of Object.entries(PREFIX)) {
|
|
44
57
|
const entries = tokens[group] ?? {};
|
|
45
58
|
for (const [key, value] of Object.entries(entries)) {
|
|
@@ -49,7 +62,6 @@ for (const [group, prefix] of Object.entries(PREFIX)) {
|
|
|
49
62
|
cssLines.push("}", "");
|
|
50
63
|
writeFileSync(join(wixDir, "design-tokens.css"), cssLines.join("\n"));
|
|
51
64
|
|
|
52
|
-
// .wix/site.d.ts ------------------------------------------------------------
|
|
53
65
|
const typeFor = (group) => {
|
|
54
66
|
const keys = Object.keys(tokens[group] ?? {});
|
|
55
67
|
if (keys.length === 0) return "Record<string, string>";
|
|
@@ -57,19 +69,13 @@ const typeFor = (group) => {
|
|
|
57
69
|
return `Record<${literal}, string>`;
|
|
58
70
|
};
|
|
59
71
|
|
|
60
|
-
const dts = `// Generated
|
|
61
|
-
export type Brand = { name: string; description: string };
|
|
72
|
+
const dts = `// Generated by emit-design-tokens.mjs. Do not edit.
|
|
62
73
|
export type DesignTokens = {
|
|
63
74
|
colors: ${typeFor("colors")};
|
|
64
75
|
fonts: ${typeFor("fonts")};
|
|
65
76
|
radii: ${typeFor("radii")};
|
|
66
77
|
spacing: ${typeFor("spacing")};
|
|
67
|
-
};
|
|
68
|
-
export type Product = { id: string; name: string; slug: string; price: number; variantId: string };
|
|
69
|
-
export declare const site: {
|
|
70
|
-
brand: Brand;
|
|
71
|
-
designTokens: DesignTokens;
|
|
72
|
-
seeded: { products?: Product[]; posts?: unknown[]; collections?: Record<string, unknown[]> };
|
|
78
|
+
containers: ${typeFor("containers")};
|
|
73
79
|
};
|
|
74
80
|
`;
|
|
75
81
|
writeFileSync(join(wixDir, "site.d.ts"), dts);
|
|
@@ -1,30 +1,70 @@
|
|
|
1
1
|
#!/usr/bin/env node
|
|
2
|
-
// Write the initial .wix/site.json
|
|
3
|
-
//
|
|
4
|
-
//
|
|
5
|
-
//
|
|
6
|
-
// to be LLM-emitted JSON, with the obvious drift risks).
|
|
2
|
+
// Write the initial .wix/site.json — slim metadata snapshot for resume
|
|
3
|
+
// detection + run.json composition. Subagents do NOT read this file during
|
|
4
|
+
// the run; the orchestrator is the sole reader/writer and inlines anything
|
|
5
|
+
// downstream phases need into their prompts.
|
|
7
6
|
//
|
|
8
|
-
//
|
|
9
|
-
//
|
|
7
|
+
// Final shape:
|
|
8
|
+
// {
|
|
9
|
+
// "brand": { "name": "...", "description": "..." },
|
|
10
|
+
// "frontend": "astro" | "custom",
|
|
11
|
+
// "verticals": ["stores", "cms", ...],
|
|
12
|
+
// "siteId": "..." (optional — Setup Step 1 may patch later),
|
|
13
|
+
// "appId": "..." (optional — Setup Step 1 may patch later)
|
|
14
|
+
// }
|
|
10
15
|
//
|
|
11
|
-
//
|
|
12
|
-
// node init-site-json.mjs
|
|
16
|
+
// Usage:
|
|
17
|
+
// node init-site-json.mjs <project-dir> <brand-name> <brand-description> \
|
|
18
|
+
// <verticals-csv> --frontend <astro|custom> \
|
|
19
|
+
// [--site-id <id>] [--app-id <id>]
|
|
20
|
+
// (In practice only "astro" reaches this step — custom frontends route to the
|
|
21
|
+
// not-available stub before Discovery's approval/site.json write.)
|
|
13
22
|
//
|
|
14
23
|
// Behavior:
|
|
15
24
|
// - Refuses to overwrite an existing .wix/site.json (exit 2). The orchestrator
|
|
16
|
-
// should call this exactly once during
|
|
17
|
-
// caller can rm the file first.
|
|
25
|
+
// should call this exactly once during Discovery's "After Approval" step.
|
|
26
|
+
// To re-init for testing, the caller can rm the file first.
|
|
18
27
|
// - Creates .wix/ if it doesn't exist.
|
|
19
28
|
// - Outputs a JSON summary to stdout.
|
|
20
29
|
|
|
21
30
|
import { writeFileSync, existsSync, mkdirSync } from "node:fs";
|
|
22
31
|
import { join } from "node:path";
|
|
23
32
|
|
|
24
|
-
const
|
|
33
|
+
const ALLOWED_FRONTENDS = new Set(["astro", "custom"]);
|
|
34
|
+
|
|
35
|
+
let frontend = "astro";
|
|
36
|
+
let siteId;
|
|
37
|
+
let appId;
|
|
38
|
+
const positional = [];
|
|
39
|
+
const rawArgs = process.argv.slice(2);
|
|
40
|
+
for (let i = 0; i < rawArgs.length; i++) {
|
|
41
|
+
const arg = rawArgs[i];
|
|
42
|
+
if (arg === "--frontend") {
|
|
43
|
+
frontend = rawArgs[++i];
|
|
44
|
+
} else if (arg.startsWith("--frontend=")) {
|
|
45
|
+
frontend = arg.slice("--frontend=".length);
|
|
46
|
+
} else if (arg === "--site-id") {
|
|
47
|
+
siteId = rawArgs[++i];
|
|
48
|
+
} else if (arg.startsWith("--site-id=")) {
|
|
49
|
+
siteId = arg.slice("--site-id=".length);
|
|
50
|
+
} else if (arg === "--app-id") {
|
|
51
|
+
appId = rawArgs[++i];
|
|
52
|
+
} else if (arg.startsWith("--app-id=")) {
|
|
53
|
+
appId = arg.slice("--app-id=".length);
|
|
54
|
+
} else {
|
|
55
|
+
positional.push(arg);
|
|
56
|
+
}
|
|
57
|
+
}
|
|
58
|
+
|
|
59
|
+
if (!ALLOWED_FRONTENDS.has(frontend)) {
|
|
60
|
+
console.error(`init-site-json: --frontend must be one of ${[...ALLOWED_FRONTENDS].join(", ")}; got ${JSON.stringify(frontend)}`);
|
|
61
|
+
process.exit(2);
|
|
62
|
+
}
|
|
63
|
+
|
|
64
|
+
const [projectDir, brandName, brandDescription, verticalsCsv] = positional;
|
|
25
65
|
|
|
26
66
|
if (!projectDir || !brandName || brandDescription === undefined || !verticalsCsv) {
|
|
27
|
-
console.error("usage: init-site-json.mjs <project-dir> <brand-name> <brand-description> <verticals-csv>");
|
|
67
|
+
console.error("usage: init-site-json.mjs <project-dir> <brand-name> <brand-description> <verticals-csv> --frontend <astro|custom> [--site-id <id>] [--app-id <id>]");
|
|
28
68
|
process.exit(2);
|
|
29
69
|
}
|
|
30
70
|
|
|
@@ -42,22 +82,20 @@ const wixDir = join(projectDir, ".wix");
|
|
|
42
82
|
const sitePath = join(wixDir, "site.json");
|
|
43
83
|
|
|
44
84
|
if (existsSync(sitePath)) {
|
|
45
|
-
console.error(`init-site-json: ${sitePath} already exists — refusing to overwrite.
|
|
85
|
+
console.error(`init-site-json: ${sitePath} already exists — refusing to overwrite. Discovery should call this exactly once.`);
|
|
46
86
|
process.exit(2);
|
|
47
87
|
}
|
|
48
88
|
|
|
49
89
|
mkdirSync(wixDir, { recursive: true });
|
|
50
90
|
|
|
51
91
|
const site = {
|
|
52
|
-
brand: {
|
|
53
|
-
|
|
54
|
-
description: brandDescription,
|
|
55
|
-
},
|
|
56
|
-
seeded: {},
|
|
57
|
-
designTokens: {},
|
|
92
|
+
brand: { name: brandName, description: brandDescription },
|
|
93
|
+
frontend,
|
|
58
94
|
verticals,
|
|
59
95
|
};
|
|
96
|
+
if (siteId) site.siteId = siteId;
|
|
97
|
+
if (appId) site.appId = appId;
|
|
60
98
|
|
|
61
99
|
writeFileSync(sitePath, JSON.stringify(site, null, 2) + "\n");
|
|
62
100
|
|
|
63
|
-
console.log(JSON.stringify({ status: "ok", path: sitePath, verticals }, null, 2));
|
|
101
|
+
console.log(JSON.stringify({ status: "ok", path: sitePath, frontend, verticals, ...(siteId ? { siteId } : {}), ...(appId ? { appId } : {}) }, null, 2));
|
|
@@ -1,59 +1,88 @@
|
|
|
1
1
|
#!/usr/bin/env node
|
|
2
|
-
// Inject Image-Phase-1 decorative URLs into the
|
|
2
|
+
// Inject Image-Phase-1 decorative URLs into the page shells.
|
|
3
3
|
//
|
|
4
|
-
// The Phase
|
|
5
|
-
// placeholders in src/pages/*.astro. Image Phase 1
|
|
6
|
-
//
|
|
7
|
-
//
|
|
8
|
-
//
|
|
4
|
+
// The design-system Composer (index.astro) and the Phase 4 page designers write
|
|
5
|
+
// `<div data-decorative-slot="<key>">…</div>` placeholders in src/pages/*.astro. Image Phase 1 returns a slot→URL map
|
|
6
|
+
// in its JSON return; the orchestrator pipes that map (as JSON) into this
|
|
7
|
+
// script's stdin. This script reads the map + walks src/pages/*.astro,
|
|
8
|
+
// then injects an <img> as the first child of each matching slot div —
|
|
9
|
+
// pure string substitution, no LLM, no file rewrites.
|
|
9
10
|
//
|
|
10
11
|
// Usage:
|
|
11
|
-
//
|
|
12
|
+
// echo '{"hero":"https://...","about":"https://..."}' \
|
|
13
|
+
// | node patch-decorative-slots.mjs <scaffold-dir>
|
|
14
|
+
//
|
|
15
|
+
// <scaffold-dir> is the dir that contains src/pages/. The orchestrator
|
|
16
|
+
// passes the scaffold subdir explicitly — no eval-dir vs scaffold-dir
|
|
17
|
+
// auto-detection is needed for the URL map (it's on stdin), but src/pages
|
|
18
|
+
// is still resolved per-input since the orchestrator may call this from
|
|
19
|
+
// either the scaffold subdir or the eval root.
|
|
12
20
|
//
|
|
13
21
|
// Behavior:
|
|
14
|
-
// -
|
|
15
|
-
//
|
|
22
|
+
// - Empty stdin or no slot→URL pairs → exit 0 status="skipped" (themed-
|
|
23
|
+
// blocks mode or Image Phase 1 had no URLs to publish).
|
|
24
|
+
// - src/pages missing at <scaffold-dir> and in any single subdir one
|
|
25
|
+
// level down → exit 2 status="error".
|
|
16
26
|
// - For each `data-decorative-slot="<key>"` in src/pages/*.astro:
|
|
17
|
-
// *
|
|
18
|
-
// *
|
|
19
|
-
// than whitespace/comments → skip with a warning (don't clobber).
|
|
27
|
+
// * Key has no URL in the input map → leave the div alone.
|
|
28
|
+
// * Div already has a non-comment child → skip with a warning.
|
|
20
29
|
// * Otherwise inject <img …> as the first child.
|
|
21
|
-
// - Output
|
|
22
|
-
// - Exit 0 even when some slots couldn't be patched — placeholders fall
|
|
23
|
-
// back to the designer's aspect-ratio + background-color rendering.
|
|
30
|
+
// - Output JSON summary of patches/skips/warnings to stdout.
|
|
24
31
|
|
|
25
32
|
import { readFileSync, writeFileSync, existsSync, readdirSync, statSync } from "node:fs";
|
|
26
33
|
import { join } from "node:path";
|
|
27
34
|
|
|
28
35
|
const projectDir = process.argv[2] ?? process.cwd();
|
|
29
36
|
|
|
30
|
-
|
|
31
|
-
if (!
|
|
32
|
-
|
|
37
|
+
let urlMap = {};
|
|
38
|
+
if (!process.stdin.isTTY) {
|
|
39
|
+
const raw = readFileSync(0, "utf8").trim();
|
|
40
|
+
if (raw) {
|
|
41
|
+
try {
|
|
42
|
+
urlMap = JSON.parse(raw);
|
|
43
|
+
} catch (e) {
|
|
44
|
+
console.error(JSON.stringify({ status: "error", reason: `stdin is not valid JSON (${e.message})` }));
|
|
45
|
+
process.exit(2);
|
|
46
|
+
}
|
|
47
|
+
if (!urlMap || typeof urlMap !== "object" || Array.isArray(urlMap)) {
|
|
48
|
+
console.error(JSON.stringify({ status: "error", reason: "expected a JSON object mapping slot keys to URLs" }));
|
|
49
|
+
process.exit(2);
|
|
50
|
+
}
|
|
51
|
+
}
|
|
52
|
+
}
|
|
53
|
+
|
|
54
|
+
if (Object.keys(urlMap).length === 0) {
|
|
55
|
+
console.log(JSON.stringify({ status: "skipped", reason: "no slot→URL pairs on stdin (themed-blocks mode or Image Phase 1 produced none)" }));
|
|
33
56
|
process.exit(0);
|
|
34
57
|
}
|
|
35
58
|
|
|
36
|
-
|
|
37
|
-
const
|
|
38
|
-
|
|
39
|
-
|
|
40
|
-
|
|
41
|
-
|
|
42
|
-
|
|
43
|
-
|
|
44
|
-
|
|
45
|
-
|
|
46
|
-
|
|
59
|
+
function findPagesDir() {
|
|
60
|
+
const direct = join(projectDir, "src/pages");
|
|
61
|
+
if (existsSync(direct)) return { path: direct, source: "projectDir" };
|
|
62
|
+
const hits = [];
|
|
63
|
+
for (const entry of readdirSync(projectDir, { withFileTypes: true })) {
|
|
64
|
+
if (!entry.isDirectory() || entry.name.startsWith(".")) continue;
|
|
65
|
+
const candidate = join(projectDir, entry.name, "src/pages");
|
|
66
|
+
if (existsSync(candidate)) hits.push(candidate);
|
|
67
|
+
}
|
|
68
|
+
if (hits.length === 1) return { path: hits[0], source: "scaffold-subdir" };
|
|
69
|
+
if (hits.length > 1) return { path: null, source: "ambiguous", hits };
|
|
70
|
+
return { path: null, source: "missing" };
|
|
47
71
|
}
|
|
48
72
|
|
|
49
|
-
|
|
50
|
-
|
|
51
|
-
|
|
73
|
+
const pagesResolved = findPagesDir();
|
|
74
|
+
if (!pagesResolved.path) {
|
|
75
|
+
console.error(JSON.stringify({
|
|
76
|
+
status: "error",
|
|
77
|
+
reason: "src/pages not found at <projectDir>/src/pages or in any scaffold subdir; pass the scaffold dir explicitly",
|
|
78
|
+
projectDir,
|
|
79
|
+
pagesSearchedAt: pagesResolved.source === "ambiguous" ? pagesResolved.hits : [join(projectDir, "src/pages")],
|
|
80
|
+
}, null, 2));
|
|
81
|
+
process.exit(2);
|
|
52
82
|
}
|
|
53
83
|
|
|
54
|
-
|
|
55
|
-
|
|
56
|
-
const pagesDir = join(projectDir, "src/pages");
|
|
84
|
+
const pagesDir = pagesResolved.path;
|
|
85
|
+
|
|
57
86
|
const candidates = [];
|
|
58
87
|
const walk = (dir) => {
|
|
59
88
|
if (!existsSync(dir)) return;
|
|
@@ -80,22 +109,17 @@ for (const file of candidates) {
|
|
|
80
109
|
modified = modified.replace(SLOT_DIV_REGEX, (match, openTag, slotKey, inner, closeTag) => {
|
|
81
110
|
const url = urlMap[slotKey];
|
|
82
111
|
if (!url) {
|
|
83
|
-
skipped.push({ file, slot: slotKey, reason: "no URL for this slot in
|
|
112
|
+
skipped.push({ file, slot: slotKey, reason: "no URL for this slot in input map" });
|
|
84
113
|
return match;
|
|
85
114
|
}
|
|
86
115
|
|
|
87
|
-
// Strip HTML comments before any content checks — the designer's placeholder
|
|
88
|
-
// is a comment like `<!-- orchestrator injects <img> here -->`, which would
|
|
89
|
-
// otherwise false-positive both the idempotency and clobber-guard checks.
|
|
90
116
|
const stripped = inner.replace(/<!--[\s\S]*?-->/g, "").trim();
|
|
91
117
|
|
|
92
|
-
// Skip if div already contains an <img> element (idempotency).
|
|
93
118
|
if (/<img\b/i.test(stripped)) {
|
|
94
119
|
skipped.push({ file, slot: slotKey, reason: "div already contains an <img> tag (idempotent skip)" });
|
|
95
120
|
return match;
|
|
96
121
|
}
|
|
97
122
|
|
|
98
|
-
// Skip if div has substantive child content beyond whitespace/comments.
|
|
99
123
|
if (stripped.length > 0) {
|
|
100
124
|
warnings.push({ file, slot: slotKey, reason: "div has existing non-image child content; not patching to avoid clobber" });
|
|
101
125
|
return match;
|
|
@@ -104,7 +128,6 @@ for (const file of candidates) {
|
|
|
104
128
|
fileChanged = true;
|
|
105
129
|
const img = `<img src="${url}" alt="" loading="lazy" decoding="async" class="decorative-slot-img" />`;
|
|
106
130
|
patched.push({ file, slot: slotKey });
|
|
107
|
-
// Preserve any whitespace inside the div (e.g., the newline + indent).
|
|
108
131
|
return `${openTag}\n ${img}${inner}${closeTag}`;
|
|
109
132
|
});
|
|
110
133
|
|
|
@@ -115,10 +138,11 @@ for (const file of candidates) {
|
|
|
115
138
|
|
|
116
139
|
const summary = {
|
|
117
140
|
status: warnings.length > 0 ? "partial" : "ok",
|
|
118
|
-
|
|
141
|
+
slots: Object.keys(urlMap),
|
|
119
142
|
filesScanned: candidates.length,
|
|
120
143
|
patched,
|
|
121
144
|
skipped,
|
|
122
145
|
warnings,
|
|
146
|
+
pagesFrom: pagesResolved.source,
|
|
123
147
|
};
|
|
124
148
|
console.log(JSON.stringify(summary, null, 2));
|
|
@@ -9,8 +9,8 @@
|
|
|
9
9
|
//
|
|
10
10
|
// waves — Runware generation requests, grouped into waves of <waveSize>
|
|
11
11
|
// (default 3) to match the google:4@2 throttle. Each wave is
|
|
12
|
-
// one orchestration step with N parallel
|
|
13
|
-
//
|
|
12
|
+
// one orchestration step with N parallel curls in one shell,
|
|
13
|
+
// backgrounded with `&`; each curl sends one task in the body array.
|
|
14
14
|
//
|
|
15
15
|
// imports — POST /site-media/v1/files/import requests, one per generated
|
|
16
16
|
// image. Indexed by taskUUID so the orchestrator threads the
|
|
@@ -155,7 +155,7 @@ for (const p of prompts) {
|
|
|
155
155
|
process.exit(1);
|
|
156
156
|
}
|
|
157
157
|
// Read-merge-PUT: echo every existing data field, set the image field
|
|
158
|
-
// to the placeholder URL.
|
|
158
|
+
// to the placeholder URL. Echoing every existing field is what prevents wiping the rest of the record.
|
|
159
159
|
const mergedData = { ...detail.data, [detail.imageField]: "__IMAGE_URL__" };
|
|
160
160
|
patches.push({
|
|
161
161
|
taskUUID: p.taskUUID,
|
|
@@ -6,7 +6,7 @@
|
|
|
6
6
|
#
|
|
7
7
|
# Run from the project directory (CWD = <project>/). Requires wix.config.json.
|
|
8
8
|
#
|
|
9
|
-
# Output: stdout is the preview URL that `npx @wix/cli preview` printed; the
|
|
9
|
+
# Output: stdout is the preview URL that `npx @wix/cli@latest preview` printed; the
|
|
10
10
|
# orchestrator captures it and records as outcome.previewUrl in run.json. All
|
|
11
11
|
# other CLI output goes to stderr.
|
|
12
12
|
#
|
|
@@ -23,14 +23,14 @@
|
|
|
23
23
|
set -euo pipefail
|
|
24
24
|
|
|
25
25
|
# Build first; surface compile errors verbatim if it fails.
|
|
26
|
-
npx @wix/cli build 1>&2
|
|
26
|
+
npx @wix/cli@latest build 1>&2
|
|
27
27
|
|
|
28
28
|
# Preview captures the deployed URL on stdout. We tee its output to stderr for
|
|
29
29
|
# the user-visible log AND parse the URL out for the orchestrator's stdout.
|
|
30
30
|
PREVIEW_OUTPUT="$(mktemp)"
|
|
31
31
|
trap 'rm -f "$PREVIEW_OUTPUT"' EXIT
|
|
32
32
|
|
|
33
|
-
npx @wix/cli preview 2>&1 | tee "$PREVIEW_OUTPUT" 1>&2
|
|
33
|
+
npx @wix/cli@latest preview 2>&1 | tee "$PREVIEW_OUTPUT" 1>&2
|
|
34
34
|
|
|
35
35
|
# Wix CLI prints `Site preview URL: <url>` (or similar) — extract the first
|
|
36
36
|
# https URL from the output. If multiple are printed, the first is the canonical
|
|
@@ -9,7 +9,7 @@
|
|
|
9
9
|
#
|
|
10
10
|
# Run from the project directory (CWD = <project>/). Requires wix.config.json.
|
|
11
11
|
#
|
|
12
|
-
# Output: stdout is the released URL that `npx @wix/cli release` printed
|
|
12
|
+
# Output: stdout is the released URL that `npx @wix/cli@latest release` printed
|
|
13
13
|
# (extracted from the line `Site published on <url>`); the orchestrator
|
|
14
14
|
# captures it as outcome.releaseUrl in run.json. All other CLI output goes
|
|
15
15
|
# to stderr.
|
|
@@ -19,12 +19,12 @@
|
|
|
19
19
|
# <other> — build or release failed; stderr surfaces the underlying error.
|
|
20
20
|
# Build failures are code bugs (TypeScript / Astro / missing
|
|
21
21
|
# module) — the orchestrator does NOT retry. Release auth failures
|
|
22
|
-
# surface as `Run npx @wix/cli login and retry.`
|
|
22
|
+
# surface as `Run npx @wix/cli@latest login and retry.`
|
|
23
23
|
# Known transient release failures are retried by this script.
|
|
24
24
|
|
|
25
25
|
set -euo pipefail
|
|
26
26
|
|
|
27
|
-
npx @wix/cli build 1>&2
|
|
27
|
+
npx @wix/cli@latest build 1>&2
|
|
28
28
|
|
|
29
29
|
RELEASE_OUTPUT="$(mktemp)"
|
|
30
30
|
trap 'rm -f "$RELEASE_OUTPUT"' EXIT
|
|
@@ -39,7 +39,7 @@ RELEASE_STATUS=1
|
|
|
39
39
|
for ((attempt = 1; attempt <= MAX_RELEASE_ATTEMPTS; attempt++)); do
|
|
40
40
|
: >"$RELEASE_OUTPUT"
|
|
41
41
|
set +e
|
|
42
|
-
npx @wix/cli release 2>&1 | tee "$RELEASE_OUTPUT" 1>&2
|
|
42
|
+
npx @wix/cli@latest release 2>&1 | tee "$RELEASE_OUTPUT" 1>&2
|
|
43
43
|
RELEASE_STATUS=${PIPESTATUS[0]}
|
|
44
44
|
set -e
|
|
45
45
|
|
|
@@ -1,53 +1,108 @@
|
|
|
1
1
|
#!/usr/bin/env bash
|
|
2
|
-
# Scaffold a new Wix Managed Headless project
|
|
2
|
+
# Scaffold a new Wix Managed Headless project using the CLI's preset blank template.
|
|
3
3
|
#
|
|
4
4
|
# Usage:
|
|
5
|
-
# bash <SKILL_ROOT>/scripts/scaffold.sh <project-slug> "<Brand Name>"
|
|
5
|
+
# bash <SKILL_ROOT>/scripts/scaffold.sh <project-slug> "<Brand Name>" [--frontend astro|custom]
|
|
6
6
|
#
|
|
7
7
|
# <project-slug>: 3-20 lowercase alphanumeric chars (no hyphens, no spaces) — the
|
|
8
8
|
# Wix CLI rejects anything else. Becomes the project directory name.
|
|
9
9
|
# <Brand Name>: human-readable business name; quote if it contains spaces.
|
|
10
|
+
# --frontend: the frontend axis. Defaults to "astro" — the only supported (and
|
|
11
|
+
# only scaffolded) frontend. "custom" (any non-astro frontend) is
|
|
12
|
+
# NOT scaffolded yet: Discovery routes custom to the not-available
|
|
13
|
+
# stub (references/custom/INSTRUCTIONS.md) before scaffold ever runs,
|
|
14
|
+
# so this script should only ever be invoked with "astro". If it is
|
|
15
|
+
# invoked with "custom" it exits 4 (recognized, not staged).
|
|
10
16
|
#
|
|
11
17
|
# After scaffold succeeds, read <project-slug>/wix.config.json to extract appId
|
|
12
|
-
# (project's appId) and siteId (used for
|
|
13
|
-
# read; this script just runs the npm create.
|
|
18
|
+
# (project's appId) and siteId (used as --site for `wix token` and in REST call
|
|
19
|
+
# bodies). The orchestrator does that read; this script just runs the npm create.
|
|
14
20
|
#
|
|
15
21
|
# Behavior:
|
|
16
22
|
# - Pre-flight validates the slug (regex ^[a-z0-9]{3,20}$).
|
|
17
|
-
# - Pre-flight requires both args.
|
|
23
|
+
# - Pre-flight requires both positional args.
|
|
18
24
|
# - Runs `npm create @wix/new@latest headless` with --no-publish + --skip-install
|
|
19
25
|
# so the orchestrator can deferred-install with its own package set.
|
|
20
|
-
# -
|
|
21
|
-
#
|
|
26
|
+
# - Passes bare `--site-template` so non-interactive scaffolding stays on the
|
|
27
|
+
# blank starter. Without it, @wix/create-new (>=0.0.72) prompts for a template
|
|
28
|
+
# choice and aborts in a non-TTY agent shell ("not supported in non-interactive
|
|
29
|
+
# terminals").
|
|
22
30
|
#
|
|
23
31
|
# Exit codes:
|
|
24
32
|
# 0 — ok
|
|
25
|
-
# 2 — argument validation failed
|
|
33
|
+
# 2 — argument validation failed (bad slug, missing args, unknown --frontend value)
|
|
34
|
+
# 3 — Wix CLI not logged in (defensive; the Discovery pre-flight is the primary check)
|
|
35
|
+
# 4 — frontend value recognized but not scaffolded yet (custom today)
|
|
26
36
|
# <other> — npm create failed; stderr surfaced to caller for orchestrator-side
|
|
27
|
-
# recovery (auth /
|
|
37
|
+
# recovery (auth / other scaffold failures live in the orchestrator).
|
|
28
38
|
|
|
29
39
|
set -euo pipefail
|
|
30
40
|
|
|
31
|
-
|
|
32
|
-
|
|
33
|
-
|
|
41
|
+
FRONTEND="astro"
|
|
42
|
+
POSITIONAL=()
|
|
43
|
+
while [[ $# -gt 0 ]]; do
|
|
44
|
+
case "$1" in
|
|
45
|
+
--frontend)
|
|
46
|
+
if [[ $# -lt 2 ]]; then
|
|
47
|
+
echo "scaffold.sh: --frontend requires a value (astro|custom)." >&2
|
|
48
|
+
exit 2
|
|
49
|
+
fi
|
|
50
|
+
FRONTEND="$2"
|
|
51
|
+
shift 2
|
|
52
|
+
;;
|
|
53
|
+
--frontend=*)
|
|
54
|
+
FRONTEND="${1#--frontend=}"
|
|
55
|
+
shift
|
|
56
|
+
;;
|
|
57
|
+
*)
|
|
58
|
+
POSITIONAL+=("$1")
|
|
59
|
+
shift
|
|
60
|
+
;;
|
|
61
|
+
esac
|
|
62
|
+
done
|
|
63
|
+
|
|
64
|
+
if [[ ${#POSITIONAL[@]} -lt 2 || -z "${POSITIONAL[0]:-}" || -z "${POSITIONAL[1]:-}" ]]; then
|
|
65
|
+
echo "scaffold.sh: both positional args required. Got project-slug='${POSITIONAL[0]:-}' brand-name='${POSITIONAL[1]:-}'." >&2
|
|
66
|
+
echo "Usage: bash scaffold.sh <slug> \"<Brand Name>\" [--frontend astro|custom] — slug first, brand quoted." >&2
|
|
34
67
|
exit 2
|
|
35
68
|
fi
|
|
36
69
|
|
|
37
|
-
|
|
38
|
-
|
|
70
|
+
case "$FRONTEND" in
|
|
71
|
+
astro)
|
|
72
|
+
;;
|
|
73
|
+
custom)
|
|
74
|
+
echo "scaffold.sh: --frontend=custom is not scaffolded yet — astro is the only supported frontend." >&2
|
|
75
|
+
echo "Discovery routes custom (non-astro) frontends to references/custom/INSTRUCTIONS.md (the not-available stub) before scaffold; this script should not be invoked with 'custom'." >&2
|
|
76
|
+
exit 4
|
|
77
|
+
;;
|
|
78
|
+
*)
|
|
79
|
+
echo "scaffold.sh: unknown --frontend value '$FRONTEND'. Allowed: astro, custom." >&2
|
|
80
|
+
exit 2
|
|
81
|
+
;;
|
|
82
|
+
esac
|
|
83
|
+
|
|
84
|
+
if [[ ! "${POSITIONAL[0]}" =~ ^[a-z0-9]{3,20}$ ]]; then
|
|
85
|
+
echo "scaffold.sh: project-slug='${POSITIONAL[0]}' is not valid." >&2
|
|
39
86
|
echo "Slug must be 3-20 lowercase alphanumeric chars (no hyphens, no spaces)." >&2
|
|
40
87
|
echo "Derive from the brand: lowercase, strip non-[a-z0-9], truncate to 20." >&2
|
|
41
88
|
exit 2
|
|
42
89
|
fi
|
|
43
90
|
|
|
44
|
-
#
|
|
45
|
-
#
|
|
46
|
-
|
|
91
|
+
# Defensive auth check — DISCOVERY.md's pre-flight should have caught this
|
|
92
|
+
# already, but scaffold.sh is also a documented standalone entry point
|
|
93
|
+
# (SKILL.md § "When NOT to use this skill"). `npm create @wix/new` requires
|
|
94
|
+
# an active CLI session and otherwise fails mid-run with an opaque error.
|
|
95
|
+
# `wix whoami` exits non-zero on a logged-out session and prints the
|
|
96
|
+
# authenticated email + user id when logged in.
|
|
97
|
+
if ! npx @wix/cli@latest whoami >/dev/null 2>&1; then
|
|
98
|
+
echo "scaffold.sh: not logged in to Wix CLI." >&2
|
|
99
|
+
echo "Run 'npx @wix/cli@latest login' and retry." >&2
|
|
100
|
+
exit 3
|
|
101
|
+
fi
|
|
47
102
|
|
|
48
103
|
npm create @wix/new@latest headless -- \
|
|
49
|
-
--business-name "$
|
|
50
|
-
--project-name "$
|
|
51
|
-
--site-template
|
|
104
|
+
--business-name "${POSITIONAL[1]}" \
|
|
105
|
+
--project-name "${POSITIONAL[0]}" \
|
|
106
|
+
--site-template \
|
|
52
107
|
--no-publish \
|
|
53
108
|
--skip-install
|