@inneranimalmedia/agentsam-sdk 2.6.3 → 2.6.5

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 (608) hide show
  1. package/AGENTSAM.md +17 -0
  2. package/README.md +31 -10
  3. package/apps/client-cms-editor/AGENTS.md +12 -0
  4. package/apps/client-cms-editor/IMPORT_PROVENANCE.json +8 -0
  5. package/apps/client-cms-editor/README.md +72 -0
  6. package/apps/client-cms-editor/agentsam.app.json +57 -0
  7. package/apps/client-cms-editor/backend/README.md +5 -0
  8. package/apps/client-cms-editor/backend/package.json +22 -0
  9. package/apps/client-cms-editor/backend/src/api/client.ts +200 -0
  10. package/apps/client-cms-editor/backend/src/demo-bootstrap.ts +145 -0
  11. package/apps/client-cms-editor/backend/src/index.ts +6 -0
  12. package/apps/client-cms-editor/backend/src/model.ts +115 -0
  13. package/apps/client-cms-editor/backend/src/preview/bridge.ts +79 -0
  14. package/apps/client-cms-editor/backend/src/preview/urls.ts +55 -0
  15. package/apps/client-cms-editor/backend/src/routing/cms-route.js +293 -0
  16. package/apps/client-cms-editor/backend/src/routing/index.js +10 -0
  17. package/apps/client-cms-editor/backend/src/storefront.ts +52 -0
  18. package/apps/client-cms-editor/backend/tsconfig.json +15 -0
  19. package/apps/client-cms-editor/backend/worker/index.js +34 -0
  20. package/apps/client-cms-editor/backend/wrangler.jsonc +11 -0
  21. package/apps/client-cms-editor/bin/agentsam-cms.mjs +229 -0
  22. package/apps/client-cms-editor/frontend/index.html +12 -0
  23. package/apps/client-cms-editor/frontend/package.json +33 -0
  24. package/apps/client-cms-editor/frontend/src/AgentSamDrawer.tsx +188 -0
  25. package/apps/client-cms-editor/frontend/src/CmsAgentSurface.tsx +191 -0
  26. package/apps/client-cms-editor/frontend/src/CmsEditor.tsx +1345 -0
  27. package/apps/client-cms-editor/frontend/src/env.d.ts +14 -0
  28. package/apps/client-cms-editor/frontend/src/index.ts +8 -0
  29. package/apps/client-cms-editor/frontend/src/lib/content-safety.ts +63 -0
  30. package/apps/client-cms-editor/frontend/src/main.tsx +17 -0
  31. package/apps/client-cms-editor/frontend/src/mount.tsx +51 -0
  32. package/apps/client-cms-editor/frontend/src/styles/agentsam-drawer.css +214 -0
  33. package/apps/client-cms-editor/frontend/src/styles/cmsShell.css +1739 -0
  34. package/apps/client-cms-editor/frontend/src/styles/studio.css +106 -0
  35. package/apps/client-cms-editor/frontend/src/surfaces/CmsDashboard.tsx +313 -0
  36. package/apps/client-cms-editor/frontend/src/surfaces/CmsGuidedChatHero.tsx +121 -0
  37. package/apps/client-cms-editor/frontend/src/surfaces/CmsHubPage.tsx +132 -0
  38. package/apps/client-cms-editor/frontend/src/surfaces/CmsSiteSwitcher.tsx +176 -0
  39. package/apps/client-cms-editor/frontend/src/surfaces/index.ts +5 -0
  40. package/apps/client-cms-editor/frontend/src/surfaces/types.ts +48 -0
  41. package/apps/client-cms-editor/frontend/tsconfig.json +25 -0
  42. package/apps/client-cms-editor/frontend/vite.config.ts +13 -0
  43. package/apps/client-cms-editor/package-lock.json +3832 -0
  44. package/apps/client-cms-editor/package.json +23 -0
  45. package/apps/client-cms-editor/reference/DONOR_README.md +52 -0
  46. package/apps/client-cms-editor/reference/DONOR_package-lock.json +1253 -0
  47. package/apps/client-cms-editor/reference/DONOR_tsconfig.json +15 -0
  48. package/apps/client-cms-editor/shared/cms/package.json +21 -0
  49. package/apps/client-cms-editor/shared/cms/src/agent-context.ts +35 -0
  50. package/apps/client-cms-editor/shared/cms/src/cloudflare-bindings.ts +51 -0
  51. package/apps/client-cms-editor/shared/cms/src/editor-types.ts +58 -0
  52. package/apps/client-cms-editor/shared/cms/src/index.ts +5 -0
  53. package/apps/client-cms-editor/shared/cms/src/publication.ts +24 -0
  54. package/apps/client-cms-editor/shared/cms/src/routes.ts +11 -0
  55. package/apps/client-cms-editor/shared/cms/tsconfig.json +12 -0
  56. package/bin/agentsam +16 -1
  57. package/bin/agentsam-rapid-rust +36 -0
  58. package/docs/AUTH_IDENTITY_CONTRACT.md +2 -0
  59. package/docs/BRAND_INTELLIGENCE.md +1 -1
  60. package/docs/MACHINE_INTELLIGENCE.md +120 -0
  61. package/docs/WINDOWS_RUNTIME_INSTALL.md +30 -0
  62. package/docs/architecture/AGENTSAM_APPLICATION_CONTRACT.md +188 -0
  63. package/docs/architecture/AGENTSAM_DISTRIBUTION_OWNERSHIP.md +176 -0
  64. package/docs/architecture/AGENTSAM_GO_RUNTIME.md +282 -0
  65. package/docs/architecture/AGENTSAM_RUNTIME_PROTOCOL.md +151 -0
  66. package/docs/architecture/CODEBASEINDEX_GUIDED_PATH.md +202 -0
  67. package/docs/architecture/FS_E2E_CLOSURE_RECEIPT.md +59 -0
  68. package/docs/architecture/LOCAL_FS_AUTHORITY.md +38 -0
  69. package/docs/architecture/LOCAL_STUDIO_CLOUDFLARE_OAUTH.md +36 -0
  70. package/docs/architecture/PLAN_CLI_AND_LOCAL_STUDIO_DESKTOP.md +96 -0
  71. package/docs/architecture/R2_SLUG_NAMESPACE.md +20 -0
  72. package/docs/architecture/SAM_ACTIVITY_RECOVERY_RECEIPT.md +39 -0
  73. package/docs/architecture/SAM_DECISION_WORK_RECEIPT.md +54 -0
  74. package/docs/architecture/SAM_KERNEL.md +181 -0
  75. package/docs/architecture/SAM_MACHINE_NORMALIZATION_PRECOMMIT_REPORT.md +208 -0
  76. package/docs/architecture/SLASH_SKILLS_PORTABLE.md +116 -0
  77. package/docs/architecture/WORK_PRODUCT_EXTRACTION.md +97 -0
  78. package/docs/architecture/fs-e2e-receipt.latest.json +42 -0
  79. package/docs/architecture/previews/codebaseindex-guided-path/CODEBASEINDEX_GUIDED_PATH.md +202 -0
  80. package/docs/architecture/previews/codebaseindex-guided-path/index.html +321 -0
  81. package/docs/brand/AGENT_SAM_ICON_GRAMMAR.md +70 -0
  82. package/docs/content-studio/HOST_MOUNT_CHECKLIST.md +71 -0
  83. package/docs/content-studio/REVISION_GATE_2026-09-27.md +501 -0
  84. package/docs/contracts/capability-install-planner.md +67 -0
  85. package/docs/contracts/environment-vocabulary.md +195 -0
  86. package/docs/contracts/google-cloud-oauth-setup.md +199 -0
  87. package/docs/local-studio/WORKMODE_DONOR_NOTES.md +1 -1
  88. package/docs/plans/LOCAL-STUDIO-GRADUATION-2026-09-26.md +290 -0
  89. package/docs/plans/LOCAL-STUDIO-REAL-APP-CONTRACT-ADDENDUM-2026-09-27.md +394 -0
  90. package/docs/plans/MACHINE-FIRST-APPS-TUI-2026-09-24.md +227 -0
  91. package/docs/plans/TOMORROW-EXTENSIVE-TODO-2026-09-26.md +221 -0
  92. package/docs/plans/TOMORROW-MACHINE-FIRST-BRIEFING.md +145 -0
  93. package/docs/plans/UNIVERSAL-INGEST-MACHINE-FIRST-2026-09-24.md +215 -0
  94. package/docs/plugins.md +2 -2
  95. package/docs/product/AGENTSAM_PRODUCT_EXPERIENCE_STANDARD.md +280 -0
  96. package/docs/product/LOCAL_STUDIO_DESKTOP_EXPERIENCE.md +139 -0
  97. package/docs/product/README.md +8 -0
  98. package/docs/rapid-rust-wasm.md +35 -0
  99. package/migrations/d1/0010_portable_tickets_memory.sql +140 -0
  100. package/migrations/d1/0011_agentsam_skill_v2.sql +185 -0
  101. package/migrations/d1/0011b_agentsam_skill_v2_cutover.sql +22 -0
  102. package/migrations/d1/0011c_agentsam_skill_v2_backfill.sql +76 -0
  103. package/migrations/d1/0011d_agentsam_skill_v2_retrieval_revisions.sql +50 -0
  104. package/migrations/d1/0012_agentsam_tools_required_seed.sql +67 -0
  105. package/migrations/d1/0013_identity_oauth_states.sql +15 -0
  106. package/migrations/d1/0014_auth_event_log.sql +20 -0
  107. package/migrations/d1/0015_identity_oauth_state_app_id.sql +3 -0
  108. package/migrations/d1/0016_cloudflare_oauth_user_oauth_tokens_ssot.sql +14 -0
  109. package/migrations/d1/README_PORTABLE_CONTROL_PLANE.md +16 -0
  110. package/migrations/sqlite/agentsam_skill_retrieval.portable.sql +42 -0
  111. package/package.json +88 -14
  112. package/packages/agentsam-brand/README.md +106 -11
  113. package/packages/agentsam-brand/bin/agentsam-brand.mjs +9 -0
  114. package/packages/agentsam-brand/package.json +39 -7
  115. package/packages/agentsam-brand/src/adapters/cloudflare-images.js +453 -0
  116. package/packages/agentsam-brand/src/adapters/cloudflare-r2.js +74 -0
  117. package/packages/agentsam-brand/src/adapters/d1-registry.js +26 -0
  118. package/packages/agentsam-brand/src/adapters/filesystem.js +59 -0
  119. package/packages/agentsam-brand/src/adapters/memory.js +31 -0
  120. package/packages/agentsam-brand/src/cli/controller.js +503 -0
  121. package/packages/agentsam-brand/src/cli/wizard.js +526 -0
  122. package/packages/agentsam-brand/src/core/capabilities.js +201 -0
  123. package/packages/agentsam-brand/src/core/derivatives.js +211 -0
  124. package/packages/agentsam-brand/src/core/errors.js +12 -0
  125. package/packages/agentsam-brand/src/core/ingest.js +195 -0
  126. package/packages/agentsam-brand/src/core/inspect.js +109 -0
  127. package/packages/agentsam-brand/src/core/keys.js +83 -0
  128. package/packages/agentsam-brand/src/core/naming.js +142 -0
  129. package/packages/agentsam-brand/src/core/optimize.js +316 -0
  130. package/packages/agentsam-brand/src/core/pack.js +305 -0
  131. package/packages/agentsam-brand/src/core/plan.js +276 -0
  132. package/packages/agentsam-brand/src/core/preview.js +159 -0
  133. package/packages/agentsam-brand/src/core/processors/cloudflare.js +68 -0
  134. package/packages/agentsam-brand/src/core/processors/contract.js +203 -0
  135. package/packages/agentsam-brand/src/core/processors/index.js +148 -0
  136. package/packages/agentsam-brand/src/core/processors/native.js +82 -0
  137. package/packages/agentsam-brand/src/core/processors/sharp.js +113 -0
  138. package/packages/agentsam-brand/src/core/processors/squoosh-binary.js +195 -0
  139. package/packages/agentsam-brand/src/core/promote.js +288 -0
  140. package/packages/agentsam-brand/src/core/receipts.js +155 -0
  141. package/packages/agentsam-brand/src/core/v2/compile.js +280 -0
  142. package/packages/agentsam-brand/src/core/v2/derivatives-semantic.js +207 -0
  143. package/packages/agentsam-brand/src/core/v2/ingest-graph.js +387 -0
  144. package/packages/agentsam-brand/src/core/v2/roles.js +180 -0
  145. package/packages/agentsam-brand/src/core/v2/schema.js +209 -0
  146. package/packages/agentsam-brand/src/core/v2/templates.js +114 -0
  147. package/packages/agentsam-brand/src/index.js +193 -36
  148. package/packages/agentsam-brand/src/presets/app-icon.json +16 -0
  149. package/packages/agentsam-brand/src/presets/favicon.json +17 -0
  150. package/packages/agentsam-brand/src/presets/hero.json +12 -0
  151. package/packages/agentsam-brand/src/presets/index.js +40 -0
  152. package/packages/agentsam-brand/src/presets/logo.json +12 -0
  153. package/packages/agentsam-brand/src/presets/model.json +8 -0
  154. package/packages/agentsam-brand/src/presets/og-image.json +10 -0
  155. package/packages/agentsam-brand/src/presets/product-shot.json +11 -0
  156. package/packages/agentsam-brand/src/presets/social-image.json +10 -0
  157. package/packages/agentsam-brand/src/presets/web-image.json +10 -0
  158. package/packages/agentsam-contracts/src/artifacts.ts +41 -0
  159. package/packages/agentsam-contracts/src/errors.ts +16 -0
  160. package/packages/agentsam-errors/src/envelope.js +53 -0
  161. package/packages/agentsam-errors/src/index.js +1 -0
  162. package/packages/agentsam-errors/src/recovery.js +301 -0
  163. package/packages/agentsam-knowledge/src/autorag/index.js +1 -1
  164. package/packages/agentsam-knowledge/src/providers/index.js +20 -6
  165. package/packages/agentsam-knowledge/src/providers/ollama-endpoint.js +31 -0
  166. package/packages/agentsam-knowledge/test/autorag.test.mjs +22 -1
  167. package/packages/agentsam-nav/package.json +2 -2
  168. package/packages/agentsam-rapid-rust/Cargo.lock +344 -0
  169. package/packages/agentsam-rapid-rust/Cargo.toml +18 -0
  170. package/packages/agentsam-rapid-rust/README.md +5 -0
  171. package/packages/agentsam-rapid-rust/src/main.rs +718 -0
  172. package/packages/agentsam-rapid-rust/templates/api/Cargo.toml.tmpl +18 -0
  173. package/packages/agentsam-rapid-rust/templates/api/src/lib.rs.tmpl +17 -0
  174. package/packages/agentsam-rapid-rust/templates/common/README.md.tmpl +22 -0
  175. package/packages/agentsam-rapid-rust/templates/common/package.json.tmpl +12 -0
  176. package/packages/agentsam-rapid-rust/templates/common/wrangler.toml.tmpl +6 -0
  177. package/packages/agentsam-rapid-rust/templates/crypto-auth/Cargo.toml.tmpl +21 -0
  178. package/packages/agentsam-rapid-rust/templates/crypto-auth/src/lib.rs.tmpl +32 -0
  179. package/packages/agentsam-rapid-rust/templates/data-processor/Cargo.toml.tmpl +18 -0
  180. package/packages/agentsam-rapid-rust/templates/data-processor/src/lib.rs.tmpl +41 -0
  181. package/packages/agentsam-rapid-rust/templates/shared-core/Cargo.toml.tmpl +9 -0
  182. package/packages/agentsam-rapid-rust/templates/shared-core/core/Cargo.toml.tmpl +7 -0
  183. package/packages/agentsam-rapid-rust/templates/shared-core/core/src/lib.rs.tmpl +23 -0
  184. package/packages/agentsam-rapid-rust/templates/shared-core/worker/Cargo.toml.tmpl +12 -0
  185. package/packages/agentsam-rapid-rust/templates/shared-core/worker/src/lib.rs.tmpl +16 -0
  186. package/packages/agentsam-rapid-rust/templates/shared-core/wrangler.toml.tmpl +6 -0
  187. package/packages/agentsam-repository/src/index.js +1 -0
  188. package/packages/agentsam-repository/src/merkle/semantic.js +3 -10
  189. package/packages/agentsam-repository/src/source-types.js +85 -0
  190. package/packages/agentsam-vault/README.md +96 -0
  191. package/packages/agentsam-vault/package.json +32 -0
  192. package/packages/agentsam-vault/src/contracts/credential.d.ts +78 -0
  193. package/packages/agentsam-vault/src/contracts/credential.js +132 -0
  194. package/packages/agentsam-vault/src/crypto/aes-gcm.d.ts +30 -0
  195. package/packages/agentsam-vault/src/crypto/aes-gcm.js +107 -0
  196. package/packages/agentsam-vault/src/crypto/oauth-envelope.js +150 -0
  197. package/packages/agentsam-vault/src/index.d.ts +9 -0
  198. package/packages/agentsam-vault/src/index.js +27 -0
  199. package/packages/agentsam-vault/src/providers/registry.js +90 -0
  200. package/packages/agentsam-vault/src/runtime/resolver.js +77 -0
  201. package/packages/agentsam-workbench/README.md +24 -0
  202. package/packages/agentsam-workbench/package.json +38 -0
  203. package/packages/agentsam-workbench/src/agent/AgentPanel.tsx +41 -0
  204. package/packages/agentsam-workbench/src/agent/ArtifactCard.tsx +9 -0
  205. package/packages/agentsam-workbench/src/agent/Composer.tsx +102 -0
  206. package/packages/agentsam-workbench/src/agent/ConnectedAgentPanel.tsx +194 -0
  207. package/packages/agentsam-workbench/src/agent/ContextualComposer.tsx +788 -0
  208. package/packages/agentsam-workbench/src/agent/GoalStatusStrip.tsx +38 -0
  209. package/packages/agentsam-workbench/src/agent/MiniAgentSam.tsx +86 -0
  210. package/packages/agentsam-workbench/src/agent/ModelSelect.tsx +19 -0
  211. package/packages/agentsam-workbench/src/agent/Thread.tsx +56 -0
  212. package/packages/agentsam-workbench/src/agent/ToolReceipt.tsx +11 -0
  213. package/packages/agentsam-workbench/src/agent/contextual-composer.css +611 -0
  214. package/packages/agentsam-workbench/src/agent/index.ts +10 -0
  215. package/packages/agentsam-workbench/src/agent/mini-agentsam.css +12 -0
  216. package/packages/agentsam-workbench/src/browser/BrowserFrame.tsx +37 -0
  217. package/packages/agentsam-workbench/src/browser/index.ts +1 -0
  218. package/packages/agentsam-workbench/src/index.ts +6 -0
  219. package/packages/agentsam-workbench/src/project-control.css +160 -0
  220. package/packages/agentsam-workbench/src/projects/ProjectsSurface.tsx +131 -0
  221. package/packages/agentsam-workbench/src/projects/index.ts +1 -0
  222. package/packages/agentsam-workbench/src/shell/Breadcrumb.tsx +35 -0
  223. package/packages/agentsam-workbench/src/shell/ResizableStage.tsx +99 -0
  224. package/packages/agentsam-workbench/src/shell/SidePanel.tsx +5 -0
  225. package/packages/agentsam-workbench/src/shell/index.ts +4 -0
  226. package/packages/agentsam-workbench/src/shell/surfaceRegistry.ts +29 -0
  227. package/packages/agentsam-workbench/src/terminal/TerminalSurface.tsx +5 -0
  228. package/packages/agentsam-workbench/src/terminal/index.ts +1 -0
  229. package/packages/agentsam-workbench/src/timeline/GanttBoard.tsx +258 -0
  230. package/packages/agentsam-workbench/src/timeline/index.ts +1 -0
  231. package/packages/agentsam-workbench/tsconfig.json +13 -0
  232. package/packages/connectors/cloudflare/OAUTH_STORAGE_AUDIT.md +53 -0
  233. package/packages/connectors/cloudflare/package.json +3 -1
  234. package/packages/connectors/cloudflare/src/api-client.js +279 -0
  235. package/packages/connectors/cloudflare/src/capabilities.js +585 -0
  236. package/packages/connectors/cloudflare/src/credential.js +318 -0
  237. package/packages/connectors/cloudflare/src/families/brand-protection.js +123 -0
  238. package/packages/connectors/cloudflare/src/families/keyless.js +114 -0
  239. package/packages/connectors/cloudflare/src/families/pages.js +151 -0
  240. package/packages/connectors/cloudflare/src/families/scanner.js +123 -0
  241. package/packages/connectors/cloudflare/src/families/snippets.js +207 -0
  242. package/packages/connectors/cloudflare/src/families/tag-gateway.js +46 -0
  243. package/packages/connectors/cloudflare/src/families/tags.js +124 -0
  244. package/packages/connectors/cloudflare/src/families/token-validation.js +95 -0
  245. package/packages/connectors/cloudflare/src/families/workflows.js +156 -0
  246. package/packages/connectors/cloudflare/src/index.js +102 -265
  247. package/packages/connectors/cloudflare/src/oauth-persist.js +336 -0
  248. package/packages/connectors/cloudflare/src/owner.js +42 -12
  249. package/packages/connectors/cloudflare/src/permission-options.js +1064 -0
  250. package/packages/connectors/cloudflare/src/routes.js +318 -144
  251. package/packages/connectors/cloudflare/src/scope-catalog.js +345 -0
  252. package/packages/connectors/cloudflare/src/vault.js +2 -2
  253. package/packages/connectors/cloudflare/tests/capabilities.test.mjs +276 -0
  254. package/packages/connectors/cloudflare/tests/connector.test.mjs +51 -30
  255. package/packages/connectors/cloudflare/tests/oauth-persist.test.mjs +125 -0
  256. package/packages/identity/.agentsam/features/oauth-login-portal/agentsam.feature.json +1 -1
  257. package/packages/identity/.agentsam/features/oauth-login-portal/providers.json +22 -2
  258. package/packages/identity/.agentsam/features/oauth-login-portal/resources.json +10 -4
  259. package/packages/identity/.agentsam/features/oauth-login-portal/routes.json +31 -2
  260. package/packages/identity/README.md +1 -1
  261. package/packages/identity/backend/README.md +1 -1
  262. package/packages/identity/docs/PORTABLE_IDENTITY_ARCHITECTURE.md +50 -0
  263. package/packages/identity/migrations/D1_SCHEMA_MAPPING.md +32 -0
  264. package/packages/identity/migrations/sqlite/001_identity_core.sql +99 -0
  265. package/packages/identity/migrations/sqlite/002_identity_oauth_client.sql +38 -0
  266. package/packages/identity/migrations/sqlite/003_identity_oauth_server.sql +64 -0
  267. package/packages/identity/migrations/sqlite/004_identity_oauth_consent_catalog.sql +48 -0
  268. package/packages/identity/package.json +3 -2
  269. package/packages/identity/scripts/local-identity-bridge.mjs +184 -0
  270. package/packages/identity/scripts/preview-auth-portal.mjs +7 -7
  271. package/packages/identity/src/adapters/cloudflare-d1/index.js +153 -24
  272. package/packages/identity/src/adapters/sqlite/index.js +322 -0
  273. package/packages/identity/src/app/verify-app.js +95 -0
  274. package/packages/identity/src/contracts/auth-config.js +28 -8
  275. package/packages/identity/src/contracts/external-identity.js +1 -1
  276. package/packages/identity/src/contracts/identity-store.js +115 -0
  277. package/packages/identity/src/contracts/provider.js +1 -0
  278. package/packages/identity/src/contracts/route-ids.js +30 -0
  279. package/packages/identity/src/contracts/route-projection.js +218 -0
  280. package/packages/identity/src/contracts/routes.js +11 -0
  281. package/packages/identity/src/core/browser-paths.js +4 -5
  282. package/packages/identity/src/core/constants.js +13 -8
  283. package/packages/identity/src/core/session-policy.js +32 -0
  284. package/packages/identity/src/frontend/auth-portal/README.md +2 -1
  285. package/packages/identity/src/frontend/auth-portal/pages/login.html +16 -15
  286. package/packages/identity/src/frontend/auth-portal/pages/reset.html +9 -8
  287. package/packages/identity/src/frontend/auth-portal/pages/signup.html +9 -8
  288. package/packages/identity/src/frontend/auth-portal/preview/dashboard-stub.html +1 -1
  289. package/packages/identity/src/frontend/auth-portal/shared/company-branding.js +1 -1
  290. package/packages/identity/src/frontend/auth-portal/shared/desktop-identity-bridge.js +207 -0
  291. package/packages/identity/src/index.js +41 -0
  292. package/packages/identity/src/migrations/0001_identity_core.sql +19 -2
  293. package/packages/identity/src/migrations/0003_accounts_ssot.sql +20 -0
  294. package/packages/identity/src/migrations/README.md +5 -2
  295. package/packages/identity/src/oauth/README.md +19 -8
  296. package/packages/identity/src/oauth/consent-view.js +388 -0
  297. package/packages/identity/src/oauth/credentials.js +46 -19
  298. package/packages/identity/src/oauth/finalize-inbound.js +1 -1
  299. package/packages/identity/src/oauth/google-desktop-exchange.js +173 -0
  300. package/packages/identity/src/oauth/iam-platform.js +8 -7
  301. package/packages/identity/src/oauth/redirect-paths.js +27 -36
  302. package/packages/identity/src/providers/cloudflare/oauth.js +3 -4
  303. package/packages/identity/src/providers/cloudflare/profile.js +49 -14
  304. package/packages/identity/src/providers/iam/index.js +27 -5
  305. package/packages/identity/src/server/identity-service.js +61 -15
  306. package/packages/identity/src/server/mount-policy.js +30 -0
  307. package/packages/identity/src/server/post-auth.js +79 -0
  308. package/packages/identity/src/server/worker-router.js +208 -146
  309. package/packages/identity/tests/auth-config.test.mjs +3 -2
  310. package/packages/identity/tests/finalize-inbound-oauth.test.mjs +6 -6
  311. package/packages/identity/tests/iam-provider.test.mjs +1 -1
  312. package/packages/identity/tests/identity-init-scaffold.test.mjs +3 -0
  313. package/packages/identity/tests/identity-service.test.mjs +52 -5
  314. package/packages/identity/tests/native-session-worker.test.mjs +64 -0
  315. package/packages/identity/tests/oauth-consent-view.test.mjs +106 -0
  316. package/packages/identity/tests/oauth-credentials.test.mjs +20 -5
  317. package/packages/identity/tests/oauth-presets-accounts-ssot.test.mjs +58 -0
  318. package/packages/identity/tests/portable-identity-architecture.test.mjs +157 -0
  319. package/packages/identity/tests/preview-auth-portal.test.mjs +3 -3
  320. package/packages/identity/tests/session-routes-policy.test.mjs +21 -0
  321. package/packages/runtime-protocol/src/index.js +154 -0
  322. package/packages/theme-church-site/package.json +2 -1
  323. package/packages/theme-church-site/src/index.js +1 -0
  324. package/packages/theme-companions-site/package.json +2 -1
  325. package/packages/theme-companions-site/src/index.js +1 -0
  326. package/packages/theme-floors-site/package.json +2 -1
  327. package/packages/theme-floors-site/src/index.js +1 -0
  328. package/packages/theme-fuelnfree-site/package.json +2 -1
  329. package/packages/theme-fuelnfree-site/src/index.js +1 -0
  330. package/packages/theme-handyman-site/package.json +2 -1
  331. package/packages/theme-handyman-site/src/index.js +1 -0
  332. package/packages/theme-insurance-site/package.json +2 -1
  333. package/packages/theme-insurance-site/src/index.js +1 -0
  334. package/packages/theme-scenes/README.md +164 -0
  335. package/packages/theme-scenes/package.json +53 -0
  336. package/packages/theme-scenes/src/blocks/index.js +30 -0
  337. package/packages/theme-scenes/src/contracts/index.js +286 -0
  338. package/packages/theme-scenes/src/demos/index.js +65 -0
  339. package/packages/theme-scenes/src/index.js +75 -0
  340. package/packages/theme-scenes/src/presets/index.js +263 -0
  341. package/packages/theme-scenes/src/runtime/compile.js +119 -0
  342. package/packages/theme-scenes/src/scenes/index.js +146 -0
  343. package/packages/theme-scenes/src/shell/index.js +47 -0
  344. package/packages/theme-scenes/src/themes/index.js +129 -0
  345. package/packages/theme-scenes/src/visuals/index.js +41 -0
  346. package/packages/theme-scenes/test/theme-scenes.test.mjs +179 -0
  347. package/packages/theme-shinshu-site/package.json +2 -1
  348. package/packages/theme-shinshu-site/src/index.js +1 -0
  349. package/packages/work-graph/src/index.js +34 -1
  350. package/packages/work-graph/src/renderers/gantt-model.js +24 -0
  351. package/packages/work-graph/test/work-graph.test.mjs +27 -7
  352. package/protocol/README.md +15 -7
  353. package/protocol/apps/agentsam.app.v1.schema.json +133 -0
  354. package/protocol/apps/agentsam.host-install.v1.schema.json +36 -0
  355. package/protocol/assets/README.md +9 -0
  356. package/protocol/assets/asset-record.v1.schema.json +64 -0
  357. package/protocol/brand/brandpack.v1.schema.json +43 -0
  358. package/protocol/credentials/issue.v1.schema.json +38 -0
  359. package/protocol/database/connection.v1.schema.json +41 -0
  360. package/protocol/embeddings/embedding-profile.v1.schema.json +20 -0
  361. package/protocol/errors/error-envelope.schema.json +135 -1
  362. package/protocol/errors/recovery.v1.schema.json +50 -0
  363. package/protocol/runtime/agentsam.runtime.v1.schema.json +75 -0
  364. package/protocol/runtime/workspace-fs.v1.schema.json +71 -0
  365. package/protocol/sam/activity.v1.schema.json +48 -0
  366. package/protocol/sam/answer.v1.schema.json +35 -0
  367. package/protocol/sam/calibration.v1.schema.json +21 -0
  368. package/protocol/sam/decision-receipt.v1.schema.json +29 -0
  369. package/protocol/sam/evaluation.v1.schema.json +19 -0
  370. package/protocol/sam/operation.schema.json +66 -0
  371. package/protocol/sam/outcome.v1.schema.json +36 -0
  372. package/protocol/sam/question.v1.schema.json +26 -0
  373. package/protocol/sam/registry.seed.json +153 -0
  374. package/protocol/sam/result.schema.json +53 -0
  375. package/protocol/sam/state.v1.schema.json +23 -0
  376. package/protocol/scoring/README.md +10 -0
  377. package/protocol/scoring/scorecard.v1.schema.json +65 -0
  378. package/protocol/skills/agentsam.interaction.v1.schema.json +50 -0
  379. package/protocol/skills/agentsam.skill.v1.schema.json +57 -0
  380. package/protocol/ui/icon-registry.mjs +227 -0
  381. package/protocol/ui/icon.v1.schema.json +51 -0
  382. package/registry/cms-rust-machine-20260928/installable-products.json +31 -0
  383. package/registry/cms-rust-machine-20260928/manifest.json +22 -0
  384. package/registry/cms-rust-machine-20260928/migration.sql +237 -0
  385. package/registry/cms-rust-machine-20260928/receipt.json +21 -0
  386. package/registry/cms-rust-machine-20260928/receipt.sql +27 -0
  387. package/scripts/build_rapid_rust_cli.py +83 -0
  388. package/skills/README.md +22 -9
  389. package/skills/agentsam-codebaseindex/SKILL.md +225 -0
  390. package/skills/catalog.json +14 -0
  391. package/src/attachments/index.js +6 -0
  392. package/src/attachments/intake.js +235 -0
  393. package/src/capabilities/repository-snapshot.js +19 -2
  394. package/src/cli/command-catalog.js +138 -0
  395. package/src/cli/dispatch.js +48 -0
  396. package/src/cli.js +225 -27
  397. package/src/commands/account-auth.js +94 -8
  398. package/src/commands/api-key.js +244 -0
  399. package/src/commands/app.js +365 -29
  400. package/src/commands/billing.js +127 -0
  401. package/src/commands/brand.js +86 -74
  402. package/src/commands/cheat-sheet.js +154 -0
  403. package/src/commands/cloudflare-login.js +222 -0
  404. package/src/commands/cloudflare.js +453 -23
  405. package/src/commands/codebaseindex.js +693 -0
  406. package/src/commands/compute.js +4 -0
  407. package/src/commands/connections.js +11 -5
  408. package/src/commands/credentials.js +116 -0
  409. package/src/commands/env.js +152 -25
  410. package/src/commands/gcloud-auth.js +427 -0
  411. package/src/commands/go.js +366 -53
  412. package/src/commands/google-cloud.js +375 -0
  413. package/src/commands/identity-init.js +2 -2
  414. package/src/commands/interaction-clack.js +115 -0
  415. package/src/commands/mcp.js +226 -33
  416. package/src/commands/models.js +1 -1
  417. package/src/commands/ollama.js +3 -2
  418. package/src/commands/plugins.js +7 -2
  419. package/src/commands/product.js +36 -0
  420. package/src/commands/providers.js +62 -14
  421. package/src/commands/runtime-status.js +28 -9
  422. package/src/commands/runtime.js +313 -0
  423. package/src/commands/rust.js +24 -0
  424. package/src/commands/setup.js +279 -0
  425. package/src/commands/shell.js +59 -5
  426. package/src/commands/skill.js +248 -0
  427. package/src/commands/skills.js +1 -1
  428. package/src/commands/start-local.js +6 -2
  429. package/src/commands/terminal.js +171 -0
  430. package/src/commands/update.js +140 -0
  431. package/src/commands/whoami.js +392 -56
  432. package/src/features/resolve.js +1 -0
  433. package/src/go/build.js +229 -39
  434. package/src/go/cloudflare.js +506 -105
  435. package/src/go/container.js +120 -0
  436. package/src/go/contract.js +9 -4
  437. package/src/go/discover.js +149 -33
  438. package/src/go/index.js +15 -3
  439. package/src/go/native-probe-runner.mjs +119 -0
  440. package/src/go/{registry.js → official-registry.js} +64 -7
  441. package/src/go/official-release.js +10 -0
  442. package/src/go/receipts.js +77 -10
  443. package/src/go/verify.js +9 -2
  444. package/src/index.js +31 -0
  445. package/src/indexing/ingest/discover-models.js +298 -0
  446. package/src/indexing/ingest/inventory.js +478 -0
  447. package/src/indexing/ingest/job-graph.js +181 -0
  448. package/src/indexing/ingest/materials.js +204 -0
  449. package/src/indexing/ingest/style-evidence.js +181 -0
  450. package/src/knowledge/source.js +3 -3
  451. package/src/lib/account-session.js +11 -4
  452. package/src/lib/app-authority.js +172 -0
  453. package/src/lib/auth.js +94 -21
  454. package/src/lib/core-client.js +5 -6
  455. package/src/lib/credentials-audit.js +451 -0
  456. package/src/lib/deploy/health.js +24 -6
  457. package/src/lib/detect-context.js +7 -1
  458. package/src/lib/google-cloud-connection.js +270 -0
  459. package/src/lib/google-cloud-inventory.js +385 -0
  460. package/src/lib/google-desktop-oauth.js +372 -0
  461. package/src/lib/google-studio-brokered-oauth.js +158 -0
  462. package/src/lib/identity-scaffold.js +24 -6
  463. package/src/lib/init-options.js +192 -0
  464. package/src/lib/local-scaffold.js +48 -16
  465. package/src/lib/provider-command-remediation.js +308 -0
  466. package/src/lib/provider-credentials.js +71 -21
  467. package/src/lib/scaffold/index.js +8 -2
  468. package/src/lib/scaffold/mcp-server.js +43 -0
  469. package/src/lib/scaffold/templates/mcp-server/index.js +397 -0
  470. package/src/lib/scaffold/templates/mcp-server/presets.js +39 -0
  471. package/src/lib/scaffold/wizards/cms.js +93 -0
  472. package/src/lib/scaffold/wizards/mcp-server.js +61 -0
  473. package/src/lib/setup/contract.js +26 -0
  474. package/src/lib/setup/discover.js +116 -0
  475. package/src/lib/setup/execute.js +205 -0
  476. package/src/lib/setup/planner.js +134 -0
  477. package/src/lib/setup/recipes.js +235 -0
  478. package/src/lib/setup/runtime-persist.js +197 -0
  479. package/src/lib/setup/runtime.js +394 -0
  480. package/src/lib/slash-commands.js +3 -0
  481. package/src/lib/terminal/machine-identity.js +95 -0
  482. package/src/lib/terminal-local.js +164 -0
  483. package/src/lib/terminal-scopes.js +52 -0
  484. package/src/lib/whoami-capabilities.js +184 -0
  485. package/src/local-fs/capability.js +121 -0
  486. package/src/local-fs/freshness.js +75 -0
  487. package/src/local-fs/index.js +385 -0
  488. package/src/local-fs/paths.js +100 -0
  489. package/src/local-pty/server.js +326 -21
  490. package/src/mcp/authority.js +58 -108
  491. package/src/mcp/client-adapters.js +68 -144
  492. package/src/mcp/client.js +142 -122
  493. package/src/mcp/cloudflare-bundles.js +225 -0
  494. package/src/mcp/index.js +12 -0
  495. package/src/models/ai-access-onboarding.js +112 -0
  496. package/src/models/discovery.js +10 -2
  497. package/src/models/inventory-core.js +9 -1
  498. package/src/plugins/cloudflare.js +1 -1
  499. package/src/providers/ollama-chat.js +2 -1
  500. package/src/sam/activity/index.js +183 -0
  501. package/src/sam/client.js +252 -0
  502. package/src/sam/decision/calibration.js +109 -0
  503. package/src/sam/decision/confidence.js +126 -0
  504. package/src/sam/decision/evaluate.js +157 -0
  505. package/src/sam/decision/evaluators/deterministic.js +341 -0
  506. package/src/sam/decision/evaluators/heuristic.js +61 -0
  507. package/src/sam/decision/evaluators/select.js +50 -0
  508. package/src/sam/decision/evaluators/semantic.js +149 -0
  509. package/src/sam/decision/hierarchical.js +61 -0
  510. package/src/sam/decision/index.js +53 -0
  511. package/src/sam/decision/policy.js +86 -0
  512. package/src/sam/decision/questions.js +120 -0
  513. package/src/sam/decision/receipt.js +148 -0
  514. package/src/sam/decision/state.js +117 -0
  515. package/src/sam/decision/types.js +22 -0
  516. package/src/sam/decision/validate.js +200 -0
  517. package/src/sam/define.js +51 -0
  518. package/src/sam/index.js +65 -0
  519. package/src/sam/operations/brand-scan.js +62 -0
  520. package/src/sam/operations/cad-blender-inspect.js +36 -0
  521. package/src/sam/operations/codebaseindex-ingest.js +49 -0
  522. package/src/sam/operations/decision-evaluate.js +59 -0
  523. package/src/sam/operations/planning-astar.js +77 -0
  524. package/src/sam/operations/planning-goap.js +60 -0
  525. package/src/sam/operations/repository-inspect.js +72 -0
  526. package/src/sam/operations/security-scan.js +33 -0
  527. package/src/sam/operations/terminal-exec.js +29 -0
  528. package/src/sam/planning/astar.js +311 -0
  529. package/src/sam/planning/goap.js +177 -0
  530. package/src/sam/planning/index.js +21 -0
  531. package/src/sam/planning/state.js +84 -0
  532. package/src/sam/registry.js +48 -0
  533. package/src/sam/result.js +77 -0
  534. package/src/sam/seed.js +44 -0
  535. package/src/sam/types.js +116 -0
  536. package/src/security/inventory.js +12 -2
  537. package/src/security/local-vault.js +2 -0
  538. package/src/security/scan.js +1 -1
  539. package/src/skills/catalog.js +64 -0
  540. package/src/skills/content-resolver.js +124 -0
  541. package/src/skills/hosted-store.js +37 -0
  542. package/src/skills/index.js +29 -64
  543. package/src/skills/interaction.js +102 -0
  544. package/src/skills/local-store.js +228 -0
  545. package/src/skills/manifest.js +104 -0
  546. package/src/skills/metrics.js +31 -0
  547. package/src/skills/registry.js +184 -0
  548. package/src/skills/runtime.js +287 -0
  549. package/src/skills/slash.js +44 -0
  550. package/src/ui/cli/help.js +94 -101
  551. package/test/account-session.test.mjs +3 -3
  552. package/test/app-authority-context.test.mjs +32 -0
  553. package/test/cli/api-key-env-whoami.test.mjs +129 -0
  554. package/test/cli/codebaseindex-plan-ux.test.mjs +37 -0
  555. package/test/cli/go.test.mjs +62 -5
  556. package/test/cli/mcp-client.test.mjs +21 -10
  557. package/test/cli/runtime-persist.test.mjs +56 -0
  558. package/test/cli/rust-command.test.mjs +21 -0
  559. package/test/cli/skill-npm-and-env.test.mjs +52 -0
  560. package/test/cli/wireframes-go-registry.test.mjs +87 -2
  561. package/test/credentials-audit.test.mjs +113 -0
  562. package/test/deploy-health-scan.test.mjs +29 -1
  563. package/test/gcloud-auth.test.mjs +111 -0
  564. package/test/go/build-source-identity.test.mjs +31 -0
  565. package/test/go/cloudflare-probe.test.mjs +274 -10
  566. package/test/go/distribution.test.mjs +28 -0
  567. package/test/google-cloud-connection.test.mjs +83 -0
  568. package/test/google-cloud-inventory.test.mjs +64 -0
  569. package/test/init-options.test.mjs +35 -0
  570. package/test/integration/ai-access-onboarding.test.mjs +47 -0
  571. package/test/integration/app-command.test.mjs +30 -0
  572. package/test/integration/cad-project.test.mjs +4 -1
  573. package/test/integration/cli-help.test.mjs +1 -1
  574. package/test/integration/cms-app-scaffold.test.mjs +71 -0
  575. package/test/integration/cms-site-tenancy-contract.test.mjs +9 -8
  576. package/test/integration/codebaseindex-ingest.test.mjs +214 -0
  577. package/test/integration/features-resolve.test.mjs +30 -11
  578. package/test/integration/icon-registry.test.mjs +67 -0
  579. package/test/integration/ingest-discover-models.test.mjs +30 -0
  580. package/test/integration/inspect-path-cli.test.mjs +46 -0
  581. package/test/integration/install-script.test.mjs +12 -9
  582. package/test/integration/inventory-evidence.test.mjs +125 -0
  583. package/test/integration/local-fs.test.mjs +113 -0
  584. package/test/integration/provider-env-cli.test.mjs +2 -1
  585. package/test/integration/runtime-status.integration.test.mjs +2 -1
  586. package/test/integration/sam-activity-recovery.test.mjs +147 -0
  587. package/test/integration/sam-decision.test.mjs +584 -0
  588. package/test/integration/sam-kernel.test.mjs +99 -0
  589. package/test/integration/sam-planning-astar.test.mjs +279 -0
  590. package/test/integration/skill-runtime.test.mjs +240 -0
  591. package/test/integration/studio-fs-pty-e2e.test.mjs +294 -0
  592. package/test/knowledge.test.mjs +35 -1
  593. package/test/loopback-oauth.test.mjs +53 -0
  594. package/test/models.test.mjs +14 -7
  595. package/test/ollama.test.mjs +22 -0
  596. package/test/security.test.mjs +23 -0
  597. package/test/setup-planner.test.mjs +74 -0
  598. package/test/setup-runtime.test.mjs +51 -0
  599. package/test/shell.test.mjs +4 -4
  600. package/test/terminal/local-pty.mock.test.mjs +3 -1
  601. package/test/terminal-machine-identity.test.mjs +88 -0
  602. package/test/whoami-resume.test.mjs +27 -6
  603. package/packages/agentsam-brand/test/brand-scan.test.mjs +0 -106
  604. package/packages/work-graph/prototype/README.md +0 -32
  605. package/packages/work-graph/prototype/data/demo-workgraph.js +0 -47
  606. package/packages/work-graph/prototype/renderers/timeline-model.js +0 -21
  607. package/packages/work-graph/prototype/renderers/workgraph-runtime.js +0 -38
  608. package/packages/work-graph/prototype-gnantt.html +0 -655
@@ -52,40 +52,60 @@ describe('cloudflare connector', () => {
52
52
  });
53
53
 
54
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
- };
55
+ const oauthState = new Map();
65
56
  const response = await handleCloudflareConnectionRequest(
66
57
  new Request('https://agentsam.example/api/connections/cloudflare/start?return_to=https://untrusted.example/after', {
67
- headers: { authorization: 'Bearer fixture' },
58
+ headers: {
59
+ authorization: 'Bearer fixture',
60
+ accept: 'application/json',
61
+ },
68
62
  }),
69
63
  {
70
- DB,
64
+ oauthState,
71
65
  fixtureSessions: new Map([['fixture', 'user_123']]),
72
66
  CLOUDFLARE_OAUTH_CLIENT_ID: 'real-client-id',
73
67
  },
74
68
  );
75
69
  assert.equal(response.status, 200);
76
- assert.equal(
77
- calls.some((call) => call.sql.includes('DELETE FROM agentsam_cloudflare_oauth_state WHERE created_at < unixepoch() - 600')),
78
- true,
70
+ const body = await response.json();
71
+ assert.equal(body.ok, true);
72
+ assert.equal(oauthState.size, 1);
73
+ const stored = [...oauthState.values()][0];
74
+ assert.equal(stored.returnTo, '');
75
+ });
76
+
77
+ it('redirects browser starts to Cloudflare authorization', async () => {
78
+ const oauthState = new Map();
79
+ const response = await handleCloudflareConnectionRequest(
80
+ new Request('https://agentsam.example/api/connections/cloudflare/start', {
81
+ headers: { authorization: 'Bearer fixture' },
82
+ }),
83
+ {
84
+ fixtureSessions: new Map([['fixture', 'user_123']]),
85
+ oauthState,
86
+ CLOUDFLARE_OAUTH_CLIENT_ID: 'real-client-id',
87
+ },
79
88
  );
80
- const stateInsert = calls.find((call) => call.sql.includes('INSERT INTO agentsam_cloudflare_oauth_state'));
81
- assert.ok(stateInsert);
82
- assert.equal(stateInsert.args.at(-1), null);
89
+
90
+ assert.equal(response.status, 302);
91
+ const location = new URL(response.headers.get('location'));
92
+ assert.equal(location.origin, 'https://dash.cloudflare.com');
93
+ assert.equal(location.pathname, '/oauth2/auth');
94
+ assert.equal(location.searchParams.get('client_id'), 'real-client-id');
95
+ assert.equal(location.searchParams.get('redirect_uri'), 'https://agentsam.example/api/connections/cloudflare/callback');
96
+ assert.equal(oauthState.size, 1);
83
97
  });
84
98
 
85
99
  it('consumes callback state and stores only encrypted OAuth tokens', async () => {
86
- const now = Math.floor(Date.now() / 1000);
87
100
  const calls = [];
88
- const statements = [];
101
+ const oauthState = new Map([
102
+ ['state_123', {
103
+ ownerId: 'user_123',
104
+ verifier: 'verifier',
105
+ returnTo: '',
106
+ createdAt: Math.floor(Date.now() / 1000),
107
+ }],
108
+ ]);
89
109
  const DB = {
90
110
  prepare(sql) {
91
111
  const statement = {
@@ -96,9 +116,6 @@ describe('cloudflare connector', () => {
96
116
  return this;
97
117
  },
98
118
  async first() {
99
- if (sql.includes('agentsam_cloudflare_oauth_state')) {
100
- return { owner_id: 'user_123', code_verifier: 'verifier', created_at: now };
101
- }
102
119
  return null;
103
120
  },
104
121
  async run() {
@@ -106,7 +123,6 @@ describe('cloudflare connector', () => {
106
123
  return { success: true };
107
124
  },
108
125
  };
109
- statements.push(statement);
110
126
  return statement;
111
127
  },
112
128
  async batch(batchStatements) {
@@ -121,7 +137,7 @@ describe('cloudflare connector', () => {
121
137
  return new Response(JSON.stringify({
122
138
  access_token: 'access-plaintext',
123
139
  refresh_token: 'refresh-plaintext',
124
- account_id: 'account_123',
140
+ account_id: 'abc123abc123abc123abc123abc123ab',
125
141
  scope: 'd1.read workers-scripts.write',
126
142
  expires_in: 3600,
127
143
  }), { status: 200, headers: { 'content-type': 'application/json' } });
@@ -132,6 +148,7 @@ describe('cloudflare connector', () => {
132
148
  new Request('https://agentsam.example/api/connections/cloudflare/callback?code=code_123&state=state_123'),
133
149
  {
134
150
  DB,
151
+ oauthState,
135
152
  CLOUDFLARE_OAUTH_CLIENT_ID: 'real-client-id',
136
153
  CLOUDFLARE_OAUTH_CLIENT_SECRET: 'obsolete-secret-must-not-be-sent',
137
154
  VAULT_MASTER_KEY: '01234567890123456789012345678901',
@@ -142,11 +159,15 @@ describe('cloudflare connector', () => {
142
159
  response.headers.get('location'),
143
160
  'https://agentsam.example/settings/integrations?connection=cloudflare&result=connected',
144
161
  );
145
- assert.equal(calls.some((call) => call.sql.includes('DELETE FROM agentsam_cloudflare_oauth_state')), true);
146
- const insert = calls.find((call) => call.sql.includes('INSERT INTO agentsam_cloudflare_connections'));
147
- assert.ok(insert);
148
- assert.notEqual(insert.args[4], 'access-plaintext');
149
- assert.notEqual(insert.args[5], 'refresh-plaintext');
162
+ assert.equal(oauthState.has('state_123'), false);
163
+ const insert = calls.find((call) => call.sql.includes('INSERT INTO user_oauth_tokens'));
164
+ assert.ok(insert, 'expected user_oauth_tokens insert (SSOT)');
165
+ // With vault: plaintext args are null; ciphertext is not plaintext tokens.
166
+ assert.equal(insert.args[3], null); // access_token plaintext
167
+ assert.equal(insert.args[4], null); // refresh_token plaintext
168
+ assert.notEqual(insert.args[5], 'access-plaintext'); // access_token_encrypted
169
+ assert.notEqual(insert.args[6], 'refresh-plaintext'); // refresh_token_encrypted
170
+ assert.equal(calls.some((call) => call.sql.includes('agentsam_cloudflare_connections')), false);
150
171
  } finally {
151
172
  globalThis.fetch = originalFetch;
152
173
  }
@@ -0,0 +1,125 @@
1
+ import assert from 'node:assert/strict';
2
+ import { describe, it } from 'node:test';
3
+ import {
4
+ resolveCloudflareAccountId,
5
+ unionScopes,
6
+ upsertCloudflareUserOauthToken,
7
+ } from '../src/oauth-persist.js';
8
+
9
+ describe('oauth-persist spine', () => {
10
+ it('unions scopes without duplicates', () => {
11
+ assert.deepEqual(
12
+ unionScopes(['d1.read', 'offline_access'], ['d1.read', 'workers-scripts.write']).sort(),
13
+ ['d1.read', 'offline_access', 'workers-scripts.write'].sort(),
14
+ );
15
+ });
16
+
17
+ it('requires explicit selection when Cloudflare exposes multiple accounts', async () => {
18
+ const result = await resolveCloudflareAccountId('token', {
19
+ fetchImpl: async () => ({
20
+ ok: true,
21
+ async json() {
22
+ return {
23
+ result: [
24
+ { id: 'aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa', name: 'A' },
25
+ { id: 'bbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbb', name: 'B' },
26
+ ],
27
+ };
28
+ },
29
+ }),
30
+ });
31
+ assert.equal(result?.error, 'cloudflare_account_selection_required');
32
+ assert.equal(result?.accounts?.length, 2);
33
+ });
34
+
35
+ it('rejects provider labels and synthetic values as account identifiers', async () => {
36
+ const result = await upsertCloudflareUserOauthToken(
37
+ { DB: { prepare() { throw new Error('should not query'); } } },
38
+ { userId: 'au_1', accessToken: 'token', accountId: 'Cloudflare' },
39
+ );
40
+ assert.equal(result.ok, false);
41
+ assert.equal(result.error, 'cloudflare_account_identifier_required');
42
+ });
43
+
44
+ it('upserts with client_id provenance and scope union (no connected_via_app)', async () => {
45
+ const rows = new Map();
46
+ const sqlSeen = [];
47
+ const env = {
48
+ VAULT_MASTER_KEY: 'test-vault-material',
49
+ DB: {
50
+ prepare(sql) {
51
+ sqlSeen.push(String(sql));
52
+ return {
53
+ bind(...args) {
54
+ return {
55
+ async first() {
56
+ if (String(sql).includes('SELECT')) {
57
+ return rows.get(`${args[0]}|${args[2]}`) || null;
58
+ }
59
+ return null;
60
+ },
61
+ async run() {
62
+ if (String(sql).includes('INSERT')) {
63
+ // Encrypted-only path: plaintext [3]/[4] are null; ciphertext [5]/[6].
64
+ const key = `${args[0]}|${args[2]}`;
65
+ const prior = rows.get(key);
66
+ rows.set(key, {
67
+ scopes: args[7],
68
+ scope: args[7],
69
+ metadata_json: args[11],
70
+ access_token: args[3],
71
+ refresh_token: args[4],
72
+ created_at: prior?.created_at || args[12],
73
+ });
74
+ }
75
+ return { success: true };
76
+ },
77
+ };
78
+ },
79
+ };
80
+ },
81
+ },
82
+ };
83
+
84
+ const r1 = await upsertCloudflareUserOauthToken(env, {
85
+ userId: 'au_1',
86
+ accessToken: 'tok1',
87
+ scopes: 'd1.read offline_access',
88
+ accountId: 'abc123abc123abc123abc123abc123ab',
89
+ clientId: 'c0704bd7a7aab7216b362603e1985499',
90
+ capabilitySet: ['cloudflare.d1'],
91
+ });
92
+ assert.equal(r1.ok, true);
93
+ assert.equal(r1.status, 'connected');
94
+ assert.equal(r1.provenance.connected_via_client_id, 'c0704bd7a7aab7216b362603e1985499');
95
+ assert.equal(r1.provenance.connected_via_app, undefined);
96
+
97
+ rows.set('au_1|abc123abc123abc123abc123abc123ab', {
98
+ scopes: 'd1.read offline_access',
99
+ scope: 'd1.read offline_access',
100
+ metadata_json: JSON.stringify({
101
+ cloudflare_account_id: 'abc123abc123abc123abc123abc123ab',
102
+ connected_via_client_id: 'c0704bd7a7aab7216b362603e1985499',
103
+ connected_via_app: 'should_be_stripped',
104
+ }),
105
+ access_token: 'tok1',
106
+ refresh_token: null,
107
+ created_at: 1,
108
+ });
109
+
110
+ const r2 = await upsertCloudflareUserOauthToken(env, {
111
+ userId: 'au_1',
112
+ accessToken: 'tok2',
113
+ scopes: 'workers-scripts.write',
114
+ accountId: 'abc123abc123abc123abc123abc123ab',
115
+ clientId: 'c0704bd7a7aab7216b362603e1985499',
116
+ capabilitySet: ['cloudflare.workers'],
117
+ });
118
+ assert.equal(r2.ok, true);
119
+ assert.ok(r2.scopes.includes('d1.read'));
120
+ assert.ok(r2.scopes.includes('workers-scripts.write'));
121
+ const upsertSql = sqlSeen.find((sql) => sql.includes('ON CONFLICT(user_id, provider, account_identifier)'));
122
+ assert.match(upsertSql || '', /last_refresh_error_code = NULL/);
123
+ assert.match(upsertSql || '', /refresh_failure_count = 0/);
124
+ });
125
+ });
@@ -6,7 +6,7 @@
6
6
  "status": "extracted",
7
7
  "package": {
8
8
  "name": "@inneranimalmedia/agentsam-sdk-identity",
9
- "version": "2.6.2",
9
+ "version": "2.6.3",
10
10
  "directory": "packages/identity"
11
11
  },
12
12
  "provides": [
@@ -35,7 +35,27 @@
35
35
  "required_configuration": [
36
36
  "GOOGLE_CLIENT_ID",
37
37
  "GOOGLE_CLIENT_SECRET"
38
- ]
38
+ ],
39
+ "notes": "Web browser OAuth (confidential client). For Desktop/CLI PKCE use google_desktop."
40
+ },
41
+ {
42
+ "id": "google_desktop",
43
+ "aliases": ["google-desktop"],
44
+ "kind": "oauth",
45
+ "status": "ready",
46
+ "implementation": "src/providers/google",
47
+ "capabilities": [
48
+ "identity.oauth.authorize",
49
+ "identity.oauth.desktop_exchange",
50
+ "identity.profile.resolve"
51
+ ],
52
+ "required_configuration": [
53
+ "GOOGLE_DESKTOP_CLIENT_ID"
54
+ ],
55
+ "optional_configuration": [
56
+ "GOOGLE_DESKTOP_CLIENT_SECRET"
57
+ ],
58
+ "notes": "Desktop/public PKCE client (Console type Desktop app — no secret). Worker brokers POST /api/oauth/google/desktop-exchange for loopback redirects. Optional GOOGLE_DESKTOP_CLIENT_SECRET only if the client id was mis-typed as Web."
39
59
  },
40
60
  {
41
61
  "id": "github",
@@ -90,7 +110,7 @@
90
110
  "optional_configuration": [
91
111
  "CLOUDFLARE_OAUTH_CLIENT_SECRET"
92
112
  ],
93
- "notes": "Registered in identityProviders. Client secret optional for PKCE-only clients."
113
+ "notes": "Cloudflare sign-in (same Worker secrets as the Cloudflare resource connector). Client secret optional for PKCE-only clients (Token Authentication Method = None)."
94
114
  }
95
115
  ]
96
116
  }
@@ -4,13 +4,19 @@
4
4
  "engine": "d1",
5
5
  "migration_sources": [
6
6
  "src/migrations/0001_identity_core.sql",
7
- "src/migrations/0002_company.sql"
7
+ "src/migrations/0002_company.sql",
8
+ "src/migrations/0003_accounts_ssot.sql"
8
9
  ],
9
- "notes": "Migration files remain the schema authority. This JSON is an index/contract only.",
10
+ "notes": "Migration files remain the schema authority. accounts is the account SSOT; account_identities is IdP linkage only.",
10
11
  "tables": [
12
+ {
13
+ "name": "accounts",
14
+ "purpose": "account SSOT (row of record)",
15
+ "source": "src/migrations/0001_identity_core.sql"
16
+ },
11
17
  {
12
18
  "name": "auth_users",
13
- "purpose": "canonical user identity",
19
+ "purpose": "login principal (1:1 with accounts.id in portable scaffold)",
14
20
  "source": "src/migrations/0001_identity_core.sql"
15
21
  },
16
22
  {
@@ -21,7 +27,7 @@
21
27
  },
22
28
  {
23
29
  "name": "account_identities",
24
- "purpose": "external identity/provider mapping",
30
+ "purpose": "IdP linkage only (provider + subject → accounts.id) — not the account SSOT",
25
31
  "owner_column": "account_id",
26
32
  "source": "src/migrations/0001_identity_core.sql"
27
33
  },
@@ -39,6 +39,20 @@
39
39
  "access": "public",
40
40
  "provider": "google"
41
41
  },
42
+ {
43
+ "path": "/api/oauth/google/callback",
44
+ "kind": "api",
45
+ "access": "public",
46
+ "provider": "google"
47
+ },
48
+ {
49
+ "path": "/api/oauth/google/desktop-exchange",
50
+ "method": "POST",
51
+ "kind": "api",
52
+ "access": "public",
53
+ "provider": "google_desktop",
54
+ "notes": "CLI/desktop PKCE broker — loopback redirect_uri only"
55
+ },
42
56
  {
43
57
  "path": "/api/oauth/github/start",
44
58
  "kind": "api",
@@ -46,11 +60,26 @@
46
60
  "provider": "github"
47
61
  },
48
62
  {
49
- "path": "/api/oauth/iam/start",
63
+ "path": "/api/oauth/github/callback",
64
+ "kind": "api",
65
+ "access": "public",
66
+ "provider": "github"
67
+ },
68
+ {
69
+ "path": "/api/oauth/inneranimalmedia/start",
70
+ "kind": "api",
71
+ "access": "public",
72
+ "provider": "inneranimalmedia",
73
+ "oauth_provider_key": "iam",
74
+ "aliases": ["/api/oauth/iam/start"]
75
+ },
76
+ {
77
+ "path": "/api/oauth/inneranimalmedia/callback",
50
78
  "kind": "api",
51
79
  "access": "public",
52
80
  "provider": "inneranimalmedia",
53
- "oauth_provider_key": "iam"
81
+ "oauth_provider_key": "iam",
82
+ "aliases": ["/api/oauth/iam/callback"]
54
83
  },
55
84
  {
56
85
  "path": "/api/oauth/cloudflare/start",
@@ -20,7 +20,7 @@ identity.login(request); // alpha: throws until Identity Service adapter is wi
20
20
  identity.session.fromRequest(request); // alpha: throws until adapter is wired
21
21
  ```
22
22
 
23
- **Alpha scope:** contracts, D1 adapter, Worker router, `agentsam identity init` scaffold (`app/frontend` + `backend` + migrations), and `agentsam identity preview`. Default OAuth: minted `IAM_CLIENT_ID` + `IAM_CLIENT_SECRET`. Developer Google/GitHub BYOK still supported when those env pairs are set.
23
+ **Alpha scope:** contracts, D1 adapter, Worker router, `agentsam identity init` scaffold (`app/frontend` + `backend` + migrations), and `agentsam identity preview`. Default OAuth: minted `IAM_CLIENT_ID` + `IAM_CLIENT_SECRET`. BYOK options: Google web, Google Desktop (`GOOGLE_DESKTOP_CLIENT_ID`), GitHub, Cloudflare (`CLOUDFLARE_OAUTH_CLIENT_*`). **Account SSOT:** `accounts` (not `account_identities` — that table is IdP linkage only).
24
24
 
25
25
  ## Layout
26
26
 
@@ -11,7 +11,7 @@ Worker-side identity: providers, OAuth finalize, sessions, adapters.
11
11
  | `oauth/callback.js` | `src/core/auth/oauth-finalize.js` → `finalizeInboundOAuth` | **bulletproof path** |
12
12
  | `oauth/authorize.js` | `src/api/auth.js` OAuth start handlers | PKCE + state — next sprint |
13
13
  | `core/session-service.js` | `src/core/auth.js` | cookie, `createLoginSession`, revoke |
14
- | `core/account-linking.js` | `ensureIdentityPlaneBeforeSession`, `ensureAppUser` | account_identities |
14
+ | `core/account-linking.js` | `ensureIdentityPlaneBeforeSession`, `ensureAppUser` | **accounts** SSOT + account_identities (IdP link) |
15
15
  | `adapters/inneranimalmedia/*` | D1 writes in auth side-effects | tenant/workspace stays adapter-only |
16
16
 
17
17
  ## Rule
@@ -0,0 +1,50 @@
1
+ # Portable Identity Architecture (pre-commit return)
2
+
3
+ ## Invariants
4
+
5
+ 1. Portable SDK owns **semantic route IDs** (`identity.login`), never host paths.
6
+ 2. App manifests own **HTTP projections**.
7
+ 3. Auth-capable apps MUST declare authenticated / login / recovery / OAuth callback.
8
+ 4. OAuth **transactions** persist `app_id` + `return_to` (required).
9
+ 5. Post-login: valid `return_to` → authenticated entry → recovery+error → **throw** (never `/`).
10
+ 6. No `DASHBOARD_AFTER_LOGIN_PATH`, no `LOCAL_STUDIO_APP` in identity, no `APP_HOME_PATH` env.
11
+ 7. Missing shell/route → package verification failure.
12
+
13
+ ## Artifacts delivered
14
+
15
+ | Deliverable | Location |
16
+ |---|---|
17
+ | IdentityStore + errors | `packages/identity/src/contracts/identity-store.js` |
18
+ | Semantic IDs | `packages/identity/src/contracts/route-ids.js` |
19
+ | Route projection | `packages/identity/src/contracts/route-projection.js` |
20
+ | Fail-closed post-auth | `packages/identity/src/server/post-auth.js` |
21
+ | SESSION_POLICY | `packages/identity/src/core/session-policy.js` |
22
+ | SQLite core pack | `packages/identity/migrations/sqlite/001_identity_core.sql` |
23
+ | SQLite oauth-client | `packages/identity/migrations/sqlite/002_identity_oauth_client.sql` |
24
+ | SQLite oauth-server (optional) | `packages/identity/migrations/sqlite/003_identity_oauth_server.sql` |
25
+ | D1 mapping | `packages/identity/migrations/D1_SCHEMA_MAPPING.md` |
26
+ | createSqliteIdentityAdapter | `packages/identity/src/adapters/sqlite/index.js` |
27
+ | App verify | `packages/identity/src/app/verify-app.js` |
28
+ | App auth contract (Local Studio) | `apps/local-studio/agentsam.app.json` |
29
+ | Tests | `packages/identity/tests/portable-identity-architecture.test.mjs` |
30
+
31
+ ## Redirect resolution
32
+
33
+ ```
34
+ transaction.return_to → owned by app?
35
+ yes → use
36
+ no → app.authenticated
37
+ missing → identity.recovery?error=…
38
+ none → IdentityRoutingError('AUTH_DESTINATION_UNRESOLVED')
39
+ ```
40
+
41
+ ## Local-only path
42
+
43
+ ```
44
+ applySqliteIdentityMigrations(db) // core + oauth-client
45
+ createSqliteIdentityAdapter(db)
46
+ createIdentityService({ adapter, app, routeRegistry })
47
+ ```
48
+
49
+ Zero Cloudflare / IAM / D1 required for password + session + OAuth transaction store.
50
+ Provider secrets → encrypted vault via `credential_ref` on `identity_provider_connections`.
@@ -0,0 +1,32 @@
1
+ # Identity schema mapping — portable ↔ Cloudflare D1
2
+
3
+ Portable SQLite (`packages/identity/migrations/sqlite/`) is the product schema.
4
+ The D1 adapter maps existing hosted table names without requiring a big-bang rename.
5
+
6
+ | Portable (SQLite) | Hosted D1 (current) | Notes |
7
+ |---|---|---|
8
+ | `identity_users` / account plane | **`accounts`** | **Account SSOT** — row of record |
9
+ | login principal | `auth_users` | 1:1 with `accounts.id` in portable scaffold |
10
+ | `identity_external_accounts` | `account_identities` | IdP linkage only (`account_id` → `accounts.id`) — never the account SSOT |
11
+ | `identity_sessions` | `auth_sessions` | Same columns |
12
+ | `identity_auth_events` | `auth_event_log` | Same columns |
13
+ | `identity_oauth_transactions` | `identity_oauth_states` → migrate to `identity_oauth_transactions` | Requires `app_id NOT NULL`; no silent pre-app_id fallback |
14
+ | `identity_provider_connections` | (new / connector tables) | `credential_ref` → vault/KMS; never store raw tokens in D1 rows |
15
+ | `identity_app_registry` | cache of `agentsam.app.json` | Disk manifests remain SSOT |
16
+ | `identity_route_registry` | projection cache | Disk manifests remain SSOT |
17
+ | `identity_oauth_clients` … | optional `identity.oauth-server` pack | Only if product is an AS |
18
+
19
+ ## Schema version
20
+
21
+ Both adapters read `identity_schema_meta.schema_version` (SQLite) or
22
+ `PRAGMA`/meta row. Missing `app_id` on OAuth transactions is an
23
+ `IdentitySchemaError('IDENTITY_SCHEMA_MIGRATION_REQUIRED')`, not a soft
24
+ downgrade.
25
+
26
+ ## Packs
27
+
28
+ | Pack | Apply when |
29
+ |---|---|
30
+ | `identity.core` | Always (local + hosted) |
31
+ | `identity.oauth-client` | Signing into external IdPs |
32
+ | `identity.oauth-server` | Product issues its own codes/tokens |
@@ -0,0 +1,99 @@
1
+ -- identity.core — portable local SQLite (no Cloudflare / IAM required)
2
+ -- Timestamps: INTEGER unixepoch seconds
3
+
4
+ PRAGMA foreign_keys = ON;
5
+
6
+ CREATE TABLE IF NOT EXISTS identity_schema_meta (
7
+ key TEXT PRIMARY KEY NOT NULL,
8
+ value TEXT NOT NULL
9
+ );
10
+
11
+ INSERT OR REPLACE INTO identity_schema_meta (key, value)
12
+ VALUES ('schema_version', '1');
13
+
14
+ INSERT OR IGNORE INTO identity_schema_meta (key, value)
15
+ VALUES ('pack_core', '1');
16
+
17
+ CREATE TABLE IF NOT EXISTS identity_users (
18
+ id TEXT PRIMARY KEY NOT NULL,
19
+ email TEXT NOT NULL COLLATE NOCASE,
20
+ display_name TEXT,
21
+ password_hash TEXT,
22
+ salt TEXT,
23
+ status TEXT NOT NULL DEFAULT 'active',
24
+ created_at INTEGER NOT NULL,
25
+ updated_at INTEGER NOT NULL
26
+ );
27
+
28
+ CREATE UNIQUE INDEX IF NOT EXISTS idx_identity_users_email
29
+ ON identity_users(email);
30
+
31
+ CREATE TABLE IF NOT EXISTS identity_external_accounts (
32
+ id TEXT PRIMARY KEY NOT NULL,
33
+ user_id TEXT NOT NULL,
34
+ provider TEXT NOT NULL,
35
+ provider_subject TEXT NOT NULL,
36
+ email TEXT,
37
+ created_at INTEGER NOT NULL,
38
+ updated_at INTEGER NOT NULL,
39
+ FOREIGN KEY (user_id) REFERENCES identity_users(id)
40
+ );
41
+
42
+ CREATE UNIQUE INDEX IF NOT EXISTS idx_identity_external_provider_subject
43
+ ON identity_external_accounts(provider, provider_subject);
44
+
45
+ CREATE TABLE IF NOT EXISTS identity_sessions (
46
+ id TEXT PRIMARY KEY NOT NULL,
47
+ user_id TEXT NOT NULL,
48
+ email TEXT,
49
+ provider TEXT,
50
+ provider_subject TEXT,
51
+ display_name TEXT,
52
+ expires_at INTEGER NOT NULL,
53
+ revoked_at INTEGER,
54
+ created_at INTEGER NOT NULL,
55
+ last_active_at INTEGER,
56
+ FOREIGN KEY (user_id) REFERENCES identity_users(id)
57
+ );
58
+
59
+ CREATE INDEX IF NOT EXISTS idx_identity_sessions_user_expires
60
+ ON identity_sessions(user_id, expires_at);
61
+
62
+ CREATE TABLE IF NOT EXISTS identity_auth_events (
63
+ id TEXT PRIMARY KEY NOT NULL,
64
+ user_id TEXT,
65
+ event_type TEXT NOT NULL,
66
+ status TEXT NOT NULL DEFAULT 'ok',
67
+ provider TEXT,
68
+ metadata_json TEXT NOT NULL DEFAULT '{}',
69
+ ip_hash TEXT,
70
+ user_agent_hash TEXT,
71
+ created_at INTEGER NOT NULL DEFAULT (unixepoch())
72
+ );
73
+
74
+ CREATE INDEX IF NOT EXISTS idx_identity_auth_events_user_created
75
+ ON identity_auth_events(user_id, created_at DESC);
76
+
77
+ CREATE TABLE IF NOT EXISTS identity_app_registry (
78
+ id TEXT PRIMARY KEY NOT NULL,
79
+ package_name TEXT,
80
+ manifest_version TEXT,
81
+ display_name TEXT,
82
+ authenticated_route_id TEXT NOT NULL,
83
+ login_route_id TEXT NOT NULL,
84
+ recovery_route_id TEXT NOT NULL,
85
+ enabled INTEGER NOT NULL DEFAULT 1,
86
+ installed_at INTEGER NOT NULL,
87
+ updated_at INTEGER NOT NULL
88
+ );
89
+
90
+ CREATE TABLE IF NOT EXISTS identity_route_registry (
91
+ app_id TEXT NOT NULL,
92
+ route_id TEXT NOT NULL,
93
+ path_pattern TEXT NOT NULL,
94
+ runtime TEXT,
95
+ auth_policy TEXT,
96
+ shell_ref TEXT,
97
+ PRIMARY KEY (app_id, route_id),
98
+ FOREIGN KEY (app_id) REFERENCES identity_app_registry(id)
99
+ );
@@ -0,0 +1,38 @@
1
+ -- identity.oauth-client — outbound OAuth (sign in with Google/CF/GitHub/IAM)
2
+ -- Secrets/tokens live in the local encrypted vault; this pack stores refs + metadata.
3
+
4
+ INSERT OR IGNORE INTO identity_schema_meta (key, value)
5
+ VALUES ('pack_oauth_client', '1');
6
+
7
+ CREATE TABLE IF NOT EXISTS identity_oauth_transactions (
8
+ state TEXT PRIMARY KEY NOT NULL,
9
+ provider TEXT NOT NULL,
10
+ code_verifier TEXT NOT NULL,
11
+ return_to TEXT,
12
+ app_id TEXT NOT NULL,
13
+ expires_at INTEGER NOT NULL,
14
+ created_at INTEGER NOT NULL,
15
+ consumed_at INTEGER
16
+ );
17
+
18
+ CREATE INDEX IF NOT EXISTS idx_identity_oauth_transactions_expires
19
+ ON identity_oauth_transactions(expires_at);
20
+
21
+ CREATE INDEX IF NOT EXISTS idx_identity_oauth_transactions_app
22
+ ON identity_oauth_transactions(app_id);
23
+
24
+ CREATE TABLE IF NOT EXISTS identity_provider_connections (
25
+ id TEXT PRIMARY KEY NOT NULL,
26
+ user_id TEXT NOT NULL,
27
+ provider TEXT NOT NULL,
28
+ granted_scopes_json TEXT NOT NULL DEFAULT '[]',
29
+ credential_ref TEXT NOT NULL,
30
+ expires_at INTEGER,
31
+ refreshable INTEGER NOT NULL DEFAULT 0,
32
+ created_at INTEGER NOT NULL,
33
+ updated_at INTEGER NOT NULL,
34
+ FOREIGN KEY (user_id) REFERENCES identity_users(id)
35
+ );
36
+
37
+ CREATE UNIQUE INDEX IF NOT EXISTS idx_identity_provider_connections_user_provider
38
+ ON identity_provider_connections(user_id, provider);