@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.
Files changed (220) hide show
  1. package/LICENSE +21 -0
  2. package/README.md +111 -0
  3. package/package.json +29 -0
  4. package/skills/wix-app/SKILL.md +344 -0
  5. package/skills/wix-app/references/APP_IDENTIFIERS.md +35 -0
  6. package/skills/wix-app/references/APP_MARKET_REVIEW.md +311 -0
  7. package/skills/wix-app/references/APP_VALIDATION.md +171 -0
  8. package/skills/wix-app/references/BACKEND_API.md +233 -0
  9. package/skills/wix-app/references/BACKEND_EVENT.md +116 -0
  10. package/skills/wix-app/references/CODE_QUALITY.md +33 -0
  11. package/skills/wix-app/references/CUSTOM_ELEMENT_WIDGET.md +587 -0
  12. package/skills/wix-app/references/DASHBOARD_MENU_PLUGIN.md +157 -0
  13. package/skills/wix-app/references/DASHBOARD_MODAL.md +283 -0
  14. package/skills/wix-app/references/DASHBOARD_PAGE.md +403 -0
  15. package/skills/wix-app/references/DASHBOARD_PLUGIN.md +205 -0
  16. package/skills/wix-app/references/DATA_COLLECTION.md +451 -0
  17. package/skills/wix-app/references/DOCUMENTATION.md +42 -0
  18. package/skills/wix-app/references/EDITOR_REACT_COMPONENT.md +65 -0
  19. package/skills/wix-app/references/EMBEDDED_SCRIPT.md +468 -0
  20. package/skills/wix-app/references/EXTENSION_REGISTRATION.md +96 -0
  21. package/skills/wix-app/references/SERVICE_PLUGIN.md +235 -0
  22. package/skills/wix-app/references/SITE_PLUGIN.md +436 -0
  23. package/skills/wix-app/references/STORES_VERSIONING.md +334 -0
  24. package/skills/wix-app/references/backend-event/COMMON-EVENTS.md +84 -0
  25. package/skills/wix-app/references/custom-element-widget/SETTINGS_PANEL.md +345 -0
  26. package/skills/wix-app/references/dashboard-menu-plugin/blog-slots.md +71 -0
  27. package/skills/wix-app/references/dashboard-menu-plugin/bookings-slots.md +58 -0
  28. package/skills/wix-app/references/dashboard-menu-plugin/crm-slots.md +8 -0
  29. package/skills/wix-app/references/dashboard-menu-plugin/ecommerce-slots.md +17 -0
  30. package/skills/wix-app/references/dashboard-menu-plugin/events-slots.md +29 -0
  31. package/skills/wix-app/references/dashboard-menu-plugin/restaurants-slots.md +27 -0
  32. package/skills/wix-app/references/dashboard-menu-plugin/stores-slots.md +35 -0
  33. package/skills/wix-app/references/dashboard-page/API_SPEC.md +138 -0
  34. package/skills/wix-app/references/dashboard-page/DASHBOARD_API.md +573 -0
  35. package/skills/wix-app/references/dashboard-page/DYNAMIC_PARAMETERS.md +269 -0
  36. package/skills/wix-app/references/dashboard-page/ECOM_NAVIGATION.md +164 -0
  37. package/skills/wix-app/references/dashboard-plugin/SLOTS.md +294 -0
  38. package/skills/wix-app/references/data-collection/WIX_DATA.md +270 -0
  39. package/skills/wix-app/references/data-collection/extension-template.ts +107 -0
  40. package/skills/wix-app/references/editor-react-component/ACCESSIBILITY.md +138 -0
  41. package/skills/wix-app/references/editor-react-component/COMPONENT-API.md +454 -0
  42. package/skills/wix-app/references/editor-react-component/COMPONENT-CONFIGURATION.md +165 -0
  43. package/skills/wix-app/references/editor-react-component/CSS-GUIDELINES.md +576 -0
  44. package/skills/wix-app/references/editor-react-component/DIRECTIONALITY.md +170 -0
  45. package/skills/wix-app/references/editor-react-component/EDIT-FLOW.md +6 -0
  46. package/skills/wix-app/references/editor-react-component/PARTS.md +25 -0
  47. package/skills/wix-app/references/editor-react-component/PROPS-VS-CSS.md +203 -0
  48. package/skills/wix-app/references/editor-react-component/REACT-GUIDELINES.md +167 -0
  49. package/skills/wix-app/references/editor-react-component/REACT-PATTERNS.md +137 -0
  50. package/skills/wix-app/references/service-plugin/ADDITIONAL-FEES.md +112 -0
  51. package/skills/wix-app/references/service-plugin/BOOKINGS-STAFF-SORTING.md +118 -0
  52. package/skills/wix-app/references/service-plugin/DISCOUNT-TRIGGERS.md +87 -0
  53. package/skills/wix-app/references/service-plugin/GIFT-CARDS.md +86 -0
  54. package/skills/wix-app/references/service-plugin/PAYMENT-SETTINGS.md +135 -0
  55. package/skills/wix-app/references/service-plugin/SHIPPING-RATES.md +79 -0
  56. package/skills/wix-app/references/service-plugin/VALIDATIONS.md +68 -0
  57. package/skills/wix-app/references/site-plugin/EXAMPLES.md +311 -0
  58. package/skills/wix-app/references/site-plugin/SLOTS.md +263 -0
  59. package/skills/wix-design-system/SKILL.md +129 -0
  60. package/skills/wix-design-system/references/file-structure.md +56 -0
  61. package/skills/wix-design-system/scripts/wds.cjs +531 -0
  62. package/skills/wix-headless/SKILL.md +418 -0
  63. package/skills/wix-headless/references/DISCOVERY.md +332 -0
  64. package/skills/wix-headless/references/ORCHESTRATION.md +269 -0
  65. package/skills/wix-headless/references/SETUP.md +154 -0
  66. package/skills/wix-headless/references/blog/BLOG_CONTENT.md +152 -0
  67. package/skills/wix-headless/references/blog/BLOG_PAGES.md +299 -0
  68. package/skills/wix-headless/references/blog/BLOG_SETUP.md +218 -0
  69. package/skills/wix-headless/references/blog/INSTRUCTIONS.md +32 -0
  70. package/skills/wix-headless/references/cms/CMS_FOUNDATIONS.md +373 -0
  71. package/skills/wix-headless/references/cms/FAQ_KNOWLEDGE_BASE.md +229 -0
  72. package/skills/wix-headless/references/cms/INSTRUCTIONS.md +40 -0
  73. package/skills/wix-headless/references/cms/PORTFOLIO.md +454 -0
  74. package/skills/wix-headless/references/cms/RESOURCE_LIBRARY.md +356 -0
  75. package/skills/wix-headless/references/cms/TEAM_DIRECTORY.md +299 -0
  76. package/skills/wix-headless/references/commands/install-app.md +42 -0
  77. package/skills/wix-headless/references/commands/known-apps.json +5 -0
  78. package/skills/wix-headless/references/commands/mcp-bootstrap.md +28 -0
  79. package/skills/wix-headless/references/designer/INSTRUCTIONS.md +828 -0
  80. package/skills/wix-headless/references/ecom/CART_PAGES.md +120 -0
  81. package/skills/wix-headless/references/ecom/CART_WIRING.md +103 -0
  82. package/skills/wix-headless/references/ecom/COMPONENTS_CSS.md +132 -0
  83. package/skills/wix-headless/references/ecom/INSTRUCTIONS.md +59 -0
  84. package/skills/wix-headless/references/forms/CONTACT_FORM.md +477 -0
  85. package/skills/wix-headless/references/forms/INSTRUCTIONS.md +43 -0
  86. package/skills/wix-headless/references/gift-cards/COMPONENTS.md +119 -0
  87. package/skills/wix-headless/references/gift-cards/INSTRUCTIONS.md +51 -0
  88. package/skills/wix-headless/references/gift-cards/PAGES.md +129 -0
  89. package/skills/wix-headless/references/images/INSTRUCTIONS.md +359 -0
  90. package/skills/wix-headless/references/shared/BUILD_NOISE.md +8 -0
  91. package/skills/wix-headless/references/shared/IMAGE_GENERATION.md +185 -0
  92. package/skills/wix-headless/references/shared/IMPLEMENTER.md +155 -0
  93. package/skills/wix-headless/references/shared/MCP_PREFIX.md +105 -0
  94. package/skills/wix-headless/references/shared/PRODUCTION_SHARP_EDGES.md +97 -0
  95. package/skills/wix-headless/references/shared/RETURN_CONTRACT.md +423 -0
  96. package/skills/wix-headless/references/shared/STYLING.md +117 -0
  97. package/skills/wix-headless/references/stores/BACK_IN_STOCK.md +178 -0
  98. package/skills/wix-headless/references/stores/CATEGORY_PAGES.md +86 -0
  99. package/skills/wix-headless/references/stores/COMPONENTS_CSS.md +129 -0
  100. package/skills/wix-headless/references/stores/HOME_AND_NAV.md +227 -0
  101. package/skills/wix-headless/references/stores/INSTRUCTIONS.md +96 -0
  102. package/skills/wix-headless/references/stores/PRODUCT_CATALOG_DATA.md +249 -0
  103. package/skills/wix-headless/references/stores/PRODUCT_PAGES.md +213 -0
  104. package/skills/wix-headless/references/stores/SHARED_WIRING.md +164 -0
  105. package/skills/wix-headless/references/verticals/_schema.json +160 -0
  106. package/skills/wix-headless/references/verticals/_schema.md +185 -0
  107. package/skills/wix-headless/references/verticals/blog.md +125 -0
  108. package/skills/wix-headless/references/verticals/cms.md +121 -0
  109. package/skills/wix-headless/references/verticals/ecom.md +96 -0
  110. package/skills/wix-headless/references/verticals/forms.md +106 -0
  111. package/skills/wix-headless/references/verticals/gift-cards.md +121 -0
  112. package/skills/wix-headless/references/verticals/stores.md +167 -0
  113. package/skills/wix-headless/scripts/check-manifest.mjs +198 -0
  114. package/skills/wix-headless/scripts/copy-utility-templates.mjs +153 -0
  115. package/skills/wix-headless/scripts/emit-design-tokens.mjs +77 -0
  116. package/skills/wix-headless/scripts/finalize-run-json.mjs +141 -0
  117. package/skills/wix-headless/scripts/init-site-json.mjs +63 -0
  118. package/skills/wix-headless/scripts/patch-decorative-slots.mjs +124 -0
  119. package/skills/wix-headless/scripts/plan-entity-image-waves.mjs +190 -0
  120. package/skills/wix-headless/scripts/preview.sh +45 -0
  121. package/skills/wix-headless/scripts/release.sh +73 -0
  122. package/skills/wix-headless/scripts/scaffold.sh +53 -0
  123. package/skills/wix-headless/scripts/seed-utilities.sh +55 -0
  124. package/skills/wix-headless/shared-utilities/analytics.ts +40 -0
  125. package/skills/wix-headless/shared-utilities/ricos.ts +179 -0
  126. package/skills/wix-headless/shared-utilities/wix-image.ts +72 -0
  127. package/skills/wix-headless/templates/ecom/CartBadge.tsx +84 -0
  128. package/skills/wix-headless/templates/ecom/CartView.tsx +543 -0
  129. package/skills/wix-headless/templates/ecom/cart.astro +13 -0
  130. package/skills/wix-headless/templates/ecom/components-ecom.css +215 -0
  131. package/skills/wix-headless/templates/ecom/discounts.ts +71 -0
  132. package/skills/wix-headless/templates/ecom/thank-you.astro +24 -0
  133. package/skills/wix-headless/templates/gift-cards/GiftCardPurchase.tsx +172 -0
  134. package/skills/wix-headless/templates/gift-cards/_home-teaser-snippet.astro +42 -0
  135. package/skills/wix-headless/templates/gift-cards/_nav-snippet.astro +11 -0
  136. package/skills/wix-headless/templates/gift-cards/components-gift-cards.css +219 -0
  137. package/skills/wix-headless/templates/gift-cards/gift-cards.astro +51 -0
  138. package/skills/wix-headless/templates/gift-cards/gift-cards.ts +75 -0
  139. package/skills/wix-headless/templates/stores/AddToCartButton.tsx +77 -0
  140. package/skills/wix-headless/templates/stores/BackInStockForm.tsx +176 -0
  141. package/skills/wix-headless/templates/stores/CategoryRail.astro +69 -0
  142. package/skills/wix-headless/templates/stores/ProductCard.astro +79 -0
  143. package/skills/wix-headless/templates/stores/ProductPurchase.tsx +397 -0
  144. package/skills/wix-headless/templates/stores/SeoTags.astro +21 -0
  145. package/skills/wix-headless/templates/stores/back-in-stock.ts +67 -0
  146. package/skills/wix-headless/templates/stores/categories.ts +155 -0
  147. package/skills/wix-headless/templates/stores/category/[slug].astro +130 -0
  148. package/skills/wix-headless/templates/stores/components-stores.css +295 -0
  149. package/skills/wix-headless/templates/stores/products/[slug].astro +128 -0
  150. package/skills/wix-headless/templates/stores/products/index.astro +101 -0
  151. package/skills/wix-manage/SKILL.md +280 -0
  152. package/skills/wix-manage/references/app-installation/install-wix-apps.md +155 -0
  153. package/skills/wix-manage/references/app-installation/list-installed-apps.md +124 -0
  154. package/skills/wix-manage/references/blog/how-to-create-blog-posts.md +226 -0
  155. package/skills/wix-manage/references/bookings/booking-service-policy-setup.md +95 -0
  156. package/skills/wix-manage/references/bookings/booking-system-integration-gaps.md +416 -0
  157. package/skills/wix-manage/references/bookings/bookings-staff-setup.md +255 -0
  158. package/skills/wix-manage/references/bookings/create-and-update-booking-services.md +462 -0
  159. package/skills/wix-manage/references/bookings/end-to-end-booking-flow.md +278 -0
  160. package/skills/wix-manage/references/bookings/external-calendar-integration.md +258 -0
  161. package/skills/wix-manage/references/bookings/multi-resource-service-creation.md +231 -0
  162. package/skills/wix-manage/references/calendar/configure-default-business-hours.md +226 -0
  163. package/skills/wix-manage/references/cms/cms-data-items-crud.md +422 -0
  164. package/skills/wix-manage/references/cms/cms-data-operations-extended.md +263 -0
  165. package/skills/wix-manage/references/cms/cms-ecommerce-catalog-integration.md +136 -0
  166. package/skills/wix-manage/references/cms/cms-references-and-relationships.md +160 -0
  167. package/skills/wix-manage/references/cms/cms-schema-management.md +143 -0
  168. package/skills/wix-manage/references/contacts/bulk-delete-contacts.md +73 -0
  169. package/skills/wix-manage/references/contacts/bulk-label-and-unlabel-contacts.md +67 -0
  170. package/skills/wix-manage/references/domains/domain-search-and-purchase.md +434 -0
  171. package/skills/wix-manage/references/ecommerce/api-recommendation-tracking.md +420 -0
  172. package/skills/wix-manage/references/ecommerce/flow-add-free-shipping.md +267 -0
  173. package/skills/wix-manage/references/ecommerce/flow-bundle-and-save.md +290 -0
  174. package/skills/wix-manage/references/ecommerce/flow-fix-coverage-gaps.md +300 -0
  175. package/skills/wix-manage/references/ecommerce/flow-optimize-shipping-rates.md +364 -0
  176. package/skills/wix-manage/references/ecommerce/flow-seasonal-promotion.md +315 -0
  177. package/skills/wix-manage/references/ecommerce/flow-stock-mover.md +308 -0
  178. package/skills/wix-manage/references/ecommerce/flow-upsell-boost.md +271 -0
  179. package/skills/wix-manage/references/ecommerce/goal-clear-inventory.md +118 -0
  180. package/skills/wix-manage/references/ecommerce/goal-drive-cross-sells.md +122 -0
  181. package/skills/wix-manage/references/ecommerce/goal-increase-aov.md +132 -0
  182. package/skills/wix-manage/references/ecommerce/goal-reduce-cart-abandonment.md +148 -0
  183. package/skills/wix-manage/references/ecommerce/goal-seasonal-revenue.md +146 -0
  184. package/skills/wix-manage/references/ecommerce/guardrail-discount-conflicts.md +118 -0
  185. package/skills/wix-manage/references/ecommerce/guardrail-margin-protection.md +88 -0
  186. package/skills/wix-manage/references/ecommerce/guardrail-rate-pricing-sanity.md +108 -0
  187. package/skills/wix-manage/references/ecommerce/guardrail-shipping-health.md +124 -0
  188. package/skills/wix-manage/references/ecommerce/recipe-apply-shipping-recommendations.md +299 -0
  189. package/skills/wix-manage/references/ecommerce/recommend-ecommerce-strategy.md +582 -0
  190. package/skills/wix-manage/references/ecommerce/setup-coupons.md +338 -0
  191. package/skills/wix-manage/references/ecommerce/setup-discount-rules.md +444 -0
  192. package/skills/wix-manage/references/ecommerce/setup-shipping-rates.md +86 -0
  193. package/skills/wix-manage/references/ecommerce/setup-shipping-regions.md +56 -0
  194. package/skills/wix-manage/references/ecommerce/setup-store-pickup-location.md +209 -0
  195. package/skills/wix-manage/references/ecommerce/skill-graph.md +139 -0
  196. package/skills/wix-manage/references/ecommerce/troubleshoot-checkout-delivery-dropoff.md +124 -0
  197. package/skills/wix-manage/references/ecommerce/troubleshoot-discount-not-applying.md +95 -0
  198. package/skills/wix-manage/references/events/list-events.md +203 -0
  199. package/skills/wix-manage/references/forms/create-form.md +260 -0
  200. package/skills/wix-manage/references/get-paid/create-payment-links.md +212 -0
  201. package/skills/wix-manage/references/get-paid/how-to-setup-wix-payments.md +57 -0
  202. package/skills/wix-manage/references/get-paid/payment-links-for-bookings.md +101 -0
  203. package/skills/wix-manage/references/media/upload-media-to-wix.md +216 -0
  204. package/skills/wix-manage/references/pricing-plans/create-and-update-pricing-plans.md +77 -0
  205. package/skills/wix-manage/references/pricing-plans/pricing-plans-bookings-integration.md +166 -0
  206. package/skills/wix-manage/references/restaurants/wix-restaurants-setup.md +336 -0
  207. package/skills/wix-manage/references/rich-content/ricos-converter-service.md +295 -0
  208. package/skills/wix-manage/references/site-properties/change-payment-currency-site-properties.md +59 -0
  209. package/skills/wix-manage/references/sites/create-site-from-template.md +183 -0
  210. package/skills/wix-manage/references/sites/query-sites.md +125 -0
  211. package/skills/wix-manage/references/stores/add-store-pages-to-site.md +57 -0
  212. package/skills/wix-manage/references/stores/bulk-create-products-with-options.md +1041 -0
  213. package/skills/wix-manage/references/stores/create-product-catalog-v1.md +125 -0
  214. package/skills/wix-manage/references/stores/create-product-from-image.md +824 -0
  215. package/skills/wix-manage/references/stores/create-product-with-options-catalog-v3.md +566 -0
  216. package/skills/wix-manage/references/stores/find-products-query-and-search-catalog-v3.md +194 -0
  217. package/skills/wix-manage/references/stores/query-products-catalog-v1.md +80 -0
  218. package/skills/wix-manage/references/stores/setup-online-store-catalog-v3.md +99 -0
  219. package/skills/wix-manage/references/stores/update-product-pre-order.md +213 -0
  220. package/skills/wix-manage/references/stores/update-product-with-options.md +318 -0
@@ -0,0 +1,198 @@
1
+ #!/usr/bin/env node
2
+ // Post-phase manifest check + template-copy recovery.
3
+ //
4
+ // Verifies that every file declared in each loaded pack's `creates:` array
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>/.
7
+ // Outputs a JSON summary of present / recovered / errored files.
8
+ //
9
+ // Usage (both modes work):
10
+ // node <SKILL_ROOT>/scripts/check-manifest.mjs <project-dir> <phase> <packs-csv>
11
+ // curl -s https://dev.wix.com/skills/wix-headless/scripts/check-manifest.mjs \
12
+ // | node --input-type=module - <project-dir> <phase> <packs-csv>
13
+ //
14
+ // <phase> ∈ { "components", "pages" }
15
+ // <packs-csv> = comma-separated pack names (loaded verticals), e.g. "stores,ecom,cms"
16
+ //
17
+ // Note: `node <(curl ...)` does NOT work for .mjs files — Node sees /dev/fd/N
18
+ // with no extension and rejects ESM syntax. Use the stdin form above.
19
+ //
20
+ // Skill-local file reads (vertical pack markdowns, template files) auto-detect
21
+ // whether they can resolve on disk (tgz install) and fall back to HTTP fetch
22
+ // otherwise (stream via stdin).
23
+ //
24
+ // Behavior:
25
+ // - For each pack, parses `references/verticals/<pack>.md` to extract the
26
+ // `creates:` array.
27
+ // - For each `creates:` entry where phase matches:
28
+ // * If file exists in the project → "present"
29
+ // * If missing AND a template exists at `templates/<pack>/<tail>`
30
+ // (where <tail> is the path under src/pages/ for page files, or the
31
+ // basename for everything else) → copy/fetch it; record as "recovered".
32
+ // * Otherwise → record as "missing" with a remediation hint.
33
+ // - Exit 0 on happy path or recoverable misses.
34
+ // - Exit 1 if any file is unrecoverably missing.
35
+
36
+ import { readFileSync, writeFileSync, existsSync, mkdirSync, copyFileSync } from "node:fs";
37
+ import { join, dirname, basename, resolve } from "node:path";
38
+ import { fileURLToPath } from "node:url";
39
+
40
+ const SKILL_URL = "https://dev.wix.com/skills/wix-headless";
41
+
42
+ // Mode detection: prefer on-disk skill root if reachable, else use HTTP.
43
+ // When invoked as `node <(curl ...)`, import.meta.url is `file:///dev/fd/N`
44
+ // and the candidate root won't contain `references/verticals` — so we fall
45
+ // through to URL mode automatically.
46
+ let SKILL_ROOT_DISK = null;
47
+ try {
48
+ const scriptDir = dirname(fileURLToPath(import.meta.url));
49
+ const candidate = resolve(scriptDir, "..");
50
+ if (existsSync(join(candidate, "references/verticals"))) {
51
+ SKILL_ROOT_DISK = candidate;
52
+ }
53
+ } catch {
54
+ // fileURLToPath may fail on non-file URLs; fall through to URL mode.
55
+ }
56
+
57
+ // Read a skill-local file (relative path like "references/verticals/stores.md").
58
+ // Returns null when the file doesn't exist.
59
+ async function readSkillText(relPath) {
60
+ if (SKILL_ROOT_DISK) {
61
+ const p = join(SKILL_ROOT_DISK, relPath);
62
+ if (!existsSync(p)) return null;
63
+ return readFileSync(p, "utf8");
64
+ }
65
+ const url = `${SKILL_URL}/${relPath}`;
66
+ const r = await fetch(url);
67
+ if (r.status === 404) return null;
68
+ if (!r.ok) throw new Error(`fetch ${url}: HTTP ${r.status}`);
69
+ return await r.text();
70
+ }
71
+
72
+ // Copy a skill-local file at relPath into destPath (in the user's project).
73
+ // Returns true on success, false if the source doesn't exist.
74
+ async function copySkillFile(relPath, destPath) {
75
+ if (SKILL_ROOT_DISK) {
76
+ const src = join(SKILL_ROOT_DISK, relPath);
77
+ if (!existsSync(src)) return false;
78
+ mkdirSync(dirname(destPath), { recursive: true });
79
+ copyFileSync(src, destPath);
80
+ return true;
81
+ }
82
+ const text = await readSkillText(relPath);
83
+ if (text === null) return false;
84
+ mkdirSync(dirname(destPath), { recursive: true });
85
+ writeFileSync(destPath, text);
86
+ return true;
87
+ }
88
+
89
+ const [, , projectDir, phase, packsCsv] = process.argv;
90
+
91
+ if (!projectDir || !phase || !packsCsv) {
92
+ console.error("usage: check-manifest.mjs <project-dir> <phase> <packs-csv>");
93
+ process.exit(2);
94
+ }
95
+
96
+ if (phase !== "components" && phase !== "pages") {
97
+ console.error(`check-manifest: invalid phase "${phase}" — must be "components" or "pages"`);
98
+ process.exit(2);
99
+ }
100
+
101
+ const packs = packsCsv.split(",").map((p) => p.trim()).filter(Boolean);
102
+
103
+ // Map a `creates:` file path to its template path (relative to skill root).
104
+ // Heuristic: `src/pages/<X>` preserves <X> under templates/<pack>/; everything
105
+ // else uses basename only.
106
+ function templateRelPath(packName, srcPath) {
107
+ const pagesMatch = srcPath.match(/^src\/pages\/(.+)$/);
108
+ const tail = pagesMatch ? pagesMatch[1] : basename(srcPath);
109
+ return `templates/${packName}/${tail}`;
110
+ }
111
+
112
+ // Parse `creates:` block from a vertical pack's markdown frontmatter.
113
+ // Format (one per line):
114
+ // - { file: src/utils/back-in-stock.ts, phase: components }
115
+ function parseCreates(text) {
116
+ const lines = text.split("\n");
117
+ const entries = [];
118
+ let inCreates = false;
119
+ for (const line of lines) {
120
+ if (/^creates:\s*$/.test(line)) {
121
+ inCreates = true;
122
+ continue;
123
+ }
124
+ if (inCreates) {
125
+ // Block ends at a non-indented, non-blank line that doesn't start with `-`.
126
+ if (/^[^\s-]/.test(line)) {
127
+ inCreates = false;
128
+ continue;
129
+ }
130
+ const m = line.match(/^\s*-\s*\{\s*file:\s*([^,]+?),\s*phase:\s*([\w-]+)\s*\}/);
131
+ if (m) entries.push({ file: m[1].trim(), phase: m[2].trim() });
132
+ }
133
+ }
134
+ return entries;
135
+ }
136
+
137
+ const present = [];
138
+ const recovered = [];
139
+ const missing = [];
140
+
141
+ for (const pack of packs) {
142
+ const verticalRel = `references/verticals/${pack}.md`;
143
+ const text = await readSkillText(verticalRel);
144
+ if (text === null) {
145
+ missing.push({
146
+ pack,
147
+ path: null,
148
+ code: "PACK_NOT_FOUND",
149
+ remediation: `vertical pack file not found at ${verticalRel} — pack "${pack}" may not be a valid loaded vertical`,
150
+ });
151
+ continue;
152
+ }
153
+
154
+ const entries = parseCreates(text).filter((e) => e.phase === phase);
155
+
156
+ for (const { file } of entries) {
157
+ const destPath = join(projectDir, file);
158
+ if (existsSync(destPath)) {
159
+ present.push({ pack, path: file });
160
+ continue;
161
+ }
162
+
163
+ const templateRel = templateRelPath(pack, file);
164
+ const ok = await copySkillFile(templateRel, destPath);
165
+ if (ok) {
166
+ recovered.push({
167
+ pack,
168
+ path: file,
169
+ source: "template-copy",
170
+ template: templateRel,
171
+ });
172
+ continue;
173
+ }
174
+
175
+ missing.push({
176
+ pack,
177
+ path: file,
178
+ code: "PHASE_FILE_MISSING",
179
+ remediation: `the ${pack} agent did not write this file and the pack ships no template at ${templateRel}. Re-dispatch the ${phase} scope, or report the gap to the pack maintainer.`,
180
+ });
181
+ }
182
+ }
183
+
184
+ const summary = {
185
+ phase,
186
+ packs,
187
+ counts: {
188
+ present: present.length,
189
+ recovered: recovered.length,
190
+ missing: missing.length,
191
+ },
192
+ present,
193
+ recovered,
194
+ missing,
195
+ };
196
+ console.log(JSON.stringify(summary, null, 2));
197
+
198
+ process.exit(missing.length > 0 ? 1 : 0);
@@ -0,0 +1,153 @@
1
+ #!/usr/bin/env node
2
+ // Copy templated utility files into the project for the named phase.
3
+ // Invoked by the wix-headless skill orchestrator before Phase 3 Components or
4
+ // Phase 4 Pages dispatches, so that mechanical SDK-wrapper utilities
5
+ // (back-in-stock.ts, discounts.ts, categories.ts) are on disk by the time
6
+ // agents start.
7
+ //
8
+ // These files are pure templates — same shape regardless of brand. Letting an
9
+ // LLM regenerate them costs tokens and risks drift. Pre-copying is structurally
10
+ // better.
11
+ //
12
+ // Usage (both modes work):
13
+ // node <SKILL_ROOT>/scripts/copy-utility-templates.mjs <project-dir> <phase>
14
+ // curl -s https://dev.wix.com/skills/wix-headless/scripts/copy-utility-templates.mjs \
15
+ // | node --input-type=module - <project-dir> <phase>
16
+ //
17
+ // <phase> ∈ { "components", "pages" }
18
+ //
19
+ // Note: `node <(curl ...)` does NOT work for .mjs files — Node sees /dev/fd/N
20
+ // with no extension and rejects ESM syntax. Use the stdin form above.
21
+ //
22
+ // Template files auto-detect whether they can be read on disk (tgz install)
23
+ // and fall back to HTTP fetch when streamed via stdin.
24
+ //
25
+ // Reads `.wix/site.json` to discover which packs are loaded, then copies the
26
+ // matching templates for the given phase. Never overwrites an existing file
27
+ // (so user customisations and earlier orchestrator state are preserved).
28
+
29
+ import { readFileSync, writeFileSync, existsSync, mkdirSync, copyFileSync } from "node:fs";
30
+ import { join, dirname, resolve } from "node:path";
31
+ import { fileURLToPath } from "node:url";
32
+
33
+ const SKILL_URL = "https://dev.wix.com/skills/wix-headless";
34
+
35
+ // Mode detection — see check-manifest.mjs for the same pattern.
36
+ let SKILL_ROOT_DISK = null;
37
+ try {
38
+ const scriptDir = dirname(fileURLToPath(import.meta.url));
39
+ const candidate = resolve(scriptDir, "..");
40
+ if (existsSync(join(candidate, "templates"))) {
41
+ SKILL_ROOT_DISK = candidate;
42
+ }
43
+ } catch {
44
+ // fileURLToPath may fail on non-file URLs; fall through to URL mode.
45
+ }
46
+
47
+ // Copy a template file (path relative to <SKILL_ROOT>/templates/) into the
48
+ // project at destPath. Returns { ok: true } on success, or { ok: false,
49
+ // reason: "..." } on failure (source missing, HTTP error, IO error).
50
+ async function copyTemplate(sourceRel, destPath) {
51
+ if (SKILL_ROOT_DISK) {
52
+ const src = join(SKILL_ROOT_DISK, "templates", sourceRel);
53
+ if (!existsSync(src)) return { ok: false, reason: `missing on disk: ${src}` };
54
+ try {
55
+ mkdirSync(dirname(destPath), { recursive: true });
56
+ copyFileSync(src, destPath);
57
+ return { ok: true };
58
+ } catch (e) {
59
+ return { ok: false, reason: e.message };
60
+ }
61
+ }
62
+ const url = `${SKILL_URL}/templates/${sourceRel}`;
63
+ try {
64
+ const r = await fetch(url);
65
+ if (r.status === 404) return { ok: false, reason: `missing at ${url}` };
66
+ if (!r.ok) return { ok: false, reason: `fetch ${url}: HTTP ${r.status}` };
67
+ const text = await r.text();
68
+ mkdirSync(dirname(destPath), { recursive: true });
69
+ writeFileSync(destPath, text);
70
+ return { ok: true };
71
+ } catch (e) {
72
+ return { ok: false, reason: e.message };
73
+ }
74
+ }
75
+
76
+ // Hardcoded mapping: { pack, phase, source (relative to templates dir), dest (relative to project) }.
77
+ // To add a new templated utility: ship the file under templates/<pack>/, then add
78
+ // an entry here. Keep this list small — only files that are pure SDK wrappers
79
+ // with no brand-specific content belong here.
80
+ const TEMPLATES = [
81
+ { pack: "stores", phase: "components", source: "stores/back-in-stock.ts", dest: "src/utils/back-in-stock.ts" },
82
+ { pack: "ecom", phase: "components", source: "ecom/discounts.ts", dest: "src/utils/discounts.ts" },
83
+ { pack: "stores", phase: "pages", source: "stores/categories.ts", dest: "src/utils/categories.ts" },
84
+ ];
85
+
86
+ const projectDir = process.argv[2];
87
+ const phase = process.argv[3];
88
+
89
+ if (!projectDir || !phase) {
90
+ console.error("usage: copy-utility-templates.mjs <project-dir> <phase>");
91
+ console.error(" <phase> ∈ { components, pages }");
92
+ process.exit(2);
93
+ }
94
+
95
+ if (phase !== "components" && phase !== "pages") {
96
+ console.error(`copy-utility-templates: invalid phase "${phase}" — must be "components" or "pages"`);
97
+ process.exit(2);
98
+ }
99
+
100
+ const sitePath = join(projectDir, ".wix/site.json");
101
+ let loadedPacks;
102
+ try {
103
+ const site = JSON.parse(readFileSync(sitePath, "utf8"));
104
+ loadedPacks = new Set(site.verticals ?? []);
105
+ if (loadedPacks.size === 0) {
106
+ console.error(`copy-utility-templates: site.json.verticals is empty — has Setup completed?`);
107
+ process.exit(1);
108
+ }
109
+ } catch (e) {
110
+ console.error(`copy-utility-templates: cannot read ${sitePath} (${e.message}). Has Setup completed?`);
111
+ process.exit(1);
112
+ }
113
+
114
+ const candidates = TEMPLATES.filter((t) => t.phase === phase && loadedPacks.has(t.pack));
115
+
116
+ if (candidates.length === 0) {
117
+ console.log(`copy-utility-templates: no templates for phase "${phase}" with loaded packs ${[...loadedPacks].join(", ")} — nothing to do`);
118
+ process.exit(0);
119
+ }
120
+
121
+ const copied = [];
122
+ const skipped = [];
123
+ const errors = [];
124
+
125
+ for (const { pack, source, dest } of candidates) {
126
+ const destPath = join(projectDir, dest);
127
+
128
+ if (existsSync(destPath)) {
129
+ skipped.push(dest);
130
+ continue;
131
+ }
132
+
133
+ const result = await copyTemplate(source, destPath);
134
+ if (result.ok) {
135
+ copied.push(dest);
136
+ } else {
137
+ errors.push(`failed to copy ${source} → ${dest} (pack "${pack}"): ${result.reason}`);
138
+ }
139
+ }
140
+
141
+ const summary = {
142
+ phase,
143
+ packs: [...loadedPacks],
144
+ copied,
145
+ skipped,
146
+ errors,
147
+ };
148
+
149
+ console.log(JSON.stringify(summary, null, 2));
150
+
151
+ if (errors.length > 0) {
152
+ process.exit(1);
153
+ }
@@ -0,0 +1,77 @@
1
+ #!/usr/bin/env node
2
+ // Generate .wix/design-tokens.css and .wix/site.d.ts deterministically from
3
+ // .wix/site.json.designTokens. Invoked by the wix-headless skill orchestrator
4
+ // after the Phase 2 Design System agent's return is merged into site.json.
5
+ //
6
+ // Why a script (not agent work): both files are pure projections of the
7
+ // designTokens JSON — no judgment, no brand-context dependence. An LLM
8
+ // emitting them is wasted tokens AND a drift risk (malformed :root blocks,
9
+ // missing token groups, divergent .d.ts skeletons).
10
+
11
+ import { readFileSync, writeFileSync, mkdirSync } from "node:fs";
12
+ import { join } from "node:path";
13
+
14
+ const projectDir = process.argv[2] ?? process.cwd();
15
+ const sitePath = join(projectDir, ".wix/site.json");
16
+
17
+ let site;
18
+ try {
19
+ site = JSON.parse(readFileSync(sitePath, "utf8"));
20
+ } catch (e) {
21
+ console.error(`emit-design-tokens: cannot read ${sitePath} (${e.message}). Has Phase 2 Design System returned and merged?`);
22
+ process.exit(1);
23
+ }
24
+
25
+ const tokens = site.designTokens ?? {};
26
+ if (!tokens || Object.keys(tokens).length === 0) {
27
+ console.error("emit-design-tokens: site.json.designTokens is empty — designer return not merged.");
28
+ process.exit(1);
29
+ }
30
+
31
+ const wixDir = join(projectDir, ".wix");
32
+ mkdirSync(wixDir, { recursive: true });
33
+
34
+ // .wix/design-tokens.css ----------------------------------------------------
35
+ const PREFIX = {
36
+ colors: "--color-",
37
+ fonts: "--font-",
38
+ radii: "--radius-",
39
+ spacing: "--spacing-",
40
+ };
41
+
42
+ const cssLines = ["/* Generated from .wix/site.json.designTokens. Do not edit. */", ":root {"];
43
+ for (const [group, prefix] of Object.entries(PREFIX)) {
44
+ const entries = tokens[group] ?? {};
45
+ for (const [key, value] of Object.entries(entries)) {
46
+ cssLines.push(` ${prefix}${key}: ${value};`);
47
+ }
48
+ }
49
+ cssLines.push("}", "");
50
+ writeFileSync(join(wixDir, "design-tokens.css"), cssLines.join("\n"));
51
+
52
+ // .wix/site.d.ts ------------------------------------------------------------
53
+ const typeFor = (group) => {
54
+ const keys = Object.keys(tokens[group] ?? {});
55
+ if (keys.length === 0) return "Record<string, string>";
56
+ const literal = keys.map((k) => JSON.stringify(k)).join(" | ");
57
+ return `Record<${literal}, string>`;
58
+ };
59
+
60
+ const dts = `// Generated from .wix/site.json.designTokens. Do not edit.
61
+ export type Brand = { name: string; description: string };
62
+ export type DesignTokens = {
63
+ colors: ${typeFor("colors")};
64
+ fonts: ${typeFor("fonts")};
65
+ radii: ${typeFor("radii")};
66
+ 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[]> };
73
+ };
74
+ `;
75
+ writeFileSync(join(wixDir, "site.d.ts"), dts);
76
+
77
+ console.log(`emit-design-tokens: wrote ${join(wixDir, "design-tokens.css")} and ${join(wixDir, "site.d.ts")}`);
@@ -0,0 +1,141 @@
1
+ #!/usr/bin/env node
2
+ // Finalize and write .wix/run.json at the end of the build.
3
+ //
4
+ // The orchestrator collects agent returns, timings, and outcome data over the
5
+ // run. This script takes the orchestrator's draft as a JSON blob via stdin,
6
+ // runs the timing-completeness gate (every required phase MUST have non-null
7
+ // seconds, otherwise emit MISSING_TIMING errors), computes totalSeconds from
8
+ // started/ended, writes the canonical .wix/run.json, and prints the perf
9
+ // one-liner the orchestrator shows in the final message.
10
+ //
11
+ // Usage:
12
+ // echo "$DRAFT_JSON" | node finalize-run-json.mjs <project-dir>
13
+ //
14
+ // Input shape (via stdin):
15
+ // {
16
+ // "run": { started, ended, brand, prompt, verticals, packs },
17
+ // "outcome": { build, previewUrl, dashboardUrl, ... },
18
+ // "phases": [ { phase, status, seconds, data?, errors? }, ... ],
19
+ // "recoveries": [ ... ], // optional; from manifest-check script outputs
20
+ // "errors": [ ... ], // optional; from agent returns / orchestrator
21
+ // "notes": [ ... ], // optional
22
+ // "requiredPhases": ["scaffold","app-install-Wix Stores","env-pull",...]
23
+ // }
24
+ //
25
+ // `requiredPhases` is the orchestrator's set of skill-invoked phases that MUST
26
+ // have a captured duration (scaffold, every app-install-*, env-pull,
27
+ // seed-utilities, npm-install, build, release|preview, etc.). The set is
28
+ // run-specific (number of app-install-* depends on loaded packs), so the
29
+ // orchestrator passes it in rather than the script guessing.
30
+ //
31
+ // Output:
32
+ // - Writes .wix/run.json (full shape, with timing-completeness gate applied).
33
+ // - Prints to stdout: a JSON object with { perfLine, missingTiming, totalSeconds }.
34
+
35
+ import { writeFileSync, mkdirSync, readFileSync } from "node:fs";
36
+ import { join } from "node:path";
37
+
38
+ const projectDir = process.argv[2];
39
+
40
+ if (!projectDir) {
41
+ console.error("usage: cat draft.json | finalize-run-json.mjs <project-dir>");
42
+ process.exit(2);
43
+ }
44
+
45
+ let draft;
46
+ try {
47
+ draft = JSON.parse(readFileSync(0, "utf8"));
48
+ } catch (e) {
49
+ console.error(`finalize-run-json: stdin is not valid JSON (${e.message})`);
50
+ process.exit(2);
51
+ }
52
+
53
+ const run = draft.run ?? {};
54
+ const phases = Array.isArray(draft.phases) ? [...draft.phases] : [];
55
+ const errors = Array.isArray(draft.errors) ? [...draft.errors] : [];
56
+ const recoveries = Array.isArray(draft.recoveries) ? draft.recoveries : [];
57
+ const notes = Array.isArray(draft.notes) ? draft.notes : [];
58
+ const outcome = draft.outcome ?? {};
59
+ const requiredPhases = Array.isArray(draft.requiredPhases) ? draft.requiredPhases : [];
60
+
61
+ // ---- 1. Timing completeness gate ------------------------------------------
62
+ const phasesByName = new Map();
63
+ for (const p of phases) {
64
+ phasesByName.set(p.phase, p);
65
+ }
66
+
67
+ const missingTiming = [];
68
+
69
+ for (const required of requiredPhases) {
70
+ const existing = phasesByName.get(required);
71
+ if (!existing) {
72
+ // Missing entry entirely.
73
+ const entry = { phase: required, status: "unknown", seconds: null };
74
+ phases.push(entry);
75
+ phasesByName.set(required, entry);
76
+ errors.push({ code: "MISSING_TIMING", phase: required });
77
+ missingTiming.push(required);
78
+ } else if (existing.seconds === null || existing.seconds === undefined) {
79
+ existing.seconds = null;
80
+ if (!errors.some((e) => e.code === "MISSING_TIMING" && e.phase === required)) {
81
+ errors.push({ code: "MISSING_TIMING", phase: required });
82
+ }
83
+ missingTiming.push(required);
84
+ }
85
+ }
86
+
87
+ // ---- 2. totalSeconds derivation -------------------------------------------
88
+ if (!run.totalSeconds && run.started && run.ended) {
89
+ const started = Date.parse(run.started);
90
+ const ended = Date.parse(run.ended);
91
+ if (!Number.isNaN(started) && !Number.isNaN(ended) && ended >= started) {
92
+ run.totalSeconds = Math.round((ended - started) / 1000);
93
+ }
94
+ }
95
+
96
+ // ---- 3. Compose final shape -----------------------------------------------
97
+ const final = {
98
+ version: "1.0",
99
+ run,
100
+ outcome,
101
+ phases,
102
+ ...(recoveries.length > 0 ? { recoveries } : {}),
103
+ ...(errors.length > 0 ? { errors } : {}),
104
+ ...(notes.length > 0 ? { notes } : { notes: [] }),
105
+ };
106
+
107
+ const wixDir = join(projectDir, ".wix");
108
+ mkdirSync(wixDir, { recursive: true });
109
+ const runJsonPath = join(wixDir, "run.json");
110
+ writeFileSync(runJsonPath, JSON.stringify(final, null, 2) + "\n");
111
+
112
+ // ---- 4. Perf one-liner ----------------------------------------------------
113
+ // Format: "Built in <Nm Ss> — design-system <n>s · images (phase 1 + phase 2) <n>s · build+release <n>s"
114
+ const fmtSeconds = (sec) => (sec === null || sec === undefined ? "–" : `${sec}s`);
115
+ const fmtTotal = (sec) => {
116
+ if (sec === null || sec === undefined) return "–";
117
+ const m = Math.floor(sec / 60);
118
+ const s = sec % 60;
119
+ return `${m}m ${s}s`;
120
+ };
121
+ const phaseSeconds = (name) => {
122
+ const p = phasesByName.get(name);
123
+ return p && p.seconds !== null && p.seconds !== undefined ? p.seconds : null;
124
+ };
125
+ const designSystem = phaseSeconds("design-system");
126
+ const img1 = phaseSeconds("image-phase-1-decorative");
127
+ const img2 = phaseSeconds("image-phase-2-entity");
128
+ const imgTotal = img1 !== null && img2 !== null ? img1 + img2 : null;
129
+ const build = phaseSeconds("build");
130
+ const release = phaseSeconds("release") ?? phaseSeconds("preview");
131
+ const buildPlusRelease = build !== null && release !== null ? build + release : null;
132
+
133
+ const perfLine = `Built in ${fmtTotal(run.totalSeconds)} — design-system ${fmtSeconds(designSystem)} · images (phase 1 + phase 2) ${fmtSeconds(imgTotal)} · build+release ${fmtSeconds(buildPlusRelease)}`;
134
+
135
+ console.log(JSON.stringify({
136
+ status: missingTiming.length > 0 ? "partial" : "ok",
137
+ path: runJsonPath,
138
+ totalSeconds: run.totalSeconds ?? null,
139
+ missingTiming,
140
+ perfLine,
141
+ }, null, 2));
@@ -0,0 +1,63 @@
1
+ #!/usr/bin/env node
2
+ // Write the initial .wix/site.json shape during Setup. Site.json is the
3
+ // single source of truth that every downstream phase reads from / appends
4
+ // to. This script writes the canonical initial structure deterministically
5
+ // so the orchestrator never has to compose the shape inline (which used
6
+ // to be LLM-emitted JSON, with the obvious drift risks).
7
+ //
8
+ // Usage:
9
+ // node init-site-json.mjs <project-dir> <brand-name> <brand-description> <verticals-csv>
10
+ //
11
+ // Example:
12
+ // node init-site-json.mjs /tmp/proj "Acme Coffee" "Warm cream-and-forest editorial" "stores,ecom,cms,gift-cards"
13
+ //
14
+ // Behavior:
15
+ // - Refuses to overwrite an existing .wix/site.json (exit 2). The orchestrator
16
+ // should call this exactly once during Setup. To re-init for testing, the
17
+ // caller can rm the file first.
18
+ // - Creates .wix/ if it doesn't exist.
19
+ // - Outputs a JSON summary to stdout.
20
+
21
+ import { writeFileSync, existsSync, mkdirSync } from "node:fs";
22
+ import { join } from "node:path";
23
+
24
+ const [, , projectDir, brandName, brandDescription, verticalsCsv] = process.argv;
25
+
26
+ if (!projectDir || !brandName || brandDescription === undefined || !verticalsCsv) {
27
+ console.error("usage: init-site-json.mjs <project-dir> <brand-name> <brand-description> <verticals-csv>");
28
+ process.exit(2);
29
+ }
30
+
31
+ const verticals = verticalsCsv
32
+ .split(",")
33
+ .map((v) => v.trim())
34
+ .filter(Boolean);
35
+
36
+ if (verticals.length === 0) {
37
+ console.error("init-site-json: <verticals-csv> resolved to zero verticals — cms is always loaded, so this is a bug");
38
+ process.exit(2);
39
+ }
40
+
41
+ const wixDir = join(projectDir, ".wix");
42
+ const sitePath = join(wixDir, "site.json");
43
+
44
+ if (existsSync(sitePath)) {
45
+ console.error(`init-site-json: ${sitePath} already exists — refusing to overwrite. Setup should call this exactly once.`);
46
+ process.exit(2);
47
+ }
48
+
49
+ mkdirSync(wixDir, { recursive: true });
50
+
51
+ const site = {
52
+ brand: {
53
+ name: brandName,
54
+ description: brandDescription,
55
+ },
56
+ seeded: {},
57
+ designTokens: {},
58
+ verticals,
59
+ };
60
+
61
+ writeFileSync(sitePath, JSON.stringify(site, null, 2) + "\n");
62
+
63
+ console.log(JSON.stringify({ status: "ok", path: sitePath, verticals }, null, 2));