@inneranimalmedia/agentsam-sdk 2.6.11 → 2.6.12

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 (411) hide show
  1. package/apps/cad-creator/shared/cad/package.json +1 -1
  2. package/apps/client-cms-editor/backend/package.json +2 -2
  3. package/apps/client-cms-editor/frontend/package.json +3 -3
  4. package/apps/client-cms-editor/frontend/src/adapters/http-authoring.test.ts +161 -0
  5. package/apps/client-cms-editor/frontend/src/adapters/http.ts +296 -65
  6. package/apps/client-cms-editor/frontend/src/editor/CmsEditor.tsx +47 -16
  7. package/apps/client-cms-editor/frontend/src/editor/composition-groups.test.ts +40 -0
  8. package/apps/client-cms-editor/frontend/src/editor/legacy/CmsEditorPrototype.tsx +28 -28
  9. package/apps/client-cms-editor/frontend/src/editor/useCmsEditorController.ts +3 -3
  10. package/apps/client-cms-editor/frontend/src/styles/agentsam-drawer.css +5 -4
  11. package/apps/client-cms-editor/frontend/src/styles/studio.css +150 -149
  12. package/apps/client-cms-editor/package.json +1 -1
  13. package/apps/client-cms-editor/reference/harvest/plans/INNERANIMALS-CONTENT-001.md +1 -1
  14. package/apps/client-cms-editor/shared/cms/package.json +1 -1
  15. package/apps/client-cms-editor/shared/cms/src/editor-types.ts +42 -1
  16. package/docs/CMS_CONTEXTUAL_COMPOSER.md +4 -4
  17. package/docs/PRODUCT_LIFECYCLE.md +38 -38
  18. package/docs/REPO_FILE_MAP.txt +2 -2
  19. package/docs/THEME_REFINERY.md +6 -6
  20. package/docs/WINDOWS_RUNTIME_INSTALL.md +1 -1
  21. package/docs/adr/ADR-0002-brand-campaign-plugin-boundaries.md +603 -0
  22. package/docs/adr/ADR-0003-copro-clean-room-product-architecture.md +34 -0
  23. package/docs/adr/ADR-0003-product-portfolio-and-package-taxonomy.md +146 -0
  24. package/docs/adr/ADR-0004-product-composition-and-provider-neutrality.md +56 -0
  25. package/docs/adr/ADR-0005-offer-graduation-standard.md +66 -0
  26. package/docs/adr/README.md +25 -0
  27. package/docs/architecture/AGENTSAM_APPLICATION_CONTRACT.md +1 -1
  28. package/docs/architecture/DUAL_ANALYTICS_PRODUCT.md +1 -1
  29. package/docs/content-studio/HOST_MOUNT_CHECKLIST.md +1 -1
  30. package/docs/content-studio/REVISION_GATE_2026-09-27.md +3 -3
  31. package/docs/contracts/google-cloud-oauth-setup.md +1 -1
  32. package/docs/local-studio/WORKMODE_DONOR_NOTES.md +3 -3
  33. package/docs/plans/ASTRA-BRIEF-2026-09-18.md +1 -1
  34. package/docs/plans/LOCAL-STUDIO-REAL-APP-CONTRACT-ADDENDUM-2026-09-27.md +2 -2
  35. package/docs/plans/MACHINE-FIRST-APPS-TUI-2026-09-24.md +1 -1
  36. package/docs/plans/NEXT-AGENT-HANDOFF.md +2 -2
  37. package/docs/plans/TOMORROW-EXTENSIVE-TODO-2026-09-26.md +68 -68
  38. package/docs/plans/TOMORROW-MACHINE-FIRST-BRIEFING.md +1 -1
  39. package/docs/plans/UNIVERSAL-INGEST-MACHINE-FIRST-2026-09-24.md +1 -1
  40. package/docs/prd/PRD-agentsam-analytics.md +174 -0
  41. package/docs/prd/PRD-agentsam-brand.md +181 -0
  42. package/docs/prd/PRD-agentsam-browser.md +177 -0
  43. package/docs/prd/PRD-agentsam-cad-studio.md +177 -0
  44. package/docs/prd/PRD-agentsam-campaign.md +1178 -0
  45. package/docs/prd/PRD-agentsam-commerce-studio.md +180 -0
  46. package/docs/prd/PRD-agentsam-content-studio.md +179 -0
  47. package/docs/prd/PRD-agentsam-copro.md +39 -0
  48. package/docs/prd/PRD-agentsam-database-studio.md +175 -0
  49. package/docs/prd/PRD-agentsam-developer-studio.md +175 -0
  50. package/docs/prd/PRD-agentsam-hosted-runtime.md +180 -0
  51. package/docs/prd/PRD-agentsam-knowledge.md +174 -0
  52. package/docs/prd/PRD-agentsam-local-studio.md +180 -0
  53. package/docs/prd/PRD-agentsam-merch.md +177 -0
  54. package/docs/prd/PRD-agentsam-platform.md +179 -0
  55. package/docs/prd/PRD-agentsam-site-studio.md +180 -0
  56. package/docs/prd/PRD-agentsam-work.md +180 -0
  57. package/docs/prd/README.md +39 -0
  58. package/docs/product/COPRO-DONOR-AUDIT.md +9 -0
  59. package/docs/product/COPRO-EXECUTION-PLAN.md +81 -0
  60. package/docs/product/COPRO-UI-QUALITY-GATE.md +119 -0
  61. package/docs/product/OFFER-PORTFOLIO.md +158 -0
  62. package/docs/product/PACKAGE-TAXONOMY.md +78 -0
  63. package/examples/hyperspace-demo/dist/assets/index-SZ2LfOpJ.js +242 -0
  64. package/examples/hyperspace-demo/dist/index.html +13 -0
  65. package/native/agentsam-machine/core/src/lib.rs +2 -2
  66. package/package.json +55 -35
  67. package/packages/agentsam-brand/package.json +3 -2
  68. package/packages/agentsam-brand/src/public.js +192 -0
  69. package/packages/agentsam-contracts/README.md +1 -1
  70. package/packages/agentsam-contracts/package.json +1 -1
  71. package/packages/agentsam-errors/package.json +1 -1
  72. package/packages/agentsam-goap/package.json +2 -2
  73. package/packages/agentsam-hooks/package.json +1 -1
  74. package/packages/agentsam-knowledge/package.json +1 -1
  75. package/packages/agentsam-merch/package.json +1 -1
  76. package/packages/agentsam-merch/test/merch.test.mjs +1 -1
  77. package/packages/agentsam-nav/dist/browser.global.js +34 -71
  78. package/packages/agentsam-nav/dist/browser.js +759 -3157
  79. package/packages/agentsam-nav/dist/index.js +751 -3149
  80. package/packages/agentsam-nav/package.json +1 -1
  81. package/packages/agentsam-queue-control/package.json +1 -1
  82. package/packages/agentsam-repository/package.json +1 -1
  83. package/packages/agentsam-repository/src/goap.js.bak-20260922011251 +670 -0
  84. package/packages/agentsam-vault/package.json +1 -1
  85. package/packages/agentsam-workbench/package.json +5 -4
  86. package/packages/agentsam-workbench/src/agent/MiniAgentSam.tsx +28 -4
  87. package/packages/agentsam-workbench/src/agent/contextual-composer.css +72 -70
  88. package/packages/agentsam-workbench/src/agent/mini-agentsam.css +228 -10
  89. package/packages/connectors/cfoa/package.json +1 -1
  90. package/packages/heuristic-theme/package.json +1 -1
  91. package/packages/identity/package.json +1 -1
  92. package/packages/identity/src/frontend/auth-portal/pages/login.html +1 -1
  93. package/packages/identity/src/frontend/auth-portal/pages/reset.html +1 -1
  94. package/packages/identity/src/frontend/auth-portal/pages/signup.html +1 -1
  95. package/packages/identity/tests/chatgpt-provider.test.mjs +3 -3
  96. package/packages/identity/tests/oauth-consent-view.test.mjs +11 -11
  97. package/packages/providers/completeful/README.md +3 -3
  98. package/packages/providers/completeful/package.json +1 -1
  99. package/packages/theme-cypress/README.md +11 -0
  100. package/packages/{theme-church-site → theme-cypress}/package.json +14 -11
  101. package/packages/theme-cypress/prebuild.json +23 -0
  102. package/packages/theme-cypress/site/assets/generated/favicon.svg +7 -0
  103. package/packages/theme-cypress/site/assets/generated/media-044ba16613.webp +0 -0
  104. package/packages/theme-cypress/site/assets/generated/media-0a1ea6f6d9.webp +0 -0
  105. package/packages/theme-cypress/site/assets/generated/media-0c06778307.webp +0 -0
  106. package/packages/theme-cypress/site/assets/generated/media-1539ed373a.webp +0 -0
  107. package/packages/theme-cypress/site/assets/generated/media-2df479fd2d.webp +0 -0
  108. package/packages/theme-cypress/site/assets/generated/media-2e8bd0d9bc.webp +0 -0
  109. package/packages/theme-cypress/site/assets/generated/media-41d4e2643c.webp +0 -0
  110. package/packages/theme-cypress/site/assets/generated/media-46205bfde8.webp +0 -0
  111. package/packages/theme-cypress/site/assets/generated/media-50c5f3e279.webp +0 -0
  112. package/packages/theme-cypress/site/assets/generated/media-5f1467778c.webp +0 -0
  113. package/packages/theme-cypress/site/assets/generated/media-6703642b22.webp +0 -0
  114. package/packages/theme-cypress/site/assets/generated/media-87a490bc8e.webp +0 -0
  115. package/packages/theme-cypress/site/assets/generated/media-997c10ef39.webp +0 -0
  116. package/packages/theme-cypress/site/assets/generated/media-a423735c21.webp +0 -0
  117. package/packages/theme-cypress/site/assets/generated/media-c9cea5245b.webp +0 -0
  118. package/packages/theme-cypress/site/assets/generated/media-cab3c84c60.webp +0 -0
  119. package/packages/theme-cypress/site/assets/generated/media-ce06595d59.webp +0 -0
  120. package/packages/theme-cypress/site/assets/generated/media-d268905e7e.webp +0 -0
  121. package/packages/theme-cypress/site/assets/generated/media-f6711b5053.webp +0 -0
  122. package/packages/theme-cypress/site/assets/generated/media-manifest.json +226 -0
  123. package/packages/theme-cypress/site/assets/generated/social-card.webp +0 -0
  124. package/packages/theme-cypress/site/assets/generated/theme-mark-192.png +0 -0
  125. package/packages/theme-cypress/site/assets/generated/theme-mark-512.png +0 -0
  126. package/packages/theme-cypress/site/assets/generated/theme-mark.svg +7 -0
  127. package/packages/theme-cypress/site/beliefs.html +175 -0
  128. package/packages/theme-cypress/site/community.html +175 -0
  129. package/packages/theme-cypress/site/connect.html +319 -0
  130. package/packages/theme-cypress/site/donate.html +106 -0
  131. package/packages/theme-cypress/site/groups.html +1352 -0
  132. package/packages/theme-cypress/site/help.html +1 -0
  133. package/packages/theme-cypress/site/icons/clock.svg +4 -0
  134. package/packages/theme-cypress/site/icons/email.svg +4 -0
  135. package/packages/theme-cypress/site/icons/giving.svg +4 -0
  136. package/packages/theme-cypress/site/icons/home.svg +4 -0
  137. package/packages/theme-cypress/site/icons/location.svg +4 -0
  138. package/packages/theme-cypress/site/icons/media.svg +4 -0
  139. package/packages/theme-cypress/site/icons/ministries.svg +6 -0
  140. package/packages/theme-cypress/site/icons/prayer.svg +5 -0
  141. package/packages/theme-cypress/site/icons/visit.svg +6 -0
  142. package/packages/theme-cypress/site/index.html +1013 -0
  143. package/packages/theme-cypress/site/mensgroup.html +477 -0
  144. package/packages/theme-cypress/site/mission.html +512 -0
  145. package/packages/theme-cypress/site/unified-footer.css +172 -0
  146. package/packages/theme-cypress/site/unified-footer.js +175 -0
  147. package/packages/theme-cypress/site/unified-header.css +226 -0
  148. package/packages/theme-cypress/site/unified-header.js +111 -0
  149. package/packages/theme-cypress/site/womansgroup.html +452 -0
  150. package/packages/{theme-church-site → theme-cypress}/src/index.js +22 -35
  151. package/packages/theme-cypress/src/node.js +69 -0
  152. package/packages/theme-cypress/test/theme.test.mjs +47 -0
  153. package/packages/theme-ember/README.md +11 -0
  154. package/packages/{theme-fuelnfree-site → theme-ember}/package.json +14 -11
  155. package/packages/theme-ember/prebuild.json +23 -0
  156. package/packages/theme-ember/site/about.html +1840 -0
  157. package/packages/theme-ember/site/assets/generated/favicon.svg +7 -0
  158. package/packages/theme-ember/site/assets/generated/media-1e0b1e6ee6.webp +0 -0
  159. package/packages/theme-ember/site/assets/generated/media-2371dcb426.webp +0 -0
  160. package/packages/theme-ember/site/assets/generated/media-2db4f5ff9e.webp +0 -0
  161. package/packages/theme-ember/site/assets/generated/media-4ed07a756e.webp +0 -0
  162. package/packages/theme-ember/site/assets/generated/media-58182cf167.webp +0 -0
  163. package/packages/theme-ember/site/assets/generated/media-5b8b8472ae.webp +0 -0
  164. package/packages/theme-ember/site/assets/generated/media-71f4bd16a1.webp +0 -0
  165. package/packages/theme-ember/site/assets/generated/media-7c1c8120bc.webp +0 -0
  166. package/packages/theme-ember/site/assets/generated/media-832b176433.webp +0 -0
  167. package/packages/theme-ember/site/assets/generated/media-931439701c.webp +0 -0
  168. package/packages/theme-ember/site/assets/generated/media-c2860d40d1.webp +0 -0
  169. package/packages/theme-ember/site/assets/generated/media-c56974d198.webp +0 -0
  170. package/packages/theme-ember/site/assets/generated/media-cb83a44ff4.webp +0 -0
  171. package/packages/theme-ember/site/assets/generated/media-df02ccdfcf.webp +0 -0
  172. package/packages/theme-ember/site/assets/generated/media-fab72cd344.webp +0 -0
  173. package/packages/theme-ember/site/assets/generated/media-manifest.json +190 -0
  174. package/packages/theme-ember/site/assets/generated/social-card.webp +0 -0
  175. package/packages/theme-ember/site/assets/generated/theme-mark-192.png +0 -0
  176. package/packages/theme-ember/site/assets/generated/theme-mark-512.png +0 -0
  177. package/packages/theme-ember/site/assets/generated/theme-mark.svg +7 -0
  178. package/packages/theme-ember/site/community.html +1664 -0
  179. package/packages/theme-ember/site/index.html +2044 -0
  180. package/packages/theme-ember/site/shop.html +2104 -0
  181. package/packages/{theme-fuelnfree-site → theme-ember}/src/index.js +23 -33
  182. package/packages/theme-ember/src/node.js +69 -0
  183. package/packages/theme-ember/test/theme.test.mjs +47 -0
  184. package/packages/theme-forge/README.md +11 -0
  185. package/packages/theme-forge/package.json +44 -0
  186. package/packages/theme-forge/prebuild.json +23 -0
  187. package/packages/theme-forge/site/apple-touch-icon.png +0 -0
  188. package/packages/theme-forge/site/assets/generated/favicon.svg +7 -0
  189. package/packages/theme-forge/site/assets/generated/media-manifest.json +17 -0
  190. package/packages/theme-forge/site/assets/generated/social-card.webp +0 -0
  191. package/packages/theme-forge/site/assets/generated/theme-mark-192.png +0 -0
  192. package/packages/theme-forge/site/assets/generated/theme-mark-512.png +0 -0
  193. package/packages/theme-forge/site/assets/generated/theme-mark.svg +7 -0
  194. package/packages/theme-forge/site/assets/index-DBOqQVsA.css +1 -0
  195. package/packages/theme-forge/site/assets/index-pXC0o9jp.js +241 -0
  196. package/packages/theme-forge/site/assets/workbox-window.prod.es5-Bd17z0YL.js +2 -0
  197. package/packages/theme-forge/site/index.html +5 -0
  198. package/packages/theme-forge/site/manifest.webmanifest +1 -0
  199. package/packages/theme-forge/site/pwa-192x192.png +0 -0
  200. package/packages/theme-forge/site/pwa-512x512.png +0 -0
  201. package/packages/theme-forge/site/sw.js +107 -0
  202. package/packages/theme-forge/site/workbox-7e5eb42b.js +3395 -0
  203. package/packages/theme-forge/src/index.js +76 -0
  204. package/packages/theme-forge/src/node.js +69 -0
  205. package/packages/theme-forge/test/theme.test.mjs +47 -0
  206. package/packages/theme-grove/README.md +11 -0
  207. package/packages/{theme-floors-site → theme-grove}/package.json +14 -11
  208. package/packages/theme-grove/prebuild.json +23 -0
  209. package/packages/theme-grove/site/assets/generated/favicon.svg +7 -0
  210. package/packages/theme-grove/site/assets/generated/media-098b13d75a.webp +0 -0
  211. package/packages/theme-grove/site/assets/generated/media-0c064db1aa.webp +0 -0
  212. package/packages/theme-grove/site/assets/generated/media-0fbfef655e.webp +0 -0
  213. package/packages/theme-grove/site/assets/generated/media-14759c7460.webp +0 -0
  214. package/packages/theme-grove/site/assets/generated/media-19b23d2a8f.webp +0 -0
  215. package/packages/theme-grove/site/assets/generated/media-2012f04243.webp +0 -0
  216. package/packages/theme-grove/site/assets/generated/media-23b8c5e2bb.webp +0 -0
  217. package/packages/theme-grove/site/assets/generated/media-2bffb1a6ef.webp +0 -0
  218. package/packages/theme-grove/site/assets/generated/media-2e1523a5b0.webp +0 -0
  219. package/packages/theme-grove/site/assets/generated/media-31107c21f2.webp +0 -0
  220. package/packages/theme-grove/site/assets/generated/media-31373ec865.webp +0 -0
  221. package/packages/theme-grove/site/assets/generated/media-45e8e27542.webp +0 -0
  222. package/packages/theme-grove/site/assets/generated/media-4aa9846fe7.webp +0 -0
  223. package/packages/theme-grove/site/assets/generated/media-5476b24219.webp +0 -0
  224. package/packages/theme-grove/site/assets/generated/media-7a227d3e4b.webp +0 -0
  225. package/packages/theme-grove/site/assets/generated/media-b183eed550.webp +0 -0
  226. package/packages/theme-grove/site/assets/generated/media-b2c650f9ab.webp +0 -0
  227. package/packages/theme-grove/site/assets/generated/media-b5d7471694.webp +0 -0
  228. package/packages/theme-grove/site/assets/generated/media-c86498fdb4.webp +0 -0
  229. package/packages/theme-grove/site/assets/generated/media-ce2cfff9a1.webp +0 -0
  230. package/packages/theme-grove/site/assets/generated/media-cf41a5f324.webp +0 -0
  231. package/packages/theme-grove/site/assets/generated/media-ec6c01bf8d.webp +0 -0
  232. package/packages/theme-grove/site/assets/generated/media-manifest.json +267 -0
  233. package/packages/theme-grove/site/assets/generated/social-card.webp +0 -0
  234. package/packages/theme-grove/site/assets/generated/theme-mark-192.png +0 -0
  235. package/packages/theme-grove/site/assets/generated/theme-mark-512.png +0 -0
  236. package/packages/theme-grove/site/assets/generated/theme-mark.svg +7 -0
  237. package/packages/theme-grove/site/index.html +1429 -0
  238. package/packages/theme-grove/site/pages/contact.html +664 -0
  239. package/packages/theme-grove/site/pages/gallery.html +216 -0
  240. package/packages/theme-grove/site/pages/privacy.html +180 -0
  241. package/packages/theme-grove/site/pages/process.html +592 -0
  242. package/packages/theme-grove/site/pages/services.html +567 -0
  243. package/packages/theme-grove/site/pages/terms.html +189 -0
  244. package/packages/theme-grove/site/shared/footer.css +140 -0
  245. package/packages/theme-grove/site/shared/footer.html +41 -0
  246. package/packages/{theme-floors-site → theme-grove}/src/index.js +24 -35
  247. package/packages/theme-grove/src/node.js +69 -0
  248. package/packages/theme-grove/test/theme.test.mjs +47 -0
  249. package/packages/theme-harbor/README.md +11 -0
  250. package/packages/{theme-insurance-site → theme-harbor}/package.json +14 -11
  251. package/packages/theme-harbor/prebuild.json +23 -0
  252. package/packages/theme-harbor/site/assets/generated/favicon.svg +7 -0
  253. package/packages/theme-harbor/site/assets/generated/media-manifest.json +17 -0
  254. package/packages/theme-harbor/site/assets/generated/social-card.webp +0 -0
  255. package/packages/theme-harbor/site/assets/generated/theme-mark-192.png +0 -0
  256. package/packages/theme-harbor/site/assets/generated/theme-mark-512.png +0 -0
  257. package/packages/theme-harbor/site/assets/generated/theme-mark.svg +7 -0
  258. package/packages/theme-harbor/site/assets/index-D58RKkr-.js +239 -0
  259. package/packages/theme-harbor/site/assets/index-Dd3YN9Mf.css +1 -0
  260. package/packages/theme-harbor/site/index.html +15 -0
  261. package/packages/theme-harbor/src/index.js +76 -0
  262. package/packages/theme-harbor/src/node.js +69 -0
  263. package/packages/theme-harbor/test/theme.test.mjs +47 -0
  264. package/packages/theme-resolve/README.md +11 -0
  265. package/packages/theme-resolve/package.json +44 -0
  266. package/packages/theme-resolve/prebuild.json +23 -0
  267. package/packages/theme-resolve/site/assets/generated/favicon.svg +7 -0
  268. package/packages/theme-resolve/site/assets/generated/media-216610d365.webp +0 -0
  269. package/packages/theme-resolve/site/assets/generated/media-2a9e0f623f.webp +0 -0
  270. package/packages/theme-resolve/site/assets/generated/media-a70660bfa9.webp +0 -0
  271. package/packages/theme-resolve/site/assets/generated/media-bc1322e813.webp +0 -0
  272. package/packages/theme-resolve/site/assets/generated/media-ced60fcecc.webp +0 -0
  273. package/packages/theme-resolve/site/assets/generated/media-manifest.json +72 -0
  274. package/packages/theme-resolve/site/assets/generated/social-card.webp +0 -0
  275. package/packages/theme-resolve/site/assets/generated/theme-mark-192.png +0 -0
  276. package/packages/theme-resolve/site/assets/generated/theme-mark-512.png +0 -0
  277. package/packages/theme-resolve/site/assets/generated/theme-mark.svg +7 -0
  278. package/packages/theme-resolve/site/assets/index-BSaLpPG1.css +2 -0
  279. package/packages/theme-resolve/site/assets/index-D8au46Z5.js +17 -0
  280. package/packages/theme-resolve/site/index.html +22 -0
  281. package/packages/theme-resolve/src/index.js +69 -0
  282. package/packages/theme-resolve/src/node.js +69 -0
  283. package/packages/theme-resolve/test/theme.test.mjs +47 -0
  284. package/packages/theme-scenes/package.json +1 -1
  285. package/packages/theme-scenes/src/registry.js +32 -49
  286. package/packages/theme-summit/README.md +11 -0
  287. package/packages/{theme-shinshu-site → theme-summit}/package.json +14 -11
  288. package/packages/theme-summit/prebuild.json +23 -0
  289. package/packages/theme-summit/site/adventures.html +450 -0
  290. package/packages/theme-summit/site/assets/generated/favicon.svg +7 -0
  291. package/packages/theme-summit/site/assets/generated/media-1e958ea679.webp +0 -0
  292. package/packages/theme-summit/site/assets/generated/media-9d4521abba.webp +0 -0
  293. package/packages/theme-summit/site/assets/generated/media-manifest.json +39 -0
  294. package/packages/theme-summit/site/assets/generated/social-card.webp +0 -0
  295. package/packages/theme-summit/site/assets/generated/theme-mark-192.png +0 -0
  296. package/packages/theme-summit/site/assets/generated/theme-mark-512.png +0 -0
  297. package/packages/theme-summit/site/assets/generated/theme-mark.svg +7 -0
  298. package/packages/theme-summit/site/business-card.html +315 -0
  299. package/packages/theme-summit/site/chatbot.js +312 -0
  300. package/packages/theme-summit/site/gallery.html +524 -0
  301. package/packages/theme-summit/site/i18n.js +947 -0
  302. package/packages/theme-summit/site/icons.svg +87 -0
  303. package/packages/theme-summit/site/index.html +2415 -0
  304. package/packages/theme-summit/site/pages/about.html +100 -0
  305. package/packages/theme-summit/site/pages/contact.html +117 -0
  306. package/packages/theme-summit/site/pages/dashboard.html +111 -0
  307. package/packages/theme-summit/site/pages/index.html +129 -0
  308. package/packages/theme-summit/site/pages/services.html +125 -0
  309. package/packages/theme-summit/site/shared/footer.html +41 -0
  310. package/packages/theme-summit/site/shared/layout.js +315 -0
  311. package/packages/theme-summit/site/shared/nav.html +19 -0
  312. package/packages/theme-summit/site/shared/styles.css +696 -0
  313. package/packages/theme-summit/site/theme-styles.css +131 -0
  314. package/packages/theme-summit/site/themes.js +442 -0
  315. package/packages/{theme-shinshu-site → theme-summit}/src/index.js +23 -35
  316. package/packages/theme-summit/src/node.js +69 -0
  317. package/packages/theme-summit/test/theme.test.mjs +47 -0
  318. package/packages/theme-violet/README.md +11 -0
  319. package/packages/{theme-companions-site → theme-violet}/package.json +14 -11
  320. package/packages/theme-violet/prebuild.json +23 -0
  321. package/packages/theme-violet/site/assets/generated/favicon.svg +7 -0
  322. package/packages/theme-violet/site/assets/generated/media-07b46d6457.webp +0 -0
  323. package/packages/theme-violet/site/assets/generated/media-09d38ddffc.webp +0 -0
  324. package/packages/theme-violet/site/assets/generated/media-254b0e2ad3.webp +0 -0
  325. package/packages/theme-violet/site/assets/generated/media-3a1b5c0a8d.webp +0 -0
  326. package/packages/theme-violet/site/assets/generated/media-3a78eb7d9d.webp +0 -0
  327. package/packages/theme-violet/site/assets/generated/media-49076977d8.webp +0 -0
  328. package/packages/theme-violet/site/assets/generated/media-6342d50dbd.webp +0 -0
  329. package/packages/theme-violet/site/assets/generated/media-646c65381e.webp +0 -0
  330. package/packages/theme-violet/site/assets/generated/media-7a5fb7c91a.webp +0 -0
  331. package/packages/theme-violet/site/assets/generated/media-9bbd133220.webp +0 -0
  332. package/packages/theme-violet/site/assets/generated/media-9e73307c2a.webp +0 -0
  333. package/packages/theme-violet/site/assets/generated/media-af382146a0.webp +0 -0
  334. package/packages/theme-violet/site/assets/generated/media-b2ae348b43.webp +0 -0
  335. package/packages/theme-violet/site/assets/generated/media-b8f43a3887.webp +0 -0
  336. package/packages/theme-violet/site/assets/generated/media-c96a3e1979.webp +0 -0
  337. package/packages/theme-violet/site/assets/generated/media-cd07daa54a.webp +0 -0
  338. package/packages/theme-violet/site/assets/generated/media-e03ab6b5fe.webp +0 -0
  339. package/packages/theme-violet/site/assets/generated/media-eae4917d25.webp +0 -0
  340. package/packages/theme-violet/site/assets/generated/media-f227ec5690.webp +0 -0
  341. package/packages/theme-violet/site/assets/generated/media-fb57ffd474.webp +0 -0
  342. package/packages/theme-violet/site/assets/generated/media-manifest.json +245 -0
  343. package/packages/theme-violet/site/assets/generated/social-card.webp +0 -0
  344. package/packages/theme-violet/site/assets/generated/theme-mark-192.png +0 -0
  345. package/packages/theme-violet/site/assets/generated/theme-mark-512.png +0 -0
  346. package/packages/theme-violet/site/assets/generated/theme-mark.svg +7 -0
  347. package/packages/theme-violet/site/global/cpas-contact.css +405 -0
  348. package/packages/theme-violet/site/global/cpas-donate-v2.css +931 -0
  349. package/packages/theme-violet/site/global/cpas-drawer-override.css +1 -0
  350. package/packages/theme-violet/site/global/cpas-footer.html +38 -0
  351. package/packages/theme-violet/site/global/cpas-header.html +30 -0
  352. package/packages/theme-violet/site/global/cpas-hero-watercolor.css +275 -0
  353. package/packages/theme-violet/site/global/cpas-modals.js +802 -0
  354. package/packages/theme-violet/site/global/cpas-public-surface.css +982 -0
  355. package/packages/theme-violet/site/global/cpas-shell.css +3980 -0
  356. package/packages/theme-violet/site/global/cpas-shell.js +107 -0
  357. package/packages/theme-violet/site/global/cpas-shelter-hub.css +326 -0
  358. package/packages/theme-violet/site/index.html +141 -0
  359. package/packages/theme-violet/site/pages/about/campaigns.html +28 -0
  360. package/packages/theme-violet/site/pages/about/cta.html +25 -0
  361. package/packages/theme-violet/site/pages/about/hero.html +46 -0
  362. package/packages/theme-violet/site/pages/about/paths.html +24 -0
  363. package/packages/theme-violet/site/pages/about/why_we_exist.html +28 -0
  364. package/packages/theme-violet/site/pages/home/campaigns.html +67 -0
  365. package/packages/theme-violet/site/pages/home/hero.html +42 -0
  366. package/packages/theme-violet/site/pages/home/how-it-helps.html +32 -0
  367. package/packages/theme-violet/site/pages/home/impact-stats.html +31 -0
  368. package/packages/theme-violet/site/pages/home/mission.html +36 -0
  369. package/packages/theme-violet/site/pages/home/newsletter.html +29 -0
  370. package/packages/theme-violet/site/pages/home/transport-win.html +22 -0
  371. package/packages/theme-violet/site/pages/index.html +141 -0
  372. package/packages/theme-violet/src/index.js +76 -0
  373. package/packages/theme-violet/src/node.js +69 -0
  374. package/packages/theme-violet/test/theme.test.mjs +47 -0
  375. package/packages/work-graph/package.json +1 -1
  376. package/protocol/features/README.md +1 -1
  377. package/protocol/features/catalog.json +12 -12
  378. package/protocol/features/examples/provider-resend.feature.json +2 -2
  379. package/protocol/presets/catalog.json +1 -1
  380. package/protocol/theme-refinery/prebuild-registry.json +45 -0
  381. package/protocol/theme-refinery/product-metadata.schema.json +63 -26
  382. package/protocol/theme-refinery/receipts/prebuild-remaster-20261004.json +21 -0
  383. package/src/plugins/completeful.js +2 -2
  384. package/packages/theme-church-site/README.md +0 -10
  385. package/packages/theme-church-site/src/harvest.json +0 -16
  386. package/packages/theme-church-site/test/theme.test.mjs +0 -21
  387. package/packages/theme-companions-site/README.md +0 -10
  388. package/packages/theme-companions-site/src/harvest.json +0 -14
  389. package/packages/theme-companions-site/src/index.js +0 -87
  390. package/packages/theme-companions-site/test/theme.test.mjs +0 -21
  391. package/packages/theme-floors-site/README.md +0 -10
  392. package/packages/theme-floors-site/src/harvest.json +0 -16
  393. package/packages/theme-floors-site/test/theme.test.mjs +0 -21
  394. package/packages/theme-fuelnfree-site/README.md +0 -10
  395. package/packages/theme-fuelnfree-site/src/harvest.json +0 -15
  396. package/packages/theme-fuelnfree-site/test/theme.test.mjs +0 -21
  397. package/packages/theme-handyman-site/README.md +0 -10
  398. package/packages/theme-handyman-site/package.json +0 -41
  399. package/packages/theme-handyman-site/src/harvest.json +0 -12
  400. package/packages/theme-handyman-site/src/index.js +0 -88
  401. package/packages/theme-handyman-site/test/theme.test.mjs +0 -21
  402. package/packages/theme-insurance-site/README.md +0 -10
  403. package/packages/theme-insurance-site/src/harvest.json +0 -12
  404. package/packages/theme-insurance-site/src/index.js +0 -88
  405. package/packages/theme-insurance-site/test/theme.test.mjs +0 -21
  406. package/packages/theme-shinshu-site/README.md +0 -10
  407. package/packages/theme-shinshu-site/src/harvest.json +0 -14
  408. package/packages/theme-shinshu-site/test/theme.test.mjs +0 -21
  409. package/protocol/theme-refinery/lineage-registry.json +0 -105
  410. package/protocol/theme-refinery/receipts/products-registry-batch-20260924.json +0 -318
  411. package/protocol/theme-refinery/receipts/theme-harvest-20260924.json +0 -472
@@ -10,14 +10,15 @@ import {
10
10
  type CmsPublicationSnapshot,
11
11
  type CmsRevision,
12
12
  } from '../../../shared/cms/src/adapter';
13
- import type {
14
- CmsEditorBlock,
15
- CmsEditorPage,
16
- CmsEditorSection,
17
- CmsEditorSite,
18
- CmsSiteCreateInput,
19
- CmsSiteRecord,
20
- CmsSiteUpdatePatch,
13
+ import {
14
+ buildCmsEditorGroups,
15
+ type CmsEditorBlock,
16
+ type CmsEditorPage,
17
+ type CmsEditorSection,
18
+ type CmsEditorSite,
19
+ type CmsSiteCreateInput,
20
+ type CmsSiteRecord,
21
+ type CmsSiteUpdatePatch,
21
22
  } from '../../../shared/cms/src/editor-types';
22
23
 
23
24
  type Json = Record<string, any>;
@@ -26,12 +27,12 @@ function siteQuery(siteId: string) {
26
27
  return `site=${encodeURIComponent(siteId)}`;
27
28
  }
28
29
 
29
- async function api<T = Json>(path: string, init: RequestInit = {}): Promise<T> {
30
+ async function api<T = Json>(path: string, init: RequestInit = {}, transport: typeof fetch = fetch): Promise<T> {
30
31
  const headers = new Headers(init.headers || {});
31
32
  if (init.body && !(init.body instanceof FormData) && !headers.has('content-type')) {
32
33
  headers.set('content-type', 'application/json');
33
34
  }
34
- const response = await fetch(path, {
35
+ const response = await transport(path, {
35
36
  credentials: 'same-origin',
36
37
  cache: 'no-store',
37
38
  ...init,
@@ -181,14 +182,17 @@ function hydratePages(boot: Json): CmsEditorPage[] {
181
182
  export class HttpCmsAdapter implements CmsEditorAdapter {
182
183
  readonly temporary = false;
183
184
  private readonly base: string;
185
+ private readonly transport: typeof fetch;
184
186
  private readonly knownSites: Map<string, CmsSiteRecord>;
185
187
 
186
188
  constructor(
187
189
  options: {
188
190
  base?: string;
191
+ transport?: typeof fetch;
189
192
  sites?: Array<{ id?: string; slug?: string; name?: string; domain?: string }>;
190
193
  } = {},
191
194
  ) {
195
+ this.transport = options.transport || fetch;
192
196
  this.base = String(options.base || '').replace(/\/$/, '');
193
197
  this.knownSites = new Map();
194
198
  for (const site of options.sites || []) {
@@ -206,6 +210,8 @@ export class HttpCmsAdapter implements CmsEditorAdapter {
206
210
  }
207
211
  }
208
212
 
213
+ private api<T = Json>(path: string, init: RequestInit = {}): Promise<T> { return api<T>(path, init, this.transport); }
214
+
209
215
  private url(path: string) {
210
216
  return `${this.base}${path}`;
211
217
  }
@@ -213,14 +219,14 @@ export class HttpCmsAdapter implements CmsEditorAdapter {
213
219
  async listSites(): Promise<CmsSiteRecord[]> {
214
220
  if (this.knownSites.size) return [...this.knownSites.values()].map((s) => structuredClone(s));
215
221
  // Fallback: bootstrap the default studio site so hub/editor share one authority.
216
- const boot = await api<Json>(this.url(`/api/cms/bootstrap?${siteQuery('agentsam-sdk')}`));
222
+ const boot = await this.api<Json>(this.url(`/api/cms/bootstrap?${siteQuery('agentsam-sdk')}`));
217
223
  const record = siteRecordFromBootstrap('agentsam-sdk', boot);
218
224
  this.knownSites.set(record.id, record);
219
225
  return [structuredClone(record)];
220
226
  }
221
227
 
222
228
  async getSite(siteId: string): Promise<CmsSiteRecord> {
223
- const boot = await api<Json>(this.url(`/api/cms/bootstrap?${siteQuery(siteId)}`));
229
+ const boot = await this.api<Json>(this.url(`/api/cms/bootstrap?${siteQuery(siteId)}`));
224
230
  const record = siteRecordFromBootstrap(siteId, boot);
225
231
  this.knownSites.set(siteId, record);
226
232
  return structuredClone(record);
@@ -237,7 +243,7 @@ export class HttpCmsAdapter implements CmsEditorAdapter {
237
243
  async updateSite(siteId: string, patch: CmsSiteUpdatePatch): Promise<CmsSiteRecord> {
238
244
  const current = await this.getSite(siteId);
239
245
  if (patch.theme?.cssVars) {
240
- await api(this.url(`/api/cms/theme-vars?${siteQuery(siteId)}`), {
246
+ await this.api(this.url(`/api/cms/theme-vars?${siteQuery(siteId)}`), {
241
247
  method: 'PATCH',
242
248
  body: JSON.stringify({ project_slug: siteId, vars: patch.theme.cssVars }),
243
249
  });
@@ -252,7 +258,7 @@ export class HttpCmsAdapter implements CmsEditorAdapter {
252
258
  }
253
259
 
254
260
  async loadSite(siteId: string): Promise<CmsEditorSite> {
255
- const boot = await api<Json>(this.url(`/api/cms/bootstrap?${siteQuery(siteId)}`));
261
+ const boot = await this.api<Json>(this.url(`/api/cms/bootstrap?${siteQuery(siteId)}`));
256
262
  const meta = siteRecordFromBootstrap(siteId, boot);
257
263
  this.knownSites.set(siteId, meta);
258
264
  return {
@@ -270,7 +276,7 @@ export class HttpCmsAdapter implements CmsEditorAdapter {
270
276
  // Worker page GET requires site slug — resolve via known sites / bootstrap scan.
271
277
  for (const siteId of this.knownSites.keys()) {
272
278
  try {
273
- const body = await api<Json>(
279
+ const body = await this.api<Json>(
274
280
  this.url(`/api/cms/pages/${encodeURIComponent(pageId)}?${siteQuery(siteId)}`),
275
281
  );
276
282
  const sections = Array.isArray(body.sections)
@@ -301,7 +307,7 @@ export class HttpCmsAdapter implements CmsEditorAdapter {
301
307
  input: Partial<CmsEditorPage> & { title: string; slug: string },
302
308
  ): Promise<CmsEditorPage> {
303
309
  const slug = input.slug.replace(/^\/+/, '');
304
- const body = await api<Json>(this.url(`/api/cms/pages?${siteQuery(siteId)}`), {
310
+ const body = await this.api<Json>(this.url(`/api/cms/pages?${siteQuery(siteId)}`), {
305
311
  method: 'POST',
306
312
  body: JSON.stringify({
307
313
  project_id: siteId,
@@ -318,7 +324,7 @@ export class HttpCmsAdapter implements CmsEditorAdapter {
318
324
 
319
325
  async updatePage(pageId: string, patch: Partial<CmsEditorPage>): Promise<CmsEditorPage> {
320
326
  const siteId = await this.findPageSiteId(pageId);
321
- const body = await api<Json>(
327
+ const body = await this.api<Json>(
322
328
  this.url(`/api/cms/pages/${encodeURIComponent(pageId)}?${siteQuery(siteId)}`),
323
329
  {
324
330
  method: 'PUT',
@@ -336,8 +342,11 @@ export class HttpCmsAdapter implements CmsEditorAdapter {
336
342
  return mapPage(body.page || body, patch.sections || []);
337
343
  }
338
344
 
339
- async deletePage(_pageId: string): Promise<void> {
340
- throw new CmsCapabilityError('deletePage', 'Hosted page delete not enabled yet', 'cms_capability_unsupported');
345
+ async deletePage(pageId: string): Promise<void> {
346
+ const siteId = await this.findPageSiteId(pageId);
347
+ await this.api(this.url(`/api/cms/pages/${encodeURIComponent(pageId)}?${siteQuery(siteId)}`), {
348
+ method: 'DELETE',
349
+ });
341
350
  }
342
351
 
343
352
  async listSections(pageId: string): Promise<CmsEditorSection[]> {
@@ -359,7 +368,7 @@ export class HttpCmsAdapter implements CmsEditorAdapter {
359
368
  input: Partial<CmsEditorSection> & { name: string },
360
369
  ): Promise<CmsEditorSection> {
361
370
  const siteId = await this.findPageSiteId(pageId);
362
- const body = await api<Json>(this.url(`/api/cms/sections?${siteQuery(siteId)}`), {
371
+ const body = await this.api<Json>(this.url(`/api/cms/sections?${siteQuery(siteId)}`), {
363
372
  method: 'POST',
364
373
  body: JSON.stringify({
365
374
  page_id: pageId,
@@ -377,7 +386,7 @@ export class HttpCmsAdapter implements CmsEditorAdapter {
377
386
  patch: Partial<CmsEditorSection>,
378
387
  ): Promise<CmsEditorSection> {
379
388
  const siteId = await this.guessSiteId();
380
- const body = await api<Json>(
389
+ const body = await this.api<Json>(
381
390
  this.url(`/api/cms/sections/${encodeURIComponent(sectionId)}?${siteQuery(siteId)}`),
382
391
  {
383
392
  method: 'PUT',
@@ -392,13 +401,16 @@ export class HttpCmsAdapter implements CmsEditorAdapter {
392
401
  return mapSection(body.section || body, patch.blocks || []);
393
402
  }
394
403
 
395
- async deleteSection(_sectionId: string): Promise<void> {
396
- throw new CmsCapabilityError('deleteSection', 'Hosted section delete not enabled yet', 'cms_capability_unsupported');
404
+ async deleteSection(sectionId: string): Promise<void> {
405
+ const siteId = await this.guessSiteId();
406
+ await this.api(this.url(`/api/cms/sections/${encodeURIComponent(sectionId)}?${siteQuery(siteId)}`), {
407
+ method: 'DELETE',
408
+ });
397
409
  }
398
410
 
399
411
  async reorderSections(pageId: string, sectionIds: string[]): Promise<void> {
400
412
  const siteId = await this.findPageSiteId(pageId);
401
- await api(this.url(`/api/cms/sections/reorder?${siteQuery(siteId)}`), {
413
+ await this.api(this.url(`/api/cms/sections/reorder?${siteQuery(siteId)}`), {
402
414
  method: 'POST',
403
415
  body: JSON.stringify({
404
416
  page_id: pageId,
@@ -409,7 +421,7 @@ export class HttpCmsAdapter implements CmsEditorAdapter {
409
421
 
410
422
  async setSectionVisibility(sectionId: string, visible: boolean): Promise<void> {
411
423
  const siteId = await this.guessSiteId();
412
- await api(
424
+ await this.api(
413
425
  this.url(`/api/cms/sections/${encodeURIComponent(sectionId)}/visibility?${siteQuery(siteId)}`),
414
426
  {
415
427
  method: 'POST',
@@ -439,7 +451,7 @@ export class HttpCmsAdapter implements CmsEditorAdapter {
439
451
  input: Partial<CmsEditorBlock> & { type: string },
440
452
  ): Promise<CmsEditorBlock> {
441
453
  const siteId = await this.guessSiteId();
442
- const body = await api<Json>(this.url(`/api/cms/blocks?${siteQuery(siteId)}`), {
454
+ const body = await this.api<Json>(this.url(`/api/cms/blocks?${siteQuery(siteId)}`), {
443
455
  method: 'POST',
444
456
  body: JSON.stringify({
445
457
  section_id: sectionId,
@@ -454,7 +466,7 @@ export class HttpCmsAdapter implements CmsEditorAdapter {
454
466
 
455
467
  async updateBlock(blockId: string, patch: Partial<CmsEditorBlock>): Promise<CmsEditorBlock> {
456
468
  const siteId = await this.guessSiteId();
457
- const body = await api<Json>(
469
+ const body = await this.api<Json>(
458
470
  this.url(`/api/cms/blocks/${encodeURIComponent(blockId)}?${siteQuery(siteId)}`),
459
471
  {
460
472
  method: 'PUT',
@@ -468,50 +480,202 @@ export class HttpCmsAdapter implements CmsEditorAdapter {
468
480
  return mapBlock(body.block || body.component || { id: blockId, ...patch }, patch.sectionId || '');
469
481
  }
470
482
 
471
- async deleteBlock(_blockId: string): Promise<void> {
472
- throw new CmsCapabilityError('deleteBlock', 'Hosted block delete not enabled yet', 'cms_capability_unsupported');
483
+ async deleteBlock(blockId: string): Promise<void> {
484
+ const siteId = await this.guessSiteId();
485
+ await this.api(this.url(`/api/cms/blocks/${encodeURIComponent(blockId)}?${siteQuery(siteId)}`), {
486
+ method: 'DELETE',
487
+ });
488
+ }
489
+
490
+ async reorderBlocks(sectionId: string, blockIds: string[]): Promise<void> {
491
+ const siteId = await this.guessSiteId();
492
+ await this.api(this.url(`/api/cms/blocks/reorder?${siteQuery(siteId)}`), {
493
+ method: 'POST',
494
+ body: JSON.stringify({
495
+ section_id: sectionId,
496
+ order: blockIds.map((id, index) => ({ id, sort_order: (index + 1) * 10 })),
497
+ }),
498
+ });
473
499
  }
474
500
 
475
501
  async saveDraft(pageId: string, payload: unknown): Promise<CmsRevision> {
476
502
  const siteId = await this.findPageSiteId(pageId);
477
503
  const body = payload as { sections?: CmsEditorSection[] };
478
- if (Array.isArray(body?.sections)) {
479
- for (const section of body.sections) {
480
- await api(this.url(`/api/cms/sections/${encodeURIComponent(section.id)}?${siteQuery(siteId)}`), {
481
- method: 'PUT',
482
- body: JSON.stringify({
483
- section_name: section.name,
484
- section_data: section.fields || {},
485
- css: section.css || {},
486
- is_visible: section.visible === false ? 0 : 1,
487
- }),
504
+ const sections = Array.isArray(body?.sections) ? body.sections : [];
505
+
506
+ for (const section of sections) {
507
+ await this.api(this.url(`/api/cms/sections/${encodeURIComponent(section.id)}?${siteQuery(siteId)}`), {
508
+ method: 'PUT',
509
+ body: JSON.stringify({
510
+ section_name: section.name,
511
+ section_data: section.fields || {},
512
+ css: section.css || {},
513
+ is_visible: section.visible === false ? 0 : 1,
514
+ }),
515
+ });
516
+ await this.setSectionVisibility(section.id, section.visible !== false);
517
+
518
+ for (const block of section.blocks || []) {
519
+ await this.updateBlock(block.id, {
520
+ ...block,
521
+ sectionId: section.id,
488
522
  });
489
523
  }
524
+ await this.reorderBlocks(section.id, (section.blocks || []).map((block) => block.id));
490
525
  }
491
- // Mark page draft
492
- await api(this.url(`/api/cms/pages/${encodeURIComponent(pageId)}?${siteQuery(siteId)}`), {
526
+
527
+ // The page is only the route/container. Revision snapshots are composition-first:
528
+ // groups -> sections -> blocks.
529
+ await this.api(this.url(`/api/cms/pages/${encodeURIComponent(pageId)}?${siteQuery(siteId)}`), {
493
530
  method: 'PUT',
494
531
  body: JSON.stringify({ status: 'draft' }),
495
532
  });
533
+
534
+ const composition = {
535
+ version: 1,
536
+ groups: buildCmsEditorGroups(sections),
537
+ sections,
538
+ };
539
+ const revisionBody = await this.api<Json>(
540
+ this.url(`/api/cms/pages/${encodeURIComponent(pageId)}/revisions?${siteQuery(siteId)}`),
541
+ {
542
+ method: 'POST',
543
+ body: JSON.stringify({ kind: 'draft', snapshot: composition }),
544
+ },
545
+ );
546
+ const revision = revisionBody.revision || revisionBody;
496
547
  return {
497
- id: `rev_${Date.now()}`,
498
- pageId,
499
- kind: 'draft',
500
- createdAt: new Date().toISOString(),
501
- snapshot: payload,
548
+ id: String(revision.id),
549
+ pageId: String(revision.pageId || revision.page_id || pageId),
550
+ kind: revision.kind === 'publication' ? 'publication' : 'draft',
551
+ createdAt: String(revision.createdAt || revision.created_at || new Date().toISOString()),
552
+ label: revision.label ? String(revision.label) : undefined,
553
+ snapshot: revision.snapshot,
502
554
  };
503
555
  }
504
556
 
505
- async getRevision(_revisionId: string): Promise<CmsRevision> {
506
- throw new CmsCapabilityError('getRevision', 'revision history API not wired yet', 'cms_capability_unsupported');
557
+ async getRevision(revisionId: string): Promise<CmsRevision> {
558
+ if (!this.knownSites.size) await this.listSites();
559
+ for (const siteId of this.knownSites.keys()) {
560
+ try {
561
+ const body = await this.api<Json>(
562
+ this.url(`/api/cms/revisions/${encodeURIComponent(revisionId)}?${siteQuery(siteId)}`),
563
+ );
564
+ const revision = body.revision || body;
565
+ return {
566
+ id: String(revision.id),
567
+ pageId: String(revision.pageId || revision.page_id),
568
+ kind: revision.kind === 'publication' ? 'publication' : 'draft',
569
+ createdAt: String(revision.createdAt || revision.created_at || new Date().toISOString()),
570
+ label: revision.label ? String(revision.label) : undefined,
571
+ snapshot: revision.snapshot,
572
+ };
573
+ } catch {
574
+ // Revision ids are scoped to a site; try the next known site.
575
+ }
576
+ }
577
+ throw new CmsCapabilityError('getRevision', `revision_not_found:${revisionId}`, 'cms_source_not_found');
507
578
  }
508
579
 
509
- async listRevisions(_pageId: string): Promise<CmsRevision[]> {
510
- return [];
580
+ async listRevisions(pageId: string): Promise<CmsRevision[]> {
581
+ const siteId = await this.findPageSiteId(pageId);
582
+ const body = await this.api<Json>(
583
+ this.url(`/api/cms/pages/${encodeURIComponent(pageId)}/revisions?${siteQuery(siteId)}`),
584
+ );
585
+ return (body.revisions || []).map((revision: Json) => ({
586
+ id: String(revision.id),
587
+ pageId: String(revision.pageId || revision.page_id || pageId),
588
+ kind: revision.kind === 'publication' ? 'publication' : 'draft',
589
+ createdAt: String(revision.createdAt || revision.created_at || ''),
590
+ label: revision.label ? String(revision.label) : undefined,
591
+ }));
511
592
  }
512
593
 
513
- async restoreRevision(_pageId: string, _revisionId: string): Promise<CmsEditorPage> {
514
- throw new CmsCapabilityError('restoreRevision', 'revision restore not wired yet', 'cms_capability_unsupported');
594
+ async restoreRevision(pageId: string, revisionId: string): Promise<CmsEditorPage> {
595
+ const revision = await this.getRevision(revisionId);
596
+ if (revision.pageId !== pageId) {
597
+ throw new CmsCapabilityError('restoreRevision', 'revision_page_mismatch', 'cms_permission_denied');
598
+ }
599
+
600
+ const snapshot = (revision.snapshot || {}) as {
601
+ sections?: CmsEditorSection[];
602
+ groups?: unknown[];
603
+ version?: number;
604
+ };
605
+ const desiredSections = Array.isArray(snapshot.sections) ? snapshot.sections : [];
606
+ const current = await this.getPage(pageId);
607
+ const currentSections = new Map(current.sections.map((section) => [section.id, section]));
608
+ const desiredIds = new Set(desiredSections.map((section) => section.id));
609
+ const restoredSectionIds: string[] = [];
610
+
611
+ // Restore composition only. Route/page metadata is deliberately left untouched.
612
+ for (const section of current.sections) {
613
+ if (!desiredIds.has(section.id)) await this.deleteSection(section.id);
614
+ }
615
+
616
+ for (const desired of desiredSections) {
617
+ const existing = currentSections.get(desired.id);
618
+ let sectionId = desired.id;
619
+
620
+ if (existing) {
621
+ await this.updateSection(existing.id, {
622
+ name: desired.name,
623
+ type: desired.type,
624
+ zone: desired.zone,
625
+ visible: desired.visible,
626
+ color: desired.color,
627
+ fields: desired.fields,
628
+ css: desired.css,
629
+ });
630
+ await this.setSectionVisibility(existing.id, desired.visible !== false);
631
+ } else {
632
+ const created = await this.createSection(pageId, {
633
+ name: desired.name,
634
+ type: desired.type,
635
+ zone: desired.zone,
636
+ visible: desired.visible,
637
+ color: desired.color,
638
+ fields: desired.fields,
639
+ css: desired.css,
640
+ });
641
+ sectionId = created.id;
642
+ }
643
+
644
+ const liveSection = existing || { ...desired, id: sectionId, blocks: [] };
645
+ const existingBlocks = new Map((liveSection.blocks || []).map((block) => [block.id, block]));
646
+ const desiredBlockIds = new Set((desired.blocks || []).map((block) => block.id));
647
+
648
+ for (const block of liveSection.blocks || []) {
649
+ if (!desiredBlockIds.has(block.id)) await this.deleteBlock(block.id);
650
+ }
651
+
652
+ const restoredBlockIds: string[] = [];
653
+ for (const desiredBlock of desired.blocks || []) {
654
+ const liveBlock = existingBlocks.get(desiredBlock.id);
655
+ let blockId = desiredBlock.id;
656
+ if (liveBlock) {
657
+ await this.updateBlock(liveBlock.id, {
658
+ ...desiredBlock,
659
+ sectionId,
660
+ });
661
+ } else {
662
+ const createdBlock = await this.createBlock(sectionId, {
663
+ type: desiredBlock.type,
664
+ visible: desiredBlock.visible,
665
+ data: desiredBlock.data,
666
+ sortOrder: desiredBlock.sortOrder,
667
+ });
668
+ blockId = createdBlock.id;
669
+ }
670
+ restoredBlockIds.push(blockId);
671
+ }
672
+
673
+ await this.reorderBlocks(sectionId, restoredBlockIds);
674
+ restoredSectionIds.push(sectionId);
675
+ }
676
+
677
+ await this.reorderSections(pageId, restoredSectionIds);
678
+ return this.getPage(pageId);
515
679
  }
516
680
 
517
681
  async previewDraft(pageId: string): Promise<{ previewUrl?: string; snapshot: unknown }> {
@@ -525,17 +689,25 @@ export class HttpCmsAdapter implements CmsEditorAdapter {
525
689
 
526
690
  async publish(pageId: string): Promise<CmsPublicationSnapshot> {
527
691
  const siteId = await this.findPageSiteId(pageId);
528
- const body = await api<Json>(
692
+ const body = await this.api<Json>(
529
693
  this.url(`/api/cms/pages/${encodeURIComponent(pageId)}/publish?${siteQuery(siteId)}`),
530
694
  { method: 'POST', body: JSON.stringify({}) },
531
695
  );
532
- const page = mapPage(body.page || { id: pageId, slug: '/' }, []);
696
+ const page = await this.getPage(pageId);
533
697
  return {
534
698
  publicationId: `pub_${pageId}`,
535
699
  route: page.slug,
536
700
  revision: 1,
537
701
  theme: 'default',
538
- sections: [],
702
+ sections: page.sections.map((section) => ({
703
+ type: section.type,
704
+ props: {
705
+ ...section.fields,
706
+ name: section.name,
707
+ group: section.fields?.group || section.fields?.group_id,
708
+ blocks: section.blocks,
709
+ },
710
+ })),
539
711
  publishedAt: new Date().toISOString(),
540
712
  };
541
713
  }
@@ -561,7 +733,7 @@ export class HttpCmsAdapter implements CmsEditorAdapter {
561
733
  }
562
734
 
563
735
  async listAssets(siteId: string): Promise<CmsAsset[]> {
564
- const body = await api<Json>(this.url(`/api/cms/assets?${siteQuery(siteId)}`));
736
+ const body = await this.api<Json>(this.url(`/api/cms/assets?${siteQuery(siteId)}`));
565
737
  return (body.assets || []).map((row: Json) => ({
566
738
  id: String(row.id),
567
739
  name: String(row.original_filename || row.filename || row.id),
@@ -582,22 +754,65 @@ export class HttpCmsAdapter implements CmsEditorAdapter {
582
754
  }
583
755
 
584
756
  async uploadAsset(
585
- _siteId: string,
586
- _file: Blob,
587
- _meta?: { name?: string; metadata?: Record<string, unknown> },
757
+ siteId: string,
758
+ file: Blob,
759
+ meta?: { name?: string; metadata?: Record<string, unknown> },
588
760
  ): Promise<CmsAsset> {
589
- throw new CmsCapabilityError('uploadAsset', 'Hosted asset upload uses Media studio', 'cms_capability_unsupported');
761
+ const form = new FormData();
762
+ const filename = meta?.name || ('name' in file && typeof file.name === 'string' ? file.name : 'asset');
763
+ form.set('file', file, filename);
764
+ if (meta?.name) form.set('name', meta.name);
765
+ if (meta?.metadata) form.set('metadata', JSON.stringify(meta.metadata));
766
+
767
+ const body = await this.api<Json>(this.url(`/api/cms/assets?${siteQuery(siteId)}`), {
768
+ method: 'POST',
769
+ body: form,
770
+ });
771
+ const row = body.asset || body;
772
+ return {
773
+ id: String(row.id),
774
+ name: String(row.original_filename || row.filename || row.id),
775
+ mimeType: row.mime_type ? String(row.mime_type) : undefined,
776
+ size: row.content_size_bytes != null ? Number(row.content_size_bytes) : undefined,
777
+ url: row.public_url ? String(row.public_url) : undefined,
778
+ key: String(row.id),
779
+ metadata: parseFields(row.metadata),
780
+ };
590
781
  }
591
782
 
592
783
  async updateAsset(
593
- _assetId: string,
594
- _patch: Partial<Pick<CmsAsset, 'name' | 'metadata' | 'url' | 'key'>>,
784
+ assetId: string,
785
+ patch: Partial<Pick<CmsAsset, 'name' | 'metadata' | 'url' | 'key'>>,
595
786
  ): Promise<CmsAsset> {
596
- throw new CmsCapabilityError('updateAsset', 'Hosted asset update not enabled', 'cms_capability_unsupported');
787
+ const siteId = await this.findAssetSiteId(assetId);
788
+ const body = await this.api<Json>(
789
+ this.url(`/api/cms/assets/${encodeURIComponent(assetId)}?${siteQuery(siteId)}`),
790
+ {
791
+ method: 'PATCH',
792
+ body: JSON.stringify({
793
+ name: patch.name,
794
+ metadata: patch.metadata,
795
+ }),
796
+ },
797
+ );
798
+ const row = body.asset || body;
799
+ return {
800
+ id: String(row.id),
801
+ name: String(row.original_filename || row.filename || row.id),
802
+ mimeType: row.mime_type ? String(row.mime_type) : undefined,
803
+ size: row.content_size_bytes != null ? Number(row.content_size_bytes) : undefined,
804
+ url: row.public_url ? String(row.public_url) : undefined,
805
+ key: String(row.id),
806
+ metadata: parseFields(row.metadata),
807
+ };
597
808
  }
598
809
 
599
- async deleteAsset(_assetId: string): Promise<void> {
600
- throw new CmsCapabilityError('deleteAsset', 'Hosted asset delete not enabled', 'cms_capability_unsupported');
810
+ async deleteAsset(assetId: string): Promise<void> {
811
+ const siteId = await this.findAssetSiteId(assetId);
812
+ await this.api(
813
+ this.url(`/api/cms/assets/${encodeURIComponent(assetId)}?${siteQuery(siteId)}`),
814
+ { method: 'DELETE' },
815
+ );
601
816
  }
602
817
 
603
818
  private guessSiteId() {
@@ -619,6 +834,21 @@ export class HttpCmsAdapter implements CmsEditorAdapter {
619
834
  }
620
835
  return this.guessSiteId();
621
836
  }
837
+
838
+ private async findAssetSiteId(assetId: string): Promise<string> {
839
+ if (!this.knownSites.size) {
840
+ await this.listSites();
841
+ }
842
+ for (const siteId of this.knownSites.keys()) {
843
+ try {
844
+ const assets = await this.listAssets(siteId);
845
+ if (assets.some((asset) => asset.id === assetId)) return siteId;
846
+ } catch {
847
+ // continue
848
+ }
849
+ }
850
+ throw new CmsCapabilityError('getAsset', `asset_not_found:${assetId}`, 'cms_source_not_found');
851
+ }
622
852
  }
623
853
 
624
854
  export function createHttpCmsAdapter(
@@ -626,3 +856,4 @@ export function createHttpCmsAdapter(
626
856
  ): HttpCmsAdapter {
627
857
  return new HttpCmsAdapter(options);
628
858
  }
859
+