@inneranimalmedia/agentsam-sdk 2.6.2 → 2.6.4

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 (661) hide show
  1. package/AGENTSAM.md +51 -1
  2. package/README.md +95 -0
  3. package/apps/README.md +34 -0
  4. package/apps/cad-creator/README.md +728 -0
  5. package/apps/cad-creator/shared/cad/package.json +19 -0
  6. package/apps/cad-creator/shared/cad/src/domain/operations.ts +7 -0
  7. package/apps/cad-creator/shared/cad/src/domain/project-contract.d.ts +3 -0
  8. package/apps/cad-creator/shared/cad/src/domain/project-contract.js +75 -0
  9. package/apps/cad-creator/shared/cad/src/domain/project-tools.d.ts +1 -0
  10. package/apps/cad-creator/shared/cad/src/domain/project-tools.js +24 -0
  11. package/apps/cad-creator/shared/cad/src/domain/validation.ts +191 -0
  12. package/apps/cad-creator/shared/cad/src/index.ts +4 -0
  13. package/apps/cad-creator/shared/cad/src/robotics/types.ts +232 -0
  14. package/apps/cad-creator/shared/cad/src/types.ts +507 -0
  15. package/apps/cad-creator/shared/cad/tsconfig.json +14 -0
  16. package/bin/agentsam +16 -1
  17. package/docs/AUTORAG.md +58 -0
  18. package/docs/BRAND_INTELLIGENCE.md +30 -0
  19. package/docs/CLI_SHELL.md +4 -2
  20. package/docs/CMS_CONTEXTUAL_COMPOSER.md +38 -0
  21. package/docs/MERKLE.md +4 -0
  22. package/docs/PROJECT_CONFIG.md +3 -0
  23. package/docs/REPOSITORY_KNOWLEDGE.md +2 -0
  24. package/docs/THEME_REFINERY.md +120 -0
  25. package/docs/architecture/AGENTSAM_DISTRIBUTION_OWNERSHIP.md +176 -0
  26. package/docs/architecture/AGENTSAM_GO_RUNTIME.md +282 -0
  27. package/docs/architecture/CODEBASEINDEX_GUIDED_PATH.md +202 -0
  28. package/docs/architecture/FS_E2E_CLOSURE_RECEIPT.md +59 -0
  29. package/docs/architecture/LOCAL_FS_AUTHORITY.md +38 -0
  30. package/docs/architecture/LOCAL_STUDIO_CLOUDFLARE_OAUTH.md +28 -0
  31. package/docs/architecture/PLAN_CLI_AND_LOCAL_STUDIO_DESKTOP.md +96 -0
  32. package/docs/architecture/PROVIDER-TOOLS-AND-COMPACTION.md +60 -0
  33. package/docs/architecture/SAM_ACTIVITY_RECOVERY_RECEIPT.md +39 -0
  34. package/docs/architecture/SAM_DECISION_WORK_RECEIPT.md +54 -0
  35. package/docs/architecture/SAM_KERNEL.md +181 -0
  36. package/docs/architecture/SAM_MACHINE_NORMALIZATION_PRECOMMIT_REPORT.md +208 -0
  37. package/docs/architecture/SLASH_SKILLS_PORTABLE.md +116 -0
  38. package/docs/architecture/STORAGE.md +87 -0
  39. package/docs/architecture/fs-e2e-receipt.latest.json +42 -0
  40. package/docs/architecture/previews/codebaseindex-guided-path/CODEBASEINDEX_GUIDED_PATH.md +202 -0
  41. package/docs/architecture/previews/codebaseindex-guided-path/index.html +321 -0
  42. package/docs/cad-project-tools.md +69 -0
  43. package/docs/cms-scaffolding-pattern-reference.md +73 -0
  44. package/docs/plans/AGENTSAM-INTERACTIVE-UI-REQUIREMENTS-codex-tui-20260919.md +113 -0
  45. package/docs/plans/AGENTSAM-INTERACTIVE-UI-REQUIREMENTS.md +85 -0
  46. package/docs/plans/AGENTSAM-MCP-CLIENT-2026-09-19.md +181 -0
  47. package/docs/plans/ASBD-PORTABLE-WORKGRAPH-UI-DEFERRED.md +34 -0
  48. package/docs/plans/ASTRA-BRIEF-2026-09-18.md +258 -0
  49. package/docs/plans/MULTI-AGENT-SPRINTS-2026-09-19.md +373 -0
  50. package/docs/plans/NEXT-AGENT-HANDOFF.md +167 -0
  51. package/docs/plans/RECONCILIATION-2026-09-19.md +178 -0
  52. package/docs/plugins.md +43 -0
  53. package/docs/tools/README.md +57 -0
  54. package/docs/tools/agent-and-orchestration.md +49 -0
  55. package/docs/tools/browser-and-research.md +46 -0
  56. package/docs/tools/cloudflare-platform.md +32 -0
  57. package/docs/tools/cms.md +25 -0
  58. package/docs/tools/communications.md +41 -0
  59. package/docs/tools/database-and-storage.md +62 -0
  60. package/docs/tools/design-and-media.md +64 -0
  61. package/docs/tools/filesystem-and-code.md +55 -0
  62. package/docs/tools/github.md +56 -0
  63. package/docs/tools/integrations-and-misc.md +16 -0
  64. package/docs/tools/memory.md +21 -0
  65. package/docs/tools/terminal-and-execution.md +29 -0
  66. package/docs/tools/tickets-and-platform.md +30 -0
  67. package/migrations/d1/0001_agentsam_plugin_runtime.sql +177 -0
  68. package/migrations/d1/0002_agentsam_ticket_ownership.sql +8 -0
  69. package/migrations/d1/0002_dynamic_model_policies.sql +23 -0
  70. package/migrations/d1/0003_expand_tool_handler_families.sql +18 -0
  71. package/migrations/d1/0004_project_aware_retrieval_lanes.sql +24 -0
  72. package/migrations/d1/0005_portable_knowledge_identity.sql +104 -0
  73. package/migrations/d1/0006_repair_ops_trail_account_scope.sql +14 -0
  74. package/migrations/d1/0007_repair_ops_trail_agent_run_account.sql +13 -0
  75. package/migrations/d1/0008_backfill_knowledge_run_legacy_tenant.sql +14 -0
  76. package/migrations/d1/0009_normalize_cloudflare_plugin_installations.sql +137 -0
  77. package/migrations/d1/0010_portable_tickets_memory.sql +140 -0
  78. package/migrations/d1/0011_agentsam_skill_v2.sql +185 -0
  79. package/migrations/d1/0011b_agentsam_skill_v2_cutover.sql +22 -0
  80. package/migrations/d1/0011c_agentsam_skill_v2_backfill.sql +76 -0
  81. package/migrations/d1/0011d_agentsam_skill_v2_retrieval_revisions.sql +50 -0
  82. package/migrations/d1/0012_agentsam_tools_required_seed.sql +67 -0
  83. package/migrations/d1/0013_identity_oauth_states.sql +15 -0
  84. package/migrations/d1/0014_auth_event_log.sql +20 -0
  85. package/migrations/d1/0015_identity_oauth_state_app_id.sql +3 -0
  86. package/migrations/d1/README_PORTABLE_CONTROL_PLANE.md +16 -0
  87. package/migrations/runtime/0001_cli_runtime.sql +67 -0
  88. package/migrations/runtime/0002_project_sessions.sql +15 -0
  89. package/migrations/runtime/0003_provider_continuations.sql +8 -0
  90. package/migrations/sqlite/agentsam_skill_retrieval.portable.sql +42 -0
  91. package/package.json +107 -12
  92. package/packages/agentsam-brand/README.md +21 -0
  93. package/packages/agentsam-brand/package.json +22 -0
  94. package/packages/agentsam-brand/src/contract.js +59 -0
  95. package/packages/agentsam-brand/src/extract.js +126 -0
  96. package/packages/agentsam-brand/src/goap-actions.js +73 -0
  97. package/packages/agentsam-brand/src/index.js +48 -0
  98. package/packages/agentsam-brand/src/plan.js +115 -0
  99. package/packages/agentsam-brand/src/resolve.js +139 -0
  100. package/packages/agentsam-brand/src/scan.js +250 -0
  101. package/packages/agentsam-brand/test/brand-scan.test.mjs +106 -0
  102. package/packages/agentsam-contracts/README.md +23 -0
  103. package/packages/agentsam-contracts/package.json +32 -0
  104. package/packages/agentsam-contracts/src/adapter.ts +25 -0
  105. package/packages/agentsam-contracts/src/agent.ts +35 -0
  106. package/packages/agentsam-contracts/src/artifacts.ts +33 -0
  107. package/packages/agentsam-contracts/src/authority.ts +29 -0
  108. package/packages/agentsam-contracts/src/context.ts +16 -0
  109. package/packages/agentsam-contracts/src/errors.ts +62 -0
  110. package/packages/agentsam-contracts/src/events.ts +47 -0
  111. package/packages/agentsam-contracts/src/execution.ts +50 -0
  112. package/packages/agentsam-contracts/src/hooks.ts +40 -0
  113. package/packages/agentsam-contracts/src/identity.ts +16 -0
  114. package/packages/agentsam-contracts/src/index.ts +14 -0
  115. package/packages/agentsam-contracts/src/models.ts +9 -0
  116. package/packages/agentsam-contracts/src/providers.ts +33 -0
  117. package/packages/agentsam-contracts/src/repository.ts +64 -0
  118. package/packages/agentsam-contracts/src/tools.ts +98 -0
  119. package/packages/agentsam-contracts/test/contracts.test.mjs +16 -0
  120. package/packages/agentsam-contracts/test/errors-catalog.test.mjs +25 -0
  121. package/packages/agentsam-contracts/test/repository.test.mjs +18 -0
  122. package/packages/agentsam-contracts/tsconfig.json +12 -0
  123. package/packages/agentsam-errors/package.json +17 -0
  124. package/packages/agentsam-errors/src/adapters/anthropic.js +15 -0
  125. package/packages/agentsam-errors/src/adapters/cad.js +109 -0
  126. package/packages/agentsam-errors/src/adapters/cloudflare.js +21 -0
  127. package/packages/agentsam-errors/src/adapters/cursor.js +4 -0
  128. package/packages/agentsam-errors/src/adapters/device.js +38 -0
  129. package/packages/agentsam-errors/src/adapters/docker.js +28 -0
  130. package/packages/agentsam-errors/src/adapters/gcp.js +14 -0
  131. package/packages/agentsam-errors/src/adapters/github.js +22 -0
  132. package/packages/agentsam-errors/src/adapters/google.js +17 -0
  133. package/packages/agentsam-errors/src/adapters/index.js +55 -0
  134. package/packages/agentsam-errors/src/adapters/internal.js +40 -0
  135. package/packages/agentsam-errors/src/adapters/oauth.js +24 -0
  136. package/packages/agentsam-errors/src/adapters/openai.js +17 -0
  137. package/packages/agentsam-errors/src/adapters/process.js +35 -0
  138. package/packages/agentsam-errors/src/adapters/provider.js +114 -0
  139. package/packages/agentsam-errors/src/envelope.js +239 -0
  140. package/packages/agentsam-errors/src/error.js +24 -0
  141. package/packages/agentsam-errors/src/fingerprint.js +35 -0
  142. package/packages/agentsam-errors/src/index.js +11 -0
  143. package/packages/agentsam-errors/src/normalize.js +30 -0
  144. package/packages/agentsam-errors/src/recovery.js +301 -0
  145. package/packages/agentsam-errors/src/redaction.js +52 -0
  146. package/packages/agentsam-errors/src/render.js +16 -0
  147. package/packages/agentsam-errors/src/retry.js +10 -0
  148. package/packages/agentsam-errors/src/transport.js +52 -0
  149. package/packages/agentsam-errors/src/vocabulary.js +320 -0
  150. package/packages/agentsam-errors/test/envelope.test.mjs +70 -0
  151. package/packages/agentsam-errors/test/providers.test.mjs +99 -0
  152. package/packages/agentsam-errors/test/redaction.test.mjs +21 -0
  153. package/packages/agentsam-errors/test/runtime-cad-device.test.mjs +76 -0
  154. package/packages/agentsam-errors/test/transport.test.mjs +46 -0
  155. package/packages/agentsam-knowledge/package.json +15 -0
  156. package/packages/agentsam-knowledge/src/autorag/index.js +64 -0
  157. package/packages/agentsam-knowledge/src/backends/index.js +26 -0
  158. package/packages/agentsam-knowledge/src/index.js +3 -0
  159. package/packages/agentsam-knowledge/src/providers/index.js +107 -0
  160. package/packages/agentsam-knowledge/test/autorag.test.mjs +42 -0
  161. package/packages/agentsam-nav/README.md +40 -0
  162. package/packages/agentsam-nav/dist/Nav.d.ts +43 -0
  163. package/packages/agentsam-nav/dist/NavCollapsible.d.ts +10 -0
  164. package/packages/agentsam-nav/dist/NavContent.d.ts +2 -0
  165. package/packages/agentsam-nav/dist/NavFooter.d.ts +2 -0
  166. package/packages/agentsam-nav/dist/NavGroup.d.ts +3 -0
  167. package/packages/agentsam-nav/dist/NavHeader.d.ts +2 -0
  168. package/packages/agentsam-nav/dist/NavMenu.d.ts +22 -0
  169. package/packages/agentsam-nav/dist/NavProvider.d.ts +35 -0
  170. package/packages/agentsam-nav/dist/NavTrigger.d.ts +2 -0
  171. package/packages/agentsam-nav/dist/Surfaces.d.ts +41 -0
  172. package/packages/agentsam-nav/dist/browser.d.ts +11 -0
  173. package/packages/agentsam-nav/dist/browser.global.js +132 -0
  174. package/packages/agentsam-nav/dist/browser.js +613 -0
  175. package/packages/agentsam-nav/dist/contracts.d.ts +76 -0
  176. package/packages/agentsam-nav/dist/index.d.ts +11 -0
  177. package/packages/agentsam-nav/dist/index.js +614 -0
  178. package/packages/agentsam-nav/dist/legacy.css +83 -0
  179. package/packages/agentsam-nav/dist/shell.css +113 -0
  180. package/packages/agentsam-nav/dist/theme.css +113 -0
  181. package/packages/agentsam-nav/dist/utils.d.ts +1 -0
  182. package/packages/agentsam-nav/package.json +43 -0
  183. package/packages/agentsam-queue-control/README.md +107 -0
  184. package/packages/agentsam-queue-control/package.json +31 -0
  185. package/packages/agentsam-queue-control/schemas/job-envelope.schema.json +56 -0
  186. package/packages/agentsam-queue-control/src/adapters/cloudflare.js +152 -0
  187. package/packages/agentsam-queue-control/src/adapters/memory.js +38 -0
  188. package/packages/agentsam-queue-control/src/contracts.js +130 -0
  189. package/packages/agentsam-queue-control/src/control-plane.js +141 -0
  190. package/packages/agentsam-queue-control/src/dispatch.js +43 -0
  191. package/packages/agentsam-queue-control/src/index.js +7 -0
  192. package/packages/agentsam-queue-control/src/policy.js +88 -0
  193. package/packages/agentsam-queue-control/src/topology.js +66 -0
  194. package/packages/agentsam-queue-control/test/queue-control.test.mjs +100 -0
  195. package/packages/agentsam-repository/src/goap.js +718 -0
  196. package/packages/agentsam-repository/src/goap.js.bak-20260922011251 +670 -0
  197. package/packages/agentsam-repository/src/index.js +5 -0
  198. package/packages/agentsam-repository/src/merkle/cloudflare-persistence.js +2 -2
  199. package/packages/agentsam-repository/src/tickets.js +184 -0
  200. package/packages/agentsam-repository/src/work-tracking.js +199 -0
  201. package/packages/agentsam-repository/src/workspace-state.js +176 -0
  202. package/packages/agentsam-repository/test/goap-tickets-workspace-state.test.mjs +152 -0
  203. package/packages/connectors/cloudflare/src/index.js +297 -15
  204. package/packages/connectors/cloudflare/src/owner.js +43 -40
  205. package/packages/connectors/cloudflare/src/routes.js +176 -26
  206. package/packages/connectors/cloudflare/tests/connector.test.mjs +137 -2
  207. package/packages/heuristic-theme/README.md +11 -0
  208. package/packages/heuristic-theme/package.json +25 -0
  209. package/packages/heuristic-theme/src/index.js +2 -0
  210. package/packages/heuristic-theme/src/registry.js +36 -0
  211. package/packages/heuristic-theme/src/theme.js +41 -0
  212. package/packages/heuristic-theme/test/theme.test.mjs +26 -0
  213. package/packages/identity/.agentsam/features/oauth-login-portal/agentsam.feature.json +64 -0
  214. package/packages/identity/.agentsam/features/oauth-login-portal/providers.json +96 -0
  215. package/packages/identity/.agentsam/features/oauth-login-portal/resources.json +47 -0
  216. package/packages/identity/.agentsam/features/oauth-login-portal/routes.json +83 -0
  217. package/packages/identity/.agentsam/features/oauth-login-portal/ui.json +35 -0
  218. package/packages/identity/docs/PORTABLE_IDENTITY_ARCHITECTURE.md +50 -0
  219. package/packages/identity/migrations/D1_SCHEMA_MAPPING.md +31 -0
  220. package/packages/identity/migrations/sqlite/001_identity_core.sql +99 -0
  221. package/packages/identity/migrations/sqlite/002_identity_oauth_client.sql +38 -0
  222. package/packages/identity/migrations/sqlite/003_identity_oauth_server.sql +64 -0
  223. package/packages/identity/package.json +4 -3
  224. package/packages/identity/src/adapters/cloudflare-d1/ids.js +4 -0
  225. package/packages/identity/src/adapters/cloudflare-d1/index.js +156 -18
  226. package/packages/identity/src/adapters/sqlite/index.js +319 -0
  227. package/packages/identity/src/app/verify-app.js +95 -0
  228. package/packages/identity/src/contracts/identity-store.js +115 -0
  229. package/packages/identity/src/contracts/provider.js +3 -2
  230. package/packages/identity/src/contracts/route-ids.js +30 -0
  231. package/packages/identity/src/contracts/route-projection.js +218 -0
  232. package/packages/identity/src/contracts/routes.js +11 -0
  233. package/packages/identity/src/core/browser-paths.js +4 -5
  234. package/packages/identity/src/core/constants.js +13 -8
  235. package/packages/identity/src/core/session-policy.js +32 -0
  236. package/packages/identity/src/frontend/auth-portal/pages/login.html +16 -9
  237. package/packages/identity/src/frontend/auth-portal/pages/reset.html +3 -3
  238. package/packages/identity/src/frontend/auth-portal/pages/signup.html +3 -3
  239. package/packages/identity/src/frontend/auth-portal/preview/dashboard-stub.html +1 -1
  240. package/packages/identity/src/index.js +27 -0
  241. package/packages/identity/src/oauth/README.md +10 -4
  242. package/packages/identity/src/oauth/credentials.js +31 -11
  243. package/packages/identity/src/oauth/finalize-inbound.js +1 -1
  244. package/packages/identity/src/oauth/iam-platform.js +13 -12
  245. package/packages/identity/src/oauth/redirect-paths.js +27 -36
  246. package/packages/identity/src/providers/cloudflare/index.js +19 -0
  247. package/packages/identity/src/providers/cloudflare/mapper.js +21 -0
  248. package/packages/identity/src/providers/cloudflare/oauth.js +48 -0
  249. package/packages/identity/src/providers/cloudflare/profile.js +28 -0
  250. package/packages/identity/src/providers/index.js +18 -2
  251. package/packages/identity/src/server/identity-service.js +35 -8
  252. package/packages/identity/src/server/mount-policy.js +30 -0
  253. package/packages/identity/src/server/post-auth.js +79 -0
  254. package/packages/identity/src/server/worker-router.js +153 -66
  255. package/packages/identity/tests/finalize-inbound-oauth.test.mjs +6 -6
  256. package/packages/identity/tests/iam-provider.test.mjs +1 -1
  257. package/packages/identity/tests/identity-service.test.mjs +47 -1
  258. package/packages/identity/tests/oauth-credentials.test.mjs +3 -1
  259. package/packages/identity/tests/portable-identity-architecture.test.mjs +157 -0
  260. package/packages/identity/tests/session-routes-policy.test.mjs +21 -0
  261. package/packages/providers/completeful/README.md +38 -0
  262. package/packages/providers/completeful/package.json +29 -0
  263. package/packages/providers/completeful/src/client.js +162 -0
  264. package/packages/providers/completeful/src/events.js +49 -0
  265. package/packages/providers/completeful/src/index.js +22 -0
  266. package/packages/providers/completeful/src/tools.js +579 -0
  267. package/packages/providers/completeful/src/webhooks.js +55 -0
  268. package/packages/providers/completeful/test/provider.test.mjs +196 -0
  269. package/packages/theme-church-site/README.md +10 -0
  270. package/packages/theme-church-site/package.json +31 -0
  271. package/packages/theme-church-site/src/harvest.json +14 -0
  272. package/packages/theme-church-site/src/index.js +85 -0
  273. package/packages/theme-church-site/test/theme.test.mjs +19 -0
  274. package/packages/theme-companions-site/README.md +10 -0
  275. package/packages/theme-companions-site/package.json +31 -0
  276. package/packages/theme-companions-site/src/harvest.json +12 -0
  277. package/packages/theme-companions-site/src/index.js +83 -0
  278. package/packages/theme-companions-site/test/theme.test.mjs +19 -0
  279. package/packages/theme-floors-site/README.md +10 -0
  280. package/packages/theme-floors-site/package.json +31 -0
  281. package/packages/theme-floors-site/src/harvest.json +14 -0
  282. package/packages/theme-floors-site/src/index.js +83 -0
  283. package/packages/theme-floors-site/test/theme.test.mjs +19 -0
  284. package/packages/theme-fuelnfree-site/README.md +10 -0
  285. package/packages/theme-fuelnfree-site/package.json +31 -0
  286. package/packages/theme-fuelnfree-site/src/harvest.json +13 -0
  287. package/packages/theme-fuelnfree-site/src/index.js +82 -0
  288. package/packages/theme-fuelnfree-site/test/theme.test.mjs +19 -0
  289. package/packages/theme-handyman-site/README.md +10 -0
  290. package/packages/theme-handyman-site/package.json +31 -0
  291. package/packages/theme-handyman-site/src/harvest.json +10 -0
  292. package/packages/theme-handyman-site/src/index.js +84 -0
  293. package/packages/theme-handyman-site/test/theme.test.mjs +19 -0
  294. package/packages/theme-insurance-site/README.md +10 -0
  295. package/packages/theme-insurance-site/package.json +31 -0
  296. package/packages/theme-insurance-site/src/harvest.json +10 -0
  297. package/packages/theme-insurance-site/src/index.js +84 -0
  298. package/packages/theme-insurance-site/test/theme.test.mjs +19 -0
  299. package/packages/theme-shinshu-site/README.md +10 -0
  300. package/packages/theme-shinshu-site/package.json +31 -0
  301. package/packages/theme-shinshu-site/src/harvest.json +12 -0
  302. package/packages/theme-shinshu-site/src/index.js +84 -0
  303. package/packages/theme-shinshu-site/test/theme.test.mjs +19 -0
  304. package/packages/work-graph/README.md +49 -0
  305. package/packages/work-graph/package.json +19 -0
  306. package/packages/work-graph/prototype/README.md +32 -0
  307. package/packages/work-graph/prototype/data/demo-workgraph.js +47 -0
  308. package/packages/work-graph/prototype/renderers/timeline-model.js +21 -0
  309. package/packages/work-graph/prototype/renderers/workgraph-runtime.js +38 -0
  310. package/packages/work-graph/prototype-gnantt.html +655 -0
  311. package/packages/work-graph/src/adapters/business/projects.js +23 -0
  312. package/packages/work-graph/src/adapters/engineering/git.js +22 -0
  313. package/packages/work-graph/src/adapters/engineering/mcp.js +22 -0
  314. package/packages/work-graph/src/index.js +76 -0
  315. package/packages/work-graph/src/renderers/gantt-model.js +11 -0
  316. package/packages/work-graph/src/renderers/timeline.js +16 -0
  317. package/packages/work-graph/test/work-graph.test.mjs +37 -0
  318. package/protocol/README.md +12 -0
  319. package/protocol/apps/agentsam.app.v1.schema.json +51 -0
  320. package/protocol/brand/brandpack.v1.schema.json +43 -0
  321. package/protocol/capabilities/cloudflare-cpu-audit-input.schema.json +30 -6
  322. package/protocol/capabilities/cloudflare-cpu-profile-input.schema.json +18 -4
  323. package/protocol/capabilities/cloudflare-wrangler-native-input.schema.json +59 -10
  324. package/protocol/capabilities/knowledge-search-input.schema.json +35 -0
  325. package/protocol/capabilities/manifest.json +163 -1
  326. package/protocol/capabilities/repository-audit-input.schema.json +39 -6
  327. package/protocol/capabilities/repository-snapshot-input.schema.json +15 -3
  328. package/protocol/capabilities/terminal-exec-input.schema.json +55 -0
  329. package/protocol/commerce/catalog.v1.json +50 -0
  330. package/protocol/credentials/issue.v1.schema.json +38 -0
  331. package/protocol/database/connection.v1.schema.json +41 -0
  332. package/protocol/embeddings/embedding-profile.v1.schema.json +20 -0
  333. package/protocol/errors/error-catalog.json +164 -0
  334. package/protocol/errors/error-envelope.schema.json +678 -0
  335. package/protocol/errors/recovery.v1.schema.json +50 -0
  336. package/protocol/features/README.md +57 -0
  337. package/protocol/features/agentsam.feature.v1.schema.json +290 -0
  338. package/protocol/features/catalog.json +65 -0
  339. package/protocol/features/examples/provider-resend.feature.json +17 -0
  340. package/protocol/go/agentsam-go-runtime.v1.json +17 -0
  341. package/protocol/knowledge/LIFECYCLE.md +140 -0
  342. package/protocol/knowledge/README.md +4 -0
  343. package/protocol/presets/catalog.json +128 -19
  344. package/protocol/rpc/v1/errors.proto +24 -0
  345. package/protocol/runtime/workspace-fs.v1.schema.json +71 -0
  346. package/protocol/sam/activity.v1.schema.json +48 -0
  347. package/protocol/sam/answer.v1.schema.json +35 -0
  348. package/protocol/sam/calibration.v1.schema.json +21 -0
  349. package/protocol/sam/decision-receipt.v1.schema.json +29 -0
  350. package/protocol/sam/evaluation.v1.schema.json +19 -0
  351. package/protocol/sam/operation.schema.json +66 -0
  352. package/protocol/sam/outcome.v1.schema.json +36 -0
  353. package/protocol/sam/question.v1.schema.json +26 -0
  354. package/protocol/sam/registry.seed.json +153 -0
  355. package/protocol/sam/result.schema.json +53 -0
  356. package/protocol/sam/state.v1.schema.json +23 -0
  357. package/protocol/skills/agentsam.interaction.v1.schema.json +50 -0
  358. package/protocol/skills/agentsam.skill.v1.schema.json +57 -0
  359. package/protocol/theme-refinery/d1-reconciliation.md +48 -0
  360. package/protocol/theme-refinery/product-metadata.schema.json +27 -0
  361. package/protocol/theme-refinery/receipts/products-registry-batch-20260924.json +318 -0
  362. package/protocol/theme-refinery/receipts/theme-harvest-20260924.json +472 -0
  363. package/protocol/theme-refinery/reconciliation-receipt.schema.json +83 -0
  364. package/protocol/ui/icon-registry.mjs +226 -0
  365. package/protocol/ui/icon.v1.schema.json +51 -0
  366. package/services/cad/server.py +249 -2
  367. package/skills/README.md +22 -9
  368. package/skills/agentsam-codebaseindex/SKILL.md +225 -0
  369. package/skills/catalog.json +14 -0
  370. package/src/agent/capability-adapter.js +15 -5
  371. package/src/agent/index.js +2 -1
  372. package/src/agent/model-turn.js +51 -0
  373. package/src/agent/responses-runner.js +304 -38
  374. package/src/capabilities/index.js +1 -0
  375. package/src/capabilities/terminal-exec.js +78 -0
  376. package/src/cli/command-catalog.js +130 -0
  377. package/src/cli/dispatch.js +48 -0
  378. package/src/cli.js +160 -10
  379. package/src/cloudflare/index.js +6 -0
  380. package/src/cloudflare/runtime-status.js +393 -0
  381. package/src/cloudflare/wrangler.js +17 -1
  382. package/src/commands/api-key.js +244 -0
  383. package/src/commands/app.js +138 -0
  384. package/src/commands/autorag.js +77 -0
  385. package/src/commands/brand.js +291 -0
  386. package/src/commands/cad.js +1 -0
  387. package/src/commands/codebaseindex.js +688 -0
  388. package/src/commands/connections.js +126 -29
  389. package/src/commands/context-economics.js +8 -0
  390. package/src/commands/db.js +7 -0
  391. package/src/commands/env.js +155 -27
  392. package/src/commands/eval.js +209 -14
  393. package/src/commands/go.js +678 -0
  394. package/src/commands/goap.js +176 -0
  395. package/src/commands/identity-init.js +27 -3
  396. package/src/commands/identity-protocol.js +195 -0
  397. package/src/commands/interaction-clack.js +115 -0
  398. package/src/commands/knowledge.js +64 -5
  399. package/src/commands/mcp.js +341 -0
  400. package/src/commands/merkle-persist.js +3 -1
  401. package/src/commands/merkle.js +18 -3
  402. package/src/commands/models.js +110 -24
  403. package/src/commands/plugins.js +175 -0
  404. package/src/commands/preferences.js +28 -8
  405. package/src/commands/product.js +53 -10
  406. package/src/commands/providers.js +173 -44
  407. package/src/commands/resume.js +9 -5
  408. package/src/commands/runtime-status.js +154 -0
  409. package/src/commands/shell.js +508 -56
  410. package/src/commands/skill.js +248 -0
  411. package/src/commands/skills.js +1 -1
  412. package/src/commands/start-local.js +4 -0
  413. package/src/commands/status.js +82 -7
  414. package/src/commands/tunnel.js +228 -195
  415. package/src/commands/whoami.js +156 -12
  416. package/src/context/budget.js +6 -0
  417. package/src/context/index.js +2 -1
  418. package/src/context/project-card.js +75 -0
  419. package/src/errors/contract.js +34 -211
  420. package/src/errors/diagnostic.js +95 -51
  421. package/src/errors/index.js +6 -13
  422. package/src/eval/index.js +6 -0
  423. package/src/eval/live.js +439 -0
  424. package/src/features/resolve.js +242 -0
  425. package/src/go/build.js +298 -0
  426. package/src/go/cloudflare.js +608 -0
  427. package/src/go/container.js +120 -0
  428. package/src/go/contract.js +144 -0
  429. package/src/go/discover.js +212 -0
  430. package/src/go/index.js +25 -0
  431. package/src/go/native-probe-runner.mjs +119 -0
  432. package/src/go/official-registry.js +280 -0
  433. package/src/go/official-release.js +10 -0
  434. package/src/go/receipts.js +144 -0
  435. package/src/go/verify.js +38 -0
  436. package/src/index.js +127 -1
  437. package/src/indexing/ingest/discover-models.js +298 -0
  438. package/src/indexing/ingest/inventory.js +243 -0
  439. package/src/indexing/ingest/job-graph.js +181 -0
  440. package/src/indexing/ingest/materials.js +210 -0
  441. package/src/knowledge/config.js +13 -5
  442. package/src/knowledge/engine.js +23 -8
  443. package/src/knowledge/index.js +1 -0
  444. package/src/knowledge/lane-registry.js +46 -0
  445. package/src/knowledge/providers/gemini.js +48 -8
  446. package/src/knowledge/service/client.js +13 -1
  447. package/src/knowledge/service/grpc-codec.js +156 -53
  448. package/src/knowledge/service/job-engine.js +133 -11
  449. package/src/knowledge/service/job-worker.js +34 -5
  450. package/src/knowledge/service/server.js +10 -1
  451. package/src/knowledge/store-discovery.js +77 -0
  452. package/src/lib/account-session.js +8 -2
  453. package/src/lib/agent-instructions.js +3 -0
  454. package/src/lib/auth.js +7 -3
  455. package/src/lib/cad/blender.js +42 -3
  456. package/src/lib/cad/d1-project-store.js +43 -0
  457. package/src/lib/cad/discovery.js +616 -0
  458. package/src/lib/cad/docker-executor.js +352 -0
  459. package/src/lib/cad/freecad.js +253 -0
  460. package/src/lib/cad/index.js +40 -0
  461. package/src/lib/cad/openscad.js +198 -0
  462. package/src/lib/cad/project-cli.d.ts +2 -0
  463. package/src/lib/cad/project-cli.js +21 -0
  464. package/src/lib/cad/project-contract.d.ts +3 -0
  465. package/src/lib/cad/project-contract.js +1 -0
  466. package/src/lib/cad/project-recipe.js +30 -0
  467. package/src/lib/cad/project-runtime.d.ts +2 -0
  468. package/src/lib/cad/project-runtime.js +53 -0
  469. package/src/lib/cad/project-store.js +25 -0
  470. package/src/lib/cad/project-workflows.js +31 -0
  471. package/src/lib/cad-docker.js +21 -2
  472. package/src/lib/cli-preferences.js +17 -2
  473. package/src/lib/core-client.js +37 -18
  474. package/src/lib/deploy/local-studio.js +6 -5
  475. package/src/lib/dockerize.js +3 -0
  476. package/src/lib/execution-approvals.js +1 -0
  477. package/src/lib/identity-scaffold.js +4 -1
  478. package/src/lib/knowledge-docker.js +9 -1
  479. package/src/lib/local-sessions.js +124 -34
  480. package/src/lib/local-status.js +35 -14
  481. package/src/lib/project-config.js +9 -0
  482. package/src/lib/provider-credentials.js +136 -32
  483. package/src/lib/scaffold/resolve-cloudflare-account.js +37 -0
  484. package/src/lib/scaffold/wizards/cms.js +2 -8
  485. package/src/lib/scaffold/wizards/worker-api.js +2 -8
  486. package/src/lib/slash-commands.js +10 -2
  487. package/src/local/migrations.js +109 -1
  488. package/src/local/runtime-store.js +31 -5
  489. package/src/local/sqlite.js +36 -1
  490. package/src/local-fs/capability.js +121 -0
  491. package/src/local-fs/freshness.js +75 -0
  492. package/src/local-fs/index.js +385 -0
  493. package/src/local-fs/paths.js +100 -0
  494. package/src/local-pty/server.js +295 -19
  495. package/src/mcp/authority.js +348 -0
  496. package/src/mcp/client-adapters.js +431 -0
  497. package/src/mcp/client.js +172 -0
  498. package/src/mcp/index.js +47 -0
  499. package/src/mcp/telemetry.js +103 -0
  500. package/src/models/ai-access-onboarding.js +112 -0
  501. package/src/models/catalog.js +329 -51
  502. package/src/models/discovery.js +34 -6
  503. package/src/models/index.js +2 -0
  504. package/src/models/inventory-core.js +190 -0
  505. package/src/models/policy.js +20 -0
  506. package/src/plugins/cloudflare.js +103 -0
  507. package/src/plugins/completeful.js +69 -0
  508. package/src/plugins/contracts.js +86 -0
  509. package/src/plugins/index.js +11 -0
  510. package/src/plugins/registry.js +207 -0
  511. package/src/plugins/resource-scope.js +45 -0
  512. package/src/plugins/runtime.js +118 -0
  513. package/src/plugins/vectorize.js +31 -0
  514. package/src/progression/engine.js +171 -0
  515. package/src/progression/index.js +1 -0
  516. package/src/providers/cloudflare-chat.js +1 -1
  517. package/src/providers/gemini-generate-content.js +2 -1
  518. package/src/providers/openai-responses.js +45 -16
  519. package/src/providers/tool-schema.js +85 -0
  520. package/src/repository/index.js +29 -0
  521. package/src/rpc/generated/errors_pb.js +961 -1
  522. package/src/sam/activity/index.js +183 -0
  523. package/src/sam/client.js +252 -0
  524. package/src/sam/decision/calibration.js +109 -0
  525. package/src/sam/decision/confidence.js +126 -0
  526. package/src/sam/decision/evaluate.js +157 -0
  527. package/src/sam/decision/evaluators/deterministic.js +341 -0
  528. package/src/sam/decision/evaluators/heuristic.js +61 -0
  529. package/src/sam/decision/evaluators/select.js +50 -0
  530. package/src/sam/decision/evaluators/semantic.js +149 -0
  531. package/src/sam/decision/hierarchical.js +61 -0
  532. package/src/sam/decision/index.js +53 -0
  533. package/src/sam/decision/policy.js +86 -0
  534. package/src/sam/decision/questions.js +120 -0
  535. package/src/sam/decision/receipt.js +148 -0
  536. package/src/sam/decision/state.js +117 -0
  537. package/src/sam/decision/types.js +22 -0
  538. package/src/sam/decision/validate.js +200 -0
  539. package/src/sam/define.js +51 -0
  540. package/src/sam/index.js +65 -0
  541. package/src/sam/operations/brand-scan.js +62 -0
  542. package/src/sam/operations/cad-blender-inspect.js +36 -0
  543. package/src/sam/operations/codebaseindex-ingest.js +49 -0
  544. package/src/sam/operations/decision-evaluate.js +59 -0
  545. package/src/sam/operations/planning-astar.js +77 -0
  546. package/src/sam/operations/planning-goap.js +60 -0
  547. package/src/sam/operations/repository-inspect.js +72 -0
  548. package/src/sam/operations/security-scan.js +33 -0
  549. package/src/sam/operations/terminal-exec.js +29 -0
  550. package/src/sam/planning/astar.js +311 -0
  551. package/src/sam/planning/goap.js +177 -0
  552. package/src/sam/planning/index.js +21 -0
  553. package/src/sam/planning/state.js +84 -0
  554. package/src/sam/registry.js +48 -0
  555. package/src/sam/result.js +77 -0
  556. package/src/sam/seed.js +44 -0
  557. package/src/sam/types.js +91 -0
  558. package/src/security/local-vault.js +415 -0
  559. package/src/security/process.js +20 -4
  560. package/src/skills/catalog.js +64 -0
  561. package/src/skills/content-resolver.js +124 -0
  562. package/src/skills/hosted-store.js +37 -0
  563. package/src/skills/index.js +29 -64
  564. package/src/skills/interaction.js +102 -0
  565. package/src/skills/local-store.js +228 -0
  566. package/src/skills/manifest.js +104 -0
  567. package/src/skills/metrics.js +31 -0
  568. package/src/skills/registry.js +184 -0
  569. package/src/skills/runtime.js +287 -0
  570. package/src/skills/slash.js +44 -0
  571. package/src/status/actions.js +192 -0
  572. package/src/tools/hydrate.js +5 -1
  573. package/src/tools/index.js +7 -0
  574. package/src/tools/redact.js +64 -0
  575. package/src/tools/registry.js +83 -0
  576. package/src/tools/runtime.js +257 -0
  577. package/src/tools/search.js +21 -8
  578. package/src/ui/ansi.js +117 -3
  579. package/src/ui/cli/activity.js +76 -7
  580. package/src/ui/cli/footer.js +110 -9
  581. package/src/ui/cli/help.js +96 -96
  582. package/src/ui/wireframes.js +166 -0
  583. package/test/account-session.test.mjs +28 -0
  584. package/test/apps-scaffold-contract.test.mjs +16 -1
  585. package/test/capabilities.test.mjs +1 -1
  586. package/test/cli/api-key-env-whoami.test.mjs +129 -0
  587. package/test/cli/codebaseindex-plan-ux.test.mjs +37 -0
  588. package/test/cli/eval-live.test.mjs +219 -0
  589. package/test/cli/go.test.mjs +128 -0
  590. package/test/cli/local-vault-and-provider-setup.test.mjs +268 -0
  591. package/test/cli/mcp-client.test.mjs +245 -0
  592. package/test/cli/runtime-ui.test.mjs +69 -2
  593. package/test/cli/skill-npm-and-env.test.mjs +52 -0
  594. package/test/cli/status-actions.test.mjs +88 -0
  595. package/test/cli/wireframes-go-registry.test.mjs +139 -0
  596. package/test/cloudflare-connector.test.mjs +3 -6
  597. package/test/cloudflare-runtime.test.mjs +8 -1
  598. package/test/context.test.mjs +15 -0
  599. package/test/error-diagnostics.test.mjs +9 -0
  600. package/test/fixtures/cad/courtyard-house.json +208 -0
  601. package/test/go/build-source-identity.test.mjs +31 -0
  602. package/test/go/cloudflare-probe.test.mjs +317 -0
  603. package/test/go/distribution.test.mjs +28 -0
  604. package/test/integration/ai-access-onboarding.test.mjs +47 -0
  605. package/test/integration/app-command.test.mjs +55 -0
  606. package/test/integration/cad-discovery.test.mjs +158 -0
  607. package/test/integration/cad-docker-executor.test.mjs +249 -0
  608. package/test/integration/cad-execution.test.mjs +184 -0
  609. package/test/integration/cad-project-app.test.mjs +31 -0
  610. package/test/integration/cad-project-d1.test.mjs +25 -0
  611. package/test/integration/cad-project-native.test.mjs +24 -0
  612. package/test/integration/cad-project-workflow.test.mjs +9 -0
  613. package/test/integration/cad-project.test.mjs +82 -0
  614. package/test/integration/cli-help.test.mjs +5 -1
  615. package/test/integration/cms-site-tenancy-contract.test.mjs +256 -0
  616. package/test/integration/codebaseindex-ingest.test.mjs +166 -0
  617. package/test/integration/core-client.integration.test.mjs +55 -0
  618. package/test/integration/error-runtime-rpc.test.mjs +71 -0
  619. package/test/integration/features-resolve.test.mjs +128 -0
  620. package/test/integration/icon-registry.test.mjs +67 -0
  621. package/test/integration/ingest-discover-models.test.mjs +30 -0
  622. package/test/integration/install-script.test.mjs +110 -0
  623. package/test/integration/inventory-core.test.mjs +53 -0
  624. package/test/integration/local-fs.test.mjs +113 -0
  625. package/test/integration/plugins-cloudflare.integration.test.mjs +28 -0
  626. package/test/integration/provider-env-cli.test.mjs +3 -2
  627. package/test/integration/runtime-migrations.test.mjs +6 -1
  628. package/test/integration/runtime-status.integration.test.mjs +211 -0
  629. package/test/integration/sam-activity-recovery.test.mjs +147 -0
  630. package/test/integration/sam-decision.test.mjs +584 -0
  631. package/test/integration/sam-kernel.test.mjs +99 -0
  632. package/test/integration/sam-planning-astar.test.mjs +279 -0
  633. package/test/integration/scaffold-cloudflare.test.mjs +46 -0
  634. package/test/integration/skill-runtime.test.mjs +240 -0
  635. package/test/integration/storage-architecture.test.mjs +154 -0
  636. package/test/integration/store-discovery.test.mjs +44 -0
  637. package/test/integration/studio-fs-pty-e2e.test.mjs +294 -0
  638. package/test/integration/terminal-exec.integration.test.mjs +86 -0
  639. package/test/integration/tool-runtime.test.mjs +124 -0
  640. package/test/integration/tool-schema.test.mjs +59 -0
  641. package/test/knowledge-service.test.mjs +4 -0
  642. package/test/local-sessions.test.mjs +11 -2
  643. package/test/local-studio-deploy.test.mjs +1 -1
  644. package/test/model-catalog.test.mjs +28 -1
  645. package/test/models.test.mjs +172 -11
  646. package/test/openai-responses.test.mjs +60 -0
  647. package/test/provider-credentials.test.mjs +15 -5
  648. package/test/responses-runner.test.mjs +321 -6
  649. package/test/shell.test.mjs +151 -6
  650. package/test/smoke.mjs +2 -2
  651. package/test/tools-search.test.mjs +33 -0
  652. package/test/unit/website-assets-bindings.test.mjs +60 -0
  653. package/test/whoami-resume.test.mjs +82 -3
  654. package/examples/gorilla-shell/README.md +0 -15
  655. package/src/lib/gorilla-template.js +0 -54
  656. package/templates/gorilla-shell/App.tsx +0 -639
  657. package/templates/gorilla-shell/README.md +0 -34
  658. package/templates/gorilla-shell/index.html +0 -15
  659. package/templates/gorilla-shell/main.jsx +0 -9
  660. package/templates/gorilla-shell/package.json +0 -19
  661. package/templates/gorilla-shell/vite.config.js +0 -21
@@ -9,7 +9,7 @@ import {
9
9
  assertConnectionOwner,
10
10
  } from './index.js';
11
11
  import { resolveAuthenticatedOwner } from './owner.js';
12
- import { sealToken, vaultConfigured } from './vault.js';
12
+ import { decryptSecret, sealToken, vaultConfigured } from './vault.js';
13
13
 
14
14
  function json(data, status = 200) {
15
15
  return new Response(JSON.stringify(data), {
@@ -22,6 +22,35 @@ function redirect(location) {
22
22
  return new Response(null, { status: 302, headers: { location } });
23
23
  }
24
24
 
25
+ function settingsRedirect(url, result, error = '', returnTo = '') {
26
+ const destination = returnTo ? new URL(returnTo) : new URL('/settings/integrations', url.origin);
27
+ destination.searchParams.set('connection', 'cloudflare');
28
+ destination.searchParams.set('result', result);
29
+ if (error) destination.searchParams.set('error', error);
30
+ return redirect(destination.toString());
31
+ }
32
+
33
+ function resolveReturnTo(url) {
34
+ const raw = url.searchParams.get('return_to') || '';
35
+ if (!raw) return '';
36
+ try {
37
+ const destination = new URL(raw, url.origin);
38
+ return destination.origin === url.origin ? destination.toString() : '';
39
+ } catch {
40
+ return '';
41
+ }
42
+ }
43
+
44
+ async function deleteOAuthState(env, state) {
45
+ if (env.DB) {
46
+ await env.DB.prepare(
47
+ `DELETE FROM agentsam_cloudflare_oauth_state WHERE state = ?`,
48
+ ).bind(state).run();
49
+ } else if (env.oauthState instanceof Map) {
50
+ env.oauthState.delete(state);
51
+ }
52
+ }
53
+
25
54
  export function isCloudflareConnectionPath(pathname) {
26
55
  return pathname === '/api/connections/cloudflare'
27
56
  || pathname === '/api/connections/cloudflare/start'
@@ -47,10 +76,58 @@ async function ensureTables(env) {
47
76
  state TEXT PRIMARY KEY,
48
77
  owner_id TEXT NOT NULL,
49
78
  code_verifier TEXT NOT NULL,
50
- created_at INTEGER
79
+ created_at INTEGER,
80
+ return_to TEXT
81
+ )`).run();
82
+ await env.DB.prepare(`CREATE TABLE IF NOT EXISTS integration_resources (
83
+ id TEXT PRIMARY KEY,
84
+ tenant_id TEXT NOT NULL,
85
+ connection_id TEXT NOT NULL,
86
+ provider TEXT NOT NULL,
87
+ resource_type TEXT NOT NULL,
88
+ provider_resource_id TEXT,
89
+ name TEXT,
90
+ url TEXT,
91
+ metadata_json TEXT DEFAULT '{}',
92
+ synced_at TEXT,
93
+ created_at TEXT NOT NULL DEFAULT (datetime('now')),
94
+ updated_at TEXT NOT NULL DEFAULT (datetime('now'))
51
95
  )`).run();
52
96
  }
53
97
 
98
+ async function seedKnownCloudflareResources(env, ownerId, connectionId, cloudflareAccountId) {
99
+ if (!env?.DB?.prepare || !cloudflareAccountId) return;
100
+ let configuredScopes = {};
101
+ try { configuredScopes = JSON.parse(env.AGENTSAM_RESOURCE_SCOPE_JSON || '{}'); } catch { configuredScopes = {}; }
102
+ const resources = [
103
+ { key: 'agentsam-sdk', type: 'worker', id: 'agentsam-sdk', name: 'AgentSam SDK / Local Studio' },
104
+ { key: 'agentsam-cad-creator', type: 'worker', id: 'agentsam-cad-creator', name: 'AgentSam CAD Creator' },
105
+ { key: 'agentsam-client-cms-editor', type: 'worker', id: 'agentsam-client-cms-editor', name: 'AgentSam Client CMS Editor' },
106
+ { key: 'fuelnfreetime', type: 'worker', id: 'fuelnfreetime', name: 'Fuel & Free Time', metadata: {
107
+ zone_id: '816a5d2284103e4481987ceeb16c2ca9',
108
+ d1_database_id: '9fd6ff92-e407-4b51-8b01-3c93f3845bb2',
109
+ r2_bucket: 'fuelnfreetime',
110
+ ...(configuredScopes.fuelnfreetime || {}),
111
+ } },
112
+ ];
113
+ const statements = resources.map((resource) => env.DB.prepare(`
114
+ INSERT OR REPLACE INTO integration_resources (
115
+ id, tenant_id, connection_id, provider, resource_type, provider_resource_id,
116
+ name, metadata_json, synced_at, updated_at
117
+ ) VALUES (?, ?, ?, 'cloudflare', ?, ?, ?, ?, datetime('now'), datetime('now'))
118
+ `).bind(
119
+ `ires_cf_${cloudflareAccountId}_${resource.key}`,
120
+ ownerId,
121
+ connectionId,
122
+ resource.type,
123
+ resource.id,
124
+ resource.name,
125
+ JSON.stringify({ cloudflare_account_id: cloudflareAccountId, ...(resource.metadata || {}) }),
126
+ ));
127
+ if (typeof env.DB.batch === 'function') await env.DB.batch(statements);
128
+ else for (const statement of statements) await statement.run();
129
+ }
130
+
54
131
  export async function handleCloudflareConnectionRequest(request, env) {
55
132
  const url = new URL(request.url);
56
133
  const client = resolveCloudflareOAuthClient(env);
@@ -98,7 +175,9 @@ export async function handleCloudflareConnectionRequest(request, env) {
98
175
  if (env.DB) {
99
176
  const row = await env.DB.prepare(
100
177
  `SELECT connection_id, owner_id, cloudflare_account_id, scopes, status, created_at, updated_at, expires_at
101
- FROM agentsam_cloudflare_connections WHERE owner_id = ? LIMIT 1`,
178
+ FROM agentsam_cloudflare_connections
179
+ WHERE owner_id = ? AND status = 'connected'
180
+ ORDER BY updated_at DESC LIMIT 1`,
102
181
  ).bind(ownerId).first();
103
182
  if (row) {
104
183
  connection = {
@@ -122,12 +201,17 @@ export async function handleCloudflareConnectionRequest(request, env) {
122
201
  const verifier = btoa(String.fromCharCode(...verifierBytes)).replace(/\+/g, '-').replace(/\//g, '_').replace(/=+$/, '');
123
202
  const digest = await crypto.subtle.digest('SHA-256', new TextEncoder().encode(verifier));
124
203
  const challenge = btoa(String.fromCharCode(...new Uint8Array(digest))).replace(/\+/g, '-').replace(/\//g, '_').replace(/=+$/, '');
204
+ const returnTo = resolveReturnTo(url);
125
205
  if (env.DB) {
126
206
  await env.DB.prepare(
127
- `INSERT INTO agentsam_cloudflare_oauth_state (state, owner_id, code_verifier, created_at) VALUES (?, ?, ?, unixepoch())`,
128
- ).bind(state, ownerId, verifier).run();
207
+ `DELETE FROM agentsam_cloudflare_oauth_state WHERE created_at < unixepoch() - 600`,
208
+ ).run();
209
+ await env.DB.prepare(
210
+ `INSERT INTO agentsam_cloudflare_oauth_state (state, owner_id, code_verifier, created_at, return_to)
211
+ VALUES (?, ?, ?, unixepoch(), ?)`,
212
+ ).bind(state, ownerId, verifier, returnTo || null).run();
129
213
  } else if (env.oauthState instanceof Map) {
130
- env.oauthState.set(state, { ownerId, verifier });
214
+ env.oauthState.set(state, { ownerId, verifier, returnTo });
131
215
  }
132
216
  const redirectUri = `${url.origin}${CLOUDFLARE_CALLBACK_PATH}`;
133
217
  const authorize = buildAuthorizeUrl({
@@ -136,47 +220,77 @@ export async function handleCloudflareConnectionRequest(request, env) {
136
220
  state,
137
221
  codeChallenge: challenge,
138
222
  });
223
+ // Browser navigation → 302 to Cloudflare. XHR/fetch (Integrations UI) → JSON.
224
+ const accept = String(request.headers.get('accept') || '');
225
+ const mode = String(request.headers.get('sec-fetch-mode') || '');
226
+ const wantsJson = accept.includes('application/json')
227
+ || mode === 'cors'
228
+ || request.headers.get('x-agentsam-oauth') === 'json';
229
+ if (!wantsJson) {
230
+ return Response.redirect(authorize, 302);
231
+ }
139
232
  return json({ ok: true, authorize_url: authorize, callback: CLOUDFLARE_CALLBACK_PATH });
140
233
  }
141
234
 
142
235
  if (url.pathname === CLOUDFLARE_CALLBACK_PATH && request.method === 'GET') {
143
236
  const code = url.searchParams.get('code') || '';
144
237
  const state = url.searchParams.get('state') || '';
238
+ const providerError = url.searchParams.get('error') || '';
145
239
  let stored = null;
146
240
  if (env.DB) {
147
241
  stored = await env.DB.prepare(
148
- `SELECT owner_id, code_verifier FROM agentsam_cloudflare_oauth_state WHERE state = ?`,
242
+ `SELECT owner_id, code_verifier, created_at, return_to
243
+ FROM agentsam_cloudflare_oauth_state WHERE state = ?`,
149
244
  ).bind(state).first();
150
245
  } else if (env.oauthState instanceof Map) {
151
246
  stored = env.oauthState.get(state);
152
- if (stored) stored = { owner_id: stored.ownerId, code_verifier: stored.verifier };
247
+ if (stored) stored = { owner_id: stored.ownerId, code_verifier: stored.verifier, return_to: stored.returnTo || '' };
153
248
  }
154
249
  if (!stored) {
250
+ // A callback without a one-time PKCE state is forged or expired. Keep
251
+ // this as an explicit 403 instead of redirecting into a misleading UI.
155
252
  return json({ ok: false, error: 'cloudflare_connection_forbidden' }, 403);
156
253
  }
157
254
  if (!ownerId) ownerId = stored.owner_id;
158
255
  if (stored.owner_id !== ownerId) {
159
- return json({ ok: false, error: 'cloudflare_connection_forbidden' }, 403);
256
+ return settingsRedirect(url, 'error', 'cloudflare_connection_forbidden', stored.return_to || '');
257
+ }
258
+ const createdAt = Number(stored.created_at || 0);
259
+ const now = Math.floor(Date.now() / 1000);
260
+ if (createdAt && now - createdAt > 10 * 60) {
261
+ await deleteOAuthState(env, state);
262
+ return settingsRedirect(url, 'error', 'oauth_state_expired', stored.return_to || '');
160
263
  }
264
+ await deleteOAuthState(env, state);
265
+ if (providerError) {
266
+ return settingsRedirect(url, 'error', providerError, stored.return_to || '');
267
+ }
268
+ if (!code) {
269
+ return settingsRedirect(url, 'error', 'authorization_code_missing', stored.return_to || '');
270
+ }
271
+ // This is Cloudflare's public PKCE client (Token Authentication Method:
272
+ // None). Do not add client_secret, even if an obsolete Worker binding is
273
+ // present; a mixed-auth exchange is rejected by Cloudflare.
274
+ const tokenParams = {
275
+ grant_type: 'authorization_code',
276
+ code,
277
+ redirect_uri: `${url.origin}${CLOUDFLARE_CALLBACK_PATH}`,
278
+ client_id: String(env.CLOUDFLARE_OAUTH_CLIENT_ID),
279
+ code_verifier: stored.code_verifier,
280
+ };
161
281
  const tokenRes = await fetch(CLOUDFLARE_OAUTH_TOKEN_URL, {
162
282
  method: 'POST',
163
283
  headers: { 'content-type': 'application/x-www-form-urlencoded' },
164
- body: new URLSearchParams({
165
- grant_type: 'authorization_code',
166
- code,
167
- redirect_uri: `${url.origin}${CLOUDFLARE_CALLBACK_PATH}`,
168
- client_id: String(env.CLOUDFLARE_OAUTH_CLIENT_ID),
169
- client_secret: String(env.CLOUDFLARE_OAUTH_CLIENT_SECRET),
170
- code_verifier: stored.code_verifier,
171
- }),
284
+ body: new URLSearchParams(tokenParams),
172
285
  });
173
286
  if (!tokenRes.ok) {
174
- return json({ ok: false, error: 'token_exchange_failed' }, 502);
287
+ console.error('cloudflare_token_exchange_failed', tokenRes.status);
288
+ return settingsRedirect(url, 'error', 'token_exchange_failed', stored.return_to || '');
175
289
  }
176
290
  const tokens = await tokenRes.json();
177
291
  const connectionId = `cfconn_${crypto.randomUUID().replace(/-/g, '').slice(0, 16)}`;
178
292
  if (tokens.access_token && !vaultConfigured(env)) {
179
- return json({ ok: false, error: 'vault_unavailable' }, 503);
293
+ return settingsRedirect(url, 'error', 'vault_unavailable', stored.return_to || '');
180
294
  }
181
295
  const aad = `cloudflare-connection:${ownerId}`;
182
296
  let accessEnc = null;
@@ -185,10 +299,16 @@ export async function handleCloudflareConnectionRequest(request, env) {
185
299
  accessEnc = await sealToken(env, tokens.access_token, aad);
186
300
  refreshEnc = await sealToken(env, tokens.refresh_token, aad);
187
301
  } catch (err) {
188
- return json({ ok: false, error: err.code || 'vault_unavailable' }, 503);
302
+ return settingsRedirect(url, 'error', err.code || 'vault_unavailable', stored.return_to || '');
189
303
  }
190
304
  if (env.DB) {
191
- await env.DB.prepare(
305
+ const removePrevious = env.DB.prepare(
306
+ `UPDATE agentsam_cloudflare_connections
307
+ SET status = 'superseded', access_token_encrypted = NULL,
308
+ refresh_token_encrypted = NULL, updated_at = unixepoch()
309
+ WHERE owner_id = ? AND status = 'connected'`,
310
+ ).bind(ownerId);
311
+ const insertConnection = env.DB.prepare(
192
312
  `INSERT INTO agentsam_cloudflare_connections (
193
313
  connection_id, owner_id, cloudflare_account_id, scopes, status,
194
314
  access_token_encrypted, refresh_token_encrypted, created_at, updated_at, expires_at
@@ -201,22 +321,52 @@ export async function handleCloudflareConnectionRequest(request, env) {
201
321
  accessEnc,
202
322
  refreshEnc,
203
323
  tokens.expires_in ? Math.floor(Date.now() / 1000) + Number(tokens.expires_in) : null,
204
- ).run();
324
+ );
325
+ if (typeof env.DB.batch === 'function') {
326
+ await env.DB.batch([removePrevious, insertConnection]);
327
+ } else {
328
+ await removePrevious.run();
329
+ await insertConnection.run();
330
+ }
331
+ await seedKnownCloudflareResources(env, ownerId, connectionId, tokens.account_id || null);
205
332
  }
206
- return redirect(`/agentsam?connection=cloudflare`);
333
+ return settingsRedirect(url, 'connected', '', stored.return_to || '');
207
334
  }
208
335
 
209
336
  if (url.pathname === '/api/connections/cloudflare/disconnect' && request.method === 'POST') {
337
+ let providerRevoked = false;
210
338
  if (env.DB) {
211
339
  const row = await env.DB.prepare(
212
- `SELECT connection_id, owner_id FROM agentsam_cloudflare_connections WHERE owner_id = ?`,
340
+ `SELECT connection_id, owner_id, access_token_encrypted
341
+ FROM agentsam_cloudflare_connections
342
+ WHERE owner_id = ? AND status = 'connected'
343
+ ORDER BY updated_at DESC LIMIT 1`,
213
344
  ).bind(ownerId).first();
214
345
  if (row) {
215
346
  assertConnectionOwner({ ownerId: row.owner_id, connectionId: row.connection_id }, ownerId);
216
- await env.DB.prepare(`DELETE FROM agentsam_cloudflare_connections WHERE owner_id = ?`).bind(ownerId).run();
347
+ if (row.access_token_encrypted) {
348
+ try {
349
+ const token = await decryptSecret(env, row.access_token_encrypted, `cloudflare-connection:${ownerId}`);
350
+ const revokeParams = new URLSearchParams({ token, client_id: String(env.CLOUDFLARE_OAUTH_CLIENT_ID) });
351
+ const revokeResponse = await fetch(CLOUDFLARE_OAUTH_REVOKE_URL, {
352
+ method: 'POST',
353
+ headers: { 'content-type': 'application/x-www-form-urlencoded' },
354
+ body: revokeParams,
355
+ });
356
+ providerRevoked = revokeResponse.ok;
357
+ } catch (error) {
358
+ console.error('cloudflare_token_revoke_failed', String(error?.message || error));
359
+ }
360
+ }
361
+ await env.DB.prepare(`
362
+ UPDATE agentsam_cloudflare_connections
363
+ SET status = 'revoked', access_token_encrypted = NULL,
364
+ refresh_token_encrypted = NULL, expires_at = unixepoch(), updated_at = unixepoch()
365
+ WHERE connection_id = ? AND owner_id = ?
366
+ `).bind(row.connection_id, ownerId).run();
217
367
  }
218
368
  }
219
- return json({ ok: true, status: 'not_configured' });
369
+ return json({ ok: true, status: 'not_configured', provider_revoked: providerRevoked });
220
370
  }
221
371
 
222
372
  return json({ ok: false, error: 'not_found' }, 404);
@@ -5,6 +5,7 @@ import {
5
5
  cloudflareConnectionSafeStatus,
6
6
  resolveCloudflareOAuthClient,
7
7
  } from '../src/index.js';
8
+ import { handleCloudflareConnectionRequest } from '../src/routes.js';
8
9
 
9
10
  describe('cloudflare connector', () => {
10
11
  it('reports not_configured when credentials are absent', () => {
@@ -17,7 +18,6 @@ describe('cloudflare connector', () => {
17
18
  it('loads fake fixtures without treating them as production authority', () => {
18
19
  const client = resolveCloudflareOAuthClient({
19
20
  CLOUDFLARE_OAUTH_CLIENT_ID: 'sillynotreal',
20
- CLOUDFLARE_OAUTH_CLIENT_SECRET: 'sillynotreal-secret',
21
21
  });
22
22
  assert.equal(client.configured, true);
23
23
  assert.equal(client.fixture, true);
@@ -32,7 +32,7 @@ describe('cloudflare connector', () => {
32
32
  });
33
33
  const blob = JSON.stringify(status);
34
34
  assert.equal(blob.includes('sillynotreal-secret'), false);
35
- assert.equal(status.secret, 'configured');
35
+ assert.equal(status.token_auth_method, 'none_pkce');
36
36
  assert.equal(status.configured, false);
37
37
  });
38
38
 
@@ -41,4 +41,139 @@ describe('cloudflare connector', () => {
41
41
  assert.throws(() => assertConnectionOwner(record, 'connor'), /cloudflare_connection_forbidden/);
42
42
  assert.equal(assertConnectionOwner(record, 'sam').connectionId, 'c1');
43
43
  });
44
+
45
+ it('supports a production PKCE client with no client secret', () => {
46
+ const client = resolveCloudflareOAuthClient({
47
+ CLOUDFLARE_OAUTH_CLIENT_ID: 'real-client-id',
48
+ });
49
+ assert.equal(client.productionReady, true);
50
+ assert.equal(client.clientIdConfigured, true);
51
+ assert.equal(client.tokenAuthMethod, 'none_pkce');
52
+ });
53
+
54
+ it('keeps connector return paths same-origin', async () => {
55
+ const calls = [];
56
+ const DB = {
57
+ prepare(sql) {
58
+ return {
59
+ args: [],
60
+ bind(...args) { this.args = args; return this; },
61
+ async run() { calls.push({ sql, args: this.args }); return { success: true }; },
62
+ };
63
+ },
64
+ };
65
+ const response = await handleCloudflareConnectionRequest(
66
+ new Request('https://agentsam.example/api/connections/cloudflare/start?return_to=https://untrusted.example/after', {
67
+ headers: {
68
+ authorization: 'Bearer fixture',
69
+ accept: 'application/json',
70
+ },
71
+ }),
72
+ {
73
+ DB,
74
+ fixtureSessions: new Map([['fixture', 'user_123']]),
75
+ CLOUDFLARE_OAUTH_CLIENT_ID: 'real-client-id',
76
+ },
77
+ );
78
+ assert.equal(response.status, 200);
79
+ assert.equal(
80
+ calls.some((call) => call.sql.includes('DELETE FROM agentsam_cloudflare_oauth_state WHERE created_at < unixepoch() - 600')),
81
+ true,
82
+ );
83
+ const stateInsert = calls.find((call) => call.sql.includes('INSERT INTO agentsam_cloudflare_oauth_state'));
84
+ assert.ok(stateInsert);
85
+ assert.equal(stateInsert.args.at(-1), null);
86
+ });
87
+
88
+ it('redirects browser starts to Cloudflare authorization', async () => {
89
+ const oauthState = new Map();
90
+ const response = await handleCloudflareConnectionRequest(
91
+ new Request('https://agentsam.example/api/connections/cloudflare/start', {
92
+ headers: { authorization: 'Bearer fixture' },
93
+ }),
94
+ {
95
+ fixtureSessions: new Map([['fixture', 'user_123']]),
96
+ oauthState,
97
+ CLOUDFLARE_OAUTH_CLIENT_ID: 'real-client-id',
98
+ },
99
+ );
100
+
101
+ assert.equal(response.status, 302);
102
+ const location = new URL(response.headers.get('location'));
103
+ assert.equal(location.origin, 'https://dash.cloudflare.com');
104
+ assert.equal(location.pathname, '/oauth2/auth');
105
+ assert.equal(location.searchParams.get('client_id'), 'real-client-id');
106
+ assert.equal(location.searchParams.get('redirect_uri'), 'https://agentsam.example/api/connections/cloudflare/callback');
107
+ assert.equal(oauthState.size, 1);
108
+ });
109
+
110
+ it('consumes callback state and stores only encrypted OAuth tokens', async () => {
111
+ const now = Math.floor(Date.now() / 1000);
112
+ const calls = [];
113
+ const statements = [];
114
+ const DB = {
115
+ prepare(sql) {
116
+ const statement = {
117
+ sql,
118
+ args: [],
119
+ bind(...args) {
120
+ this.args = args;
121
+ return this;
122
+ },
123
+ async first() {
124
+ if (sql.includes('agentsam_cloudflare_oauth_state')) {
125
+ return { owner_id: 'user_123', code_verifier: 'verifier', created_at: now };
126
+ }
127
+ return null;
128
+ },
129
+ async run() {
130
+ calls.push({ sql, args: this.args });
131
+ return { success: true };
132
+ },
133
+ };
134
+ statements.push(statement);
135
+ return statement;
136
+ },
137
+ async batch(batchStatements) {
138
+ for (const statement of batchStatements) await statement.run();
139
+ return batchStatements.map(() => ({ success: true }));
140
+ },
141
+ };
142
+ const originalFetch = globalThis.fetch;
143
+ globalThis.fetch = async (_input, init) => {
144
+ const body = new URLSearchParams(init.body);
145
+ assert.equal(body.get('client_secret'), null);
146
+ return new Response(JSON.stringify({
147
+ access_token: 'access-plaintext',
148
+ refresh_token: 'refresh-plaintext',
149
+ account_id: 'account_123',
150
+ scope: 'd1.read workers-scripts.write',
151
+ expires_in: 3600,
152
+ }), { status: 200, headers: { 'content-type': 'application/json' } });
153
+ };
154
+
155
+ try {
156
+ const response = await handleCloudflareConnectionRequest(
157
+ new Request('https://agentsam.example/api/connections/cloudflare/callback?code=code_123&state=state_123'),
158
+ {
159
+ DB,
160
+ CLOUDFLARE_OAUTH_CLIENT_ID: 'real-client-id',
161
+ CLOUDFLARE_OAUTH_CLIENT_SECRET: 'obsolete-secret-must-not-be-sent',
162
+ VAULT_MASTER_KEY: '01234567890123456789012345678901',
163
+ },
164
+ );
165
+ assert.equal(response.status, 302);
166
+ assert.equal(
167
+ response.headers.get('location'),
168
+ 'https://agentsam.example/settings/integrations?connection=cloudflare&result=connected',
169
+ );
170
+ assert.equal(calls.some((call) => call.sql.includes('DELETE FROM agentsam_cloudflare_oauth_state')), true);
171
+ const insert = calls.find((call) => call.sql.includes('INSERT INTO agentsam_cloudflare_connections'));
172
+ assert.ok(insert);
173
+ assert.notEqual(insert.args[4], 'access-plaintext');
174
+ assert.notEqual(insert.args[5], 'refresh-plaintext');
175
+ } finally {
176
+ globalThis.fetch = originalFetch;
177
+ }
178
+ });
44
179
  });
@@ -0,0 +1,11 @@
1
+ # @inneranimalmedia/heuristic-theme
2
+
3
+ Stock AgentSam CMS storefront shell theme. Exports a deterministic theme contract consumed by CMS presets and `theme.storefront.shell`.
4
+
5
+ ```js
6
+ import { createStorefrontShellTheme } from "@inneranimalmedia/heuristic-theme";
7
+
8
+ const theme = createStorefrontShellTheme();
9
+ ```
10
+
11
+ Historical gallery demos live in `apps/theme-gallery-preview` — this package owns the reusable stock contract, not donor site archives.
@@ -0,0 +1,25 @@
1
+ {
2
+ "name": "@inneranimalmedia/heuristic-theme",
3
+ "version": "0.1.0",
4
+ "description": "Stock AgentSam CMS storefront shell theme contract (heuristic-theme).",
5
+ "type": "module",
6
+ "main": "./src/index.js",
7
+ "exports": {
8
+ ".": "./src/index.js",
9
+ "./theme": "./src/theme.js"
10
+ },
11
+ "files": [
12
+ "src",
13
+ "README.md"
14
+ ],
15
+ "scripts": {
16
+ "test": "node --test test/*.test.mjs"
17
+ },
18
+ "engines": {
19
+ "node": ">=22 <25"
20
+ },
21
+ "publishConfig": {
22
+ "access": "public"
23
+ },
24
+ "license": "MIT"
25
+ }
@@ -0,0 +1,2 @@
1
+ export { createStorefrontShellTheme } from "./theme.js";
2
+ export { createHeuristicThemeProductRow } from "./registry.js";
@@ -0,0 +1,36 @@
1
+ import { createStorefrontShellTheme } from "./theme.js";
2
+
3
+ /**
4
+ * Durable agentsam_products payload for the stock heuristic theme.
5
+ * Caller resolves repository_id against live code_repositories before UPSERT.
6
+ */
7
+ export function createHeuristicThemeProductRow({ accountId, repositoryId = null } = {}) {
8
+ const theme = createStorefrontShellTheme();
9
+ return {
10
+ account_id: accountId || null,
11
+ slug: theme.slug,
12
+ name: theme.displayName,
13
+ kind: "theme",
14
+ status: "wired",
15
+ repository_id: repositoryId,
16
+ canonical_path: "packages/heuristic-theme",
17
+ package_name: "@inneranimalmedia/heuristic-theme",
18
+ metadata: {
19
+ origin: "gallery_mount",
20
+ normalization_state: "wired",
21
+ package: "@inneranimalmedia/heuristic-theme",
22
+ preview_kind: "live",
23
+ capabilities: ["theme.storefront.shell"],
24
+ app_manifest: null,
25
+ help_root: "docs/",
26
+ },
27
+ capability: "theme.storefront.shell",
28
+ relationships: [
29
+ {
30
+ relationship_type: "packaged_as",
31
+ target_type: "sdk-package",
32
+ target_slug: "heuristic-theme",
33
+ },
34
+ ],
35
+ };
36
+ }
@@ -0,0 +1,41 @@
1
+ /** @typedef {{ id: string, slug: string, displayName: string, version: string, kind: string, surfaces: string[], slots: Record<string, string[]>, tokens: Record<string, string>, sections: Array<{ type: string, label: string }>, metadata: Record<string, unknown> }} StorefrontShellTheme */
2
+
3
+ /**
4
+ * Deterministic stock CMS storefront shell theme contract.
5
+ * @returns {StorefrontShellTheme}
6
+ */
7
+ export function createStorefrontShellTheme() {
8
+ return {
9
+ id: "theme.storefront.shell",
10
+ slug: "heuristic-theme",
11
+ displayName: "Heuristic Theme",
12
+ version: "0.1.0",
13
+ kind: "storefront-shell",
14
+ surfaces: ["cms.editor", "cms.preview", "theme.gallery"],
15
+ slots: {
16
+ shell: ["header", "main", "footer"],
17
+ page: ["hero", "products", "content", "footer"],
18
+ navigation: ["brand", "links", "cta"],
19
+ },
20
+ tokens: {
21
+ "--color-bg": "#F9F7F2",
22
+ "--color-ink": "#101014",
23
+ "--color-accent": "#1e6a6f",
24
+ "--color-muted": "#8a8a95",
25
+ "--font-display": "\"Iowan Old Style\", \"Palatino Linotype\", Palatino, serif",
26
+ "--font-body": "ui-sans-serif, system-ui, -apple-system, sans-serif",
27
+ "--radius-control": "8px",
28
+ },
29
+ sections: [
30
+ { type: "hero", label: "Editorial hero" },
31
+ { type: "products", label: "Product grid" },
32
+ { type: "footer", label: "Footer" },
33
+ ],
34
+ metadata: {
35
+ package: "@inneranimalmedia/heuristic-theme",
36
+ capability: "theme.storefront.shell",
37
+ deterministic: true,
38
+ demoSite: "demo",
39
+ },
40
+ };
41
+ }
@@ -0,0 +1,26 @@
1
+ import assert from "node:assert/strict";
2
+ import test from "node:test";
3
+ import { createStorefrontShellTheme } from "../src/index.js";
4
+
5
+ test("createStorefrontShellTheme returns stable stock contract", () => {
6
+ const theme = createStorefrontShellTheme();
7
+ assert.equal(theme.id, "theme.storefront.shell");
8
+ assert.equal(theme.slug, "heuristic-theme");
9
+ assert.equal(theme.kind, "storefront-shell");
10
+ assert.ok(theme.surfaces.includes("cms.editor"));
11
+ assert.ok(theme.slots.shell.includes("header"));
12
+ assert.equal(theme.tokens["--color-accent"], "#1e6a6f");
13
+ assert.equal(theme.metadata.package, "@inneranimalmedia/heuristic-theme");
14
+ assert.deepEqual(createStorefrontShellTheme(), theme);
15
+ });
16
+
17
+ import { createHeuristicThemeProductRow } from "../src/index.js";
18
+
19
+ test("createHeuristicThemeProductRow emits D1-ready product identity", () => {
20
+ const row = createHeuristicThemeProductRow({ accountId: "acct_demo", repositoryId: "repo_sdk" });
21
+ assert.equal(row.slug, "heuristic-theme");
22
+ assert.equal(row.kind, "theme");
23
+ assert.equal(row.status, "wired");
24
+ assert.equal(row.metadata.capabilities[0], "theme.storefront.shell");
25
+ assert.equal(row.canonical_path, "packages/heuristic-theme");
26
+ });