@inneranimalmedia/agentsam-sdk 2.6.5 → 2.6.8

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 (400) hide show
  1. package/AGENTSAM.md +29 -0
  2. package/README.md +37 -0
  3. package/apps/README.md +5 -0
  4. package/apps/cad-creator/README.md +4 -4
  5. package/apps/cad-creator/shared/cad/package.json +1 -1
  6. package/apps/client-cms-editor/AGENTS.md +12 -7
  7. package/apps/client-cms-editor/README.md +76 -48
  8. package/apps/client-cms-editor/agentsam.app.json +26 -9
  9. package/apps/client-cms-editor/backend/package.json +20 -3
  10. package/apps/client-cms-editor/backend/src/api/client.ts +134 -101
  11. package/apps/client-cms-editor/backend/src/index.ts +1 -1
  12. package/apps/client-cms-editor/backend/src/model.ts +11 -115
  13. package/apps/client-cms-editor/backend/src/preview/bridge.ts +1 -1
  14. package/apps/client-cms-editor/backend/tsconfig.json +6 -1
  15. package/apps/client-cms-editor/bin/agentsam-cms.js +262 -0
  16. package/apps/client-cms-editor/bin/agentsam-cms.mjs +2 -228
  17. package/apps/client-cms-editor/frontend/package.json +16 -7
  18. package/apps/client-cms-editor/frontend/src/AgentSamDrawer.tsx +9 -41
  19. package/apps/client-cms-editor/frontend/src/CmsAgentSurface.tsx +19 -174
  20. package/apps/client-cms-editor/frontend/src/adapters/heuristic.ts +29 -0
  21. package/apps/client-cms-editor/frontend/src/adapters/http.ts +628 -0
  22. package/apps/client-cms-editor/frontend/src/adapters/memory.ts +510 -0
  23. package/apps/client-cms-editor/frontend/src/editor/CmsEditor.tsx +213 -0
  24. package/apps/client-cms-editor/frontend/src/editor/CmsEditorProvider.tsx +20 -0
  25. package/apps/client-cms-editor/frontend/src/editor/canvas/PreviewCanvas.tsx +53 -0
  26. package/apps/client-cms-editor/frontend/src/{CmsEditor.tsx → editor/legacy/CmsEditorPrototype.tsx} +52 -23
  27. package/apps/client-cms-editor/frontend/src/editor/useCmsEditorController.ts +218 -0
  28. package/apps/client-cms-editor/frontend/src/index.ts +19 -5
  29. package/apps/client-cms-editor/frontend/src/lib/agent-host.ts +24 -0
  30. package/apps/client-cms-editor/frontend/src/main.tsx +82 -8
  31. package/apps/client-cms-editor/frontend/src/mount.tsx +92 -30
  32. package/apps/client-cms-editor/frontend/src/styles/agentsam-drawer.css +1 -1
  33. package/apps/client-cms-editor/frontend/src/styles/cmsShell.css +8 -8
  34. package/apps/client-cms-editor/frontend/src/styles/studio.css +55 -3
  35. package/apps/client-cms-editor/frontend/tsconfig.json +12 -1
  36. package/apps/client-cms-editor/frontend/vite.config.ts +12 -0
  37. package/apps/client-cms-editor/package-lock.json +973 -134
  38. package/apps/client-cms-editor/package.json +118 -6
  39. package/apps/client-cms-editor/reference/harvest/HARVEST_RECEIPT.json +201 -0
  40. package/apps/client-cms-editor/reference/harvest/PROVENANCE_HISTORY.txt +10 -0
  41. package/apps/client-cms-editor/reference/harvest/README.md +8 -0
  42. package/apps/client-cms-editor/reference/harvest/plans/ARCHIVE-INTAKE.md +135 -0
  43. package/apps/client-cms-editor/reference/harvest/plans/CHATGPT-IDENTITY-HARVEST.md +83 -0
  44. package/apps/client-cms-editor/reference/harvest/plans/CMS-EDITOR-HARVEST.md +166 -0
  45. package/apps/client-cms-editor/reference/harvest/plans/HARVEST-INDEX.md +196 -0
  46. package/apps/client-cms-editor/reference/harvest/plans/INNERANIMALS-CONTENT-001.md +137 -0
  47. package/apps/client-cms-editor/reference/harvest/plans/NO-IMPLICIT-SIDE-EFFECTS.md +87 -0
  48. package/apps/client-cms-editor/reference/harvest/plans/STOREFRONT-SURFACE-MAP.md +140 -0
  49. package/apps/client-cms-editor/reference/harvest/plans/THEME-INNERANIMALS-HARVEST.md +137 -0
  50. package/apps/client-cms-editor/reference/harvest/plans/TOOLING-LAB.md +63 -0
  51. package/apps/client-cms-editor/reference/harvest/plans/harvest-manifest.json +97 -0
  52. package/apps/client-cms-editor/reference/harvest/plans/local-cms-harvest-schema.sql +328 -0
  53. package/apps/client-cms-editor/shared/cms/package.json +17 -7
  54. package/apps/client-cms-editor/shared/cms/src/adapter.ts +204 -0
  55. package/apps/client-cms-editor/shared/cms/src/agent-context.ts +7 -5
  56. package/apps/client-cms-editor/shared/cms/src/editor-types.ts +32 -0
  57. package/apps/client-cms-editor/shared/cms/src/host.ts +82 -0
  58. package/apps/client-cms-editor/shared/cms/src/index.ts +4 -0
  59. package/apps/client-cms-editor/shared/cms/src/map.ts +115 -0
  60. package/apps/client-cms-editor/shared/cms/src/starter-pack.ts +158 -0
  61. package/contracts/source-types.v1.json +353 -0
  62. package/docs/CMS_CONTEXTUAL_COMPOSER.md +1 -1
  63. package/docs/PRODUCT_LIFECYCLE.md +566 -0
  64. package/docs/REPO_FILE_MAP.txt +132 -0
  65. package/docs/THEME_REFINERY.md +2 -2
  66. package/docs/architecture/AGENTSAM_RUNTIME_PROTOCOL.md +40 -20
  67. package/docs/content-studio/REVISION_GATE_2026-09-27.md +1 -1
  68. package/docs/plans/LOCAL_STUDIO_DESKTOP_RELEASE_2026-09-29.md +150 -0
  69. package/migrations/d1/0017_identity_native_oauth.sql +21 -0
  70. package/migrations/d1/0018_goap_control_plane_remaster.sql +40 -0
  71. package/migrations/d1/0019_agentsam_agent_run_plan_todo.sql +14 -0
  72. package/migrations/d1/README_PORTABLE_CONTROL_PLANE.md +20 -9
  73. package/migrations/runtime/0002_goap_blackboard_v1.sql +15 -0
  74. package/migrations/runtime/0004_agent_run_plan_linkage.sql +8 -0
  75. package/native/agentsam-machine/Cargo.lock +426 -0
  76. package/native/agentsam-machine/Cargo.toml +9 -0
  77. package/native/agentsam-machine/cli/Cargo.toml +21 -0
  78. package/native/agentsam-machine/cli/README.md +21 -0
  79. package/native/agentsam-machine/cli/src/main.rs +77 -0
  80. package/native/agentsam-machine/core/Cargo.toml +22 -0
  81. package/native/agentsam-machine/core/README.md +14 -0
  82. package/native/agentsam-machine/core/build.rs +33 -0
  83. package/native/agentsam-machine/core/contracts/source-types.v1.json +353 -0
  84. package/native/agentsam-machine/core/src/assets.rs +790 -0
  85. package/native/agentsam-machine/core/src/bound.rs +298 -0
  86. package/native/agentsam-machine/core/src/enrich.rs +706 -0
  87. package/native/agentsam-machine/core/src/frontend.rs +442 -0
  88. package/native/agentsam-machine/core/src/lib.rs +1092 -0
  89. package/native/agentsam-machine/core/src/liquid.rs +528 -0
  90. package/native/agentsam-machine/core/src/source_types.rs +78 -0
  91. package/package.json +64 -24
  92. package/packages/agentsam-brand/README.md +1 -1
  93. package/packages/agentsam-brand/package.json +4 -4
  94. package/packages/agentsam-brand/src/index.js +1 -1
  95. package/packages/agentsam-contracts/package.json +13 -3
  96. package/packages/agentsam-contracts/src/tools.ts +22 -0
  97. package/packages/agentsam-errors/package.json +13 -3
  98. package/packages/agentsam-errors/src/index.js +1 -0
  99. package/packages/agentsam-errors/src/tool.js +56 -0
  100. package/packages/agentsam-errors/test/tool.test.mjs +58 -0
  101. package/packages/agentsam-goap/README.md +52 -0
  102. package/packages/agentsam-goap/package.json +37 -0
  103. package/packages/agentsam-goap/src/adapters/d1-sqlite.js +570 -0
  104. package/packages/agentsam-goap/src/adapters/memory.js +199 -0
  105. package/packages/agentsam-goap/src/contracts.js +226 -0
  106. package/packages/agentsam-goap/src/control-plane.js +112 -0
  107. package/packages/agentsam-goap/src/errors.js +157 -0
  108. package/packages/agentsam-goap/src/index.js +5 -0
  109. package/packages/agentsam-goap/src/world.js +202 -0
  110. package/packages/agentsam-goap/test/goap-control-plane.test.mjs +245 -0
  111. package/packages/agentsam-goap/test/world.test.mjs +79 -0
  112. package/packages/agentsam-knowledge/package.json +18 -4
  113. package/packages/agentsam-knowledge/src/autorag/index.js +10 -3
  114. package/packages/agentsam-knowledge/src/backends/index.js +33 -1
  115. package/packages/agentsam-knowledge/test/autorag.test.mjs +60 -1
  116. package/packages/agentsam-nav/dist/browser.global.js +21 -18
  117. package/packages/agentsam-nav/dist/browser.js +6807 -130
  118. package/packages/agentsam-nav/dist/index.js +6799 -122
  119. package/packages/agentsam-nav/package.json +24 -6
  120. package/packages/agentsam-queue-control/README.md +1 -1
  121. package/packages/agentsam-queue-control/package.json +7 -2
  122. package/packages/agentsam-rapid-rust/src/main.rs +1 -1
  123. package/packages/agentsam-repository/package.json +13 -3
  124. package/packages/agentsam-repository/src/goap.js +13 -14
  125. package/packages/agentsam-repository/src/source-types.js +8 -0
  126. package/packages/agentsam-repository/src/tickets.js +15 -22
  127. package/packages/agentsam-repository/test/goap-tickets-workspace-state.test.mjs +19 -8
  128. package/packages/agentsam-vault/package.json +14 -4
  129. package/packages/agentsam-workbench/package.json +15 -4
  130. package/packages/agentsam-workbench/src/agent/ToolPermissionRequest.tsx +94 -0
  131. package/packages/agentsam-workbench/src/agent/index.ts +2 -0
  132. package/packages/agentsam-workbench/src/agent/tool-permission.css +134 -0
  133. package/packages/connectors/cloudflare/package.json +15 -3
  134. package/packages/connectors/cloudflare/src/api-client.js +3 -2
  135. package/packages/connectors/cloudflare/src/families/vectorize.js +127 -0
  136. package/packages/connectors/cloudflare/src/index.js +1 -0
  137. package/packages/heuristic-theme/README.md +2 -2
  138. package/packages/heuristic-theme/package.json +8 -3
  139. package/packages/heuristic-theme/src/registry.js +2 -2
  140. package/packages/heuristic-theme/src/theme.js +1 -1
  141. package/packages/heuristic-theme/test/theme.test.mjs +1 -1
  142. package/packages/identity/.agentsam/features/oauth-login-portal/agentsam.feature.json +1 -1
  143. package/packages/identity/.agentsam/features/oauth-login-portal/providers.json +27 -7
  144. package/packages/identity/README.md +2 -2
  145. package/packages/identity/migrations/D1_SCHEMA_MAPPING.md +18 -15
  146. package/packages/identity/migrations/apply-portable.js +109 -0
  147. package/packages/identity/migrations/sqlite/004_identity_oauth_consent_catalog.sql +1 -1
  148. package/packages/identity/migrations/sqlite/005_identity_company_native.sql +52 -0
  149. package/packages/identity/package.json +27 -6
  150. package/packages/identity/schema/agentsam.identity/manifest.json +101 -0
  151. package/packages/identity/scripts/local-identity-bridge.mjs +13 -7
  152. package/packages/identity/scripts/preview-auth-portal.mjs +6 -6
  153. package/packages/identity/src/adapters/cloudflare-d1/index.js +8 -401
  154. package/packages/identity/src/adapters/iam-compat/index.js +540 -0
  155. package/packages/identity/src/adapters/portable-d1/index.js +18 -0
  156. package/packages/identity/src/adapters/portable-store.js +479 -0
  157. package/packages/identity/src/adapters/sqlite/index.js +13 -312
  158. package/packages/identity/src/contracts/auth-config.js +0 -1
  159. package/packages/identity/src/contracts/identity-store.js +56 -5
  160. package/packages/identity/src/contracts/provider.js +1 -0
  161. package/packages/identity/src/contracts/sign-in-options.js +104 -0
  162. package/packages/identity/src/core/constants.js +1 -1
  163. package/packages/identity/src/core/session-policy.js +31 -0
  164. package/packages/identity/src/frontend/auth-portal/pages/login.html +6 -6
  165. package/packages/identity/src/frontend/auth-portal/pages/reset.html +5 -5
  166. package/packages/identity/src/frontend/auth-portal/pages/signup.html +5 -5
  167. package/packages/identity/src/frontend/auth-portal/shared/company-branding.js +1 -1
  168. package/packages/identity/src/frontend/auth-portal/shared/desktop-identity-bridge.js +6 -37
  169. package/packages/identity/src/index.js +28 -1
  170. package/packages/identity/src/migrations/README.md +23 -23
  171. package/packages/identity/src/oauth/README.md +1 -1
  172. package/packages/identity/src/oauth/credentials.js +10 -11
  173. package/packages/identity/src/oauth/google-desktop-exchange.js +195 -27
  174. package/packages/identity/src/oauth/iam-platform.js +21 -9
  175. package/packages/identity/src/oauth/native-handoff.js +136 -0
  176. package/packages/identity/src/providers/chatgpt/headers.js +65 -0
  177. package/packages/identity/src/providers/chatgpt/index.js +86 -0
  178. package/packages/identity/src/providers/chatgpt/mapper.js +43 -0
  179. package/packages/identity/src/providers/chatgpt/paths.js +45 -0
  180. package/packages/identity/src/providers/github/oauth.js +1 -2
  181. package/packages/identity/src/providers/github/profile.js +16 -2
  182. package/packages/identity/src/providers/index.js +11 -3
  183. package/packages/identity/src/server/identity-service.js +2 -1
  184. package/packages/identity/src/server/worker-router.js +71 -18
  185. package/packages/identity/tests/chatgpt-provider.test.mjs +75 -0
  186. package/packages/identity/tests/google-desktop-identity-login.test.mjs +210 -0
  187. package/packages/identity/tests/identity-init-scaffold.test.mjs +15 -4
  188. package/packages/identity/tests/lane1-identity-store-parity.test.mjs +527 -0
  189. package/packages/identity/tests/lane1-packed-consumer.test.mjs +175 -0
  190. package/packages/identity/tests/native-oauth-handoff.test.mjs +292 -0
  191. package/packages/identity/tests/oauth-credentials.test.mjs +4 -4
  192. package/packages/identity/tests/preview-auth-portal.test.mjs +4 -2
  193. package/packages/identity/tests/session-routes-policy.test.mjs +13 -1
  194. package/packages/identity/tests/worker-runtime-boundary.test.mjs +11 -0
  195. package/packages/providers/completeful/package.json +7 -2
  196. package/packages/theme-church-site/package.json +17 -6
  197. package/packages/theme-church-site/src/harvest.json +4 -2
  198. package/packages/theme-church-site/src/index.js +7 -3
  199. package/packages/theme-church-site/test/theme.test.mjs +4 -2
  200. package/packages/theme-companions-site/package.json +17 -6
  201. package/packages/theme-companions-site/src/harvest.json +4 -2
  202. package/packages/theme-companions-site/src/index.js +7 -3
  203. package/packages/theme-companions-site/test/theme.test.mjs +4 -2
  204. package/packages/theme-floors-site/package.json +17 -6
  205. package/packages/theme-floors-site/src/harvest.json +4 -2
  206. package/packages/theme-floors-site/src/index.js +7 -3
  207. package/packages/theme-floors-site/test/theme.test.mjs +4 -2
  208. package/packages/theme-fuelnfree-site/package.json +17 -6
  209. package/packages/theme-fuelnfree-site/src/harvest.json +4 -2
  210. package/packages/theme-fuelnfree-site/src/index.js +7 -3
  211. package/packages/theme-fuelnfree-site/test/theme.test.mjs +4 -2
  212. package/packages/theme-handyman-site/package.json +17 -6
  213. package/packages/theme-handyman-site/src/harvest.json +4 -2
  214. package/packages/theme-handyman-site/src/index.js +7 -3
  215. package/packages/theme-handyman-site/test/theme.test.mjs +4 -2
  216. package/packages/theme-insurance-site/package.json +17 -6
  217. package/packages/theme-insurance-site/src/harvest.json +4 -2
  218. package/packages/theme-insurance-site/src/index.js +7 -3
  219. package/packages/theme-insurance-site/test/theme.test.mjs +4 -2
  220. package/packages/theme-scenes/README.md +1 -1
  221. package/packages/theme-scenes/package.json +4 -3
  222. package/packages/theme-scenes/src/registry.js +187 -0
  223. package/packages/theme-shinshu-site/package.json +17 -6
  224. package/packages/theme-shinshu-site/src/harvest.json +4 -2
  225. package/packages/theme-shinshu-site/src/index.js +7 -3
  226. package/packages/theme-shinshu-site/test/theme.test.mjs +4 -2
  227. package/packages/work-graph/package.json +14 -4
  228. package/protocol/FILEMETA_V1.md +2 -2
  229. package/protocol/capabilities/manifest.json +1 -1
  230. package/protocol/database/agentsam.schema-pack.v1.schema.json +72 -0
  231. package/protocol/presets/catalog.json +2 -2
  232. package/protocol/theme-refinery/lineage-registry.json +105 -0
  233. package/protocol/theme-refinery/product-metadata.schema.json +21 -1
  234. package/python/agentsam_sdk/repository/intelligence/discovery.py +27 -2
  235. package/python/agentsam_sdk/repository/intelligence/git.py +4 -0
  236. package/python/tests/test_repository_intelligence.py +30 -0
  237. package/src/cli/command-catalog.js +48 -5
  238. package/src/cli/dispatch.js +1 -0
  239. package/src/cli.js +20 -1
  240. package/src/cloudflare/runtime-status.js +2 -1
  241. package/src/commands/autorag.js +67 -13
  242. package/src/commands/cheat-sheet.js +29 -4
  243. package/src/commands/codebaseindex.js +45 -2
  244. package/src/commands/goap-world.js +134 -0
  245. package/src/commands/goap.js +11 -4
  246. package/src/commands/knowledge.js +59 -2
  247. package/src/commands/machine-binary.js +109 -0
  248. package/src/commands/machine-runtime.js +266 -0
  249. package/src/commands/machine.js +208 -0
  250. package/src/commands/package.js +530 -0
  251. package/src/commands/plan-ledger.js +370 -0
  252. package/src/commands/plan.js +183 -0
  253. package/src/commands/security.js +67 -4
  254. package/src/commands/setup.js +33 -16
  255. package/src/commands/skill.js +78 -17
  256. package/src/commands/status.js +8 -1
  257. package/src/features/resolve.js +1 -0
  258. package/src/knowledge/engine.js +21 -2
  259. package/src/knowledge/runtime-discovery.js +127 -0
  260. package/src/knowledge/source.js +1 -1
  261. package/src/lib/identity-scaffold.js +53 -13
  262. package/src/lib/setup/recipes.js +1 -1
  263. package/src/lib/slash-commands.js +1 -1
  264. package/src/local/runtime-store.js +24 -2
  265. package/src/local/sqlite.js +17 -0
  266. package/src/models/discovery.js +40 -22
  267. package/src/models/inventory-core.d.ts +105 -0
  268. package/src/models/inventory-core.js +54 -6
  269. package/src/sam/operations/package-audit.js +41 -0
  270. package/src/sam/seed.js +2 -0
  271. package/src/security/logs.js +3 -0
  272. package/src/ui/cli/help.js +41 -0
  273. package/apps/client-cms-editor/backend/src/demo-bootstrap.ts +0 -145
  274. package/test/account-session.test.mjs +0 -101
  275. package/test/agent-capabilities.test.mjs +0 -67
  276. package/test/app-authority-context.test.mjs +0 -32
  277. package/test/app-building-skills.test.mjs +0 -61
  278. package/test/apps-scaffold-contract.test.mjs +0 -114
  279. package/test/blender-cad.test.mjs +0 -146
  280. package/test/cad-docker.test.mjs +0 -96
  281. package/test/capabilities.test.mjs +0 -133
  282. package/test/cli/api-key-env-whoami.test.mjs +0 -129
  283. package/test/cli/codebaseindex-plan-ux.test.mjs +0 -37
  284. package/test/cli/eval-live.test.mjs +0 -219
  285. package/test/cli/go.test.mjs +0 -128
  286. package/test/cli/local-vault-and-provider-setup.test.mjs +0 -268
  287. package/test/cli/mcp-client.test.mjs +0 -256
  288. package/test/cli/preferences-runtime.test.mjs +0 -11
  289. package/test/cli/runtime-persist.test.mjs +0 -56
  290. package/test/cli/runtime-ui.test.mjs +0 -141
  291. package/test/cli/rust-command.test.mjs +0 -21
  292. package/test/cli/skill-npm-and-env.test.mjs +0 -52
  293. package/test/cli/status-actions.test.mjs +0 -88
  294. package/test/cli/wireframes-go-registry.test.mjs +0 -139
  295. package/test/cli-preferences.test.mjs +0 -46
  296. package/test/cloudflare-connector.test.mjs +0 -93
  297. package/test/cloudflare-runtime.test.mjs +0 -82
  298. package/test/context.test.mjs +0 -159
  299. package/test/credentials-audit.test.mjs +0 -113
  300. package/test/deploy-health-scan.test.mjs +0 -95
  301. package/test/deploy-receipt.test.mjs +0 -91
  302. package/test/dockerize.test.mjs +0 -93
  303. package/test/error-diagnostics.test.mjs +0 -124
  304. package/test/eval-context.test.mjs +0 -37
  305. package/test/execution-approvals.test.mjs +0 -27
  306. package/test/fixtures/cad/courtyard-house.json +0 -208
  307. package/test/fixtures/knowledge-rpc-worker.mjs +0 -16
  308. package/test/gcloud-auth.test.mjs +0 -111
  309. package/test/go/build-source-identity.test.mjs +0 -31
  310. package/test/go/cloudflare-probe.test.mjs +0 -317
  311. package/test/go/distribution.test.mjs +0 -28
  312. package/test/google-cloud-connection.test.mjs +0 -83
  313. package/test/google-cloud-inventory.test.mjs +0 -64
  314. package/test/indexing-provider.test.mjs +0 -29
  315. package/test/init-options.test.mjs +0 -35
  316. package/test/integration/ai-access-onboarding.test.mjs +0 -47
  317. package/test/integration/app-command.test.mjs +0 -85
  318. package/test/integration/cad-discovery.test.mjs +0 -158
  319. package/test/integration/cad-docker-executor.test.mjs +0 -249
  320. package/test/integration/cad-execution.test.mjs +0 -184
  321. package/test/integration/cad-project-app.test.mjs +0 -31
  322. package/test/integration/cad-project-d1.test.mjs +0 -25
  323. package/test/integration/cad-project-native.test.mjs +0 -24
  324. package/test/integration/cad-project-workflow.test.mjs +0 -9
  325. package/test/integration/cad-project.test.mjs +0 -85
  326. package/test/integration/cli-help.test.mjs +0 -41
  327. package/test/integration/cms-app-scaffold.test.mjs +0 -71
  328. package/test/integration/cms-site-tenancy-contract.test.mjs +0 -257
  329. package/test/integration/codebaseindex-ingest.test.mjs +0 -214
  330. package/test/integration/core-client.integration.test.mjs +0 -55
  331. package/test/integration/error-runtime-rpc.test.mjs +0 -71
  332. package/test/integration/features-resolve.test.mjs +0 -147
  333. package/test/integration/icon-registry.test.mjs +0 -67
  334. package/test/integration/ingest-discover-models.test.mjs +0 -30
  335. package/test/integration/inspect-path-cli.test.mjs +0 -46
  336. package/test/integration/install-script.test.mjs +0 -110
  337. package/test/integration/inventory-core.test.mjs +0 -53
  338. package/test/integration/inventory-evidence.test.mjs +0 -125
  339. package/test/integration/knowledge-rpc.test.mjs +0 -112
  340. package/test/integration/local-fs.test.mjs +0 -113
  341. package/test/integration/merkle-cli.test.mjs +0 -61
  342. package/test/integration/merkle-persistence-identity.test.mjs +0 -48
  343. package/test/integration/plugins-cloudflare.integration.test.mjs +0 -28
  344. package/test/integration/provider-env-cli.test.mjs +0 -50
  345. package/test/integration/provider-factory.test.mjs +0 -197
  346. package/test/integration/repository-company-graph.test.mjs +0 -90
  347. package/test/integration/runtime-migrations.test.mjs +0 -87
  348. package/test/integration/runtime-status.integration.test.mjs +0 -212
  349. package/test/integration/sam-activity-recovery.test.mjs +0 -147
  350. package/test/integration/sam-decision.test.mjs +0 -584
  351. package/test/integration/sam-kernel.test.mjs +0 -99
  352. package/test/integration/sam-planning-astar.test.mjs +0 -279
  353. package/test/integration/scaffold-cloudflare.test.mjs +0 -46
  354. package/test/integration/skill-runtime.test.mjs +0 -240
  355. package/test/integration/storage-architecture.test.mjs +0 -154
  356. package/test/integration/store-discovery.test.mjs +0 -44
  357. package/test/integration/studio-fs-pty-e2e.test.mjs +0 -294
  358. package/test/integration/terminal-exec.integration.test.mjs +0 -86
  359. package/test/integration/tool-runtime.test.mjs +0 -124
  360. package/test/integration/tool-schema.test.mjs +0 -59
  361. package/test/jr-dev-skill.test.mjs +0 -26
  362. package/test/knowledge-context-pack.test.mjs +0 -19
  363. package/test/knowledge-postgres.test.mjs +0 -40
  364. package/test/knowledge-service.test.mjs +0 -110
  365. package/test/knowledge.test.mjs +0 -206
  366. package/test/live/terminal-transport.live.test.mjs +0 -24
  367. package/test/local-sessions.test.mjs +0 -57
  368. package/test/local-studio-deploy.test.mjs +0 -83
  369. package/test/loopback-oauth.test.mjs +0 -53
  370. package/test/merkle-render.test.mjs +0 -31
  371. package/test/mini.test.mjs +0 -140
  372. package/test/model-catalog.test.mjs +0 -70
  373. package/test/models.test.mjs +0 -309
  374. package/test/npm10-lock.test.mjs +0 -29
  375. package/test/ollama.test.mjs +0 -137
  376. package/test/open-url.test.mjs +0 -64
  377. package/test/openai-responses.test.mjs +0 -155
  378. package/test/portable-context.test.mjs +0 -94
  379. package/test/project-config.test.mjs +0 -81
  380. package/test/project-rules.test.mjs +0 -44
  381. package/test/provider-credentials.test.mjs +0 -106
  382. package/test/rehydrate.test.mjs +0 -25
  383. package/test/release-hygiene.test.mjs +0 -42
  384. package/test/repository-snapshot-view.test.mjs +0 -112
  385. package/test/responses-runner.test.mjs +0 -465
  386. package/test/runtime-activity.test.mjs +0 -98
  387. package/test/sdk-worker-contract.test.mjs +0 -72
  388. package/test/security.test.mjs +0 -252
  389. package/test/setup-planner.test.mjs +0 -74
  390. package/test/setup-runtime.test.mjs +0 -51
  391. package/test/shell.test.mjs +0 -281
  392. package/test/skills.test.mjs +0 -22
  393. package/test/smoke.mjs +0 -122
  394. package/test/telemetry.test.mjs +0 -79
  395. package/test/terminal/local-pty.mock.test.mjs +0 -153
  396. package/test/terminal-machine-identity.test.mjs +0 -88
  397. package/test/theme-portability.test.mjs +0 -14
  398. package/test/tools-search.test.mjs +0 -73
  399. package/test/unit/website-assets-bindings.test.mjs +0 -60
  400. package/test/whoami-resume.test.mjs +0 -157
@@ -0,0 +1,628 @@
1
+ /**
2
+ * HTTP CmsEditorAdapter — hosted Worker CMS authority via /api/cms/*.
3
+ * Durable D1-backed persistence. Never an in-memory substitute.
4
+ */
5
+
6
+ import {
7
+ CmsCapabilityError,
8
+ type CmsAsset,
9
+ type CmsEditorAdapter,
10
+ type CmsPublicationSnapshot,
11
+ type CmsRevision,
12
+ } from '../../../shared/cms/src/adapter';
13
+ import type {
14
+ CmsEditorBlock,
15
+ CmsEditorPage,
16
+ CmsEditorSection,
17
+ CmsEditorSite,
18
+ CmsSiteCreateInput,
19
+ CmsSiteRecord,
20
+ CmsSiteUpdatePatch,
21
+ } from '../../../shared/cms/src/editor-types';
22
+
23
+ type Json = Record<string, any>;
24
+
25
+ function siteQuery(siteId: string) {
26
+ return `site=${encodeURIComponent(siteId)}`;
27
+ }
28
+
29
+ async function api<T = Json>(path: string, init: RequestInit = {}): Promise<T> {
30
+ const headers = new Headers(init.headers || {});
31
+ if (init.body && !(init.body instanceof FormData) && !headers.has('content-type')) {
32
+ headers.set('content-type', 'application/json');
33
+ }
34
+ const response = await fetch(path, {
35
+ credentials: 'same-origin',
36
+ cache: 'no-store',
37
+ ...init,
38
+ headers,
39
+ });
40
+ const body = (await response.json().catch(() => ({}))) as Json;
41
+ if (!response.ok || body?.ok === false) {
42
+ throw new Error(body?.error || body?.detail || `HTTP ${response.status}`);
43
+ }
44
+ return body as T;
45
+ }
46
+
47
+ function parseFields(raw: unknown): Record<string, any> {
48
+ if (!raw) return {};
49
+ if (typeof raw === 'object' && !Array.isArray(raw)) return { ...(raw as object) };
50
+ if (typeof raw === 'string') {
51
+ try {
52
+ const parsed = JSON.parse(raw);
53
+ return parsed && typeof parsed === 'object' && !Array.isArray(parsed) ? parsed : {};
54
+ } catch {
55
+ return {};
56
+ }
57
+ }
58
+ return {};
59
+ }
60
+
61
+ function mapStatus(row: Json): CmsEditorPage['status'] {
62
+ const status = String(row.status || '').toLowerCase();
63
+ if (status === 'live' || status === 'published' || row.published === 1 || row.published === true) {
64
+ return 'live';
65
+ }
66
+ if (status === 'new') return 'new';
67
+ return 'draft';
68
+ }
69
+
70
+ function mapZone(row: Json): CmsEditorSection['zone'] {
71
+ const zone = String(row.zone || row.section_zone || '').toUpperCase();
72
+ if (zone === 'HEADER' || zone === 'FOOTER' || zone === 'TEMPLATE') return zone;
73
+ const type = String(row.section_type || row.type || '').toLowerCase();
74
+ if (type.includes('header') || type.includes('nav')) return 'HEADER';
75
+ if (type.includes('footer')) return 'FOOTER';
76
+ return 'BODY';
77
+ }
78
+
79
+ function mapBlock(row: Json, sectionId: string): CmsEditorBlock {
80
+ return {
81
+ id: String(row.id),
82
+ sectionId,
83
+ type: String(row.block_type || row.component_type || row.type || 'text'),
84
+ visible: row.is_visible !== 0 && row.is_visible !== false && row.visible !== false,
85
+ data: parseFields(row.block_data ?? row.component_data ?? row.data),
86
+ sortOrder: Number(row.sort_order || 0) || 0,
87
+ };
88
+ }
89
+
90
+ function mapSection(row: Json, blocks: CmsEditorBlock[] = []): CmsEditorSection {
91
+ const fields = parseFields(row.section_data ?? row.data ?? row.fields);
92
+ const css = parseFields(fields.css_override ?? row.css);
93
+ return {
94
+ id: String(row.id),
95
+ name: String(row.section_name || row.name || row.section_type || 'Section'),
96
+ type: String(row.section_type || row.type || 'section'),
97
+ zone: mapZone(row),
98
+ visible: row.is_visible !== 0 && row.is_visible !== false && row.visible !== false,
99
+ color: String(fields.color || row.color || '#111115'),
100
+ fields,
101
+ css,
102
+ blocks,
103
+ };
104
+ }
105
+
106
+ function mapPage(row: Json, sections: CmsEditorSection[] = []): CmsEditorPage {
107
+ const slugRaw = String(row.slug || row.route_path || row.path || '/').trim() || '/';
108
+ const slug = slugRaw.startsWith('/') ? slugRaw : `/${slugRaw}`;
109
+ return {
110
+ id: String(row.id),
111
+ title: String(row.title || 'Untitled'),
112
+ slug,
113
+ status: mapStatus(row),
114
+ type: String(row.page_type || row.type || 'Interior'),
115
+ parent: row.parent_id ? String(row.parent_id) : undefined,
116
+ sections,
117
+ metaTitle: String(row.meta_title || row.title || ''),
118
+ metaDescription: String(row.meta_description || ''),
119
+ };
120
+ }
121
+
122
+ function initialsFrom(name: string) {
123
+ return (
124
+ name
125
+ .split(/\s+/)
126
+ .filter(Boolean)
127
+ .slice(0, 2)
128
+ .map((part) => part[0])
129
+ .join('')
130
+ .toUpperCase() || 'CMS'
131
+ );
132
+ }
133
+
134
+ function siteRecordFromBootstrap(siteId: string, boot: Json): CmsSiteRecord {
135
+ const name = String(boot.tenant?.name || boot.workspace_label || siteId);
136
+ return {
137
+ id: siteId,
138
+ name,
139
+ initials: initialsFrom(name),
140
+ domain: String(boot.tenant?.domain || boot.public_domain || ''),
141
+ edited: 'synced',
142
+ color: String(boot.tenant?.primary_color || '#1e6a6f'),
143
+ theme: {
144
+ cssVars: parseFields(boot.active_theme?.css_vars || {}),
145
+ },
146
+ schemas: boot.schemas
147
+ ? {
148
+ protocol_version: Number(boot.schemas.protocol_version || 1),
149
+ sections: Array.isArray(boot.schemas.sections) ? boot.schemas.sections : [],
150
+ blocks: Array.isArray(boot.schemas.blocks) ? boot.schemas.blocks : [],
151
+ }
152
+ : undefined,
153
+ };
154
+ }
155
+
156
+ function hydratePages(boot: Json): CmsEditorPage[] {
157
+ const pages = Array.isArray(boot.pages) ? boot.pages : [];
158
+ const sectionsByPage = boot.sections_by_page || {};
159
+ const blocksBySection = boot.blocks_by_section || boot.components_by_section || {};
160
+
161
+ return pages.map((pageRow: Json) => {
162
+ const sectionRows = Array.isArray(sectionsByPage[pageRow.id])
163
+ ? sectionsByPage[pageRow.id]
164
+ : [];
165
+ const sections = sectionRows.map((sectionRow: Json) => {
166
+ const blockRows = Array.isArray(blocksBySection[sectionRow.id])
167
+ ? blocksBySection[sectionRow.id]
168
+ : [];
169
+ return mapSection(
170
+ sectionRow,
171
+ blockRows.map((blockRow: Json) => mapBlock(blockRow, String(sectionRow.id))),
172
+ );
173
+ });
174
+ return mapPage(pageRow, sections);
175
+ });
176
+ }
177
+
178
+ /**
179
+ * Hosted HTTP adapter bound to Worker `/api/cms/*` for a single site id (project_slug).
180
+ */
181
+ export class HttpCmsAdapter implements CmsEditorAdapter {
182
+ readonly temporary = false;
183
+ private readonly base: string;
184
+ private readonly knownSites: Map<string, CmsSiteRecord>;
185
+
186
+ constructor(
187
+ options: {
188
+ base?: string;
189
+ sites?: Array<{ id?: string; slug?: string; name?: string; domain?: string }>;
190
+ } = {},
191
+ ) {
192
+ this.base = String(options.base || '').replace(/\/$/, '');
193
+ this.knownSites = new Map();
194
+ for (const site of options.sites || []) {
195
+ const id = String(site.id || site.slug || '').trim();
196
+ if (!id) continue;
197
+ const name = String(site.name || id);
198
+ this.knownSites.set(id, {
199
+ id,
200
+ name,
201
+ initials: initialsFrom(name),
202
+ domain: String(site.domain || ''),
203
+ edited: 'catalog',
204
+ color: '#1e6a6f',
205
+ });
206
+ }
207
+ }
208
+
209
+ private url(path: string) {
210
+ return `${this.base}${path}`;
211
+ }
212
+
213
+ async listSites(): Promise<CmsSiteRecord[]> {
214
+ if (this.knownSites.size) return [...this.knownSites.values()].map((s) => structuredClone(s));
215
+ // 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')}`));
217
+ const record = siteRecordFromBootstrap('agentsam-sdk', boot);
218
+ this.knownSites.set(record.id, record);
219
+ return [structuredClone(record)];
220
+ }
221
+
222
+ async getSite(siteId: string): Promise<CmsSiteRecord> {
223
+ const boot = await api<Json>(this.url(`/api/cms/bootstrap?${siteQuery(siteId)}`));
224
+ const record = siteRecordFromBootstrap(siteId, boot);
225
+ this.knownSites.set(siteId, record);
226
+ return structuredClone(record);
227
+ }
228
+
229
+ async createSite(_input: CmsSiteCreateInput): Promise<CmsSiteRecord> {
230
+ throw new CmsCapabilityError(
231
+ 'createSite',
232
+ 'Hosted site creation uses the deploy wizard / projects API — not inline CMS create yet.',
233
+ 'cms_capability_unsupported',
234
+ );
235
+ }
236
+
237
+ async updateSite(siteId: string, patch: CmsSiteUpdatePatch): Promise<CmsSiteRecord> {
238
+ const current = await this.getSite(siteId);
239
+ if (patch.theme?.cssVars) {
240
+ await api(this.url(`/api/cms/theme-vars?${siteQuery(siteId)}`), {
241
+ method: 'PATCH',
242
+ body: JSON.stringify({ project_slug: siteId, vars: patch.theme.cssVars }),
243
+ });
244
+ }
245
+ const next = { ...current, ...patch, id: siteId, edited: 'just now' };
246
+ this.knownSites.set(siteId, next);
247
+ return structuredClone(next);
248
+ }
249
+
250
+ async deleteSite(_siteId: string): Promise<void> {
251
+ throw new CmsCapabilityError('deleteSite', 'Hosted site delete is not enabled', 'cms_capability_unsupported');
252
+ }
253
+
254
+ async loadSite(siteId: string): Promise<CmsEditorSite> {
255
+ const boot = await api<Json>(this.url(`/api/cms/bootstrap?${siteQuery(siteId)}`));
256
+ const meta = siteRecordFromBootstrap(siteId, boot);
257
+ this.knownSites.set(siteId, meta);
258
+ return {
259
+ ...meta,
260
+ pages: hydratePages(boot),
261
+ };
262
+ }
263
+
264
+ async listPages(siteId: string): Promise<CmsEditorPage[]> {
265
+ const site = await this.loadSite(siteId);
266
+ return site.pages;
267
+ }
268
+
269
+ async getPage(pageId: string): Promise<CmsEditorPage> {
270
+ // Worker page GET requires site slug — resolve via known sites / bootstrap scan.
271
+ for (const siteId of this.knownSites.keys()) {
272
+ try {
273
+ const body = await api<Json>(
274
+ this.url(`/api/cms/pages/${encodeURIComponent(pageId)}?${siteQuery(siteId)}`),
275
+ );
276
+ const sections = Array.isArray(body.sections)
277
+ ? body.sections.map((row: Json) => mapSection(row, []))
278
+ : [];
279
+ // Hydrate blocks via bootstrap for completeness when section list is bare.
280
+ if (!sections.some((s) => s.blocks.length)) {
281
+ const full = await this.loadSite(siteId);
282
+ const hit = full.pages.find((p) => p.id === pageId);
283
+ if (hit) return structuredClone(hit);
284
+ }
285
+ return mapPage(body.page || { id: pageId }, sections);
286
+ } catch {
287
+ // try next site
288
+ }
289
+ }
290
+ // Last resort: agentsam-sdk
291
+ const full = await this.loadSite('agentsam-sdk');
292
+ const hit = full.pages.find((p) => p.id === pageId);
293
+ if (!hit) {
294
+ throw new CmsCapabilityError('getPage', `page_not_found:${pageId}`, 'cms_source_not_found');
295
+ }
296
+ return structuredClone(hit);
297
+ }
298
+
299
+ async createPage(
300
+ siteId: string,
301
+ input: Partial<CmsEditorPage> & { title: string; slug: string },
302
+ ): Promise<CmsEditorPage> {
303
+ const slug = input.slug.replace(/^\/+/, '');
304
+ const body = await api<Json>(this.url(`/api/cms/pages?${siteQuery(siteId)}`), {
305
+ method: 'POST',
306
+ body: JSON.stringify({
307
+ project_id: siteId,
308
+ project_slug: siteId,
309
+ title: input.title || 'Untitled',
310
+ slug,
311
+ route_path: `/${slug}`,
312
+ page_type: input.type || 'interior',
313
+ status: 'draft',
314
+ }),
315
+ });
316
+ return mapPage(body.page || body, []);
317
+ }
318
+
319
+ async updatePage(pageId: string, patch: Partial<CmsEditorPage>): Promise<CmsEditorPage> {
320
+ const siteId = await this.findPageSiteId(pageId);
321
+ const body = await api<Json>(
322
+ this.url(`/api/cms/pages/${encodeURIComponent(pageId)}?${siteQuery(siteId)}`),
323
+ {
324
+ method: 'PUT',
325
+ body: JSON.stringify({
326
+ title: patch.title,
327
+ slug: patch.slug?.replace(/^\/+/, ''),
328
+ route_path: patch.slug,
329
+ page_type: patch.type,
330
+ status: patch.status,
331
+ meta_title: patch.metaTitle,
332
+ meta_description: patch.metaDescription,
333
+ }),
334
+ },
335
+ );
336
+ return mapPage(body.page || body, patch.sections || []);
337
+ }
338
+
339
+ async deletePage(_pageId: string): Promise<void> {
340
+ throw new CmsCapabilityError('deletePage', 'Hosted page delete not enabled yet', 'cms_capability_unsupported');
341
+ }
342
+
343
+ async listSections(pageId: string): Promise<CmsEditorSection[]> {
344
+ const page = await this.getPage(pageId);
345
+ return page.sections;
346
+ }
347
+
348
+ async getSection(sectionId: string): Promise<CmsEditorSection> {
349
+ const site = await this.loadSite(await this.guessSiteId());
350
+ for (const page of site.pages) {
351
+ const section = page.sections.find((s) => s.id === sectionId);
352
+ if (section) return structuredClone(section);
353
+ }
354
+ throw new CmsCapabilityError('getSection', `section_not_found:${sectionId}`, 'cms_source_not_found');
355
+ }
356
+
357
+ async createSection(
358
+ pageId: string,
359
+ input: Partial<CmsEditorSection> & { name: string },
360
+ ): Promise<CmsEditorSection> {
361
+ const siteId = await this.findPageSiteId(pageId);
362
+ const body = await api<Json>(this.url(`/api/cms/sections?${siteQuery(siteId)}`), {
363
+ method: 'POST',
364
+ body: JSON.stringify({
365
+ page_id: pageId,
366
+ section_type: input.type || 'section',
367
+ section_name: input.name,
368
+ section_data: input.fields || {},
369
+ sort_order: 0,
370
+ }),
371
+ });
372
+ return mapSection(body.section || body, []);
373
+ }
374
+
375
+ async updateSection(
376
+ sectionId: string,
377
+ patch: Partial<CmsEditorSection>,
378
+ ): Promise<CmsEditorSection> {
379
+ const siteId = await this.guessSiteId();
380
+ const body = await api<Json>(
381
+ this.url(`/api/cms/sections/${encodeURIComponent(sectionId)}?${siteQuery(siteId)}`),
382
+ {
383
+ method: 'PUT',
384
+ body: JSON.stringify({
385
+ section_name: patch.name,
386
+ section_data: patch.fields,
387
+ css: patch.css,
388
+ is_visible: patch.visible === false ? 0 : 1,
389
+ }),
390
+ },
391
+ );
392
+ return mapSection(body.section || body, patch.blocks || []);
393
+ }
394
+
395
+ async deleteSection(_sectionId: string): Promise<void> {
396
+ throw new CmsCapabilityError('deleteSection', 'Hosted section delete not enabled yet', 'cms_capability_unsupported');
397
+ }
398
+
399
+ async reorderSections(pageId: string, sectionIds: string[]): Promise<void> {
400
+ const siteId = await this.findPageSiteId(pageId);
401
+ await api(this.url(`/api/cms/sections/reorder?${siteQuery(siteId)}`), {
402
+ method: 'POST',
403
+ body: JSON.stringify({
404
+ page_id: pageId,
405
+ order: sectionIds.map((id, index) => ({ id, sort_order: (index + 1) * 10 })),
406
+ }),
407
+ });
408
+ }
409
+
410
+ async setSectionVisibility(sectionId: string, visible: boolean): Promise<void> {
411
+ const siteId = await this.guessSiteId();
412
+ await api(
413
+ this.url(`/api/cms/sections/${encodeURIComponent(sectionId)}/visibility?${siteQuery(siteId)}`),
414
+ {
415
+ method: 'POST',
416
+ body: JSON.stringify({ is_visible: visible ? 1 : 0 }),
417
+ },
418
+ );
419
+ }
420
+
421
+ async listBlocks(sectionId: string): Promise<CmsEditorBlock[]> {
422
+ const section = await this.getSection(sectionId);
423
+ return section.blocks;
424
+ }
425
+
426
+ async getBlock(blockId: string): Promise<CmsEditorBlock> {
427
+ const site = await this.loadSite(await this.guessSiteId());
428
+ for (const page of site.pages) {
429
+ for (const section of page.sections) {
430
+ const block = section.blocks.find((b) => b.id === blockId);
431
+ if (block) return structuredClone(block);
432
+ }
433
+ }
434
+ throw new CmsCapabilityError('getBlock', `block_not_found:${blockId}`, 'cms_source_not_found');
435
+ }
436
+
437
+ async createBlock(
438
+ sectionId: string,
439
+ input: Partial<CmsEditorBlock> & { type: string },
440
+ ): Promise<CmsEditorBlock> {
441
+ const siteId = await this.guessSiteId();
442
+ const body = await api<Json>(this.url(`/api/cms/blocks?${siteQuery(siteId)}`), {
443
+ method: 'POST',
444
+ body: JSON.stringify({
445
+ section_id: sectionId,
446
+ block_type: input.type,
447
+ type: input.type,
448
+ block_data: input.data || {},
449
+ sort_order: input.sortOrder ?? 10,
450
+ }),
451
+ });
452
+ return mapBlock(body.block || body.component || body, sectionId);
453
+ }
454
+
455
+ async updateBlock(blockId: string, patch: Partial<CmsEditorBlock>): Promise<CmsEditorBlock> {
456
+ const siteId = await this.guessSiteId();
457
+ const body = await api<Json>(
458
+ this.url(`/api/cms/blocks/${encodeURIComponent(blockId)}?${siteQuery(siteId)}`),
459
+ {
460
+ method: 'PUT',
461
+ body: JSON.stringify({
462
+ block_data: patch.data,
463
+ block_type: patch.type,
464
+ type: patch.type,
465
+ }),
466
+ },
467
+ );
468
+ return mapBlock(body.block || body.component || { id: blockId, ...patch }, patch.sectionId || '');
469
+ }
470
+
471
+ async deleteBlock(_blockId: string): Promise<void> {
472
+ throw new CmsCapabilityError('deleteBlock', 'Hosted block delete not enabled yet', 'cms_capability_unsupported');
473
+ }
474
+
475
+ async saveDraft(pageId: string, payload: unknown): Promise<CmsRevision> {
476
+ const siteId = await this.findPageSiteId(pageId);
477
+ 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
+ }),
488
+ });
489
+ }
490
+ }
491
+ // Mark page draft
492
+ await api(this.url(`/api/cms/pages/${encodeURIComponent(pageId)}?${siteQuery(siteId)}`), {
493
+ method: 'PUT',
494
+ body: JSON.stringify({ status: 'draft' }),
495
+ });
496
+ return {
497
+ id: `rev_${Date.now()}`,
498
+ pageId,
499
+ kind: 'draft',
500
+ createdAt: new Date().toISOString(),
501
+ snapshot: payload,
502
+ };
503
+ }
504
+
505
+ async getRevision(_revisionId: string): Promise<CmsRevision> {
506
+ throw new CmsCapabilityError('getRevision', 'revision history API not wired yet', 'cms_capability_unsupported');
507
+ }
508
+
509
+ async listRevisions(_pageId: string): Promise<CmsRevision[]> {
510
+ return [];
511
+ }
512
+
513
+ async restoreRevision(_pageId: string, _revisionId: string): Promise<CmsEditorPage> {
514
+ throw new CmsCapabilityError('restoreRevision', 'revision restore not wired yet', 'cms_capability_unsupported');
515
+ }
516
+
517
+ async previewDraft(pageId: string): Promise<{ previewUrl?: string; snapshot: unknown }> {
518
+ const siteId = await this.findPageSiteId(pageId);
519
+ const page = await this.getPage(pageId);
520
+ return {
521
+ previewUrl: `/api/cms/render-page?${siteQuery(siteId)}&page_id=${encodeURIComponent(pageId)}&mode=draft`,
522
+ snapshot: page,
523
+ };
524
+ }
525
+
526
+ async publish(pageId: string): Promise<CmsPublicationSnapshot> {
527
+ const siteId = await this.findPageSiteId(pageId);
528
+ const body = await api<Json>(
529
+ this.url(`/api/cms/pages/${encodeURIComponent(pageId)}/publish?${siteQuery(siteId)}`),
530
+ { method: 'POST', body: JSON.stringify({}) },
531
+ );
532
+ const page = mapPage(body.page || { id: pageId, slug: '/' }, []);
533
+ return {
534
+ publicationId: `pub_${pageId}`,
535
+ route: page.slug,
536
+ revision: 1,
537
+ theme: 'default',
538
+ sections: [],
539
+ publishedAt: new Date().toISOString(),
540
+ };
541
+ }
542
+
543
+ async getPublishedRevision(pageId: string): Promise<CmsPublicationSnapshot | null> {
544
+ try {
545
+ const page = await this.getPage(pageId);
546
+ if (page.status !== 'live') return null;
547
+ return {
548
+ publicationId: `pub_${pageId}`,
549
+ route: page.slug,
550
+ revision: 1,
551
+ theme: 'default',
552
+ sections: page.sections.map((section) => ({
553
+ type: section.type,
554
+ props: { ...section.fields, name: section.name, blocks: section.blocks },
555
+ })),
556
+ publishedAt: undefined,
557
+ };
558
+ } catch {
559
+ return null;
560
+ }
561
+ }
562
+
563
+ async listAssets(siteId: string): Promise<CmsAsset[]> {
564
+ const body = await api<Json>(this.url(`/api/cms/assets?${siteQuery(siteId)}`));
565
+ return (body.assets || []).map((row: Json) => ({
566
+ id: String(row.id),
567
+ name: String(row.original_filename || row.filename || row.id),
568
+ mimeType: row.mime_type ? String(row.mime_type) : undefined,
569
+ size: row.content_size_bytes != null ? Number(row.content_size_bytes) : undefined,
570
+ url: row.public_url ? String(row.public_url) : undefined,
571
+ key: String(row.id),
572
+ }));
573
+ }
574
+
575
+ async getAsset(assetId: string): Promise<CmsAsset> {
576
+ for (const siteId of this.knownSites.keys()) {
577
+ const assets = await this.listAssets(siteId);
578
+ const hit = assets.find((a) => a.id === assetId);
579
+ if (hit) return hit;
580
+ }
581
+ throw new CmsCapabilityError('getAsset', `asset_not_found:${assetId}`, 'cms_source_not_found');
582
+ }
583
+
584
+ async uploadAsset(
585
+ _siteId: string,
586
+ _file: Blob,
587
+ _meta?: { name?: string; metadata?: Record<string, unknown> },
588
+ ): Promise<CmsAsset> {
589
+ throw new CmsCapabilityError('uploadAsset', 'Hosted asset upload uses Media studio', 'cms_capability_unsupported');
590
+ }
591
+
592
+ async updateAsset(
593
+ _assetId: string,
594
+ _patch: Partial<Pick<CmsAsset, 'name' | 'metadata' | 'url' | 'key'>>,
595
+ ): Promise<CmsAsset> {
596
+ throw new CmsCapabilityError('updateAsset', 'Hosted asset update not enabled', 'cms_capability_unsupported');
597
+ }
598
+
599
+ async deleteAsset(_assetId: string): Promise<void> {
600
+ throw new CmsCapabilityError('deleteAsset', 'Hosted asset delete not enabled', 'cms_capability_unsupported');
601
+ }
602
+
603
+ private guessSiteId() {
604
+ const first = this.knownSites.keys().next().value;
605
+ return first || 'agentsam-sdk';
606
+ }
607
+
608
+ private async findPageSiteId(pageId: string): Promise<string> {
609
+ if (!this.knownSites.size) {
610
+ await this.listSites();
611
+ }
612
+ for (const siteId of this.knownSites.keys()) {
613
+ try {
614
+ const site = await this.loadSite(siteId);
615
+ if (site.pages.some((p) => p.id === pageId)) return siteId;
616
+ } catch {
617
+ // continue
618
+ }
619
+ }
620
+ return this.guessSiteId();
621
+ }
622
+ }
623
+
624
+ export function createHttpCmsAdapter(
625
+ options?: ConstructorParameters<typeof HttpCmsAdapter>[0],
626
+ ): HttpCmsAdapter {
627
+ return new HttpCmsAdapter(options);
628
+ }