@inneranimalmedia/agentsam-sdk 2.6.4 → 2.6.5
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/AGENTSAM.md +11 -0
- package/README.md +15 -9
- package/apps/client-cms-editor/AGENTS.md +12 -0
- package/apps/client-cms-editor/IMPORT_PROVENANCE.json +8 -0
- package/apps/client-cms-editor/README.md +72 -0
- package/apps/client-cms-editor/agentsam.app.json +57 -0
- package/apps/client-cms-editor/backend/README.md +5 -0
- package/apps/client-cms-editor/backend/package.json +22 -0
- package/apps/client-cms-editor/backend/src/api/client.ts +200 -0
- package/apps/client-cms-editor/backend/src/demo-bootstrap.ts +145 -0
- package/apps/client-cms-editor/backend/src/index.ts +6 -0
- package/apps/client-cms-editor/backend/src/model.ts +115 -0
- package/apps/client-cms-editor/backend/src/preview/bridge.ts +79 -0
- package/apps/client-cms-editor/backend/src/preview/urls.ts +55 -0
- package/apps/client-cms-editor/backend/src/routing/cms-route.js +293 -0
- package/apps/client-cms-editor/backend/src/routing/index.js +10 -0
- package/apps/client-cms-editor/backend/src/storefront.ts +52 -0
- package/apps/client-cms-editor/backend/tsconfig.json +15 -0
- package/apps/client-cms-editor/backend/worker/index.js +34 -0
- package/apps/client-cms-editor/backend/wrangler.jsonc +11 -0
- package/apps/client-cms-editor/bin/agentsam-cms.mjs +229 -0
- package/apps/client-cms-editor/frontend/index.html +12 -0
- package/apps/client-cms-editor/frontend/package.json +33 -0
- package/apps/client-cms-editor/frontend/src/AgentSamDrawer.tsx +188 -0
- package/apps/client-cms-editor/frontend/src/CmsAgentSurface.tsx +191 -0
- package/apps/client-cms-editor/frontend/src/CmsEditor.tsx +1345 -0
- package/apps/client-cms-editor/frontend/src/env.d.ts +14 -0
- package/apps/client-cms-editor/frontend/src/index.ts +8 -0
- package/apps/client-cms-editor/frontend/src/lib/content-safety.ts +63 -0
- package/apps/client-cms-editor/frontend/src/main.tsx +17 -0
- package/apps/client-cms-editor/frontend/src/mount.tsx +51 -0
- package/apps/client-cms-editor/frontend/src/styles/agentsam-drawer.css +214 -0
- package/apps/client-cms-editor/frontend/src/styles/cmsShell.css +1739 -0
- package/apps/client-cms-editor/frontend/src/styles/studio.css +106 -0
- package/apps/client-cms-editor/frontend/src/surfaces/CmsDashboard.tsx +313 -0
- package/apps/client-cms-editor/frontend/src/surfaces/CmsGuidedChatHero.tsx +121 -0
- package/apps/client-cms-editor/frontend/src/surfaces/CmsHubPage.tsx +132 -0
- package/apps/client-cms-editor/frontend/src/surfaces/CmsSiteSwitcher.tsx +176 -0
- package/apps/client-cms-editor/frontend/src/surfaces/index.ts +5 -0
- package/apps/client-cms-editor/frontend/src/surfaces/types.ts +48 -0
- package/apps/client-cms-editor/frontend/tsconfig.json +25 -0
- package/apps/client-cms-editor/frontend/vite.config.ts +13 -0
- package/apps/client-cms-editor/package-lock.json +3832 -0
- package/apps/client-cms-editor/package.json +23 -0
- package/apps/client-cms-editor/reference/DONOR_README.md +52 -0
- package/apps/client-cms-editor/reference/DONOR_package-lock.json +1253 -0
- package/apps/client-cms-editor/reference/DONOR_tsconfig.json +15 -0
- package/apps/client-cms-editor/shared/cms/package.json +21 -0
- package/apps/client-cms-editor/shared/cms/src/agent-context.ts +35 -0
- package/apps/client-cms-editor/shared/cms/src/cloudflare-bindings.ts +51 -0
- package/apps/client-cms-editor/shared/cms/src/editor-types.ts +58 -0
- package/apps/client-cms-editor/shared/cms/src/index.ts +5 -0
- package/apps/client-cms-editor/shared/cms/src/publication.ts +24 -0
- package/apps/client-cms-editor/shared/cms/src/routes.ts +11 -0
- package/apps/client-cms-editor/shared/cms/tsconfig.json +12 -0
- package/bin/agentsam-rapid-rust +36 -0
- package/docs/AUTH_IDENTITY_CONTRACT.md +2 -0
- package/docs/MACHINE_INTELLIGENCE.md +120 -0
- package/docs/WINDOWS_RUNTIME_INSTALL.md +30 -0
- package/docs/architecture/AGENTSAM_APPLICATION_CONTRACT.md +188 -0
- package/docs/architecture/AGENTSAM_RUNTIME_PROTOCOL.md +151 -0
- package/docs/architecture/LOCAL_STUDIO_CLOUDFLARE_OAUTH.md +12 -4
- package/docs/architecture/R2_SLUG_NAMESPACE.md +20 -0
- package/docs/architecture/WORK_PRODUCT_EXTRACTION.md +97 -0
- package/docs/brand/AGENT_SAM_ICON_GRAMMAR.md +70 -0
- package/docs/content-studio/HOST_MOUNT_CHECKLIST.md +71 -0
- package/docs/content-studio/REVISION_GATE_2026-09-27.md +501 -0
- package/docs/contracts/capability-install-planner.md +67 -0
- package/docs/contracts/environment-vocabulary.md +195 -0
- package/docs/contracts/google-cloud-oauth-setup.md +199 -0
- package/docs/local-studio/WORKMODE_DONOR_NOTES.md +1 -1
- package/docs/plans/LOCAL-STUDIO-GRADUATION-2026-09-26.md +290 -0
- package/docs/plans/LOCAL-STUDIO-REAL-APP-CONTRACT-ADDENDUM-2026-09-27.md +394 -0
- package/docs/plans/MACHINE-FIRST-APPS-TUI-2026-09-24.md +227 -0
- package/docs/plans/TOMORROW-EXTENSIVE-TODO-2026-09-26.md +221 -0
- package/docs/plans/TOMORROW-MACHINE-FIRST-BRIEFING.md +145 -0
- package/docs/plans/UNIVERSAL-INGEST-MACHINE-FIRST-2026-09-24.md +215 -0
- package/docs/plugins.md +2 -2
- package/docs/product/AGENTSAM_PRODUCT_EXPERIENCE_STANDARD.md +280 -0
- package/docs/product/LOCAL_STUDIO_DESKTOP_EXPERIENCE.md +139 -0
- package/docs/product/README.md +8 -0
- package/docs/rapid-rust-wasm.md +35 -0
- package/migrations/d1/0016_cloudflare_oauth_user_oauth_tokens_ssot.sql +14 -0
- package/package.json +73 -14
- package/packages/agentsam-brand/README.md +106 -11
- package/packages/agentsam-brand/bin/agentsam-brand.mjs +9 -0
- package/packages/agentsam-brand/package.json +39 -7
- package/packages/agentsam-brand/src/adapters/cloudflare-images.js +453 -0
- package/packages/agentsam-brand/src/adapters/cloudflare-r2.js +74 -0
- package/packages/agentsam-brand/src/adapters/d1-registry.js +26 -0
- package/packages/agentsam-brand/src/adapters/filesystem.js +59 -0
- package/packages/agentsam-brand/src/adapters/memory.js +31 -0
- package/packages/agentsam-brand/src/cli/controller.js +503 -0
- package/packages/agentsam-brand/src/cli/wizard.js +526 -0
- package/packages/agentsam-brand/src/core/capabilities.js +201 -0
- package/packages/agentsam-brand/src/core/derivatives.js +211 -0
- package/packages/agentsam-brand/src/core/errors.js +12 -0
- package/packages/agentsam-brand/src/core/ingest.js +195 -0
- package/packages/agentsam-brand/src/core/inspect.js +109 -0
- package/packages/agentsam-brand/src/core/keys.js +83 -0
- package/packages/agentsam-brand/src/core/naming.js +142 -0
- package/packages/agentsam-brand/src/core/optimize.js +316 -0
- package/packages/agentsam-brand/src/core/pack.js +305 -0
- package/packages/agentsam-brand/src/core/plan.js +276 -0
- package/packages/agentsam-brand/src/core/preview.js +159 -0
- package/packages/agentsam-brand/src/core/processors/cloudflare.js +68 -0
- package/packages/agentsam-brand/src/core/processors/contract.js +203 -0
- package/packages/agentsam-brand/src/core/processors/index.js +148 -0
- package/packages/agentsam-brand/src/core/processors/native.js +82 -0
- package/packages/agentsam-brand/src/core/processors/sharp.js +113 -0
- package/packages/agentsam-brand/src/core/processors/squoosh-binary.js +195 -0
- package/packages/agentsam-brand/src/core/promote.js +288 -0
- package/packages/agentsam-brand/src/core/receipts.js +155 -0
- package/packages/agentsam-brand/src/core/v2/compile.js +280 -0
- package/packages/agentsam-brand/src/core/v2/derivatives-semantic.js +207 -0
- package/packages/agentsam-brand/src/core/v2/ingest-graph.js +387 -0
- package/packages/agentsam-brand/src/core/v2/roles.js +180 -0
- package/packages/agentsam-brand/src/core/v2/schema.js +209 -0
- package/packages/agentsam-brand/src/core/v2/templates.js +114 -0
- package/packages/agentsam-brand/src/index.js +193 -36
- package/packages/agentsam-brand/src/presets/app-icon.json +16 -0
- package/packages/agentsam-brand/src/presets/favicon.json +17 -0
- package/packages/agentsam-brand/src/presets/hero.json +12 -0
- package/packages/agentsam-brand/src/presets/index.js +40 -0
- package/packages/agentsam-brand/src/presets/logo.json +12 -0
- package/packages/agentsam-brand/src/presets/model.json +8 -0
- package/packages/agentsam-brand/src/presets/og-image.json +10 -0
- package/packages/agentsam-brand/src/presets/product-shot.json +11 -0
- package/packages/agentsam-brand/src/presets/social-image.json +10 -0
- package/packages/agentsam-brand/src/presets/web-image.json +10 -0
- package/packages/agentsam-contracts/src/artifacts.ts +41 -0
- package/packages/agentsam-knowledge/src/autorag/index.js +1 -1
- package/packages/agentsam-knowledge/src/providers/index.js +6 -4
- package/packages/agentsam-knowledge/src/providers/ollama-endpoint.js +31 -0
- package/packages/agentsam-knowledge/test/autorag.test.mjs +22 -1
- package/packages/agentsam-nav/package.json +2 -2
- package/packages/agentsam-rapid-rust/Cargo.lock +344 -0
- package/packages/agentsam-rapid-rust/Cargo.toml +18 -0
- package/packages/agentsam-rapid-rust/README.md +5 -0
- package/packages/agentsam-rapid-rust/src/main.rs +718 -0
- package/packages/agentsam-rapid-rust/templates/api/Cargo.toml.tmpl +18 -0
- package/packages/agentsam-rapid-rust/templates/api/src/lib.rs.tmpl +17 -0
- package/packages/agentsam-rapid-rust/templates/common/README.md.tmpl +22 -0
- package/packages/agentsam-rapid-rust/templates/common/package.json.tmpl +12 -0
- package/packages/agentsam-rapid-rust/templates/common/wrangler.toml.tmpl +6 -0
- package/packages/agentsam-rapid-rust/templates/crypto-auth/Cargo.toml.tmpl +21 -0
- package/packages/agentsam-rapid-rust/templates/crypto-auth/src/lib.rs.tmpl +32 -0
- package/packages/agentsam-rapid-rust/templates/data-processor/Cargo.toml.tmpl +18 -0
- package/packages/agentsam-rapid-rust/templates/data-processor/src/lib.rs.tmpl +41 -0
- package/packages/agentsam-rapid-rust/templates/shared-core/Cargo.toml.tmpl +9 -0
- package/packages/agentsam-rapid-rust/templates/shared-core/core/Cargo.toml.tmpl +7 -0
- package/packages/agentsam-rapid-rust/templates/shared-core/core/src/lib.rs.tmpl +23 -0
- package/packages/agentsam-rapid-rust/templates/shared-core/worker/Cargo.toml.tmpl +12 -0
- package/packages/agentsam-rapid-rust/templates/shared-core/worker/src/lib.rs.tmpl +16 -0
- package/packages/agentsam-rapid-rust/templates/shared-core/wrangler.toml.tmpl +6 -0
- package/packages/agentsam-repository/src/index.js +1 -0
- package/packages/agentsam-repository/src/merkle/semantic.js +3 -10
- package/packages/agentsam-repository/src/source-types.js +85 -0
- package/packages/agentsam-vault/README.md +96 -0
- package/packages/agentsam-vault/package.json +32 -0
- package/packages/agentsam-vault/src/contracts/credential.d.ts +78 -0
- package/packages/agentsam-vault/src/contracts/credential.js +132 -0
- package/packages/agentsam-vault/src/crypto/aes-gcm.d.ts +30 -0
- package/packages/agentsam-vault/src/crypto/aes-gcm.js +107 -0
- package/packages/agentsam-vault/src/crypto/oauth-envelope.js +150 -0
- package/packages/agentsam-vault/src/index.d.ts +9 -0
- package/packages/agentsam-vault/src/index.js +27 -0
- package/packages/agentsam-vault/src/providers/registry.js +90 -0
- package/packages/agentsam-vault/src/runtime/resolver.js +77 -0
- package/packages/agentsam-workbench/README.md +24 -0
- package/packages/agentsam-workbench/package.json +38 -0
- package/packages/agentsam-workbench/src/agent/AgentPanel.tsx +41 -0
- package/packages/agentsam-workbench/src/agent/ArtifactCard.tsx +9 -0
- package/packages/agentsam-workbench/src/agent/Composer.tsx +102 -0
- package/packages/agentsam-workbench/src/agent/ConnectedAgentPanel.tsx +194 -0
- package/packages/agentsam-workbench/src/agent/ContextualComposer.tsx +788 -0
- package/packages/agentsam-workbench/src/agent/GoalStatusStrip.tsx +38 -0
- package/packages/agentsam-workbench/src/agent/MiniAgentSam.tsx +86 -0
- package/packages/agentsam-workbench/src/agent/ModelSelect.tsx +19 -0
- package/packages/agentsam-workbench/src/agent/Thread.tsx +56 -0
- package/packages/agentsam-workbench/src/agent/ToolReceipt.tsx +11 -0
- package/packages/agentsam-workbench/src/agent/contextual-composer.css +611 -0
- package/packages/agentsam-workbench/src/agent/index.ts +10 -0
- package/packages/agentsam-workbench/src/agent/mini-agentsam.css +12 -0
- package/packages/agentsam-workbench/src/browser/BrowserFrame.tsx +37 -0
- package/packages/agentsam-workbench/src/browser/index.ts +1 -0
- package/packages/agentsam-workbench/src/index.ts +6 -0
- package/packages/agentsam-workbench/src/project-control.css +160 -0
- package/packages/agentsam-workbench/src/projects/ProjectsSurface.tsx +131 -0
- package/packages/agentsam-workbench/src/projects/index.ts +1 -0
- package/packages/agentsam-workbench/src/shell/Breadcrumb.tsx +35 -0
- package/packages/agentsam-workbench/src/shell/ResizableStage.tsx +99 -0
- package/packages/agentsam-workbench/src/shell/SidePanel.tsx +5 -0
- package/packages/agentsam-workbench/src/shell/index.ts +4 -0
- package/packages/agentsam-workbench/src/shell/surfaceRegistry.ts +29 -0
- package/packages/agentsam-workbench/src/terminal/TerminalSurface.tsx +5 -0
- package/packages/agentsam-workbench/src/terminal/index.ts +1 -0
- package/packages/agentsam-workbench/src/timeline/GanttBoard.tsx +258 -0
- package/packages/agentsam-workbench/src/timeline/index.ts +1 -0
- package/packages/agentsam-workbench/tsconfig.json +13 -0
- package/packages/connectors/cloudflare/OAUTH_STORAGE_AUDIT.md +53 -0
- package/packages/connectors/cloudflare/package.json +3 -1
- package/packages/connectors/cloudflare/src/api-client.js +279 -0
- package/packages/connectors/cloudflare/src/capabilities.js +585 -0
- package/packages/connectors/cloudflare/src/credential.js +318 -0
- package/packages/connectors/cloudflare/src/families/brand-protection.js +123 -0
- package/packages/connectors/cloudflare/src/families/keyless.js +114 -0
- package/packages/connectors/cloudflare/src/families/pages.js +151 -0
- package/packages/connectors/cloudflare/src/families/scanner.js +123 -0
- package/packages/connectors/cloudflare/src/families/snippets.js +207 -0
- package/packages/connectors/cloudflare/src/families/tag-gateway.js +46 -0
- package/packages/connectors/cloudflare/src/families/tags.js +124 -0
- package/packages/connectors/cloudflare/src/families/token-validation.js +95 -0
- package/packages/connectors/cloudflare/src/families/workflows.js +156 -0
- package/packages/connectors/cloudflare/src/index.js +102 -265
- package/packages/connectors/cloudflare/src/oauth-persist.js +336 -0
- package/packages/connectors/cloudflare/src/owner.js +42 -12
- package/packages/connectors/cloudflare/src/permission-options.js +1064 -0
- package/packages/connectors/cloudflare/src/routes.js +309 -144
- package/packages/connectors/cloudflare/src/scope-catalog.js +345 -0
- package/packages/connectors/cloudflare/src/vault.js +2 -2
- package/packages/connectors/cloudflare/tests/capabilities.test.mjs +276 -0
- package/packages/connectors/cloudflare/tests/connector.test.mjs +26 -30
- package/packages/connectors/cloudflare/tests/oauth-persist.test.mjs +125 -0
- package/packages/identity/.agentsam/features/oauth-login-portal/providers.json +22 -2
- package/packages/identity/.agentsam/features/oauth-login-portal/resources.json +10 -4
- package/packages/identity/.agentsam/features/oauth-login-portal/routes.json +20 -0
- package/packages/identity/README.md +1 -1
- package/packages/identity/backend/README.md +1 -1
- package/packages/identity/migrations/D1_SCHEMA_MAPPING.md +3 -2
- package/packages/identity/migrations/sqlite/004_identity_oauth_consent_catalog.sql +48 -0
- package/packages/identity/package.json +4 -3
- package/packages/identity/scripts/local-identity-bridge.mjs +184 -0
- package/packages/identity/scripts/preview-auth-portal.mjs +7 -7
- package/packages/identity/src/adapters/cloudflare-d1/index.js +31 -2
- package/packages/identity/src/adapters/sqlite/index.js +4 -1
- package/packages/identity/src/contracts/auth-config.js +28 -8
- package/packages/identity/src/contracts/external-identity.js +1 -1
- package/packages/identity/src/contracts/provider.js +1 -0
- package/packages/identity/src/frontend/auth-portal/README.md +2 -1
- package/packages/identity/src/frontend/auth-portal/pages/login.html +6 -5
- package/packages/identity/src/frontend/auth-portal/pages/reset.html +6 -5
- package/packages/identity/src/frontend/auth-portal/pages/signup.html +6 -5
- package/packages/identity/src/frontend/auth-portal/shared/company-branding.js +1 -1
- package/packages/identity/src/frontend/auth-portal/shared/desktop-identity-bridge.js +207 -0
- package/packages/identity/src/index.js +16 -0
- package/packages/identity/src/migrations/0001_identity_core.sql +19 -2
- package/packages/identity/src/migrations/0003_accounts_ssot.sql +20 -0
- package/packages/identity/src/migrations/README.md +5 -2
- package/packages/identity/src/oauth/README.md +10 -5
- package/packages/identity/src/oauth/consent-view.js +388 -0
- package/packages/identity/src/oauth/credentials.js +31 -11
- package/packages/identity/src/oauth/google-desktop-exchange.js +173 -0
- package/packages/identity/src/providers/cloudflare/oauth.js +3 -4
- package/packages/identity/src/providers/cloudflare/profile.js +49 -14
- package/packages/identity/src/providers/iam/index.js +27 -5
- package/packages/identity/src/server/identity-service.js +31 -2
- package/packages/identity/src/server/worker-router.js +111 -81
- package/packages/identity/tests/auth-config.test.mjs +3 -2
- package/packages/identity/tests/identity-init-scaffold.test.mjs +3 -0
- package/packages/identity/tests/identity-service.test.mjs +16 -0
- package/packages/identity/tests/native-session-worker.test.mjs +64 -0
- package/packages/identity/tests/oauth-consent-view.test.mjs +106 -0
- package/packages/identity/tests/oauth-credentials.test.mjs +17 -4
- package/packages/identity/tests/oauth-presets-accounts-ssot.test.mjs +58 -0
- package/packages/identity/tests/preview-auth-portal.test.mjs +3 -3
- package/packages/runtime-protocol/src/index.js +154 -0
- package/packages/theme-scenes/README.md +164 -0
- package/packages/theme-scenes/package.json +53 -0
- package/packages/theme-scenes/src/blocks/index.js +30 -0
- package/packages/theme-scenes/src/contracts/index.js +286 -0
- package/packages/theme-scenes/src/demos/index.js +65 -0
- package/packages/theme-scenes/src/index.js +75 -0
- package/packages/theme-scenes/src/presets/index.js +263 -0
- package/packages/theme-scenes/src/runtime/compile.js +119 -0
- package/packages/theme-scenes/src/scenes/index.js +146 -0
- package/packages/theme-scenes/src/shell/index.js +47 -0
- package/packages/theme-scenes/src/themes/index.js +129 -0
- package/packages/theme-scenes/src/visuals/index.js +41 -0
- package/packages/theme-scenes/test/theme-scenes.test.mjs +179 -0
- package/packages/work-graph/src/index.js +34 -1
- package/packages/work-graph/src/renderers/gantt-model.js +24 -0
- package/packages/work-graph/test/work-graph.test.mjs +27 -7
- package/protocol/README.md +15 -7
- package/protocol/apps/agentsam.app.v1.schema.json +89 -7
- package/protocol/apps/agentsam.host-install.v1.schema.json +36 -0
- package/protocol/assets/README.md +9 -0
- package/protocol/assets/asset-record.v1.schema.json +64 -0
- package/protocol/runtime/agentsam.runtime.v1.schema.json +75 -0
- package/protocol/scoring/README.md +10 -0
- package/protocol/scoring/scorecard.v1.schema.json +65 -0
- package/protocol/ui/icon-registry.mjs +1 -0
- package/registry/cms-rust-machine-20260928/installable-products.json +31 -0
- package/registry/cms-rust-machine-20260928/manifest.json +22 -0
- package/registry/cms-rust-machine-20260928/migration.sql +237 -0
- package/registry/cms-rust-machine-20260928/receipt.json +21 -0
- package/registry/cms-rust-machine-20260928/receipt.sql +27 -0
- package/scripts/build_rapid_rust_cli.py +83 -0
- package/src/attachments/index.js +6 -0
- package/src/attachments/intake.js +235 -0
- package/src/capabilities/repository-snapshot.js +19 -2
- package/src/cli/command-catalog.js +8 -0
- package/src/cli.js +182 -26
- package/src/commands/account-auth.js +94 -8
- package/src/commands/app.js +307 -3
- package/src/commands/billing.js +127 -0
- package/src/commands/brand.js +74 -60
- package/src/commands/cheat-sheet.js +154 -0
- package/src/commands/cloudflare-login.js +222 -0
- package/src/commands/cloudflare.js +453 -23
- package/src/commands/codebaseindex.js +6 -1
- package/src/commands/compute.js +4 -0
- package/src/commands/connections.js +11 -5
- package/src/commands/credentials.js +116 -0
- package/src/commands/gcloud-auth.js +427 -0
- package/src/commands/google-cloud.js +375 -0
- package/src/commands/identity-init.js +2 -2
- package/src/commands/mcp.js +226 -33
- package/src/commands/ollama.js +3 -2
- package/src/commands/plugins.js +7 -2
- package/src/commands/product.js +36 -0
- package/src/commands/runtime-status.js +28 -9
- package/src/commands/runtime.js +313 -0
- package/src/commands/rust.js +24 -0
- package/src/commands/setup.js +279 -0
- package/src/commands/shell.js +16 -3
- package/src/commands/start-local.js +2 -2
- package/src/commands/terminal.js +171 -0
- package/src/commands/update.js +140 -0
- package/src/commands/whoami.js +329 -65
- package/src/features/resolve.js +1 -0
- package/src/index.js +4 -0
- package/src/indexing/ingest/inventory.js +254 -19
- package/src/indexing/ingest/materials.js +3 -9
- package/src/indexing/ingest/style-evidence.js +181 -0
- package/src/knowledge/source.js +3 -3
- package/src/lib/account-session.js +11 -4
- package/src/lib/app-authority.js +172 -0
- package/src/lib/auth.js +94 -21
- package/src/lib/core-client.js +5 -6
- package/src/lib/credentials-audit.js +451 -0
- package/src/lib/deploy/health.js +24 -6
- package/src/lib/detect-context.js +7 -1
- package/src/lib/google-cloud-connection.js +270 -0
- package/src/lib/google-cloud-inventory.js +385 -0
- package/src/lib/google-desktop-oauth.js +372 -0
- package/src/lib/google-studio-brokered-oauth.js +158 -0
- package/src/lib/identity-scaffold.js +24 -6
- package/src/lib/init-options.js +192 -0
- package/src/lib/local-scaffold.js +48 -16
- package/src/lib/provider-command-remediation.js +308 -0
- package/src/lib/provider-credentials.js +8 -0
- package/src/lib/scaffold/index.js +8 -2
- package/src/lib/scaffold/mcp-server.js +43 -0
- package/src/lib/scaffold/templates/mcp-server/index.js +397 -0
- package/src/lib/scaffold/templates/mcp-server/presets.js +39 -0
- package/src/lib/scaffold/wizards/cms.js +93 -0
- package/src/lib/scaffold/wizards/mcp-server.js +61 -0
- package/src/lib/setup/contract.js +26 -0
- package/src/lib/setup/discover.js +116 -0
- package/src/lib/setup/execute.js +205 -0
- package/src/lib/setup/planner.js +134 -0
- package/src/lib/setup/recipes.js +235 -0
- package/src/lib/setup/runtime-persist.js +197 -0
- package/src/lib/setup/runtime.js +394 -0
- package/src/lib/slash-commands.js +2 -0
- package/src/lib/terminal/machine-identity.js +95 -0
- package/src/lib/terminal-local.js +164 -0
- package/src/lib/terminal-scopes.js +52 -0
- package/src/lib/whoami-capabilities.js +184 -0
- package/src/local-pty/server.js +34 -5
- package/src/mcp/authority.js +58 -108
- package/src/mcp/client-adapters.js +68 -144
- package/src/mcp/client.js +142 -122
- package/src/mcp/cloudflare-bundles.js +225 -0
- package/src/mcp/index.js +12 -0
- package/src/plugins/cloudflare.js +1 -1
- package/src/providers/ollama-chat.js +2 -1
- package/src/sam/types.js +27 -2
- package/src/security/inventory.js +12 -2
- package/src/security/local-vault.js +2 -0
- package/src/security/scan.js +1 -1
- package/test/account-session.test.mjs +3 -3
- package/test/app-authority-context.test.mjs +32 -0
- package/test/cli/codebaseindex-plan-ux.test.mjs +1 -1
- package/test/cli/mcp-client.test.mjs +21 -10
- package/test/cli/runtime-persist.test.mjs +56 -0
- package/test/cli/rust-command.test.mjs +21 -0
- package/test/credentials-audit.test.mjs +113 -0
- package/test/deploy-health-scan.test.mjs +29 -1
- package/test/gcloud-auth.test.mjs +111 -0
- package/test/google-cloud-connection.test.mjs +83 -0
- package/test/google-cloud-inventory.test.mjs +64 -0
- package/test/init-options.test.mjs +35 -0
- package/test/integration/app-command.test.mjs +30 -0
- package/test/integration/cad-project.test.mjs +4 -1
- package/test/integration/cms-app-scaffold.test.mjs +71 -0
- package/test/integration/cms-site-tenancy-contract.test.mjs +3 -2
- package/test/integration/codebaseindex-ingest.test.mjs +48 -0
- package/test/integration/features-resolve.test.mjs +30 -11
- package/test/integration/inspect-path-cli.test.mjs +46 -0
- package/test/integration/inventory-evidence.test.mjs +125 -0
- package/test/integration/runtime-status.integration.test.mjs +2 -1
- package/test/knowledge.test.mjs +35 -1
- package/test/loopback-oauth.test.mjs +53 -0
- package/test/ollama.test.mjs +22 -0
- package/test/security.test.mjs +23 -0
- package/test/setup-planner.test.mjs +74 -0
- package/test/setup-runtime.test.mjs +51 -0
- package/test/terminal/local-pty.mock.test.mjs +3 -1
- package/test/terminal-machine-identity.test.mjs +88 -0
- package/test/whoami-resume.test.mjs +27 -6
- package/packages/agentsam-brand/test/brand-scan.test.mjs +0 -106
- package/packages/work-graph/prototype/README.md +0 -32
- package/packages/work-graph/prototype/data/demo-workgraph.js +0 -47
- package/packages/work-graph/prototype/renderers/timeline-model.js +0 -21
- package/packages/work-graph/prototype/renderers/workgraph-runtime.js +0 -38
- package/packages/work-graph/prototype-gnantt.html +0 -655
|
@@ -1,10 +1,9 @@
|
|
|
1
1
|
const CLOUDFLARE_AUTH_URL = 'https://dash.cloudflare.com/oauth2/auth';
|
|
2
2
|
const CLOUDFLARE_TOKEN_URL = 'https://dash.cloudflare.com/oauth2/token';
|
|
3
3
|
|
|
4
|
-
// Identity-only login
|
|
5
|
-
//
|
|
6
|
-
|
|
7
|
-
const CLOUDFLARE_LOGIN_SCOPE = 'account-settings.read offline_access';
|
|
4
|
+
// Identity-only login: account identity + user details (email/name via /v4/user).
|
|
5
|
+
// Do NOT request the resource-access scope set used by the Cloudflare *connection* flow.
|
|
6
|
+
const CLOUDFLARE_LOGIN_SCOPE = 'account-settings.read user-details.read offline_access';
|
|
8
7
|
|
|
9
8
|
/** @param {import('../../provider-contract.js').OAuthAuthorizeInput} input */
|
|
10
9
|
export function getCloudflareAuthUrl({ clientId, redirectUri, state, codeChallenge, scope } = {}) {
|
|
@@ -1,26 +1,61 @@
|
|
|
1
1
|
const CLOUDFLARE_USERINFO_URL = 'https://dash.cloudflare.com/oauth2/userinfo';
|
|
2
|
+
const CLOUDFLARE_API_USER_URL = 'https://api.cloudflare.com/client/v4/user';
|
|
2
3
|
|
|
3
4
|
/**
|
|
4
5
|
* Fetch the authenticated Cloudflare user's identity.
|
|
5
|
-
*
|
|
6
|
-
*
|
|
7
|
-
*
|
|
8
|
-
*
|
|
6
|
+
*
|
|
7
|
+
* OIDC userinfo (`/oauth2/userinfo`) structurally returns `sub` only.
|
|
8
|
+
* Email/name require `user-details.read` and a second call to `/client/v4/user`
|
|
9
|
+
* (`data.result.*`, not top-level fields).
|
|
10
|
+
*
|
|
9
11
|
* @param {string} accessToken
|
|
12
|
+
* @param {{ fetchImpl?: typeof fetch }} [opts]
|
|
10
13
|
*/
|
|
11
|
-
export async function fetchCloudflareProfile(accessToken) {
|
|
14
|
+
export async function fetchCloudflareProfile(accessToken, opts = {}) {
|
|
15
|
+
const token = String(accessToken || '').trim();
|
|
16
|
+
if (!token) return null;
|
|
17
|
+
const fetchImpl = opts.fetchImpl || fetch;
|
|
12
18
|
try {
|
|
13
|
-
const
|
|
14
|
-
headers: { Authorization: `Bearer ${
|
|
19
|
+
const userinfoRes = await fetchImpl(CLOUDFLARE_USERINFO_URL, {
|
|
20
|
+
headers: { Authorization: `Bearer ${token}` },
|
|
15
21
|
});
|
|
16
|
-
if (!
|
|
17
|
-
const
|
|
18
|
-
if (!
|
|
22
|
+
if (!userinfoRes.ok) return null;
|
|
23
|
+
const userinfo = await userinfoRes.json().catch(() => null);
|
|
24
|
+
if (!userinfo) return null;
|
|
25
|
+
|
|
26
|
+
const sub = userinfo.sub || userinfo.id || userinfo.user_id || null;
|
|
27
|
+
let email = typeof userinfo.email === 'string' ? userinfo.email : null;
|
|
28
|
+
let name = typeof userinfo.name === 'string'
|
|
29
|
+
? userinfo.name
|
|
30
|
+
: (typeof userinfo.display_name === 'string' ? userinfo.display_name : null);
|
|
31
|
+
|
|
32
|
+
// Cloudflare userinfo does not return email/name — enrich from /v4/user.
|
|
33
|
+
if (!email || !name) {
|
|
34
|
+
try {
|
|
35
|
+
const apiRes = await fetchImpl(CLOUDFLARE_API_USER_URL, {
|
|
36
|
+
headers: { Authorization: `Bearer ${token}`, Accept: 'application/json' },
|
|
37
|
+
});
|
|
38
|
+
if (apiRes.ok) {
|
|
39
|
+
const body = await apiRes.json().catch(() => null);
|
|
40
|
+
const result = body?.result && typeof body.result === 'object' ? body.result : null;
|
|
41
|
+
if (result) {
|
|
42
|
+
if (!email && typeof result.email === 'string') email = result.email;
|
|
43
|
+
if (!name && typeof result.first_name === 'string' && typeof result.last_name === 'string') {
|
|
44
|
+
name = `${result.first_name} ${result.last_name}`.trim() || null;
|
|
45
|
+
}
|
|
46
|
+
if (!name && typeof result.name === 'string') name = result.name;
|
|
47
|
+
}
|
|
48
|
+
}
|
|
49
|
+
} catch {
|
|
50
|
+
// Non-fatal: identity can proceed with sub alone.
|
|
51
|
+
}
|
|
52
|
+
}
|
|
53
|
+
|
|
19
54
|
return {
|
|
20
|
-
sub:
|
|
21
|
-
email
|
|
22
|
-
name
|
|
23
|
-
raw:
|
|
55
|
+
sub: sub || null,
|
|
56
|
+
email,
|
|
57
|
+
name,
|
|
58
|
+
raw: userinfo,
|
|
24
59
|
};
|
|
25
60
|
} catch {
|
|
26
61
|
return null;
|
|
@@ -9,13 +9,16 @@ import {
|
|
|
9
9
|
} from './oauth.js';
|
|
10
10
|
import { fetchIamProfile } from './profile.js';
|
|
11
11
|
import { normalizeIamIdentity } from './mapper.js';
|
|
12
|
-
import {
|
|
12
|
+
import { resolveIamIssuer } from '../../contracts/auth-config.js';
|
|
13
13
|
|
|
14
14
|
/**
|
|
15
|
-
* @param {string}
|
|
15
|
+
* @param {string} origin Absolute IAM issuer origin (required — no DEFAULT_*).
|
|
16
16
|
*/
|
|
17
|
-
export function createIamIdentityProvider(origin
|
|
18
|
-
const resolvedOrigin = String(origin ||
|
|
17
|
+
export function createIamIdentityProvider(origin) {
|
|
18
|
+
const resolvedOrigin = String(origin || '').replace(/\/+$/, '');
|
|
19
|
+
if (!resolvedOrigin) {
|
|
20
|
+
throw new Error('IAM_OAUTH_ISSUER is required to create the IAM identity provider');
|
|
21
|
+
}
|
|
19
22
|
return createIdentityProvider({
|
|
20
23
|
id: 'iam',
|
|
21
24
|
authorizeUrl: (input) => getIamAuthUrl({ ...input, origin: resolvedOrigin }),
|
|
@@ -25,7 +28,26 @@ export function createIamIdentityProvider(origin = DEFAULT_IAM_ORIGIN) {
|
|
|
25
28
|
});
|
|
26
29
|
}
|
|
27
30
|
|
|
28
|
-
|
|
31
|
+
/**
|
|
32
|
+
* Registry singleton — resolves IAM_OAUTH_ISSUER from env/input at call time.
|
|
33
|
+
* No baked-in product host.
|
|
34
|
+
*/
|
|
35
|
+
export const IamProvider = createIdentityProvider({
|
|
36
|
+
id: 'iam',
|
|
37
|
+
authorizeUrl: (input) => {
|
|
38
|
+
const origin = resolveIamIssuer(input?.env || process.env, input?.origin || input?.issuer || '');
|
|
39
|
+
return getIamAuthUrl({ ...input, origin });
|
|
40
|
+
},
|
|
41
|
+
exchangeCode: (input) => {
|
|
42
|
+
const origin = resolveIamIssuer(input?.env || process.env, input?.origin || input?.issuer || '');
|
|
43
|
+
return exchangeIamCode({ ...input, origin });
|
|
44
|
+
},
|
|
45
|
+
getProfile: (accessToken, input = {}) => {
|
|
46
|
+
const origin = resolveIamIssuer(input?.env || process.env, input?.origin || input?.issuer || '');
|
|
47
|
+
return fetchIamProfile({ origin, accessToken });
|
|
48
|
+
},
|
|
49
|
+
normalizeIdentity: normalizeIamIdentity,
|
|
50
|
+
});
|
|
29
51
|
|
|
30
52
|
export {
|
|
31
53
|
getIamAuthUrl,
|
|
@@ -61,6 +61,11 @@ export function createIdentityService(config) {
|
|
|
61
61
|
return match ? decodeURIComponent(match[1]) : null;
|
|
62
62
|
}
|
|
63
63
|
|
|
64
|
+
function parseBearerSessionId(authorization) {
|
|
65
|
+
const match = String(authorization || '').match(/^Bearer\s+([^\s]+)$/i);
|
|
66
|
+
return match ? match[1] : null;
|
|
67
|
+
}
|
|
68
|
+
|
|
64
69
|
return Object.freeze({
|
|
65
70
|
cookieName,
|
|
66
71
|
app,
|
|
@@ -108,7 +113,8 @@ export function createIdentityService(config) {
|
|
|
108
113
|
},
|
|
109
114
|
|
|
110
115
|
async sessionFromRequest(request) {
|
|
111
|
-
const sessionId =
|
|
116
|
+
const sessionId = parseBearerSessionId(request.headers.get('Authorization'))
|
|
117
|
+
|| parseSessionId(request.headers.get('Cookie'));
|
|
112
118
|
if (!sessionId) return null;
|
|
113
119
|
const session = await adapter.getSession(sessionId);
|
|
114
120
|
if (!session) return null;
|
|
@@ -118,7 +124,8 @@ export function createIdentityService(config) {
|
|
|
118
124
|
},
|
|
119
125
|
|
|
120
126
|
async logout(request) {
|
|
121
|
-
const sessionId =
|
|
127
|
+
const sessionId = parseBearerSessionId(request.headers.get('Authorization'))
|
|
128
|
+
|| parseSessionId(request.headers.get('Cookie'));
|
|
122
129
|
if (sessionId) await adapter.revokeSession(sessionId);
|
|
123
130
|
return { ok: true };
|
|
124
131
|
},
|
|
@@ -152,6 +159,28 @@ export function createIdentityService(config) {
|
|
|
152
159
|
return { ok: true, authUserId: user.id, sessionId: session.id, session };
|
|
153
160
|
},
|
|
154
161
|
|
|
162
|
+
isNativeSessionRequest(request) {
|
|
163
|
+
const marker = String(request?.headers?.get?.('X-AgentSam-Native-Client') || '').toLowerCase();
|
|
164
|
+
return marker === '1' || marker === 'true' || marker === 'native';
|
|
165
|
+
},
|
|
166
|
+
|
|
167
|
+
buildNativeLoginSuccessResponse(result, nextPath) {
|
|
168
|
+
const redirect = resolvePostLoginPath(nextPath);
|
|
169
|
+
return jsonResponse({
|
|
170
|
+
ok: true,
|
|
171
|
+
redirect,
|
|
172
|
+
session_id: result.sessionId,
|
|
173
|
+
expires_at: result.session?.expires_at ?? null,
|
|
174
|
+
user: result.user
|
|
175
|
+
? {
|
|
176
|
+
id: result.user.id,
|
|
177
|
+
email: result.user.email,
|
|
178
|
+
displayName: result.user.display_name ?? null,
|
|
179
|
+
}
|
|
180
|
+
: null,
|
|
181
|
+
});
|
|
182
|
+
},
|
|
183
|
+
|
|
155
184
|
buildLoginSuccessResponse(request, sessionId, nextPath) {
|
|
156
185
|
const redirect = resolvePostLoginPath(nextPath);
|
|
157
186
|
return jsonResponse(
|
|
@@ -12,6 +12,7 @@ import { fetchCloudflareProfile } from '../providers/cloudflare/profile.js';
|
|
|
12
12
|
import { IDENTITY_ROUTE_IDS } from '../contracts/route-ids.js';
|
|
13
13
|
import { IdentityRoutingError } from '../contracts/identity-store.js';
|
|
14
14
|
import { resolveOAuthCredentialLane } from '../oauth/credentials.js';
|
|
15
|
+
import { handleGoogleDesktopExchangeRequest } from '../oauth/google-desktop-exchange.js';
|
|
15
16
|
import { iamPlatformOAuthCallback, iamPlatformOAuthStart } from '../oauth/iam-platform.js';
|
|
16
17
|
import { pkceChallenge, pkceVerifier, randomOAuthState } from '../oauth/pkce.js';
|
|
17
18
|
|
|
@@ -23,6 +24,10 @@ function escapeHtml(value) {
|
|
|
23
24
|
.replace(/"/g, '"');
|
|
24
25
|
}
|
|
25
26
|
|
|
27
|
+
function resolveLoginPath(identity) {
|
|
28
|
+
return identity.routeRegistry.resolve(identity.app.id, IDENTITY_ROUTE_IDS.LOGIN) || '/auth/login';
|
|
29
|
+
}
|
|
30
|
+
|
|
26
31
|
function resolveKv(env) {
|
|
27
32
|
return env?.SESSION_CACHE || env?.KV || null;
|
|
28
33
|
}
|
|
@@ -115,6 +120,9 @@ export async function handleIdentityWorkerRequest(request, env, options = {}) {
|
|
|
115
120
|
await adapter.logAuthEvent({
|
|
116
121
|
userId: result.user.id, eventType: 'login', status: 'ok', provider: 'email', request,
|
|
117
122
|
});
|
|
123
|
+
if (identity.isNativeSessionRequest(request)) {
|
|
124
|
+
return identity.buildNativeLoginSuccessResponse(result, body.next);
|
|
125
|
+
}
|
|
118
126
|
return identity.buildLoginSuccessResponse(request, result.sessionId, body.next);
|
|
119
127
|
}
|
|
120
128
|
|
|
@@ -128,6 +136,9 @@ export async function handleIdentityWorkerRequest(request, env, options = {}) {
|
|
|
128
136
|
if (!result.ok) {
|
|
129
137
|
return jsonResponse({ ok: false, error: result.error }, 400);
|
|
130
138
|
}
|
|
139
|
+
if (identity.isNativeSessionRequest(request)) {
|
|
140
|
+
return identity.buildNativeLoginSuccessResponse(result, body.next);
|
|
141
|
+
}
|
|
131
142
|
return identity.buildLoginSuccessResponse(request, result.sessionId, body.next);
|
|
132
143
|
}
|
|
133
144
|
|
|
@@ -218,9 +229,13 @@ export async function handleIdentityWorkerRequest(request, env, options = {}) {
|
|
|
218
229
|
}
|
|
219
230
|
|
|
220
231
|
// ── OAuth ────────────────────────────────────────────────────────────────
|
|
221
|
-
// Default: IAM_CLIENT_* (minted). Developer BYOK GOOGLE_*/GITHUB_*
|
|
222
|
-
// matching /api/oauth/{provider}/start button when set.
|
|
232
|
+
// Default: IAM_CLIENT_* (minted). Developer BYOK GOOGLE_*/GITHUB_*/CLOUDFLARE_*
|
|
233
|
+
// take the matching /api/oauth/{provider}/start button when set.
|
|
234
|
+
// Desktop PKCE: GOOGLE_DESKTOP_CLIENT_ID → POST /api/oauth/google/desktop-exchange.
|
|
223
235
|
// Canonical platform id = inneranimalmedia (legacy /api/oauth/iam/* still accepted).
|
|
236
|
+
if (path === '/api/oauth/google/desktop-exchange') {
|
|
237
|
+
return handleGoogleDesktopExchangeRequest(request, env);
|
|
238
|
+
}
|
|
224
239
|
if (path === '/api/oauth/inneranimalmedia/callback' || path === '/api/oauth/iam/callback') {
|
|
225
240
|
if (method === 'GET') {
|
|
226
241
|
return iamPlatformOAuthCallback(request, env, adapter, identity);
|
|
@@ -367,91 +382,106 @@ async function oauthStart(request, env, identity, adapter, provider, creds) {
|
|
|
367
382
|
|
|
368
383
|
async function oauthCallback(request, env, identity, adapter, provider, creds) {
|
|
369
384
|
const url = new URL(request.url);
|
|
370
|
-
const
|
|
371
|
-
|
|
372
|
-
|
|
373
|
-
|
|
374
|
-
|
|
375
|
-
|
|
376
|
-
|
|
377
|
-
|
|
378
|
-
if (!saved || saved.provider !== provider) {
|
|
379
|
-
await adapter.logAuthEvent({ eventType: 'login', status: 'failed', provider, request, metadata: { reason: 'state_mismatch' } });
|
|
380
|
-
return Response.redirect(`${url.origin}${loginPath()}?error=state_mismatch`, 302);
|
|
381
|
-
}
|
|
382
|
-
const redirectUri = `${url.origin}/api/oauth/${provider}/callback`;
|
|
383
|
-
let token;
|
|
384
|
-
let profile;
|
|
385
|
-
if (provider === 'google') {
|
|
386
|
-
token = await exchangeGoogleCode({
|
|
387
|
-
code,
|
|
388
|
-
codeVerifier: saved.code_verifier,
|
|
389
|
-
clientId: creds.clientId,
|
|
390
|
-
clientSecret: creds.clientSecret,
|
|
391
|
-
redirectUri,
|
|
392
|
-
});
|
|
393
|
-
if (!token?.access_token) {
|
|
394
|
-
return Response.redirect(`${url.origin}${loginPath()}?error=token_exchange_failed`, 302);
|
|
385
|
+
const login = resolveLoginPath(identity);
|
|
386
|
+
try {
|
|
387
|
+
const code = url.searchParams.get('code');
|
|
388
|
+
const state = url.searchParams.get('state');
|
|
389
|
+
const err = url.searchParams.get('error');
|
|
390
|
+
if (err || !code || !state) {
|
|
391
|
+
await adapter.logAuthEvent({ eventType: 'login', status: 'failed', provider, request, metadata: { reason: 'oauth_failed' } });
|
|
392
|
+
return Response.redirect(`${url.origin}${login}?error=oauth_failed`, 302);
|
|
395
393
|
}
|
|
396
|
-
|
|
397
|
-
|
|
398
|
-
|
|
399
|
-
|
|
400
|
-
codeVerifier: saved.code_verifier,
|
|
401
|
-
clientId: creds.clientId,
|
|
402
|
-
clientSecret: creds.clientSecret,
|
|
403
|
-
redirectUri,
|
|
404
|
-
});
|
|
405
|
-
if (!token?.access_token) {
|
|
406
|
-
return Response.redirect(`${url.origin}${loginPath()}?error=token_exchange_failed`, 302);
|
|
394
|
+
const saved = await adapter.consumeOAuthState(state);
|
|
395
|
+
if (!saved || saved.provider !== provider) {
|
|
396
|
+
await adapter.logAuthEvent({ eventType: 'login', status: 'failed', provider, request, metadata: { reason: 'state_mismatch' } });
|
|
397
|
+
return Response.redirect(`${url.origin}${login}?error=state_mismatch`, 302);
|
|
407
398
|
}
|
|
408
|
-
|
|
409
|
-
|
|
410
|
-
|
|
411
|
-
|
|
412
|
-
|
|
413
|
-
|
|
414
|
-
|
|
415
|
-
|
|
416
|
-
|
|
417
|
-
|
|
418
|
-
|
|
399
|
+
const redirectUri = `${url.origin}/api/oauth/${provider}/callback`;
|
|
400
|
+
let token;
|
|
401
|
+
let profile;
|
|
402
|
+
if (provider === 'google') {
|
|
403
|
+
token = await exchangeGoogleCode({
|
|
404
|
+
code,
|
|
405
|
+
codeVerifier: saved.code_verifier,
|
|
406
|
+
clientId: creds.clientId,
|
|
407
|
+
clientSecret: creds.clientSecret,
|
|
408
|
+
redirectUri,
|
|
409
|
+
});
|
|
410
|
+
if (!token?.access_token) {
|
|
411
|
+
return Response.redirect(`${url.origin}${login}?error=token_exchange_failed`, 302);
|
|
412
|
+
}
|
|
413
|
+
profile = await fetchGoogleProfile(token.access_token);
|
|
414
|
+
} else if (provider === 'cloudflare') {
|
|
415
|
+
token = await exchangeCloudflareCode({
|
|
416
|
+
code,
|
|
417
|
+
codeVerifier: saved.code_verifier,
|
|
418
|
+
clientId: creds.clientId,
|
|
419
|
+
clientSecret: creds.clientSecret,
|
|
420
|
+
redirectUri,
|
|
421
|
+
});
|
|
422
|
+
if (!token?.access_token) {
|
|
423
|
+
return Response.redirect(`${url.origin}${login}?error=token_exchange_failed`, 302);
|
|
424
|
+
}
|
|
425
|
+
profile = await fetchCloudflareProfile(token.access_token);
|
|
426
|
+
} else {
|
|
427
|
+
token = await exchangeGithubCode({
|
|
428
|
+
code,
|
|
429
|
+
codeVerifier: saved.code_verifier,
|
|
430
|
+
clientId: creds.clientId,
|
|
431
|
+
clientSecret: creds.clientSecret,
|
|
432
|
+
redirectUri,
|
|
433
|
+
});
|
|
434
|
+
if (!token?.access_token) {
|
|
435
|
+
return Response.redirect(`${url.origin}${login}?error=token_exchange_failed`, 302);
|
|
436
|
+
}
|
|
437
|
+
profile = await fetchGithubProfile(token.access_token);
|
|
438
|
+
}
|
|
439
|
+
if (!profile) {
|
|
440
|
+
return Response.redirect(`${url.origin}${login}?error=userinfo_failed`, 302);
|
|
419
441
|
}
|
|
420
|
-
profile = await fetchGithubProfile(token.access_token);
|
|
421
|
-
}
|
|
422
|
-
if (!profile) {
|
|
423
|
-
return Response.redirect(`${url.origin}${loginPath()}?error=userinfo_failed`, 302);
|
|
424
|
-
}
|
|
425
442
|
|
|
426
|
-
|
|
427
|
-
|
|
428
|
-
|
|
429
|
-
|
|
430
|
-
|
|
431
|
-
|
|
432
|
-
|
|
433
|
-
|
|
443
|
+
let normalized;
|
|
444
|
+
if (provider === 'google') {
|
|
445
|
+
normalized = { subject: profile.sub, email: profile.email, name: profile.name };
|
|
446
|
+
} else if (provider === 'cloudflare') {
|
|
447
|
+
const subject = profile.sub || profile.email;
|
|
448
|
+
if (!subject) {
|
|
449
|
+
return Response.redirect(`${url.origin}${login}?error=userinfo_incomplete`, 302);
|
|
450
|
+
}
|
|
451
|
+
normalized = { subject: String(subject), email: profile.email, name: profile.name || profile.email };
|
|
452
|
+
} else {
|
|
453
|
+
normalized = { subject: String(profile.id), email: profile.email, name: profile.name || profile.login };
|
|
454
|
+
}
|
|
434
455
|
|
|
435
|
-
|
|
436
|
-
|
|
437
|
-
|
|
438
|
-
|
|
439
|
-
|
|
440
|
-
|
|
441
|
-
|
|
442
|
-
|
|
443
|
-
|
|
456
|
+
const result = await identity.provisionOAuthUser({
|
|
457
|
+
provider,
|
|
458
|
+
providerSubject: normalized.subject,
|
|
459
|
+
email: normalized.email,
|
|
460
|
+
displayName: normalized.name,
|
|
461
|
+
});
|
|
462
|
+
await adapter.logAuthEvent({
|
|
463
|
+
userId: result.authUserId, eventType: 'login', status: 'ok', provider, request,
|
|
464
|
+
});
|
|
444
465
|
|
|
445
|
-
|
|
446
|
-
|
|
447
|
-
|
|
448
|
-
|
|
449
|
-
|
|
450
|
-
|
|
451
|
-
|
|
452
|
-
|
|
453
|
-
|
|
454
|
-
|
|
466
|
+
const redirectTo = identity.resolvePostLoginPath(saved.redirect_to);
|
|
467
|
+
const res = identity.buildLoginSuccessResponse(request, result.sessionId, redirectTo);
|
|
468
|
+
const globeUrl = `${url.origin}${login}?globe_exit=1&next=${encodeURIComponent(redirectTo)}`;
|
|
469
|
+
return new Response(null, {
|
|
470
|
+
status: 302,
|
|
471
|
+
headers: {
|
|
472
|
+
Location: globeUrl,
|
|
473
|
+
'Set-Cookie': res.headers.get('Set-Cookie') || '',
|
|
474
|
+
},
|
|
475
|
+
});
|
|
476
|
+
} catch (error) {
|
|
477
|
+
const message = String(error?.message || error || 'oauth_callback_failed');
|
|
478
|
+
console.error('oauth_callback_failed', provider, message);
|
|
479
|
+
const loginUrl = new URL(login, url.origin);
|
|
480
|
+
loginUrl.searchParams.set('error', 'oauth_callback_failed');
|
|
481
|
+
loginUrl.searchParams.set('provider', provider);
|
|
482
|
+
loginUrl.searchParams.set('detail', message.slice(0, 120));
|
|
483
|
+
return Response.redirect(loginUrl.toString(), 302);
|
|
484
|
+
}
|
|
455
485
|
}
|
|
456
486
|
|
|
457
487
|
export { createIdentityService, createCloudflareD1Adapter };
|
|
@@ -2,6 +2,7 @@ import assert from 'node:assert/strict';
|
|
|
2
2
|
import { describe, it } from 'node:test';
|
|
3
3
|
import {
|
|
4
4
|
AGENTSAM_AUTH_CONTRACT,
|
|
5
|
+
PLATFORM_ACCOUNT_ISSUER,
|
|
5
6
|
buildApiAuthorizationHeaders,
|
|
6
7
|
resolveApiKey,
|
|
7
8
|
resolveBridgeKey,
|
|
@@ -23,8 +24,8 @@ describe('auth configuration contract', () => {
|
|
|
23
24
|
assert.equal(resolveIamOrigin({ IAM_ORIGIN: 'https://legacy.example.test/' }), 'https://legacy.example.test');
|
|
24
25
|
});
|
|
25
26
|
|
|
26
|
-
it('
|
|
27
|
-
assert.equal(resolveIamOrigin({}),
|
|
27
|
+
it('falls back to the canonical platform account issuer when env is unset', () => {
|
|
28
|
+
assert.equal(resolveIamOrigin({}), PLATFORM_ACCOUNT_ISSUER);
|
|
28
29
|
});
|
|
29
30
|
|
|
30
31
|
it('resolves only AGENTSAM_API_KEY for delegated account API auth', () => {
|
|
@@ -16,7 +16,10 @@ describe('identity init scaffold', () => {
|
|
|
16
16
|
assert.ok(files['app/frontend/auth/signup.html'].includes('/api/auth/signup'));
|
|
17
17
|
assert.ok(files['backend/src/index.js'].includes('handleIdentityWorkerRequest'));
|
|
18
18
|
assert.ok(files['migrations/0001_identity_core.sql'].includes('CREATE TABLE IF NOT EXISTS company'));
|
|
19
|
+
assert.ok(files['migrations/0001_identity_core.sql'].includes('CREATE TABLE IF NOT EXISTS accounts'));
|
|
19
20
|
assert.ok(files['migrations/0001_identity_core.sql'].includes('INSERT OR IGNORE INTO company'));
|
|
21
|
+
assert.ok(files['.env.example'].includes('GOOGLE_DESKTOP_CLIENT_ID'));
|
|
22
|
+
assert.ok(files['.env.example'].includes('CLOUDFLARE_OAUTH_CLIENT_ID'));
|
|
20
23
|
assert.ok(files['app/frontend/shared/company-branding.js'].includes('/api/company'));
|
|
21
24
|
|
|
22
25
|
const tmp = fs.mkdtempSync(path.join(os.tmpdir(), 'identity-init-'));
|
|
@@ -128,6 +128,22 @@ describe('identity service', () => {
|
|
|
128
128
|
});
|
|
129
129
|
assert.equal(login.ok, true);
|
|
130
130
|
|
|
131
|
+
const nativeRequest = new Request('https://example.test/api/auth/login', {
|
|
132
|
+
headers: { 'X-AgentSam-Native-Client': '1' },
|
|
133
|
+
});
|
|
134
|
+
assert.equal(identity.isNativeSessionRequest(nativeRequest), true);
|
|
135
|
+
const nativeResponse = identity.buildNativeLoginSuccessResponse(login, '/agentsam');
|
|
136
|
+
const nativeBody = await nativeResponse.json();
|
|
137
|
+
assert.equal(nativeBody.ok, true);
|
|
138
|
+
assert.equal(nativeBody.session_id, login.sessionId);
|
|
139
|
+
assert.equal(nativeBody.user.email, 'user@example.com');
|
|
140
|
+
assert.equal(nativeResponse.headers.get('set-cookie'), null);
|
|
141
|
+
|
|
142
|
+
const bearerCtx = await identity.sessionFromRequest(new Request('https://example.test/api/auth/me', {
|
|
143
|
+
headers: { Authorization: `Bearer ${login.sessionId}` },
|
|
144
|
+
}));
|
|
145
|
+
assert.equal(bearerCtx?.user?.email, 'user@example.com');
|
|
146
|
+
|
|
131
147
|
const bad = await identity.loginWithPassword({
|
|
132
148
|
email: 'user@example.com',
|
|
133
149
|
password: 'wrong',
|
|
@@ -0,0 +1,64 @@
|
|
|
1
|
+
import assert from 'node:assert/strict';
|
|
2
|
+
import { test } from 'node:test';
|
|
3
|
+
import { handleIdentityWorkerRequest } from '../src/server/worker-router.js';
|
|
4
|
+
|
|
5
|
+
function fakeDb() {
|
|
6
|
+
return {
|
|
7
|
+
prepare() {
|
|
8
|
+
return {
|
|
9
|
+
bind() {
|
|
10
|
+
return {
|
|
11
|
+
async run() { return { success: true }; },
|
|
12
|
+
async first() { return null; },
|
|
13
|
+
async all() { return { results: [] }; },
|
|
14
|
+
};
|
|
15
|
+
},
|
|
16
|
+
};
|
|
17
|
+
},
|
|
18
|
+
};
|
|
19
|
+
}
|
|
20
|
+
|
|
21
|
+
test('native login returns bearer session JSON instead of cookie response', async () => {
|
|
22
|
+
let nativeBranch = false;
|
|
23
|
+
const identity = {
|
|
24
|
+
app: { id: 'local-studio' },
|
|
25
|
+
routeRegistry: { resolve: () => '/agentsam' },
|
|
26
|
+
async loginWithPassword() {
|
|
27
|
+
return {
|
|
28
|
+
ok: true,
|
|
29
|
+
user: { id: 'au_test', email: 'user@example.com', display_name: 'User' },
|
|
30
|
+
sessionId: 'sess_native_123',
|
|
31
|
+
session: { expires_at: 1234567890 },
|
|
32
|
+
};
|
|
33
|
+
},
|
|
34
|
+
isNativeSessionRequest(request) {
|
|
35
|
+
return request.headers.get('X-AgentSam-Native-Client') === '1';
|
|
36
|
+
},
|
|
37
|
+
buildNativeLoginSuccessResponse(result) {
|
|
38
|
+
nativeBranch = true;
|
|
39
|
+
return Response.json({ ok: true, session_id: result.sessionId, user: result.user });
|
|
40
|
+
},
|
|
41
|
+
buildLoginSuccessResponse() {
|
|
42
|
+
throw new Error('cookie_login_response_should_not_run');
|
|
43
|
+
},
|
|
44
|
+
};
|
|
45
|
+
|
|
46
|
+
const response = await handleIdentityWorkerRequest(
|
|
47
|
+
new Request('https://example.test/api/auth/login', {
|
|
48
|
+
method: 'POST',
|
|
49
|
+
headers: {
|
|
50
|
+
'content-type': 'application/json',
|
|
51
|
+
'X-AgentSam-Native-Client': '1',
|
|
52
|
+
},
|
|
53
|
+
body: JSON.stringify({ email: 'user@example.com', password: 'secret-pass' }),
|
|
54
|
+
}),
|
|
55
|
+
{ DB: fakeDb() },
|
|
56
|
+
{ identity },
|
|
57
|
+
);
|
|
58
|
+
|
|
59
|
+
assert.equal(response.status, 200);
|
|
60
|
+
assert.equal(nativeBranch, true);
|
|
61
|
+
assert.equal(response.headers.get('set-cookie'), null);
|
|
62
|
+
const body = await response.json();
|
|
63
|
+
assert.equal(body.session_id, 'sess_native_123');
|
|
64
|
+
});
|