@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
|
@@ -120,7 +120,9 @@ function osStoreWriteDarwin(provider, secret) {
|
|
|
120
120
|
try {
|
|
121
121
|
const res = spawnSync('/usr/bin/security', ['add-generic-password', '-a', `agentsam:${provider}`, '-s', 'agentsam', '-w', secret, '-U'], {
|
|
122
122
|
stdio: 'ignore',
|
|
123
|
+
timeout: 12_000,
|
|
123
124
|
});
|
|
125
|
+
if (res.error?.code === 'ETIMEDOUT' || res.signal === 'SIGTERM') return false;
|
|
124
126
|
return res.status === 0;
|
|
125
127
|
} catch { return false; }
|
|
126
128
|
}
|
package/src/security/scan.js
CHANGED
|
@@ -4,7 +4,7 @@ import { triageLog, resolveLogFindings } from './logs.js';
|
|
|
4
4
|
import { scanTrustBoundary } from './trust-boundary.js';
|
|
5
5
|
|
|
6
6
|
export async function scanProjectSecurity(options = {}) {
|
|
7
|
-
const inventory = collectNpmDependencies(options.projectRoot);
|
|
7
|
+
const inventory = collectNpmDependencies(options.projectRoot, { releaseCandidate: options.releaseCandidate });
|
|
8
8
|
const results = options.offline
|
|
9
9
|
? inventory.dependencies.map(d => ({ ...d, checked: false, advisories: [] }))
|
|
10
10
|
: await queryOsv(inventory.dependencies, options);
|
|
@@ -38,7 +38,7 @@ test('opaque browser login persists in machine-local storage and resolves indepe
|
|
|
38
38
|
assert.equal(loaded.access_token, 'browser_session_machine_test');
|
|
39
39
|
const browser = resolveBrowserSessionCredential({ env: {}, home });
|
|
40
40
|
assert.equal(browser.source, 'agentsam_browser_oauth');
|
|
41
|
-
assert.equal(browser.kind, '
|
|
41
|
+
assert.equal(browser.kind, 'agentsam_browser_oauth');
|
|
42
42
|
assert.equal(browser.value, 'browser_session_machine_test');
|
|
43
43
|
assert.equal(resolveAccountApiKey({ env: {}, home }).value, '');
|
|
44
44
|
assert.equal(resolveAccountAuth({ env: {}, home }).value, 'browser_session_machine_test');
|
|
@@ -70,7 +70,7 @@ test('invalid environment API key cannot shadow a valid browser login', t => {
|
|
|
70
70
|
saveAccountSession({ access_token: 'browser_session_machine_test' }, { home });
|
|
71
71
|
const resolved = resolveAccountAuth({ env: { AGENTSAM_API_KEY: 'not-an-aak' }, home });
|
|
72
72
|
assert.equal(resolved.value, 'browser_session_machine_test');
|
|
73
|
-
assert.equal(resolved.kind, '
|
|
73
|
+
assert.equal(resolved.kind, 'agentsam_browser_oauth');
|
|
74
74
|
assert.equal(resolved.fallback_error, 'invalid_api_key_prefix');
|
|
75
75
|
});
|
|
76
76
|
|
|
@@ -79,7 +79,7 @@ test('async IAM authority also falls back from invalid environment key to browse
|
|
|
79
79
|
saveAccountSession({ access_token: 'browser_session_machine_test' }, { home });
|
|
80
80
|
const resolved = await resolveAccountAuthority({ env: { AGENTSAM_API_KEY: 'not-an-aak' }, home });
|
|
81
81
|
assert.equal(resolved.value, 'browser_session_machine_test');
|
|
82
|
-
assert.equal(resolved.kind, '
|
|
82
|
+
assert.equal(resolved.kind, 'agentsam_browser_oauth');
|
|
83
83
|
assert.equal(resolved.fallback_error, 'invalid_api_key_prefix');
|
|
84
84
|
});
|
|
85
85
|
|
|
@@ -0,0 +1,32 @@
|
|
|
1
|
+
import assert from 'node:assert/strict';
|
|
2
|
+
import path from 'node:path';
|
|
3
|
+
import { fileURLToPath } from 'node:url';
|
|
4
|
+
import test from 'node:test';
|
|
5
|
+
import { resolveCurrentAppContext } from '../src/lib/app-authority.js';
|
|
6
|
+
|
|
7
|
+
const HERE = path.dirname(fileURLToPath(import.meta.url));
|
|
8
|
+
const ROOT = path.resolve(HERE, '..');
|
|
9
|
+
|
|
10
|
+
test('generic repo root has no fabricated app identity', () => {
|
|
11
|
+
const context = resolveCurrentAppContext({ root: ROOT, cwd: ROOT });
|
|
12
|
+
assert.deepEqual(context, { app_id: null, host_origin: null, source: null });
|
|
13
|
+
});
|
|
14
|
+
|
|
15
|
+
test('Local Studio context resolves from nearest agentsam.app.json', () => {
|
|
16
|
+
const context = resolveCurrentAppContext({
|
|
17
|
+
root: ROOT,
|
|
18
|
+
cwd: path.join(ROOT, 'apps/local-studio/frontend'),
|
|
19
|
+
});
|
|
20
|
+
assert.equal(context.app_id, 'local-studio');
|
|
21
|
+
assert.equal(context.host_origin, null);
|
|
22
|
+
assert.match(context.source || '', /apps\/local-studio\/agentsam\.app\.json$/);
|
|
23
|
+
});
|
|
24
|
+
|
|
25
|
+
test('package app identity resolves from its own manifest without Local Studio leakage', () => {
|
|
26
|
+
const context = resolveCurrentAppContext({
|
|
27
|
+
root: ROOT,
|
|
28
|
+
cwd: path.join(ROOT, 'packages/agentsam-database-editor/src'),
|
|
29
|
+
});
|
|
30
|
+
assert.equal(context.app_id, 'database-editor');
|
|
31
|
+
assert.equal(context.host_origin, null);
|
|
32
|
+
});
|
|
@@ -32,6 +32,6 @@ describe('inventory path categories', () => {
|
|
|
32
32
|
assert.equal(classifyTopLevel('node_modules'), 'dependencies');
|
|
33
33
|
assert.equal(classifyTopLevel('dist'), 'dependencies');
|
|
34
34
|
assert.equal(classifyTopLevel('generated'), 'generated');
|
|
35
|
-
assert.equal(classifyTopLevel('.agentsam'), '
|
|
35
|
+
assert.equal(classifyTopLevel('.agentsam'), 'operational');
|
|
36
36
|
});
|
|
37
37
|
});
|
|
@@ -58,7 +58,7 @@ test('MCP authority store manages servers under ~/.agentsam/mcp with safe permis
|
|
|
58
58
|
assert.equal(readMcpServer('inneranimalmedia', { home }), null);
|
|
59
59
|
});
|
|
60
60
|
|
|
61
|
-
test('MCP external client registry recognizes chatgpt, claude, cursor
|
|
61
|
+
test('MCP external client registry recognizes chatgpt, claude, cursor — not CF portals', async () => {
|
|
62
62
|
const home = tempHome();
|
|
63
63
|
|
|
64
64
|
// Baseline seed / cached client list
|
|
@@ -68,9 +68,11 @@ test('MCP external client registry recognizes chatgpt, claude, cursor and respec
|
|
|
68
68
|
assert.ok(keys.includes('cursor'), 'Cursor is recognized in the external client registry');
|
|
69
69
|
assert.ok(keys.includes('claude'), 'Claude is recognized in the external client registry');
|
|
70
70
|
assert.ok(keys.includes('agentsam'), 'AgentSam is recognized in the external client registry');
|
|
71
|
+
assert.equal(keys.some((k) => k.startsWith('cf_')), false, 'CF MCP portals are servers, not clients');
|
|
71
72
|
|
|
72
73
|
assert.equal(isClientRegistered('chatgpt', { home }), true);
|
|
73
74
|
assert.equal(isClientRegistered('cursor', { home }), true);
|
|
75
|
+
assert.equal(isClientRegistered('cf_bindings_mcp', { home }), false);
|
|
74
76
|
assert.equal(isClientRegistered('nonexistent_client_xyz', { home }), false);
|
|
75
77
|
|
|
76
78
|
// Cache path is created upon writing
|
|
@@ -154,23 +156,25 @@ test('MCP client adapters materialize Cursor, Claude, and ChatGPT configurations
|
|
|
154
156
|
assert.equal(fs.existsSync(chatgptConfigPath), false);
|
|
155
157
|
});
|
|
156
158
|
|
|
157
|
-
test('MCP server catalog resolves
|
|
159
|
+
test('MCP server catalog resolves CF portal bundles + IAM without fabricated health', () => {
|
|
158
160
|
const home = tempHome();
|
|
159
161
|
const catalog = listKnownServers({ home });
|
|
160
162
|
assert.ok(catalog.length >= 8);
|
|
161
163
|
|
|
162
|
-
// Cloudflare API server from D1
|
|
163
164
|
const cfApi = resolveServerPreset('cloudflare-api', { home });
|
|
164
165
|
assert.ok(cfApi);
|
|
165
166
|
assert.equal(cfApi.url, 'https://mcp.cloudflare.com/mcp');
|
|
166
|
-
assert.equal(cfApi.
|
|
167
|
-
assert.equal(cfApi.
|
|
167
|
+
assert.equal(cfApi.provider, 'cloudflare');
|
|
168
|
+
assert.equal(cfApi.kind, 'mcp_portal_bundle');
|
|
169
|
+
assert.ok(cfApi.portal_manage_scopes.includes('mcp-portals.read'));
|
|
170
|
+
|
|
171
|
+
const bindings = resolveServerPreset('cloudflare-bindings', { home });
|
|
172
|
+
assert.ok(bindings);
|
|
173
|
+
assert.ok(bindings.feature_packs.includes('data'));
|
|
168
174
|
|
|
169
|
-
// InnerAnimalMedia Main MCP from D1
|
|
170
175
|
const iam = resolveServerPreset('inneranimalmedia', { home });
|
|
171
176
|
assert.ok(iam);
|
|
172
|
-
assert.equal(iam.
|
|
173
|
-
assert.equal(iam.avg_latency_ms, 443);
|
|
177
|
+
assert.equal(iam.url, 'https://mcp.inneranimalmedia.com/mcp');
|
|
174
178
|
});
|
|
175
179
|
|
|
176
180
|
test('MCP telemetry logs tool receipts and computes accurate summaries', () => {
|
|
@@ -204,6 +208,7 @@ test('agentsam mcp CLI handles add, list, status, doctor, and remove end-to-end'
|
|
|
204
208
|
const helpText = logs.join('\n');
|
|
205
209
|
assert.ok(helpText.includes('chatgpt'), 'Help text displays ChatGPT as a recognized client');
|
|
206
210
|
assert.ok(helpText.includes('cloudflare-api'), 'Help text displays cloudflare-api preset');
|
|
211
|
+
assert.ok(helpText.includes('bindings.mcp.cloudflare.com') || helpText.includes('cloudflare-bindings'), 'CF portal hostnames remain offerable');
|
|
207
212
|
logs.length = 0;
|
|
208
213
|
|
|
209
214
|
// Add inneranimalmedia preset for chatgpt client
|
|
@@ -230,11 +235,17 @@ test('agentsam mcp CLI handles add, list, status, doctor, and remove end-to-end'
|
|
|
230
235
|
assert.equal(statusRes.name, 'inneranimalmedia');
|
|
231
236
|
assert.equal(statusRes.hasAuth, true);
|
|
232
237
|
|
|
233
|
-
// Doctor includes catalog
|
|
238
|
+
// Doctor includes catalog / CF pack metadata
|
|
234
239
|
const doctorRes = await runMcp(['doctor', 'inneranimalmedia', '--json'], { home, write });
|
|
235
240
|
assert.equal(doctorRes.name, 'inneranimalmedia');
|
|
236
241
|
assert.equal(doctorRes.authConfigured, true);
|
|
237
|
-
assert.equal(doctorRes.
|
|
242
|
+
assert.equal(doctorRes.catalog?.auth_type, 'bearer');
|
|
243
|
+
|
|
244
|
+
// Cloudflare bundle scopes are pack-scoped (includes mcp-portals.*)
|
|
245
|
+
const scopeRes = await runMcp(['scopes', 'cloudflare-bindings', '--json'], { home, write });
|
|
246
|
+
assert.ok(scopeRes.oauth_scopes.includes('mcp-portals.read'));
|
|
247
|
+
assert.ok(scopeRes.oauth_scopes.includes('mcp-portals.write'));
|
|
248
|
+
assert.ok(scopeRes.oauth_scopes.includes('d1.read'));
|
|
238
249
|
|
|
239
250
|
// Remove
|
|
240
251
|
const removeRes = await runMcp(['remove', 'inneranimalmedia', '--client', 'all', '--json'], { home, write });
|
|
@@ -0,0 +1,56 @@
|
|
|
1
|
+
import test from 'node:test';
|
|
2
|
+
import assert from 'node:assert/strict';
|
|
3
|
+
import fs from 'node:fs';
|
|
4
|
+
import os from 'node:os';
|
|
5
|
+
import path from 'node:path';
|
|
6
|
+
import {
|
|
7
|
+
buildWindowsScheduledTaskXml,
|
|
8
|
+
buildLaunchAgentPlist,
|
|
9
|
+
writeWindowsScheduledTask,
|
|
10
|
+
WINDOWS_TASK_NAME,
|
|
11
|
+
} from '../../src/lib/setup/runtime-persist.js';
|
|
12
|
+
|
|
13
|
+
test('buildWindowsScheduledTaskXml includes binary, listen, logon trigger', () => {
|
|
14
|
+
const xml = buildWindowsScheduledTaskXml({
|
|
15
|
+
binary: 'C:\\Users\\sam\\.agentsam\\bin\\agentsamd.exe',
|
|
16
|
+
listen: '127.0.0.1:18765',
|
|
17
|
+
workingDirectory: 'C:\\Users\\sam\\.agentsam\\bin',
|
|
18
|
+
});
|
|
19
|
+
assert.match(xml, /agentsamd\.exe/);
|
|
20
|
+
assert.match(xml, /--listen 127\.0\.0\.1:18765/);
|
|
21
|
+
assert.match(xml, /LogonTrigger/);
|
|
22
|
+
assert.match(xml, /InteractiveToken/);
|
|
23
|
+
assert.match(xml, /RestartOnFailure/);
|
|
24
|
+
});
|
|
25
|
+
|
|
26
|
+
test('buildLaunchAgentPlist includes KeepAlive and listen', () => {
|
|
27
|
+
const plist = buildLaunchAgentPlist({
|
|
28
|
+
binary: '/Users/sam/.agentsam/bin/agentsamd',
|
|
29
|
+
listen: '127.0.0.1:18765',
|
|
30
|
+
stdoutLog: '/tmp/out.log',
|
|
31
|
+
stderrLog: '/tmp/err.log',
|
|
32
|
+
});
|
|
33
|
+
assert.match(plist, /com\.inneranimalmedia\.agentsamd/);
|
|
34
|
+
assert.match(plist, /KeepAlive/);
|
|
35
|
+
assert.match(plist, /127\.0\.0\.1:18765/);
|
|
36
|
+
});
|
|
37
|
+
|
|
38
|
+
test('writeWindowsScheduledTask writes XML without calling schtasks when skipRegister', async () => {
|
|
39
|
+
const home = fs.mkdtempSync(path.join(os.tmpdir(), 'agentsam-runtime-'));
|
|
40
|
+
try {
|
|
41
|
+
const result = await writeWindowsScheduledTask(
|
|
42
|
+
home,
|
|
43
|
+
path.join(home, '.agentsam', 'bin', 'agentsamd.exe'),
|
|
44
|
+
'127.0.0.1:18765',
|
|
45
|
+
{ forcePlatform: 'win32', skipRegister: true },
|
|
46
|
+
);
|
|
47
|
+
assert.equal(result.kind, 'scheduled_task');
|
|
48
|
+
assert.equal(result.taskName, WINDOWS_TASK_NAME);
|
|
49
|
+
assert.equal(result.registered, false);
|
|
50
|
+
assert.ok(fs.existsSync(result.xmlPath));
|
|
51
|
+
const xml = fs.readFileSync(result.xmlPath, 'utf8');
|
|
52
|
+
assert.match(xml, /agentsamd\.exe/);
|
|
53
|
+
} finally {
|
|
54
|
+
fs.rmSync(home, { recursive: true, force: true });
|
|
55
|
+
}
|
|
56
|
+
});
|
|
@@ -0,0 +1,21 @@
|
|
|
1
|
+
import test from 'node:test';
|
|
2
|
+
import assert from 'node:assert/strict';
|
|
3
|
+
import fs from 'node:fs';
|
|
4
|
+
import path from 'node:path';
|
|
5
|
+
import { fileURLToPath } from 'node:url';
|
|
6
|
+
import { getCliCommand } from '../../src/cli/command-catalog.js';
|
|
7
|
+
|
|
8
|
+
const root = path.resolve(path.dirname(fileURLToPath(import.meta.url)), '../..');
|
|
9
|
+
|
|
10
|
+
test('rust/wasm command aliases resolve to one catalog authority', () => {
|
|
11
|
+
const rust = getCliCommand('rust');
|
|
12
|
+
assert.equal(rust?.id, 'rust');
|
|
13
|
+
assert.equal(getCliCommand('wasm')?.id, 'rust');
|
|
14
|
+
assert.equal(getCliCommand('rapid-rust')?.id, 'rust');
|
|
15
|
+
});
|
|
16
|
+
|
|
17
|
+
test('rapid rust root bin and native crate ship in source tree', () => {
|
|
18
|
+
assert.equal(fs.existsSync(path.join(root, 'bin/agentsam-rapid-rust')), true);
|
|
19
|
+
assert.equal(fs.existsSync(path.join(root, 'packages/agentsam-rapid-rust/Cargo.toml')), true);
|
|
20
|
+
assert.equal(fs.existsSync(path.join(root, 'scripts/build_rapid_rust_cli.py')), true);
|
|
21
|
+
});
|
|
@@ -0,0 +1,113 @@
|
|
|
1
|
+
import assert from 'node:assert/strict';
|
|
2
|
+
import test from 'node:test';
|
|
3
|
+
import {
|
|
4
|
+
remediateGcloudEdgeServiceAccountKey,
|
|
5
|
+
remediateGcloudPermissionDenied,
|
|
6
|
+
remediateGithubTokenShadow,
|
|
7
|
+
remediateProviderFailure,
|
|
8
|
+
renderRemediationCard,
|
|
9
|
+
recommendedCommand,
|
|
10
|
+
} from '../src/lib/provider-command-remediation.js';
|
|
11
|
+
import { runCredentials } from '../src/commands/credentials.js';
|
|
12
|
+
import { listCheatSheetGroups, renderCheatSheet } from '../src/commands/cheat-sheet.js';
|
|
13
|
+
import { collectCredentialsAudit } from '../src/lib/credentials-audit.js';
|
|
14
|
+
|
|
15
|
+
test('edge-cloud service-account key create remediates to IAM / compute intents', () => {
|
|
16
|
+
const card = remediateGcloudEdgeServiceAccountKey({
|
|
17
|
+
argv: ['gcloud', 'edge-cloud', 'service-accounts', 'keys', 'create'],
|
|
18
|
+
projectId: 'gen-lang-client-0684066529',
|
|
19
|
+
instance: 'iam-tunnel',
|
|
20
|
+
zone: 'us-central1-f',
|
|
21
|
+
});
|
|
22
|
+
assert.ok(card);
|
|
23
|
+
assert.equal(card.provider, 'google_cloud');
|
|
24
|
+
assert.equal(card.kind, 'command_incomplete_wrong_family');
|
|
25
|
+
assert.match(card.summary, /Distributed Cloud Edge/i);
|
|
26
|
+
assert.match(card.summary, /Compute Engine/i);
|
|
27
|
+
const commands = card.actions.map((row) => row.command).join('\n');
|
|
28
|
+
assert.match(commands, /gcloud compute instances describe iam-tunnel/);
|
|
29
|
+
assert.match(commands, /gcloud iam service-accounts list/);
|
|
30
|
+
assert.match(commands, /gcloud iam service-accounts keys create/);
|
|
31
|
+
assert.match(commands, /agentsam connections/);
|
|
32
|
+
const rendered = renderRemediationCard(card);
|
|
33
|
+
assert.match(rendered, /Command incomplete/);
|
|
34
|
+
assert.match(rendered, /\[enter\]/);
|
|
35
|
+
assert.equal(recommendedCommand(card), card.actions[0].command);
|
|
36
|
+
});
|
|
37
|
+
|
|
38
|
+
test('remediateProviderFailure matches edge-cloud argv fixture', () => {
|
|
39
|
+
const card = remediateProviderFailure({
|
|
40
|
+
argv: ['gcloud', 'edge-cloud', 'service-accounts', 'keys', 'create'],
|
|
41
|
+
stderr: 'ERROR: argument OUTPUT_FILE (--service-account : --location): Must be specified.',
|
|
42
|
+
});
|
|
43
|
+
assert.ok(card);
|
|
44
|
+
assert.equal(card.kind, 'command_incomplete_wrong_family');
|
|
45
|
+
});
|
|
46
|
+
|
|
47
|
+
test('permission denied remediation exposes reauth + IAM console actions', () => {
|
|
48
|
+
const card = remediateGcloudPermissionDenied({
|
|
49
|
+
operation: 'compute.instances.list',
|
|
50
|
+
projectId: 'gen-lang-client-0684066529',
|
|
51
|
+
connection: 'Google Cloud · InnerAnimalMedia',
|
|
52
|
+
});
|
|
53
|
+
assert.equal(card.kind, 'permission_denied');
|
|
54
|
+
assert.match(renderRemediationCard(card), /Permission missing/);
|
|
55
|
+
assert.match(renderRemediationCard(card), /Re-authorize Google Cloud/);
|
|
56
|
+
assert.ok(card.actions.some((row) => /console\.cloud\.google\.com\/iam-admin/i.test(row.docs_url || '')));
|
|
57
|
+
});
|
|
58
|
+
|
|
59
|
+
test('github token shadow remediation prefers unset + keyring status', () => {
|
|
60
|
+
const card = remediateGithubTokenShadow({
|
|
61
|
+
envTokenPresent: true,
|
|
62
|
+
keyringHealthy: true,
|
|
63
|
+
scopes: ['repo', 'read:org'],
|
|
64
|
+
});
|
|
65
|
+
assert.ok(card);
|
|
66
|
+
assert.equal(card.kind, 'credential_shadow');
|
|
67
|
+
assert.match(recommendedCommand(card), /unset GITHUB_TOKEN/);
|
|
68
|
+
});
|
|
69
|
+
|
|
70
|
+
test('credentials remediate CLI prints edge-cloud card without secrets', async () => {
|
|
71
|
+
const chunks = [];
|
|
72
|
+
const code = await runCredentials(
|
|
73
|
+
['remediate', '--', 'gcloud', 'edge-cloud', 'service-accounts', 'keys', 'create'],
|
|
74
|
+
{ write: (s) => chunks.push(s) },
|
|
75
|
+
);
|
|
76
|
+
assert.equal(code, 0);
|
|
77
|
+
const out = chunks.join('');
|
|
78
|
+
assert.match(out, /Google Cloud/);
|
|
79
|
+
assert.match(out, /gcloud iam service-accounts list/);
|
|
80
|
+
assert.doesNotMatch(out, /gho_/);
|
|
81
|
+
assert.doesNotMatch(out, /AIza/);
|
|
82
|
+
});
|
|
83
|
+
|
|
84
|
+
test('credentials audit --names-only never includes secret-looking values', async () => {
|
|
85
|
+
const report = await collectCredentialsAudit({
|
|
86
|
+
env: {
|
|
87
|
+
HOME: process.env.HOME,
|
|
88
|
+
AGENTSAM_API_KEY: 'aak_test_should_never_appear_in_output_fields_as_value',
|
|
89
|
+
GITHUB_TOKEN: 'ghp_should_never_be_echoed',
|
|
90
|
+
OPENAI_API_KEY: 'sk-should-never-be-echoed',
|
|
91
|
+
},
|
|
92
|
+
verify: false,
|
|
93
|
+
drift: true,
|
|
94
|
+
namesOnly: true,
|
|
95
|
+
noNetwork: true,
|
|
96
|
+
});
|
|
97
|
+
const blob = JSON.stringify(report);
|
|
98
|
+
assert.doesNotMatch(blob, /aak_test_should_never/);
|
|
99
|
+
assert.doesNotMatch(blob, /ghp_should_never/);
|
|
100
|
+
assert.doesNotMatch(blob, /sk-should-never/);
|
|
101
|
+
assert.equal(report.shell_presence.GITHUB_TOKEN, true);
|
|
102
|
+
assert.equal(report.shell_presence.AGENTSAM_API_KEY, true);
|
|
103
|
+
assert.ok(report.drift.some((row) => row.code === 'github_env_token_present'));
|
|
104
|
+
});
|
|
105
|
+
|
|
106
|
+
test('cheat-sheet exposes System + Providers groups', () => {
|
|
107
|
+
const groups = listCheatSheetGroups();
|
|
108
|
+
assert.ok(groups.some((g) => g.id === 'system'));
|
|
109
|
+
assert.ok(groups.some((g) => g.id === 'providers'));
|
|
110
|
+
const text = renderCheatSheet('2.6.4');
|
|
111
|
+
assert.match(text, /credentials audit/);
|
|
112
|
+
assert.match(text, /cheat-sheet/);
|
|
113
|
+
});
|
|
@@ -28,12 +28,18 @@ describe('deploy health', () => {
|
|
|
28
28
|
|
|
29
29
|
it('reads hostname from wrangler.jsonc', () => {
|
|
30
30
|
const origin = resolveHealthOrigin({
|
|
31
|
-
env: {},
|
|
32
31
|
wranglerConfigText: '{"routes":[{"pattern":"agentsam.inneranimalmedia.com","custom_domain":true}]}',
|
|
33
32
|
});
|
|
34
33
|
assert.equal(origin, 'https://agentsam.inneranimalmedia.com');
|
|
35
34
|
});
|
|
36
35
|
|
|
36
|
+
it('fails loud when wrangler routes pattern is missing', () => {
|
|
37
|
+
assert.throws(
|
|
38
|
+
() => resolveHealthOrigin({ wranglerConfigText: '{}' }),
|
|
39
|
+
(err) => err?.code === 'health_origin_required',
|
|
40
|
+
);
|
|
41
|
+
});
|
|
42
|
+
|
|
37
43
|
it('treats /health ok:true with connector unconfigured as healthy', async () => {
|
|
38
44
|
const fetchImpl = async (url) => {
|
|
39
45
|
if (String(url).endsWith('/health')) {
|
|
@@ -48,6 +54,28 @@ describe('deploy health', () => {
|
|
|
48
54
|
assert.equal(health.ok, true);
|
|
49
55
|
assert.equal(health.results['/health'].appOk, true);
|
|
50
56
|
assert.equal(health.results['/health'].cloudflareConfigured, false);
|
|
57
|
+
assert.equal(health.results['/privacy'].ok, true);
|
|
58
|
+
assert.equal(health.results['/terms'].ok, true);
|
|
59
|
+
});
|
|
60
|
+
|
|
61
|
+
it('fails deploy health when /privacy or /terms are not HTTP 200', async () => {
|
|
62
|
+
const fetchImpl = async (url) => {
|
|
63
|
+
const path = String(url).replace(/^https?:\/\/[^/]+/, '');
|
|
64
|
+
if (path === '/health') {
|
|
65
|
+
return {
|
|
66
|
+
status: 200,
|
|
67
|
+
json: async () => ({ ok: true, connections: { cloudflare: { configured: true } } }),
|
|
68
|
+
};
|
|
69
|
+
}
|
|
70
|
+
if (path === '/privacy' || path === '/terms') {
|
|
71
|
+
return { status: 404, json: async () => ({}) };
|
|
72
|
+
}
|
|
73
|
+
return { status: 200, json: async () => ({}) };
|
|
74
|
+
};
|
|
75
|
+
const health = await probeDeployHealth('https://agentsam.inneranimalmedia.com', { fetchImpl });
|
|
76
|
+
assert.equal(health.ok, false);
|
|
77
|
+
assert.equal(health.results['/privacy'].ok, false);
|
|
78
|
+
assert.equal(health.results['/terms'].ok, false);
|
|
51
79
|
});
|
|
52
80
|
|
|
53
81
|
it('sends a browser-safe User-Agent so WAF does not 403 the probe', async () => {
|
|
@@ -0,0 +1,111 @@
|
|
|
1
|
+
import assert from 'node:assert/strict';
|
|
2
|
+
import test from 'node:test';
|
|
3
|
+
import {
|
|
4
|
+
resolveGoogleOauthStartUrl,
|
|
5
|
+
runAgentsamGoogleOauthLogin,
|
|
6
|
+
runGcloudAuth,
|
|
7
|
+
} from '../src/commands/gcloud-auth.js';
|
|
8
|
+
import {
|
|
9
|
+
GOOGLE_CLOUD_CONNECTION_SCOPES,
|
|
10
|
+
buildGoogleDesktopAuthUrl,
|
|
11
|
+
googleCloudPermissionChecklist,
|
|
12
|
+
resolveGoogleDesktopClientId,
|
|
13
|
+
} from '../src/lib/google-desktop-oauth.js';
|
|
14
|
+
|
|
15
|
+
const TEST_ENV = {
|
|
16
|
+
IAM_OAUTH_ISSUER: 'https://inneranimalmedia.com',
|
|
17
|
+
GOOGLE_CLIENT_ID: '246811022042-d8q1rc1oki4uv9qiqjah8lvkffb91crp.apps.googleusercontent.com',
|
|
18
|
+
GOOGLE_DESKTOP_CLIENT_ID: '246811022042-cckq00b5seekpkv0in358jhu42n0b6u9.apps.googleusercontent.com',
|
|
19
|
+
};
|
|
20
|
+
|
|
21
|
+
test('hosted --web login emits start URL in --json', async () => {
|
|
22
|
+
let out = '';
|
|
23
|
+
const code = await runAgentsamGoogleOauthLogin({
|
|
24
|
+
write: (s) => {
|
|
25
|
+
out += s;
|
|
26
|
+
},
|
|
27
|
+
json: true,
|
|
28
|
+
nonInteractive: true,
|
|
29
|
+
env: TEST_ENV,
|
|
30
|
+
});
|
|
31
|
+
assert.equal(code, 0);
|
|
32
|
+
const parsed = JSON.parse(out.slice(out.indexOf('{')));
|
|
33
|
+
assert.equal(parsed.mode, 'hosted_identity');
|
|
34
|
+
assert.equal(
|
|
35
|
+
parsed.start_url,
|
|
36
|
+
resolveGoogleOauthStartUrl(TEST_ENV),
|
|
37
|
+
);
|
|
38
|
+
});
|
|
39
|
+
|
|
40
|
+
test('gcloud auth login --web is hosted identity', async () => {
|
|
41
|
+
let out = '';
|
|
42
|
+
const code = await runGcloudAuth(['login', '--web', '--json'], {
|
|
43
|
+
write: (s) => {
|
|
44
|
+
out += s;
|
|
45
|
+
},
|
|
46
|
+
nonInteractive: true,
|
|
47
|
+
env: TEST_ENV,
|
|
48
|
+
});
|
|
49
|
+
assert.equal(code, 0);
|
|
50
|
+
assert.match(out, /hosted_identity|\/api\/oauth\/google\/start/);
|
|
51
|
+
});
|
|
52
|
+
|
|
53
|
+
test('gcloud auth help mentions studio broker default and --desktop/--web/--sdk', async () => {
|
|
54
|
+
let out = '';
|
|
55
|
+
await runGcloudAuth(['help'], {
|
|
56
|
+
write: (s) => {
|
|
57
|
+
out += s;
|
|
58
|
+
},
|
|
59
|
+
});
|
|
60
|
+
assert.match(out, /Studio Web OAuth broker|Worker holds/i);
|
|
61
|
+
assert.match(out, /--desktop/);
|
|
62
|
+
assert.match(out, /--web/);
|
|
63
|
+
assert.match(out, /--sdk/);
|
|
64
|
+
});
|
|
65
|
+
|
|
66
|
+
test('desktop auth URL requests cloud-platform + offline', () => {
|
|
67
|
+
const url = new URL(buildGoogleDesktopAuthUrl({
|
|
68
|
+
clientId: resolveGoogleDesktopClientId(TEST_ENV),
|
|
69
|
+
redirectUri: 'http://127.0.0.1:12345/callback',
|
|
70
|
+
state: 'abc',
|
|
71
|
+
codeChallenge: 'challenge',
|
|
72
|
+
}));
|
|
73
|
+
assert.match(url.searchParams.get('scope') || '', /cloud-platform/);
|
|
74
|
+
assert.equal(url.searchParams.get('access_type'), 'offline');
|
|
75
|
+
assert.equal(url.searchParams.get('code_challenge_method'), 'S256');
|
|
76
|
+
assert.match(GOOGLE_CLOUD_CONNECTION_SCOPES, /openid/);
|
|
77
|
+
});
|
|
78
|
+
|
|
79
|
+
test('permissions checklist separates OAuth scopes from IAM roles', async () => {
|
|
80
|
+
let out = '';
|
|
81
|
+
const code = await runGcloudAuth(['login', '--permissions'], {
|
|
82
|
+
write: (s) => {
|
|
83
|
+
out += s;
|
|
84
|
+
},
|
|
85
|
+
});
|
|
86
|
+
assert.equal(code, 0);
|
|
87
|
+
assert.match(out, /cloud-platform/);
|
|
88
|
+
assert.match(out, /mcp\.toolUser|roles\/mcp/);
|
|
89
|
+
const checklist = googleCloudPermissionChecklist();
|
|
90
|
+
assert.ok(checklist.oauth_scopes_requested.includes('https://www.googleapis.com/auth/cloud-platform'));
|
|
91
|
+
});
|
|
92
|
+
|
|
93
|
+
test('resolveGoogleDesktopClientId fails loud when unset', () => {
|
|
94
|
+
assert.throws(
|
|
95
|
+
() => resolveGoogleDesktopClientId({}),
|
|
96
|
+
(err) => err?.code === 'google_desktop_client_not_configured',
|
|
97
|
+
);
|
|
98
|
+
});
|
|
99
|
+
|
|
100
|
+
test('resolveGoogleDesktopClientIdAsync uses public-config when env unset', async () => {
|
|
101
|
+
const { resolveGoogleDesktopClientIdAsync } = await import('../src/lib/google-desktop-oauth.js');
|
|
102
|
+
const id = await resolveGoogleDesktopClientIdAsync({}, {
|
|
103
|
+
publicConfigUrl: 'https://example.test/api/public-config',
|
|
104
|
+
fetchImpl: async () =>
|
|
105
|
+
new Response(JSON.stringify({
|
|
106
|
+
ok: true,
|
|
107
|
+
google_desktop_client_id: 'from-public-config.apps.googleusercontent.com',
|
|
108
|
+
}), { status: 200 }),
|
|
109
|
+
});
|
|
110
|
+
assert.equal(id, 'from-public-config.apps.googleusercontent.com');
|
|
111
|
+
});
|
|
@@ -0,0 +1,83 @@
|
|
|
1
|
+
import assert from 'node:assert/strict';
|
|
2
|
+
import fs from 'node:fs';
|
|
3
|
+
import os from 'node:os';
|
|
4
|
+
import path from 'node:path';
|
|
5
|
+
import test from 'node:test';
|
|
6
|
+
import {
|
|
7
|
+
diagnoseGoogleCloudAccountMismatch,
|
|
8
|
+
diagnoseInsufficientAccess,
|
|
9
|
+
readGoogleCloudConnection,
|
|
10
|
+
renderInsufficientAccessCard,
|
|
11
|
+
writeGoogleCloudConnection,
|
|
12
|
+
} from '../src/lib/google-cloud-connection.js';
|
|
13
|
+
import { describeAuthShadow, renderLoginResult } from '../src/commands/whoami.js';
|
|
14
|
+
|
|
15
|
+
test('connection preference persists identity+project without secrets', () => {
|
|
16
|
+
const home = fs.mkdtempSync(path.join(os.tmpdir(), 'agentsam-conn-'));
|
|
17
|
+
const saved = writeGoogleCloudConnection(
|
|
18
|
+
{
|
|
19
|
+
identity: 'meauxbility@gmail.com',
|
|
20
|
+
organization: 'inneranimals.com',
|
|
21
|
+
project: 'gen-lang-client-0684066529',
|
|
22
|
+
billing_account: '017E01-4426EF-21356F',
|
|
23
|
+
},
|
|
24
|
+
{ home },
|
|
25
|
+
);
|
|
26
|
+
assert.equal(saved.identity, 'meauxbility@gmail.com');
|
|
27
|
+
assert.equal(saved.project, 'gen-lang-client-0684066529');
|
|
28
|
+
const again = readGoogleCloudConnection({ home });
|
|
29
|
+
assert.equal(again.organization, 'inneranimals.com');
|
|
30
|
+
assert.doesNotMatch(JSON.stringify(again), /private_key|BEGIN /);
|
|
31
|
+
});
|
|
32
|
+
|
|
33
|
+
test('identity mismatch diagnosis is deterministic', () => {
|
|
34
|
+
const d = diagnoseGoogleCloudAccountMismatch({
|
|
35
|
+
preferred: { identity: 'meauxbility@gmail.com', project: 't-pulsar-483701-q1' },
|
|
36
|
+
activeAccount: 'info@inneranimals.com',
|
|
37
|
+
activeProject: 't-pulsar-483701-q1',
|
|
38
|
+
accounts: [
|
|
39
|
+
{ account: 'info@inneranimals.com', status: 'ACTIVE' },
|
|
40
|
+
{ account: 'meauxbility@gmail.com', status: '' },
|
|
41
|
+
],
|
|
42
|
+
});
|
|
43
|
+
assert.equal(d.ok, false);
|
|
44
|
+
assert.equal(d.kind, 'identity_mismatch');
|
|
45
|
+
assert.equal(d.alternate_authenticated, true);
|
|
46
|
+
assert.match(d.remediation.actions[0].command, /gcloud config set account meauxbility@gmail.com/);
|
|
47
|
+
});
|
|
48
|
+
|
|
49
|
+
test('insufficient access card matches product UX', () => {
|
|
50
|
+
const d = diagnoseInsufficientAccess({
|
|
51
|
+
currentAccount: 'info@inneranimals.com',
|
|
52
|
+
requiredRole: 'roles/owner',
|
|
53
|
+
project: 'gen-lang-client-0684066529',
|
|
54
|
+
accounts: [
|
|
55
|
+
{ account: 'info@inneranimals.com', roles: ['roles/viewer'] },
|
|
56
|
+
{ account: 'meauxbility@gmail.com', roles: ['roles/owner'] },
|
|
57
|
+
],
|
|
58
|
+
});
|
|
59
|
+
assert.equal(d.kind, 'insufficient_access');
|
|
60
|
+
const text = renderInsufficientAccessCard(d);
|
|
61
|
+
assert.match(text, /This Google account does not have enough access/);
|
|
62
|
+
assert.match(text, /meauxbility@gmail\.com/);
|
|
63
|
+
assert.match(text, /✓ Owner/);
|
|
64
|
+
assert.match(text, /\[enter\]/);
|
|
65
|
+
assert.match(text, /\[a\]/);
|
|
66
|
+
assert.match(text, /\[c\]/);
|
|
67
|
+
});
|
|
68
|
+
|
|
69
|
+
test('login result explains API key shadowing OAuth', () => {
|
|
70
|
+
const status = {
|
|
71
|
+
active_auth: { kind: 'api_key', source: 'environment' },
|
|
72
|
+
api_key: { configured: true, source: 'environment' },
|
|
73
|
+
browser_session: { configured: true, expired: false, refreshable: true },
|
|
74
|
+
};
|
|
75
|
+
const text = renderLoginResult(status);
|
|
76
|
+
assert.match(text, /Browser OAuth login saved/);
|
|
77
|
+
assert.match(text, /not currently authoritative/);
|
|
78
|
+
assert.match(text, /AGENTSAM_API_KEY has higher precedence/);
|
|
79
|
+
assert.match(text, /\[enter\] keep API key/);
|
|
80
|
+
const shadow = describeAuthShadow(status);
|
|
81
|
+
assert.ok(shadow);
|
|
82
|
+
assert.match(shadow.join('\n'), /Authority lanes/);
|
|
83
|
+
});
|