@inneranimalmedia/agentsam-sdk 2.6.2 → 2.6.4

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (661) hide show
  1. package/AGENTSAM.md +51 -1
  2. package/README.md +95 -0
  3. package/apps/README.md +34 -0
  4. package/apps/cad-creator/README.md +728 -0
  5. package/apps/cad-creator/shared/cad/package.json +19 -0
  6. package/apps/cad-creator/shared/cad/src/domain/operations.ts +7 -0
  7. package/apps/cad-creator/shared/cad/src/domain/project-contract.d.ts +3 -0
  8. package/apps/cad-creator/shared/cad/src/domain/project-contract.js +75 -0
  9. package/apps/cad-creator/shared/cad/src/domain/project-tools.d.ts +1 -0
  10. package/apps/cad-creator/shared/cad/src/domain/project-tools.js +24 -0
  11. package/apps/cad-creator/shared/cad/src/domain/validation.ts +191 -0
  12. package/apps/cad-creator/shared/cad/src/index.ts +4 -0
  13. package/apps/cad-creator/shared/cad/src/robotics/types.ts +232 -0
  14. package/apps/cad-creator/shared/cad/src/types.ts +507 -0
  15. package/apps/cad-creator/shared/cad/tsconfig.json +14 -0
  16. package/bin/agentsam +16 -1
  17. package/docs/AUTORAG.md +58 -0
  18. package/docs/BRAND_INTELLIGENCE.md +30 -0
  19. package/docs/CLI_SHELL.md +4 -2
  20. package/docs/CMS_CONTEXTUAL_COMPOSER.md +38 -0
  21. package/docs/MERKLE.md +4 -0
  22. package/docs/PROJECT_CONFIG.md +3 -0
  23. package/docs/REPOSITORY_KNOWLEDGE.md +2 -0
  24. package/docs/THEME_REFINERY.md +120 -0
  25. package/docs/architecture/AGENTSAM_DISTRIBUTION_OWNERSHIP.md +176 -0
  26. package/docs/architecture/AGENTSAM_GO_RUNTIME.md +282 -0
  27. package/docs/architecture/CODEBASEINDEX_GUIDED_PATH.md +202 -0
  28. package/docs/architecture/FS_E2E_CLOSURE_RECEIPT.md +59 -0
  29. package/docs/architecture/LOCAL_FS_AUTHORITY.md +38 -0
  30. package/docs/architecture/LOCAL_STUDIO_CLOUDFLARE_OAUTH.md +28 -0
  31. package/docs/architecture/PLAN_CLI_AND_LOCAL_STUDIO_DESKTOP.md +96 -0
  32. package/docs/architecture/PROVIDER-TOOLS-AND-COMPACTION.md +60 -0
  33. package/docs/architecture/SAM_ACTIVITY_RECOVERY_RECEIPT.md +39 -0
  34. package/docs/architecture/SAM_DECISION_WORK_RECEIPT.md +54 -0
  35. package/docs/architecture/SAM_KERNEL.md +181 -0
  36. package/docs/architecture/SAM_MACHINE_NORMALIZATION_PRECOMMIT_REPORT.md +208 -0
  37. package/docs/architecture/SLASH_SKILLS_PORTABLE.md +116 -0
  38. package/docs/architecture/STORAGE.md +87 -0
  39. package/docs/architecture/fs-e2e-receipt.latest.json +42 -0
  40. package/docs/architecture/previews/codebaseindex-guided-path/CODEBASEINDEX_GUIDED_PATH.md +202 -0
  41. package/docs/architecture/previews/codebaseindex-guided-path/index.html +321 -0
  42. package/docs/cad-project-tools.md +69 -0
  43. package/docs/cms-scaffolding-pattern-reference.md +73 -0
  44. package/docs/plans/AGENTSAM-INTERACTIVE-UI-REQUIREMENTS-codex-tui-20260919.md +113 -0
  45. package/docs/plans/AGENTSAM-INTERACTIVE-UI-REQUIREMENTS.md +85 -0
  46. package/docs/plans/AGENTSAM-MCP-CLIENT-2026-09-19.md +181 -0
  47. package/docs/plans/ASBD-PORTABLE-WORKGRAPH-UI-DEFERRED.md +34 -0
  48. package/docs/plans/ASTRA-BRIEF-2026-09-18.md +258 -0
  49. package/docs/plans/MULTI-AGENT-SPRINTS-2026-09-19.md +373 -0
  50. package/docs/plans/NEXT-AGENT-HANDOFF.md +167 -0
  51. package/docs/plans/RECONCILIATION-2026-09-19.md +178 -0
  52. package/docs/plugins.md +43 -0
  53. package/docs/tools/README.md +57 -0
  54. package/docs/tools/agent-and-orchestration.md +49 -0
  55. package/docs/tools/browser-and-research.md +46 -0
  56. package/docs/tools/cloudflare-platform.md +32 -0
  57. package/docs/tools/cms.md +25 -0
  58. package/docs/tools/communications.md +41 -0
  59. package/docs/tools/database-and-storage.md +62 -0
  60. package/docs/tools/design-and-media.md +64 -0
  61. package/docs/tools/filesystem-and-code.md +55 -0
  62. package/docs/tools/github.md +56 -0
  63. package/docs/tools/integrations-and-misc.md +16 -0
  64. package/docs/tools/memory.md +21 -0
  65. package/docs/tools/terminal-and-execution.md +29 -0
  66. package/docs/tools/tickets-and-platform.md +30 -0
  67. package/migrations/d1/0001_agentsam_plugin_runtime.sql +177 -0
  68. package/migrations/d1/0002_agentsam_ticket_ownership.sql +8 -0
  69. package/migrations/d1/0002_dynamic_model_policies.sql +23 -0
  70. package/migrations/d1/0003_expand_tool_handler_families.sql +18 -0
  71. package/migrations/d1/0004_project_aware_retrieval_lanes.sql +24 -0
  72. package/migrations/d1/0005_portable_knowledge_identity.sql +104 -0
  73. package/migrations/d1/0006_repair_ops_trail_account_scope.sql +14 -0
  74. package/migrations/d1/0007_repair_ops_trail_agent_run_account.sql +13 -0
  75. package/migrations/d1/0008_backfill_knowledge_run_legacy_tenant.sql +14 -0
  76. package/migrations/d1/0009_normalize_cloudflare_plugin_installations.sql +137 -0
  77. package/migrations/d1/0010_portable_tickets_memory.sql +140 -0
  78. package/migrations/d1/0011_agentsam_skill_v2.sql +185 -0
  79. package/migrations/d1/0011b_agentsam_skill_v2_cutover.sql +22 -0
  80. package/migrations/d1/0011c_agentsam_skill_v2_backfill.sql +76 -0
  81. package/migrations/d1/0011d_agentsam_skill_v2_retrieval_revisions.sql +50 -0
  82. package/migrations/d1/0012_agentsam_tools_required_seed.sql +67 -0
  83. package/migrations/d1/0013_identity_oauth_states.sql +15 -0
  84. package/migrations/d1/0014_auth_event_log.sql +20 -0
  85. package/migrations/d1/0015_identity_oauth_state_app_id.sql +3 -0
  86. package/migrations/d1/README_PORTABLE_CONTROL_PLANE.md +16 -0
  87. package/migrations/runtime/0001_cli_runtime.sql +67 -0
  88. package/migrations/runtime/0002_project_sessions.sql +15 -0
  89. package/migrations/runtime/0003_provider_continuations.sql +8 -0
  90. package/migrations/sqlite/agentsam_skill_retrieval.portable.sql +42 -0
  91. package/package.json +107 -12
  92. package/packages/agentsam-brand/README.md +21 -0
  93. package/packages/agentsam-brand/package.json +22 -0
  94. package/packages/agentsam-brand/src/contract.js +59 -0
  95. package/packages/agentsam-brand/src/extract.js +126 -0
  96. package/packages/agentsam-brand/src/goap-actions.js +73 -0
  97. package/packages/agentsam-brand/src/index.js +48 -0
  98. package/packages/agentsam-brand/src/plan.js +115 -0
  99. package/packages/agentsam-brand/src/resolve.js +139 -0
  100. package/packages/agentsam-brand/src/scan.js +250 -0
  101. package/packages/agentsam-brand/test/brand-scan.test.mjs +106 -0
  102. package/packages/agentsam-contracts/README.md +23 -0
  103. package/packages/agentsam-contracts/package.json +32 -0
  104. package/packages/agentsam-contracts/src/adapter.ts +25 -0
  105. package/packages/agentsam-contracts/src/agent.ts +35 -0
  106. package/packages/agentsam-contracts/src/artifacts.ts +33 -0
  107. package/packages/agentsam-contracts/src/authority.ts +29 -0
  108. package/packages/agentsam-contracts/src/context.ts +16 -0
  109. package/packages/agentsam-contracts/src/errors.ts +62 -0
  110. package/packages/agentsam-contracts/src/events.ts +47 -0
  111. package/packages/agentsam-contracts/src/execution.ts +50 -0
  112. package/packages/agentsam-contracts/src/hooks.ts +40 -0
  113. package/packages/agentsam-contracts/src/identity.ts +16 -0
  114. package/packages/agentsam-contracts/src/index.ts +14 -0
  115. package/packages/agentsam-contracts/src/models.ts +9 -0
  116. package/packages/agentsam-contracts/src/providers.ts +33 -0
  117. package/packages/agentsam-contracts/src/repository.ts +64 -0
  118. package/packages/agentsam-contracts/src/tools.ts +98 -0
  119. package/packages/agentsam-contracts/test/contracts.test.mjs +16 -0
  120. package/packages/agentsam-contracts/test/errors-catalog.test.mjs +25 -0
  121. package/packages/agentsam-contracts/test/repository.test.mjs +18 -0
  122. package/packages/agentsam-contracts/tsconfig.json +12 -0
  123. package/packages/agentsam-errors/package.json +17 -0
  124. package/packages/agentsam-errors/src/adapters/anthropic.js +15 -0
  125. package/packages/agentsam-errors/src/adapters/cad.js +109 -0
  126. package/packages/agentsam-errors/src/adapters/cloudflare.js +21 -0
  127. package/packages/agentsam-errors/src/adapters/cursor.js +4 -0
  128. package/packages/agentsam-errors/src/adapters/device.js +38 -0
  129. package/packages/agentsam-errors/src/adapters/docker.js +28 -0
  130. package/packages/agentsam-errors/src/adapters/gcp.js +14 -0
  131. package/packages/agentsam-errors/src/adapters/github.js +22 -0
  132. package/packages/agentsam-errors/src/adapters/google.js +17 -0
  133. package/packages/agentsam-errors/src/adapters/index.js +55 -0
  134. package/packages/agentsam-errors/src/adapters/internal.js +40 -0
  135. package/packages/agentsam-errors/src/adapters/oauth.js +24 -0
  136. package/packages/agentsam-errors/src/adapters/openai.js +17 -0
  137. package/packages/agentsam-errors/src/adapters/process.js +35 -0
  138. package/packages/agentsam-errors/src/adapters/provider.js +114 -0
  139. package/packages/agentsam-errors/src/envelope.js +239 -0
  140. package/packages/agentsam-errors/src/error.js +24 -0
  141. package/packages/agentsam-errors/src/fingerprint.js +35 -0
  142. package/packages/agentsam-errors/src/index.js +11 -0
  143. package/packages/agentsam-errors/src/normalize.js +30 -0
  144. package/packages/agentsam-errors/src/recovery.js +301 -0
  145. package/packages/agentsam-errors/src/redaction.js +52 -0
  146. package/packages/agentsam-errors/src/render.js +16 -0
  147. package/packages/agentsam-errors/src/retry.js +10 -0
  148. package/packages/agentsam-errors/src/transport.js +52 -0
  149. package/packages/agentsam-errors/src/vocabulary.js +320 -0
  150. package/packages/agentsam-errors/test/envelope.test.mjs +70 -0
  151. package/packages/agentsam-errors/test/providers.test.mjs +99 -0
  152. package/packages/agentsam-errors/test/redaction.test.mjs +21 -0
  153. package/packages/agentsam-errors/test/runtime-cad-device.test.mjs +76 -0
  154. package/packages/agentsam-errors/test/transport.test.mjs +46 -0
  155. package/packages/agentsam-knowledge/package.json +15 -0
  156. package/packages/agentsam-knowledge/src/autorag/index.js +64 -0
  157. package/packages/agentsam-knowledge/src/backends/index.js +26 -0
  158. package/packages/agentsam-knowledge/src/index.js +3 -0
  159. package/packages/agentsam-knowledge/src/providers/index.js +107 -0
  160. package/packages/agentsam-knowledge/test/autorag.test.mjs +42 -0
  161. package/packages/agentsam-nav/README.md +40 -0
  162. package/packages/agentsam-nav/dist/Nav.d.ts +43 -0
  163. package/packages/agentsam-nav/dist/NavCollapsible.d.ts +10 -0
  164. package/packages/agentsam-nav/dist/NavContent.d.ts +2 -0
  165. package/packages/agentsam-nav/dist/NavFooter.d.ts +2 -0
  166. package/packages/agentsam-nav/dist/NavGroup.d.ts +3 -0
  167. package/packages/agentsam-nav/dist/NavHeader.d.ts +2 -0
  168. package/packages/agentsam-nav/dist/NavMenu.d.ts +22 -0
  169. package/packages/agentsam-nav/dist/NavProvider.d.ts +35 -0
  170. package/packages/agentsam-nav/dist/NavTrigger.d.ts +2 -0
  171. package/packages/agentsam-nav/dist/Surfaces.d.ts +41 -0
  172. package/packages/agentsam-nav/dist/browser.d.ts +11 -0
  173. package/packages/agentsam-nav/dist/browser.global.js +132 -0
  174. package/packages/agentsam-nav/dist/browser.js +613 -0
  175. package/packages/agentsam-nav/dist/contracts.d.ts +76 -0
  176. package/packages/agentsam-nav/dist/index.d.ts +11 -0
  177. package/packages/agentsam-nav/dist/index.js +614 -0
  178. package/packages/agentsam-nav/dist/legacy.css +83 -0
  179. package/packages/agentsam-nav/dist/shell.css +113 -0
  180. package/packages/agentsam-nav/dist/theme.css +113 -0
  181. package/packages/agentsam-nav/dist/utils.d.ts +1 -0
  182. package/packages/agentsam-nav/package.json +43 -0
  183. package/packages/agentsam-queue-control/README.md +107 -0
  184. package/packages/agentsam-queue-control/package.json +31 -0
  185. package/packages/agentsam-queue-control/schemas/job-envelope.schema.json +56 -0
  186. package/packages/agentsam-queue-control/src/adapters/cloudflare.js +152 -0
  187. package/packages/agentsam-queue-control/src/adapters/memory.js +38 -0
  188. package/packages/agentsam-queue-control/src/contracts.js +130 -0
  189. package/packages/agentsam-queue-control/src/control-plane.js +141 -0
  190. package/packages/agentsam-queue-control/src/dispatch.js +43 -0
  191. package/packages/agentsam-queue-control/src/index.js +7 -0
  192. package/packages/agentsam-queue-control/src/policy.js +88 -0
  193. package/packages/agentsam-queue-control/src/topology.js +66 -0
  194. package/packages/agentsam-queue-control/test/queue-control.test.mjs +100 -0
  195. package/packages/agentsam-repository/src/goap.js +718 -0
  196. package/packages/agentsam-repository/src/goap.js.bak-20260922011251 +670 -0
  197. package/packages/agentsam-repository/src/index.js +5 -0
  198. package/packages/agentsam-repository/src/merkle/cloudflare-persistence.js +2 -2
  199. package/packages/agentsam-repository/src/tickets.js +184 -0
  200. package/packages/agentsam-repository/src/work-tracking.js +199 -0
  201. package/packages/agentsam-repository/src/workspace-state.js +176 -0
  202. package/packages/agentsam-repository/test/goap-tickets-workspace-state.test.mjs +152 -0
  203. package/packages/connectors/cloudflare/src/index.js +297 -15
  204. package/packages/connectors/cloudflare/src/owner.js +43 -40
  205. package/packages/connectors/cloudflare/src/routes.js +176 -26
  206. package/packages/connectors/cloudflare/tests/connector.test.mjs +137 -2
  207. package/packages/heuristic-theme/README.md +11 -0
  208. package/packages/heuristic-theme/package.json +25 -0
  209. package/packages/heuristic-theme/src/index.js +2 -0
  210. package/packages/heuristic-theme/src/registry.js +36 -0
  211. package/packages/heuristic-theme/src/theme.js +41 -0
  212. package/packages/heuristic-theme/test/theme.test.mjs +26 -0
  213. package/packages/identity/.agentsam/features/oauth-login-portal/agentsam.feature.json +64 -0
  214. package/packages/identity/.agentsam/features/oauth-login-portal/providers.json +96 -0
  215. package/packages/identity/.agentsam/features/oauth-login-portal/resources.json +47 -0
  216. package/packages/identity/.agentsam/features/oauth-login-portal/routes.json +83 -0
  217. package/packages/identity/.agentsam/features/oauth-login-portal/ui.json +35 -0
  218. package/packages/identity/docs/PORTABLE_IDENTITY_ARCHITECTURE.md +50 -0
  219. package/packages/identity/migrations/D1_SCHEMA_MAPPING.md +31 -0
  220. package/packages/identity/migrations/sqlite/001_identity_core.sql +99 -0
  221. package/packages/identity/migrations/sqlite/002_identity_oauth_client.sql +38 -0
  222. package/packages/identity/migrations/sqlite/003_identity_oauth_server.sql +64 -0
  223. package/packages/identity/package.json +4 -3
  224. package/packages/identity/src/adapters/cloudflare-d1/ids.js +4 -0
  225. package/packages/identity/src/adapters/cloudflare-d1/index.js +156 -18
  226. package/packages/identity/src/adapters/sqlite/index.js +319 -0
  227. package/packages/identity/src/app/verify-app.js +95 -0
  228. package/packages/identity/src/contracts/identity-store.js +115 -0
  229. package/packages/identity/src/contracts/provider.js +3 -2
  230. package/packages/identity/src/contracts/route-ids.js +30 -0
  231. package/packages/identity/src/contracts/route-projection.js +218 -0
  232. package/packages/identity/src/contracts/routes.js +11 -0
  233. package/packages/identity/src/core/browser-paths.js +4 -5
  234. package/packages/identity/src/core/constants.js +13 -8
  235. package/packages/identity/src/core/session-policy.js +32 -0
  236. package/packages/identity/src/frontend/auth-portal/pages/login.html +16 -9
  237. package/packages/identity/src/frontend/auth-portal/pages/reset.html +3 -3
  238. package/packages/identity/src/frontend/auth-portal/pages/signup.html +3 -3
  239. package/packages/identity/src/frontend/auth-portal/preview/dashboard-stub.html +1 -1
  240. package/packages/identity/src/index.js +27 -0
  241. package/packages/identity/src/oauth/README.md +10 -4
  242. package/packages/identity/src/oauth/credentials.js +31 -11
  243. package/packages/identity/src/oauth/finalize-inbound.js +1 -1
  244. package/packages/identity/src/oauth/iam-platform.js +13 -12
  245. package/packages/identity/src/oauth/redirect-paths.js +27 -36
  246. package/packages/identity/src/providers/cloudflare/index.js +19 -0
  247. package/packages/identity/src/providers/cloudflare/mapper.js +21 -0
  248. package/packages/identity/src/providers/cloudflare/oauth.js +48 -0
  249. package/packages/identity/src/providers/cloudflare/profile.js +28 -0
  250. package/packages/identity/src/providers/index.js +18 -2
  251. package/packages/identity/src/server/identity-service.js +35 -8
  252. package/packages/identity/src/server/mount-policy.js +30 -0
  253. package/packages/identity/src/server/post-auth.js +79 -0
  254. package/packages/identity/src/server/worker-router.js +153 -66
  255. package/packages/identity/tests/finalize-inbound-oauth.test.mjs +6 -6
  256. package/packages/identity/tests/iam-provider.test.mjs +1 -1
  257. package/packages/identity/tests/identity-service.test.mjs +47 -1
  258. package/packages/identity/tests/oauth-credentials.test.mjs +3 -1
  259. package/packages/identity/tests/portable-identity-architecture.test.mjs +157 -0
  260. package/packages/identity/tests/session-routes-policy.test.mjs +21 -0
  261. package/packages/providers/completeful/README.md +38 -0
  262. package/packages/providers/completeful/package.json +29 -0
  263. package/packages/providers/completeful/src/client.js +162 -0
  264. package/packages/providers/completeful/src/events.js +49 -0
  265. package/packages/providers/completeful/src/index.js +22 -0
  266. package/packages/providers/completeful/src/tools.js +579 -0
  267. package/packages/providers/completeful/src/webhooks.js +55 -0
  268. package/packages/providers/completeful/test/provider.test.mjs +196 -0
  269. package/packages/theme-church-site/README.md +10 -0
  270. package/packages/theme-church-site/package.json +31 -0
  271. package/packages/theme-church-site/src/harvest.json +14 -0
  272. package/packages/theme-church-site/src/index.js +85 -0
  273. package/packages/theme-church-site/test/theme.test.mjs +19 -0
  274. package/packages/theme-companions-site/README.md +10 -0
  275. package/packages/theme-companions-site/package.json +31 -0
  276. package/packages/theme-companions-site/src/harvest.json +12 -0
  277. package/packages/theme-companions-site/src/index.js +83 -0
  278. package/packages/theme-companions-site/test/theme.test.mjs +19 -0
  279. package/packages/theme-floors-site/README.md +10 -0
  280. package/packages/theme-floors-site/package.json +31 -0
  281. package/packages/theme-floors-site/src/harvest.json +14 -0
  282. package/packages/theme-floors-site/src/index.js +83 -0
  283. package/packages/theme-floors-site/test/theme.test.mjs +19 -0
  284. package/packages/theme-fuelnfree-site/README.md +10 -0
  285. package/packages/theme-fuelnfree-site/package.json +31 -0
  286. package/packages/theme-fuelnfree-site/src/harvest.json +13 -0
  287. package/packages/theme-fuelnfree-site/src/index.js +82 -0
  288. package/packages/theme-fuelnfree-site/test/theme.test.mjs +19 -0
  289. package/packages/theme-handyman-site/README.md +10 -0
  290. package/packages/theme-handyman-site/package.json +31 -0
  291. package/packages/theme-handyman-site/src/harvest.json +10 -0
  292. package/packages/theme-handyman-site/src/index.js +84 -0
  293. package/packages/theme-handyman-site/test/theme.test.mjs +19 -0
  294. package/packages/theme-insurance-site/README.md +10 -0
  295. package/packages/theme-insurance-site/package.json +31 -0
  296. package/packages/theme-insurance-site/src/harvest.json +10 -0
  297. package/packages/theme-insurance-site/src/index.js +84 -0
  298. package/packages/theme-insurance-site/test/theme.test.mjs +19 -0
  299. package/packages/theme-shinshu-site/README.md +10 -0
  300. package/packages/theme-shinshu-site/package.json +31 -0
  301. package/packages/theme-shinshu-site/src/harvest.json +12 -0
  302. package/packages/theme-shinshu-site/src/index.js +84 -0
  303. package/packages/theme-shinshu-site/test/theme.test.mjs +19 -0
  304. package/packages/work-graph/README.md +49 -0
  305. package/packages/work-graph/package.json +19 -0
  306. package/packages/work-graph/prototype/README.md +32 -0
  307. package/packages/work-graph/prototype/data/demo-workgraph.js +47 -0
  308. package/packages/work-graph/prototype/renderers/timeline-model.js +21 -0
  309. package/packages/work-graph/prototype/renderers/workgraph-runtime.js +38 -0
  310. package/packages/work-graph/prototype-gnantt.html +655 -0
  311. package/packages/work-graph/src/adapters/business/projects.js +23 -0
  312. package/packages/work-graph/src/adapters/engineering/git.js +22 -0
  313. package/packages/work-graph/src/adapters/engineering/mcp.js +22 -0
  314. package/packages/work-graph/src/index.js +76 -0
  315. package/packages/work-graph/src/renderers/gantt-model.js +11 -0
  316. package/packages/work-graph/src/renderers/timeline.js +16 -0
  317. package/packages/work-graph/test/work-graph.test.mjs +37 -0
  318. package/protocol/README.md +12 -0
  319. package/protocol/apps/agentsam.app.v1.schema.json +51 -0
  320. package/protocol/brand/brandpack.v1.schema.json +43 -0
  321. package/protocol/capabilities/cloudflare-cpu-audit-input.schema.json +30 -6
  322. package/protocol/capabilities/cloudflare-cpu-profile-input.schema.json +18 -4
  323. package/protocol/capabilities/cloudflare-wrangler-native-input.schema.json +59 -10
  324. package/protocol/capabilities/knowledge-search-input.schema.json +35 -0
  325. package/protocol/capabilities/manifest.json +163 -1
  326. package/protocol/capabilities/repository-audit-input.schema.json +39 -6
  327. package/protocol/capabilities/repository-snapshot-input.schema.json +15 -3
  328. package/protocol/capabilities/terminal-exec-input.schema.json +55 -0
  329. package/protocol/commerce/catalog.v1.json +50 -0
  330. package/protocol/credentials/issue.v1.schema.json +38 -0
  331. package/protocol/database/connection.v1.schema.json +41 -0
  332. package/protocol/embeddings/embedding-profile.v1.schema.json +20 -0
  333. package/protocol/errors/error-catalog.json +164 -0
  334. package/protocol/errors/error-envelope.schema.json +678 -0
  335. package/protocol/errors/recovery.v1.schema.json +50 -0
  336. package/protocol/features/README.md +57 -0
  337. package/protocol/features/agentsam.feature.v1.schema.json +290 -0
  338. package/protocol/features/catalog.json +65 -0
  339. package/protocol/features/examples/provider-resend.feature.json +17 -0
  340. package/protocol/go/agentsam-go-runtime.v1.json +17 -0
  341. package/protocol/knowledge/LIFECYCLE.md +140 -0
  342. package/protocol/knowledge/README.md +4 -0
  343. package/protocol/presets/catalog.json +128 -19
  344. package/protocol/rpc/v1/errors.proto +24 -0
  345. package/protocol/runtime/workspace-fs.v1.schema.json +71 -0
  346. package/protocol/sam/activity.v1.schema.json +48 -0
  347. package/protocol/sam/answer.v1.schema.json +35 -0
  348. package/protocol/sam/calibration.v1.schema.json +21 -0
  349. package/protocol/sam/decision-receipt.v1.schema.json +29 -0
  350. package/protocol/sam/evaluation.v1.schema.json +19 -0
  351. package/protocol/sam/operation.schema.json +66 -0
  352. package/protocol/sam/outcome.v1.schema.json +36 -0
  353. package/protocol/sam/question.v1.schema.json +26 -0
  354. package/protocol/sam/registry.seed.json +153 -0
  355. package/protocol/sam/result.schema.json +53 -0
  356. package/protocol/sam/state.v1.schema.json +23 -0
  357. package/protocol/skills/agentsam.interaction.v1.schema.json +50 -0
  358. package/protocol/skills/agentsam.skill.v1.schema.json +57 -0
  359. package/protocol/theme-refinery/d1-reconciliation.md +48 -0
  360. package/protocol/theme-refinery/product-metadata.schema.json +27 -0
  361. package/protocol/theme-refinery/receipts/products-registry-batch-20260924.json +318 -0
  362. package/protocol/theme-refinery/receipts/theme-harvest-20260924.json +472 -0
  363. package/protocol/theme-refinery/reconciliation-receipt.schema.json +83 -0
  364. package/protocol/ui/icon-registry.mjs +226 -0
  365. package/protocol/ui/icon.v1.schema.json +51 -0
  366. package/services/cad/server.py +249 -2
  367. package/skills/README.md +22 -9
  368. package/skills/agentsam-codebaseindex/SKILL.md +225 -0
  369. package/skills/catalog.json +14 -0
  370. package/src/agent/capability-adapter.js +15 -5
  371. package/src/agent/index.js +2 -1
  372. package/src/agent/model-turn.js +51 -0
  373. package/src/agent/responses-runner.js +304 -38
  374. package/src/capabilities/index.js +1 -0
  375. package/src/capabilities/terminal-exec.js +78 -0
  376. package/src/cli/command-catalog.js +130 -0
  377. package/src/cli/dispatch.js +48 -0
  378. package/src/cli.js +160 -10
  379. package/src/cloudflare/index.js +6 -0
  380. package/src/cloudflare/runtime-status.js +393 -0
  381. package/src/cloudflare/wrangler.js +17 -1
  382. package/src/commands/api-key.js +244 -0
  383. package/src/commands/app.js +138 -0
  384. package/src/commands/autorag.js +77 -0
  385. package/src/commands/brand.js +291 -0
  386. package/src/commands/cad.js +1 -0
  387. package/src/commands/codebaseindex.js +688 -0
  388. package/src/commands/connections.js +126 -29
  389. package/src/commands/context-economics.js +8 -0
  390. package/src/commands/db.js +7 -0
  391. package/src/commands/env.js +155 -27
  392. package/src/commands/eval.js +209 -14
  393. package/src/commands/go.js +678 -0
  394. package/src/commands/goap.js +176 -0
  395. package/src/commands/identity-init.js +27 -3
  396. package/src/commands/identity-protocol.js +195 -0
  397. package/src/commands/interaction-clack.js +115 -0
  398. package/src/commands/knowledge.js +64 -5
  399. package/src/commands/mcp.js +341 -0
  400. package/src/commands/merkle-persist.js +3 -1
  401. package/src/commands/merkle.js +18 -3
  402. package/src/commands/models.js +110 -24
  403. package/src/commands/plugins.js +175 -0
  404. package/src/commands/preferences.js +28 -8
  405. package/src/commands/product.js +53 -10
  406. package/src/commands/providers.js +173 -44
  407. package/src/commands/resume.js +9 -5
  408. package/src/commands/runtime-status.js +154 -0
  409. package/src/commands/shell.js +508 -56
  410. package/src/commands/skill.js +248 -0
  411. package/src/commands/skills.js +1 -1
  412. package/src/commands/start-local.js +4 -0
  413. package/src/commands/status.js +82 -7
  414. package/src/commands/tunnel.js +228 -195
  415. package/src/commands/whoami.js +156 -12
  416. package/src/context/budget.js +6 -0
  417. package/src/context/index.js +2 -1
  418. package/src/context/project-card.js +75 -0
  419. package/src/errors/contract.js +34 -211
  420. package/src/errors/diagnostic.js +95 -51
  421. package/src/errors/index.js +6 -13
  422. package/src/eval/index.js +6 -0
  423. package/src/eval/live.js +439 -0
  424. package/src/features/resolve.js +242 -0
  425. package/src/go/build.js +298 -0
  426. package/src/go/cloudflare.js +608 -0
  427. package/src/go/container.js +120 -0
  428. package/src/go/contract.js +144 -0
  429. package/src/go/discover.js +212 -0
  430. package/src/go/index.js +25 -0
  431. package/src/go/native-probe-runner.mjs +119 -0
  432. package/src/go/official-registry.js +280 -0
  433. package/src/go/official-release.js +10 -0
  434. package/src/go/receipts.js +144 -0
  435. package/src/go/verify.js +38 -0
  436. package/src/index.js +127 -1
  437. package/src/indexing/ingest/discover-models.js +298 -0
  438. package/src/indexing/ingest/inventory.js +243 -0
  439. package/src/indexing/ingest/job-graph.js +181 -0
  440. package/src/indexing/ingest/materials.js +210 -0
  441. package/src/knowledge/config.js +13 -5
  442. package/src/knowledge/engine.js +23 -8
  443. package/src/knowledge/index.js +1 -0
  444. package/src/knowledge/lane-registry.js +46 -0
  445. package/src/knowledge/providers/gemini.js +48 -8
  446. package/src/knowledge/service/client.js +13 -1
  447. package/src/knowledge/service/grpc-codec.js +156 -53
  448. package/src/knowledge/service/job-engine.js +133 -11
  449. package/src/knowledge/service/job-worker.js +34 -5
  450. package/src/knowledge/service/server.js +10 -1
  451. package/src/knowledge/store-discovery.js +77 -0
  452. package/src/lib/account-session.js +8 -2
  453. package/src/lib/agent-instructions.js +3 -0
  454. package/src/lib/auth.js +7 -3
  455. package/src/lib/cad/blender.js +42 -3
  456. package/src/lib/cad/d1-project-store.js +43 -0
  457. package/src/lib/cad/discovery.js +616 -0
  458. package/src/lib/cad/docker-executor.js +352 -0
  459. package/src/lib/cad/freecad.js +253 -0
  460. package/src/lib/cad/index.js +40 -0
  461. package/src/lib/cad/openscad.js +198 -0
  462. package/src/lib/cad/project-cli.d.ts +2 -0
  463. package/src/lib/cad/project-cli.js +21 -0
  464. package/src/lib/cad/project-contract.d.ts +3 -0
  465. package/src/lib/cad/project-contract.js +1 -0
  466. package/src/lib/cad/project-recipe.js +30 -0
  467. package/src/lib/cad/project-runtime.d.ts +2 -0
  468. package/src/lib/cad/project-runtime.js +53 -0
  469. package/src/lib/cad/project-store.js +25 -0
  470. package/src/lib/cad/project-workflows.js +31 -0
  471. package/src/lib/cad-docker.js +21 -2
  472. package/src/lib/cli-preferences.js +17 -2
  473. package/src/lib/core-client.js +37 -18
  474. package/src/lib/deploy/local-studio.js +6 -5
  475. package/src/lib/dockerize.js +3 -0
  476. package/src/lib/execution-approvals.js +1 -0
  477. package/src/lib/identity-scaffold.js +4 -1
  478. package/src/lib/knowledge-docker.js +9 -1
  479. package/src/lib/local-sessions.js +124 -34
  480. package/src/lib/local-status.js +35 -14
  481. package/src/lib/project-config.js +9 -0
  482. package/src/lib/provider-credentials.js +136 -32
  483. package/src/lib/scaffold/resolve-cloudflare-account.js +37 -0
  484. package/src/lib/scaffold/wizards/cms.js +2 -8
  485. package/src/lib/scaffold/wizards/worker-api.js +2 -8
  486. package/src/lib/slash-commands.js +10 -2
  487. package/src/local/migrations.js +109 -1
  488. package/src/local/runtime-store.js +31 -5
  489. package/src/local/sqlite.js +36 -1
  490. package/src/local-fs/capability.js +121 -0
  491. package/src/local-fs/freshness.js +75 -0
  492. package/src/local-fs/index.js +385 -0
  493. package/src/local-fs/paths.js +100 -0
  494. package/src/local-pty/server.js +295 -19
  495. package/src/mcp/authority.js +348 -0
  496. package/src/mcp/client-adapters.js +431 -0
  497. package/src/mcp/client.js +172 -0
  498. package/src/mcp/index.js +47 -0
  499. package/src/mcp/telemetry.js +103 -0
  500. package/src/models/ai-access-onboarding.js +112 -0
  501. package/src/models/catalog.js +329 -51
  502. package/src/models/discovery.js +34 -6
  503. package/src/models/index.js +2 -0
  504. package/src/models/inventory-core.js +190 -0
  505. package/src/models/policy.js +20 -0
  506. package/src/plugins/cloudflare.js +103 -0
  507. package/src/plugins/completeful.js +69 -0
  508. package/src/plugins/contracts.js +86 -0
  509. package/src/plugins/index.js +11 -0
  510. package/src/plugins/registry.js +207 -0
  511. package/src/plugins/resource-scope.js +45 -0
  512. package/src/plugins/runtime.js +118 -0
  513. package/src/plugins/vectorize.js +31 -0
  514. package/src/progression/engine.js +171 -0
  515. package/src/progression/index.js +1 -0
  516. package/src/providers/cloudflare-chat.js +1 -1
  517. package/src/providers/gemini-generate-content.js +2 -1
  518. package/src/providers/openai-responses.js +45 -16
  519. package/src/providers/tool-schema.js +85 -0
  520. package/src/repository/index.js +29 -0
  521. package/src/rpc/generated/errors_pb.js +961 -1
  522. package/src/sam/activity/index.js +183 -0
  523. package/src/sam/client.js +252 -0
  524. package/src/sam/decision/calibration.js +109 -0
  525. package/src/sam/decision/confidence.js +126 -0
  526. package/src/sam/decision/evaluate.js +157 -0
  527. package/src/sam/decision/evaluators/deterministic.js +341 -0
  528. package/src/sam/decision/evaluators/heuristic.js +61 -0
  529. package/src/sam/decision/evaluators/select.js +50 -0
  530. package/src/sam/decision/evaluators/semantic.js +149 -0
  531. package/src/sam/decision/hierarchical.js +61 -0
  532. package/src/sam/decision/index.js +53 -0
  533. package/src/sam/decision/policy.js +86 -0
  534. package/src/sam/decision/questions.js +120 -0
  535. package/src/sam/decision/receipt.js +148 -0
  536. package/src/sam/decision/state.js +117 -0
  537. package/src/sam/decision/types.js +22 -0
  538. package/src/sam/decision/validate.js +200 -0
  539. package/src/sam/define.js +51 -0
  540. package/src/sam/index.js +65 -0
  541. package/src/sam/operations/brand-scan.js +62 -0
  542. package/src/sam/operations/cad-blender-inspect.js +36 -0
  543. package/src/sam/operations/codebaseindex-ingest.js +49 -0
  544. package/src/sam/operations/decision-evaluate.js +59 -0
  545. package/src/sam/operations/planning-astar.js +77 -0
  546. package/src/sam/operations/planning-goap.js +60 -0
  547. package/src/sam/operations/repository-inspect.js +72 -0
  548. package/src/sam/operations/security-scan.js +33 -0
  549. package/src/sam/operations/terminal-exec.js +29 -0
  550. package/src/sam/planning/astar.js +311 -0
  551. package/src/sam/planning/goap.js +177 -0
  552. package/src/sam/planning/index.js +21 -0
  553. package/src/sam/planning/state.js +84 -0
  554. package/src/sam/registry.js +48 -0
  555. package/src/sam/result.js +77 -0
  556. package/src/sam/seed.js +44 -0
  557. package/src/sam/types.js +91 -0
  558. package/src/security/local-vault.js +415 -0
  559. package/src/security/process.js +20 -4
  560. package/src/skills/catalog.js +64 -0
  561. package/src/skills/content-resolver.js +124 -0
  562. package/src/skills/hosted-store.js +37 -0
  563. package/src/skills/index.js +29 -64
  564. package/src/skills/interaction.js +102 -0
  565. package/src/skills/local-store.js +228 -0
  566. package/src/skills/manifest.js +104 -0
  567. package/src/skills/metrics.js +31 -0
  568. package/src/skills/registry.js +184 -0
  569. package/src/skills/runtime.js +287 -0
  570. package/src/skills/slash.js +44 -0
  571. package/src/status/actions.js +192 -0
  572. package/src/tools/hydrate.js +5 -1
  573. package/src/tools/index.js +7 -0
  574. package/src/tools/redact.js +64 -0
  575. package/src/tools/registry.js +83 -0
  576. package/src/tools/runtime.js +257 -0
  577. package/src/tools/search.js +21 -8
  578. package/src/ui/ansi.js +117 -3
  579. package/src/ui/cli/activity.js +76 -7
  580. package/src/ui/cli/footer.js +110 -9
  581. package/src/ui/cli/help.js +96 -96
  582. package/src/ui/wireframes.js +166 -0
  583. package/test/account-session.test.mjs +28 -0
  584. package/test/apps-scaffold-contract.test.mjs +16 -1
  585. package/test/capabilities.test.mjs +1 -1
  586. package/test/cli/api-key-env-whoami.test.mjs +129 -0
  587. package/test/cli/codebaseindex-plan-ux.test.mjs +37 -0
  588. package/test/cli/eval-live.test.mjs +219 -0
  589. package/test/cli/go.test.mjs +128 -0
  590. package/test/cli/local-vault-and-provider-setup.test.mjs +268 -0
  591. package/test/cli/mcp-client.test.mjs +245 -0
  592. package/test/cli/runtime-ui.test.mjs +69 -2
  593. package/test/cli/skill-npm-and-env.test.mjs +52 -0
  594. package/test/cli/status-actions.test.mjs +88 -0
  595. package/test/cli/wireframes-go-registry.test.mjs +139 -0
  596. package/test/cloudflare-connector.test.mjs +3 -6
  597. package/test/cloudflare-runtime.test.mjs +8 -1
  598. package/test/context.test.mjs +15 -0
  599. package/test/error-diagnostics.test.mjs +9 -0
  600. package/test/fixtures/cad/courtyard-house.json +208 -0
  601. package/test/go/build-source-identity.test.mjs +31 -0
  602. package/test/go/cloudflare-probe.test.mjs +317 -0
  603. package/test/go/distribution.test.mjs +28 -0
  604. package/test/integration/ai-access-onboarding.test.mjs +47 -0
  605. package/test/integration/app-command.test.mjs +55 -0
  606. package/test/integration/cad-discovery.test.mjs +158 -0
  607. package/test/integration/cad-docker-executor.test.mjs +249 -0
  608. package/test/integration/cad-execution.test.mjs +184 -0
  609. package/test/integration/cad-project-app.test.mjs +31 -0
  610. package/test/integration/cad-project-d1.test.mjs +25 -0
  611. package/test/integration/cad-project-native.test.mjs +24 -0
  612. package/test/integration/cad-project-workflow.test.mjs +9 -0
  613. package/test/integration/cad-project.test.mjs +82 -0
  614. package/test/integration/cli-help.test.mjs +5 -1
  615. package/test/integration/cms-site-tenancy-contract.test.mjs +256 -0
  616. package/test/integration/codebaseindex-ingest.test.mjs +166 -0
  617. package/test/integration/core-client.integration.test.mjs +55 -0
  618. package/test/integration/error-runtime-rpc.test.mjs +71 -0
  619. package/test/integration/features-resolve.test.mjs +128 -0
  620. package/test/integration/icon-registry.test.mjs +67 -0
  621. package/test/integration/ingest-discover-models.test.mjs +30 -0
  622. package/test/integration/install-script.test.mjs +110 -0
  623. package/test/integration/inventory-core.test.mjs +53 -0
  624. package/test/integration/local-fs.test.mjs +113 -0
  625. package/test/integration/plugins-cloudflare.integration.test.mjs +28 -0
  626. package/test/integration/provider-env-cli.test.mjs +3 -2
  627. package/test/integration/runtime-migrations.test.mjs +6 -1
  628. package/test/integration/runtime-status.integration.test.mjs +211 -0
  629. package/test/integration/sam-activity-recovery.test.mjs +147 -0
  630. package/test/integration/sam-decision.test.mjs +584 -0
  631. package/test/integration/sam-kernel.test.mjs +99 -0
  632. package/test/integration/sam-planning-astar.test.mjs +279 -0
  633. package/test/integration/scaffold-cloudflare.test.mjs +46 -0
  634. package/test/integration/skill-runtime.test.mjs +240 -0
  635. package/test/integration/storage-architecture.test.mjs +154 -0
  636. package/test/integration/store-discovery.test.mjs +44 -0
  637. package/test/integration/studio-fs-pty-e2e.test.mjs +294 -0
  638. package/test/integration/terminal-exec.integration.test.mjs +86 -0
  639. package/test/integration/tool-runtime.test.mjs +124 -0
  640. package/test/integration/tool-schema.test.mjs +59 -0
  641. package/test/knowledge-service.test.mjs +4 -0
  642. package/test/local-sessions.test.mjs +11 -2
  643. package/test/local-studio-deploy.test.mjs +1 -1
  644. package/test/model-catalog.test.mjs +28 -1
  645. package/test/models.test.mjs +172 -11
  646. package/test/openai-responses.test.mjs +60 -0
  647. package/test/provider-credentials.test.mjs +15 -5
  648. package/test/responses-runner.test.mjs +321 -6
  649. package/test/shell.test.mjs +151 -6
  650. package/test/smoke.mjs +2 -2
  651. package/test/tools-search.test.mjs +33 -0
  652. package/test/unit/website-assets-bindings.test.mjs +60 -0
  653. package/test/whoami-resume.test.mjs +82 -3
  654. package/examples/gorilla-shell/README.md +0 -15
  655. package/src/lib/gorilla-template.js +0 -54
  656. package/templates/gorilla-shell/App.tsx +0 -639
  657. package/templates/gorilla-shell/README.md +0 -34
  658. package/templates/gorilla-shell/index.html +0 -15
  659. package/templates/gorilla-shell/main.jsx +0 -9
  660. package/templates/gorilla-shell/package.json +0 -19
  661. package/templates/gorilla-shell/vite.config.js +0 -21
@@ -21,12 +21,18 @@ npx wrangler secret put IAM_CLIENT_SECRET
21
21
 
22
22
  These routes live in the **customer** worker (`handleIdentityWorkerRequest`):
23
23
 
24
- 1. `/api/oauth/iam/start` → redirects to IAM AS (requires minted `IAM_CLIENT_*`)
25
- 2. `/api/oauth/google/start` → BYOK Google if `GOOGLE_*` set, else IAM if minted, else 503
24
+ 1. `/api/oauth/inneranimalmedia/start` → redirects to IAM AS (requires minted `IAM_CLIENT_*`)
25
+ - Legacy alias: `/api/oauth/iam/start`
26
+ 2. `/api/oauth/google/start` → BYOK Google if `GOOGLE_*` set, else platform lane if minted, else 503
26
27
  3. `/api/oauth/github/start` → same for GitHub
27
- 4. Callback: `/api/oauth/iam/callback` (IAM lane) or `/api/oauth/{google|github}/callback` (BYOK)
28
+ 4. Callback: `/api/oauth/inneranimalmedia/callback` (platform lane) or `/api/oauth/{google|github|cloudflare}/callback` (BYOK)
29
+ - Legacy alias: `/api/oauth/iam/callback`
28
30
 
29
- Register IAM redirect URI: `https://<customer-host>/api/oauth/iam/callback`
31
+ Register platform redirect URI on the IAM client:
32
+
33
+ `https://<customer-host>/api/oauth/inneranimalmedia/callback`
34
+
35
+ (Keep the legacy `/api/oauth/iam/callback` registered during migration.)
30
36
 
31
37
  ## IAM authorization server endpoints (issuer)
32
38
 
@@ -8,13 +8,17 @@ import { DEFAULT_IAM_ORIGIN, resolveIamOrigin } from '../contracts/auth-config.j
8
8
  * — SECRET is wrangler secret put only (encryption is law, not luxury).
9
9
  *
10
10
  * Developer BYOK: GOOGLE_CLIENT_* / GITHUB_CLIENT_* when set for that provider
11
- * take the /api/oauth/{provider}/start button; otherwise the button uses IAM.
11
+ * take the /api/oauth/{provider}/start button; otherwise the button uses the
12
+ * Inner Animal Media platform lane (`inneranimalmedia`).
12
13
  */
13
14
 
14
15
  /** @deprecated Use DEFAULT_IAM_ORIGIN from the auth configuration contract. */
15
16
  export const DEFAULT_IAM_OAUTH_ISSUER = DEFAULT_IAM_ORIGIN;
16
17
  export const IAM_PLATFORM_STATE_PROVIDER = 'iam_platform';
17
- export const IAM_PLATFORM_CALLBACK_PATH = '/api/oauth/iam/callback';
18
+ /** Canonical platform OAuth callback (protocol id = inneranimalmedia). */
19
+ export const IAM_PLATFORM_CALLBACK_PATH = '/api/oauth/inneranimalmedia/callback';
20
+ /** @deprecated Legacy path — still accepted; prefer IAM_PLATFORM_CALLBACK_PATH. */
21
+ export const IAM_PLATFORM_CALLBACK_PATH_LEGACY = '/api/oauth/iam/callback';
18
22
 
19
23
  /**
20
24
  * @param {Record<string, unknown> | null | undefined} env
@@ -42,9 +46,9 @@ export function requireIamPlatformCredentials(env) {
42
46
 
43
47
  /**
44
48
  * @param {Record<string, unknown> | null | undefined} env
45
- * @param {'google' | 'github' | 'iam'} provider
49
+ * @param {'google' | 'github' | 'cloudflare' | 'inneranimalmedia' | 'iam'} provider
46
50
  * @returns {{
47
- * lane: 'iam_platform' | 'byok_google' | 'byok_github',
51
+ * lane: 'iam_platform' | 'byok_google' | 'byok_github' | 'byok_cloudflare',
48
52
  * clientId: string,
49
53
  * clientSecret: string,
50
54
  * origin?: string,
@@ -53,7 +57,10 @@ export function requireIamPlatformCredentials(env) {
53
57
  * } | null}
54
58
  */
55
59
  export function resolveOAuthCredentialLane(env, provider) {
56
- if (provider === 'iam') {
60
+ const key = String(provider || '').trim().toLowerCase();
61
+
62
+ // Protocol/selection id is inneranimalmedia; `iam` remains a legacy alias.
63
+ if (key === 'inneranimalmedia' || key === 'iam') {
57
64
  const iam = resolveIamPlatformCredentials(env);
58
65
  if (!iam) return null;
59
66
  return {
@@ -62,24 +69,37 @@ export function resolveOAuthCredentialLane(env, provider) {
62
69
  clientSecret: iam.clientSecret,
63
70
  origin: iam.origin,
64
71
  issuer: iam.issuer,
65
- provider: 'iam',
72
+ provider: 'inneranimalmedia',
66
73
  };
67
74
  }
68
75
 
69
- if (provider === 'google') {
76
+ if (key === 'google') {
70
77
  const clientId = String(env?.GOOGLE_CLIENT_ID || '').trim();
71
78
  const clientSecret = String(env?.GOOGLE_CLIENT_SECRET || '').trim();
72
79
  if (clientId && clientSecret) {
73
- return { lane: 'byok_google', clientId, clientSecret, provider };
80
+ return { lane: 'byok_google', clientId, clientSecret, provider: 'google' };
74
81
  }
75
82
  }
76
83
 
77
- if (provider === 'github') {
84
+ if (key === 'github') {
78
85
  const clientId = String(env?.GITHUB_CLIENT_ID || '').trim();
79
86
  const clientSecret = String(env?.GITHUB_CLIENT_SECRET || '').trim();
80
87
  if (clientId && clientSecret) {
81
- return { lane: 'byok_github', clientId, clientSecret, provider };
88
+ return { lane: 'byok_github', clientId, clientSecret, provider: 'github' };
89
+ }
90
+ }
91
+
92
+ if (key === 'cloudflare') {
93
+ // Reuses the same Worker secrets as the Local Studio Cloudflare resource
94
+ // connector (packages/connectors/cloudflare). clientSecret may be empty
95
+ // if that client is configured as PKCE-only (Token Authentication
96
+ // Method = None) — exchangeCloudflareCode() omits it in that case.
97
+ const clientId = String(env?.CLOUDFLARE_OAUTH_CLIENT_ID || '').trim();
98
+ const clientSecret = String(env?.CLOUDFLARE_OAUTH_CLIENT_SECRET || '').trim();
99
+ if (clientId) {
100
+ return { lane: 'byok_cloudflare', clientId, clientSecret, provider: 'cloudflare' };
82
101
  }
102
+ return null;
83
103
  }
84
104
 
85
105
  // Default: Google/GitHub buttons route through IAM platform when minted.
@@ -91,7 +111,7 @@ export function resolveOAuthCredentialLane(env, provider) {
91
111
  clientSecret: iam.clientSecret,
92
112
  origin: iam.origin,
93
113
  issuer: iam.issuer,
94
- provider,
114
+ provider: 'inneranimalmedia',
95
115
  };
96
116
  }
97
117
 
@@ -51,7 +51,7 @@ export function createFinalizeInboundOAuth(ports) {
51
51
  ? String(input.supabaseUserId).trim()
52
52
  : null;
53
53
  const source = String(input?.source || `${provider}_oauth`).trim();
54
- const pageContext = String(input?.pageContext || '/dashboard/agent').trim();
54
+ const pageContext = String(input?.pageContext || '/').trim();
55
55
 
56
56
  if (!ports.hasDatabase(env) || !oauthEmail || !provider || !providerUid) {
57
57
  return /** @type {InboundOAuthFailure} */ ({ ok: false, error: 'provision_failed' });
@@ -1,4 +1,4 @@
1
- import { AUTH_LOGIN_PATH } from '../core/constants.js';
1
+ import { IDENTITY_ROUTE_IDS } from '../contracts/route-ids.js';
2
2
  import {
3
3
  IAM_PLATFORM_CALLBACK_PATH,
4
4
  IAM_PLATFORM_STATE_PROVIDER,
@@ -19,7 +19,7 @@ import { normalizeIamIdentity } from '../providers/iam/mapper.js';
19
19
  * @param {Record<string, unknown>} env
20
20
  * @param {import('../adapters/cloudflare-d1/index.js').CloudflareD1Adapter} adapter
21
21
  */
22
- export async function iamPlatformOAuthStart(request, env, adapter) {
22
+ export async function iamPlatformOAuthStart(request, env, adapter, identity) {
23
23
  const creds = resolveIamPlatformCredentials(env);
24
24
  if (!creds) {
25
25
  return Response.json({ ok: false, error: 'iam_oauth_not_configured' }, 503);
@@ -29,15 +29,16 @@ export async function iamPlatformOAuthStart(request, env, adapter) {
29
29
  const state = randomOAuthState();
30
30
  const codeVerifier = pkceVerifier();
31
31
  const codeChallenge = await pkceChallenge(codeVerifier);
32
- const redirectTo = url.searchParams.get('next')
33
- || url.searchParams.get('return_to')
34
- || '/dashboard/cms';
32
+ const redirectTo = identity?.resolvePostLoginPath(
33
+ url.searchParams.get('next') || url.searchParams.get('return_to'),
34
+ ) || '/';
35
35
 
36
36
  await adapter.saveOAuthState({
37
37
  state,
38
38
  provider: IAM_PLATFORM_STATE_PROVIDER,
39
39
  codeVerifier,
40
40
  redirectTo,
41
+ appId: identity?.app?.id || null,
41
42
  });
42
43
 
43
44
  const redirectUri = `${url.origin}${IAM_PLATFORM_CALLBACK_PATH}`;
@@ -67,15 +68,15 @@ export async function iamPlatformOAuthCallback(request, env, adapter, identity)
67
68
  const err = url.searchParams.get('error');
68
69
 
69
70
  if (err || !code || !state) {
70
- return Response.redirect(`${url.origin}${AUTH_LOGIN_PATH}?error=oauth_failed`, 302);
71
+ return Response.redirect(`${url.origin}${identity.routeRegistry.resolve(identity.app.id, IDENTITY_ROUTE_IDS.LOGIN)}?error=oauth_failed`, 302);
71
72
  }
72
73
  if (!creds) {
73
- return Response.redirect(`${url.origin}${AUTH_LOGIN_PATH}?error=iam_oauth_not_configured`, 302);
74
+ return Response.redirect(`${url.origin}${identity.routeRegistry.resolve(identity.app.id, IDENTITY_ROUTE_IDS.LOGIN)}?error=iam_oauth_not_configured`, 302);
74
75
  }
75
76
 
76
77
  const saved = await adapter.consumeOAuthState(state);
77
78
  if (!saved || saved.provider !== IAM_PLATFORM_STATE_PROVIDER) {
78
- return Response.redirect(`${url.origin}${AUTH_LOGIN_PATH}?error=state_mismatch`, 302);
79
+ return Response.redirect(`${url.origin}${identity.routeRegistry.resolve(identity.app.id, IDENTITY_ROUTE_IDS.LOGIN)}?error=state_mismatch`, 302);
79
80
  }
80
81
 
81
82
  const redirectUri = `${url.origin}${IAM_PLATFORM_CALLBACK_PATH}`;
@@ -88,7 +89,7 @@ export async function iamPlatformOAuthCallback(request, env, adapter, identity)
88
89
  redirectUri,
89
90
  });
90
91
  if (!token?.access_token) {
91
- return Response.redirect(`${url.origin}${AUTH_LOGIN_PATH}?error=token_exchange_failed`, 302);
92
+ return Response.redirect(`${url.origin}${identity.routeRegistry.resolve(identity.app.id, IDENTITY_ROUTE_IDS.LOGIN)}?error=token_exchange_failed`, 302);
92
93
  }
93
94
 
94
95
  const profile = await fetchIamProfile({
@@ -97,7 +98,7 @@ export async function iamPlatformOAuthCallback(request, env, adapter, identity)
97
98
  });
98
99
  const normalized = profile ? normalizeIamIdentity(profile) : null;
99
100
  if (!normalized?.subject || !normalized?.email) {
100
- return Response.redirect(`${url.origin}${AUTH_LOGIN_PATH}?error=userinfo_failed`, 302);
101
+ return Response.redirect(`${url.origin}${identity.routeRegistry.resolve(identity.app.id, IDENTITY_ROUTE_IDS.LOGIN)}?error=userinfo_failed`, 302);
101
102
  }
102
103
 
103
104
  const result = await identity.provisionOAuthUser({
@@ -107,9 +108,9 @@ export async function iamPlatformOAuthCallback(request, env, adapter, identity)
107
108
  displayName: normalized.name || normalized.email.split('@')[0] || 'User',
108
109
  });
109
110
 
110
- const redirectTo = saved.redirect_to || '/dashboard/cms';
111
+ const redirectTo = identity.resolvePostLoginPath(saved.redirect_to);
111
112
  const res = identity.buildLoginSuccessResponse(request, result.sessionId, redirectTo);
112
- const globeUrl = `${url.origin}${AUTH_LOGIN_PATH}?globe_exit=1&next=${encodeURIComponent(redirectTo)}`;
113
+ const globeUrl = `${url.origin}${identity.routeRegistry.resolve(identity.app.id, IDENTITY_ROUTE_IDS.LOGIN)}?globe_exit=1&next=${encodeURIComponent(redirectTo)}`;
113
114
  return new Response(null, {
114
115
  status: 302,
115
116
  headers: {
@@ -1,29 +1,35 @@
1
1
  /**
2
2
  * Post-OAuth redirect helpers — portable path policy with host injectables.
3
+ * Hosts MUST pass loginPath from their route projection (never hardcode).
3
4
  */
4
5
 
5
- const DEFAULT_DASHBOARD_FALLBACK = '/dashboard/agent';
6
+ import { sanitizeBrowserNextPath } from '../core/browser-paths.js';
7
+ import { IdentityRoutingError } from '../contracts/identity-store.js';
6
8
 
7
9
  /**
8
10
  * @typedef {object} OAuthRedirectPathOptions
9
11
  * @property {string} [authCookieName]
10
- * @property {string} [dashboardFallback]
12
+ * @property {string} loginPath concrete projection of identity.login
13
+ * @property {string} [fallback] only used when isAllowedLoginResumePath rejects; prefer omit
11
14
  * @property {(path: string) => boolean} [isAllowedLoginResumePath]
12
15
  * @property {(env: unknown, rawCookie: string) => Promise<string|null>} [resolveSessionIdFromCookie]
13
16
  * @property {(env: unknown, sessionId: string, reason: string, userId: string|null) => Promise<void>} [revokeAuthSession]
14
17
  */
15
18
 
16
- /**
17
- * @param {OAuthRedirectPathOptions} options
18
- */
19
19
  export function createOAuthRedirectHelpers(options = {}) {
20
20
  const authCookieName = options.authCookieName ?? 'iam_session';
21
- const dashboardFallback = options.dashboardFallback ?? DEFAULT_DASHBOARD_FALLBACK;
22
- const isAllowedLoginResumePath = options.isAllowedLoginResumePath ?? (() => false);
21
+ const loginPath = options.loginPath;
22
+ if (!loginPath || !String(loginPath).startsWith('/')) {
23
+ throw new IdentityRoutingError(
24
+ 'AUTH_ROUTE_MISSING',
25
+ 'createOAuthRedirectHelpers requires loginPath from route projection',
26
+ );
27
+ }
28
+ const isAllowedLoginResumePath = options.isAllowedLoginResumePath
29
+ ?? ((path) => Boolean(sanitizeBrowserNextPath(path)));
23
30
  const resolveSessionIdFromCookie = options.resolveSessionIdFromCookie;
24
31
  const revokeAuthSession = options.revokeAuthSession;
25
32
 
26
- /** Revoke browser cookie session before issuing a new login session. */
27
33
  async function revokeIncomingCookieSession(request, env, reason = 'oauth_login_replaced') {
28
34
  const cookie = request.headers.get('Cookie') || '';
29
35
  const match = cookie.match(new RegExp(`(?:^|;\\s*)${authCookieName}=([^;]+)`));
@@ -45,48 +51,33 @@ export function createOAuthRedirectHelpers(options = {}) {
45
51
  }
46
52
  }
47
53
 
48
- function safeDashboardLoginRedirectPath(originBase, returnTo) {
49
- if (!returnTo || typeof returnTo !== 'string') return dashboardFallback;
50
- const t = returnTo.trim();
51
- if (!t) return dashboardFallback;
52
- if (t.startsWith('/') && !t.startsWith('//') && !t.includes('://')) {
53
- if (isAllowedLoginResumePath(t)) return t;
54
- if (t.startsWith('/dashboard/settings/integrations')) return dashboardFallback;
55
- if (!t.startsWith('/dashboard')) return dashboardFallback;
56
- return t;
54
+ function safeLoginRedirectPath(_originBase, returnTo) {
55
+ const cleaned = sanitizeBrowserNextPath(returnTo);
56
+ if (!cleaned) {
57
+ throw new IdentityRoutingError('AUTH_DESTINATION_UNRESOLVED', 'return_to missing/invalid');
57
58
  }
58
- try {
59
- const u = new URL(t);
60
- const ob = new URL(originBase);
61
- if (u.origin !== ob.origin) return dashboardFallback;
62
- const p = u.pathname + (u.search || '');
63
- if (p.startsWith('/dashboard/settings/integrations')) return dashboardFallback;
64
- if (!p.startsWith('/dashboard')) return dashboardFallback;
65
- return p;
66
- } catch {
67
- return dashboardFallback;
59
+ if (!isAllowedLoginResumePath(cleaned)) {
60
+ throw new IdentityRoutingError('AUTH_DESTINATION_UNRESOLVED', 'return_to not allowed', { returnTo: cleaned });
68
61
  }
62
+ return cleaned;
69
63
  }
70
64
 
71
65
  function oauthPostLoginGlobeRedirectUrl(originBase, returnToFullUrl) {
72
- let path = dashboardFallback;
66
+ let path;
73
67
  try {
74
68
  const u = new URL(returnToFullUrl);
75
69
  path = u.pathname + (u.search || '');
76
70
  } catch {
77
- /* keep default */
78
- }
79
- if (!path.startsWith('/') || path.startsWith('//')) path = dashboardFallback;
80
- if (path.startsWith('/dashboard/settings/integrations')) path = dashboardFallback;
81
- if (!isAllowedLoginResumePath(path) && !path.startsWith('/dashboard')) {
82
- path = dashboardFallback;
71
+ throw new IdentityRoutingError('AUTH_DESTINATION_UNRESOLVED', 'invalid returnToFullUrl');
83
72
  }
84
- return `${originBase}/auth/login?globe_exit=1&next=${encodeURIComponent(path)}`;
73
+ path = safeLoginRedirectPath(originBase, path);
74
+ return `${originBase}${loginPath}?globe_exit=1&next=${encodeURIComponent(path)}`;
85
75
  }
86
76
 
87
77
  return {
88
78
  revokeIncomingCookieSession,
89
- safeDashboardLoginRedirectPath,
79
+ safeDashboardLoginRedirectPath: safeLoginRedirectPath,
80
+ safeLoginRedirectPath,
90
81
  oauthPostLoginGlobeRedirectUrl,
91
82
  };
92
83
  }
@@ -0,0 +1,19 @@
1
+ import { createIdentityProvider } from '../../provider-contract.js';
2
+ import { exchangeCloudflareCode, getCloudflareAuthUrl } from './oauth.js';
3
+ import { fetchCloudflareProfile } from './profile.js';
4
+ import { normalizeCloudflareIdentity } from './mapper.js';
5
+
6
+ export const CloudflareProvider = createIdentityProvider({
7
+ id: 'cloudflare',
8
+ authorizeUrl: getCloudflareAuthUrl,
9
+ exchangeCode: exchangeCloudflareCode,
10
+ getProfile: fetchCloudflareProfile,
11
+ normalizeIdentity: normalizeCloudflareIdentity,
12
+ });
13
+
14
+ export {
15
+ getCloudflareAuthUrl,
16
+ exchangeCloudflareCode,
17
+ fetchCloudflareProfile,
18
+ normalizeCloudflareIdentity,
19
+ };
@@ -0,0 +1,21 @@
1
+ import { normalizeExternalIdentity } from '../../contracts/external-identity.js';
2
+
3
+ /**
4
+ * @param {Record<string, unknown>|null|undefined} profile
5
+ */
6
+ export function normalizeCloudflareIdentity(profile) {
7
+ const raw = profile && typeof profile === 'object' ? profile : {};
8
+ const subject = String(raw.sub || raw.id || raw.user_id || raw.account_id || '').trim();
9
+ if (!subject) {
10
+ throw new Error('cloudflare_identity_requires_subject');
11
+ }
12
+ return normalizeExternalIdentity({
13
+ provider: 'cloudflare',
14
+ subject,
15
+ email: typeof raw.email === 'string' ? raw.email : null,
16
+ emailVerified: Boolean(raw.email),
17
+ name: typeof raw.name === 'string' ? raw.name : (typeof raw.display_name === 'string' ? raw.display_name : null),
18
+ avatar: null,
19
+ raw,
20
+ });
21
+ }
@@ -0,0 +1,48 @@
1
+ const CLOUDFLARE_AUTH_URL = 'https://dash.cloudflare.com/oauth2/auth';
2
+ const CLOUDFLARE_TOKEN_URL = 'https://dash.cloudflare.com/oauth2/token';
3
+
4
+ // Identity-only login should not request the full resource-access scope set
5
+ // used elsewhere for the Local Studio Cloudflare *connection* (deploy/d1/r2/etc).
6
+ // account-settings.read is enough to resolve the account for userinfo.
7
+ const CLOUDFLARE_LOGIN_SCOPE = 'account-settings.read offline_access';
8
+
9
+ /** @param {import('../../provider-contract.js').OAuthAuthorizeInput} input */
10
+ export function getCloudflareAuthUrl({ clientId, redirectUri, state, codeChallenge, scope } = {}) {
11
+ const url = new URL(CLOUDFLARE_AUTH_URL);
12
+ url.searchParams.set('client_id', clientId || '');
13
+ url.searchParams.set('redirect_uri', redirectUri || '');
14
+ url.searchParams.set('response_type', 'code');
15
+ url.searchParams.set('scope', scope || CLOUDFLARE_LOGIN_SCOPE);
16
+ url.searchParams.set('state', state || '');
17
+ if (codeChallenge) {
18
+ url.searchParams.set('code_challenge', codeChallenge);
19
+ url.searchParams.set('code_challenge_method', 'S256');
20
+ }
21
+ return url.toString();
22
+ }
23
+
24
+ /** @param {import('../../provider-contract.js').OAuthExchangeInput} input */
25
+ export async function exchangeCloudflareCode({ code, codeVerifier, clientId, clientSecret, redirectUri }) {
26
+ try {
27
+ const body = new URLSearchParams();
28
+ body.set('grant_type', 'authorization_code');
29
+ body.set('code', code || '');
30
+ body.set('code_verifier', codeVerifier || '');
31
+ body.set('client_id', clientId || '');
32
+ // client_secret is only sent when configured — the client may be a
33
+ // PKCE-only public client (Token Authentication Method = None), same
34
+ // pattern as the Local Studio resource connector.
35
+ if (clientSecret) body.set('client_secret', clientSecret);
36
+ body.set('redirect_uri', redirectUri || '');
37
+
38
+ const res = await fetch(CLOUDFLARE_TOKEN_URL, {
39
+ method: 'POST',
40
+ headers: { 'Content-Type': 'application/x-www-form-urlencoded' },
41
+ body,
42
+ });
43
+ if (!res.ok) return null;
44
+ return await res.json();
45
+ } catch {
46
+ return null;
47
+ }
48
+ }
@@ -0,0 +1,28 @@
1
+ const CLOUDFLARE_USERINFO_URL = 'https://dash.cloudflare.com/oauth2/userinfo';
2
+
3
+ /**
4
+ * Fetch the authenticated Cloudflare user's identity.
5
+ * Response shape not fully verified against a live token yet — this reads
6
+ * defensively (sub/id/user_id, email, name) rather than assuming Cloudflare's
7
+ * exact OIDC field names. Confirm the real shape on first live login and
8
+ * tighten this if fields differ.
9
+ * @param {string} accessToken
10
+ */
11
+ export async function fetchCloudflareProfile(accessToken) {
12
+ try {
13
+ const res = await fetch(CLOUDFLARE_USERINFO_URL, {
14
+ headers: { Authorization: `Bearer ${accessToken}` },
15
+ });
16
+ if (!res.ok) return null;
17
+ const data = await res.json();
18
+ if (!data) return null;
19
+ return {
20
+ sub: data.sub || data.id || data.user_id || data.account_id || null,
21
+ email: data.email || null,
22
+ name: data.name || data.display_name || null,
23
+ raw: data,
24
+ };
25
+ } catch {
26
+ return null;
27
+ }
28
+ }
@@ -4,19 +4,28 @@ import { GithubProvider } from './github/index.js';
4
4
  import { GcpProvider } from './gcp/index.js';
5
5
  import { EmailProvider } from './email/index.js';
6
6
  import { IamProvider } from './iam/index.js';
7
+ import { CloudflareProvider } from './cloudflare/index.js';
7
8
 
8
- /** @type {Record<string, import('../provider-contract.js').IdentityProvider>} */
9
+ /**
10
+ * Active identity provider registry.
11
+ * `inneranimalmedia` is the canonical platform template id; `iam` remains a
12
+ * legacy lookup alias (OAuth/DB provider key on platform identities).
13
+ * @type {Record<string, import('../provider-contract.js').IdentityProvider>}
14
+ */
9
15
  export const identityProviders = Object.freeze({
10
16
  google: GoogleProvider,
11
17
  github: GithubProvider,
12
18
  gcp: GcpProvider,
13
19
  email: EmailProvider,
20
+ inneranimalmedia: IamProvider,
14
21
  iam: IamProvider,
22
+ cloudflare: CloudflareProvider,
15
23
  });
16
24
 
17
25
  /** @param {string} id */
18
26
  export function getIdentityProvider(id) {
19
27
  const key = String(id || '').trim().toLowerCase();
28
+ if (key === 'iam') return identityProviders.inneranimalmedia || identityProviders.iam || null;
20
29
  return identityProviders[key] || null;
21
30
  }
22
31
 
@@ -24,4 +33,11 @@ export function listIdentityProviders() {
24
33
  return IdentityProviders.map((id) => identityProviders[id]).filter(Boolean);
25
34
  }
26
35
 
27
- export { GoogleProvider, GithubProvider, GcpProvider, EmailProvider, IamProvider };
36
+ export {
37
+ GoogleProvider,
38
+ GithubProvider,
39
+ GcpProvider,
40
+ EmailProvider,
41
+ IamProvider,
42
+ CloudflareProvider,
43
+ };
@@ -1,24 +1,48 @@
1
- import { AUTH_COOKIE_NAME, AUTH_SESSION_TTL_SECONDS, DASHBOARD_AFTER_LOGIN_PATH } from '../core/constants.js';
1
+ import { AUTH_COOKIE_NAME, SESSION_POLICY } from '../core/constants.js';
2
2
  import { hashPassword, verifyPassword } from '../core/password-crypto.js';
3
3
  import { jsonResponse } from '../core/http-json.js';
4
- import { sanitizeBrowserNextPath } from '../core/browser-paths.js';
4
+ import { resolvePostAuthDestination } from './post-auth.js';
5
+ import { IdentityRoutingError } from '../contracts/identity-store.js';
5
6
  import { newAuthUserId } from '../adapters/cloudflare-d1/ids.js';
6
7
 
7
8
  /**
8
- * @typedef {ReturnType<import('../adapters/cloudflare-d1/index.js').createCloudflareD1Adapter>} IdentityStorageAdapter
9
+ * @typedef {import('../contracts/identity-store.js').IdentityStore} IdentityStore
9
10
  */
10
11
 
11
12
  /**
12
13
  * Server-side identity orchestration (Worker / Node). No secrets in client bundle.
13
- * @param {{ adapter: IdentityStorageAdapter, cookieName?: string, defaultRedirect?: string }} config
14
+ * Hosts must supply `app` + `routeRegistry` — no platform "/" fallback.
15
+ *
16
+ * @param {{
17
+ * adapter: IdentityStore,
18
+ * cookieName?: string,
19
+ * app: { id: string },
20
+ * routeRegistry: ReturnType<import('../contracts/route-projection.js').createRouteRegistry>,
21
+ * }} config
14
22
  */
15
23
  export function createIdentityService(config) {
16
24
  const adapter = config.adapter;
17
25
  if (!adapter) throw new Error('identity_service_requires_adapter');
18
26
  const cookieName = config.cookieName || AUTH_COOKIE_NAME;
19
- const defaultRedirect = config.defaultRedirect || DASHBOARD_AFTER_LOGIN_PATH;
27
+ const app = config.app || null;
28
+ const routeRegistry = config.routeRegistry || null;
29
+ if (!app?.id || !routeRegistry) {
30
+ throw new IdentityRoutingError(
31
+ 'AUTH_APP_UNRESOLVED',
32
+ 'createIdentityService requires app + routeRegistry (no platform fallback)',
33
+ );
34
+ }
35
+ routeRegistry.assertAuthCapable(app.id);
36
+
37
+ function resolvePostLoginPath(nextPath) {
38
+ return resolvePostAuthDestination({
39
+ transaction: { return_to: nextPath, app_id: app.id },
40
+ app,
41
+ routeRegistry,
42
+ });
43
+ }
20
44
 
21
- function sessionCookieHeader(sessionId, requestUrl, maxAge = AUTH_SESSION_TTL_SECONDS) {
45
+ function sessionCookieHeader(sessionId, requestUrl, maxAge = SESSION_POLICY.browser.ttlSeconds) {
22
46
  const secure = new URL(requestUrl).protocol === 'https:';
23
47
  const parts = [
24
48
  `${cookieName}=${sessionId}`,
@@ -39,7 +63,9 @@ export function createIdentityService(config) {
39
63
 
40
64
  return Object.freeze({
41
65
  cookieName,
42
- defaultRedirect,
66
+ app,
67
+ routeRegistry,
68
+ defaultRedirect: resolvePostLoginPath(null),
43
69
 
44
70
  async signup({ email, password, displayName }) {
45
71
  const normalized = String(email || '').trim().toLowerCase();
@@ -127,7 +153,7 @@ export function createIdentityService(config) {
127
153
  },
128
154
 
129
155
  buildLoginSuccessResponse(request, sessionId, nextPath) {
130
- const redirect = sanitizeBrowserNextPath(nextPath) || defaultRedirect;
156
+ const redirect = resolvePostLoginPath(nextPath);
131
157
  return jsonResponse(
132
158
  { ok: true, redirect },
133
159
  200,
@@ -150,6 +176,7 @@ export function createIdentityService(config) {
150
176
 
151
177
  parseSessionId,
152
178
  sessionCookieHeader,
179
+ resolvePostLoginPath,
153
180
  });
154
181
  }
155
182
 
@@ -0,0 +1,30 @@
1
+ /**
2
+ * Mount-level auth policy helpers (host applies; identity does not invent mounts).
3
+ */
4
+
5
+ /**
6
+ * @typedef {{ path: string, auth?: 'required'|'optional'|'public', spa?: boolean, shell?: string }} AppMount
7
+ */
8
+
9
+ export function pathMatchesMount(pathname, mount) {
10
+ const base = String(mount?.path || '');
11
+ if (!base) return false;
12
+ const path = String(pathname || '');
13
+ return path === base || path.startsWith(`${base}/`);
14
+ }
15
+
16
+ export function resolveMountForPath(pathname, app) {
17
+ const mounts = Array.isArray(app?.routes?.mounts) ? app.routes.mounts : [];
18
+ let best = null;
19
+ for (const mount of mounts) {
20
+ if (!pathMatchesMount(pathname, mount)) continue;
21
+ if (!best || String(mount.path).length > String(best.path).length) best = mount;
22
+ }
23
+ return best;
24
+ }
25
+
26
+ export function mountRequiresAuth(pathname, app) {
27
+ const mount = resolveMountForPath(pathname, app);
28
+ if (!mount) return false;
29
+ return (mount.auth || 'public') === 'required';
30
+ }