@inneranimalmedia/agentsam-sdk 2.6.5 → 2.6.8

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (400) hide show
  1. package/AGENTSAM.md +29 -0
  2. package/README.md +37 -0
  3. package/apps/README.md +5 -0
  4. package/apps/cad-creator/README.md +4 -4
  5. package/apps/cad-creator/shared/cad/package.json +1 -1
  6. package/apps/client-cms-editor/AGENTS.md +12 -7
  7. package/apps/client-cms-editor/README.md +76 -48
  8. package/apps/client-cms-editor/agentsam.app.json +26 -9
  9. package/apps/client-cms-editor/backend/package.json +20 -3
  10. package/apps/client-cms-editor/backend/src/api/client.ts +134 -101
  11. package/apps/client-cms-editor/backend/src/index.ts +1 -1
  12. package/apps/client-cms-editor/backend/src/model.ts +11 -115
  13. package/apps/client-cms-editor/backend/src/preview/bridge.ts +1 -1
  14. package/apps/client-cms-editor/backend/tsconfig.json +6 -1
  15. package/apps/client-cms-editor/bin/agentsam-cms.js +262 -0
  16. package/apps/client-cms-editor/bin/agentsam-cms.mjs +2 -228
  17. package/apps/client-cms-editor/frontend/package.json +16 -7
  18. package/apps/client-cms-editor/frontend/src/AgentSamDrawer.tsx +9 -41
  19. package/apps/client-cms-editor/frontend/src/CmsAgentSurface.tsx +19 -174
  20. package/apps/client-cms-editor/frontend/src/adapters/heuristic.ts +29 -0
  21. package/apps/client-cms-editor/frontend/src/adapters/http.ts +628 -0
  22. package/apps/client-cms-editor/frontend/src/adapters/memory.ts +510 -0
  23. package/apps/client-cms-editor/frontend/src/editor/CmsEditor.tsx +213 -0
  24. package/apps/client-cms-editor/frontend/src/editor/CmsEditorProvider.tsx +20 -0
  25. package/apps/client-cms-editor/frontend/src/editor/canvas/PreviewCanvas.tsx +53 -0
  26. package/apps/client-cms-editor/frontend/src/{CmsEditor.tsx → editor/legacy/CmsEditorPrototype.tsx} +52 -23
  27. package/apps/client-cms-editor/frontend/src/editor/useCmsEditorController.ts +218 -0
  28. package/apps/client-cms-editor/frontend/src/index.ts +19 -5
  29. package/apps/client-cms-editor/frontend/src/lib/agent-host.ts +24 -0
  30. package/apps/client-cms-editor/frontend/src/main.tsx +82 -8
  31. package/apps/client-cms-editor/frontend/src/mount.tsx +92 -30
  32. package/apps/client-cms-editor/frontend/src/styles/agentsam-drawer.css +1 -1
  33. package/apps/client-cms-editor/frontend/src/styles/cmsShell.css +8 -8
  34. package/apps/client-cms-editor/frontend/src/styles/studio.css +55 -3
  35. package/apps/client-cms-editor/frontend/tsconfig.json +12 -1
  36. package/apps/client-cms-editor/frontend/vite.config.ts +12 -0
  37. package/apps/client-cms-editor/package-lock.json +973 -134
  38. package/apps/client-cms-editor/package.json +118 -6
  39. package/apps/client-cms-editor/reference/harvest/HARVEST_RECEIPT.json +201 -0
  40. package/apps/client-cms-editor/reference/harvest/PROVENANCE_HISTORY.txt +10 -0
  41. package/apps/client-cms-editor/reference/harvest/README.md +8 -0
  42. package/apps/client-cms-editor/reference/harvest/plans/ARCHIVE-INTAKE.md +135 -0
  43. package/apps/client-cms-editor/reference/harvest/plans/CHATGPT-IDENTITY-HARVEST.md +83 -0
  44. package/apps/client-cms-editor/reference/harvest/plans/CMS-EDITOR-HARVEST.md +166 -0
  45. package/apps/client-cms-editor/reference/harvest/plans/HARVEST-INDEX.md +196 -0
  46. package/apps/client-cms-editor/reference/harvest/plans/INNERANIMALS-CONTENT-001.md +137 -0
  47. package/apps/client-cms-editor/reference/harvest/plans/NO-IMPLICIT-SIDE-EFFECTS.md +87 -0
  48. package/apps/client-cms-editor/reference/harvest/plans/STOREFRONT-SURFACE-MAP.md +140 -0
  49. package/apps/client-cms-editor/reference/harvest/plans/THEME-INNERANIMALS-HARVEST.md +137 -0
  50. package/apps/client-cms-editor/reference/harvest/plans/TOOLING-LAB.md +63 -0
  51. package/apps/client-cms-editor/reference/harvest/plans/harvest-manifest.json +97 -0
  52. package/apps/client-cms-editor/reference/harvest/plans/local-cms-harvest-schema.sql +328 -0
  53. package/apps/client-cms-editor/shared/cms/package.json +17 -7
  54. package/apps/client-cms-editor/shared/cms/src/adapter.ts +204 -0
  55. package/apps/client-cms-editor/shared/cms/src/agent-context.ts +7 -5
  56. package/apps/client-cms-editor/shared/cms/src/editor-types.ts +32 -0
  57. package/apps/client-cms-editor/shared/cms/src/host.ts +82 -0
  58. package/apps/client-cms-editor/shared/cms/src/index.ts +4 -0
  59. package/apps/client-cms-editor/shared/cms/src/map.ts +115 -0
  60. package/apps/client-cms-editor/shared/cms/src/starter-pack.ts +158 -0
  61. package/contracts/source-types.v1.json +353 -0
  62. package/docs/CMS_CONTEXTUAL_COMPOSER.md +1 -1
  63. package/docs/PRODUCT_LIFECYCLE.md +566 -0
  64. package/docs/REPO_FILE_MAP.txt +132 -0
  65. package/docs/THEME_REFINERY.md +2 -2
  66. package/docs/architecture/AGENTSAM_RUNTIME_PROTOCOL.md +40 -20
  67. package/docs/content-studio/REVISION_GATE_2026-09-27.md +1 -1
  68. package/docs/plans/LOCAL_STUDIO_DESKTOP_RELEASE_2026-09-29.md +150 -0
  69. package/migrations/d1/0017_identity_native_oauth.sql +21 -0
  70. package/migrations/d1/0018_goap_control_plane_remaster.sql +40 -0
  71. package/migrations/d1/0019_agentsam_agent_run_plan_todo.sql +14 -0
  72. package/migrations/d1/README_PORTABLE_CONTROL_PLANE.md +20 -9
  73. package/migrations/runtime/0002_goap_blackboard_v1.sql +15 -0
  74. package/migrations/runtime/0004_agent_run_plan_linkage.sql +8 -0
  75. package/native/agentsam-machine/Cargo.lock +426 -0
  76. package/native/agentsam-machine/Cargo.toml +9 -0
  77. package/native/agentsam-machine/cli/Cargo.toml +21 -0
  78. package/native/agentsam-machine/cli/README.md +21 -0
  79. package/native/agentsam-machine/cli/src/main.rs +77 -0
  80. package/native/agentsam-machine/core/Cargo.toml +22 -0
  81. package/native/agentsam-machine/core/README.md +14 -0
  82. package/native/agentsam-machine/core/build.rs +33 -0
  83. package/native/agentsam-machine/core/contracts/source-types.v1.json +353 -0
  84. package/native/agentsam-machine/core/src/assets.rs +790 -0
  85. package/native/agentsam-machine/core/src/bound.rs +298 -0
  86. package/native/agentsam-machine/core/src/enrich.rs +706 -0
  87. package/native/agentsam-machine/core/src/frontend.rs +442 -0
  88. package/native/agentsam-machine/core/src/lib.rs +1092 -0
  89. package/native/agentsam-machine/core/src/liquid.rs +528 -0
  90. package/native/agentsam-machine/core/src/source_types.rs +78 -0
  91. package/package.json +64 -24
  92. package/packages/agentsam-brand/README.md +1 -1
  93. package/packages/agentsam-brand/package.json +4 -4
  94. package/packages/agentsam-brand/src/index.js +1 -1
  95. package/packages/agentsam-contracts/package.json +13 -3
  96. package/packages/agentsam-contracts/src/tools.ts +22 -0
  97. package/packages/agentsam-errors/package.json +13 -3
  98. package/packages/agentsam-errors/src/index.js +1 -0
  99. package/packages/agentsam-errors/src/tool.js +56 -0
  100. package/packages/agentsam-errors/test/tool.test.mjs +58 -0
  101. package/packages/agentsam-goap/README.md +52 -0
  102. package/packages/agentsam-goap/package.json +37 -0
  103. package/packages/agentsam-goap/src/adapters/d1-sqlite.js +570 -0
  104. package/packages/agentsam-goap/src/adapters/memory.js +199 -0
  105. package/packages/agentsam-goap/src/contracts.js +226 -0
  106. package/packages/agentsam-goap/src/control-plane.js +112 -0
  107. package/packages/agentsam-goap/src/errors.js +157 -0
  108. package/packages/agentsam-goap/src/index.js +5 -0
  109. package/packages/agentsam-goap/src/world.js +202 -0
  110. package/packages/agentsam-goap/test/goap-control-plane.test.mjs +245 -0
  111. package/packages/agentsam-goap/test/world.test.mjs +79 -0
  112. package/packages/agentsam-knowledge/package.json +18 -4
  113. package/packages/agentsam-knowledge/src/autorag/index.js +10 -3
  114. package/packages/agentsam-knowledge/src/backends/index.js +33 -1
  115. package/packages/agentsam-knowledge/test/autorag.test.mjs +60 -1
  116. package/packages/agentsam-nav/dist/browser.global.js +21 -18
  117. package/packages/agentsam-nav/dist/browser.js +6807 -130
  118. package/packages/agentsam-nav/dist/index.js +6799 -122
  119. package/packages/agentsam-nav/package.json +24 -6
  120. package/packages/agentsam-queue-control/README.md +1 -1
  121. package/packages/agentsam-queue-control/package.json +7 -2
  122. package/packages/agentsam-rapid-rust/src/main.rs +1 -1
  123. package/packages/agentsam-repository/package.json +13 -3
  124. package/packages/agentsam-repository/src/goap.js +13 -14
  125. package/packages/agentsam-repository/src/source-types.js +8 -0
  126. package/packages/agentsam-repository/src/tickets.js +15 -22
  127. package/packages/agentsam-repository/test/goap-tickets-workspace-state.test.mjs +19 -8
  128. package/packages/agentsam-vault/package.json +14 -4
  129. package/packages/agentsam-workbench/package.json +15 -4
  130. package/packages/agentsam-workbench/src/agent/ToolPermissionRequest.tsx +94 -0
  131. package/packages/agentsam-workbench/src/agent/index.ts +2 -0
  132. package/packages/agentsam-workbench/src/agent/tool-permission.css +134 -0
  133. package/packages/connectors/cloudflare/package.json +15 -3
  134. package/packages/connectors/cloudflare/src/api-client.js +3 -2
  135. package/packages/connectors/cloudflare/src/families/vectorize.js +127 -0
  136. package/packages/connectors/cloudflare/src/index.js +1 -0
  137. package/packages/heuristic-theme/README.md +2 -2
  138. package/packages/heuristic-theme/package.json +8 -3
  139. package/packages/heuristic-theme/src/registry.js +2 -2
  140. package/packages/heuristic-theme/src/theme.js +1 -1
  141. package/packages/heuristic-theme/test/theme.test.mjs +1 -1
  142. package/packages/identity/.agentsam/features/oauth-login-portal/agentsam.feature.json +1 -1
  143. package/packages/identity/.agentsam/features/oauth-login-portal/providers.json +27 -7
  144. package/packages/identity/README.md +2 -2
  145. package/packages/identity/migrations/D1_SCHEMA_MAPPING.md +18 -15
  146. package/packages/identity/migrations/apply-portable.js +109 -0
  147. package/packages/identity/migrations/sqlite/004_identity_oauth_consent_catalog.sql +1 -1
  148. package/packages/identity/migrations/sqlite/005_identity_company_native.sql +52 -0
  149. package/packages/identity/package.json +27 -6
  150. package/packages/identity/schema/agentsam.identity/manifest.json +101 -0
  151. package/packages/identity/scripts/local-identity-bridge.mjs +13 -7
  152. package/packages/identity/scripts/preview-auth-portal.mjs +6 -6
  153. package/packages/identity/src/adapters/cloudflare-d1/index.js +8 -401
  154. package/packages/identity/src/adapters/iam-compat/index.js +540 -0
  155. package/packages/identity/src/adapters/portable-d1/index.js +18 -0
  156. package/packages/identity/src/adapters/portable-store.js +479 -0
  157. package/packages/identity/src/adapters/sqlite/index.js +13 -312
  158. package/packages/identity/src/contracts/auth-config.js +0 -1
  159. package/packages/identity/src/contracts/identity-store.js +56 -5
  160. package/packages/identity/src/contracts/provider.js +1 -0
  161. package/packages/identity/src/contracts/sign-in-options.js +104 -0
  162. package/packages/identity/src/core/constants.js +1 -1
  163. package/packages/identity/src/core/session-policy.js +31 -0
  164. package/packages/identity/src/frontend/auth-portal/pages/login.html +6 -6
  165. package/packages/identity/src/frontend/auth-portal/pages/reset.html +5 -5
  166. package/packages/identity/src/frontend/auth-portal/pages/signup.html +5 -5
  167. package/packages/identity/src/frontend/auth-portal/shared/company-branding.js +1 -1
  168. package/packages/identity/src/frontend/auth-portal/shared/desktop-identity-bridge.js +6 -37
  169. package/packages/identity/src/index.js +28 -1
  170. package/packages/identity/src/migrations/README.md +23 -23
  171. package/packages/identity/src/oauth/README.md +1 -1
  172. package/packages/identity/src/oauth/credentials.js +10 -11
  173. package/packages/identity/src/oauth/google-desktop-exchange.js +195 -27
  174. package/packages/identity/src/oauth/iam-platform.js +21 -9
  175. package/packages/identity/src/oauth/native-handoff.js +136 -0
  176. package/packages/identity/src/providers/chatgpt/headers.js +65 -0
  177. package/packages/identity/src/providers/chatgpt/index.js +86 -0
  178. package/packages/identity/src/providers/chatgpt/mapper.js +43 -0
  179. package/packages/identity/src/providers/chatgpt/paths.js +45 -0
  180. package/packages/identity/src/providers/github/oauth.js +1 -2
  181. package/packages/identity/src/providers/github/profile.js +16 -2
  182. package/packages/identity/src/providers/index.js +11 -3
  183. package/packages/identity/src/server/identity-service.js +2 -1
  184. package/packages/identity/src/server/worker-router.js +71 -18
  185. package/packages/identity/tests/chatgpt-provider.test.mjs +75 -0
  186. package/packages/identity/tests/google-desktop-identity-login.test.mjs +210 -0
  187. package/packages/identity/tests/identity-init-scaffold.test.mjs +15 -4
  188. package/packages/identity/tests/lane1-identity-store-parity.test.mjs +527 -0
  189. package/packages/identity/tests/lane1-packed-consumer.test.mjs +175 -0
  190. package/packages/identity/tests/native-oauth-handoff.test.mjs +292 -0
  191. package/packages/identity/tests/oauth-credentials.test.mjs +4 -4
  192. package/packages/identity/tests/preview-auth-portal.test.mjs +4 -2
  193. package/packages/identity/tests/session-routes-policy.test.mjs +13 -1
  194. package/packages/identity/tests/worker-runtime-boundary.test.mjs +11 -0
  195. package/packages/providers/completeful/package.json +7 -2
  196. package/packages/theme-church-site/package.json +17 -6
  197. package/packages/theme-church-site/src/harvest.json +4 -2
  198. package/packages/theme-church-site/src/index.js +7 -3
  199. package/packages/theme-church-site/test/theme.test.mjs +4 -2
  200. package/packages/theme-companions-site/package.json +17 -6
  201. package/packages/theme-companions-site/src/harvest.json +4 -2
  202. package/packages/theme-companions-site/src/index.js +7 -3
  203. package/packages/theme-companions-site/test/theme.test.mjs +4 -2
  204. package/packages/theme-floors-site/package.json +17 -6
  205. package/packages/theme-floors-site/src/harvest.json +4 -2
  206. package/packages/theme-floors-site/src/index.js +7 -3
  207. package/packages/theme-floors-site/test/theme.test.mjs +4 -2
  208. package/packages/theme-fuelnfree-site/package.json +17 -6
  209. package/packages/theme-fuelnfree-site/src/harvest.json +4 -2
  210. package/packages/theme-fuelnfree-site/src/index.js +7 -3
  211. package/packages/theme-fuelnfree-site/test/theme.test.mjs +4 -2
  212. package/packages/theme-handyman-site/package.json +17 -6
  213. package/packages/theme-handyman-site/src/harvest.json +4 -2
  214. package/packages/theme-handyman-site/src/index.js +7 -3
  215. package/packages/theme-handyman-site/test/theme.test.mjs +4 -2
  216. package/packages/theme-insurance-site/package.json +17 -6
  217. package/packages/theme-insurance-site/src/harvest.json +4 -2
  218. package/packages/theme-insurance-site/src/index.js +7 -3
  219. package/packages/theme-insurance-site/test/theme.test.mjs +4 -2
  220. package/packages/theme-scenes/README.md +1 -1
  221. package/packages/theme-scenes/package.json +4 -3
  222. package/packages/theme-scenes/src/registry.js +187 -0
  223. package/packages/theme-shinshu-site/package.json +17 -6
  224. package/packages/theme-shinshu-site/src/harvest.json +4 -2
  225. package/packages/theme-shinshu-site/src/index.js +7 -3
  226. package/packages/theme-shinshu-site/test/theme.test.mjs +4 -2
  227. package/packages/work-graph/package.json +14 -4
  228. package/protocol/FILEMETA_V1.md +2 -2
  229. package/protocol/capabilities/manifest.json +1 -1
  230. package/protocol/database/agentsam.schema-pack.v1.schema.json +72 -0
  231. package/protocol/presets/catalog.json +2 -2
  232. package/protocol/theme-refinery/lineage-registry.json +105 -0
  233. package/protocol/theme-refinery/product-metadata.schema.json +21 -1
  234. package/python/agentsam_sdk/repository/intelligence/discovery.py +27 -2
  235. package/python/agentsam_sdk/repository/intelligence/git.py +4 -0
  236. package/python/tests/test_repository_intelligence.py +30 -0
  237. package/src/cli/command-catalog.js +48 -5
  238. package/src/cli/dispatch.js +1 -0
  239. package/src/cli.js +20 -1
  240. package/src/cloudflare/runtime-status.js +2 -1
  241. package/src/commands/autorag.js +67 -13
  242. package/src/commands/cheat-sheet.js +29 -4
  243. package/src/commands/codebaseindex.js +45 -2
  244. package/src/commands/goap-world.js +134 -0
  245. package/src/commands/goap.js +11 -4
  246. package/src/commands/knowledge.js +59 -2
  247. package/src/commands/machine-binary.js +109 -0
  248. package/src/commands/machine-runtime.js +266 -0
  249. package/src/commands/machine.js +208 -0
  250. package/src/commands/package.js +530 -0
  251. package/src/commands/plan-ledger.js +370 -0
  252. package/src/commands/plan.js +183 -0
  253. package/src/commands/security.js +67 -4
  254. package/src/commands/setup.js +33 -16
  255. package/src/commands/skill.js +78 -17
  256. package/src/commands/status.js +8 -1
  257. package/src/features/resolve.js +1 -0
  258. package/src/knowledge/engine.js +21 -2
  259. package/src/knowledge/runtime-discovery.js +127 -0
  260. package/src/knowledge/source.js +1 -1
  261. package/src/lib/identity-scaffold.js +53 -13
  262. package/src/lib/setup/recipes.js +1 -1
  263. package/src/lib/slash-commands.js +1 -1
  264. package/src/local/runtime-store.js +24 -2
  265. package/src/local/sqlite.js +17 -0
  266. package/src/models/discovery.js +40 -22
  267. package/src/models/inventory-core.d.ts +105 -0
  268. package/src/models/inventory-core.js +54 -6
  269. package/src/sam/operations/package-audit.js +41 -0
  270. package/src/sam/seed.js +2 -0
  271. package/src/security/logs.js +3 -0
  272. package/src/ui/cli/help.js +41 -0
  273. package/apps/client-cms-editor/backend/src/demo-bootstrap.ts +0 -145
  274. package/test/account-session.test.mjs +0 -101
  275. package/test/agent-capabilities.test.mjs +0 -67
  276. package/test/app-authority-context.test.mjs +0 -32
  277. package/test/app-building-skills.test.mjs +0 -61
  278. package/test/apps-scaffold-contract.test.mjs +0 -114
  279. package/test/blender-cad.test.mjs +0 -146
  280. package/test/cad-docker.test.mjs +0 -96
  281. package/test/capabilities.test.mjs +0 -133
  282. package/test/cli/api-key-env-whoami.test.mjs +0 -129
  283. package/test/cli/codebaseindex-plan-ux.test.mjs +0 -37
  284. package/test/cli/eval-live.test.mjs +0 -219
  285. package/test/cli/go.test.mjs +0 -128
  286. package/test/cli/local-vault-and-provider-setup.test.mjs +0 -268
  287. package/test/cli/mcp-client.test.mjs +0 -256
  288. package/test/cli/preferences-runtime.test.mjs +0 -11
  289. package/test/cli/runtime-persist.test.mjs +0 -56
  290. package/test/cli/runtime-ui.test.mjs +0 -141
  291. package/test/cli/rust-command.test.mjs +0 -21
  292. package/test/cli/skill-npm-and-env.test.mjs +0 -52
  293. package/test/cli/status-actions.test.mjs +0 -88
  294. package/test/cli/wireframes-go-registry.test.mjs +0 -139
  295. package/test/cli-preferences.test.mjs +0 -46
  296. package/test/cloudflare-connector.test.mjs +0 -93
  297. package/test/cloudflare-runtime.test.mjs +0 -82
  298. package/test/context.test.mjs +0 -159
  299. package/test/credentials-audit.test.mjs +0 -113
  300. package/test/deploy-health-scan.test.mjs +0 -95
  301. package/test/deploy-receipt.test.mjs +0 -91
  302. package/test/dockerize.test.mjs +0 -93
  303. package/test/error-diagnostics.test.mjs +0 -124
  304. package/test/eval-context.test.mjs +0 -37
  305. package/test/execution-approvals.test.mjs +0 -27
  306. package/test/fixtures/cad/courtyard-house.json +0 -208
  307. package/test/fixtures/knowledge-rpc-worker.mjs +0 -16
  308. package/test/gcloud-auth.test.mjs +0 -111
  309. package/test/go/build-source-identity.test.mjs +0 -31
  310. package/test/go/cloudflare-probe.test.mjs +0 -317
  311. package/test/go/distribution.test.mjs +0 -28
  312. package/test/google-cloud-connection.test.mjs +0 -83
  313. package/test/google-cloud-inventory.test.mjs +0 -64
  314. package/test/indexing-provider.test.mjs +0 -29
  315. package/test/init-options.test.mjs +0 -35
  316. package/test/integration/ai-access-onboarding.test.mjs +0 -47
  317. package/test/integration/app-command.test.mjs +0 -85
  318. package/test/integration/cad-discovery.test.mjs +0 -158
  319. package/test/integration/cad-docker-executor.test.mjs +0 -249
  320. package/test/integration/cad-execution.test.mjs +0 -184
  321. package/test/integration/cad-project-app.test.mjs +0 -31
  322. package/test/integration/cad-project-d1.test.mjs +0 -25
  323. package/test/integration/cad-project-native.test.mjs +0 -24
  324. package/test/integration/cad-project-workflow.test.mjs +0 -9
  325. package/test/integration/cad-project.test.mjs +0 -85
  326. package/test/integration/cli-help.test.mjs +0 -41
  327. package/test/integration/cms-app-scaffold.test.mjs +0 -71
  328. package/test/integration/cms-site-tenancy-contract.test.mjs +0 -257
  329. package/test/integration/codebaseindex-ingest.test.mjs +0 -214
  330. package/test/integration/core-client.integration.test.mjs +0 -55
  331. package/test/integration/error-runtime-rpc.test.mjs +0 -71
  332. package/test/integration/features-resolve.test.mjs +0 -147
  333. package/test/integration/icon-registry.test.mjs +0 -67
  334. package/test/integration/ingest-discover-models.test.mjs +0 -30
  335. package/test/integration/inspect-path-cli.test.mjs +0 -46
  336. package/test/integration/install-script.test.mjs +0 -110
  337. package/test/integration/inventory-core.test.mjs +0 -53
  338. package/test/integration/inventory-evidence.test.mjs +0 -125
  339. package/test/integration/knowledge-rpc.test.mjs +0 -112
  340. package/test/integration/local-fs.test.mjs +0 -113
  341. package/test/integration/merkle-cli.test.mjs +0 -61
  342. package/test/integration/merkle-persistence-identity.test.mjs +0 -48
  343. package/test/integration/plugins-cloudflare.integration.test.mjs +0 -28
  344. package/test/integration/provider-env-cli.test.mjs +0 -50
  345. package/test/integration/provider-factory.test.mjs +0 -197
  346. package/test/integration/repository-company-graph.test.mjs +0 -90
  347. package/test/integration/runtime-migrations.test.mjs +0 -87
  348. package/test/integration/runtime-status.integration.test.mjs +0 -212
  349. package/test/integration/sam-activity-recovery.test.mjs +0 -147
  350. package/test/integration/sam-decision.test.mjs +0 -584
  351. package/test/integration/sam-kernel.test.mjs +0 -99
  352. package/test/integration/sam-planning-astar.test.mjs +0 -279
  353. package/test/integration/scaffold-cloudflare.test.mjs +0 -46
  354. package/test/integration/skill-runtime.test.mjs +0 -240
  355. package/test/integration/storage-architecture.test.mjs +0 -154
  356. package/test/integration/store-discovery.test.mjs +0 -44
  357. package/test/integration/studio-fs-pty-e2e.test.mjs +0 -294
  358. package/test/integration/terminal-exec.integration.test.mjs +0 -86
  359. package/test/integration/tool-runtime.test.mjs +0 -124
  360. package/test/integration/tool-schema.test.mjs +0 -59
  361. package/test/jr-dev-skill.test.mjs +0 -26
  362. package/test/knowledge-context-pack.test.mjs +0 -19
  363. package/test/knowledge-postgres.test.mjs +0 -40
  364. package/test/knowledge-service.test.mjs +0 -110
  365. package/test/knowledge.test.mjs +0 -206
  366. package/test/live/terminal-transport.live.test.mjs +0 -24
  367. package/test/local-sessions.test.mjs +0 -57
  368. package/test/local-studio-deploy.test.mjs +0 -83
  369. package/test/loopback-oauth.test.mjs +0 -53
  370. package/test/merkle-render.test.mjs +0 -31
  371. package/test/mini.test.mjs +0 -140
  372. package/test/model-catalog.test.mjs +0 -70
  373. package/test/models.test.mjs +0 -309
  374. package/test/npm10-lock.test.mjs +0 -29
  375. package/test/ollama.test.mjs +0 -137
  376. package/test/open-url.test.mjs +0 -64
  377. package/test/openai-responses.test.mjs +0 -155
  378. package/test/portable-context.test.mjs +0 -94
  379. package/test/project-config.test.mjs +0 -81
  380. package/test/project-rules.test.mjs +0 -44
  381. package/test/provider-credentials.test.mjs +0 -106
  382. package/test/rehydrate.test.mjs +0 -25
  383. package/test/release-hygiene.test.mjs +0 -42
  384. package/test/repository-snapshot-view.test.mjs +0 -112
  385. package/test/responses-runner.test.mjs +0 -465
  386. package/test/runtime-activity.test.mjs +0 -98
  387. package/test/sdk-worker-contract.test.mjs +0 -72
  388. package/test/security.test.mjs +0 -252
  389. package/test/setup-planner.test.mjs +0 -74
  390. package/test/setup-runtime.test.mjs +0 -51
  391. package/test/shell.test.mjs +0 -281
  392. package/test/skills.test.mjs +0 -22
  393. package/test/smoke.mjs +0 -122
  394. package/test/telemetry.test.mjs +0 -79
  395. package/test/terminal/local-pty.mock.test.mjs +0 -153
  396. package/test/terminal-machine-identity.test.mjs +0 -88
  397. package/test/theme-portability.test.mjs +0 -14
  398. package/test/tools-search.test.mjs +0 -73
  399. package/test/unit/website-assets-bindings.test.mjs +0 -60
  400. package/test/whoami-resume.test.mjs +0 -157
@@ -0,0 +1,527 @@
1
+ /**
2
+ * Lane 1 shared IdentityStore behavioral suite.
3
+ * Adapter factory is the variable; expected behavior is not.
4
+ */
5
+ import assert from 'node:assert/strict';
6
+ import fs from 'node:fs';
7
+ import os from 'node:os';
8
+ import path from 'node:path';
9
+ import { createHash } from 'node:crypto';
10
+ import { DatabaseSync } from 'node:sqlite';
11
+ import { describe, it } from 'node:test';
12
+ import { fileURLToPath } from 'node:url';
13
+ import { createLocalSqliteDatabase } from '../../../src/local/sqlite.js';
14
+ import {
15
+ applyPortableIdentityMigrations,
16
+ createSqliteIdentityAdapter,
17
+ resolveIdentitySchemaPack,
18
+ } from '../src/adapters/sqlite/index.js';
19
+ import { createPortableD1IdentityAdapter } from '../src/adapters/portable-d1/index.js';
20
+ import {
21
+ createIamCompatIdentityAdapter,
22
+ createCloudflareD1Adapter,
23
+ } from '../src/adapters/iam-compat/index.js';
24
+ import { createPasswordResetService } from '../src/recovery/password-reset.js';
25
+ import { IDENTITY_STORE_SCHEMA_VERSION } from '../src/contracts/identity-store.js';
26
+ import { SESSION_TYPES } from '../src/core/session-policy.js';
27
+
28
+ const PKG = path.resolve(path.dirname(fileURLToPath(import.meta.url)), '..');
29
+ const SQL_DIR = path.join(PKG, 'migrations', 'sqlite');
30
+
31
+ const FIXTURE = Object.freeze({
32
+ email: 'user123@example.test',
33
+ displayName: 'User 123',
34
+ companyName: 'Example Company',
35
+ companySlug: 'example',
36
+ host: 'example.test',
37
+ appId: 'app.example.test',
38
+ provider: 'example-idp',
39
+ providerSubject: 'subj_user123',
40
+ credentialRef: 'vault:ref/example-idp/user123',
41
+ });
42
+
43
+ function wrapDatabaseSync(sqlite) {
44
+ return {
45
+ sqlite,
46
+ prepare(sql) {
47
+ const stmt = () => sqlite.prepare(sql);
48
+ const bound = (...args) => ({
49
+ first: async () => stmt().get(...args) ?? null,
50
+ run: async () => {
51
+ stmt().run(...args);
52
+ return { success: true };
53
+ },
54
+ all: async () => ({ results: stmt().all(...args) }),
55
+ });
56
+ return {
57
+ bind: (...args) => bound(...args),
58
+ first: async () => stmt().get() ?? null,
59
+ run: async () => {
60
+ stmt().run();
61
+ return { success: true };
62
+ },
63
+ all: async () => ({ results: stmt().all() }),
64
+ };
65
+ },
66
+ exec(sql) {
67
+ sqlite.exec(sql);
68
+ },
69
+ };
70
+ }
71
+
72
+ function createMemoryKv() {
73
+ const map = new Map();
74
+ return {
75
+ async get(key) {
76
+ const row = map.get(key);
77
+ if (!row) return null;
78
+ if (row.exp && Date.now() > row.exp) {
79
+ map.delete(key);
80
+ return null;
81
+ }
82
+ return row.value;
83
+ },
84
+ async put(key, value, opts = {}) {
85
+ const ttl = opts.expirationTtl ? opts.expirationTtl * 1000 : null;
86
+ map.set(key, { value, exp: ttl ? Date.now() + ttl : null });
87
+ },
88
+ async delete(key) {
89
+ map.delete(key);
90
+ },
91
+ };
92
+ }
93
+
94
+ async function runIdentityStoreSuite(adapter, { label }) {
95
+ const company = await adapter.upsertCompany({
96
+ id: 'co_example',
97
+ slug: FIXTURE.companySlug,
98
+ name: FIXTURE.companyName,
99
+ supportEmail: 'support@example.test',
100
+ websiteUrl: `https://${FIXTURE.host}`,
101
+ meta: { hosts: [FIXTURE.host] },
102
+ });
103
+ assert.equal(company.name, FIXTURE.companyName, label);
104
+ assert.equal((await adapter.getCompanyBySlug(FIXTURE.companySlug))?.name, FIXTURE.companyName);
105
+ assert.equal((await adapter.getCompanyByHost(FIXTURE.host))?.slug, FIXTURE.companySlug);
106
+
107
+ const user = await adapter.createUser({
108
+ email: FIXTURE.email,
109
+ displayName: FIXTURE.displayName,
110
+ passwordHash: 'hash_demo',
111
+ salt: 'salt_demo',
112
+ });
113
+ assert.ok(user?.id, label);
114
+ assert.equal((await adapter.findUserByEmail(FIXTURE.email))?.id, user.id);
115
+ assert.equal((await adapter.findUserById(user.id))?.email, FIXTURE.email);
116
+
117
+ await adapter.updateUserPassword(user.id, 'hash_rotated', 'salt_rotated');
118
+ assert.equal((await adapter.findUserById(user.id))?.password_hash, 'hash_rotated');
119
+
120
+ await adapter.upsertProviderIdentity({
121
+ accountId: user.id,
122
+ provider: FIXTURE.provider,
123
+ providerSubject: FIXTURE.providerSubject,
124
+ email: FIXTURE.email,
125
+ });
126
+ assert.equal(
127
+ (await adapter.findUserByProvider(FIXTURE.provider, FIXTURE.providerSubject))?.id,
128
+ user.id,
129
+ );
130
+
131
+ const session = await adapter.createSession({
132
+ userId: user.id,
133
+ email: FIXTURE.email,
134
+ provider: 'email',
135
+ displayName: FIXTURE.displayName,
136
+ type: SESSION_TYPES.BROWSER,
137
+ });
138
+ assert.ok(session?.id);
139
+ assert.equal((await adapter.getSession(session.id))?.user_id, user.id);
140
+
141
+ const desktop = await adapter.createSession({
142
+ userId: user.id,
143
+ email: FIXTURE.email,
144
+ provider: FIXTURE.provider,
145
+ providerSubject: FIXTURE.providerSubject,
146
+ type: SESSION_TYPES.DESKTOP,
147
+ });
148
+ assert.equal(desktop.type, SESSION_TYPES.DESKTOP);
149
+
150
+ await adapter.createOAuthTransaction({
151
+ state: 'st_user123',
152
+ provider: FIXTURE.provider,
153
+ codeVerifier: 'verifier_user123',
154
+ returnTo: '/home',
155
+ appId: FIXTURE.appId,
156
+ });
157
+ const tx = await adapter.consumeOAuthTransaction('st_user123');
158
+ assert.equal(tx.app_id, FIXTURE.appId);
159
+ assert.equal(tx.return_to, '/home');
160
+ assert.equal(await adapter.consumeOAuthTransaction('st_user123'), null);
161
+
162
+ await adapter.createOAuthTransaction({
163
+ state: 'st_native_user123',
164
+ provider: FIXTURE.provider,
165
+ codeVerifier: 'verifier_native',
166
+ returnTo: '/home',
167
+ appId: FIXTURE.appId,
168
+ clientType: SESSION_TYPES.DESKTOP,
169
+ nativeChallenge: 'A'.repeat(43).replace(/A/g, 'a'),
170
+ nativeRedirect: 'exampleapp://auth/callback',
171
+ });
172
+ const nativeTx = await adapter.consumeOAuthTransaction('st_native_user123');
173
+ assert.equal(nativeTx.client_type, SESSION_TYPES.DESKTOP);
174
+ assert.ok(nativeTx.native_challenge);
175
+ assert.ok(nativeTx.native_redirect);
176
+
177
+ await assert.rejects(
178
+ () => adapter.createOAuthTransaction({
179
+ state: 'st_missing_app',
180
+ provider: FIXTURE.provider,
181
+ codeVerifier: 'v',
182
+ }),
183
+ (err) => err?.code === 'OAUTH_TRANSACTION_APP_ID_REQUIRED',
184
+ );
185
+
186
+ await adapter.logAuthEvent({
187
+ userId: user.id,
188
+ eventType: 'login',
189
+ status: 'ok',
190
+ provider: 'email',
191
+ });
192
+ const activity = await adapter.countAuthActivity(user.id);
193
+ assert.ok(activity.loginCount >= 1);
194
+ assert.ok(activity.activeSessionCount >= 1);
195
+
196
+ const handoffHash = createHash('sha256').update('handoff_code_user123').digest('hex');
197
+ await adapter.createNativeHandoff({
198
+ handoffHash,
199
+ sessionId: desktop.id,
200
+ challenge: nativeTx.native_challenge,
201
+ });
202
+ const claimed = await adapter.consumeNativeHandoff(handoffHash);
203
+ assert.equal(claimed.session_id, desktop.id);
204
+ assert.equal(await adapter.consumeNativeHandoff(handoffHash), null);
205
+
206
+ const connId = await adapter.upsertProviderConnection({
207
+ userId: user.id,
208
+ provider: FIXTURE.provider,
209
+ credentialRef: FIXTURE.credentialRef,
210
+ grantedScopes: ['openid', 'email'],
211
+ refreshable: true,
212
+ });
213
+ assert.ok(connId);
214
+ const conn = await adapter.getProviderConnection(user.id, FIXTURE.provider);
215
+ assert.equal(conn.credential_ref, FIXTURE.credentialRef);
216
+ assert.deepEqual(conn.granted_scopes, ['openid', 'email']);
217
+ assert.equal(conn.credential_ref.includes('secret'), false);
218
+
219
+ // Recovery: same storage-agnostic service against this adapter (injected KV + user hooks).
220
+ const kv = createMemoryKv();
221
+ let emailedCode = null;
222
+ const recovery = createPasswordResetService({
223
+ kv,
224
+ findEligibleUser: async (email) => adapter.findUserByEmail(email),
225
+ hashPassword: async (password) => ({
226
+ saltHex: 'salt_reset',
227
+ hashHex: `hash_${password}`,
228
+ }),
229
+ updatePassword: async (userId, hashHex, saltHex) => {
230
+ await adapter.updateUserPassword(userId, hashHex, saltHex);
231
+ },
232
+ sendResetEmail: async ({ code }) => {
233
+ emailedCode = code;
234
+ },
235
+ });
236
+ await recovery.requestReset({ email: FIXTURE.email });
237
+ assert.ok(emailedCode);
238
+ const reset = await recovery.confirmReset({
239
+ email: FIXTURE.email,
240
+ code: emailedCode,
241
+ password: 'new-password-ok',
242
+ confirmPassword: 'new-password-ok',
243
+ });
244
+ assert.equal(reset.ok, true);
245
+ assert.equal((await adapter.findUserById(user.id))?.password_hash, 'hash_new-password-ok');
246
+
247
+ await adapter.revokeSession(session.id);
248
+ assert.equal(await adapter.getSession(session.id), null);
249
+
250
+ return { userId: user.id, desktopSessionId: desktop.id };
251
+ }
252
+
253
+ function iamCompatMinimumSchemaSql() {
254
+ return `
255
+ CREATE TABLE IF NOT EXISTS accounts (
256
+ id TEXT PRIMARY KEY NOT NULL,
257
+ email TEXT NOT NULL COLLATE NOCASE,
258
+ display_name TEXT,
259
+ status TEXT NOT NULL DEFAULT 'active',
260
+ created_at INTEGER NOT NULL,
261
+ updated_at INTEGER NOT NULL
262
+ );
263
+ CREATE TABLE IF NOT EXISTS auth_users (
264
+ id TEXT PRIMARY KEY NOT NULL,
265
+ email TEXT NOT NULL COLLATE NOCASE,
266
+ display_name TEXT,
267
+ password_hash TEXT,
268
+ salt TEXT,
269
+ status TEXT NOT NULL DEFAULT 'active',
270
+ created_at INTEGER NOT NULL,
271
+ updated_at INTEGER NOT NULL
272
+ );
273
+ CREATE TABLE IF NOT EXISTS account_identities (
274
+ id TEXT PRIMARY KEY NOT NULL,
275
+ account_id TEXT NOT NULL,
276
+ provider TEXT NOT NULL,
277
+ provider_subject TEXT NOT NULL,
278
+ email TEXT,
279
+ created_at INTEGER NOT NULL,
280
+ updated_at INTEGER NOT NULL,
281
+ UNIQUE(provider, provider_subject)
282
+ );
283
+ CREATE TABLE IF NOT EXISTS auth_sessions (
284
+ id TEXT PRIMARY KEY NOT NULL,
285
+ user_id TEXT NOT NULL,
286
+ email TEXT,
287
+ provider TEXT,
288
+ provider_subject TEXT,
289
+ display_name TEXT,
290
+ expires_at INTEGER NOT NULL,
291
+ revoked_at INTEGER,
292
+ created_at INTEGER NOT NULL,
293
+ last_active_at INTEGER,
294
+ type TEXT NOT NULL DEFAULT 'browser'
295
+ );
296
+ CREATE TABLE IF NOT EXISTS auth_event_log (
297
+ id TEXT PRIMARY KEY NOT NULL,
298
+ user_id TEXT,
299
+ event_type TEXT NOT NULL,
300
+ status TEXT NOT NULL DEFAULT 'ok',
301
+ provider TEXT,
302
+ metadata_json TEXT NOT NULL DEFAULT '{}',
303
+ ip_hash TEXT,
304
+ user_agent_hash TEXT,
305
+ created_at INTEGER NOT NULL DEFAULT (unixepoch())
306
+ );
307
+ CREATE TABLE IF NOT EXISTS identity_oauth_states (
308
+ state TEXT PRIMARY KEY NOT NULL,
309
+ provider TEXT NOT NULL,
310
+ code_verifier TEXT NOT NULL,
311
+ redirect_to TEXT,
312
+ app_id TEXT NOT NULL,
313
+ expires_at INTEGER NOT NULL,
314
+ created_at INTEGER NOT NULL,
315
+ client_type TEXT,
316
+ native_challenge TEXT,
317
+ native_redirect TEXT
318
+ );
319
+ CREATE TABLE IF NOT EXISTS identity_native_handoffs (
320
+ handoff_hash TEXT PRIMARY KEY NOT NULL,
321
+ session_id TEXT NOT NULL,
322
+ challenge TEXT NOT NULL,
323
+ expires_at INTEGER NOT NULL,
324
+ created_at INTEGER NOT NULL,
325
+ consumed_at INTEGER
326
+ );
327
+ CREATE TABLE IF NOT EXISTS company (
328
+ id TEXT PRIMARY KEY NOT NULL,
329
+ slug TEXT NOT NULL,
330
+ name TEXT NOT NULL,
331
+ legal_name TEXT,
332
+ logo_url TEXT,
333
+ favicon_url TEXT,
334
+ primary_color TEXT,
335
+ auth_bg_color TEXT,
336
+ support_email TEXT,
337
+ website_url TEXT,
338
+ tagline TEXT,
339
+ meta_json TEXT,
340
+ created_at INTEGER NOT NULL,
341
+ updated_at INTEGER NOT NULL
342
+ );
343
+ CREATE UNIQUE INDEX IF NOT EXISTS idx_company_slug ON company(slug);
344
+ CREATE TABLE IF NOT EXISTS identity_provider_connections (
345
+ id TEXT PRIMARY KEY NOT NULL,
346
+ user_id TEXT NOT NULL,
347
+ provider TEXT NOT NULL,
348
+ granted_scopes_json TEXT NOT NULL DEFAULT '[]',
349
+ credential_ref TEXT NOT NULL,
350
+ expires_at INTEGER,
351
+ refreshable INTEGER NOT NULL DEFAULT 0,
352
+ created_at INTEGER NOT NULL,
353
+ updated_at INTEGER NOT NULL,
354
+ UNIQUE(user_id, provider)
355
+ );
356
+ `;
357
+ }
358
+
359
+ describe('Lane 1 agentsam.identity pack manifest', () => {
360
+ it('resolves pack family + protocol schema-pack contract', () => {
361
+ const { manifest, manifestPath, sqlDir } = resolveIdentitySchemaPack();
362
+ assert.equal(manifest.schema, 'agentsam.schema-pack.v1');
363
+ assert.equal(manifest.id, 'agentsam.identity');
364
+ assert.ok(manifest.components.includes('identity.core'));
365
+ assert.ok(manifest.components.includes('identity.oauth-client'));
366
+ assert.ok(manifest.components.includes('identity.oauth-server'));
367
+ assert.equal(manifest.seed_policy, 'none');
368
+ assert.equal(manifest.compatibility['iam-compat'].owns_portable_schema, false);
369
+ assert.ok(fs.existsSync(manifestPath));
370
+ assert.ok(fs.existsSync(path.join(sqlDir, '001_identity_core.sql')));
371
+ assert.ok(fs.existsSync(path.join(sqlDir, '005_identity_company_native.sql')));
372
+ const protocolSchema = path.resolve(PKG, '../../protocol/database/agentsam.schema-pack.v1.schema.json');
373
+ assert.ok(fs.existsSync(protocolSchema));
374
+ assert.equal(
375
+ fs.existsSync(path.join(PKG, 'schema/agentsam.schema-pack.v1.schema.json')),
376
+ false,
377
+ 'generic schema-pack contract must not live under identity package',
378
+ );
379
+ });
380
+ });
381
+
382
+ describe('Lane 1 migration paths', () => {
383
+ it('fresh install reaches schema_version 2', async () => {
384
+ const dir = fs.mkdtempSync(path.join(os.tmpdir(), 'lane1-fresh-'));
385
+ const db = await createLocalSqliteDatabase(path.join(dir, 'identity.sqlite'));
386
+ await applyPortableIdentityMigrations(db);
387
+ const row = await db.prepare(
388
+ `SELECT value FROM identity_schema_meta WHERE key = 'schema_version' LIMIT 1`,
389
+ ).bind().first();
390
+ assert.equal(Number(row.value), IDENTITY_STORE_SCHEMA_VERSION);
391
+ const companies = await db.prepare(
392
+ `SELECT name FROM sqlite_master WHERE type='table' AND name='identity_companies'`,
393
+ ).bind().first();
394
+ assert.ok(companies);
395
+ const forbidden = await db.prepare(
396
+ `SELECT name FROM sqlite_master WHERE type='table' AND name IN ('accounts','auth_users','company','oauth_states')`,
397
+ ).bind().all();
398
+ assert.equal((forbidden.results || []).length, 0);
399
+ });
400
+
401
+ it('upgrade: schema_version 1 → 005 → 2 keeps prior rows', async () => {
402
+ const sqlite = new DatabaseSync(':memory:');
403
+ sqlite.exec(fs.readFileSync(path.join(SQL_DIR, '001_identity_core.sql'), 'utf8'));
404
+ sqlite.exec(fs.readFileSync(path.join(SQL_DIR, '002_identity_oauth_client.sql'), 'utf8'));
405
+ const before = sqlite.prepare(`SELECT value FROM identity_schema_meta WHERE key='schema_version'`).get();
406
+ assert.equal(Number(before.value), 1);
407
+
408
+ const ts = Math.floor(Date.now() / 1000);
409
+ sqlite.prepare(
410
+ `INSERT INTO identity_users (id, email, display_name, password_hash, salt, status, created_at, updated_at)
411
+ VALUES ('au_upgrade', 'upgrade@example.test', 'Upgrade', 'h', 's', 'active', ?, ?)`,
412
+ ).run(ts, ts);
413
+ sqlite.prepare(
414
+ `INSERT INTO identity_oauth_transactions
415
+ (state, provider, code_verifier, return_to, app_id, expires_at, created_at, consumed_at)
416
+ VALUES ('st_upgrade', 'example', 'v', '/x', 'app.example', ?, ?, NULL)`,
417
+ ).run(ts + 600, ts);
418
+
419
+ const db = wrapDatabaseSync(sqlite);
420
+ // Apply only 005 (upgrade path).
421
+ const sql005 = fs.readFileSync(path.join(SQL_DIR, '005_identity_company_native.sql'), 'utf8');
422
+ const statements = sql005
423
+ .replace(/\/\*[\s\S]*?\*\//g, '')
424
+ .split(';')
425
+ .map((s) => s.replace(/--[^\n]*/g, '').trim())
426
+ .filter(Boolean);
427
+ for (const statement of statements) {
428
+ try {
429
+ sqlite.exec(statement);
430
+ } catch (err) {
431
+ const msg = String(err?.message || err).toLowerCase();
432
+ if (!msg.includes('duplicate column')) throw err;
433
+ }
434
+ }
435
+
436
+ const after = sqlite.prepare(`SELECT value FROM identity_schema_meta WHERE key='schema_version'`).get();
437
+ assert.equal(Number(after.value), 2);
438
+ const user = sqlite.prepare(`SELECT email FROM identity_users WHERE id='au_upgrade'`).get();
439
+ assert.equal(user.email, 'upgrade@example.test');
440
+ const tx = sqlite.prepare(`SELECT app_id FROM identity_oauth_transactions WHERE state='st_upgrade'`).get();
441
+ assert.equal(tx.app_id, 'app.example');
442
+ const handoffs = sqlite.prepare(
443
+ `SELECT name FROM sqlite_master WHERE type='table' AND name='identity_native_handoffs'`,
444
+ ).get();
445
+ assert.ok(handoffs);
446
+
447
+ const adapter = createSqliteIdentityAdapter(db);
448
+ const session = await adapter.createSession({
449
+ userId: 'au_upgrade',
450
+ email: 'upgrade@example.test',
451
+ type: SESSION_TYPES.DESKTOP,
452
+ });
453
+ assert.equal(session.type, SESSION_TYPES.DESKTOP);
454
+ });
455
+ });
456
+
457
+ describe('Lane 1 shared IdentityStore parity', () => {
458
+ it('A. clean SQLite portable', async () => {
459
+ const dir = fs.mkdtempSync(path.join(os.tmpdir(), 'lane1-sqlite-'));
460
+ const file = path.join(dir, 'identity.sqlite');
461
+ const db = await createLocalSqliteDatabase(file);
462
+ await applyPortableIdentityMigrations(db);
463
+ const adapter = createSqliteIdentityAdapter(db);
464
+ assert.equal(adapter.backend, 'sqlite');
465
+ await runIdentityStoreSuite(adapter, { label: 'sqlite' });
466
+
467
+ // Durability: reopen
468
+ const db2 = await createLocalSqliteDatabase(file);
469
+ const adapter2 = createSqliteIdentityAdapter(db2);
470
+ assert.equal((await adapter2.findUserByEmail(FIXTURE.email))?.display_name, FIXTURE.displayName);
471
+ assert.equal((await adapter2.getCompanyBySlug(FIXTURE.companySlug))?.name, FIXTURE.companyName);
472
+ });
473
+
474
+ it('B. clean portable D1-shaped (same SQL pack)', async () => {
475
+ const sqlite = new DatabaseSync(':memory:');
476
+ const db = wrapDatabaseSync(sqlite);
477
+ await applyPortableIdentityMigrations(db);
478
+ const adapter = createPortableD1IdentityAdapter(db);
479
+ assert.equal(adapter.backend, 'portable-d1');
480
+ await runIdentityStoreSuite(adapter, { label: 'portable-d1' });
481
+ const forbidden = sqlite.prepare(
482
+ `SELECT name FROM sqlite_master WHERE type='table' AND name IN ('accounts','auth_users','company')`,
483
+ ).all();
484
+ assert.equal(forbidden.length, 0);
485
+ });
486
+
487
+ it('C. IAM compat on production-shaped fixture (no production rows)', async () => {
488
+ const sqlite = new DatabaseSync(':memory:');
489
+ sqlite.exec(iamCompatMinimumSchemaSql());
490
+ const db = wrapDatabaseSync(sqlite);
491
+ const adapter = createIamCompatIdentityAdapter(db);
492
+ assert.equal(adapter.backend, 'iam-compat');
493
+ await runIdentityStoreSuite(adapter, { label: 'iam-compat' });
494
+ const accounts = sqlite.prepare(`SELECT email FROM auth_users WHERE email=?`).get(FIXTURE.email);
495
+ assert.ok(accounts);
496
+ const companies = sqlite.prepare(`SELECT name FROM company WHERE slug=?`).get(FIXTURE.companySlug);
497
+ assert.equal(companies.name, FIXTURE.companyName);
498
+ });
499
+
500
+ it('D. createCloudflareD1Adapter remains IAM-compat alias', async () => {
501
+ const sqlite = new DatabaseSync(':memory:');
502
+ sqlite.exec(iamCompatMinimumSchemaSql());
503
+ const db = wrapDatabaseSync(sqlite);
504
+ const adapter = createCloudflareD1Adapter(db);
505
+ assert.equal(adapter.backend, 'iam-compat');
506
+ assert.equal(createCloudflareD1Adapter, createIamCompatIdentityAdapter);
507
+ await runIdentityStoreSuite(adapter, { label: 'cloudflare-d1-alias' });
508
+ });
509
+ });
510
+
511
+ describe('Lane 1 operator-bleed guard (fixtures)', () => {
512
+ it('parity fixture uses generic user123 identities only', () => {
513
+ assert.equal(FIXTURE.email, 'user123@example.test');
514
+ assert.equal(FIXTURE.companyName, 'Example Company');
515
+ assert.equal(FIXTURE.host, 'example.test');
516
+ assert.equal(FIXTURE.appId, 'app.example.test');
517
+ const fixtureBlob = JSON.stringify(FIXTURE);
518
+ for (const bad of [
519
+ 'SamPrimeaux',
520
+ 'Sams-iMac',
521
+ 'inneranimalmedia-business',
522
+ 'inneranimalmedia.com',
523
+ ]) {
524
+ assert.equal(fixtureBlob.includes(bad), false, `operator bleed in fixture: ${bad}`);
525
+ }
526
+ });
527
+ });
@@ -0,0 +1,175 @@
1
+ /**
2
+ * Mandatory packed-npm consumer proof for Lane 1 identity portability.
3
+ * Installs the root SDK tarball outside the monorepo and runs a user123 smoke
4
+ * using ONLY package exports (no file: escapes / absolute operator paths).
5
+ */
6
+ import assert from 'node:assert/strict';
7
+ import { execFileSync } from 'node:child_process';
8
+ import fs from 'node:fs';
9
+ import os from 'node:os';
10
+ import path from 'node:path';
11
+ import { describe, it } from 'node:test';
12
+ import { fileURLToPath } from 'node:url';
13
+
14
+ const REPO = path.resolve(path.dirname(fileURLToPath(import.meta.url)), '../../..');
15
+
16
+ function run(cmd, args, cwd) {
17
+ // npm run exports allow-scripts as an environment option, which newer npm rejects
18
+ // for nested project installs. Strip that inherited allowance in the child only.
19
+ const env = { ...process.env };
20
+ for (const key of Object.keys(env)) {
21
+ if (/^npm_config_(?:allow[_-]?scripts|dry[_-]?run)$/i.test(key)) delete env[key];
22
+ }
23
+ return execFileSync(cmd, args, {
24
+ cwd,
25
+ env,
26
+ encoding: 'utf8',
27
+ stdio: ['ignore', 'pipe', 'pipe'],
28
+ maxBuffer: 32 * 1024 * 1024,
29
+ });
30
+ }
31
+
32
+ describe('Lane 1 packed identity consumer proof', () => {
33
+ it('npm pack → clean install → portable migrate + sqlite smoke', () => {
34
+ const work = fs.mkdtempSync(path.join(os.tmpdir(), 'lane1-pack-'));
35
+ const artifacts = path.join(work, 'artifacts');
36
+ fs.mkdirSync(artifacts);
37
+ const packOut = run('npm', ['pack', '--json', '--ignore-scripts', '--pack-destination', artifacts], REPO);
38
+ const packed = JSON.parse(packOut);
39
+ const tarballName = packed[0]?.filename || packed.filename;
40
+ assert.ok(tarballName, 'npm pack must emit a tarball name');
41
+ const tarballDest = path.join(artifacts, tarballName);
42
+ assert.ok(fs.existsSync(tarballDest), tarballDest);
43
+
44
+ const consumer = path.join(work, 'consumer');
45
+ fs.mkdirSync(consumer);
46
+ fs.writeFileSync(
47
+ path.join(consumer, 'package.json'),
48
+ JSON.stringify({
49
+ name: 'user123-identity-smoke',
50
+ private: true,
51
+ type: 'module',
52
+ allowScripts: {},
53
+ }, null, 2),
54
+ );
55
+ run(
56
+ 'npm',
57
+ ['install', tarballDest, '--ignore-scripts', '--no-audit', '--no-fund'],
58
+ consumer,
59
+ );
60
+
61
+ const smoke = `
62
+ import assert from 'node:assert/strict';
63
+ import fs from 'node:fs';
64
+ import os from 'node:os';
65
+ import path from 'node:path';
66
+ import { createRequire } from 'node:module';
67
+ import { pathToFileURL } from 'node:url';
68
+ import {
69
+ IDENTITY_STORE_SCHEMA_VERSION,
70
+ IdentitySchemaError,
71
+ } from '@inneranimalmedia/agentsam-sdk/identity/contracts/identity-store';
72
+ import {
73
+ applyPortableIdentityMigrations,
74
+ createSqliteIdentityAdapter,
75
+ resolveIdentitySchemaPack,
76
+ } from '@inneranimalmedia/agentsam-sdk/identity/adapters/sqlite';
77
+ import { createPortableD1IdentityAdapter } from '@inneranimalmedia/agentsam-sdk/identity/adapters/portable-d1';
78
+ import { createIamCompatIdentityAdapter } from '@inneranimalmedia/agentsam-sdk/identity/adapters/iam-compat';
79
+ import { createCloudflareD1Adapter } from '@inneranimalmedia/agentsam-sdk/identity/adapters/cloudflare-d1';
80
+
81
+ assert.equal(typeof createIamCompatIdentityAdapter, 'function');
82
+ assert.equal(createCloudflareD1Adapter, createIamCompatIdentityAdapter);
83
+ assert.equal(typeof createPortableD1IdentityAdapter, 'function');
84
+ assert.ok(IDENTITY_STORE_SCHEMA_VERSION >= 2);
85
+ assert.ok(IdentitySchemaError);
86
+
87
+ const pack = resolveIdentitySchemaPack();
88
+ assert.equal(pack.manifest.id, 'agentsam.identity');
89
+ assert.ok(fs.existsSync(pack.manifestPath));
90
+ assert.ok(fs.existsSync(path.join(pack.sqlDir, '001_identity_core.sql')));
91
+ assert.ok(fs.existsSync(path.join(pack.sqlDir, '005_identity_company_native.sql')));
92
+
93
+ const require = createRequire(import.meta.url);
94
+ const sdkPkgJson = require.resolve('@inneranimalmedia/agentsam-sdk/package.json');
95
+ const pkgRoot = path.dirname(sdkPkgJson);
96
+ for (const p of [pack.manifestPath, pack.sqlDir, pkgRoot]) {
97
+ assert.ok(p.includes('node_modules/@inneranimalmedia/agentsam-sdk'), p);
98
+ assert.equal(p.includes('Sams-iMac'), false, p);
99
+ assert.equal(p.includes('inneranimalmedia-business'), false, p);
100
+ }
101
+
102
+ const { DatabaseSync } = require('node:sqlite');
103
+ const dbFile = path.join(os.tmpdir(), 'user123-identity-' + Date.now() + '.sqlite');
104
+ const sqlite = new DatabaseSync(dbFile);
105
+ const db = {
106
+ prepare(sql) {
107
+ const statement = sqlite.prepare(sql);
108
+ return {
109
+ bind(...args) {
110
+ return {
111
+ first: async () => statement.get(...args) ?? null,
112
+ run: async () => { statement.run(...args); return { success: true }; },
113
+ all: async () => ({ results: statement.all(...args) }),
114
+ };
115
+ },
116
+ first: async () => statement.get() ?? null,
117
+ run: async () => { statement.run(); return { success: true }; },
118
+ all: async () => ({ results: statement.all() }),
119
+ };
120
+ },
121
+ exec(sql) { sqlite.exec(sql); },
122
+ };
123
+
124
+ await applyPortableIdentityMigrations(db);
125
+ const adapter = createSqliteIdentityAdapter(db);
126
+ const user = await adapter.createUser({
127
+ email: 'user123@example.test',
128
+ displayName: 'User 123',
129
+ passwordHash: 'h',
130
+ salt: 's',
131
+ });
132
+ await adapter.upsertCompany({
133
+ slug: 'example',
134
+ name: 'Example Company',
135
+ supportEmail: 'support@example.test',
136
+ });
137
+ assert.equal((await adapter.findUserByEmail('user123@example.test'))?.id, user.id);
138
+ assert.equal((await adapter.getCompanyBySlug('example'))?.name, 'Example Company');
139
+ await adapter.createOAuthTransaction({
140
+ state: 'st1',
141
+ provider: 'example',
142
+ codeVerifier: 'v',
143
+ appId: 'app.example.test',
144
+ });
145
+ const tx = await adapter.consumeOAuthTransaction('st1');
146
+ assert.equal(tx.app_id, 'app.example.test');
147
+ console.log(JSON.stringify({ ok: true, schemaVersion: IDENTITY_STORE_SCHEMA_VERSION, userId: user.id }));
148
+ `;
149
+ const smokePath = path.join(consumer, 'smoke.mjs');
150
+ fs.writeFileSync(smokePath, smoke);
151
+ const out = run(process.execPath, [smokePath], consumer);
152
+ const receipt = JSON.parse(out.trim().split('\n').at(-1));
153
+ assert.equal(receipt.ok, true);
154
+ assert.ok(receipt.userId);
155
+
156
+ const installedPkg = JSON.parse(
157
+ fs.readFileSync(
158
+ path.join(consumer, 'node_modules/@inneranimalmedia/agentsam-sdk/package.json'),
159
+ 'utf8',
160
+ ),
161
+ );
162
+ const depValues = Object.values(installedPkg.dependencies || {});
163
+ for (const v of depValues) {
164
+ assert.equal(String(v).startsWith('file:../'), false, v);
165
+ assert.equal(String(v).includes('/Users/samprimeaux'), false, v);
166
+ }
167
+
168
+ // Packed tarball must include portable SQL + manifest
169
+ const listed = run('tar', ['-tzf', tarballDest], work);
170
+ assert.ok(listed.includes('packages/identity/migrations/sqlite/001_identity_core.sql'));
171
+ assert.ok(listed.includes('packages/identity/migrations/sqlite/005_identity_company_native.sql'));
172
+ assert.ok(listed.includes('packages/identity/schema/agentsam.identity/manifest.json'));
173
+ assert.ok(listed.includes('protocol/database/agentsam.schema-pack.v1.schema.json'));
174
+ });
175
+ });