@wix/agent-skills 1.0.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/LICENSE +21 -0
- package/README.md +111 -0
- package/package.json +29 -0
- package/skills/wix-app/SKILL.md +344 -0
- package/skills/wix-app/references/APP_IDENTIFIERS.md +35 -0
- package/skills/wix-app/references/APP_MARKET_REVIEW.md +311 -0
- package/skills/wix-app/references/APP_VALIDATION.md +171 -0
- package/skills/wix-app/references/BACKEND_API.md +233 -0
- package/skills/wix-app/references/BACKEND_EVENT.md +116 -0
- package/skills/wix-app/references/CODE_QUALITY.md +33 -0
- package/skills/wix-app/references/CUSTOM_ELEMENT_WIDGET.md +587 -0
- package/skills/wix-app/references/DASHBOARD_MENU_PLUGIN.md +157 -0
- package/skills/wix-app/references/DASHBOARD_MODAL.md +283 -0
- package/skills/wix-app/references/DASHBOARD_PAGE.md +403 -0
- package/skills/wix-app/references/DASHBOARD_PLUGIN.md +205 -0
- package/skills/wix-app/references/DATA_COLLECTION.md +451 -0
- package/skills/wix-app/references/DOCUMENTATION.md +42 -0
- package/skills/wix-app/references/EDITOR_REACT_COMPONENT.md +65 -0
- package/skills/wix-app/references/EMBEDDED_SCRIPT.md +468 -0
- package/skills/wix-app/references/EXTENSION_REGISTRATION.md +96 -0
- package/skills/wix-app/references/SERVICE_PLUGIN.md +235 -0
- package/skills/wix-app/references/SITE_PLUGIN.md +436 -0
- package/skills/wix-app/references/STORES_VERSIONING.md +334 -0
- package/skills/wix-app/references/backend-event/COMMON-EVENTS.md +84 -0
- package/skills/wix-app/references/custom-element-widget/SETTINGS_PANEL.md +345 -0
- package/skills/wix-app/references/dashboard-menu-plugin/blog-slots.md +71 -0
- package/skills/wix-app/references/dashboard-menu-plugin/bookings-slots.md +58 -0
- package/skills/wix-app/references/dashboard-menu-plugin/crm-slots.md +8 -0
- package/skills/wix-app/references/dashboard-menu-plugin/ecommerce-slots.md +17 -0
- package/skills/wix-app/references/dashboard-menu-plugin/events-slots.md +29 -0
- package/skills/wix-app/references/dashboard-menu-plugin/restaurants-slots.md +27 -0
- package/skills/wix-app/references/dashboard-menu-plugin/stores-slots.md +35 -0
- package/skills/wix-app/references/dashboard-page/API_SPEC.md +138 -0
- package/skills/wix-app/references/dashboard-page/DASHBOARD_API.md +573 -0
- package/skills/wix-app/references/dashboard-page/DYNAMIC_PARAMETERS.md +269 -0
- package/skills/wix-app/references/dashboard-page/ECOM_NAVIGATION.md +164 -0
- package/skills/wix-app/references/dashboard-plugin/SLOTS.md +294 -0
- package/skills/wix-app/references/data-collection/WIX_DATA.md +270 -0
- package/skills/wix-app/references/data-collection/extension-template.ts +107 -0
- package/skills/wix-app/references/editor-react-component/ACCESSIBILITY.md +138 -0
- package/skills/wix-app/references/editor-react-component/COMPONENT-API.md +454 -0
- package/skills/wix-app/references/editor-react-component/COMPONENT-CONFIGURATION.md +165 -0
- package/skills/wix-app/references/editor-react-component/CSS-GUIDELINES.md +576 -0
- package/skills/wix-app/references/editor-react-component/DIRECTIONALITY.md +170 -0
- package/skills/wix-app/references/editor-react-component/EDIT-FLOW.md +6 -0
- package/skills/wix-app/references/editor-react-component/PARTS.md +25 -0
- package/skills/wix-app/references/editor-react-component/PROPS-VS-CSS.md +203 -0
- package/skills/wix-app/references/editor-react-component/REACT-GUIDELINES.md +167 -0
- package/skills/wix-app/references/editor-react-component/REACT-PATTERNS.md +137 -0
- package/skills/wix-app/references/service-plugin/ADDITIONAL-FEES.md +112 -0
- package/skills/wix-app/references/service-plugin/BOOKINGS-STAFF-SORTING.md +118 -0
- package/skills/wix-app/references/service-plugin/DISCOUNT-TRIGGERS.md +87 -0
- package/skills/wix-app/references/service-plugin/GIFT-CARDS.md +86 -0
- package/skills/wix-app/references/service-plugin/PAYMENT-SETTINGS.md +135 -0
- package/skills/wix-app/references/service-plugin/SHIPPING-RATES.md +79 -0
- package/skills/wix-app/references/service-plugin/VALIDATIONS.md +68 -0
- package/skills/wix-app/references/site-plugin/EXAMPLES.md +311 -0
- package/skills/wix-app/references/site-plugin/SLOTS.md +263 -0
- package/skills/wix-design-system/SKILL.md +129 -0
- package/skills/wix-design-system/references/file-structure.md +56 -0
- package/skills/wix-design-system/scripts/wds.cjs +531 -0
- package/skills/wix-headless/SKILL.md +418 -0
- package/skills/wix-headless/references/DISCOVERY.md +332 -0
- package/skills/wix-headless/references/ORCHESTRATION.md +269 -0
- package/skills/wix-headless/references/SETUP.md +154 -0
- package/skills/wix-headless/references/blog/BLOG_CONTENT.md +152 -0
- package/skills/wix-headless/references/blog/BLOG_PAGES.md +299 -0
- package/skills/wix-headless/references/blog/BLOG_SETUP.md +218 -0
- package/skills/wix-headless/references/blog/INSTRUCTIONS.md +32 -0
- package/skills/wix-headless/references/cms/CMS_FOUNDATIONS.md +373 -0
- package/skills/wix-headless/references/cms/FAQ_KNOWLEDGE_BASE.md +229 -0
- package/skills/wix-headless/references/cms/INSTRUCTIONS.md +40 -0
- package/skills/wix-headless/references/cms/PORTFOLIO.md +454 -0
- package/skills/wix-headless/references/cms/RESOURCE_LIBRARY.md +356 -0
- package/skills/wix-headless/references/cms/TEAM_DIRECTORY.md +299 -0
- package/skills/wix-headless/references/commands/install-app.md +42 -0
- package/skills/wix-headless/references/commands/known-apps.json +5 -0
- package/skills/wix-headless/references/commands/mcp-bootstrap.md +28 -0
- package/skills/wix-headless/references/designer/INSTRUCTIONS.md +828 -0
- package/skills/wix-headless/references/ecom/CART_PAGES.md +120 -0
- package/skills/wix-headless/references/ecom/CART_WIRING.md +103 -0
- package/skills/wix-headless/references/ecom/COMPONENTS_CSS.md +132 -0
- package/skills/wix-headless/references/ecom/INSTRUCTIONS.md +59 -0
- package/skills/wix-headless/references/forms/CONTACT_FORM.md +477 -0
- package/skills/wix-headless/references/forms/INSTRUCTIONS.md +43 -0
- package/skills/wix-headless/references/gift-cards/COMPONENTS.md +119 -0
- package/skills/wix-headless/references/gift-cards/INSTRUCTIONS.md +51 -0
- package/skills/wix-headless/references/gift-cards/PAGES.md +129 -0
- package/skills/wix-headless/references/images/INSTRUCTIONS.md +359 -0
- package/skills/wix-headless/references/shared/BUILD_NOISE.md +8 -0
- package/skills/wix-headless/references/shared/IMAGE_GENERATION.md +185 -0
- package/skills/wix-headless/references/shared/IMPLEMENTER.md +155 -0
- package/skills/wix-headless/references/shared/MCP_PREFIX.md +105 -0
- package/skills/wix-headless/references/shared/PRODUCTION_SHARP_EDGES.md +97 -0
- package/skills/wix-headless/references/shared/RETURN_CONTRACT.md +423 -0
- package/skills/wix-headless/references/shared/STYLING.md +117 -0
- package/skills/wix-headless/references/stores/BACK_IN_STOCK.md +178 -0
- package/skills/wix-headless/references/stores/CATEGORY_PAGES.md +86 -0
- package/skills/wix-headless/references/stores/COMPONENTS_CSS.md +129 -0
- package/skills/wix-headless/references/stores/HOME_AND_NAV.md +227 -0
- package/skills/wix-headless/references/stores/INSTRUCTIONS.md +96 -0
- package/skills/wix-headless/references/stores/PRODUCT_CATALOG_DATA.md +249 -0
- package/skills/wix-headless/references/stores/PRODUCT_PAGES.md +213 -0
- package/skills/wix-headless/references/stores/SHARED_WIRING.md +164 -0
- package/skills/wix-headless/references/verticals/_schema.json +160 -0
- package/skills/wix-headless/references/verticals/_schema.md +185 -0
- package/skills/wix-headless/references/verticals/blog.md +125 -0
- package/skills/wix-headless/references/verticals/cms.md +121 -0
- package/skills/wix-headless/references/verticals/ecom.md +96 -0
- package/skills/wix-headless/references/verticals/forms.md +106 -0
- package/skills/wix-headless/references/verticals/gift-cards.md +121 -0
- package/skills/wix-headless/references/verticals/stores.md +167 -0
- package/skills/wix-headless/scripts/check-manifest.mjs +198 -0
- package/skills/wix-headless/scripts/copy-utility-templates.mjs +153 -0
- package/skills/wix-headless/scripts/emit-design-tokens.mjs +77 -0
- package/skills/wix-headless/scripts/finalize-run-json.mjs +141 -0
- package/skills/wix-headless/scripts/init-site-json.mjs +63 -0
- package/skills/wix-headless/scripts/patch-decorative-slots.mjs +124 -0
- package/skills/wix-headless/scripts/plan-entity-image-waves.mjs +190 -0
- package/skills/wix-headless/scripts/preview.sh +45 -0
- package/skills/wix-headless/scripts/release.sh +73 -0
- package/skills/wix-headless/scripts/scaffold.sh +53 -0
- package/skills/wix-headless/scripts/seed-utilities.sh +55 -0
- package/skills/wix-headless/shared-utilities/analytics.ts +40 -0
- package/skills/wix-headless/shared-utilities/ricos.ts +179 -0
- package/skills/wix-headless/shared-utilities/wix-image.ts +72 -0
- package/skills/wix-headless/templates/ecom/CartBadge.tsx +84 -0
- package/skills/wix-headless/templates/ecom/CartView.tsx +543 -0
- package/skills/wix-headless/templates/ecom/cart.astro +13 -0
- package/skills/wix-headless/templates/ecom/components-ecom.css +215 -0
- package/skills/wix-headless/templates/ecom/discounts.ts +71 -0
- package/skills/wix-headless/templates/ecom/thank-you.astro +24 -0
- package/skills/wix-headless/templates/gift-cards/GiftCardPurchase.tsx +172 -0
- package/skills/wix-headless/templates/gift-cards/_home-teaser-snippet.astro +42 -0
- package/skills/wix-headless/templates/gift-cards/_nav-snippet.astro +11 -0
- package/skills/wix-headless/templates/gift-cards/components-gift-cards.css +219 -0
- package/skills/wix-headless/templates/gift-cards/gift-cards.astro +51 -0
- package/skills/wix-headless/templates/gift-cards/gift-cards.ts +75 -0
- package/skills/wix-headless/templates/stores/AddToCartButton.tsx +77 -0
- package/skills/wix-headless/templates/stores/BackInStockForm.tsx +176 -0
- package/skills/wix-headless/templates/stores/CategoryRail.astro +69 -0
- package/skills/wix-headless/templates/stores/ProductCard.astro +79 -0
- package/skills/wix-headless/templates/stores/ProductPurchase.tsx +397 -0
- package/skills/wix-headless/templates/stores/SeoTags.astro +21 -0
- package/skills/wix-headless/templates/stores/back-in-stock.ts +67 -0
- package/skills/wix-headless/templates/stores/categories.ts +155 -0
- package/skills/wix-headless/templates/stores/category/[slug].astro +130 -0
- package/skills/wix-headless/templates/stores/components-stores.css +295 -0
- package/skills/wix-headless/templates/stores/products/[slug].astro +128 -0
- package/skills/wix-headless/templates/stores/products/index.astro +101 -0
- package/skills/wix-manage/SKILL.md +280 -0
- package/skills/wix-manage/references/app-installation/install-wix-apps.md +155 -0
- package/skills/wix-manage/references/app-installation/list-installed-apps.md +124 -0
- package/skills/wix-manage/references/blog/how-to-create-blog-posts.md +226 -0
- package/skills/wix-manage/references/bookings/booking-service-policy-setup.md +95 -0
- package/skills/wix-manage/references/bookings/booking-system-integration-gaps.md +416 -0
- package/skills/wix-manage/references/bookings/bookings-staff-setup.md +255 -0
- package/skills/wix-manage/references/bookings/create-and-update-booking-services.md +462 -0
- package/skills/wix-manage/references/bookings/end-to-end-booking-flow.md +278 -0
- package/skills/wix-manage/references/bookings/external-calendar-integration.md +258 -0
- package/skills/wix-manage/references/bookings/multi-resource-service-creation.md +231 -0
- package/skills/wix-manage/references/calendar/configure-default-business-hours.md +226 -0
- package/skills/wix-manage/references/cms/cms-data-items-crud.md +422 -0
- package/skills/wix-manage/references/cms/cms-data-operations-extended.md +263 -0
- package/skills/wix-manage/references/cms/cms-ecommerce-catalog-integration.md +136 -0
- package/skills/wix-manage/references/cms/cms-references-and-relationships.md +160 -0
- package/skills/wix-manage/references/cms/cms-schema-management.md +143 -0
- package/skills/wix-manage/references/contacts/bulk-delete-contacts.md +73 -0
- package/skills/wix-manage/references/contacts/bulk-label-and-unlabel-contacts.md +67 -0
- package/skills/wix-manage/references/domains/domain-search-and-purchase.md +434 -0
- package/skills/wix-manage/references/ecommerce/api-recommendation-tracking.md +420 -0
- package/skills/wix-manage/references/ecommerce/flow-add-free-shipping.md +267 -0
- package/skills/wix-manage/references/ecommerce/flow-bundle-and-save.md +290 -0
- package/skills/wix-manage/references/ecommerce/flow-fix-coverage-gaps.md +300 -0
- package/skills/wix-manage/references/ecommerce/flow-optimize-shipping-rates.md +364 -0
- package/skills/wix-manage/references/ecommerce/flow-seasonal-promotion.md +315 -0
- package/skills/wix-manage/references/ecommerce/flow-stock-mover.md +308 -0
- package/skills/wix-manage/references/ecommerce/flow-upsell-boost.md +271 -0
- package/skills/wix-manage/references/ecommerce/goal-clear-inventory.md +118 -0
- package/skills/wix-manage/references/ecommerce/goal-drive-cross-sells.md +122 -0
- package/skills/wix-manage/references/ecommerce/goal-increase-aov.md +132 -0
- package/skills/wix-manage/references/ecommerce/goal-reduce-cart-abandonment.md +148 -0
- package/skills/wix-manage/references/ecommerce/goal-seasonal-revenue.md +146 -0
- package/skills/wix-manage/references/ecommerce/guardrail-discount-conflicts.md +118 -0
- package/skills/wix-manage/references/ecommerce/guardrail-margin-protection.md +88 -0
- package/skills/wix-manage/references/ecommerce/guardrail-rate-pricing-sanity.md +108 -0
- package/skills/wix-manage/references/ecommerce/guardrail-shipping-health.md +124 -0
- package/skills/wix-manage/references/ecommerce/recipe-apply-shipping-recommendations.md +299 -0
- package/skills/wix-manage/references/ecommerce/recommend-ecommerce-strategy.md +582 -0
- package/skills/wix-manage/references/ecommerce/setup-coupons.md +338 -0
- package/skills/wix-manage/references/ecommerce/setup-discount-rules.md +444 -0
- package/skills/wix-manage/references/ecommerce/setup-shipping-rates.md +86 -0
- package/skills/wix-manage/references/ecommerce/setup-shipping-regions.md +56 -0
- package/skills/wix-manage/references/ecommerce/setup-store-pickup-location.md +209 -0
- package/skills/wix-manage/references/ecommerce/skill-graph.md +139 -0
- package/skills/wix-manage/references/ecommerce/troubleshoot-checkout-delivery-dropoff.md +124 -0
- package/skills/wix-manage/references/ecommerce/troubleshoot-discount-not-applying.md +95 -0
- package/skills/wix-manage/references/events/list-events.md +203 -0
- package/skills/wix-manage/references/forms/create-form.md +260 -0
- package/skills/wix-manage/references/get-paid/create-payment-links.md +212 -0
- package/skills/wix-manage/references/get-paid/how-to-setup-wix-payments.md +57 -0
- package/skills/wix-manage/references/get-paid/payment-links-for-bookings.md +101 -0
- package/skills/wix-manage/references/media/upload-media-to-wix.md +216 -0
- package/skills/wix-manage/references/pricing-plans/create-and-update-pricing-plans.md +77 -0
- package/skills/wix-manage/references/pricing-plans/pricing-plans-bookings-integration.md +166 -0
- package/skills/wix-manage/references/restaurants/wix-restaurants-setup.md +336 -0
- package/skills/wix-manage/references/rich-content/ricos-converter-service.md +295 -0
- package/skills/wix-manage/references/site-properties/change-payment-currency-site-properties.md +59 -0
- package/skills/wix-manage/references/sites/create-site-from-template.md +183 -0
- package/skills/wix-manage/references/sites/query-sites.md +125 -0
- package/skills/wix-manage/references/stores/add-store-pages-to-site.md +57 -0
- package/skills/wix-manage/references/stores/bulk-create-products-with-options.md +1041 -0
- package/skills/wix-manage/references/stores/create-product-catalog-v1.md +125 -0
- package/skills/wix-manage/references/stores/create-product-from-image.md +824 -0
- package/skills/wix-manage/references/stores/create-product-with-options-catalog-v3.md +566 -0
- package/skills/wix-manage/references/stores/find-products-query-and-search-catalog-v3.md +194 -0
- package/skills/wix-manage/references/stores/query-products-catalog-v1.md +80 -0
- package/skills/wix-manage/references/stores/setup-online-store-catalog-v3.md +99 -0
- package/skills/wix-manage/references/stores/update-product-pre-order.md +213 -0
- package/skills/wix-manage/references/stores/update-product-with-options.md +318 -0
|
@@ -0,0 +1,124 @@
|
|
|
1
|
+
#!/usr/bin/env node
|
|
2
|
+
// Inject Image-Phase-1 decorative URLs into the designer-emitted page shells.
|
|
3
|
+
//
|
|
4
|
+
// The Phase 2 designer writes `<div data-decorative-slot="<key>">…</div>`
|
|
5
|
+
// placeholders in src/pages/*.astro. Image Phase 1 writes resolved URLs to
|
|
6
|
+
// .wix/image-urls.md. This script reads both, then injects an <img> element
|
|
7
|
+
// as the first child of each matching slot div — pure string substitution,
|
|
8
|
+
// no LLM, no file rewrites.
|
|
9
|
+
//
|
|
10
|
+
// Usage:
|
|
11
|
+
// node patch-decorative-slots.mjs <project-dir>
|
|
12
|
+
//
|
|
13
|
+
// Behavior:
|
|
14
|
+
// - If .wix/image-urls.md doesn't exist, exit 0 silently (Image Phase 1
|
|
15
|
+
// timed out / failed; the slot placeholders look complete on their own).
|
|
16
|
+
// - For each `data-decorative-slot="<key>"` in src/pages/*.astro:
|
|
17
|
+
// * If <key> has no URL in image-urls.md → leave the div alone.
|
|
18
|
+
// * If the div is self-closing or already has a child element other
|
|
19
|
+
// than whitespace/comments → skip with a warning (don't clobber).
|
|
20
|
+
// * Otherwise inject <img …> as the first child.
|
|
21
|
+
// - Output a JSON summary of patches/skips/warnings to stdout.
|
|
22
|
+
// - Exit 0 even when some slots couldn't be patched — placeholders fall
|
|
23
|
+
// back to the designer's aspect-ratio + background-color rendering.
|
|
24
|
+
|
|
25
|
+
import { readFileSync, writeFileSync, existsSync, readdirSync, statSync } from "node:fs";
|
|
26
|
+
import { join } from "node:path";
|
|
27
|
+
|
|
28
|
+
const projectDir = process.argv[2] ?? process.cwd();
|
|
29
|
+
|
|
30
|
+
const imageUrlsPath = join(projectDir, ".wix/image-urls.md");
|
|
31
|
+
if (!existsSync(imageUrlsPath)) {
|
|
32
|
+
console.log(JSON.stringify({ status: "skipped", reason: "no .wix/image-urls.md (Image Phase 1 didn't write — failed or timed out)" }));
|
|
33
|
+
process.exit(0);
|
|
34
|
+
}
|
|
35
|
+
|
|
36
|
+
// Parse `## <key>\n- url: <url>` blocks from .wix/image-urls.md.
|
|
37
|
+
const imageUrlsRaw = readFileSync(imageUrlsPath, "utf8");
|
|
38
|
+
const urlMap = {};
|
|
39
|
+
// Match `## key\n…- url: <url>` per section. The inner `(?:(?!^##\s)[\s\S])*?`
|
|
40
|
+
// forbids the lazy span from crossing into the next `## ` line — without
|
|
41
|
+
// that guard, an empty `- url:` for one slot silently steals the next
|
|
42
|
+
// section's URL on partial-failure runs.
|
|
43
|
+
const sectionRegex = /^##\s+(\S+)\s*\n(?:(?!^##\s)[\s\S])*?-\s*url:\s*(https?:\/\/\S+)/gm;
|
|
44
|
+
let m;
|
|
45
|
+
while ((m = sectionRegex.exec(imageUrlsRaw)) !== null) {
|
|
46
|
+
urlMap[m[1]] = m[2];
|
|
47
|
+
}
|
|
48
|
+
|
|
49
|
+
if (Object.keys(urlMap).length === 0) {
|
|
50
|
+
console.log(JSON.stringify({ status: "skipped", reason: ".wix/image-urls.md exists but has no parseable `## key` + `- url:` blocks" }));
|
|
51
|
+
process.exit(0);
|
|
52
|
+
}
|
|
53
|
+
|
|
54
|
+
// Find candidate page files: src/pages/*.astro, recursively (designer may emit
|
|
55
|
+
// /about.astro at top level OR /pages/about.astro).
|
|
56
|
+
const pagesDir = join(projectDir, "src/pages");
|
|
57
|
+
const candidates = [];
|
|
58
|
+
const walk = (dir) => {
|
|
59
|
+
if (!existsSync(dir)) return;
|
|
60
|
+
for (const entry of readdirSync(dir)) {
|
|
61
|
+
const full = join(dir, entry);
|
|
62
|
+
const stat = statSync(full);
|
|
63
|
+
if (stat.isDirectory()) walk(full);
|
|
64
|
+
else if (stat.isFile() && entry.endsWith(".astro")) candidates.push(full);
|
|
65
|
+
}
|
|
66
|
+
};
|
|
67
|
+
walk(pagesDir);
|
|
68
|
+
|
|
69
|
+
const patched = [];
|
|
70
|
+
const skipped = [];
|
|
71
|
+
const warnings = [];
|
|
72
|
+
|
|
73
|
+
const SLOT_DIV_REGEX = /(<div[^>]*\bdata-decorative-slot="([^"]+)"[^>]*>)([\s\S]*?)(<\/div>)/g;
|
|
74
|
+
|
|
75
|
+
for (const file of candidates) {
|
|
76
|
+
const original = readFileSync(file, "utf8");
|
|
77
|
+
let modified = original;
|
|
78
|
+
let fileChanged = false;
|
|
79
|
+
|
|
80
|
+
modified = modified.replace(SLOT_DIV_REGEX, (match, openTag, slotKey, inner, closeTag) => {
|
|
81
|
+
const url = urlMap[slotKey];
|
|
82
|
+
if (!url) {
|
|
83
|
+
skipped.push({ file, slot: slotKey, reason: "no URL for this slot in image-urls.md" });
|
|
84
|
+
return match;
|
|
85
|
+
}
|
|
86
|
+
|
|
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
|
+
const stripped = inner.replace(/<!--[\s\S]*?-->/g, "").trim();
|
|
91
|
+
|
|
92
|
+
// Skip if div already contains an <img> element (idempotency).
|
|
93
|
+
if (/<img\b/i.test(stripped)) {
|
|
94
|
+
skipped.push({ file, slot: slotKey, reason: "div already contains an <img> tag (idempotent skip)" });
|
|
95
|
+
return match;
|
|
96
|
+
}
|
|
97
|
+
|
|
98
|
+
// Skip if div has substantive child content beyond whitespace/comments.
|
|
99
|
+
if (stripped.length > 0) {
|
|
100
|
+
warnings.push({ file, slot: slotKey, reason: "div has existing non-image child content; not patching to avoid clobber" });
|
|
101
|
+
return match;
|
|
102
|
+
}
|
|
103
|
+
|
|
104
|
+
fileChanged = true;
|
|
105
|
+
const img = `<img src="${url}" alt="" loading="lazy" decoding="async" class="decorative-slot-img" />`;
|
|
106
|
+
patched.push({ file, slot: slotKey });
|
|
107
|
+
// Preserve any whitespace inside the div (e.g., the newline + indent).
|
|
108
|
+
return `${openTag}\n ${img}${inner}${closeTag}`;
|
|
109
|
+
});
|
|
110
|
+
|
|
111
|
+
if (fileChanged) {
|
|
112
|
+
writeFileSync(file, modified);
|
|
113
|
+
}
|
|
114
|
+
}
|
|
115
|
+
|
|
116
|
+
const summary = {
|
|
117
|
+
status: warnings.length > 0 ? "partial" : "ok",
|
|
118
|
+
imageUrls: Object.keys(urlMap),
|
|
119
|
+
filesScanned: candidates.length,
|
|
120
|
+
patched,
|
|
121
|
+
skipped,
|
|
122
|
+
warnings,
|
|
123
|
+
};
|
|
124
|
+
console.log(JSON.stringify(summary, null, 2));
|
|
@@ -0,0 +1,190 @@
|
|
|
1
|
+
#!/usr/bin/env node
|
|
2
|
+
// Build a deterministic execution plan for Image Phase 2 from a slim image
|
|
3
|
+
// agent's prompt array + the orchestrator's per-product / per-cms-item GETs.
|
|
4
|
+
//
|
|
5
|
+
// The slim image agent's only job is to return a list of brand-aligned prompts
|
|
6
|
+
// (one per entity). This script transforms that list (plus the entity details
|
|
7
|
+
// the orchestrator pre-fetched) into a structured plan the orchestrator can
|
|
8
|
+
// execute as a sequence of concurrent batches:
|
|
9
|
+
//
|
|
10
|
+
// waves — Runware generation requests, grouped into waves of <waveSize>
|
|
11
|
+
// (default 3) to match the google:4@2 throttle. Each wave is
|
|
12
|
+
// one orchestration step with N parallel CallWixSiteAPI tool
|
|
13
|
+
// calls; each tool call sends one task in the body array.
|
|
14
|
+
//
|
|
15
|
+
// imports — POST /site-media/v1/files/import requests, one per generated
|
|
16
|
+
// image. Indexed by taskUUID so the orchestrator threads the
|
|
17
|
+
// wave-result URL through to the import body.
|
|
18
|
+
//
|
|
19
|
+
// patches — Per-entity-type write requests (PATCH for products & blog
|
|
20
|
+
// posts; PUT for CMS items). Bodies use placeholders the
|
|
21
|
+
// orchestrator substitutes with import results:
|
|
22
|
+
// __IMAGE_URL__ — the full wixstatic URL (file.url)
|
|
23
|
+
// __IMAGE_FILE_ID__ — the file ID (file.fileUrl)
|
|
24
|
+
//
|
|
25
|
+
// publishes — Re-publish calls for blog posts ONLY (PATCHing a published
|
|
26
|
+
// draft un-publishes it). One per blog-post entity.
|
|
27
|
+
//
|
|
28
|
+
// Usage:
|
|
29
|
+
// echo "$INPUT_JSON" | node plan-entity-image-waves.mjs
|
|
30
|
+
//
|
|
31
|
+
// The script is pure data transformation — no I/O beyond stdin / stdout, no
|
|
32
|
+
// MCP, no network. The encoded knowledge is the per-entity-type body shapes
|
|
33
|
+
// (frozen from references/images/INSTRUCTIONS.md so a single source of truth).
|
|
34
|
+
|
|
35
|
+
import { readFileSync } from "node:fs";
|
|
36
|
+
|
|
37
|
+
// Body shape constants — keep aligned with references/images/INSTRUCTIONS.md.
|
|
38
|
+
const RUNWARE_DEFAULTS = {
|
|
39
|
+
taskType: "imageInference",
|
|
40
|
+
outputType: "URL",
|
|
41
|
+
outputFormat: "PNG",
|
|
42
|
+
model: "google:4@2",
|
|
43
|
+
numberResults: 1,
|
|
44
|
+
};
|
|
45
|
+
|
|
46
|
+
const DEFAULT_WAVE_SIZE = 3;
|
|
47
|
+
|
|
48
|
+
let input;
|
|
49
|
+
try {
|
|
50
|
+
input = JSON.parse(readFileSync(0, "utf8"));
|
|
51
|
+
} catch (e) {
|
|
52
|
+
console.error(`plan-entity-image-waves: stdin is not valid JSON (${e.message})`);
|
|
53
|
+
process.exit(2);
|
|
54
|
+
}
|
|
55
|
+
|
|
56
|
+
const prompts = Array.isArray(input.prompts) ? input.prompts : [];
|
|
57
|
+
if (prompts.length === 0) {
|
|
58
|
+
console.error("plan-entity-image-waves: no prompts in input — nothing to plan");
|
|
59
|
+
process.exit(2);
|
|
60
|
+
}
|
|
61
|
+
|
|
62
|
+
const productDetails = input.productDetails ?? {};
|
|
63
|
+
const cmsDetails = input.cmsDetails ?? {};
|
|
64
|
+
const waveSize = Math.max(1, Math.min(input.waveSize ?? DEFAULT_WAVE_SIZE, 8));
|
|
65
|
+
const model = input.model ?? RUNWARE_DEFAULTS.model;
|
|
66
|
+
|
|
67
|
+
// ---- 1. Runware waves (gen-side parallelism, throttle-bucketed) -----------
|
|
68
|
+
const waves = [];
|
|
69
|
+
for (let i = 0; i < prompts.length; i += waveSize) {
|
|
70
|
+
const slice = prompts.slice(i, i + waveSize);
|
|
71
|
+
waves.push(slice.map((p) => ({
|
|
72
|
+
taskUUID: p.taskUUID,
|
|
73
|
+
body: [{
|
|
74
|
+
...RUNWARE_DEFAULTS,
|
|
75
|
+
model,
|
|
76
|
+
taskUUID: p.taskUUID,
|
|
77
|
+
positivePrompt: p.positivePrompt,
|
|
78
|
+
width: p.width ?? 1024,
|
|
79
|
+
height: p.height ?? 1024,
|
|
80
|
+
outputFormat: p.outputFormat ?? RUNWARE_DEFAULTS.outputFormat,
|
|
81
|
+
}],
|
|
82
|
+
})));
|
|
83
|
+
}
|
|
84
|
+
|
|
85
|
+
// ---- 2. Wix Media imports (one per generated image) -----------------------
|
|
86
|
+
const imports = prompts.map((p) => ({
|
|
87
|
+
taskUUID: p.taskUUID,
|
|
88
|
+
mimeType: p.outputFormat === "JPG" ? "image/jpeg" : "image/png",
|
|
89
|
+
displayName: p.displayName ?? `${p.entityId}.${(p.outputFormat ?? "PNG").toLowerCase()}`,
|
|
90
|
+
}));
|
|
91
|
+
|
|
92
|
+
// ---- 3. Per-entity-type write requests ------------------------------------
|
|
93
|
+
const patches = [];
|
|
94
|
+
const publishes = [];
|
|
95
|
+
|
|
96
|
+
for (const p of prompts) {
|
|
97
|
+
if (p.entityType === "product") {
|
|
98
|
+
const detail = productDetails[p.entityId];
|
|
99
|
+
if (!detail) {
|
|
100
|
+
console.error(`plan-entity-image-waves: missing productDetails for entityId=${p.entityId}`);
|
|
101
|
+
process.exit(1);
|
|
102
|
+
}
|
|
103
|
+
if (detail.revision === undefined || detail.revision === null) {
|
|
104
|
+
console.error(`plan-entity-image-waves: productDetails[${p.entityId}].revision is required (mandatory per Update-Product endpoint)`);
|
|
105
|
+
process.exit(1);
|
|
106
|
+
}
|
|
107
|
+
patches.push({
|
|
108
|
+
taskUUID: p.taskUUID,
|
|
109
|
+
entityType: "product",
|
|
110
|
+
entityId: p.entityId,
|
|
111
|
+
method: "PATCH",
|
|
112
|
+
url: `https://www.wixapis.com/stores/v3/products/${p.entityId}`,
|
|
113
|
+
// Body echoes options + variantsInfo (mandatory — see images/INSTRUCTIONS.md
|
|
114
|
+
// §428-prevention) and embeds the URL via __IMAGE_URL__ placeholder.
|
|
115
|
+
body: {
|
|
116
|
+
product: {
|
|
117
|
+
revision: detail.revision,
|
|
118
|
+
media: {
|
|
119
|
+
itemsInfo: {
|
|
120
|
+
items: [{ url: "__IMAGE_URL__", altText: p.displayName ?? p.entityId }],
|
|
121
|
+
},
|
|
122
|
+
},
|
|
123
|
+
...(detail.options !== undefined ? { options: detail.options } : {}),
|
|
124
|
+
...(detail.variantsInfo !== undefined ? { variantsInfo: detail.variantsInfo } : {}),
|
|
125
|
+
},
|
|
126
|
+
},
|
|
127
|
+
});
|
|
128
|
+
} else if (p.entityType === "blogPost") {
|
|
129
|
+
patches.push({
|
|
130
|
+
taskUUID: p.taskUUID,
|
|
131
|
+
entityType: "blogPost",
|
|
132
|
+
entityId: p.entityId,
|
|
133
|
+
method: "PATCH",
|
|
134
|
+
url: `https://www.wixapis.com/blog/v3/draft-posts/${p.entityId}`,
|
|
135
|
+
// Blog uses the file ID (fileUrl), not the wixstatic URL.
|
|
136
|
+
body: {
|
|
137
|
+
draftPost: {
|
|
138
|
+
media: { wixMedia: { image: { id: "__IMAGE_FILE_ID__" } } },
|
|
139
|
+
},
|
|
140
|
+
},
|
|
141
|
+
});
|
|
142
|
+
publishes.push({
|
|
143
|
+
entityId: p.entityId,
|
|
144
|
+
method: "POST",
|
|
145
|
+
url: `https://www.wixapis.com/blog/v3/draft-posts/${p.entityId}/publish`,
|
|
146
|
+
});
|
|
147
|
+
} else if (p.entityType === "cmsItem") {
|
|
148
|
+
const detail = cmsDetails[p.entityId];
|
|
149
|
+
if (!detail) {
|
|
150
|
+
console.error(`plan-entity-image-waves: missing cmsDetails for entityId=${p.entityId}`);
|
|
151
|
+
process.exit(1);
|
|
152
|
+
}
|
|
153
|
+
if (!detail.collectionId || !detail.imageField || !detail.data) {
|
|
154
|
+
console.error(`plan-entity-image-waves: cmsDetails[${p.entityId}] requires collectionId, imageField, and data (existing item record)`);
|
|
155
|
+
process.exit(1);
|
|
156
|
+
}
|
|
157
|
+
// Read-merge-PUT: echo every existing data field, set the image field
|
|
158
|
+
// to the placeholder URL. Wipes nothing (the bug observed in 2026-04-19).
|
|
159
|
+
const mergedData = { ...detail.data, [detail.imageField]: "__IMAGE_URL__" };
|
|
160
|
+
patches.push({
|
|
161
|
+
taskUUID: p.taskUUID,
|
|
162
|
+
entityType: "cmsItem",
|
|
163
|
+
entityId: p.entityId,
|
|
164
|
+
method: "PUT",
|
|
165
|
+
url: `https://www.wixapis.com/wix-data/v2/items/${p.entityId}`,
|
|
166
|
+
body: {
|
|
167
|
+
dataCollectionId: detail.collectionId,
|
|
168
|
+
dataItem: { id: p.entityId, data: mergedData },
|
|
169
|
+
},
|
|
170
|
+
});
|
|
171
|
+
} else {
|
|
172
|
+
console.error(`plan-entity-image-waves: unknown entityType "${p.entityType}" for entityId=${p.entityId} — must be product | blogPost | cmsItem`);
|
|
173
|
+
process.exit(1);
|
|
174
|
+
}
|
|
175
|
+
}
|
|
176
|
+
|
|
177
|
+
const plan = {
|
|
178
|
+
meta: {
|
|
179
|
+
promptCount: prompts.length,
|
|
180
|
+
waveCount: waves.length,
|
|
181
|
+
waveSize,
|
|
182
|
+
model,
|
|
183
|
+
},
|
|
184
|
+
waves,
|
|
185
|
+
imports,
|
|
186
|
+
patches,
|
|
187
|
+
publishes,
|
|
188
|
+
};
|
|
189
|
+
|
|
190
|
+
console.log(JSON.stringify(plan, null, 2));
|
|
@@ -0,0 +1,45 @@
|
|
|
1
|
+
#!/usr/bin/env bash
|
|
2
|
+
# Build the project and deploy a rotating preview URL.
|
|
3
|
+
#
|
|
4
|
+
# Usage:
|
|
5
|
+
# bash <SKILL_ROOT>/scripts/preview.sh
|
|
6
|
+
#
|
|
7
|
+
# Run from the project directory (CWD = <project>/). Requires wix.config.json.
|
|
8
|
+
#
|
|
9
|
+
# Output: stdout is the preview URL that `npx @wix/cli preview` printed; the
|
|
10
|
+
# orchestrator captures it and records as outcome.previewUrl in run.json. All
|
|
11
|
+
# other CLI output goes to stderr.
|
|
12
|
+
#
|
|
13
|
+
# `preview` does NOT populate the Frontend link in headless settings — that's
|
|
14
|
+
# what `release.sh` is for. Use preview for fast iteration on a rotating URL;
|
|
15
|
+
# use release for production deploy + transactional-email URL stability.
|
|
16
|
+
#
|
|
17
|
+
# Exit codes:
|
|
18
|
+
# 0 — ok; preview URL on stdout
|
|
19
|
+
# <other> — build or preview failed; stderr surfaces the underlying error
|
|
20
|
+
# (TypeScript / Astro errors are code bugs, not endpoint drift —
|
|
21
|
+
# the orchestrator's recovery ladder doesn't retry build).
|
|
22
|
+
|
|
23
|
+
set -euo pipefail
|
|
24
|
+
|
|
25
|
+
# Build first; surface compile errors verbatim if it fails.
|
|
26
|
+
npx @wix/cli build 1>&2
|
|
27
|
+
|
|
28
|
+
# Preview captures the deployed URL on stdout. We tee its output to stderr for
|
|
29
|
+
# the user-visible log AND parse the URL out for the orchestrator's stdout.
|
|
30
|
+
PREVIEW_OUTPUT="$(mktemp)"
|
|
31
|
+
trap 'rm -f "$PREVIEW_OUTPUT"' EXIT
|
|
32
|
+
|
|
33
|
+
npx @wix/cli preview 2>&1 | tee "$PREVIEW_OUTPUT" 1>&2
|
|
34
|
+
|
|
35
|
+
# Wix CLI prints `Site preview URL: <url>` (or similar) — extract the first
|
|
36
|
+
# https URL from the output. If multiple are printed, the first is the canonical
|
|
37
|
+
# preview URL.
|
|
38
|
+
PREVIEW_URL="$(grep -oE 'https://[A-Za-z0-9.-]+\.wix-host\.com[^[:space:]]*' "$PREVIEW_OUTPUT" | head -n 1 || true)"
|
|
39
|
+
|
|
40
|
+
if [[ -z "$PREVIEW_URL" ]]; then
|
|
41
|
+
echo "preview.sh: could not extract a *.wix-host.com URL from preview output" >&2
|
|
42
|
+
exit 1
|
|
43
|
+
fi
|
|
44
|
+
|
|
45
|
+
echo "$PREVIEW_URL"
|
|
@@ -0,0 +1,73 @@
|
|
|
1
|
+
#!/usr/bin/env bash
|
|
2
|
+
# Build the project and release to production. Unlike preview.sh, this populates
|
|
3
|
+
# the Frontend link in dashboard → Settings → Headless Settings → Manage URLs,
|
|
4
|
+
# which Wix injects into transactional emails (order confirmations, password
|
|
5
|
+
# resets, member invites). Use release.sh for production deploys.
|
|
6
|
+
#
|
|
7
|
+
# Usage:
|
|
8
|
+
# bash <SKILL_ROOT>/scripts/release.sh
|
|
9
|
+
#
|
|
10
|
+
# Run from the project directory (CWD = <project>/). Requires wix.config.json.
|
|
11
|
+
#
|
|
12
|
+
# Output: stdout is the released URL that `npx @wix/cli release` printed
|
|
13
|
+
# (extracted from the line `Site published on <url>`); the orchestrator
|
|
14
|
+
# captures it as outcome.releaseUrl in run.json. All other CLI output goes
|
|
15
|
+
# to stderr.
|
|
16
|
+
#
|
|
17
|
+
# Exit codes:
|
|
18
|
+
# 0 — ok; release URL on stdout
|
|
19
|
+
# <other> — build or release failed; stderr surfaces the underlying error.
|
|
20
|
+
# Build failures are code bugs (TypeScript / Astro / missing
|
|
21
|
+
# module) — the orchestrator does NOT retry. Release auth failures
|
|
22
|
+
# surface as `Run npx @wix/cli login and retry.`
|
|
23
|
+
# Known transient release failures are retried by this script.
|
|
24
|
+
|
|
25
|
+
set -euo pipefail
|
|
26
|
+
|
|
27
|
+
npx @wix/cli build 1>&2
|
|
28
|
+
|
|
29
|
+
RELEASE_OUTPUT="$(mktemp)"
|
|
30
|
+
trap 'rm -f "$RELEASE_OUTPUT"' EXIT
|
|
31
|
+
|
|
32
|
+
release_is_retryable() {
|
|
33
|
+
grep -Eiq 'ECONNRESET|ETIMEDOUT|EAI_AGAIN|STATE_MISMATCH|temporary system error|temporarily unavailable|try again shortly' "$RELEASE_OUTPUT"
|
|
34
|
+
}
|
|
35
|
+
|
|
36
|
+
MAX_RELEASE_ATTEMPTS="${WIX_RELEASE_ATTEMPTS:-3}"
|
|
37
|
+
RELEASE_STATUS=1
|
|
38
|
+
|
|
39
|
+
for ((attempt = 1; attempt <= MAX_RELEASE_ATTEMPTS; attempt++)); do
|
|
40
|
+
: >"$RELEASE_OUTPUT"
|
|
41
|
+
set +e
|
|
42
|
+
npx @wix/cli release 2>&1 | tee "$RELEASE_OUTPUT" 1>&2
|
|
43
|
+
RELEASE_STATUS=${PIPESTATUS[0]}
|
|
44
|
+
set -e
|
|
45
|
+
|
|
46
|
+
if [[ "$RELEASE_STATUS" -eq 0 ]]; then
|
|
47
|
+
break
|
|
48
|
+
fi
|
|
49
|
+
|
|
50
|
+
if [[ "$attempt" -lt "$MAX_RELEASE_ATTEMPTS" ]] && release_is_retryable; then
|
|
51
|
+
sleep_seconds=$((attempt * 5))
|
|
52
|
+
echo "release.sh: release attempt $attempt failed with a retryable Wix error; retrying in ${sleep_seconds}s" >&2
|
|
53
|
+
sleep "$sleep_seconds"
|
|
54
|
+
continue
|
|
55
|
+
fi
|
|
56
|
+
|
|
57
|
+
exit "$RELEASE_STATUS"
|
|
58
|
+
done
|
|
59
|
+
|
|
60
|
+
# CLI prints `Site published on <url>` — extract the URL after that marker.
|
|
61
|
+
# Fall back to the first Wix-hosted URL if the marker line is not found
|
|
62
|
+
# (CLI wording may vary between versions).
|
|
63
|
+
RELEASE_URL="$(sed -nE 's/.*Site published on ([^[:space:]]+).*/\1/p' "$RELEASE_OUTPUT" | head -n 1 || true)"
|
|
64
|
+
if [[ -z "$RELEASE_URL" ]]; then
|
|
65
|
+
RELEASE_URL="$(grep -oE 'https://[A-Za-z0-9.-]+\.wix-(site-)?host\.com[^[:space:]]*' "$RELEASE_OUTPUT" | head -n 1 || true)"
|
|
66
|
+
fi
|
|
67
|
+
|
|
68
|
+
if [[ -z "$RELEASE_URL" ]]; then
|
|
69
|
+
echo "release.sh: could not extract a release URL from release output" >&2
|
|
70
|
+
exit 1
|
|
71
|
+
fi
|
|
72
|
+
|
|
73
|
+
echo "$RELEASE_URL"
|
|
@@ -0,0 +1,53 @@
|
|
|
1
|
+
#!/usr/bin/env bash
|
|
2
|
+
# Scaffold a new Wix Managed Headless project with the pure-headless blank template.
|
|
3
|
+
#
|
|
4
|
+
# Usage:
|
|
5
|
+
# bash <SKILL_ROOT>/scripts/scaffold.sh <project-slug> "<Brand Name>"
|
|
6
|
+
#
|
|
7
|
+
# <project-slug>: 3-20 lowercase alphanumeric chars (no hyphens, no spaces) — the
|
|
8
|
+
# Wix CLI rejects anything else. Becomes the project directory name.
|
|
9
|
+
# <Brand Name>: human-readable business name; quote if it contains spaces.
|
|
10
|
+
#
|
|
11
|
+
# After scaffold succeeds, read <project-slug>/wix.config.json to extract appId
|
|
12
|
+
# (project's appId) and siteId (used for MCP calls). The orchestrator does that
|
|
13
|
+
# read; this script just runs the npm create.
|
|
14
|
+
#
|
|
15
|
+
# Behavior:
|
|
16
|
+
# - Pre-flight validates the slug (regex ^[a-z0-9]{3,20}$).
|
|
17
|
+
# - Pre-flight requires both args.
|
|
18
|
+
# - Runs `npm create @wix/new@latest headless` with --no-publish + --skip-install
|
|
19
|
+
# so the orchestrator can deferred-install with its own package set.
|
|
20
|
+
# - Template ID is the pure-headless blank (vibe-compatible templates trigger
|
|
21
|
+
# an interactive prompt that blocks non-TTY runs).
|
|
22
|
+
#
|
|
23
|
+
# Exit codes:
|
|
24
|
+
# 0 — ok
|
|
25
|
+
# 2 — argument validation failed
|
|
26
|
+
# <other> — npm create failed; stderr surfaced to caller for orchestrator-side
|
|
27
|
+
# recovery (auth / invalid-template ladder lives in the orchestrator).
|
|
28
|
+
|
|
29
|
+
set -euo pipefail
|
|
30
|
+
|
|
31
|
+
if [[ $# -lt 2 || -z "${1:-}" || -z "${2:-}" ]]; then
|
|
32
|
+
echo "scaffold.sh: both args required. Got project-slug='${1:-}' brand-name='${2:-}'." >&2
|
|
33
|
+
echo "Usage: bash scaffold.sh <slug> \"<Brand Name>\" — slug first, brand quoted." >&2
|
|
34
|
+
exit 2
|
|
35
|
+
fi
|
|
36
|
+
|
|
37
|
+
if [[ ! "$1" =~ ^[a-z0-9]{3,20}$ ]]; then
|
|
38
|
+
echo "scaffold.sh: project-slug='$1' is not valid." >&2
|
|
39
|
+
echo "Slug must be 3-20 lowercase alphanumeric chars (no hyphens, no spaces)." >&2
|
|
40
|
+
echo "Derive from the brand: lowercase, strip non-[a-z0-9], truncate to 20." >&2
|
|
41
|
+
exit 2
|
|
42
|
+
fi
|
|
43
|
+
|
|
44
|
+
# Pure-headless blank template. Vibe-compatible templates show an interactive
|
|
45
|
+
# vibe setup prompt that blocks non-TTY contexts — do not substitute.
|
|
46
|
+
TEMPLATE_ID="blank"
|
|
47
|
+
|
|
48
|
+
npm create @wix/new@latest headless -- \
|
|
49
|
+
--business-name "$2" \
|
|
50
|
+
--project-name "$1" \
|
|
51
|
+
--site-template "$TEMPLATE_ID" \
|
|
52
|
+
--no-publish \
|
|
53
|
+
--skip-install
|
|
@@ -0,0 +1,55 @@
|
|
|
1
|
+
#!/usr/bin/env bash
|
|
2
|
+
# Copy the skill's shared utilities into the project's src/utils/ and strip the
|
|
3
|
+
# Astro starter cruft that ships with the blank template.
|
|
4
|
+
#
|
|
5
|
+
# Usage (both modes work):
|
|
6
|
+
# bash <SKILL_ROOT>/scripts/seed-utilities.sh # installed tgz
|
|
7
|
+
# bash <(curl -s https://dev.wix.com/skills/wix-headless/scripts/seed-utilities.sh)
|
|
8
|
+
#
|
|
9
|
+
# Run from the project directory (CWD = <project>/). The script auto-detects
|
|
10
|
+
# whether shared-utilities is available on disk (tgz install) and falls back
|
|
11
|
+
# to fetching from the well-known URL when streamed via process substitution
|
|
12
|
+
# (BASH_SOURCE is /dev/fd/N, so the on-disk lookup naturally falls through).
|
|
13
|
+
#
|
|
14
|
+
# Behavior:
|
|
15
|
+
# - Copies the three shared utility files into src/utils/ — never overwrites
|
|
16
|
+
# an existing file (users can drop in their own version to override).
|
|
17
|
+
# - Removes Astro starter cruft (Welcome.astro + marketing SVGs) that ships
|
|
18
|
+
# with the blank template but is never imported by the build skill.
|
|
19
|
+
#
|
|
20
|
+
# Shared utilities copied:
|
|
21
|
+
# - wix-image.ts — media URL resolver (used by stores, blog, cms)
|
|
22
|
+
# - analytics.ts — event tracking (used by stores, ecom, blog)
|
|
23
|
+
# - ricos.ts — Ricos JSON to HTML renderer for SSR Astro pages
|
|
24
|
+
|
|
25
|
+
set -euo pipefail
|
|
26
|
+
|
|
27
|
+
SKILL_URL="https://dev.wix.com/skills/wix-headless"
|
|
28
|
+
UTILS=(analytics.ts ricos.ts wix-image.ts)
|
|
29
|
+
|
|
30
|
+
# Mode detection: prefer on-disk skill root if the sibling dir exists, else
|
|
31
|
+
# fetch over HTTP. Covers both tgz install and `bash <(curl ...)` streaming.
|
|
32
|
+
SHARED_UTILS_DIR=""
|
|
33
|
+
script_path="${BASH_SOURCE[0]}"
|
|
34
|
+
if [[ -f "$script_path" ]]; then
|
|
35
|
+
candidate="$(dirname "$script_path")/../shared-utilities"
|
|
36
|
+
if [[ -d "$candidate" ]]; then
|
|
37
|
+
SHARED_UTILS_DIR="$(cd "$candidate" && pwd)"
|
|
38
|
+
fi
|
|
39
|
+
fi
|
|
40
|
+
|
|
41
|
+
mkdir -p src/utils
|
|
42
|
+
|
|
43
|
+
for f in "${UTILS[@]}"; do
|
|
44
|
+
dest="src/utils/$f"
|
|
45
|
+
if [[ -e "$dest" ]]; then continue; fi
|
|
46
|
+
if [[ -n "$SHARED_UTILS_DIR" ]]; then
|
|
47
|
+
cp "$SHARED_UTILS_DIR/$f" "$dest"
|
|
48
|
+
else
|
|
49
|
+
curl -fsSL "$SKILL_URL/shared-utilities/$f" -o "$dest"
|
|
50
|
+
fi
|
|
51
|
+
done
|
|
52
|
+
|
|
53
|
+
# Astro starter cruft cleanup.
|
|
54
|
+
rm -f src/components/Welcome.astro
|
|
55
|
+
rm -f src/assets/astro.svg src/assets/wix.svg src/assets/background.svg
|
|
@@ -0,0 +1,40 @@
|
|
|
1
|
+
export type AnalyticsEventName =
|
|
2
|
+
| "AddToCart"
|
|
3
|
+
| "RemoveFromCart"
|
|
4
|
+
| "InitiateCheckout"
|
|
5
|
+
| "Purchase"
|
|
6
|
+
| "ArticleView"
|
|
7
|
+
| "FormSubmit"
|
|
8
|
+
| "AddProductImpression"
|
|
9
|
+
| "ViewContent"
|
|
10
|
+
| "ClickProduct"
|
|
11
|
+
| (string & {});
|
|
12
|
+
|
|
13
|
+
export function trackEvent(
|
|
14
|
+
name: AnalyticsEventName,
|
|
15
|
+
payload?: Record<string, unknown>,
|
|
16
|
+
): void {
|
|
17
|
+
if (typeof window === "undefined") return;
|
|
18
|
+
|
|
19
|
+
const event = { name, ...(payload ?? {}) };
|
|
20
|
+
|
|
21
|
+
const w = window as unknown as {
|
|
22
|
+
dataLayer?: unknown[];
|
|
23
|
+
wixAnalytics?: { track(event: { name: string } & Record<string, unknown>): void };
|
|
24
|
+
};
|
|
25
|
+
|
|
26
|
+
if (w.wixAnalytics?.track) {
|
|
27
|
+
w.wixAnalytics.track(event);
|
|
28
|
+
return;
|
|
29
|
+
}
|
|
30
|
+
|
|
31
|
+
if (w.dataLayer) {
|
|
32
|
+
w.dataLayer.push({ event: name, ...event });
|
|
33
|
+
return;
|
|
34
|
+
}
|
|
35
|
+
|
|
36
|
+
const meta = import.meta as unknown as { env?: { DEV?: boolean } };
|
|
37
|
+
if (meta.env?.DEV) {
|
|
38
|
+
console.debug("[analytics]", event);
|
|
39
|
+
}
|
|
40
|
+
}
|