@nextcommerce/campaigns-os 1.33.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 (310) hide show
  1. package/AGENTS.md +204 -0
  2. package/CHANGELOG.md +5002 -0
  3. package/CONTEXT.md +685 -0
  4. package/LICENSE +202 -0
  5. package/NOTICE +4 -0
  6. package/README.md +368 -0
  7. package/agents/claude/CLAUDE.md +32 -0
  8. package/agents/codex/AGENTS.md +27 -0
  9. package/agents/copilot/copilot-instructions.md +14 -0
  10. package/agents/cursor/campaigns-os.mdc +13 -0
  11. package/bin/campaigns-os.mjs +38 -0
  12. package/campaign-spec/README.md +138 -0
  13. package/campaign-spec/dist/analytics-vocabulary.d.ts +47 -0
  14. package/campaign-spec/dist/analytics-vocabulary.js +74 -0
  15. package/campaign-spec/dist/index.d.ts +40 -0
  16. package/campaign-spec/dist/index.js +77 -0
  17. package/campaign-spec/dist/normalize.d.ts +22 -0
  18. package/campaign-spec/dist/normalize.js +41 -0
  19. package/campaign-spec/dist/routing.d.ts +190 -0
  20. package/campaign-spec/dist/routing.js +263 -0
  21. package/campaign-spec/dist/rules/analytics-contract-shape.d.ts +42 -0
  22. package/campaign-spec/dist/rules/analytics-contract-shape.js +303 -0
  23. package/campaign-spec/dist/rules/assembly-hints-shape.d.ts +42 -0
  24. package/campaign-spec/dist/rules/assembly-hints-shape.js +191 -0
  25. package/campaign-spec/dist/rules/campaign-metadata.d.ts +14 -0
  26. package/campaign-spec/dist/rules/campaign-metadata.js +40 -0
  27. package/campaign-spec/dist/rules/checkout-has-success-url.d.ts +31 -0
  28. package/campaign-spec/dist/rules/checkout-has-success-url.js +66 -0
  29. package/campaign-spec/dist/rules/cycle-detection.d.ts +12 -0
  30. package/campaign-spec/dist/rules/cycle-detection.js +141 -0
  31. package/campaign-spec/dist/rules/design-source-shape.d.ts +29 -0
  32. package/campaign-spec/dist/rules/design-source-shape.js +142 -0
  33. package/campaign-spec/dist/rules/downsell-without-upsell.d.ts +11 -0
  34. package/campaign-spec/dist/rules/downsell-without-upsell.js +40 -0
  35. package/campaign-spec/dist/rules/exit-intent-validation.d.ts +23 -0
  36. package/campaign-spec/dist/rules/exit-intent-validation.js +147 -0
  37. package/campaign-spec/dist/rules/funnel-count.d.ts +9 -0
  38. package/campaign-spec/dist/rules/funnel-count.js +37 -0
  39. package/campaign-spec/dist/rules/funnel-hypothesis-length.d.ts +22 -0
  40. package/campaign-spec/dist/rules/funnel-hypothesis-length.js +60 -0
  41. package/campaign-spec/dist/rules/funnel-identity.d.ts +15 -0
  42. package/campaign-spec/dist/rules/funnel-identity.js +57 -0
  43. package/campaign-spec/dist/rules/funnel-weight-sum.d.ts +20 -0
  44. package/campaign-spec/dist/rules/funnel-weight-sum.js +66 -0
  45. package/campaign-spec/dist/rules/index.d.ts +69 -0
  46. package/campaign-spec/dist/rules/index.js +131 -0
  47. package/campaign-spec/dist/rules/offer-ref-integrity.d.ts +13 -0
  48. package/campaign-spec/dist/rules/offer-ref-integrity.js +59 -0
  49. package/campaign-spec/dist/rules/package-pricing-sanity.d.ts +12 -0
  50. package/campaign-spec/dist/rules/package-pricing-sanity.js +42 -0
  51. package/campaign-spec/dist/rules/page-count.d.ts +11 -0
  52. package/campaign-spec/dist/rules/page-count.js +31 -0
  53. package/campaign-spec/dist/rules/page-id-uniqueness.d.ts +14 -0
  54. package/campaign-spec/dist/rules/page-id-uniqueness.js +47 -0
  55. package/campaign-spec/dist/rules/promo-code-input-validation.d.ts +8 -0
  56. package/campaign-spec/dist/rules/promo-code-input-validation.js +126 -0
  57. package/campaign-spec/dist/rules/promo-codes-shape.d.ts +30 -0
  58. package/campaign-spec/dist/rules/promo-codes-shape.js +187 -0
  59. package/campaign-spec/dist/rules/route-field-ignored-for-page-type.d.ts +33 -0
  60. package/campaign-spec/dist/rules/route-field-ignored-for-page-type.js +81 -0
  61. package/campaign-spec/dist/rules/route-target-resolves.d.ts +32 -0
  62. package/campaign-spec/dist/rules/route-target-resolves.js +112 -0
  63. package/campaign-spec/dist/rules/schema-version.d.ts +21 -0
  64. package/campaign-spec/dist/rules/schema-version.js +53 -0
  65. package/campaign-spec/dist/rules/sdk-version.d.ts +26 -0
  66. package/campaign-spec/dist/rules/sdk-version.js +96 -0
  67. package/campaign-spec/dist/rules/shipping-countries-shape.d.ts +10 -0
  68. package/campaign-spec/dist/rules/shipping-countries-shape.js +30 -0
  69. package/campaign-spec/dist/rules/shipping-methods-present.d.ts +10 -0
  70. package/campaign-spec/dist/rules/shipping-methods-present.js +26 -0
  71. package/campaign-spec/dist/rules/store-profile-shape.d.ts +30 -0
  72. package/campaign-spec/dist/rules/store-profile-shape.js +127 -0
  73. package/campaign-spec/dist/rules/thank-you-requirement.d.ts +16 -0
  74. package/campaign-spec/dist/rules/thank-you-requirement.js +50 -0
  75. package/campaign-spec/dist/rules/unknown-top-level-fields.d.ts +28 -0
  76. package/campaign-spec/dist/rules/unknown-top-level-fields.js +114 -0
  77. package/campaign-spec/dist/rules/upsell-has-packages.d.ts +9 -0
  78. package/campaign-spec/dist/rules/upsell-has-packages.js +35 -0
  79. package/campaign-spec/dist/rules/upsell-routing-complete.d.ts +10 -0
  80. package/campaign-spec/dist/rules/upsell-routing-complete.js +45 -0
  81. package/campaign-spec/dist/rules/upsell-without-checkout.d.ts +11 -0
  82. package/campaign-spec/dist/rules/upsell-without-checkout.js +44 -0
  83. package/campaign-spec/dist/rules/variant-labels-shape.d.ts +28 -0
  84. package/campaign-spec/dist/rules/variant-labels-shape.js +86 -0
  85. package/campaign-spec/dist/sdk-version-parse.d.ts +43 -0
  86. package/campaign-spec/dist/sdk-version-parse.js +62 -0
  87. package/campaign-spec/dist/types.d.ts +674 -0
  88. package/campaign-spec/dist/types.js +40 -0
  89. package/campaign-spec/package.json +12 -0
  90. package/compatibility.json +25 -0
  91. package/contracts/agent-relevant-change-policy.v1.json +111 -0
  92. package/contracts/brand-theme-source-defaults.figma-sections-export.v0.json +32 -0
  93. package/contracts/brand-theme-target-tokens.next-core.v0.json +65 -0
  94. package/contracts/campaign-cart-checkout-field-contract.v0.json +45 -0
  95. package/contracts/campaign-cart-sdk-support-policy.v0.json +11 -0
  96. package/contracts/commerce-surface-catalog.json +2452 -0
  97. package/contracts/fixtures/orientation/canonicalization/v1.json +34 -0
  98. package/contracts/fixtures/orientation/envelope/current.json +95 -0
  99. package/contracts/fixtures/orientation/envelope/freshness_unknown.json +97 -0
  100. package/contracts/fixtures/orientation/envelope/legacy_baseline.json +95 -0
  101. package/contracts/fixtures/orientation/envelope/orientation_available.json +136 -0
  102. package/contracts/fixtures/orientation/envelope/recovered_interrupted_update.json +136 -0
  103. package/contracts/fixtures/orientation/envelope/refused.json +100 -0
  104. package/contracts/fixtures/orientation/envelope/restart_required.json +137 -0
  105. package/contracts/fixtures/orientation/envelope/updated.json +135 -0
  106. package/contracts/fixtures/orientation/hostile-target/README.md +61 -0
  107. package/contracts/fixtures/orientation/hostile-target/manifest.json +82 -0
  108. package/contracts/fixtures/orientation/hostile-target/repo/CHANGELOG.md +18 -0
  109. package/contracts/fixtures/orientation/hostile-target/repo/bin/intended.mjs +12 -0
  110. package/contracts/fixtures/orientation/hostile-target/repo/bin/tripwire.mjs +15 -0
  111. package/contracts/fixtures/orientation/hostile-target/repo/contracts/release-ledger.json +48 -0
  112. package/contracts/fixtures/orientation/hostile-target/repo/contracts/supported-surface.json +17 -0
  113. package/contracts/fixtures/orientation/hostile-target/repo/docs/example-contract.md +13 -0
  114. package/contracts/fixtures/orientation/hostile-target/repo/hooks/post-checkout +5 -0
  115. package/contracts/fixtures/orientation/hostile-target/repo/hooks/post-merge +5 -0
  116. package/contracts/fixtures/orientation/hostile-target/repo/hooks/pre-commit +5 -0
  117. package/contracts/fixtures/orientation/hostile-target/repo/hostile-dependency-tripwire/package.json +15 -0
  118. package/contracts/fixtures/orientation/hostile-target/repo/hostile-dependency-tripwire/tripwire.mjs +9 -0
  119. package/contracts/fixtures/orientation/hostile-target/repo/package.json +20 -0
  120. package/contracts/fixtures/orientation/hostile-target/repo/schemas/example.v0.schema.json +15 -0
  121. package/contracts/fixtures/orientation/release-gate/cases.json +1073 -0
  122. package/contracts/fixtures/runtime-recipe/accept/current.json +299 -0
  123. package/contracts/fixtures/runtime-recipe/accept/minimal.json +294 -0
  124. package/contracts/fixtures/runtime-recipe/dist-states.json +51 -0
  125. package/contracts/fixtures/runtime-recipe/manifest.json +85 -0
  126. package/contracts/fixtures/runtime-recipe/reject/advisory-enforcement.json +299 -0
  127. package/contracts/fixtures/runtime-recipe/reject/allowlist-without-hosts.json +297 -0
  128. package/contracts/fixtures/runtime-recipe/reject/committed-output-claim.json +299 -0
  129. package/contracts/fixtures/runtime-recipe/reject/engines-disagreement-warns.json +299 -0
  130. package/contracts/fixtures/runtime-recipe/reject/lifecycle-scripts-enabled.json +299 -0
  131. package/contracts/fixtures/runtime-recipe/reject/missing-required-field.json +251 -0
  132. package/contracts/fixtures/runtime-recipe/reject/unknown-kind.json +299 -0
  133. package/contracts/fixtures/runtime-recipe/reject/unknown-network-policy.json +299 -0
  134. package/contracts/fixtures/runtime-recipe/reject/unknown-output-check.json +310 -0
  135. package/contracts/fixtures/runtime-recipe/reject/unknown-revision.json +299 -0
  136. package/contracts/fixtures/runtime-recipe/reject/unknown-step-id.json +299 -0
  137. package/contracts/fixtures/runtime-recipe/reject/unperformable-check-skipped.json +299 -0
  138. package/contracts/fixtures/runtime-recipe/reject/unpinned-lockfile.json +299 -0
  139. package/contracts/fixtures/sidecar-bundle/production-shaped/.campaign-runtime/assembly-report.json +180 -0
  140. package/contracts/fixtures/sidecar-bundle/production-shaped/.campaign-runtime/build-context.json +115 -0
  141. package/contracts/fixtures/sidecar-bundle/production-shaped/.campaign-runtime/doctor-output.json +29 -0
  142. package/contracts/fixtures/sidecar-bundle/production-shaped/.campaign-runtime/qa-verdict.json +27 -0
  143. package/contracts/fixtures/sidecar-bundle/production-shaped/campaign-runtime.build.json +141 -0
  144. package/contracts/migration-sidecar-bundle.v0.json +149 -0
  145. package/contracts/orientation-limits.v1.json +41 -0
  146. package/contracts/orientation-reason-codes.v1.json +196 -0
  147. package/contracts/private-template-sources.json +8 -0
  148. package/contracts/release-ledger.json +4598 -0
  149. package/contracts/reserved-skill-names.json +13 -0
  150. package/contracts/runtime-recipe.campaigns-os-node-v1.json +299 -0
  151. package/contracts/supported-surface.json +180 -0
  152. package/contracts/template-brand-contract.apollo-mv-single-step.v0.json +27 -0
  153. package/contracts/template-brand-contract.apollo.v0.json +27 -0
  154. package/contracts/template-brand-contract.demeter.v0.json +27 -0
  155. package/contracts/template-brand-contract.olympus-mv-single-step.v0.json +27 -0
  156. package/contracts/template-brand-contract.olympus-mv-two-step.v0.json +28 -0
  157. package/contracts/template-brand-contract.olympus.v0.json +27 -0
  158. package/contracts/template-brand-contract.shared-commerce.v0.json +190 -0
  159. package/contracts/template-brand-contract.shop-single-step.v0.json +27 -0
  160. package/contracts/template-brand-contract.shop-three-step.v0.json +29 -0
  161. package/contracts/template-slot-manifest.apollo-mv-single-step.v0.json +14 -0
  162. package/contracts/template-slot-manifest.apollo.v0.json +12 -0
  163. package/contracts/template-slot-manifest.demeter.v0.json +30 -0
  164. package/contracts/template-slot-manifest.olympus-mv-single-step.v0.json +14 -0
  165. package/contracts/template-slot-manifest.olympus-mv-two-step.v0.json +15 -0
  166. package/contracts/template-slot-manifest.olympus.v0.json +12 -0
  167. package/contracts/template-slot-manifest.shared-content-core.v0.json +4254 -0
  168. package/contracts/template-slot-manifest.shop-single-step.v0.json +47 -0
  169. package/contracts/template-slot-manifest.shop-three-step.v0.json +33 -0
  170. package/docs/brand-theme-bridge.md +159 -0
  171. package/docs/build-packet.md +1300 -0
  172. package/docs/campaign-build-brief.md +145 -0
  173. package/docs/campaign-standardization-report.md +329 -0
  174. package/docs/campaigns-os-build-flow.md +117 -0
  175. package/docs/design-source-package.md +784 -0
  176. package/docs/legacy-migration.md +58 -0
  177. package/docs/migration-sidecar-bundle.md +139 -0
  178. package/docs/orientation-contract-reference.md +1220 -0
  179. package/docs/polish-evidence.md +502 -0
  180. package/docs/qa-and-test-orders.md +1691 -0
  181. package/docs/release-ledger-authoring-guide.md +274 -0
  182. package/docs/runtime-readiness.md +211 -0
  183. package/docs/supported-surface.md +83 -0
  184. package/docs/versioning.md +55 -0
  185. package/docs/workflow-findings-sidecar.md +588 -0
  186. package/package.json +135 -0
  187. package/prompts/first-build.md +27 -0
  188. package/prompts/friction-log.md +30 -0
  189. package/schemas/campaign-build-brief.v1.schema.json +149 -0
  190. package/schemas/campaign-design-source-package.v0.schema.json +697 -0
  191. package/schemas/campaign-runtime-assembly-report.v0.schema.json +390 -0
  192. package/schemas/campaign-runtime-build-context.v0.schema.json +339 -0
  193. package/schemas/campaign-runtime-build-packet.v0.schema.json +452 -0
  194. package/schemas/campaign-spec.v4.schema.json +582 -0
  195. package/schemas/campaigns-os-doctor-output.v0.schema.json +43 -0
  196. package/schemas/campaigns-os-legacy-migration-inventory.v0.schema.json +112 -0
  197. package/schemas/campaigns-os-legacy-provisioning-plan.v0.schema.json +38 -0
  198. package/schemas/campaigns-os-legacy-provisioning-receipt.v0.schema.json +57 -0
  199. package/schemas/campaigns-os-qa-verdict-sidecar.v0.schema.json +150 -0
  200. package/schemas/campaigns-os-qa-verdict.v0.schema.json +438 -0
  201. package/schemas/campaigns-os-release-ledger.v1.schema.json +162 -0
  202. package/schemas/campaigns-os-run-record.v0.schema.json +343 -0
  203. package/schemas/campaigns-os-runtime-recipe.v1.schema.json +313 -0
  204. package/schemas/campaigns-os-sidecar-bundle-conformance.v0.schema.json +78 -0
  205. package/schemas/campaigns-os-tooling-orientation.v1.schema.json +381 -0
  206. package/schemas/campaigns-os-workflow-finding.v0.schema.json +134 -0
  207. package/schemas/source-html-manifest.v0.schema.json +252 -0
  208. package/skills/next-campaigns-build/SKILL.md +73 -0
  209. package/skills/next-campaigns-os/SKILL.md +101 -0
  210. package/skills/next-campaigns-os/references/session-intake.md +160 -0
  211. package/skills/next-campaigns-os-setup/SKILL.md +22 -0
  212. package/skills/next-campaigns-polish/SKILL.md +145 -0
  213. package/skills/next-campaigns-qa/SKILL.md +92 -0
  214. package/skills.json +56 -0
  215. package/skills.sh +64 -0
  216. package/src/adapter-decision-contract.mjs +333 -0
  217. package/src/brand-theme.mjs +1151 -0
  218. package/src/browser-launch.mjs +79 -0
  219. package/src/build-brief.mjs +781 -0
  220. package/src/built-site-scope.mjs +312 -0
  221. package/src/campaign-ecosystem.mjs +734 -0
  222. package/src/campaign-identity.mjs +405 -0
  223. package/src/campaign-workspace.mjs +127 -0
  224. package/src/checkpoint-waiver.mjs +302 -0
  225. package/src/cli.mjs +13442 -0
  226. package/src/commercial-journey.mjs +1119 -0
  227. package/src/commercial-parity.mjs +965 -0
  228. package/src/consent.mjs +347 -0
  229. package/src/content-residue.mjs +322 -0
  230. package/src/deadline.mjs +81 -0
  231. package/src/design-source-package.mjs +2604 -0
  232. package/src/deviation.mjs +107 -0
  233. package/src/doctor-check-registry.mjs +49 -0
  234. package/src/doctor-sidecar.mjs +106 -0
  235. package/src/finding-cause.mjs +557 -0
  236. package/src/findings.mjs +326 -0
  237. package/src/fs-identity.mjs +68 -0
  238. package/src/gate-actions.mjs +105 -0
  239. package/src/html-scan.mjs +53 -0
  240. package/src/install-mode.mjs +272 -0
  241. package/src/legacy-migration.d.ts +128 -0
  242. package/src/legacy-migration.mjs +510 -0
  243. package/src/lifecycle.mjs +338 -0
  244. package/src/local-proof.mjs +401 -0
  245. package/src/map-pin-writeback.mjs +210 -0
  246. package/src/orchestration-stage-contract.mjs +81 -0
  247. package/src/package-install-fixture.mjs +33 -0
  248. package/src/page-kit-build-summary.mjs +175 -0
  249. package/src/page-kit-campaign-config.mjs +57 -0
  250. package/src/page-kit-sdk-version.mjs +392 -0
  251. package/src/page-kit-store-profile.mjs +369 -0
  252. package/src/page-kit-sync.mjs +162 -0
  253. package/src/polish-browser.mjs +867 -0
  254. package/src/polish-capture.mjs +1094 -0
  255. package/src/polish-deadline.mjs +51 -0
  256. package/src/polish-gate.mjs +739 -0
  257. package/src/polish-node.mjs +639 -0
  258. package/src/polish-page-load.mjs +1100 -0
  259. package/src/private-template-source.mjs +237 -0
  260. package/src/proof-policy.mjs +82 -0
  261. package/src/qa-analytics-correctness.mjs +307 -0
  262. package/src/qa-analytics-errors.mjs +38 -0
  263. package/src/qa-analytics-parity.mjs +699 -0
  264. package/src/qa-binding-evidence.mjs +140 -0
  265. package/src/qa-browser.mjs +6608 -0
  266. package/src/qa-cart-entry.mjs +406 -0
  267. package/src/qa-commercial-parity.mjs +641 -0
  268. package/src/qa-node.mjs +3620 -0
  269. package/src/qa-order-bump.mjs +381 -0
  270. package/src/qa-parity-capture.mjs +428 -0
  271. package/src/qa-parity-fixture.mjs +359 -0
  272. package/src/qa-publish.mjs +362 -0
  273. package/src/qa-purchase-data-layer.mjs +263 -0
  274. package/src/qa-route-probe.mjs +272 -0
  275. package/src/qa-sidecar.mjs +188 -0
  276. package/src/qa-test-order-topology.mjs +207 -0
  277. package/src/qa-url-privacy.mjs +13 -0
  278. package/src/qa-verdict-discovery.mjs +192 -0
  279. package/src/qa-verdict-publish.mjs +105 -0
  280. package/src/qa-verdict.mjs +287 -0
  281. package/src/remit.mjs +388 -0
  282. package/src/repo-scan.mjs +83 -0
  283. package/src/route-identity.mjs +133 -0
  284. package/src/run-record-closeout.mjs +229 -0
  285. package/src/run-record.mjs +839 -0
  286. package/src/run-session.mjs +226 -0
  287. package/src/runtime-state-ignore.mjs +113 -0
  288. package/src/sdk-attribute-index.mjs +212 -0
  289. package/src/sdk-markup.mjs +358 -0
  290. package/src/sdk-meta-tags.mjs +52 -0
  291. package/src/shell-token.mjs +7 -0
  292. package/src/sidecar-bundle.mjs +399 -0
  293. package/src/source-asset-crawl.mjs +469 -0
  294. package/src/source-html-intake.mjs +627 -0
  295. package/src/source-html-manifest.mjs +276 -0
  296. package/src/source-prep.mjs +284 -0
  297. package/src/spec-derive-store.mjs +431 -0
  298. package/src/spec-derive.mjs +514 -0
  299. package/src/spec-fetch.mjs +66 -0
  300. package/src/spec-hash.mjs +48 -0
  301. package/src/spec-identity.mjs +27 -0
  302. package/src/stage-ledger.mjs +509 -0
  303. package/src/standardization-report.mjs +1297 -0
  304. package/src/template-brand-contract.mjs +473 -0
  305. package/src/template-freshness.mjs +196 -0
  306. package/src/template-reference.mjs +81 -0
  307. package/src/template-slot-manifest.mjs +150 -0
  308. package/src/text-safety.mjs +62 -0
  309. package/src/theme-gate.mjs +185 -0
  310. package/src/upsell-selector-scope.mjs +299 -0
@@ -0,0 +1,333 @@
1
+ import { existsSync, readFileSync, statSync } from "node:fs";
2
+ import { relative, resolve } from "node:path";
3
+
4
+ export const ADAPTER_DECISION_REQUIRED_FIELDS = Object.freeze([
5
+ "raw_html_conversion_status",
6
+ "source_asset_strategy",
7
+ "commerce_shell_adoption",
8
+ "route_rewrite_policy",
9
+ "template_files_copied",
10
+ "config_script_strategy",
11
+ "wrapper_policy",
12
+ "frontmatter_policy",
13
+ "script_style_reference_policy",
14
+ "cta_rewrite_policy",
15
+ "layout_choice",
16
+ ]);
17
+
18
+ export const ADAPTER_DECISION_STRATEGY_FIELDS = Object.freeze([
19
+ "raw_html_conversion_status",
20
+ "source_asset_strategy",
21
+ "route_rewrite_policy",
22
+ "config_script_strategy",
23
+ "commerce_shell_adoption",
24
+ "wrapper_policy",
25
+ "frontmatter_policy",
26
+ "script_style_reference_policy",
27
+ "cta_rewrite_policy",
28
+ "layout_choice",
29
+ ]);
30
+
31
+ export const TEMPLATE_SLICE_REQUIRED_GROUPS = Object.freeze([
32
+ "pages",
33
+ "_includes",
34
+ "_layouts",
35
+ "assets/css",
36
+ "assets/js",
37
+ "frontmatter_vocabulary",
38
+ ]);
39
+
40
+ const TEMPLATE_FILES_COPIED_REQUIRED_FIELDS = Object.freeze(["status", "required_groups", "groups", "paths"]);
41
+ const RUNTIME_PAGE_TYPES = new Set(["checkout", "select", "upsell", "downsell", "thankyou", "receipt"]);
42
+ const RAW_HTML_CONVERSION_STATUSES = new Set(["pending", "in_progress", "completed", "not_required", "blocked"]);
43
+ const SOURCE_ASSET_STRATEGIES = new Set(["pagekit_campaign_asset_root", "external_cdn", "raw_passthrough", "not_applicable", "unknown"]);
44
+ const ROUTE_REWRITE_POLICIES = new Set(["campaignspec_routes_via_campaign_link", "pagekit_public_routes", "raw_passthrough", "not_applicable", "unknown"]);
45
+ const CONFIG_SCRIPT_STRATEGIES = new Set(["campaign_asset", "frontmatter_script", "inline", "not_required", "unknown"]);
46
+ const COMMERCE_SHELL_ADOPTIONS = new Set(["not_required", "template_clone_first_required", "template_clone_first_verified", "sdk_surfaces_preserved", "custom_html_experimental"]);
47
+ const TEMPLATE_FILES_COPIED_STATUSES = new Set(["pending", "complete", "verified_existing_slice", "partial", "not_applicable"]);
48
+ // The single wrapper-policy vocabulary. Every channel that can select a
49
+ // policy — the adapter contract on the packet, the source-html manifest key,
50
+ // and the prepare-build CLI flag — reads this list, so there is exactly one
51
+ // value set and one spelling of each value.
52
+ export const ADAPTER_WRAPPER_POLICIES = Object.freeze([
53
+ "strip_document_wrappers",
54
+ "preserve_document_wrappers",
55
+ "not_required",
56
+ "unknown",
57
+ ]);
58
+ export const DEFAULT_WRAPPER_POLICY = "strip_document_wrappers";
59
+ const WRAPPER_POLICIES = new Set(ADAPTER_WRAPPER_POLICIES);
60
+
61
+ export function isWrapperPolicy(value) {
62
+ return typeof value === "string" && WRAPPER_POLICIES.has(value);
63
+ }
64
+ const FRONTMATTER_POLICIES = new Set(["pagekit_yaml_frontmatter", "raw_passthrough", "not_required", "unknown"]);
65
+ const SCRIPT_STYLE_REFERENCE_POLICIES = new Set(["frontmatter_or_campaign_asset", "frontmatter", "campaign_asset", "inline", "raw_passthrough", "not_required", "unknown"]);
66
+ const CTA_REWRITE_POLICIES = ROUTE_REWRITE_POLICIES;
67
+ const LAYOUT_CHOICES = new Set(["campaign_layout", "page_layout", "raw_passthrough", "not_applicable", "unknown"]);
68
+
69
+ /**
70
+ * Seeds the adapter decision record written onto a new Build Packet.
71
+ *
72
+ * `wrapperPolicy` is the operator-selected document-wrapper policy resolved by
73
+ * the caller (prepare-build) from the CLI flag and the source-html manifest.
74
+ * An unrecognized or absent value falls back to the default, so a caller that
75
+ * does not resolve one keeps the previous behavior exactly.
76
+ */
77
+ export function createAdapterDecisions({ commerceZoneFindings = [], wrapperPolicy = null } = {}) {
78
+ const shellRequired = commerceZoneFindings.some((finding) => finding?.requires_template_shell === true);
79
+ return {
80
+ raw_html_conversion_status: "pending",
81
+ source_asset_strategy: "pagekit_campaign_asset_root",
82
+ route_rewrite_policy: "campaignspec_routes_via_campaign_link",
83
+ config_script_strategy: "campaign_asset",
84
+ commerce_shell_adoption: shellRequired ? "template_clone_first_required" : "not_required",
85
+ wrapper_policy: isWrapperPolicy(wrapperPolicy) ? wrapperPolicy : DEFAULT_WRAPPER_POLICY,
86
+ frontmatter_policy: "pagekit_yaml_frontmatter",
87
+ script_style_reference_policy: "frontmatter_or_campaign_asset",
88
+ cta_rewrite_policy: "campaignspec_routes_via_campaign_link",
89
+ layout_choice: "campaign_layout",
90
+ template_files_copied: {
91
+ status: "pending",
92
+ required_groups: [...TEMPLATE_SLICE_REQUIRED_GROUPS],
93
+ groups: [],
94
+ paths: [],
95
+ },
96
+ };
97
+ }
98
+
99
+ export function validateAdapterDecisionShape(decisions, location, warnings, ready, { addIssue }) {
100
+ if (!decisions) {
101
+ addIssue(warnings, location, `${location} is missing; adapter choices are not doctor-able. New prepare-build runs write source_asset_strategy, commerce_shell_adoption, route_rewrite_policy, template_files_copied, config_script_strategy, raw_html_conversion_status, wrapper_policy, frontmatter_policy, script_style_reference_policy, cta_rewrite_policy, and layout_choice.`);
102
+ return;
103
+ }
104
+ if (!isObject(decisions)) {
105
+ addIssue(warnings, location, `${location} must be an object when present.`);
106
+ return;
107
+ }
108
+ for (const field of ADAPTER_DECISION_REQUIRED_FIELDS) {
109
+ if (!(field in decisions)) {
110
+ addIssue(warnings, `${location}.${field}`, `${location}.${field} is missing; adapter decisions must carry every required public contract field.`);
111
+ }
112
+ }
113
+ checkEnum(decisions.raw_html_conversion_status, RAW_HTML_CONVERSION_STATUSES, `${location}.raw_html_conversion_status`, warnings, addIssue);
114
+ checkEnum(decisions.source_asset_strategy, SOURCE_ASSET_STRATEGIES, `${location}.source_asset_strategy`, warnings, addIssue);
115
+ checkEnum(decisions.route_rewrite_policy, ROUTE_REWRITE_POLICIES, `${location}.route_rewrite_policy`, warnings, addIssue);
116
+ checkEnum(decisions.config_script_strategy, CONFIG_SCRIPT_STRATEGIES, `${location}.config_script_strategy`, warnings, addIssue);
117
+ checkEnum(decisions.commerce_shell_adoption, COMMERCE_SHELL_ADOPTIONS, `${location}.commerce_shell_adoption`, warnings, addIssue);
118
+ checkEnum(decisions.wrapper_policy, WRAPPER_POLICIES, `${location}.wrapper_policy`, warnings, addIssue);
119
+ checkEnum(decisions.frontmatter_policy, FRONTMATTER_POLICIES, `${location}.frontmatter_policy`, warnings, addIssue);
120
+ checkEnum(decisions.script_style_reference_policy, SCRIPT_STYLE_REFERENCE_POLICIES, `${location}.script_style_reference_policy`, warnings, addIssue);
121
+ checkEnum(decisions.cta_rewrite_policy, CTA_REWRITE_POLICIES, `${location}.cta_rewrite_policy`, warnings, addIssue);
122
+ checkEnum(decisions.layout_choice, LAYOUT_CHOICES, `${location}.layout_choice`, warnings, addIssue);
123
+
124
+ const copied = decisions.template_files_copied;
125
+ if (copied != null) {
126
+ if (!isObject(copied)) {
127
+ addIssue(warnings, `${location}.template_files_copied`, `${location}.template_files_copied must be an object when present.`);
128
+ } else {
129
+ for (const field of TEMPLATE_FILES_COPIED_REQUIRED_FIELDS) {
130
+ if (!(field in copied)) {
131
+ addIssue(warnings, `${location}.template_files_copied.${field}`, `${location}.template_files_copied.${field} is missing; template slice proof must record status, required_groups, groups, and paths.`);
132
+ }
133
+ }
134
+ checkEnum(copied.status, TEMPLATE_FILES_COPIED_STATUSES, `${location}.template_files_copied.status`, warnings, addIssue);
135
+ if (copied.required_groups != null && !Array.isArray(copied.required_groups)) {
136
+ addIssue(warnings, `${location}.template_files_copied.required_groups`, `${location}.template_files_copied.required_groups must be an array.`);
137
+ }
138
+ if (copied.groups != null && !Array.isArray(copied.groups)) {
139
+ addIssue(warnings, `${location}.template_files_copied.groups`, `${location}.template_files_copied.groups must be an array.`);
140
+ }
141
+ if (copied.paths != null && !Array.isArray(copied.paths)) {
142
+ addIssue(warnings, `${location}.template_files_copied.paths`, `${location}.template_files_copied.paths must be an array.`);
143
+ }
144
+ }
145
+ }
146
+ ready.push(`${location} adapter decision fields loaded`);
147
+ }
148
+
149
+ export function validateAdapterSourceFiles({ decisions, sourceRoot, pages = [], warnings, ready, addIssue }) {
150
+ if (!isObject(decisions)) return;
151
+ const status = decisions.raw_html_conversion_status;
152
+ if (!["completed", "not_required"].includes(status)) return;
153
+
154
+ if (!sourceRoot || !existsSync(sourceRoot) || !statSync(sourceRoot).isDirectory()) return;
155
+ const hits = [];
156
+ for (const page of pages || []) {
157
+ if (!page.path) continue;
158
+ const fullPath = resolve(sourceRoot, page.path);
159
+ if (!existsSync(fullPath) || !statSync(fullPath).isFile()) continue;
160
+ const content = readFileSync(fullPath, "utf8");
161
+ const wrappers = collectDocumentWrapperNames(content);
162
+ if (wrappers.length) hits.push({ path: page.path, wrappers });
163
+ }
164
+ if (!hits.length) {
165
+ ready.push("Source adapter wrapper check found no document wrappers in completed source pages");
166
+ return;
167
+ }
168
+ const sample = hits.slice(0, 4).map((hit) => `${hit.path} (${hit.wrappers.join(", ")})`).join("; ");
169
+ const more = hits.length > 4 ? `; plus ${hits.length - 4} more` : "";
170
+ addIssue(
171
+ warnings,
172
+ "source_html.raw_html_wrappers",
173
+ `source_html.adapter_contract.raw_html_conversion_status is "${status}", but mapped source HTML still contains document wrapper tags: ${sample}${more}. Strip <!doctype>, <html>, <head>, and <body> before treating the page as page-kit-ready source.`
174
+ );
175
+ }
176
+
177
+ export function validateAdapterDecisionGates({ decisions, location, specPages = [], family, assemblyComplete, targetRepo = null, errors, warnings, ready, addIssue }) {
178
+ if (!isObject(decisions)) return;
179
+ const runtimePages = specPages.filter((page) => RUNTIME_PAGE_TYPES.has(String(page.type || "").toLowerCase()));
180
+ const familyAutomatable = isNonEmptyString(family) && family !== "undecided" && family !== "custom";
181
+
182
+ if (assemblyComplete) {
183
+ if (["pending", "in_progress", "blocked"].includes(decisions.raw_html_conversion_status)) {
184
+ addIssue(
185
+ warnings,
186
+ "adapter.raw_html_conversion_status",
187
+ `Assembly is recorded complete, but ${location}.raw_html_conversion_status is "${decisions.raw_html_conversion_status}". Record completed/not_required after wrapper stripping, frontmatter, asset moves, script/style refs, CTA rewrites, route policy, and layout choice are settled.`
188
+ );
189
+ }
190
+ if (["raw_passthrough", "unknown"].includes(decisions.source_asset_strategy)) {
191
+ addIssue(warnings, "adapter.source_asset_strategy", `Assembly is recorded complete with ${location}.source_asset_strategy="${decisions.source_asset_strategy}". Page-kit builds should normally use pagekit_campaign_asset_root so src/<slug>/assets/* publishes at /<slug>/*.`);
192
+ }
193
+ if (["raw_passthrough", "unknown"].includes(decisions.route_rewrite_policy)) {
194
+ addIssue(warnings, "adapter.route_rewrite_policy", `Assembly is recorded complete with ${location}.route_rewrite_policy="${decisions.route_rewrite_policy}". Record how CampaignSpec routes and CTA destinations were rewritten before QA.`);
195
+ }
196
+ if (decisions.config_script_strategy === "unknown") {
197
+ addIssue(warnings, "adapter.config_script_strategy", `Assembly is recorded complete but ${location}.config_script_strategy is unknown. Record whether config scripts load via campaign assets, frontmatter scripts, inline config, or not_required.`);
198
+ }
199
+ if (["preserve_document_wrappers", "unknown"].includes(decisions.wrapper_policy)) {
200
+ addIssue(warnings, "adapter.wrapper_policy", `Assembly is recorded complete with ${location}.wrapper_policy="${decisions.wrapper_policy}". Page-kit source should normally strip document wrappers unless preserving them is explicitly not_required.`);
201
+ }
202
+ if (["raw_passthrough", "unknown"].includes(decisions.frontmatter_policy)) {
203
+ addIssue(warnings, "adapter.frontmatter_policy", `Assembly is recorded complete with ${location}.frontmatter_policy="${decisions.frontmatter_policy}". Record how Page Kit YAML frontmatter was created or why it is not_required.`);
204
+ }
205
+ if (["raw_passthrough", "unknown"].includes(decisions.script_style_reference_policy)) {
206
+ addIssue(warnings, "adapter.script_style_reference_policy", `Assembly is recorded complete with ${location}.script_style_reference_policy="${decisions.script_style_reference_policy}". Record how scripts/styles load via frontmatter, campaign assets, inline blocks, or not_required.`);
207
+ }
208
+ if (["raw_passthrough", "unknown"].includes(decisions.cta_rewrite_policy)) {
209
+ addIssue(warnings, "adapter.cta_rewrite_policy", `Assembly is recorded complete with ${location}.cta_rewrite_policy="${decisions.cta_rewrite_policy}". Record how CTA destinations were rewritten from CampaignSpec routes before QA.`);
210
+ }
211
+ if (["raw_passthrough", "unknown"].includes(decisions.layout_choice)) {
212
+ addIssue(warnings, "adapter.layout_choice", `Assembly is recorded complete with ${location}.layout_choice="${decisions.layout_choice}". Record the Page Kit layout strategy before handoff.`);
213
+ }
214
+ }
215
+
216
+ if (runtimePages.length > 0 && familyAutomatable) {
217
+ const adoption = decisions.commerce_shell_adoption;
218
+ if (adoption === "custom_html_experimental") {
219
+ addIssue(
220
+ errors,
221
+ "adapter.commerce_shell_adoption",
222
+ `Runtime commerce pages (${runtimePages.map((page) => page.id).join(", ")}) are marked custom_html_experimental for template family "${family}". Use template_clone_first_verified or sdk_surfaces_preserved before treating checkout/upsell/downsell/receipt as build-ready.`
223
+ );
224
+ } else if (assemblyComplete && !["template_clone_first_verified", "sdk_surfaces_preserved"].includes(adoption)) {
225
+ addIssue(
226
+ warnings,
227
+ "adapter.commerce_shell_adoption",
228
+ `Assembly is recorded complete, but ${location}.commerce_shell_adoption is "${adoption || "missing"}" for runtime commerce pages (${runtimePages.map((page) => page.id).join(", ")}). Commerce pages should be template-clone-first, then styled, with SDK-owned surfaces preserved.`
229
+ );
230
+ }
231
+ }
232
+
233
+ if (assemblyComplete && familyAutomatable) {
234
+ validateTemplateFilesCopied(decisions.template_files_copied, location, warnings, ready, addIssue, { targetRepo });
235
+ }
236
+ }
237
+
238
+ export function collectDocumentWrapperNames(content) {
239
+ const wrappers = [];
240
+ const text = String(content || "");
241
+ if (/<!doctype\b/i.test(text)) wrappers.push("doctype");
242
+ if (/<html(?:\s|>)/i.test(text)) wrappers.push("html");
243
+ if (/<head(?:\s|>)/i.test(text)) wrappers.push("head");
244
+ if (/<body(?:\s|>)/i.test(text)) wrappers.push("body");
245
+ return wrappers;
246
+ }
247
+
248
+ function validateTemplateFilesCopied(copied, location, warnings, ready, addIssue, { targetRepo = null } = {}) {
249
+ if (!isObject(copied)) {
250
+ addIssue(warnings, "adapter.template_files_copied", `Assembly is recorded complete, but ${location}.template_files_copied is missing. Record the selected template family as an atomic slice: pages, _includes, _layouts, CSS, JS, and frontmatter vocabulary.`);
251
+ return;
252
+ }
253
+ const status = copied.status || "missing";
254
+ if (!["complete", "verified_existing_slice", "not_applicable"].includes(status)) {
255
+ addIssue(warnings, "adapter.template_files_copied", `Assembly is recorded complete, but ${location}.template_files_copied.status is "${status}". Copy or verify the selected template family as one atomic slice, not individual commerce pages.`);
256
+ return;
257
+ }
258
+ if (status === "not_applicable") {
259
+ ready.push("Template slice copying marked not_applicable");
260
+ return;
261
+ }
262
+ const groups = new Set(Array.isArray(copied.groups) ? copied.groups.map(String) : []);
263
+ const missing = TEMPLATE_SLICE_REQUIRED_GROUPS.filter((group) => !groups.has(group));
264
+ if (missing.length) {
265
+ addIssue(
266
+ warnings,
267
+ "adapter.template_files_copied.groups",
268
+ `${location}.template_files_copied.status is "${status}", but required group(s) are missing: ${missing.join(", ")}. Atomic template slices include pages, _includes, _layouts, assets/css, assets/js, and frontmatter_vocabulary.`
269
+ );
270
+ return;
271
+ }
272
+ if (!validateTemplateSlicePaths(copied, location, targetRepo, warnings, ready, addIssue)) return;
273
+ ready.push("Template family slice copy/verification covers required page-kit dependency groups");
274
+ }
275
+
276
+ function validateTemplateSlicePaths(copied, location, targetRepo, warnings, ready, addIssue) {
277
+ const paths = Array.isArray(copied.paths) ? copied.paths.filter(isNonEmptyString) : [];
278
+ if (paths.length === 0) {
279
+ addIssue(warnings, "adapter.template_files_copied.paths", `Assembly is recorded complete, but ${location}.template_files_copied.paths is empty. Record the target repo paths that prove the template family slice exists.`);
280
+ return false;
281
+ }
282
+ if (!isNonEmptyString(targetRepo) || !existsSync(targetRepo) || !statSync(targetRepo).isDirectory()) {
283
+ addIssue(warnings, "adapter.template_files_copied.paths", `${location}.template_files_copied.paths cannot be verified because assembly.target_repo is missing or is not a directory.`);
284
+ return false;
285
+ }
286
+
287
+ const missing = [];
288
+ const absolute = [];
289
+ const escaping = [];
290
+ const targetRoot = resolve(targetRepo);
291
+ for (const path of paths) {
292
+ if (isAbsoluteOrUncPath(path)) {
293
+ absolute.push(path);
294
+ continue;
295
+ }
296
+ const fullPath = resolve(targetRoot, path);
297
+ const relativePath = relative(targetRoot, fullPath);
298
+ if (relativePath.startsWith("..") || isAbsoluteOrUncPath(relativePath)) {
299
+ escaping.push(path);
300
+ continue;
301
+ }
302
+ if (!existsSync(fullPath)) missing.push(path);
303
+ }
304
+ if (absolute.length) {
305
+ addIssue(warnings, "adapter.template_files_copied.paths", `${location}.template_files_copied.paths should be target-repo-relative, not absolute: ${absolute.slice(0, 5).join(", ")}.`);
306
+ }
307
+ if (escaping.length) {
308
+ addIssue(warnings, "adapter.template_files_copied.paths", `${location}.template_files_copied.paths must stay inside the target repo: ${escaping.slice(0, 5).join(", ")}.`);
309
+ }
310
+ if (missing.length) {
311
+ addIssue(warnings, "adapter.template_files_copied.paths", `${location}.template_files_copied.paths references missing target repo path(s): ${missing.slice(0, 8).join(", ")}${missing.length > 8 ? `; plus ${missing.length - 8} more` : ""}.`);
312
+ return false;
313
+ }
314
+ ready.push("Template family slice paths exist in target repo");
315
+ return absolute.length === 0 && escaping.length === 0;
316
+ }
317
+
318
+ function checkEnum(value, allowed, code, warnings, addIssue) {
319
+ if (value == null) return;
320
+ if (!allowed.has(value)) addIssue(warnings, code, `${code} has unknown value "${value}".`);
321
+ }
322
+
323
+ function isObject(value) {
324
+ return Boolean(value) && typeof value === "object" && !Array.isArray(value);
325
+ }
326
+
327
+ function isNonEmptyString(value) {
328
+ return typeof value === "string" && value.trim().length > 0;
329
+ }
330
+
331
+ function isAbsoluteOrUncPath(path) {
332
+ return /^(?:\/|[A-Za-z]:[\\/]|\\\\)/.test(path);
333
+ }