@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
|
@@ -0,0 +1,372 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Native Desktop Google OAuth (PKCE + loopback) for Agent Sam CLI.
|
|
3
|
+
* Uses GOOGLE_DESKTOP_CLIENT_ID — never embeds a desktop client secret as a security boundary.
|
|
4
|
+
*/
|
|
5
|
+
import { createHash, randomBytes } from 'node:crypto';
|
|
6
|
+
import {
|
|
7
|
+
createLoopbackCallbackListener,
|
|
8
|
+
createPkcePair,
|
|
9
|
+
} from './auth.js';
|
|
10
|
+
import { promptToOpenUrl, openExternalUrl } from './open-url.js';
|
|
11
|
+
import { setSecureProviderKey } from '../security/local-vault.js';
|
|
12
|
+
import { writeGoogleCloudConnection } from './google-cloud-connection.js';
|
|
13
|
+
|
|
14
|
+
/** Identity + Cloud Platform — what `agentsam gcloud auth login` requests by default. */
|
|
15
|
+
export const GOOGLE_CLOUD_CONNECTION_SCOPES = [
|
|
16
|
+
'openid',
|
|
17
|
+
'email',
|
|
18
|
+
'profile',
|
|
19
|
+
'https://www.googleapis.com/auth/cloud-platform',
|
|
20
|
+
].join(' ');
|
|
21
|
+
|
|
22
|
+
const GOOGLE_AUTH_URL = 'https://accounts.google.com/o/oauth2/v2/auth';
|
|
23
|
+
const GOOGLE_TOKEN_URL = 'https://oauth2.googleapis.com/token';
|
|
24
|
+
const GOOGLE_USERINFO_URL = 'https://openidconnect.googleapis.com/v1/userinfo';
|
|
25
|
+
|
|
26
|
+
function clean(value) {
|
|
27
|
+
return value == null ? '' : String(value).trim();
|
|
28
|
+
}
|
|
29
|
+
|
|
30
|
+
function base64url(value) {
|
|
31
|
+
return Buffer.from(value)
|
|
32
|
+
.toString('base64')
|
|
33
|
+
.replace(/=/g, '')
|
|
34
|
+
.replace(/\+/g, '-')
|
|
35
|
+
.replace(/\//g, '_');
|
|
36
|
+
}
|
|
37
|
+
|
|
38
|
+
function randomState(randomBytesImpl = randomBytes) {
|
|
39
|
+
return base64url(randomBytesImpl(24));
|
|
40
|
+
}
|
|
41
|
+
|
|
42
|
+
/** Public Desktop client id — env first, then stock Studio public-config (not load-agent-env). */
|
|
43
|
+
export function resolveGoogleDesktopClientId(env = process.env) {
|
|
44
|
+
const id = clean(env.GOOGLE_DESKTOP_CLIENT_ID);
|
|
45
|
+
if (!id) {
|
|
46
|
+
const err = new Error(
|
|
47
|
+
'GOOGLE_DESKTOP_CLIENT_ID is not configured. Stock path: fetch from Local Studio GET /api/public-config (Worker vars). Do not rely on another user\'s ~/.agentsam/load-agent-env.sh. Tip: agentsam gcloud auth login --permissions',
|
|
48
|
+
);
|
|
49
|
+
err.code = 'google_desktop_client_not_configured';
|
|
50
|
+
throw err;
|
|
51
|
+
}
|
|
52
|
+
return id;
|
|
53
|
+
}
|
|
54
|
+
|
|
55
|
+
/**
|
|
56
|
+
* Resolve desktop client id: env override, then Studio/public host public-config.
|
|
57
|
+
* @param {object} [env]
|
|
58
|
+
* @param {{ fetchImpl?: typeof fetch, publicConfigUrl?: string }} [opts]
|
|
59
|
+
*/
|
|
60
|
+
export async function resolveGoogleDesktopClientIdAsync(env = process.env, opts = {}) {
|
|
61
|
+
const fromEnv = clean(env.GOOGLE_DESKTOP_CLIENT_ID);
|
|
62
|
+
if (fromEnv) return fromEnv;
|
|
63
|
+
|
|
64
|
+
const fetchImpl = opts.fetchImpl || fetch;
|
|
65
|
+
const candidates = [];
|
|
66
|
+
if (clean(opts.publicConfigUrl)) candidates.push(clean(opts.publicConfigUrl));
|
|
67
|
+
const studioOrigin = clean(env.AGENTSAM_STUDIO_ORIGIN) || 'https://agentsam.inneranimalmedia.com';
|
|
68
|
+
candidates.push(new URL('/api/public-config', `${studioOrigin}/`).toString());
|
|
69
|
+
|
|
70
|
+
for (const url of candidates) {
|
|
71
|
+
try {
|
|
72
|
+
const res = await fetchImpl(url, {
|
|
73
|
+
headers: { accept: 'application/json' },
|
|
74
|
+
signal: typeof AbortSignal?.timeout === 'function' ? AbortSignal.timeout(8000) : undefined,
|
|
75
|
+
});
|
|
76
|
+
if (!res.ok) continue;
|
|
77
|
+
const body = await res.json().catch(() => null);
|
|
78
|
+
const id = clean(body?.google_desktop_client_id);
|
|
79
|
+
if (id) return id;
|
|
80
|
+
} catch {
|
|
81
|
+
/* try next */
|
|
82
|
+
}
|
|
83
|
+
}
|
|
84
|
+
|
|
85
|
+
return resolveGoogleDesktopClientId(env);
|
|
86
|
+
}
|
|
87
|
+
|
|
88
|
+
export function buildGoogleDesktopAuthUrl({
|
|
89
|
+
clientId,
|
|
90
|
+
redirectUri,
|
|
91
|
+
state,
|
|
92
|
+
codeChallenge,
|
|
93
|
+
scope = GOOGLE_CLOUD_CONNECTION_SCOPES,
|
|
94
|
+
} = {}) {
|
|
95
|
+
const url = new URL(GOOGLE_AUTH_URL);
|
|
96
|
+
url.searchParams.set('client_id', clientId || '');
|
|
97
|
+
url.searchParams.set('redirect_uri', redirectUri || '');
|
|
98
|
+
url.searchParams.set('response_type', 'code');
|
|
99
|
+
url.searchParams.set('scope', scope || GOOGLE_CLOUD_CONNECTION_SCOPES);
|
|
100
|
+
url.searchParams.set('state', state || '');
|
|
101
|
+
url.searchParams.set('code_challenge', codeChallenge || '');
|
|
102
|
+
url.searchParams.set('code_challenge_method', 'S256');
|
|
103
|
+
url.searchParams.set('access_type', 'offline');
|
|
104
|
+
url.searchParams.set('prompt', 'consent');
|
|
105
|
+
url.searchParams.set('include_granted_scopes', 'true');
|
|
106
|
+
return url.toString();
|
|
107
|
+
}
|
|
108
|
+
|
|
109
|
+
export async function exchangeGoogleDesktopCode({
|
|
110
|
+
code,
|
|
111
|
+
codeVerifier,
|
|
112
|
+
clientId,
|
|
113
|
+
redirectUri,
|
|
114
|
+
fetchImpl = fetch,
|
|
115
|
+
timeoutMs = 20_000,
|
|
116
|
+
studioOrigin = '',
|
|
117
|
+
allowStudioBroker = true,
|
|
118
|
+
} = {}) {
|
|
119
|
+
const body = new URLSearchParams({
|
|
120
|
+
grant_type: 'authorization_code',
|
|
121
|
+
code: code || '',
|
|
122
|
+
code_verifier: codeVerifier || '',
|
|
123
|
+
client_id: clientId || '',
|
|
124
|
+
redirect_uri: redirectUri || '',
|
|
125
|
+
});
|
|
126
|
+
// Desktop public clients: secret is optional / not a confidentiality boundary.
|
|
127
|
+
const signal = typeof AbortSignal?.timeout === 'function'
|
|
128
|
+
? AbortSignal.timeout(Math.max(1, Number(timeoutMs) || 20_000))
|
|
129
|
+
: undefined;
|
|
130
|
+
const res = await fetchImpl(GOOGLE_TOKEN_URL, {
|
|
131
|
+
method: 'POST',
|
|
132
|
+
headers: { 'Content-Type': 'application/x-www-form-urlencoded' },
|
|
133
|
+
body,
|
|
134
|
+
signal,
|
|
135
|
+
});
|
|
136
|
+
const data = await res.json().catch(() => ({}));
|
|
137
|
+
if (res.ok && data.access_token) return data;
|
|
138
|
+
|
|
139
|
+
const detail = data.error_description || data.error || `token_http_${res.status}`;
|
|
140
|
+
const needsSecret = /client_secret/i.test(String(detail));
|
|
141
|
+
|
|
142
|
+
// Stock mitigation: never put a Google client secret in the CLI. If this client_id
|
|
143
|
+
// was created as a Web app in Google Console, ask Local Studio to exchange using
|
|
144
|
+
// Worker-held secrets (GOOGLE_DESKTOP_CLIENT_SECRET or matching web secret).
|
|
145
|
+
if (needsSecret && allowStudioBroker) {
|
|
146
|
+
const origin = clean(studioOrigin)
|
|
147
|
+
|| clean(process.env.AGENTSAM_STUDIO_ORIGIN)
|
|
148
|
+
|| 'https://agentsam.inneranimalmedia.com';
|
|
149
|
+
try {
|
|
150
|
+
const brokerRes = await fetchImpl(new URL('/api/oauth/google/desktop-exchange', `${origin}/`).toString(), {
|
|
151
|
+
method: 'POST',
|
|
152
|
+
headers: { 'content-type': 'application/json', accept: 'application/json' },
|
|
153
|
+
body: JSON.stringify({
|
|
154
|
+
code,
|
|
155
|
+
code_verifier: codeVerifier,
|
|
156
|
+
redirect_uri: redirectUri,
|
|
157
|
+
client_id: clientId,
|
|
158
|
+
}),
|
|
159
|
+
signal,
|
|
160
|
+
});
|
|
161
|
+
const broker = await brokerRes.json().catch(() => ({}));
|
|
162
|
+
if (brokerRes.ok && broker.access_token) {
|
|
163
|
+
return {
|
|
164
|
+
access_token: broker.access_token,
|
|
165
|
+
refresh_token: broker.refresh_token || null,
|
|
166
|
+
token_type: broker.token_type || 'Bearer',
|
|
167
|
+
expires_in: broker.expires_in || null,
|
|
168
|
+
scope: broker.scope || null,
|
|
169
|
+
exchange_via: 'studio_broker',
|
|
170
|
+
};
|
|
171
|
+
}
|
|
172
|
+
const brokerDetail = broker.detail || broker.error || `broker_http_${brokerRes.status}`;
|
|
173
|
+
const err = new Error(
|
|
174
|
+
`google_token_exchange_failed: ${brokerDetail}. `
|
|
175
|
+
+ 'Desktop clients must be type "Desktop app" in Google Console (no secret). '
|
|
176
|
+
+ 'Or set Worker secret GOOGLE_DESKTOP_CLIENT_SECRET for a Web-typed client id. '
|
|
177
|
+
+ 'Web app login uses GOOGLE_CLIENT_ID + GOOGLE_CLIENT_SECRET on the Worker only.',
|
|
178
|
+
);
|
|
179
|
+
err.code = 'google_token_exchange_failed';
|
|
180
|
+
err.remediation = broker.remediation || null;
|
|
181
|
+
throw err;
|
|
182
|
+
} catch (brokerErr) {
|
|
183
|
+
if (brokerErr?.code === 'google_token_exchange_failed') throw brokerErr;
|
|
184
|
+
// fall through to original error
|
|
185
|
+
}
|
|
186
|
+
}
|
|
187
|
+
|
|
188
|
+
const err = new Error(
|
|
189
|
+
needsSecret
|
|
190
|
+
? `google_token_exchange_failed: ${detail}. `
|
|
191
|
+
+ 'This client_id is confidential (Web) in Google Console. '
|
|
192
|
+
+ 'Create an OAuth client type Desktop app and set GOOGLE_DESKTOP_CLIENT_ID, '
|
|
193
|
+
+ 'or put that Web client\'s secret on the Worker as GOOGLE_DESKTOP_CLIENT_SECRET.'
|
|
194
|
+
: `google_token_exchange_failed: ${detail}`,
|
|
195
|
+
);
|
|
196
|
+
err.code = 'google_token_exchange_failed';
|
|
197
|
+
throw err;
|
|
198
|
+
}
|
|
199
|
+
|
|
200
|
+
export async function fetchGoogleUserInfo(accessToken, fetchImpl = fetch, timeoutMs = 15_000) {
|
|
201
|
+
const signal = typeof AbortSignal?.timeout === 'function'
|
|
202
|
+
? AbortSignal.timeout(Math.max(1, Number(timeoutMs) || 15_000))
|
|
203
|
+
: undefined;
|
|
204
|
+
const res = await fetchImpl(GOOGLE_USERINFO_URL, {
|
|
205
|
+
headers: { Authorization: `Bearer ${accessToken}` },
|
|
206
|
+
signal,
|
|
207
|
+
});
|
|
208
|
+
if (!res.ok) return null;
|
|
209
|
+
return res.json().catch(() => null);
|
|
210
|
+
}
|
|
211
|
+
|
|
212
|
+
/**
|
|
213
|
+
* Full Desktop Google Cloud connection login.
|
|
214
|
+
* Opens system browser → loopback callback settles automatically (no second Enter).
|
|
215
|
+
*/
|
|
216
|
+
export async function runGoogleDesktopCloudLogin(options = {}) {
|
|
217
|
+
const write = options.write || ((s) => process.stdout.write(s));
|
|
218
|
+
const env = options.env || process.env;
|
|
219
|
+
const clientId = await resolveGoogleDesktopClientIdAsync(env, {
|
|
220
|
+
fetchImpl: options.fetchImpl,
|
|
221
|
+
publicConfigUrl: options.publicConfigUrl,
|
|
222
|
+
});
|
|
223
|
+
const scope = clean(options.scope) || GOOGLE_CLOUD_CONNECTION_SCOPES;
|
|
224
|
+
const state = randomState(options.randomBytesImpl);
|
|
225
|
+
const pkce = createPkcePair({ randomBytesImpl: options.randomBytesImpl });
|
|
226
|
+
|
|
227
|
+
const listener = await createLoopbackCallbackListener({
|
|
228
|
+
state,
|
|
229
|
+
host: options.host || '127.0.0.1',
|
|
230
|
+
port: options.port,
|
|
231
|
+
callbackPath: options.callbackPath || '/callback',
|
|
232
|
+
timeoutMs: options.timeoutMs || 300_000,
|
|
233
|
+
createServerImpl: options.createServerImpl,
|
|
234
|
+
});
|
|
235
|
+
|
|
236
|
+
try {
|
|
237
|
+
const authUrl = buildGoogleDesktopAuthUrl({
|
|
238
|
+
clientId,
|
|
239
|
+
redirectUri: listener.redirectUri,
|
|
240
|
+
state,
|
|
241
|
+
codeChallenge: pkce.challenge,
|
|
242
|
+
scope,
|
|
243
|
+
});
|
|
244
|
+
|
|
245
|
+
write('\n Agent Sam · Google Cloud connection\n');
|
|
246
|
+
write(' ────────────────────────────────────────────────────────\n');
|
|
247
|
+
write(' Desktop OAuth + PKCE (loopback). Browser will return here automatically.\n');
|
|
248
|
+
write(` Client ${clientId.slice(0, 28)}…\n`);
|
|
249
|
+
write(` Redirect ${listener.redirectUri}\n`);
|
|
250
|
+
write(' Scopes\n');
|
|
251
|
+
for (const s of scope.split(/\s+/).filter(Boolean)) {
|
|
252
|
+
write(` • ${s}\n`);
|
|
253
|
+
}
|
|
254
|
+
write('\n');
|
|
255
|
+
|
|
256
|
+
if (options.json) {
|
|
257
|
+
write(JSON.stringify({
|
|
258
|
+
schema_version: 'agentsam-google-desktop-oauth-v1',
|
|
259
|
+
mode: 'desktop_pkce',
|
|
260
|
+
client_id: clientId,
|
|
261
|
+
redirect_uri: listener.redirectUri,
|
|
262
|
+
authorization_url: authUrl,
|
|
263
|
+
scopes: scope.split(/\s+/).filter(Boolean),
|
|
264
|
+
}, null, 2) + '\n');
|
|
265
|
+
}
|
|
266
|
+
|
|
267
|
+
if (!options.noLaunchBrowser) {
|
|
268
|
+
const promptImpl = options.promptToOpenUrlImpl || promptToOpenUrl;
|
|
269
|
+
await promptImpl(authUrl, {
|
|
270
|
+
heading: ' Continue to Agent Sam (Google Cloud) at:',
|
|
271
|
+
prompt: 'Press ENTER to open Google in your browser. When you finish, this terminal continues automatically.',
|
|
272
|
+
input: options.input,
|
|
273
|
+
output: options.output,
|
|
274
|
+
openImpl: options.openImpl || openExternalUrl,
|
|
275
|
+
});
|
|
276
|
+
} else {
|
|
277
|
+
write(` Open this URL manually:\n ${authUrl}\n\n`);
|
|
278
|
+
write(' Waiting for loopback callback…\n');
|
|
279
|
+
}
|
|
280
|
+
|
|
281
|
+
write(' Waiting for Google callback on loopback…\n');
|
|
282
|
+
const callback = await listener.waitForCallback();
|
|
283
|
+
write(' ✓ Loopback callback received\n');
|
|
284
|
+
// Release the port before network/keychain work so the browser tab can close cleanly.
|
|
285
|
+
try { await listener.close(); } catch { /* ignore */ }
|
|
286
|
+
write(' Exchanging authorization code with Google…\n');
|
|
287
|
+
const token = await exchangeGoogleDesktopCode({
|
|
288
|
+
code: callback.code,
|
|
289
|
+
codeVerifier: pkce.verifier,
|
|
290
|
+
clientId,
|
|
291
|
+
redirectUri: listener.redirectUri,
|
|
292
|
+
fetchImpl: options.fetchImpl,
|
|
293
|
+
});
|
|
294
|
+
|
|
295
|
+
write(' Fetching Google account profile…\n');
|
|
296
|
+
const profile = await fetchGoogleUserInfo(token.access_token, options.fetchImpl);
|
|
297
|
+
const email = clean(profile?.email) || null;
|
|
298
|
+
const expiresAt = token.expires_in
|
|
299
|
+
? new Date(Date.now() + Number(token.expires_in) * 1000).toISOString()
|
|
300
|
+
: null;
|
|
301
|
+
|
|
302
|
+
const credentialPayload = JSON.stringify({
|
|
303
|
+
schema_version: 'agentsam-google-oauth-token-v1',
|
|
304
|
+
access_token: token.access_token,
|
|
305
|
+
refresh_token: token.refresh_token || null,
|
|
306
|
+
token_type: token.token_type || 'Bearer',
|
|
307
|
+
scope: token.scope || scope,
|
|
308
|
+
expires_at: expiresAt,
|
|
309
|
+
email,
|
|
310
|
+
client_id: clientId,
|
|
311
|
+
});
|
|
312
|
+
|
|
313
|
+
if (options.storeCredential !== false) {
|
|
314
|
+
write(' Storing credential (keychain / local vault)…\n');
|
|
315
|
+
setSecureProviderKey('google-cloud', {
|
|
316
|
+
value: credentialPayload,
|
|
317
|
+
accountId: email,
|
|
318
|
+
}, { home: options.home, env, disableOsStore: options.disableOsStore });
|
|
319
|
+
}
|
|
320
|
+
|
|
321
|
+
if (email && options.writeConnection !== false) {
|
|
322
|
+
writeGoogleCloudConnection(
|
|
323
|
+
{ identity: email },
|
|
324
|
+
{ home: options.home, env },
|
|
325
|
+
);
|
|
326
|
+
}
|
|
327
|
+
|
|
328
|
+
write('\n ✓ Google Cloud connection authorized\n');
|
|
329
|
+
if (email) write(` Identity ${email}\n`);
|
|
330
|
+
write(' Stored OS keychain / local vault (google-cloud)\n');
|
|
331
|
+
write(' Next\n');
|
|
332
|
+
write(' agentsam google-cloud connection set --project PROJECT_ID\n');
|
|
333
|
+
write(' agentsam google-cloud doctor\n');
|
|
334
|
+
write('\n');
|
|
335
|
+
|
|
336
|
+
return {
|
|
337
|
+
ok: true,
|
|
338
|
+
email,
|
|
339
|
+
scopes: (token.scope || scope).split(/\s+/).filter(Boolean),
|
|
340
|
+
expires_at: expiresAt,
|
|
341
|
+
has_refresh_token: Boolean(token.refresh_token),
|
|
342
|
+
};
|
|
343
|
+
} finally {
|
|
344
|
+
try { await listener.close(); } catch { /* already closed */ }
|
|
345
|
+
}
|
|
346
|
+
}
|
|
347
|
+
|
|
348
|
+
/**
|
|
349
|
+
* Console / IAM checklist for Google Cloud + MCP (not OAuth scopes).
|
|
350
|
+
*/
|
|
351
|
+
export function googleCloudPermissionChecklist() {
|
|
352
|
+
return {
|
|
353
|
+
oauth_scopes_requested: GOOGLE_CLOUD_CONNECTION_SCOPES.split(/\s+/),
|
|
354
|
+
oauth_consent_screen: [
|
|
355
|
+
'Google Auth Platform → Data Access: add cloud-platform (and openid/email/profile)',
|
|
356
|
+
'Branding → App name: AgentSam Local Studio (name shows only after brand verification)',
|
|
357
|
+
'Until verified, Google shows the authorized domain (often inneranimalmedia.com)',
|
|
358
|
+
'Audience: Testing → add your Google accounts as test users',
|
|
359
|
+
],
|
|
360
|
+
project_iam_roles: [
|
|
361
|
+
'roles/viewer or stronger for read discovery',
|
|
362
|
+
'roles/editor or roles/owner for provision/mutate',
|
|
363
|
+
'roles/mcp.toolUser for Google/Google Cloud remote MCP (mcp.tools.call)',
|
|
364
|
+
'Plus product roles (e.g. run.developer, bigquery.jobUser) for specific MCP servers',
|
|
365
|
+
],
|
|
366
|
+
notes: [
|
|
367
|
+
'OAuth scopes authorize the app to call APIs as you.',
|
|
368
|
+
'IAM roles on the GCP project authorize what that principal can actually do.',
|
|
369
|
+
'Both are required for Cloud operations.',
|
|
370
|
+
],
|
|
371
|
+
};
|
|
372
|
+
}
|
|
@@ -0,0 +1,158 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Stock CLI Google Cloud login via Local Studio Web client (secret stays on Worker).
|
|
3
|
+
* Browser: Studio /api/oauth/google/cli-cloud/* → loopback pickup → CLI stores tokens.
|
|
4
|
+
*/
|
|
5
|
+
import { randomBytes } from 'node:crypto';
|
|
6
|
+
import {
|
|
7
|
+
createLoopbackCallbackListener,
|
|
8
|
+
} from './auth.js';
|
|
9
|
+
import { promptToOpenUrl, openExternalUrl } from './open-url.js';
|
|
10
|
+
import { setSecureProviderKey } from '../security/local-vault.js';
|
|
11
|
+
import { writeGoogleCloudConnection } from './google-cloud-connection.js';
|
|
12
|
+
import { GOOGLE_CLOUD_CONNECTION_SCOPES } from './google-desktop-oauth.js';
|
|
13
|
+
|
|
14
|
+
function clean(value) {
|
|
15
|
+
return value == null ? '' : String(value).trim();
|
|
16
|
+
}
|
|
17
|
+
|
|
18
|
+
function base64url(value) {
|
|
19
|
+
return Buffer.from(value)
|
|
20
|
+
.toString('base64')
|
|
21
|
+
.replace(/=/g, '')
|
|
22
|
+
.replace(/\+/g, '-')
|
|
23
|
+
.replace(/\//g, '_');
|
|
24
|
+
}
|
|
25
|
+
|
|
26
|
+
function randomState(randomBytesImpl = randomBytes) {
|
|
27
|
+
return base64url(randomBytesImpl(24));
|
|
28
|
+
}
|
|
29
|
+
|
|
30
|
+
/**
|
|
31
|
+
* Stock CLI Google Cloud login via Local Studio Web client (secret stays on Worker).
|
|
32
|
+
* Browser: Studio /api/oauth/google/cli-cloud/* → loopback pickup → CLI stores tokens.
|
|
33
|
+
*/
|
|
34
|
+
export async function runGoogleStudioBrokeredCloudLogin(options = {}) {
|
|
35
|
+
const write = options.write || ((s) => process.stdout.write(s));
|
|
36
|
+
const env = options.env || process.env;
|
|
37
|
+
const fetchImpl = options.fetchImpl || fetch;
|
|
38
|
+
const studioOrigin = clean(options.studioOrigin)
|
|
39
|
+
|| clean(env.AGENTSAM_STUDIO_ORIGIN)
|
|
40
|
+
|| 'https://agentsam.inneranimalmedia.com';
|
|
41
|
+
const state = randomState(options.randomBytesImpl);
|
|
42
|
+
|
|
43
|
+
const listener = await createLoopbackCallbackListener({
|
|
44
|
+
state,
|
|
45
|
+
host: options.host || '127.0.0.1',
|
|
46
|
+
port: options.port,
|
|
47
|
+
callbackPath: options.callbackPath || '/callback',
|
|
48
|
+
timeoutMs: options.timeoutMs || 300_000,
|
|
49
|
+
createServerImpl: options.createServerImpl,
|
|
50
|
+
});
|
|
51
|
+
|
|
52
|
+
try {
|
|
53
|
+
const startUrl = new URL('/api/oauth/google/cli-cloud/start', `${studioOrigin}/`);
|
|
54
|
+
startUrl.searchParams.set('loopback', listener.redirectUri);
|
|
55
|
+
startUrl.searchParams.set('state', state);
|
|
56
|
+
|
|
57
|
+
write('\n Agent Sam · Google Cloud connection\n');
|
|
58
|
+
write(' ────────────────────────────────────────────────────────\n');
|
|
59
|
+
write(' Studio Web OAuth broker (GOOGLE_CLIENT_ID + Worker secret).\n');
|
|
60
|
+
write(' Desktop PKCE is optional via: agentsam gcloud auth login --desktop\n');
|
|
61
|
+
write(` Studio ${studioOrigin}\n`);
|
|
62
|
+
write(` Loopback ${listener.redirectUri}\n`);
|
|
63
|
+
write(' Scopes\n');
|
|
64
|
+
for (const s of GOOGLE_CLOUD_CONNECTION_SCOPES.split(/\s+/).filter(Boolean)) {
|
|
65
|
+
write(` • ${s}\n`);
|
|
66
|
+
}
|
|
67
|
+
write('\n');
|
|
68
|
+
|
|
69
|
+
if (!options.noLaunchBrowser) {
|
|
70
|
+
const promptImpl = options.promptToOpenUrlImpl || promptToOpenUrl;
|
|
71
|
+
await promptImpl(startUrl.toString(), {
|
|
72
|
+
heading: ' Continue to Agent Sam (Google Cloud) at:',
|
|
73
|
+
prompt: 'Press ENTER to open Google via Local Studio. When you finish, this terminal continues automatically.',
|
|
74
|
+
input: options.input,
|
|
75
|
+
output: options.output,
|
|
76
|
+
openImpl: options.openImpl || openExternalUrl,
|
|
77
|
+
});
|
|
78
|
+
} else {
|
|
79
|
+
write(` Open this URL manually:\n ${startUrl}\n\n`);
|
|
80
|
+
}
|
|
81
|
+
|
|
82
|
+
write(' Waiting for Studio → loopback handoff…\n');
|
|
83
|
+
const callback = await listener.waitForCallback();
|
|
84
|
+
write(' ✓ Loopback handoff received\n');
|
|
85
|
+
try { await listener.close(); } catch { /* ignore */ }
|
|
86
|
+
|
|
87
|
+
if (!callback?.pickup) {
|
|
88
|
+
throw Object.assign(new Error('studio_pickup_missing'), { code: 'studio_pickup_missing' });
|
|
89
|
+
}
|
|
90
|
+
|
|
91
|
+
write(' Collecting tokens from Studio…\n');
|
|
92
|
+
const pickupRes = await fetchImpl(new URL('/api/oauth/google/cli-cloud/pickup', `${studioOrigin}/`).toString(), {
|
|
93
|
+
method: 'POST',
|
|
94
|
+
headers: { 'content-type': 'application/json', accept: 'application/json' },
|
|
95
|
+
body: JSON.stringify({ pickup: callback.pickup, state }),
|
|
96
|
+
signal: typeof AbortSignal?.timeout === 'function' ? AbortSignal.timeout(20_000) : undefined,
|
|
97
|
+
});
|
|
98
|
+
const pickup = await pickupRes.json().catch(() => ({}));
|
|
99
|
+
if (!pickupRes.ok || !pickup.access_token) {
|
|
100
|
+
throw Object.assign(
|
|
101
|
+
new Error(`studio_pickup_failed: ${pickup.error || pickupRes.status}`),
|
|
102
|
+
{ code: 'studio_pickup_failed' },
|
|
103
|
+
);
|
|
104
|
+
}
|
|
105
|
+
|
|
106
|
+
const email = clean(pickup.email) || null;
|
|
107
|
+
const expiresAt = pickup.expires_at
|
|
108
|
+
? new Date(Number(pickup.expires_at) * 1000).toISOString()
|
|
109
|
+
: null;
|
|
110
|
+
|
|
111
|
+
const credentialPayload = JSON.stringify({
|
|
112
|
+
schema_version: 'agentsam-google-oauth-token-v1',
|
|
113
|
+
access_token: pickup.access_token,
|
|
114
|
+
refresh_token: pickup.refresh_token || null,
|
|
115
|
+
token_type: pickup.token_type || 'Bearer',
|
|
116
|
+
scope: pickup.scope || GOOGLE_CLOUD_CONNECTION_SCOPES,
|
|
117
|
+
expires_at: expiresAt,
|
|
118
|
+
email,
|
|
119
|
+
client_id: clean(env.GOOGLE_CLIENT_ID) || 'studio_web_broker',
|
|
120
|
+
exchange_via: 'studio_web_broker',
|
|
121
|
+
});
|
|
122
|
+
|
|
123
|
+
if (options.storeCredential !== false) {
|
|
124
|
+
write(' Storing credential (keychain / local vault)…\n');
|
|
125
|
+
setSecureProviderKey('google-cloud', {
|
|
126
|
+
value: credentialPayload,
|
|
127
|
+
accountId: email,
|
|
128
|
+
}, { home: options.home, env, disableOsStore: options.disableOsStore });
|
|
129
|
+
}
|
|
130
|
+
|
|
131
|
+
if (email && options.writeConnection !== false) {
|
|
132
|
+
writeGoogleCloudConnection(
|
|
133
|
+
{ identity: email },
|
|
134
|
+
{ home: options.home, env },
|
|
135
|
+
);
|
|
136
|
+
}
|
|
137
|
+
|
|
138
|
+
write('\n ✓ Google Cloud connection authorized\n');
|
|
139
|
+
if (email) write(` Identity ${email}\n`);
|
|
140
|
+
write(' Stored OS keychain / local vault (google-cloud)\n');
|
|
141
|
+
write(' Via Local Studio Web OAuth broker\n');
|
|
142
|
+
write(' Next\n');
|
|
143
|
+
write(' agentsam google-cloud connection set --project PROJECT_ID\n');
|
|
144
|
+
write(' agentsam google-cloud doctor\n');
|
|
145
|
+
write('\n');
|
|
146
|
+
|
|
147
|
+
return {
|
|
148
|
+
ok: true,
|
|
149
|
+
email,
|
|
150
|
+
scopes: String(pickup.scope || GOOGLE_CLOUD_CONNECTION_SCOPES).split(/\s+/).filter(Boolean),
|
|
151
|
+
expires_at: expiresAt,
|
|
152
|
+
has_refresh_token: Boolean(pickup.refresh_token),
|
|
153
|
+
exchange_via: 'studio_web_broker',
|
|
154
|
+
};
|
|
155
|
+
} finally {
|
|
156
|
+
try { await listener.close(); } catch { /* already closed */ }
|
|
157
|
+
}
|
|
158
|
+
}
|
|
@@ -17,7 +17,7 @@ export function buildIdentityAppScaffold(config) {
|
|
|
17
17
|
const brandName = config.brandName || projectName;
|
|
18
18
|
const logoUrl = config.logoUrl || '/brand/logo.svg';
|
|
19
19
|
const sdkVersion = config.sdkVersion || 'alpha';
|
|
20
|
-
const provider = config.provider || '
|
|
20
|
+
const provider = config.provider || 'email';
|
|
21
21
|
|
|
22
22
|
const migrationSql = `${fs.readFileSync(MIGRATION_FILE, 'utf8')}\n${buildCompanySeedSql({ brandName, logoUrl })}\n`;
|
|
23
23
|
const loginHtml = injectBrandingScript(applyBrandTokens(fs.readFileSync(path.join(AUTH_PAGES_DIR, 'login.html'), 'utf8'), {
|
|
@@ -78,11 +78,20 @@ migrations_dir = "migrations"
|
|
|
78
78
|
# IAM_CLIENT_SECRET= # wrangler secret put only
|
|
79
79
|
# IAM_ORIGIN=https://inneranimalmedia.com
|
|
80
80
|
|
|
81
|
-
#
|
|
81
|
+
# Web browser OAuth (BYOK) — takes /api/oauth/{google|github}/start when set
|
|
82
82
|
# GOOGLE_CLIENT_ID=
|
|
83
83
|
# GOOGLE_CLIENT_SECRET=
|
|
84
84
|
# GITHUB_CLIENT_ID=
|
|
85
85
|
# GITHUB_CLIENT_SECRET=
|
|
86
|
+
|
|
87
|
+
# Google Desktop / CLI PKCE — Console type "Desktop app" (no secret required)
|
|
88
|
+
# GOOGLE_DESKTOP_CLIENT_ID=
|
|
89
|
+
# GOOGLE_DESKTOP_CLIENT_SECRET= # optional; only if client was mis-typed as Web
|
|
90
|
+
# Broker: POST /api/oauth/google/desktop-exchange (loopback redirect only)
|
|
91
|
+
|
|
92
|
+
# Cloudflare sign-in — same secrets as the CF resource connector
|
|
93
|
+
# CLOUDFLARE_OAUTH_CLIENT_ID=
|
|
94
|
+
# CLOUDFLARE_OAUTH_CLIENT_SECRET= # optional for PKCE-only clients
|
|
86
95
|
`;
|
|
87
96
|
|
|
88
97
|
files['.gitignore'] = `node_modules/
|
|
@@ -98,6 +107,8 @@ Boring scaffold: **app/frontend** (auth UI) + **backend** (Worker API) + **migra
|
|
|
98
107
|
|
|
99
108
|
Provider template: \`${provider}\` (see \`agentsam identity plan --provider ${provider}\`).
|
|
100
109
|
|
|
110
|
+
**Account SSOT:** \`accounts\` (row of record). \`account_identities\` is IdP linkage only.
|
|
111
|
+
|
|
101
112
|
## Quick start
|
|
102
113
|
|
|
103
114
|
\`\`\`bash
|
|
@@ -109,7 +120,15 @@ npm run dev
|
|
|
109
120
|
# open http://localhost:8787/auth/login
|
|
110
121
|
\`\`\`
|
|
111
122
|
|
|
112
|
-
OAuth
|
|
123
|
+
### OAuth options (pick what you need)
|
|
124
|
+
|
|
125
|
+
| Lane | Env | Routes |
|
|
126
|
+
|------|-----|--------|
|
|
127
|
+
| IAM platform (default) | \`IAM_CLIENT_ID\` + \`IAM_CLIENT_SECRET\` | \`/api/oauth/inneranimalmedia/*\` |
|
|
128
|
+
| Google web | \`GOOGLE_CLIENT_ID\` + \`GOOGLE_CLIENT_SECRET\` | \`/api/oauth/google/start\` |
|
|
129
|
+
| Google desktop/CLI | \`GOOGLE_DESKTOP_CLIENT_ID\` | \`POST /api/oauth/google/desktop-exchange\` |
|
|
130
|
+
| GitHub | \`GITHUB_CLIENT_*\` | \`/api/oauth/github/start\` |
|
|
131
|
+
| Cloudflare | \`CLOUDFLARE_OAUTH_CLIENT_ID\` (+ optional secret) | \`/api/oauth/cloudflare/start\` |
|
|
113
132
|
|
|
114
133
|
## Layout
|
|
115
134
|
|
|
@@ -185,9 +204,8 @@ export default {
|
|
|
185
204
|
function applyBrandTokens(html, { brandName, logoUrl }) {
|
|
186
205
|
return html
|
|
187
206
|
.replace(/Inner Animal Media/g, brandName)
|
|
188
|
-
.replace(/
|
|
189
|
-
.replace(/
|
|
190
|
-
.replace(/Reset password \| Inner Animal Media/g, `Reset password | ${brandName}`)
|
|
207
|
+
.replace(/AgentSam/g, brandName)
|
|
208
|
+
.replace(/src="\/shared\/agentsam-mark\.svg"/g, `src="${logoUrl}"`)
|
|
191
209
|
.replace(/src="\/brand\/[^"]*"/g, `src="${logoUrl}"`)
|
|
192
210
|
.replace(/href="\/brand\/[^"]*"/g, `href="${logoUrl}"`);
|
|
193
211
|
}
|