@inneranimalmedia/agentsam-sdk 2.6.7 → 2.6.9
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/README.md +37 -0
- package/apps/README.md +25 -0
- package/apps/cad-creator/shared/cad/package.json +1 -1
- package/apps/client-cms-editor/backend/package.json +4 -6
- package/apps/client-cms-editor/frontend/package.json +6 -8
- package/apps/client-cms-editor/frontend/tsconfig.json +27 -8
- package/apps/client-cms-editor/package.json +1 -1
- package/apps/client-cms-editor/shared/cms/package.json +4 -6
- package/docs/LOCAL_ENGINE_COMPUTE_AUDIT_PLAN.md +299 -0
- package/docs/REPO_FILE_MAP.txt +132 -0
- package/migrations/d1/0018_goap_control_plane_remaster.sql +40 -0
- package/migrations/d1/0019_agentsam_agent_run_plan_todo.sql +14 -0
- package/migrations/d1/README_PORTABLE_CONTROL_PLANE.md +20 -9
- package/migrations/runtime/0002_goap_blackboard_v1.sql +15 -0
- package/migrations/runtime/0004_agent_run_plan_linkage.sql +8 -0
- package/native/agentsam-machine/cli/Cargo.toml +8 -1
- package/native/agentsam-machine/cli/README.md +21 -0
- package/native/agentsam-machine/core/Cargo.toml +7 -0
- package/native/agentsam-machine/core/README.md +14 -0
- package/native/agentsam-machine/core/build.rs +33 -0
- package/native/agentsam-machine/core/contracts/source-types.v1.json +353 -0
- package/native/agentsam-machine/core/src/lib.rs +6 -0
- package/native/agentsam-machine/core/src/source_types.rs +2 -2
- package/package.json +31 -10
- package/packages/agentsam-brand/package.json +1 -1
- package/packages/agentsam-contracts/package.json +71 -20
- package/packages/agentsam-contracts/scripts/build.mjs +18 -0
- package/packages/agentsam-contracts/test/contracts.test.mjs +4 -1
- package/packages/agentsam-contracts/test/repository.test.mjs +4 -1
- package/packages/agentsam-contracts/tsconfig.build.json +10 -0
- package/packages/agentsam-errors/package.json +3 -2
- package/packages/agentsam-errors/src/index.js +1 -0
- package/packages/agentsam-errors/src/tool.js +56 -0
- package/packages/agentsam-errors/test/tool.test.mjs +58 -0
- package/packages/agentsam-goap/README.md +52 -0
- package/packages/agentsam-goap/package.json +37 -0
- package/packages/agentsam-goap/src/adapters/d1-sqlite.js +570 -0
- package/packages/agentsam-goap/src/adapters/memory.js +199 -0
- package/packages/agentsam-goap/src/contracts.js +226 -0
- package/packages/agentsam-goap/src/control-plane.js +112 -0
- package/packages/agentsam-goap/src/errors.js +157 -0
- package/packages/agentsam-goap/src/index.js +5 -0
- package/packages/agentsam-goap/src/world.js +202 -0
- package/packages/agentsam-goap/test/goap-control-plane.test.mjs +245 -0
- package/packages/agentsam-goap/test/world.test.mjs +79 -0
- package/packages/agentsam-knowledge/package.json +3 -2
- package/packages/agentsam-nav/package.json +1 -1
- package/packages/agentsam-queue-control/package.json +1 -1
- package/packages/agentsam-rapid-rust/src/main.rs +1 -0
- package/packages/agentsam-repository/package.json +3 -2
- package/packages/agentsam-repository/src/goap.js +13 -14
- package/packages/agentsam-repository/src/tickets.js +15 -22
- package/packages/agentsam-repository/test/goap-tickets-workspace-state.test.mjs +19 -8
- package/packages/agentsam-vault/package.json +8 -5
- package/packages/agentsam-workbench/package.json +44 -17
- package/packages/connectors/cloudflare/package.json +4 -2
- package/packages/heuristic-theme/package.json +1 -1
- package/packages/identity/package.json +4 -3
- package/packages/identity/tests/lane1-packed-consumer.test.mjs +10 -2
- package/packages/providers/completeful/package.json +1 -1
- package/packages/theme-church-site/README.md +2 -2
- package/packages/theme-church-site/package.json +3 -4
- package/packages/theme-church-site/src/index.js +1 -1
- package/packages/theme-church-site/test/theme.test.mjs +1 -1
- package/packages/theme-companions-site/README.md +2 -2
- package/packages/theme-companions-site/package.json +3 -4
- package/packages/theme-companions-site/src/index.js +1 -1
- package/packages/theme-companions-site/test/theme.test.mjs +1 -1
- package/packages/theme-floors-site/README.md +2 -2
- package/packages/theme-floors-site/package.json +3 -4
- package/packages/theme-floors-site/src/index.js +1 -1
- package/packages/theme-floors-site/test/theme.test.mjs +1 -1
- package/packages/theme-fuelnfree-site/README.md +2 -2
- package/packages/theme-fuelnfree-site/package.json +3 -4
- package/packages/theme-fuelnfree-site/src/index.js +1 -1
- package/packages/theme-fuelnfree-site/test/theme.test.mjs +1 -1
- package/packages/theme-handyman-site/README.md +2 -2
- package/packages/theme-handyman-site/package.json +3 -4
- package/packages/theme-handyman-site/src/index.js +1 -1
- package/packages/theme-handyman-site/test/theme.test.mjs +1 -1
- package/packages/theme-insurance-site/README.md +2 -2
- package/packages/theme-insurance-site/package.json +3 -4
- package/packages/theme-insurance-site/src/index.js +1 -1
- package/packages/theme-insurance-site/test/theme.test.mjs +1 -1
- package/packages/theme-scenes/package.json +1 -1
- package/packages/theme-shinshu-site/README.md +2 -2
- package/packages/theme-shinshu-site/package.json +3 -4
- package/packages/theme-shinshu-site/src/index.js +1 -1
- package/packages/theme-shinshu-site/test/theme.test.mjs +1 -1
- package/packages/work-graph/package.json +3 -2
- package/protocol/local-engine/benchmark.v1.schema.json +14 -0
- package/protocol/local-engine/engine.v1.schema.json +17 -0
- package/python/agentsam_sdk/repository/intelligence/discovery.py +27 -2
- package/python/agentsam_sdk/repository/intelligence/git.py +4 -0
- package/python/tests/test_repository_intelligence.py +30 -0
- package/src/cli/command-catalog.js +3 -1
- package/src/cli.js +20 -1
- package/src/commands/app.js +10 -0
- package/src/commands/engine.js +10 -0
- package/src/commands/goap-world.js +134 -0
- package/src/commands/goap.js +11 -4
- package/src/commands/machine-binary.js +33 -27
- package/src/commands/machine-runtime.js +266 -0
- package/src/commands/machine.js +155 -51
- package/src/commands/package.js +537 -0
- package/src/commands/plan-ledger.js +370 -0
- package/src/commands/plan.js +183 -0
- package/src/commands/runtime.js +25 -10
- package/src/commands/setup.js +30 -6
- package/src/commands/skill.js +78 -17
- package/src/commands/terminal.js +20 -8
- package/src/errors/contract.js +4 -4
- package/src/errors/diagnostic.js +1 -1
- package/src/errors/index.js +1 -1
- package/src/index.js +20 -0
- package/src/indexing/ingest/materials.js +237 -30
- package/src/knowledge/source.js +1 -1
- package/src/lib/setup/runtime.js +4 -2
- package/src/lib/slash-commands.js +1 -1
- package/src/local/runtime-store.js +24 -2
- package/src/local/sqlite.js +17 -0
- package/src/local-engine/assets.js +37 -0
- package/src/local-engine/audit.js +133 -0
- package/src/local-engine/benchmark.js +26 -0
- package/src/local-engine/contracts.js +101 -0
- package/src/local-engine/engines.js +142 -0
- package/src/local-engine/index.js +18 -0
- package/src/local-engine/runtime.js +39 -0
- package/src/sam/operations/package-audit.js +41 -0
- package/src/sam/seed.js +2 -0
- package/skills/grok-auth/SKILL.md +0 -110
- package/skills/grok-auth/agentsam.skill.json +0 -25
- package/skills/grok-auth/references/grok-identity.md +0 -64
- package/skills/grok-auth/references/per-user-data.md +0 -49
- package/skills/grok-auth/references/prewired-and-env.md +0 -54
- package/skills/grok-auth/references/session-ui.md +0 -133
- package/skills/grok-auth/references/sign-in-methods.md +0 -55
- package/skills/grok-auth/references/wiring.md +0 -71
- package/skills/grok-building-games/SKILL.md +0 -213
- package/skills/grok-building-games/agentsam.skill.json +0 -25
- package/skills/grok-building-games/references/3d-libs.md +0 -64
- package/skills/grok-building-games/references/ai-pathfinding.md +0 -122
- package/skills/grok-building-games/references/audio.md +0 -129
- package/skills/grok-building-games/references/babylon.md +0 -202
- package/skills/grok-building-games/references/collision-physics.md +0 -122
- package/skills/grok-building-games/references/ecs-architecture.md +0 -111
- package/skills/grok-building-games/references/game-feel-juice.md +0 -110
- package/skills/grok-building-games/references/genres/board-card-chess.md +0 -89
- package/skills/grok-building-games/references/genres/endless-runner.md +0 -83
- package/skills/grok-building-games/references/genres/fps.md +0 -105
- package/skills/grok-building-games/references/genres/platformer-2d.md +0 -97
- package/skills/grok-building-games/references/genres/puzzle-match3-tetris.md +0 -131
- package/skills/grok-building-games/references/genres/racing-kart.md +0 -106
- package/skills/grok-building-games/references/genres/topdown-twin-stick.md +0 -97
- package/skills/grok-building-games/references/genres/tower-defense.md +0 -84
- package/skills/grok-building-games/references/genres/voxel-minecraft.md +0 -89
- package/skills/grok-building-games/references/input.md +0 -139
- package/skills/grok-building-games/references/phaser.md +0 -277
- package/skills/grok-building-games/references/procedural-generation.md +0 -141
- package/skills/grok-building-games/references/save-persistence.md +0 -108
- package/skills/grok-building-games/references/threejs-foundational.md +0 -148
- package/skills/grok-controls/SKILL.md +0 -274
- package/skills/grok-controls/agentsam.skill.json +0 -25
- package/skills/grok-design-ui/SKILL.md +0 -122
- package/skills/grok-design-ui/agentsam.skill.json +0 -25
- package/skills/grok-design-ui/references/animations.md +0 -379
- package/skills/grok-design-ui/references/performance.md +0 -88
- package/skills/grok-design-ui/references/refined-ui.md +0 -384
- package/skills/grok-design-ui/references/surfaces.md +0 -247
- package/skills/grok-design-ui/references/typography.md +0 -123
- package/skills/grok-game-animation-frames/SKILL.md +0 -84
- package/skills/grok-game-animation-frames/agentsam.skill.json +0 -25
- package/skills/grok-game-asset-core/SKILL.md +0 -69
- package/skills/grok-game-asset-core/agentsam.skill.json +0 -25
- package/skills/grok-game-character-consistency/SKILL.md +0 -69
- package/skills/grok-game-character-consistency/agentsam.skill.json +0 -25
- package/skills/grok-game-tilesets/SKILL.md +0 -65
- package/skills/grok-game-tilesets/agentsam.skill.json +0 -25
- package/skills/grok-game-ui-icons/SKILL.md +0 -56
- package/skills/grok-game-ui-icons/agentsam.skill.json +0 -25
- package/skills/grok-generate2dmap/LICENSE +0 -21
- package/skills/grok-generate2dmap/SKILL.md +0 -120
- package/skills/grok-generate2dmap/SOURCE.md +0 -6
- package/skills/grok-generate2dmap/agentsam.skill.json +0 -25
- package/skills/grok-generate2dmap/references/deliverables.md +0 -101
- package/skills/grok-generate2dmap/references/layered-map-contract.md +0 -209
- package/skills/grok-generate2dmap/references/map-strategies.md +0 -341
- package/skills/grok-generate2dmap/references/object-production-gate.md +0 -24
- package/skills/grok-generate2dmap/references/pipeline.md +0 -149
- package/skills/grok-generate2dmap/references/prop-pack-contract.md +0 -174
- package/skills/grok-generate2dmap/references/side-scroll-stages.md +0 -29
- package/skills/grok-generate2dmap/scripts/compose_layered_preview.py +0 -157
- package/skills/grok-generate2dmap/scripts/extract_prop_pack.py +0 -369
- package/skills/grok-generate2dsprite/LICENSE +0 -21
- package/skills/grok-generate2dsprite/SKILL.md +0 -313
- package/skills/grok-generate2dsprite/SOURCE.md +0 -6
- package/skills/grok-generate2dsprite/agentsam.skill.json +0 -25
- package/skills/grok-generate2dsprite/references/modes.md +0 -124
- package/skills/grok-generate2dsprite/references/prompt-rules.md +0 -315
- package/skills/grok-generate2dsprite/scripts/generate2dsprite.py +0 -1031
- package/skills/grok-generate2dsprite/scripts/make_layout_guide.py +0 -109
- package/skills/grok-imagine/SKILL.md +0 -201
- package/skills/grok-imagine/agentsam.skill.json +0 -25
- package/skills/grok-multiplayer-p2p/SKILL.md +0 -111
- package/skills/grok-multiplayer-p2p/agentsam.skill.json +0 -25
- package/skills/grok-multiplayer-p2p/references/react-binding.md +0 -144
- package/skills/grok-multiplayer-p2p/references/signaling-relay.md +0 -269
- package/skills/grok-neon/SKILL.md +0 -157
- package/skills/grok-neon/agentsam.skill.json +0 -25
- package/skills/grok-og/SKILL.md +0 -102
- package/skills/grok-og/agentsam.skill.json +0 -25
- package/skills/grok-og/references/brand-pass.md +0 -53
- package/skills/grok-og/references/custom-card.md +0 -107
- package/skills/grok-og/references/favicon-and-icons.md +0 -48
- package/skills/grok-og/references/og-type-contract.md +0 -18
- package/skills/grok-og/references/placeholder-card.md +0 -21
- package/skills/grok-og/references/x-banner.md +0 -41
- package/skills/grok-threejs/SKILL.md +0 -67
- package/skills/grok-threejs/agentsam.skill.json +0 -25
- package/skills/grok-threejs/references/llms-full.txt +0 -2780
- package/skills/grok-video2dsprite/LICENSE +0 -21
- package/skills/grok-video2dsprite/SKILL.md +0 -236
- package/skills/grok-video2dsprite/SOURCE.md +0 -6
- package/skills/grok-video2dsprite/agentsam.skill.json +0 -25
- package/skills/grok-video2dsprite/references/pipeline.md +0 -90
- package/skills/grok-video2dsprite/references/prompt-rules.md +0 -63
- package/skills/grok-video2dsprite/scripts/video2dsprite.py +0 -490
- package/skills/grok-xai-api/SKILL.md +0 -152
- package/skills/grok-xai-api/agentsam.skill.json +0 -25
- package/test/account-session.test.mjs +0 -101
- package/test/agent-capabilities.test.mjs +0 -67
- package/test/app-authority-context.test.mjs +0 -32
- package/test/app-building-skills.test.mjs +0 -61
- package/test/apps-scaffold-contract.test.mjs +0 -115
- package/test/blender-cad.test.mjs +0 -146
- package/test/cad-docker.test.mjs +0 -96
- package/test/capabilities.test.mjs +0 -133
- package/test/cli/api-key-env-whoami.test.mjs +0 -129
- package/test/cli/catalog-authority.test.mjs +0 -64
- package/test/cli/codebaseindex-plan-ux.test.mjs +0 -37
- package/test/cli/eval-live.test.mjs +0 -219
- package/test/cli/go.test.mjs +0 -128
- package/test/cli/local-vault-and-provider-setup.test.mjs +0 -268
- package/test/cli/machine-command.test.mjs +0 -34
- package/test/cli/mcp-client.test.mjs +0 -256
- package/test/cli/preferences-runtime.test.mjs +0 -11
- package/test/cli/runtime-persist.test.mjs +0 -56
- package/test/cli/runtime-ui.test.mjs +0 -141
- package/test/cli/rust-command.test.mjs +0 -21
- package/test/cli/skill-npm-and-env.test.mjs +0 -52
- package/test/cli/status-actions.test.mjs +0 -88
- package/test/cli/wireframes-go-registry.test.mjs +0 -139
- package/test/cli-preferences.test.mjs +0 -46
- package/test/cloudflare-connector.test.mjs +0 -93
- package/test/cloudflare-runtime.test.mjs +0 -82
- package/test/context.test.mjs +0 -159
- package/test/credentials-audit.test.mjs +0 -113
- package/test/deploy-health-scan.test.mjs +0 -95
- package/test/deploy-receipt.test.mjs +0 -91
- package/test/dockerize.test.mjs +0 -93
- package/test/error-diagnostics.test.mjs +0 -124
- package/test/eval-context.test.mjs +0 -37
- package/test/execution-approvals.test.mjs +0 -27
- package/test/fixtures/cad/courtyard-house.json +0 -208
- package/test/fixtures/knowledge-rpc-worker.mjs +0 -16
- package/test/fixtures/project-authority/customer-app/.agentsam/app.json +0 -5
- package/test/fixtures/project-authority/customer-app/apps/my-product/index.ts +0 -1
- package/test/fixtures/project-authority/customer-app/wrangler.toml +0 -17
- package/test/gcloud-auth.test.mjs +0 -111
- package/test/go/build-source-identity.test.mjs +0 -31
- package/test/go/cloudflare-probe.test.mjs +0 -317
- package/test/go/distribution.test.mjs +0 -28
- package/test/google-cloud-connection.test.mjs +0 -83
- package/test/google-cloud-inventory.test.mjs +0 -64
- package/test/indexing-provider.test.mjs +0 -29
- package/test/init-options.test.mjs +0 -35
- package/test/integration/ai-access-onboarding.test.mjs +0 -47
- package/test/integration/app-command.test.mjs +0 -85
- package/test/integration/autorag-project-authority.integration.test.mjs +0 -51
- package/test/integration/autorag-runtime-discovery.test.mjs +0 -107
- package/test/integration/cad-discovery.test.mjs +0 -158
- package/test/integration/cad-docker-executor.test.mjs +0 -249
- package/test/integration/cad-execution.test.mjs +0 -184
- package/test/integration/cad-project-app.test.mjs +0 -31
- package/test/integration/cad-project-d1.test.mjs +0 -25
- package/test/integration/cad-project-native.test.mjs +0 -24
- package/test/integration/cad-project-workflow.test.mjs +0 -9
- package/test/integration/cad-project.test.mjs +0 -85
- package/test/integration/cli-help.test.mjs +0 -41
- package/test/integration/cms-app-scaffold.test.mjs +0 -77
- package/test/integration/cms-site-tenancy-contract.test.mjs +0 -268
- package/test/integration/codebaseindex-ingest.test.mjs +0 -255
- package/test/integration/core-client.integration.test.mjs +0 -55
- package/test/integration/database-hosted-honesty.test.mjs +0 -49
- package/test/integration/desktop-keychain-boundary.test.mjs +0 -45
- package/test/integration/error-runtime-rpc.test.mjs +0 -71
- package/test/integration/features-resolve.test.mjs +0 -147
- package/test/integration/hosted-work-host-authority.test.mjs +0 -47
- package/test/integration/icon-registry.test.mjs +0 -67
- package/test/integration/ingest-discover-models.test.mjs +0 -30
- package/test/integration/inspect-path-cli.test.mjs +0 -46
- package/test/integration/install-script.test.mjs +0 -110
- package/test/integration/inventory-core.test.mjs +0 -53
- package/test/integration/inventory-eligibility.test.mjs +0 -59
- package/test/integration/inventory-evidence.test.mjs +0 -125
- package/test/integration/knowledge-rpc.test.mjs +0 -112
- package/test/integration/local-fs.test.mjs +0 -113
- package/test/integration/local-provider-bridge.test.mjs +0 -65
- package/test/integration/local-studio-settings-production.test.mjs +0 -40
- package/test/integration/lockfile-sync.test.mjs +0 -26
- package/test/integration/merkle-cli.test.mjs +0 -61
- package/test/integration/merkle-persistence-identity.test.mjs +0 -48
- package/test/integration/plugins-cloudflare.integration.test.mjs +0 -28
- package/test/integration/provider-env-cli.test.mjs +0 -60
- package/test/integration/provider-factory.test.mjs +0 -197
- package/test/integration/repository-company-graph.test.mjs +0 -90
- package/test/integration/runtime-migrations.test.mjs +0 -87
- package/test/integration/runtime-status.integration.test.mjs +0 -227
- package/test/integration/sam-activity-recovery.test.mjs +0 -147
- package/test/integration/sam-decision.test.mjs +0 -584
- package/test/integration/sam-kernel.test.mjs +0 -99
- package/test/integration/sam-planning-astar.test.mjs +0 -279
- package/test/integration/scaffold-cloudflare.test.mjs +0 -46
- package/test/integration/skill-runtime.test.mjs +0 -240
- package/test/integration/storage-architecture.test.mjs +0 -154
- package/test/integration/store-discovery.test.mjs +0 -44
- package/test/integration/studio-fs-pty-e2e.test.mjs +0 -294
- package/test/integration/terminal-exec.integration.test.mjs +0 -86
- package/test/integration/theme-package-registry.test.mjs +0 -31
- package/test/integration/tool-runtime.test.mjs +0 -124
- package/test/integration/tool-schema.test.mjs +0 -59
- package/test/jr-dev-skill.test.mjs +0 -26
- package/test/knowledge-context-pack.test.mjs +0 -19
- package/test/knowledge-postgres.test.mjs +0 -40
- package/test/knowledge-service.test.mjs +0 -110
- package/test/knowledge.test.mjs +0 -206
- package/test/live/terminal-transport.live.test.mjs +0 -24
- package/test/local-sessions.test.mjs +0 -57
- package/test/local-studio-deploy.test.mjs +0 -83
- package/test/loopback-oauth.test.mjs +0 -53
- package/test/merkle-render.test.mjs +0 -31
- package/test/mini.test.mjs +0 -140
- package/test/model-catalog.test.mjs +0 -70
- package/test/models.test.mjs +0 -309
- package/test/npm10-lock.test.mjs +0 -29
- package/test/ollama.test.mjs +0 -137
- package/test/open-url.test.mjs +0 -64
- package/test/openai-responses.test.mjs +0 -155
- package/test/portable-context.test.mjs +0 -94
- package/test/project-config.test.mjs +0 -81
- package/test/project-rules.test.mjs +0 -44
- package/test/provider-credentials.test.mjs +0 -106
- package/test/rehydrate.test.mjs +0 -25
- package/test/release-hygiene.test.mjs +0 -42
- package/test/repository-snapshot-view.test.mjs +0 -112
- package/test/responses-runner.test.mjs +0 -465
- package/test/runtime-activity.test.mjs +0 -98
- package/test/sdk-worker-contract.test.mjs +0 -72
- package/test/security.test.mjs +0 -266
- package/test/setup-planner.test.mjs +0 -74
- package/test/setup-runtime.test.mjs +0 -51
- package/test/shell.test.mjs +0 -281
- package/test/skills.test.mjs +0 -22
- package/test/smoke.mjs +0 -122
- package/test/telemetry.test.mjs +0 -79
- package/test/terminal/local-pty.mock.test.mjs +0 -153
- package/test/terminal-machine-identity.test.mjs +0 -88
- package/test/theme-portability.test.mjs +0 -14
- package/test/tools-search.test.mjs +0 -73
- package/test/unit/website-assets-bindings.test.mjs +0 -60
- package/test/whoami-resume.test.mjs +0 -157
package/test/cli/go.test.mjs
DELETED
|
@@ -1,128 +0,0 @@
|
|
|
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 { fileURLToPath } from 'node:url';
|
|
7
|
-
import { discoverGoRuntime, resolveProductRoot, ensureProductContract, buildGoProduct } from '../../src/go/index.js';
|
|
8
|
-
import { runGo } from '../../src/commands/go.js';
|
|
9
|
-
|
|
10
|
-
const SDK_ROOT = path.resolve(path.dirname(fileURLToPath(import.meta.url)), '../..');
|
|
11
|
-
|
|
12
|
-
|
|
13
|
-
function tempStateRoot() {
|
|
14
|
-
return fs.mkdtempSync(path.join(os.tmpdir(), 'agentsam-go-test-state-'));
|
|
15
|
-
}
|
|
16
|
-
|
|
17
|
-
test('discoverGoRuntime finds agentsam-go-worker without inventing a sibling', () => {
|
|
18
|
-
const discovery = discoverGoRuntime(SDK_ROOT);
|
|
19
|
-
assert.equal(discovery.go.ok, true);
|
|
20
|
-
assert.ok(discovery.runtime, 'expected Go runtime');
|
|
21
|
-
assert.match(discovery.runtime.module, /agentsam-go-worker/);
|
|
22
|
-
assert.equal(path.basename(discovery.runtime.productRoot), 'agentsam-go-worker');
|
|
23
|
-
const productRoot = resolveProductRoot(discovery, 'agentsam-go-worker');
|
|
24
|
-
const contract = ensureProductContract(productRoot);
|
|
25
|
-
assert.equal(contract.product, 'agentsam-go-worker');
|
|
26
|
-
assert.equal(contract.existing, true);
|
|
27
|
-
assert.deepEqual(contract.created, []);
|
|
28
|
-
});
|
|
29
|
-
|
|
30
|
-
test('ensureProductContract refuses missing product roots instead of scaffolding siblings', () => {
|
|
31
|
-
const missing = path.join(os.tmpdir(), `agentsam-go-missing-${Date.now()}`);
|
|
32
|
-
assert.throws(() => ensureProductContract(missing), /product_root_missing/);
|
|
33
|
-
});
|
|
34
|
-
|
|
35
|
-
test('buildGoProduct emits build receipt after go test/vet/build', () => {
|
|
36
|
-
const discovery = discoverGoRuntime(SDK_ROOT);
|
|
37
|
-
const productRoot = resolveProductRoot(discovery);
|
|
38
|
-
const stateRoot = tempStateRoot();
|
|
39
|
-
const result = buildGoProduct({
|
|
40
|
-
productRoot,
|
|
41
|
-
runtimeRoot: discovery.runtime.runtimeRoot,
|
|
42
|
-
repositoryRoot: discovery.repository_root,
|
|
43
|
-
stateRoot,
|
|
44
|
-
});
|
|
45
|
-
assert.equal(result.receipt.schema, 'agentsam.go-build-receipt.v1');
|
|
46
|
-
assert.equal(result.tests.ok, true);
|
|
47
|
-
assert.equal(result.vet.ok, true);
|
|
48
|
-
assert.ok(result.build.binary);
|
|
49
|
-
assert.match(result.receipt.artifact.digest, /^sha256:[a-f0-9]{64}$/);
|
|
50
|
-
assert.equal(result.receipt.tests.runtime_probe, true);
|
|
51
|
-
assert.match(result.receipt.source.identity, /^git:[a-f0-9]{40}$/);
|
|
52
|
-
assert.equal(result.probe.checks.source_identity, true);
|
|
53
|
-
assert.equal(result.probe.checks.source_commit, true);
|
|
54
|
-
assert.equal(result.probe.checks.error_envelope, true);
|
|
55
|
-
assert.equal(result.probe.checks.clean_shutdown, true);
|
|
56
|
-
assert.ok(fs.existsSync(result.receiptPath));
|
|
57
|
-
});
|
|
58
|
-
|
|
59
|
-
test('agentsam go build --json exposes only portable build paths', async () => {
|
|
60
|
-
const stateRoot = tempStateRoot();
|
|
61
|
-
const chunks = [];
|
|
62
|
-
|
|
63
|
-
const result = await runGo(
|
|
64
|
-
['build', '--json'],
|
|
65
|
-
{
|
|
66
|
-
write: (value) => chunks.push(String(value)),
|
|
67
|
-
stateRoot,
|
|
68
|
-
},
|
|
69
|
-
);
|
|
70
|
-
|
|
71
|
-
assert.ok(path.isAbsolute(result.receiptPath), 'internal execution keeps absolute receipt path');
|
|
72
|
-
assert.ok(path.isAbsolute(result.build.binary), 'internal execution keeps absolute binary path');
|
|
73
|
-
|
|
74
|
-
const output = chunks.join('');
|
|
75
|
-
const parsed = JSON.parse(output);
|
|
76
|
-
|
|
77
|
-
assert.equal(path.isAbsolute(parsed.receiptPath), false);
|
|
78
|
-
assert.equal(path.isAbsolute(parsed.build.binary), false);
|
|
79
|
-
assert.equal(path.isAbsolute(parsed.receipt.runtime.module_root), false);
|
|
80
|
-
assert.equal(Object.hasOwn(parsed.probe || {}, 'origin'), false);
|
|
81
|
-
assert.equal(Object.hasOwn(parsed.receipt?.probe || {}, 'origin'), false);
|
|
82
|
-
assert.equal(output.includes(SDK_ROOT), false);
|
|
83
|
-
});
|
|
84
|
-
|
|
85
|
-
test('agentsam go --cloudflare agentsam-go-worker --skip-deploy is idempotent', async () => {
|
|
86
|
-
const stateRoot = tempStateRoot();
|
|
87
|
-
const chunks = [];
|
|
88
|
-
const write = (v) => chunks.push(String(v));
|
|
89
|
-
const first = await runGo(
|
|
90
|
-
['--cloudflare', 'agentsam-go-worker', '--skip-deploy', '--json'],
|
|
91
|
-
{ write, stateRoot },
|
|
92
|
-
);
|
|
93
|
-
assert.equal(first.ok, true);
|
|
94
|
-
assert.equal(first.product, 'agentsam-go-worker');
|
|
95
|
-
assert.equal(first.scaffold_changes_required, false);
|
|
96
|
-
assert.equal(first.mode, 'self_host');
|
|
97
|
-
assert.equal(first.deploy.registry.reason, 'self_host_registry_isolated');
|
|
98
|
-
|
|
99
|
-
const chunks2 = [];
|
|
100
|
-
const second = await runGo(
|
|
101
|
-
['--cloudflare', 'agentsam-go-worker', '--skip-deploy', '--json'],
|
|
102
|
-
{
|
|
103
|
-
write: (v) => chunks2.push(String(v)),
|
|
104
|
-
stateRoot,
|
|
105
|
-
},
|
|
106
|
-
);
|
|
107
|
-
assert.equal(second.ok, true);
|
|
108
|
-
assert.equal(second.existing_product, true);
|
|
109
|
-
assert.equal(second.scaffold_changes_required, false);
|
|
110
|
-
assert.ok(second.deploy.receiptPath);
|
|
111
|
-
assert.ok(fs.existsSync(second.deploy.productPath));
|
|
112
|
-
});
|
|
113
|
-
|
|
114
|
-
test('agentsam go status --json reports discovery', async () => {
|
|
115
|
-
const stateRoot = tempStateRoot();
|
|
116
|
-
const chunks = [];
|
|
117
|
-
const result = await runGo(
|
|
118
|
-
['status', '--json'],
|
|
119
|
-
{
|
|
120
|
-
write: (v) => chunks.push(String(v)),
|
|
121
|
-
stateRoot,
|
|
122
|
-
},
|
|
123
|
-
);
|
|
124
|
-
assert.equal(result.ok, true);
|
|
125
|
-
assert.ok(result.discovery.go.ok);
|
|
126
|
-
const parsed = JSON.parse(chunks.join(''));
|
|
127
|
-
assert.equal(parsed.product, 'agentsam-go-worker');
|
|
128
|
-
});
|
|
@@ -1,268 +0,0 @@
|
|
|
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
|
-
|
|
7
|
-
import {
|
|
8
|
-
getSecureProviderKey,
|
|
9
|
-
setSecureProviderKey,
|
|
10
|
-
deleteSecureProviderKey,
|
|
11
|
-
listSecureConfiguredProviders,
|
|
12
|
-
hydrateSecureCredentials,
|
|
13
|
-
localVaultPath,
|
|
14
|
-
localVaultSaltPath,
|
|
15
|
-
} from '../../src/security/local-vault.js';
|
|
16
|
-
import { resolveExecutableCommand } from '../../src/security/process.js';
|
|
17
|
-
import {
|
|
18
|
-
resolveProviderCredential,
|
|
19
|
-
setProviderCredential,
|
|
20
|
-
removeProviderCredential,
|
|
21
|
-
exportProviderEnvProfile,
|
|
22
|
-
} from '../../src/lib/provider-credentials.js';
|
|
23
|
-
import {
|
|
24
|
-
validateAndSaveProviderCredential,
|
|
25
|
-
providerChoices,
|
|
26
|
-
runProviders,
|
|
27
|
-
} from '../../src/commands/providers.js';
|
|
28
|
-
import { renderModelsStatus } from '../../src/commands/models.js';
|
|
29
|
-
|
|
30
|
-
// picocolors color-detection differs between local runs and CI runners (CI often
|
|
31
|
-
// reports TTY-like support that enables ANSI output) - strip escape codes before
|
|
32
|
-
// asserting on rendered text content so this test checks content, not incidental
|
|
33
|
-
// terminal color state.
|
|
34
|
-
// eslint-disable-next-line no-control-regex
|
|
35
|
-
const ANSI_PATTERN = /\x1B\[[0-9;]*m/g;
|
|
36
|
-
const stripAnsi = (s) => String(s).replace(ANSI_PATTERN, '');
|
|
37
|
-
|
|
38
|
-
function createTempHome(t) {
|
|
39
|
-
const home = fs.mkdtempSync(path.join(os.tmpdir(), 'agentsam-vault-test-'));
|
|
40
|
-
t.after(() => fs.rmSync(home, { recursive: true, force: true }));
|
|
41
|
-
return home;
|
|
42
|
-
}
|
|
43
|
-
|
|
44
|
-
test('resolveExecutableCommand resolves Windows .cmd shims with shell: true on win32', () => {
|
|
45
|
-
const npxWin = resolveExecutableCommand('npx', 'win32');
|
|
46
|
-
assert.equal(npxWin.command, 'npx.cmd');
|
|
47
|
-
assert.equal(npxWin.shell, true);
|
|
48
|
-
|
|
49
|
-
const npmWin = resolveExecutableCommand('npm', 'win32');
|
|
50
|
-
assert.equal(npmWin.command, 'npm.cmd');
|
|
51
|
-
assert.equal(npmWin.shell, true);
|
|
52
|
-
|
|
53
|
-
const wranglerWin = resolveExecutableCommand('wrangler', 'win32');
|
|
54
|
-
assert.equal(wranglerWin.command, 'wrangler.cmd');
|
|
55
|
-
assert.equal(wranglerWin.shell, true);
|
|
56
|
-
|
|
57
|
-
const scriptWin = resolveExecutableCommand('build.bat', 'win32');
|
|
58
|
-
assert.equal(scriptWin.command, 'build.bat');
|
|
59
|
-
assert.equal(scriptWin.shell, true);
|
|
60
|
-
|
|
61
|
-
// Linux and macOS are untouched
|
|
62
|
-
const npxMac = resolveExecutableCommand('npx', 'darwin');
|
|
63
|
-
assert.equal(npxMac.command, 'npx');
|
|
64
|
-
assert.equal(npxMac.shell, false);
|
|
65
|
-
|
|
66
|
-
const npmLinux = resolveExecutableCommand('npm', 'linux');
|
|
67
|
-
assert.equal(npmLinux.command, 'npm');
|
|
68
|
-
assert.equal(npmLinux.shell, false);
|
|
69
|
-
});
|
|
70
|
-
|
|
71
|
-
test('local vault encrypts with AES-256-GCM and never writes plaintext secrets to disk', (t) => {
|
|
72
|
-
const home = createTempHome(t);
|
|
73
|
-
const opts = { home, disableOsStore: true };
|
|
74
|
-
|
|
75
|
-
const secret = 'sk-proj-testsecret1234567890abcdef';
|
|
76
|
-
setSecureProviderKey('openai', secret, opts);
|
|
77
|
-
|
|
78
|
-
const retrieved = getSecureProviderKey('openai', opts);
|
|
79
|
-
assert.equal(retrieved.value, secret);
|
|
80
|
-
assert.equal(retrieved.source, 'local_vault');
|
|
81
|
-
|
|
82
|
-
// Verify disk contents
|
|
83
|
-
const encFile = localVaultPath(opts);
|
|
84
|
-
assert.equal(fs.existsSync(encFile), true);
|
|
85
|
-
const rawText = fs.readFileSync(encFile, 'utf8');
|
|
86
|
-
|
|
87
|
-
// Plaintext MUST NOT appear anywhere in the file
|
|
88
|
-
assert.equal(rawText.includes(secret), false);
|
|
89
|
-
|
|
90
|
-
// Must have JSON with iv, tag, and data
|
|
91
|
-
const parsed = JSON.parse(rawText);
|
|
92
|
-
assert.ok(parsed.secrets.openai.iv);
|
|
93
|
-
assert.ok(parsed.secrets.openai.tag);
|
|
94
|
-
assert.ok(parsed.secrets.openai.data);
|
|
95
|
-
|
|
96
|
-
// Salt file must exist with restrictive permissions
|
|
97
|
-
const saltFile = localVaultSaltPath(opts);
|
|
98
|
-
assert.equal(fs.existsSync(saltFile), true);
|
|
99
|
-
if (process.platform !== 'win32') {
|
|
100
|
-
assert.equal(fs.statSync(saltFile).mode & 0o777, 0o600);
|
|
101
|
-
assert.equal(fs.statSync(encFile).mode & 0o777, 0o600);
|
|
102
|
-
}
|
|
103
|
-
});
|
|
104
|
-
|
|
105
|
-
test('local vault detects tampering of encrypted ciphertext', (t) => {
|
|
106
|
-
const home = createTempHome(t);
|
|
107
|
-
const opts = { home, disableOsStore: true };
|
|
108
|
-
|
|
109
|
-
setSecureProviderKey('anthropic', 'sk-ant-test-key-12345', opts);
|
|
110
|
-
|
|
111
|
-
// Tamper with the ciphertext
|
|
112
|
-
const encFile = localVaultPath(opts);
|
|
113
|
-
const parsed = JSON.parse(fs.readFileSync(encFile, 'utf8'));
|
|
114
|
-
const originalData = parsed.secrets.anthropic.data;
|
|
115
|
-
// Flip the last hex byte
|
|
116
|
-
const tamperedData = originalData.slice(0, -2) + (originalData.slice(-2) === 'aa' ? 'bb' : 'aa');
|
|
117
|
-
parsed.secrets.anthropic.data = tamperedData;
|
|
118
|
-
fs.writeFileSync(encFile, JSON.stringify(parsed));
|
|
119
|
-
|
|
120
|
-
// Decryption must fail and return null safely rather than corrupt data
|
|
121
|
-
const retrieved = getSecureProviderKey('anthropic', opts);
|
|
122
|
-
assert.equal(retrieved, null);
|
|
123
|
-
});
|
|
124
|
-
|
|
125
|
-
test('local vault stores and retrieves Cloudflare accountId alongside token', (t) => {
|
|
126
|
-
const home = createTempHome(t);
|
|
127
|
-
const opts = { home, disableOsStore: true };
|
|
128
|
-
|
|
129
|
-
setSecureProviderKey('cloudflare', { value: 'cf-token-123', accountId: 'abcdef0123456789abcdef0123456789' }, opts);
|
|
130
|
-
const retrieved = getSecureProviderKey('cloudflare', opts);
|
|
131
|
-
|
|
132
|
-
assert.equal(retrieved.value, 'cf-token-123');
|
|
133
|
-
assert.equal(retrieved.accountId, 'abcdef0123456789abcdef0123456789');
|
|
134
|
-
});
|
|
135
|
-
|
|
136
|
-
test('hydrateSecureCredentials populates process.env for unconfigured providers without overwriting', (t) => {
|
|
137
|
-
const home = createTempHome(t);
|
|
138
|
-
const opts = { home, disableOsStore: true };
|
|
139
|
-
|
|
140
|
-
setSecureProviderKey('gemini', 'gemini-key-val-789', opts);
|
|
141
|
-
|
|
142
|
-
const mockEnv = {
|
|
143
|
-
EXISTING_KEY: 'pre-existing',
|
|
144
|
-
};
|
|
145
|
-
|
|
146
|
-
const hydrated = hydrateSecureCredentials(mockEnv, opts);
|
|
147
|
-
assert.ok(hydrated.includes('gemini'));
|
|
148
|
-
assert.equal(mockEnv.GEMINI_API_KEY, 'gemini-key-val-789');
|
|
149
|
-
|
|
150
|
-
// Second run does not overwrite
|
|
151
|
-
mockEnv.GEMINI_API_KEY = 'user-override';
|
|
152
|
-
hydrateSecureCredentials(mockEnv, opts);
|
|
153
|
-
assert.equal(mockEnv.GEMINI_API_KEY, 'user-override');
|
|
154
|
-
});
|
|
155
|
-
|
|
156
|
-
test('resolveProviderCredential resolves keys from local secure vault across any directory', (t) => {
|
|
157
|
-
const home = createTempHome(t);
|
|
158
|
-
const opts = { home, disableOsStore: true };
|
|
159
|
-
|
|
160
|
-
setProviderCredential('cursor', 'cur-key-secret-456', opts);
|
|
161
|
-
|
|
162
|
-
const resolved = resolveProviderCredential('cursor', { env: {}, home, disableOsStore: true });
|
|
163
|
-
assert.equal(resolved.configured, true);
|
|
164
|
-
assert.equal(resolved.value, 'cur-key-secret-456');
|
|
165
|
-
|
|
166
|
-
// Deleting removes it
|
|
167
|
-
removeProviderCredential('cursor', opts);
|
|
168
|
-
const afterRemove = resolveProviderCredential('cursor', { env: {}, home, disableOsStore: true });
|
|
169
|
-
assert.equal(afterRemove.configured, false);
|
|
170
|
-
});
|
|
171
|
-
|
|
172
|
-
test('validateAndSaveProviderCredential rejects invalid key and does NOT persist it', async (t) => {
|
|
173
|
-
const home = createTempHome(t);
|
|
174
|
-
const opts = {
|
|
175
|
-
home,
|
|
176
|
-
disableOsStore: true,
|
|
177
|
-
fetchImpl: async () => ({
|
|
178
|
-
ok: false,
|
|
179
|
-
status: 401,
|
|
180
|
-
json: async () => ({ error: { message: 'Incorrect API key provided' } }),
|
|
181
|
-
}),
|
|
182
|
-
};
|
|
183
|
-
|
|
184
|
-
const result = await validateAndSaveProviderCredential('openai', 'sk-invalid-test-key', opts);
|
|
185
|
-
assert.equal(result.ok, false);
|
|
186
|
-
assert.equal(result.saved, false);
|
|
187
|
-
assert.match(result.error, /Incorrect API key/i);
|
|
188
|
-
|
|
189
|
-
// Verify it was NOT stored in the vault!
|
|
190
|
-
const retrieved = getSecureProviderKey('openai', opts);
|
|
191
|
-
assert.equal(retrieved, null);
|
|
192
|
-
});
|
|
193
|
-
|
|
194
|
-
test('validateAndSaveProviderCredential verifies valid key and saves ONLY to local vault without plaintext file', async (t) => {
|
|
195
|
-
const home = createTempHome(t);
|
|
196
|
-
const opts = {
|
|
197
|
-
home,
|
|
198
|
-
disableOsStore: true,
|
|
199
|
-
fetchImpl: async () => ({
|
|
200
|
-
ok: true,
|
|
201
|
-
status: 200,
|
|
202
|
-
json: async () => ({
|
|
203
|
-
data: [{ id: 'gpt-4o' }, { id: 'gpt-4o-mini' }],
|
|
204
|
-
}),
|
|
205
|
-
}),
|
|
206
|
-
};
|
|
207
|
-
|
|
208
|
-
const result = await validateAndSaveProviderCredential('openai', 'sk-valid-key-xyz', opts);
|
|
209
|
-
assert.equal(result.ok, true);
|
|
210
|
-
assert.equal(result.saved, true);
|
|
211
|
-
assert.equal(result.model_count, 2);
|
|
212
|
-
|
|
213
|
-
// Verify it was saved to local vault
|
|
214
|
-
const retrieved = getSecureProviderKey('openai', opts);
|
|
215
|
-
assert.equal(retrieved.value, 'sk-valid-key-xyz');
|
|
216
|
-
|
|
217
|
-
// CRITICAL: Plaintext .env profile file MUST NOT be created automatically!
|
|
218
|
-
const plaintextFile = path.join(home, '.agentsam', 'env.d', 'openai.env');
|
|
219
|
-
assert.equal(fs.existsSync(plaintextFile), false, 'Plaintext .env file must NOT exist after secure provider setup');
|
|
220
|
-
});
|
|
221
|
-
|
|
222
|
-
test('exportProviderEnvProfile and agentsam providers export create plaintext .env file ONLY on explicit opt-in', async (t) => {
|
|
223
|
-
const home = createTempHome(t);
|
|
224
|
-
const opts = { home, disableOsStore: true };
|
|
225
|
-
|
|
226
|
-
// Set up provider key in secure vault
|
|
227
|
-
setProviderCredential('anthropic', 'sk-ant-test-export-key', opts);
|
|
228
|
-
|
|
229
|
-
// Confirm NO plaintext file exists yet
|
|
230
|
-
const plaintextFile = path.join(home, '.agentsam', 'env.d', 'anthropic.env');
|
|
231
|
-
assert.equal(fs.existsSync(plaintextFile), false);
|
|
232
|
-
|
|
233
|
-
// Explicit opt-in export via CLI command
|
|
234
|
-
let output = '';
|
|
235
|
-
const exported = await runProviders(['export', 'anthropic'], {
|
|
236
|
-
...opts,
|
|
237
|
-
write: (text) => { output += text; },
|
|
238
|
-
});
|
|
239
|
-
|
|
240
|
-
assert.equal(exported.provider, 'anthropic');
|
|
241
|
-
assert.equal(fs.existsSync(plaintextFile), true);
|
|
242
|
-
const content = fs.readFileSync(plaintextFile, 'utf8');
|
|
243
|
-
assert.match(content, /ANTHROPIC_API_KEY="sk-ant-test-export-key"/);
|
|
244
|
-
assert.match(output, /Exported anthropic profile/);
|
|
245
|
-
});
|
|
246
|
-
|
|
247
|
-
test('renderModelsStatus shows tip: Select your preferred provider when providers are unconfigured', () => {
|
|
248
|
-
const status = {
|
|
249
|
-
providers: [
|
|
250
|
-
{ id: 'openai', label: 'OpenAI', configured: false, credential: 'OPENAI_API_KEY' },
|
|
251
|
-
{ id: 'anthropic', label: 'Anthropic', configured: false, credential: 'ANTHROPIC_API_KEY' },
|
|
252
|
-
],
|
|
253
|
-
discovery: {},
|
|
254
|
-
providerModels: {},
|
|
255
|
-
local: { online: false, models: [] },
|
|
256
|
-
};
|
|
257
|
-
|
|
258
|
-
const output = stripAnsi(renderModelsStatus(status));
|
|
259
|
-
assert.match(output, /Tip:\s*Select your preferred provider/i);
|
|
260
|
-
});
|
|
261
|
-
|
|
262
|
-
test('providerChoices returns valid choice list for select picker', () => {
|
|
263
|
-
const choices = providerChoices();
|
|
264
|
-
assert.ok(choices.length >= 6);
|
|
265
|
-
assert.ok(choices.some((c) => c.value === 'openai'));
|
|
266
|
-
assert.ok(choices.some((c) => c.value === 'anthropic'));
|
|
267
|
-
assert.ok(choices.some((c) => c.value === 'gemini'));
|
|
268
|
-
});
|
|
@@ -1,34 +0,0 @@
|
|
|
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
|
-
import { resolveMachineBinary } from '../../src/commands/machine-binary.js';
|
|
8
|
-
|
|
9
|
-
const root = path.resolve(path.dirname(fileURLToPath(import.meta.url)), '../..');
|
|
10
|
-
|
|
11
|
-
test('machine command is catalogued as machine.inspect', () => {
|
|
12
|
-
const entry = getCliCommand('machine');
|
|
13
|
-
assert.equal(entry?.id, 'machine');
|
|
14
|
-
assert.equal(entry?.operation, 'machine.inspect');
|
|
15
|
-
assert.equal(entry?.common, true);
|
|
16
|
-
});
|
|
17
|
-
|
|
18
|
-
test('machine crate + CLI sources exist for graduation', () => {
|
|
19
|
-
assert.equal(fs.existsSync(path.join(root, 'native/agentsam-machine/Cargo.toml')), true);
|
|
20
|
-
assert.equal(fs.existsSync(path.join(root, 'native/agentsam-machine/cli/src/main.rs')), true);
|
|
21
|
-
assert.equal(fs.existsSync(path.join(root, 'src/commands/machine.js')), true);
|
|
22
|
-
assert.equal(fs.existsSync(path.join(root, 'src/commands/machine-binary.js')), true);
|
|
23
|
-
});
|
|
24
|
-
|
|
25
|
-
test('resolveMachineBinary finds crate binary or cargo fallback in this repo', () => {
|
|
26
|
-
const resolution = resolveMachineBinary();
|
|
27
|
-
assert.notEqual(resolution.kind, 'missing');
|
|
28
|
-
if (resolution.kind === 'binary') {
|
|
29
|
-
assert.equal(fs.existsSync(resolution.path), true);
|
|
30
|
-
} else {
|
|
31
|
-
assert.equal(resolution.kind, 'cargo');
|
|
32
|
-
assert.equal(fs.existsSync(resolution.manifest), true);
|
|
33
|
-
}
|
|
34
|
-
});
|
|
@@ -1,256 +0,0 @@
|
|
|
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
|
-
|
|
7
|
-
import {
|
|
8
|
-
MCP_PRESETS,
|
|
9
|
-
deleteMcpServer,
|
|
10
|
-
fetchExternalClientRegistry,
|
|
11
|
-
fetchMcpServerCatalog,
|
|
12
|
-
getClientConfigPath,
|
|
13
|
-
getClientRegistryCachePath,
|
|
14
|
-
getServerCatalogCachePath,
|
|
15
|
-
getSessionToolReceipts,
|
|
16
|
-
inspectClientAdapter,
|
|
17
|
-
isClientRegistered,
|
|
18
|
-
listKnownServers,
|
|
19
|
-
listMcpServers,
|
|
20
|
-
listRegisteredClients,
|
|
21
|
-
readMcpServer,
|
|
22
|
-
recordToolReceipt,
|
|
23
|
-
removeServerFromClient,
|
|
24
|
-
resolveServerPreset,
|
|
25
|
-
summarizeToolReceipts,
|
|
26
|
-
syncServerToClient,
|
|
27
|
-
writeMcpServer,
|
|
28
|
-
} from '../../src/mcp/index.js';
|
|
29
|
-
import { runMcp } from '../../src/commands/mcp.js';
|
|
30
|
-
|
|
31
|
-
function tempHome() {
|
|
32
|
-
return fs.mkdtempSync(path.join(os.tmpdir(), 'agentsam-mcp-test-'));
|
|
33
|
-
}
|
|
34
|
-
|
|
35
|
-
test('MCP authority store manages servers under ~/.agentsam/mcp with safe permissions', () => {
|
|
36
|
-
const home = tempHome();
|
|
37
|
-
const config = {
|
|
38
|
-
url: 'https://mcp.inneranimalmedia.com/mcp',
|
|
39
|
-
auth: { type: 'bearer', token: 'iam_token_abc' },
|
|
40
|
-
clients: ['cursor', 'claude'],
|
|
41
|
-
};
|
|
42
|
-
|
|
43
|
-
const written = writeMcpServer('inneranimalmedia', config, { home });
|
|
44
|
-
assert.equal(written.name, 'inneranimalmedia');
|
|
45
|
-
assert.equal(written.url, 'https://mcp.inneranimalmedia.com/mcp');
|
|
46
|
-
|
|
47
|
-
const read = readMcpServer('inneranimalmedia', { home });
|
|
48
|
-
assert.equal(read.name, 'inneranimalmedia');
|
|
49
|
-
assert.equal(read.auth.token, 'iam_token_abc');
|
|
50
|
-
assert.deepEqual(read.clients, ['cursor', 'claude']);
|
|
51
|
-
|
|
52
|
-
const list = listMcpServers({ home });
|
|
53
|
-
assert.equal(list.length, 1);
|
|
54
|
-
assert.equal(list[0].name, 'inneranimalmedia');
|
|
55
|
-
|
|
56
|
-
const deleted = deleteMcpServer('inneranimalmedia', { home });
|
|
57
|
-
assert.equal(deleted, true);
|
|
58
|
-
assert.equal(readMcpServer('inneranimalmedia', { home }), null);
|
|
59
|
-
});
|
|
60
|
-
|
|
61
|
-
test('MCP external client registry recognizes chatgpt, claude, cursor — not CF portals', async () => {
|
|
62
|
-
const home = tempHome();
|
|
63
|
-
|
|
64
|
-
// Baseline seed / cached client list
|
|
65
|
-
const clients = listRegisteredClients({ home });
|
|
66
|
-
const keys = clients.map((c) => c.client_key);
|
|
67
|
-
assert.ok(keys.includes('chatgpt'), 'ChatGPT is recognized in the external client registry');
|
|
68
|
-
assert.ok(keys.includes('cursor'), 'Cursor is recognized in the external client registry');
|
|
69
|
-
assert.ok(keys.includes('claude'), 'Claude is recognized in the external client registry');
|
|
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');
|
|
72
|
-
|
|
73
|
-
assert.equal(isClientRegistered('chatgpt', { home }), true);
|
|
74
|
-
assert.equal(isClientRegistered('cursor', { home }), true);
|
|
75
|
-
assert.equal(isClientRegistered('cf_bindings_mcp', { home }), false);
|
|
76
|
-
assert.equal(isClientRegistered('nonexistent_client_xyz', { home }), false);
|
|
77
|
-
|
|
78
|
-
// Cache path is created upon writing
|
|
79
|
-
const cachePath = getClientRegistryCachePath({ home });
|
|
80
|
-
assert.equal(cachePath.endsWith('client-registry-cache.json'), true);
|
|
81
|
-
});
|
|
82
|
-
|
|
83
|
-
test('MCP client adapters materialize Cursor, Claude, and ChatGPT configurations cleanly', () => {
|
|
84
|
-
const home = tempHome();
|
|
85
|
-
const serverConfig = {
|
|
86
|
-
url: 'https://mcp.inneranimalmedia.com/mcp',
|
|
87
|
-
auth: { type: 'bearer', token: 'oauth_cursor_123' },
|
|
88
|
-
};
|
|
89
|
-
|
|
90
|
-
// Pre-seed an existing server in Cursor config to ensure no clobbering
|
|
91
|
-
const cursorConfigPath = getClientConfigPath('cursor', { home });
|
|
92
|
-
fs.mkdirSync(path.dirname(cursorConfigPath), { recursive: true });
|
|
93
|
-
fs.writeFileSync(
|
|
94
|
-
cursorConfigPath,
|
|
95
|
-
JSON.stringify({ mcpServers: { other_server: { url: 'http://localhost:8080' } } })
|
|
96
|
-
);
|
|
97
|
-
|
|
98
|
-
// Sync to Cursor
|
|
99
|
-
const cursorResult = syncServerToClient('cursor', 'inneranimalmedia', serverConfig, { home });
|
|
100
|
-
assert.equal(cursorResult.synced, true);
|
|
101
|
-
|
|
102
|
-
const cursorContent = JSON.parse(fs.readFileSync(cursorConfigPath, 'utf8'));
|
|
103
|
-
assert.ok(cursorContent.mcpServers.other_server, 'Preserved other server in Cursor config');
|
|
104
|
-
assert.equal(cursorContent.mcpServers.inneranimalmedia.url, 'https://mcp.inneranimalmedia.com/mcp');
|
|
105
|
-
assert.equal(cursorContent.mcpServers.inneranimalmedia.headers.Authorization, 'Bearer oauth_cursor_123');
|
|
106
|
-
assert.equal(cursorContent.mcpServers.inneranimalmedia.headers.Accept, 'application/json, text/event-stream');
|
|
107
|
-
|
|
108
|
-
// Inspect Cursor adapter
|
|
109
|
-
const inspection = inspectClientAdapter('cursor', 'inneranimalmedia', { home });
|
|
110
|
-
assert.equal(inspection.configured, true);
|
|
111
|
-
assert.equal(inspection.present, true);
|
|
112
|
-
|
|
113
|
-
// Sync to Claude
|
|
114
|
-
const claudeResult = syncServerToClient('claude', 'inneranimalmedia', serverConfig, { home });
|
|
115
|
-
assert.equal(claudeResult.synced, true);
|
|
116
|
-
const claudeConfigPath = getClientConfigPath('claude', { home });
|
|
117
|
-
const claudeContent = JSON.parse(fs.readFileSync(claudeConfigPath, 'utf8'));
|
|
118
|
-
assert.equal(claudeContent.mcpServers.inneranimalmedia.url, 'https://mcp.inneranimalmedia.com/mcp');
|
|
119
|
-
|
|
120
|
-
// Sync to ChatGPT
|
|
121
|
-
const chatgptResult = syncServerToClient('chatgpt', 'inneranimalmedia', serverConfig, { home });
|
|
122
|
-
assert.equal(chatgptResult.synced, true);
|
|
123
|
-
const chatgptConfigPath = getClientConfigPath('chatgpt', { home });
|
|
124
|
-
assert.ok(fs.existsSync(chatgptConfigPath));
|
|
125
|
-
const chatgptContent = JSON.parse(fs.readFileSync(chatgptConfigPath, 'utf8'));
|
|
126
|
-
assert.equal(chatgptContent.name, 'inneranimalmedia');
|
|
127
|
-
assert.equal(chatgptContent.server_url, 'https://mcp.inneranimalmedia.com/mcp');
|
|
128
|
-
assert.equal(chatgptContent.schema, 'agentsam.mcp.client-adapter.chatgpt.v1');
|
|
129
|
-
|
|
130
|
-
// Sync to AgentSam family adapter (~/.agentsam/mcp.json)
|
|
131
|
-
const agentsamResult = syncServerToClient('agentsam', 'inneranimalmedia', serverConfig, { home });
|
|
132
|
-
assert.equal(agentsamResult.synced, true);
|
|
133
|
-
const agentsamConfigPath = getClientConfigPath('agentsam', { home });
|
|
134
|
-
assert.equal(agentsamConfigPath, path.join(home, '.agentsam', 'mcp.json'));
|
|
135
|
-
assert.ok(fs.existsSync(agentsamConfigPath));
|
|
136
|
-
const agentsamContent = JSON.parse(fs.readFileSync(agentsamConfigPath, 'utf8'));
|
|
137
|
-
assert.equal(agentsamContent.mcpServers.inneranimalmedia.url, 'https://mcp.inneranimalmedia.com/mcp');
|
|
138
|
-
assert.equal(agentsamContent.mcpServers.inneranimalmedia.headers.Authorization, 'Bearer oauth_cursor_123');
|
|
139
|
-
|
|
140
|
-
// Remove from Cursor
|
|
141
|
-
const removeResult = removeServerFromClient('cursor', 'inneranimalmedia', { home });
|
|
142
|
-
assert.equal(removeResult.removed, true);
|
|
143
|
-
const postRemove = JSON.parse(fs.readFileSync(cursorConfigPath, 'utf8'));
|
|
144
|
-
assert.equal(postRemove.mcpServers.inneranimalmedia, undefined);
|
|
145
|
-
assert.ok(postRemove.mcpServers.other_server, 'Still preserved other server');
|
|
146
|
-
|
|
147
|
-
// Remove from AgentSam family adapter
|
|
148
|
-
const removeAgentsam = removeServerFromClient('agentsam', 'inneranimalmedia', { home });
|
|
149
|
-
assert.equal(removeAgentsam.removed, true);
|
|
150
|
-
const postRemoveAgentsam = JSON.parse(fs.readFileSync(agentsamConfigPath, 'utf8'));
|
|
151
|
-
assert.equal(postRemoveAgentsam.mcpServers.inneranimalmedia, undefined);
|
|
152
|
-
|
|
153
|
-
// Remove from ChatGPT
|
|
154
|
-
const removeChatgpt = removeServerFromClient('chatgpt', 'inneranimalmedia', { home });
|
|
155
|
-
assert.equal(removeChatgpt.removed, true);
|
|
156
|
-
assert.equal(fs.existsSync(chatgptConfigPath), false);
|
|
157
|
-
});
|
|
158
|
-
|
|
159
|
-
test('MCP server catalog resolves CF portal bundles + IAM without fabricated health', () => {
|
|
160
|
-
const home = tempHome();
|
|
161
|
-
const catalog = listKnownServers({ home });
|
|
162
|
-
assert.ok(catalog.length >= 8);
|
|
163
|
-
|
|
164
|
-
const cfApi = resolveServerPreset('cloudflare-api', { home });
|
|
165
|
-
assert.ok(cfApi);
|
|
166
|
-
assert.equal(cfApi.url, 'https://mcp.cloudflare.com/mcp');
|
|
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'));
|
|
174
|
-
|
|
175
|
-
const iam = resolveServerPreset('inneranimalmedia', { home });
|
|
176
|
-
assert.ok(iam);
|
|
177
|
-
assert.equal(iam.url, 'https://mcp.inneranimalmedia.com/mcp');
|
|
178
|
-
});
|
|
179
|
-
|
|
180
|
-
test('MCP telemetry logs tool receipts and computes accurate summaries', () => {
|
|
181
|
-
const home = tempHome();
|
|
182
|
-
|
|
183
|
-
recordToolReceipt({ tool_key: 'github_read', source_client: 'cursor', duration_ms: 120 }, { home });
|
|
184
|
-
recordToolReceipt({ tool_key: 'mcp:d1_query', source_client: 'cursor_mcp', duration_ms: 45 }, { home });
|
|
185
|
-
recordToolReceipt({ tool_key: 'terminal_exec', source_client: 'agentsam', duration_ms: 800 }, { home });
|
|
186
|
-
recordToolReceipt({ tool_key: 'mcp:tool_broken', error_code: 'TIMEOUT', duration_ms: 5000 }, { home });
|
|
187
|
-
|
|
188
|
-
const receipts = getSessionToolReceipts({ home });
|
|
189
|
-
assert.equal(receipts.length, 4);
|
|
190
|
-
|
|
191
|
-
const summary = summarizeToolReceipts(receipts);
|
|
192
|
-
assert.equal(summary.tool_call_count, 4);
|
|
193
|
-
assert.equal(summary.mcp_call_count, 2);
|
|
194
|
-
assert.equal(summary.github_call_count, 1);
|
|
195
|
-
assert.equal(summary.d1_call_count, 1);
|
|
196
|
-
assert.equal(summary.terminal_call_count, 1);
|
|
197
|
-
assert.equal(summary.failure_count, 1);
|
|
198
|
-
assert.equal(summary.success_count, 3);
|
|
199
|
-
});
|
|
200
|
-
|
|
201
|
-
test('agentsam mcp CLI handles add, list, status, doctor, and remove end-to-end', async () => {
|
|
202
|
-
const home = tempHome();
|
|
203
|
-
const logs = [];
|
|
204
|
-
const write = (str) => logs.push(str);
|
|
205
|
-
|
|
206
|
-
// Test --help output surfaces chatgpt and known catalog servers
|
|
207
|
-
await runMcp(['--help'], { home, write });
|
|
208
|
-
const helpText = logs.join('\n');
|
|
209
|
-
assert.ok(helpText.includes('chatgpt'), 'Help text displays ChatGPT as a recognized client');
|
|
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');
|
|
212
|
-
logs.length = 0;
|
|
213
|
-
|
|
214
|
-
// Add inneranimalmedia preset for chatgpt client
|
|
215
|
-
const addRes = await runMcp(
|
|
216
|
-
['add', 'inneranimalmedia', '--client', 'chatgpt', '--token', 'test_tok_777', '--json'],
|
|
217
|
-
{ home, write }
|
|
218
|
-
);
|
|
219
|
-
assert.equal(addRes.ok, true);
|
|
220
|
-
assert.equal(addRes.server.name, 'inneranimalmedia');
|
|
221
|
-
assert.equal(addRes.server.auth.token, 'test_tok_777');
|
|
222
|
-
assert.equal(addRes.syncedAdapters[0].client, 'chatgpt');
|
|
223
|
-
|
|
224
|
-
// List
|
|
225
|
-
const listRes = await runMcp(['list', '--json'], { home, write });
|
|
226
|
-
assert.equal(listRes.length, 1);
|
|
227
|
-
assert.equal(listRes[0].name, 'inneranimalmedia');
|
|
228
|
-
|
|
229
|
-
// List catalog
|
|
230
|
-
const catalogRes = await runMcp(['list', '--catalog', '--json'], { home, write });
|
|
231
|
-
assert.ok(catalogRes.length >= 8);
|
|
232
|
-
|
|
233
|
-
// Status
|
|
234
|
-
const statusRes = await runMcp(['status', 'inneranimalmedia', '--json'], { home, write });
|
|
235
|
-
assert.equal(statusRes.name, 'inneranimalmedia');
|
|
236
|
-
assert.equal(statusRes.hasAuth, true);
|
|
237
|
-
|
|
238
|
-
// Doctor includes catalog / CF pack metadata
|
|
239
|
-
const doctorRes = await runMcp(['doctor', 'inneranimalmedia', '--json'], { home, write });
|
|
240
|
-
assert.equal(doctorRes.name, 'inneranimalmedia');
|
|
241
|
-
assert.equal(doctorRes.authConfigured, true);
|
|
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'));
|
|
249
|
-
|
|
250
|
-
// Remove
|
|
251
|
-
const removeRes = await runMcp(['remove', 'inneranimalmedia', '--client', 'all', '--json'], { home, write });
|
|
252
|
-
assert.equal(removeRes.deletedAuthority, true);
|
|
253
|
-
|
|
254
|
-
const emptyList = await runMcp(['list', '--json'], { home, write });
|
|
255
|
-
assert.equal(emptyList.length, 0);
|
|
256
|
-
});
|