@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,270 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Persisted Google Cloud connection preference (not ambient gcloud active account).
|
|
3
|
+
* Secrets never stored here — identity/project references only.
|
|
4
|
+
*/
|
|
5
|
+
import fs from 'node:fs';
|
|
6
|
+
import os from 'node:os';
|
|
7
|
+
import path from 'node:path';
|
|
8
|
+
|
|
9
|
+
const SCHEMA = 'agentsam-google-cloud-connection-v1';
|
|
10
|
+
|
|
11
|
+
function clean(value) {
|
|
12
|
+
return value == null ? '' : String(value).trim();
|
|
13
|
+
}
|
|
14
|
+
|
|
15
|
+
function homeDirectory(options = {}) {
|
|
16
|
+
return path.resolve(
|
|
17
|
+
clean(options.home) || clean(options.env?.HOME) || clean(options.env?.USERPROFILE) || os.homedir(),
|
|
18
|
+
);
|
|
19
|
+
}
|
|
20
|
+
|
|
21
|
+
export function googleCloudConnectionPath(options = {}) {
|
|
22
|
+
return path.join(homeDirectory(options), '.agentsam', 'connections', 'google-cloud.json');
|
|
23
|
+
}
|
|
24
|
+
|
|
25
|
+
export function readGoogleCloudConnection(options = {}) {
|
|
26
|
+
const file = googleCloudConnectionPath(options);
|
|
27
|
+
try {
|
|
28
|
+
if (!fs.existsSync(file)) return null;
|
|
29
|
+
const raw = JSON.parse(fs.readFileSync(file, 'utf8'));
|
|
30
|
+
if (!raw || typeof raw !== 'object') return null;
|
|
31
|
+
return {
|
|
32
|
+
schema_version: SCHEMA,
|
|
33
|
+
identity: clean(raw.identity) || null,
|
|
34
|
+
organization: clean(raw.organization) || null,
|
|
35
|
+
project: clean(raw.project) || null,
|
|
36
|
+
billing_account: clean(raw.billing_account) || null,
|
|
37
|
+
always_use_for_projects:
|
|
38
|
+
raw.always_use_for_projects && typeof raw.always_use_for_projects === 'object'
|
|
39
|
+
? { ...raw.always_use_for_projects }
|
|
40
|
+
: {},
|
|
41
|
+
updated_at: clean(raw.updated_at) || null,
|
|
42
|
+
};
|
|
43
|
+
} catch {
|
|
44
|
+
return null;
|
|
45
|
+
}
|
|
46
|
+
}
|
|
47
|
+
|
|
48
|
+
export function writeGoogleCloudConnection(input = {}, options = {}) {
|
|
49
|
+
const file = googleCloudConnectionPath(options);
|
|
50
|
+
fs.mkdirSync(path.dirname(file), { recursive: true, mode: 0o700 });
|
|
51
|
+
const prev = readGoogleCloudConnection(options) || {};
|
|
52
|
+
const next = {
|
|
53
|
+
schema_version: SCHEMA,
|
|
54
|
+
identity: clean(input.identity) || prev.identity || null,
|
|
55
|
+
organization: clean(input.organization) || prev.organization || null,
|
|
56
|
+
project: clean(input.project) || prev.project || null,
|
|
57
|
+
billing_account: clean(input.billing_account) || prev.billing_account || null,
|
|
58
|
+
always_use_for_projects: {
|
|
59
|
+
...(prev.always_use_for_projects || {}),
|
|
60
|
+
...(input.always_use_for_projects || {}),
|
|
61
|
+
},
|
|
62
|
+
updated_at: new Date().toISOString(),
|
|
63
|
+
};
|
|
64
|
+
fs.writeFileSync(file, `${JSON.stringify(next, null, 2)}\n`, { mode: 0o600 });
|
|
65
|
+
return next;
|
|
66
|
+
}
|
|
67
|
+
|
|
68
|
+
/**
|
|
69
|
+
* Compare preferred connection vs ambient gcloud active account/project.
|
|
70
|
+
*/
|
|
71
|
+
export function diagnoseGoogleCloudAccountMismatch({
|
|
72
|
+
preferred = null,
|
|
73
|
+
activeAccount = null,
|
|
74
|
+
activeProject = null,
|
|
75
|
+
accounts = [],
|
|
76
|
+
} = {}) {
|
|
77
|
+
const preferredIdentity = clean(preferred?.identity);
|
|
78
|
+
const preferredProject = clean(preferred?.project);
|
|
79
|
+
const active = clean(activeAccount);
|
|
80
|
+
const project = clean(activeProject);
|
|
81
|
+
|
|
82
|
+
if (!preferredIdentity) {
|
|
83
|
+
return {
|
|
84
|
+
ok: true,
|
|
85
|
+
kind: 'no_preference',
|
|
86
|
+
message: 'No AgentSam Google Cloud connection preference stored yet.',
|
|
87
|
+
hint: 'agentsam google-cloud connection set --identity you@example.com --project PROJECT_ID',
|
|
88
|
+
};
|
|
89
|
+
}
|
|
90
|
+
|
|
91
|
+
if (active && preferredIdentity && active.toLowerCase() !== preferredIdentity.toLowerCase()) {
|
|
92
|
+
const alt = (accounts || []).find(
|
|
93
|
+
(row) => clean(row.account).toLowerCase() === preferredIdentity.toLowerCase(),
|
|
94
|
+
);
|
|
95
|
+
return {
|
|
96
|
+
ok: false,
|
|
97
|
+
kind: 'identity_mismatch',
|
|
98
|
+
message: 'Ambient gcloud active account is not the AgentSam connection identity.',
|
|
99
|
+
current_account: active,
|
|
100
|
+
required_identity: preferredIdentity,
|
|
101
|
+
required_project: preferredProject || null,
|
|
102
|
+
alternate_authenticated: Boolean(alt),
|
|
103
|
+
remediation: {
|
|
104
|
+
title: 'This Google account does not match the saved connection.',
|
|
105
|
+
actions: [
|
|
106
|
+
{
|
|
107
|
+
id: 'retry',
|
|
108
|
+
title: `Retry with ${preferredIdentity}`,
|
|
109
|
+
command: `gcloud config set account ${preferredIdentity}`,
|
|
110
|
+
recommended: true,
|
|
111
|
+
},
|
|
112
|
+
{
|
|
113
|
+
id: 'always',
|
|
114
|
+
title: 'Always use preferred identity for this project',
|
|
115
|
+
command: `agentsam google-cloud connection set --identity ${preferredIdentity}${preferredProject ? ` --project ${preferredProject}` : ''}`,
|
|
116
|
+
},
|
|
117
|
+
{
|
|
118
|
+
id: 'login',
|
|
119
|
+
title: 'Login preferred identity',
|
|
120
|
+
command: 'agentsam gcloud auth login',
|
|
121
|
+
},
|
|
122
|
+
],
|
|
123
|
+
},
|
|
124
|
+
};
|
|
125
|
+
}
|
|
126
|
+
|
|
127
|
+
if (preferredProject && project && preferredProject !== project) {
|
|
128
|
+
return {
|
|
129
|
+
ok: false,
|
|
130
|
+
kind: 'project_mismatch',
|
|
131
|
+
message: 'Ambient gcloud project differs from the AgentSam connection project.',
|
|
132
|
+
current_project: project,
|
|
133
|
+
required_project: preferredProject,
|
|
134
|
+
remediation: {
|
|
135
|
+
title: 'Switch to the connection project (or pass --project explicitly).',
|
|
136
|
+
actions: [
|
|
137
|
+
{
|
|
138
|
+
id: 'set_project',
|
|
139
|
+
title: `Use project ${preferredProject}`,
|
|
140
|
+
command: `gcloud config set project ${preferredProject}`,
|
|
141
|
+
recommended: true,
|
|
142
|
+
},
|
|
143
|
+
],
|
|
144
|
+
},
|
|
145
|
+
};
|
|
146
|
+
}
|
|
147
|
+
|
|
148
|
+
return {
|
|
149
|
+
ok: true,
|
|
150
|
+
kind: 'aligned',
|
|
151
|
+
message: 'Ambient gcloud account/project aligns with AgentSam connection preference.',
|
|
152
|
+
identity: preferredIdentity,
|
|
153
|
+
project: preferredProject || project || null,
|
|
154
|
+
};
|
|
155
|
+
}
|
|
156
|
+
|
|
157
|
+
/**
|
|
158
|
+
* Deterministic insufficient-access card when ambient account lacks a required role
|
|
159
|
+
* but another authenticated account has it (e.g. Owner).
|
|
160
|
+
*/
|
|
161
|
+
export function diagnoseInsufficientAccess({
|
|
162
|
+
currentAccount = null,
|
|
163
|
+
requiredRole = 'roles/owner',
|
|
164
|
+
accounts = [],
|
|
165
|
+
project = null,
|
|
166
|
+
} = {}) {
|
|
167
|
+
const current = clean(currentAccount);
|
|
168
|
+
const need = clean(requiredRole) || 'roles/owner';
|
|
169
|
+
const rows = Array.isArray(accounts) ? accounts : [];
|
|
170
|
+
const capable = rows.filter((row) => {
|
|
171
|
+
const roles = Array.isArray(row.roles) ? row.roles : [];
|
|
172
|
+
return roles.some((r) => String(r).toLowerCase() === need.toLowerCase());
|
|
173
|
+
});
|
|
174
|
+
if (!capable.length) {
|
|
175
|
+
return {
|
|
176
|
+
ok: false,
|
|
177
|
+
kind: 'insufficient_access_no_alternate',
|
|
178
|
+
message: 'No authenticated Google account has the required role.',
|
|
179
|
+
current_account: current || null,
|
|
180
|
+
required_role: need,
|
|
181
|
+
project: clean(project) || null,
|
|
182
|
+
};
|
|
183
|
+
}
|
|
184
|
+
|
|
185
|
+
const preferred = capable[0];
|
|
186
|
+
const email = clean(preferred.account || preferred.email);
|
|
187
|
+
const roleLabel = need.replace(/^roles\//, '');
|
|
188
|
+
return {
|
|
189
|
+
ok: false,
|
|
190
|
+
kind: 'insufficient_access',
|
|
191
|
+
message: 'This Google account does not have enough access.',
|
|
192
|
+
current_account: current || null,
|
|
193
|
+
required_role: need,
|
|
194
|
+
project: clean(project) || null,
|
|
195
|
+
alternate: {
|
|
196
|
+
identity: email,
|
|
197
|
+
roles: preferred.roles || [need],
|
|
198
|
+
role_label: roleLabel,
|
|
199
|
+
},
|
|
200
|
+
remediation: {
|
|
201
|
+
title: 'This Google account does not have enough access.',
|
|
202
|
+
body: [
|
|
203
|
+
'A locally authenticated Google account does:',
|
|
204
|
+
'',
|
|
205
|
+
` ${email}`,
|
|
206
|
+
` ✓ ${roleLabel.charAt(0).toUpperCase()}${roleLabel.slice(1)}`,
|
|
207
|
+
],
|
|
208
|
+
actions: [
|
|
209
|
+
{
|
|
210
|
+
id: 'retry',
|
|
211
|
+
title: `Retry with ${email}`,
|
|
212
|
+
command: `gcloud config set account ${email}`,
|
|
213
|
+
recommended: true,
|
|
214
|
+
},
|
|
215
|
+
{
|
|
216
|
+
id: 'always',
|
|
217
|
+
title: 'Always use for this project',
|
|
218
|
+
command: project
|
|
219
|
+
? `agentsam google-cloud connection set --identity ${email} --project ${project}`
|
|
220
|
+
: `agentsam google-cloud connection set --identity ${email}`,
|
|
221
|
+
},
|
|
222
|
+
{ id: 'cancel', title: 'Cancel' },
|
|
223
|
+
],
|
|
224
|
+
},
|
|
225
|
+
};
|
|
226
|
+
}
|
|
227
|
+
|
|
228
|
+
export function renderInsufficientAccessCard(diagnosis) {
|
|
229
|
+
if (!diagnosis || diagnosis.ok) return '';
|
|
230
|
+
const rem = diagnosis.remediation;
|
|
231
|
+
if (!rem) return ` ✕ ${diagnosis.message}\n`;
|
|
232
|
+
const lines = ['', ` ${rem.title}`, ''];
|
|
233
|
+
for (const line of rem.body || []) lines.push(` ${line}`);
|
|
234
|
+
lines.push('');
|
|
235
|
+
for (const action of rem.actions || []) {
|
|
236
|
+
const key =
|
|
237
|
+
action.id === 'retry' ? '[enter]' : action.id === 'always' ? '[a] ' : action.id === 'cancel' ? '[c] ' : `[${action.id}]`;
|
|
238
|
+
lines.push(` ${key} ${action.title}`);
|
|
239
|
+
}
|
|
240
|
+
lines.push('');
|
|
241
|
+
return lines.join('\n');
|
|
242
|
+
}
|
|
243
|
+
|
|
244
|
+
export function renderGoogleCloudConnection(connection) {
|
|
245
|
+
if (!connection) {
|
|
246
|
+
return [
|
|
247
|
+
'',
|
|
248
|
+
' Agent Sam · Google Cloud connection',
|
|
249
|
+
'',
|
|
250
|
+
' (none stored)',
|
|
251
|
+
'',
|
|
252
|
+
' Set with:',
|
|
253
|
+
' agentsam google-cloud connection set --identity you@example.com --project PROJECT_ID',
|
|
254
|
+
'',
|
|
255
|
+
].join('\n');
|
|
256
|
+
}
|
|
257
|
+
return [
|
|
258
|
+
'',
|
|
259
|
+
' Agent Sam · Google Cloud connection',
|
|
260
|
+
'',
|
|
261
|
+
` identity ${connection.identity || '—'}`,
|
|
262
|
+
` organization ${connection.organization || '—'}`,
|
|
263
|
+
` project ${connection.project || '—'}`,
|
|
264
|
+
` billing ${connection.billing_account || '—'}`,
|
|
265
|
+
` updated ${connection.updated_at || '—'}`,
|
|
266
|
+
'',
|
|
267
|
+
' Operations should use this preference explicitly — not ambient gcloud active account.',
|
|
268
|
+
'',
|
|
269
|
+
].join('\n');
|
|
270
|
+
}
|
|
@@ -0,0 +1,385 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Read-only Google Cloud inventory for AgentSam Connections / CLI.
|
|
3
|
+
* Never prints private key material or access tokens.
|
|
4
|
+
*/
|
|
5
|
+
import { execFile } from 'node:child_process';
|
|
6
|
+
import { promisify } from 'node:util';
|
|
7
|
+
import {
|
|
8
|
+
diagnoseGoogleCloudAccountMismatch,
|
|
9
|
+
readGoogleCloudConnection,
|
|
10
|
+
} from './google-cloud-connection.js';
|
|
11
|
+
|
|
12
|
+
const execFileAsync = promisify(execFile);
|
|
13
|
+
|
|
14
|
+
function clean(value) {
|
|
15
|
+
return value == null ? '' : String(value).trim();
|
|
16
|
+
}
|
|
17
|
+
|
|
18
|
+
export async function runGcloudJson(args, env = process.env, timeoutMs = 45000) {
|
|
19
|
+
try {
|
|
20
|
+
const { stdout, stderr } = await execFileAsync('gcloud', args, {
|
|
21
|
+
timeout: timeoutMs,
|
|
22
|
+
env,
|
|
23
|
+
maxBuffer: 8 * 1024 * 1024,
|
|
24
|
+
});
|
|
25
|
+
const text = String(stdout || '').trim();
|
|
26
|
+
return {
|
|
27
|
+
ok: true,
|
|
28
|
+
code: 0,
|
|
29
|
+
data: text ? JSON.parse(text) : null,
|
|
30
|
+
stderr: String(stderr || '').trim(),
|
|
31
|
+
};
|
|
32
|
+
} catch (error) {
|
|
33
|
+
const stdout = String(error?.stdout || '').trim();
|
|
34
|
+
let data = null;
|
|
35
|
+
if (stdout) {
|
|
36
|
+
try {
|
|
37
|
+
data = JSON.parse(stdout);
|
|
38
|
+
} catch {
|
|
39
|
+
data = null;
|
|
40
|
+
}
|
|
41
|
+
}
|
|
42
|
+
return {
|
|
43
|
+
ok: false,
|
|
44
|
+
code: Number(error?.code) || 1,
|
|
45
|
+
data,
|
|
46
|
+
stderr: String(error?.stderr || error?.message || '').trim(),
|
|
47
|
+
stdout,
|
|
48
|
+
};
|
|
49
|
+
}
|
|
50
|
+
}
|
|
51
|
+
|
|
52
|
+
export async function resolveActiveProject(env = process.env, explicit = '') {
|
|
53
|
+
if (clean(explicit)) return clean(explicit);
|
|
54
|
+
const result = await runGcloudJson(['config', 'get-value', 'project', '--format=json'], env, 10000);
|
|
55
|
+
if (result.ok && result.data && result.data !== '(unset)') return String(result.data);
|
|
56
|
+
return '';
|
|
57
|
+
}
|
|
58
|
+
|
|
59
|
+
function shortName(email) {
|
|
60
|
+
const local = String(email || '').split('@')[0] || '';
|
|
61
|
+
return local;
|
|
62
|
+
}
|
|
63
|
+
|
|
64
|
+
function classifySa(email, displayName = '') {
|
|
65
|
+
const id = `${email} ${displayName}`.toLowerCase();
|
|
66
|
+
if (/agentsam-env-controller|agentsam-env-builder|agent-sam-vertex/.test(id)) return 'agentsam';
|
|
67
|
+
if (/compute@developer\.gserviceaccount\.com/.test(email)) return 'compute_default';
|
|
68
|
+
if (/firebase|vertex-express/.test(id)) return 'provider_service';
|
|
69
|
+
if (/ais-gemini-key|meauxide|agentsamremix|remix/.test(id)) return 'historical';
|
|
70
|
+
if (/billing-reader/.test(id)) return 'billing';
|
|
71
|
+
return 'other';
|
|
72
|
+
}
|
|
73
|
+
|
|
74
|
+
function dispositionHint(bucket, roles, keys, attached) {
|
|
75
|
+
const userKeys = (keys || []).filter((k) => String(k.key_type || k.keyType).toUpperCase() === 'USER_MANAGED');
|
|
76
|
+
if (bucket === 'agentsam') {
|
|
77
|
+
if (userKeys.length) return 'KEEP · HOLD USER_MANAGED until local JSON provenance mapped';
|
|
78
|
+
return 'KEEP';
|
|
79
|
+
}
|
|
80
|
+
if (bucket === 'compute_default' && attached.length) return 'KEEP · active VM attachment';
|
|
81
|
+
if (bucket === 'provider_service') return 'KEEP · inspect if product still uses provider';
|
|
82
|
+
if (bucket === 'billing') {
|
|
83
|
+
if (userKeys.length) return 'KEEP · migrate/ROTATE USER key after provenance (BQ billing export)';
|
|
84
|
+
return 'KEEP if billing export used';
|
|
85
|
+
}
|
|
86
|
+
if (bucket === 'historical') {
|
|
87
|
+
if (!(roles || []).length) return 'INSPECT → likely DELETE if unused';
|
|
88
|
+
return 'PROVENANCE · DETACH/DELETE after confirm unused';
|
|
89
|
+
}
|
|
90
|
+
if (!(roles || []).length && !attached.length) return 'INSPECT · no project IAM roles';
|
|
91
|
+
return 'INSPECT';
|
|
92
|
+
}
|
|
93
|
+
|
|
94
|
+
/**
|
|
95
|
+
* Build inventory for one project. Does not create/rotate/delete keys.
|
|
96
|
+
*/
|
|
97
|
+
export async function collectGoogleCloudServiceAccountInventory(options = {}) {
|
|
98
|
+
const env = options.env || process.env;
|
|
99
|
+
const projectId = await resolveActiveProject(env, options.projectId);
|
|
100
|
+
if (!projectId) {
|
|
101
|
+
return {
|
|
102
|
+
schema_version: 'agentsam-gcp-sa-inventory-v1',
|
|
103
|
+
ok: false,
|
|
104
|
+
error: 'no_active_project',
|
|
105
|
+
project_id: null,
|
|
106
|
+
accounts: [],
|
|
107
|
+
};
|
|
108
|
+
}
|
|
109
|
+
|
|
110
|
+
const list = await runGcloudJson(
|
|
111
|
+
['iam', 'service-accounts', 'list', `--project=${projectId}`, '--format=json'],
|
|
112
|
+
env,
|
|
113
|
+
);
|
|
114
|
+
if (!list.ok) {
|
|
115
|
+
return {
|
|
116
|
+
schema_version: 'agentsam-gcp-sa-inventory-v1',
|
|
117
|
+
ok: false,
|
|
118
|
+
error: 'service_accounts_list_failed',
|
|
119
|
+
detail: list.stderr,
|
|
120
|
+
project_id: projectId,
|
|
121
|
+
accounts: [],
|
|
122
|
+
};
|
|
123
|
+
}
|
|
124
|
+
|
|
125
|
+
const policy = await runGcloudJson(
|
|
126
|
+
['projects', 'get-iam-policy', projectId, '--format=json'],
|
|
127
|
+
env,
|
|
128
|
+
);
|
|
129
|
+
const bindings = Array.isArray(policy.data?.bindings) ? policy.data.bindings : [];
|
|
130
|
+
|
|
131
|
+
const instances = await runGcloudJson(
|
|
132
|
+
['compute', 'instances', 'list', `--project=${projectId}`, '--format=json'],
|
|
133
|
+
env,
|
|
134
|
+
);
|
|
135
|
+
const instanceRows = Array.isArray(instances.data) ? instances.data : [];
|
|
136
|
+
|
|
137
|
+
const accounts = [];
|
|
138
|
+
for (const sa of Array.isArray(list.data) ? list.data : []) {
|
|
139
|
+
const email = clean(sa.email);
|
|
140
|
+
if (!email) continue;
|
|
141
|
+
const member = `serviceAccount:${email}`;
|
|
142
|
+
const roles = bindings
|
|
143
|
+
.filter((b) => Array.isArray(b.members) && b.members.includes(member))
|
|
144
|
+
.map((b) => b.role)
|
|
145
|
+
.filter(Boolean)
|
|
146
|
+
.sort();
|
|
147
|
+
|
|
148
|
+
const keysResult = await runGcloudJson(
|
|
149
|
+
[
|
|
150
|
+
'iam',
|
|
151
|
+
'service-accounts',
|
|
152
|
+
'keys',
|
|
153
|
+
'list',
|
|
154
|
+
`--iam-account=${email}`,
|
|
155
|
+
`--project=${projectId}`,
|
|
156
|
+
'--format=json',
|
|
157
|
+
],
|
|
158
|
+
env,
|
|
159
|
+
);
|
|
160
|
+
const rawKeys = Array.isArray(keysResult.data) ? keysResult.data : [];
|
|
161
|
+
const keys = rawKeys.map((key) => ({
|
|
162
|
+
// Google key id basename only — never private key material
|
|
163
|
+
key_id: clean(key.name).split('/').pop() || null,
|
|
164
|
+
key_type: key.keyType || null,
|
|
165
|
+
key_origin: key.keyOrigin || null,
|
|
166
|
+
// Product overlay: Google API origin stays GOOGLE_PROVIDED.
|
|
167
|
+
// INNERANIMALMEDIA_PROVIDED is reserved for AgentSam-issued credentials in our vault.
|
|
168
|
+
agentsam_origin_label:
|
|
169
|
+
String(key.keyOrigin || '').toUpperCase() === 'GOOGLE_PROVIDED'
|
|
170
|
+
? 'GOOGLE_PROVIDED'
|
|
171
|
+
: String(key.keyOrigin || 'UNKNOWN'),
|
|
172
|
+
created_at: key.validAfterTime || null,
|
|
173
|
+
expires_at: key.validBeforeTime || null,
|
|
174
|
+
disabled: Boolean(key.disabled),
|
|
175
|
+
}));
|
|
176
|
+
|
|
177
|
+
const attached = instanceRows
|
|
178
|
+
.filter((inst) => (inst.serviceAccounts || []).some((row) => row.email === email))
|
|
179
|
+
.map((inst) => ({
|
|
180
|
+
name: inst.name,
|
|
181
|
+
zone: clean(inst.zone).split('/').pop(),
|
|
182
|
+
status: inst.status,
|
|
183
|
+
}));
|
|
184
|
+
|
|
185
|
+
const bucket = classifySa(email, sa.displayName);
|
|
186
|
+
accounts.push({
|
|
187
|
+
email,
|
|
188
|
+
name: sa.displayName || shortName(email),
|
|
189
|
+
short_name: shortName(email),
|
|
190
|
+
disabled: Boolean(sa.disabled),
|
|
191
|
+
bucket,
|
|
192
|
+
roles,
|
|
193
|
+
keys,
|
|
194
|
+
key_counts: {
|
|
195
|
+
total: keys.length,
|
|
196
|
+
system_managed: keys.filter((k) => String(k.key_type).toUpperCase() === 'SYSTEM_MANAGED').length,
|
|
197
|
+
user_managed: keys.filter((k) => String(k.key_type).toUpperCase() === 'USER_MANAGED').length,
|
|
198
|
+
},
|
|
199
|
+
attached,
|
|
200
|
+
disposition_hint: dispositionHint(bucket, roles, keys, attached),
|
|
201
|
+
status: sa.disabled ? 'disabled' : attached.length ? 'active' : roles.length ? 'ready' : 'orphan_roles',
|
|
202
|
+
});
|
|
203
|
+
}
|
|
204
|
+
|
|
205
|
+
accounts.sort((a, b) => a.email.localeCompare(b.email));
|
|
206
|
+
|
|
207
|
+
return {
|
|
208
|
+
schema_version: 'agentsam-gcp-sa-inventory-v1',
|
|
209
|
+
ok: true,
|
|
210
|
+
project_id: projectId,
|
|
211
|
+
generated_at: new Date().toISOString(),
|
|
212
|
+
accounts,
|
|
213
|
+
policy_readable: policy.ok,
|
|
214
|
+
instances_readable: instances.ok,
|
|
215
|
+
};
|
|
216
|
+
}
|
|
217
|
+
|
|
218
|
+
export async function inspectGoogleCloudServiceAccount(options = {}) {
|
|
219
|
+
const inventory = await collectGoogleCloudServiceAccountInventory(options);
|
|
220
|
+
if (!inventory.ok) return inventory;
|
|
221
|
+
const needle = clean(options.account).toLowerCase();
|
|
222
|
+
const hit = inventory.accounts.find(
|
|
223
|
+
(row) =>
|
|
224
|
+
row.email.toLowerCase() === needle ||
|
|
225
|
+
row.short_name.toLowerCase() === needle ||
|
|
226
|
+
row.name.toLowerCase() === needle ||
|
|
227
|
+
row.email.toLowerCase().startsWith(`${needle}@`),
|
|
228
|
+
);
|
|
229
|
+
return {
|
|
230
|
+
schema_version: 'agentsam-gcp-sa-inspect-v1',
|
|
231
|
+
ok: Boolean(hit),
|
|
232
|
+
project_id: inventory.project_id,
|
|
233
|
+
account: hit || null,
|
|
234
|
+
error: hit ? null : 'service_account_not_found',
|
|
235
|
+
};
|
|
236
|
+
}
|
|
237
|
+
|
|
238
|
+
export async function collectGoogleCloudDoctor(options = {}) {
|
|
239
|
+
const env = options.env || process.env;
|
|
240
|
+
const projectId = await resolveActiveProject(env, options.projectId);
|
|
241
|
+
const auth = await runGcloudJson(['auth', 'list', '--format=json'], env, 15000);
|
|
242
|
+
const billing = projectId
|
|
243
|
+
? await runGcloudJson(['billing', 'projects', 'describe', projectId, '--format=json'], env, 20000)
|
|
244
|
+
: { ok: false, data: null, stderr: 'no_project' };
|
|
245
|
+
const inventory = projectId
|
|
246
|
+
? await collectGoogleCloudServiceAccountInventory({ env, projectId })
|
|
247
|
+
: { ok: false, accounts: [] };
|
|
248
|
+
|
|
249
|
+
const allAccounts = Array.isArray(auth.data) ? auth.data : [];
|
|
250
|
+
const activeAccounts = allAccounts.filter((row) => String(row.status || '').toUpperCase() === 'ACTIVE');
|
|
251
|
+
const activeAccount = clean(activeAccounts[0]?.account) || null;
|
|
252
|
+
const preferred = readGoogleCloudConnection({ env, home: options.home });
|
|
253
|
+
const connectionDiagnosis = diagnoseGoogleCloudAccountMismatch({
|
|
254
|
+
preferred,
|
|
255
|
+
activeAccount,
|
|
256
|
+
activeProject: projectId,
|
|
257
|
+
accounts: allAccounts.map((row) => ({ account: row.account, status: row.status })),
|
|
258
|
+
});
|
|
259
|
+
|
|
260
|
+
const issues = [];
|
|
261
|
+
if (!activeAccounts.length) issues.push({ code: 'no_active_gcloud_auth', severity: 'high' });
|
|
262
|
+
if (!projectId) issues.push({ code: 'no_active_project', severity: 'high' });
|
|
263
|
+
if (billing.ok === false && projectId) {
|
|
264
|
+
issues.push({ code: 'billing_describe_failed', severity: 'medium', detail: billing.stderr });
|
|
265
|
+
}
|
|
266
|
+
if (!connectionDiagnosis.ok) {
|
|
267
|
+
issues.push({
|
|
268
|
+
code: connectionDiagnosis.kind,
|
|
269
|
+
severity: 'high',
|
|
270
|
+
note: connectionDiagnosis.message,
|
|
271
|
+
remediation: connectionDiagnosis.remediation || null,
|
|
272
|
+
});
|
|
273
|
+
}
|
|
274
|
+
const userManaged = (inventory.accounts || []).flatMap((sa) =>
|
|
275
|
+
(sa.keys || [])
|
|
276
|
+
.filter((k) => String(k.key_type).toUpperCase() === 'USER_MANAGED')
|
|
277
|
+
.map((k) => ({ email: sa.email, key_id: k.key_id, expires_at: k.expires_at })),
|
|
278
|
+
);
|
|
279
|
+
if (userManaged.length) {
|
|
280
|
+
issues.push({
|
|
281
|
+
code: 'user_managed_sa_keys_present',
|
|
282
|
+
severity: 'medium',
|
|
283
|
+
count: userManaged.length,
|
|
284
|
+
note: 'Prefer ADC/workload identity; rotate long-lived USER_MANAGED keys after provenance.',
|
|
285
|
+
});
|
|
286
|
+
}
|
|
287
|
+
|
|
288
|
+
return {
|
|
289
|
+
schema_version: 'agentsam-gcp-doctor-v1',
|
|
290
|
+
ok: issues.every((i) => i.severity !== 'high'),
|
|
291
|
+
project_id: projectId || null,
|
|
292
|
+
auth_active: activeAccounts.length > 0,
|
|
293
|
+
auth_account_count: allAccounts.length,
|
|
294
|
+
active_account: activeAccount,
|
|
295
|
+
connection: preferred,
|
|
296
|
+
connection_diagnosis: connectionDiagnosis,
|
|
297
|
+
billing: billing.ok
|
|
298
|
+
? {
|
|
299
|
+
enabled: Boolean(billing.data?.billingEnabled),
|
|
300
|
+
account_name: billing.data?.billingAccountName || null,
|
|
301
|
+
}
|
|
302
|
+
: { enabled: null, account_name: null, error: billing.stderr || null },
|
|
303
|
+
service_accounts: inventory.ok ? inventory.accounts.length : 0,
|
|
304
|
+
user_managed_keys: userManaged.length,
|
|
305
|
+
issues,
|
|
306
|
+
credential_lanes: {
|
|
307
|
+
agentsam_api_key: 'InnerAnimalMedia account / platform authority (aak_*) — not a GCP SA key',
|
|
308
|
+
agentsam_bridge_key: 'Machine↔AgentSam Worker/ExecOS trust — not a Google SYSTEM_MANAGED key',
|
|
309
|
+
google_user_oauth: 'Human gcloud / ADC session used to discover this inventory',
|
|
310
|
+
google_sa: 'Workload identity inside the customer GCP project',
|
|
311
|
+
google_connection: 'AgentSam-persisted identity+project preference (not ambient gcloud active)',
|
|
312
|
+
},
|
|
313
|
+
};
|
|
314
|
+
}
|
|
315
|
+
|
|
316
|
+
export function renderServiceAccountTable(inventory) {
|
|
317
|
+
const lines = [
|
|
318
|
+
'',
|
|
319
|
+
` Agent Sam · Google Cloud · service accounts`,
|
|
320
|
+
` Project ${inventory.project_id || '(unset)'}`,
|
|
321
|
+
'',
|
|
322
|
+
' NAME ATTACHED KEYS USER STATUS HINT',
|
|
323
|
+
];
|
|
324
|
+
for (const row of inventory.accounts || []) {
|
|
325
|
+
const attached = row.attached?.map((a) => a.name).join(',') || '—';
|
|
326
|
+
const name = String(row.name || row.short_name).slice(0, 32).padEnd(32);
|
|
327
|
+
const att = attached.slice(0, 12).padEnd(12);
|
|
328
|
+
const keys = String(row.key_counts?.total ?? 0).padStart(4);
|
|
329
|
+
const user = String(row.key_counts?.user_managed ?? 0).padStart(4);
|
|
330
|
+
const status = String(row.status || '').padEnd(10);
|
|
331
|
+
lines.push(` ${name} ${att} ${keys} ${user} ${status} ${row.disposition_hint || ''}`);
|
|
332
|
+
}
|
|
333
|
+
lines.push('');
|
|
334
|
+
lines.push(' Key origin note');
|
|
335
|
+
lines.push(' Google API keyOrigin stays GOOGLE_PROVIDED for GCP-managed keys.');
|
|
336
|
+
lines.push(' INNERANIMALMEDIA_PROVIDED is only for AgentSam-issued AGENTSAM_* credentials in our vault.');
|
|
337
|
+
lines.push(' Never rewrite Google metadata; overlay labels live in AgentSam inventory only.');
|
|
338
|
+
lines.push('');
|
|
339
|
+
lines.push(' Inspect: agentsam google-cloud iam service-accounts inspect <name-or-email>');
|
|
340
|
+
lines.push('');
|
|
341
|
+
return lines.join('\n');
|
|
342
|
+
}
|
|
343
|
+
|
|
344
|
+
export function renderServiceAccountInspect(result) {
|
|
345
|
+
if (!result.ok || !result.account) {
|
|
346
|
+
return `\n ✕ Service account not found${result.project_id ? ` in ${result.project_id}` : ''}.\n`;
|
|
347
|
+
}
|
|
348
|
+
const sa = result.account;
|
|
349
|
+
const lines = [
|
|
350
|
+
'',
|
|
351
|
+
` Agent Sam · Google Cloud · ${sa.short_name}`,
|
|
352
|
+
'',
|
|
353
|
+
' Project',
|
|
354
|
+
` ${result.project_id}`,
|
|
355
|
+
'',
|
|
356
|
+
' Email',
|
|
357
|
+
` ${sa.email}`,
|
|
358
|
+
'',
|
|
359
|
+
' Bucket',
|
|
360
|
+
` ${sa.bucket}`,
|
|
361
|
+
'',
|
|
362
|
+
' IAM roles',
|
|
363
|
+
];
|
|
364
|
+
if (sa.roles.length) for (const role of sa.roles) lines.push(` ${role}`);
|
|
365
|
+
else lines.push(' (none on project IAM policy)');
|
|
366
|
+
lines.push('');
|
|
367
|
+
lines.push(' Keys (metadata only)');
|
|
368
|
+
if (!sa.keys.length) lines.push(' (none listed)');
|
|
369
|
+
for (const key of sa.keys) {
|
|
370
|
+
lines.push(
|
|
371
|
+
` ${key.key_type || '?'} ${key.agentsam_origin_label || key.key_origin || '?'} created ${key.created_at || '?'} expires ${key.expires_at || '?'} id ${key.key_id || '?'}`,
|
|
372
|
+
);
|
|
373
|
+
}
|
|
374
|
+
lines.push('');
|
|
375
|
+
lines.push(' Attached compute');
|
|
376
|
+
if (!sa.attached.length) lines.push(' —');
|
|
377
|
+
for (const inst of sa.attached) {
|
|
378
|
+
lines.push(` ${inst.name} ${inst.zone} ${inst.status}`);
|
|
379
|
+
}
|
|
380
|
+
lines.push('');
|
|
381
|
+
lines.push(' Disposition hint');
|
|
382
|
+
lines.push(` ${sa.disposition_hint}`);
|
|
383
|
+
lines.push('');
|
|
384
|
+
return lines.join('\n');
|
|
385
|
+
}
|