@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/models.test.mjs
DELETED
|
@@ -1,309 +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 { collectModelsStatus, renderModelsStatus } from '../src/commands/models.js';
|
|
7
|
-
|
|
8
|
-
function response(body, status = 200) {
|
|
9
|
-
return { ok: status >= 200 && status < 300, status, async json() { return body; } };
|
|
10
|
-
}
|
|
11
|
-
|
|
12
|
-
function tempHome(t) {
|
|
13
|
-
const home = fs.mkdtempSync(path.join(os.tmpdir(), 'agentsam-model-home-'));
|
|
14
|
-
t.after(() => fs.rmSync(home, { recursive: true, force: true }));
|
|
15
|
-
return home;
|
|
16
|
-
}
|
|
17
|
-
|
|
18
|
-
test('model inventory reports configured API providers without exposing credentials', async t => {
|
|
19
|
-
const home = tempHome(t);
|
|
20
|
-
const status = await collectModelsStatus({
|
|
21
|
-
home,
|
|
22
|
-
discoverRemote: false,
|
|
23
|
-
env: {
|
|
24
|
-
OPENAI_API_KEY: 'secret-openai', GEMINI_API_KEY: '', XAI_API_KEY: 'secret-xai', ANTHROPIC_API_KEY: 'secret-anthropic', CLOUDFLARE_API_TOKEN: 'secret-cf', CLOUDFLARE_ACCOUNT_ID: '33333333333333333333333333333333',
|
|
25
|
-
OLLAMA_BASE_URL: 'http://127.0.0.1:11434', OLLAMA_MODEL: 'qwen:test', OLLAMA_EMBED_MODEL: 'embed:test',
|
|
26
|
-
},
|
|
27
|
-
fetchImpl: async () => response({ models: [{ name: 'qwen:test' }, { name: 'embed:test' }] }),
|
|
28
|
-
});
|
|
29
|
-
assert.equal(status.providers.find((row) => row.id === 'openai').configured, true);
|
|
30
|
-
assert.equal(status.providers.find((row) => row.id === 'gemini').configured, false);
|
|
31
|
-
assert.equal(status.providers.find((row) => row.id === 'grok').configured, true);
|
|
32
|
-
assert.equal(status.providers.find((row) => row.id === 'anthropic').configured, true);
|
|
33
|
-
assert.equal(status.providers.find((row) => row.id === 'cloudflare').configured, true);
|
|
34
|
-
assert.equal(status.local.online, true);
|
|
35
|
-
assert.deepEqual(status.local.models.map((row) => row.name), ['qwen:test', 'embed:test']);
|
|
36
|
-
const rendered = renderModelsStatus(status);
|
|
37
|
-
assert.match(rendered, /OpenAI/);
|
|
38
|
-
assert.match(rendered, /qwen:test/);
|
|
39
|
-
assert.doesNotMatch(rendered, /secret-openai|secret-xai|secret-anthropic|secret-cf/);
|
|
40
|
-
});
|
|
41
|
-
|
|
42
|
-
test('static/reference metadata never invents hosted model availability', async t => {
|
|
43
|
-
const home = tempHome(t);
|
|
44
|
-
const status = await collectModelsStatus({
|
|
45
|
-
home,
|
|
46
|
-
env: { OPENAI_API_KEY: 'secret-openai', OLLAMA_BASE_URL: 'http://127.0.0.1:11434' },
|
|
47
|
-
fetchImpl: async () => response({ models: [] }),
|
|
48
|
-
providerFetchImpl: async () => response({ data: [{ id: 'some-other-model' }] }),
|
|
49
|
-
});
|
|
50
|
-
|
|
51
|
-
assert.deepEqual(status.availableModels.map((row) => row.provider_model_id), ['some-other-model']);
|
|
52
|
-
const referenceOnly = status.catalogModels.find((row) => row.provider_model_id === 'gpt-6-astra');
|
|
53
|
-
assert.equal(referenceOnly?.availability, 'unverified');
|
|
54
|
-
assert.equal(referenceOnly?.availability_source, 'sdk_reference');
|
|
55
|
-
});
|
|
56
|
-
|
|
57
|
-
test('exact hosted model availability is verified against the provider inventory', async t => {
|
|
58
|
-
const home = tempHome(t);
|
|
59
|
-
const status = await collectModelsStatus({
|
|
60
|
-
home,
|
|
61
|
-
env: { OPENAI_API_KEY: 'secret-openai', OLLAMA_BASE_URL: 'http://127.0.0.1:11434' },
|
|
62
|
-
fetchImpl: async () => response({ models: [] }),
|
|
63
|
-
providerFetchImpl: async () => response({ data: [{ id: 'gpt-6-astra' }, { id: 'some-other-model' }] }),
|
|
64
|
-
});
|
|
65
|
-
assert.equal(status.discovery.openai.ok, true);
|
|
66
|
-
assert.equal(status.discovery.openai.returnedModelCount, 2);
|
|
67
|
-
assert.deepEqual(status.availableModels.map((row) => row.provider_model_id), ['gpt-6-astra', 'some-other-model']);
|
|
68
|
-
assert.equal(status.availableModels[0].availability_source, 'provider_api');
|
|
69
|
-
assert.equal(status.availableModels[0].context_window_source, 'sdk_reference');
|
|
70
|
-
});
|
|
71
|
-
|
|
72
|
-
|
|
73
|
-
|
|
74
|
-
|
|
75
|
-
test('Gemini and xAI discovery keep per-key limits from provider metadata', async t => {
|
|
76
|
-
const home = tempHome(t);
|
|
77
|
-
const seen = [];
|
|
78
|
-
const status = await collectModelsStatus({
|
|
79
|
-
home,
|
|
80
|
-
env: {
|
|
81
|
-
GEMINI_API_KEY: 'gem-key',
|
|
82
|
-
XAI_API_KEY: 'xai-key',
|
|
83
|
-
OLLAMA_BASE_URL: 'http://127.0.0.1:11434',
|
|
84
|
-
},
|
|
85
|
-
fetchImpl: async () => response({ models: [] }),
|
|
86
|
-
providerFetchImpl: async (url, options) => {
|
|
87
|
-
seen.push(url);
|
|
88
|
-
if (url.includes('generativelanguage.googleapis.com')) {
|
|
89
|
-
return response({ models: [{
|
|
90
|
-
name: 'models/gemini-test',
|
|
91
|
-
baseModelId: 'gemini-test',
|
|
92
|
-
displayName: 'Gemini Test',
|
|
93
|
-
inputTokenLimit: 123456,
|
|
94
|
-
outputTokenLimit: 8192,
|
|
95
|
-
supportedGenerationMethods: ['generateContent'],
|
|
96
|
-
thinking: true,
|
|
97
|
-
}] });
|
|
98
|
-
}
|
|
99
|
-
if (url.includes('api.x.ai')) {
|
|
100
|
-
return response({ data: [{
|
|
101
|
-
id: 'grok-test',
|
|
102
|
-
context_length: 256000,
|
|
103
|
-
prompt_text_token_price: 1000,
|
|
104
|
-
cached_prompt_text_token_price: 500,
|
|
105
|
-
completion_text_token_price: 4000,
|
|
106
|
-
}] });
|
|
107
|
-
}
|
|
108
|
-
throw new Error('unexpected URL ' + url);
|
|
109
|
-
},
|
|
110
|
-
});
|
|
111
|
-
|
|
112
|
-
const gemini = status.providerModels.gemini[0];
|
|
113
|
-
assert.equal(gemini.provider_model_id, 'gemini-test');
|
|
114
|
-
assert.equal(gemini.context_window, 123456);
|
|
115
|
-
assert.equal(gemini.context_window_source, 'provider_api');
|
|
116
|
-
assert.deepEqual(gemini.reasoning_efforts, ['auto', 'low', 'medium', 'high']);
|
|
117
|
-
|
|
118
|
-
const grok = status.providerModels.grok[0];
|
|
119
|
-
assert.equal(grok.provider_model_id, 'grok-test');
|
|
120
|
-
assert.equal(grok.context_window, 256000);
|
|
121
|
-
assert.equal(grok.pricing.input, 1);
|
|
122
|
-
assert.equal(grok.pricing.output, 4);
|
|
123
|
-
assert.equal(seen.some((url) => url.includes('generativelanguage.googleapis.com')), true);
|
|
124
|
-
assert.equal(seen.some((url) => url.includes('api.x.ai')), true);
|
|
125
|
-
});
|
|
126
|
-
|
|
127
|
-
|
|
128
|
-
test('Cloudflare discovery is scoped to the loaded account and surfaces text-generation + embeddings', async t => {
|
|
129
|
-
const seen = [];
|
|
130
|
-
const home = tempHome(t);
|
|
131
|
-
const status = await collectModelsStatus({
|
|
132
|
-
home,
|
|
133
|
-
curateWorkersAi: false,
|
|
134
|
-
env: { CLOUDFLARE_API_TOKEN: 'secret-cf', CLOUDFLARE_ACCOUNT_ID: '44444444444444444444444444444444', OLLAMA_BASE_URL: 'http://127.0.0.1:11434' },
|
|
135
|
-
fetchImpl: async () => response({ models: [] }),
|
|
136
|
-
providerFetchImpl: async (url, options) => {
|
|
137
|
-
seen.push({ url, auth: options.headers.authorization });
|
|
138
|
-
return response({ success: true, result: [
|
|
139
|
-
{ name: '@cf/qwen/code', task: { name: 'Text Generation' }, description: 'coding' },
|
|
140
|
-
{ name: '@cf/baai/embed', task: { name: 'Text Embeddings' }, description: 'embeddings' },
|
|
141
|
-
] });
|
|
142
|
-
},
|
|
143
|
-
});
|
|
144
|
-
assert.equal(seen.length, 1);
|
|
145
|
-
assert.match(seen[0].url, /accounts\/44444444444444444444444444444444\/ai\/models\/search$/);
|
|
146
|
-
assert.equal(status.discovery.cloudflare.ok, true);
|
|
147
|
-
assert.equal(status.discovery.cloudflare.returnedModelCount, 2);
|
|
148
|
-
assert.deepEqual(
|
|
149
|
-
status.providerModels.cloudflare.map((row) => row.provider_model_id).sort(),
|
|
150
|
-
['@cf/baai/embed', '@cf/qwen/code'],
|
|
151
|
-
);
|
|
152
|
-
const embed = status.providerModels.cloudflare.find((row) => row.provider_model_id === '@cf/baai/embed');
|
|
153
|
-
const qwen = status.providerModels.cloudflare.find((row) => row.provider_model_id === '@cf/qwen/code');
|
|
154
|
-
assert.equal(qwen.availability_source, 'provider_api');
|
|
155
|
-
assert.equal(qwen.context_window_source, 'unknown');
|
|
156
|
-
const rendered = renderModelsStatus(status);
|
|
157
|
-
assert.match(rendered, /@cf\/qwen\/code/);
|
|
158
|
-
assert.match(rendered, /@cf\/baai\/embed/);
|
|
159
|
-
assert.doesNotMatch(rendered, /secret-cf/);
|
|
160
|
-
});
|
|
161
|
-
|
|
162
|
-
test('Cursor participates in machine inventory when CURSOR_API_KEY is configured', async t => {
|
|
163
|
-
const home = tempHome(t);
|
|
164
|
-
const seen = [];
|
|
165
|
-
const status = await collectModelsStatus({
|
|
166
|
-
home,
|
|
167
|
-
env: {
|
|
168
|
-
CURSOR_API_KEY: 'cursor-secret-key',
|
|
169
|
-
OLLAMA_BASE_URL: 'http://127.0.0.1:11434',
|
|
170
|
-
},
|
|
171
|
-
fetchImpl: async () => response({ models: [] }),
|
|
172
|
-
providerFetchImpl: async (url, options) => {
|
|
173
|
-
seen.push({ url, auth: options?.headers?.authorization });
|
|
174
|
-
if (String(url).includes('api.cursor.com')) {
|
|
175
|
-
return response({
|
|
176
|
-
items: [
|
|
177
|
-
{ id: 'composer-2.5', displayName: 'Composer 2.5', parameters: [] },
|
|
178
|
-
{ id: 'gpt-5.6-sol', displayName: 'GPT-5.6 Sol', parameters: [{ id: 'reasoning', values: [{ value: 'high' }] }] },
|
|
179
|
-
],
|
|
180
|
-
});
|
|
181
|
-
}
|
|
182
|
-
throw new Error('unexpected URL ' + url);
|
|
183
|
-
},
|
|
184
|
-
});
|
|
185
|
-
|
|
186
|
-
const cursor = status.providers.find((row) => row.id === 'cursor');
|
|
187
|
-
assert.equal(cursor?.configured, true);
|
|
188
|
-
assert.equal(status.discovery.cursor.ok, true);
|
|
189
|
-
assert.equal(status.discovery.cursor.returnedModelCount, 2);
|
|
190
|
-
assert.equal(seen.length, 1);
|
|
191
|
-
assert.match(seen[0].url, /api\.cursor\.com\/v1\/models/);
|
|
192
|
-
assert.match(seen[0].auth, /Bearer cursor-secret-key/);
|
|
193
|
-
assert.deepEqual(
|
|
194
|
-
status.availableModels.filter((row) => row.provider === 'cursor').map((row) => row.provider_model_id),
|
|
195
|
-
['composer-2.5', 'gpt-5.6-sol'],
|
|
196
|
-
);
|
|
197
|
-
const rendered = renderModelsStatus(status);
|
|
198
|
-
assert.match(rendered, /Cursor/);
|
|
199
|
-
assert.match(rendered, /composer-2\.5/);
|
|
200
|
-
assert.doesNotMatch(rendered, /cursor-secret-key/);
|
|
201
|
-
});
|
|
202
|
-
|
|
203
|
-
test('missing Cursor credential skips discovery and does not fall back to another provider', async t => {
|
|
204
|
-
const home = tempHome(t);
|
|
205
|
-
const seen = [];
|
|
206
|
-
const status = await collectModelsStatus({
|
|
207
|
-
home,
|
|
208
|
-
env: {
|
|
209
|
-
OPENAI_API_KEY: 'secret-openai',
|
|
210
|
-
OLLAMA_BASE_URL: 'http://127.0.0.1:11434',
|
|
211
|
-
},
|
|
212
|
-
fetchImpl: async () => response({ models: [] }),
|
|
213
|
-
providerFetchImpl: async (url) => {
|
|
214
|
-
seen.push(url);
|
|
215
|
-
if (String(url).includes('api.openai.com')) return response({ data: [{ id: 'gpt-test' }] });
|
|
216
|
-
if (String(url).includes('api.cursor.com')) throw new Error('cursor must not be called');
|
|
217
|
-
return response({ data: [] });
|
|
218
|
-
},
|
|
219
|
-
});
|
|
220
|
-
assert.equal(status.providers.find((row) => row.id === 'cursor')?.configured, false);
|
|
221
|
-
assert.equal(status.discovery.cursor.attempted, false);
|
|
222
|
-
assert.equal(seen.some((url) => String(url).includes('api.cursor.com')), false);
|
|
223
|
-
assert.equal(status.availableModels.some((row) => row.provider === 'cursor'), false);
|
|
224
|
-
assert.equal(status.availableModels.some((row) => row.provider === 'openai'), true);
|
|
225
|
-
});
|
|
226
|
-
|
|
227
|
-
test('Cursor discovery failure stays attached to Cursor and does not invent OpenAI models', async t => {
|
|
228
|
-
const home = tempHome(t);
|
|
229
|
-
const status = await collectModelsStatus({
|
|
230
|
-
home,
|
|
231
|
-
env: {
|
|
232
|
-
CURSOR_API_KEY: 'bad-cursor-key',
|
|
233
|
-
OLLAMA_BASE_URL: 'http://127.0.0.1:11434',
|
|
234
|
-
},
|
|
235
|
-
fetchImpl: async () => response({ models: [] }),
|
|
236
|
-
providerFetchImpl: async (url) => {
|
|
237
|
-
if (String(url).includes('api.cursor.com')) {
|
|
238
|
-
return { ok: false, status: 401, async json() { return { error: 'unauthorized' }; } };
|
|
239
|
-
}
|
|
240
|
-
throw new Error('unexpected URL ' + url);
|
|
241
|
-
},
|
|
242
|
-
});
|
|
243
|
-
assert.equal(status.providers.find((row) => row.id === 'cursor')?.configured, true);
|
|
244
|
-
assert.equal(status.discovery.cursor.ok, false);
|
|
245
|
-
assert.ok(status.discovery.cursor.error);
|
|
246
|
-
assert.equal((status.providerModels.cursor || []).length, 0);
|
|
247
|
-
assert.equal(status.availableModels.some((row) => row.provider === 'openai'), false);
|
|
248
|
-
});
|
|
249
|
-
|
|
250
|
-
test('Workers AI curated allowlist intersects live Cloudflare discovery', async t => {
|
|
251
|
-
const home = tempHome(t);
|
|
252
|
-
const status = await collectModelsStatus({
|
|
253
|
-
home,
|
|
254
|
-
curateWorkersAi: true,
|
|
255
|
-
env: { CLOUDFLARE_API_TOKEN: 'secret-cf', CLOUDFLARE_ACCOUNT_ID: '44444444444444444444444444444444', OLLAMA_BASE_URL: 'http://127.0.0.1:11434' },
|
|
256
|
-
fetchImpl: async () => response({ models: [] }),
|
|
257
|
-
providerFetchImpl: async () => response({
|
|
258
|
-
success: true,
|
|
259
|
-
result: [
|
|
260
|
-
{ name: '@cf/qwen/qwen2.5-coder-32b-instruct', task: { name: 'Text Generation' } },
|
|
261
|
-
{ name: '@cf/meta/llama-3.2-1b-instruct', task: { name: 'Text Generation' } },
|
|
262
|
-
{ name: '@cf/openai/gpt-oss-120b', task: { name: 'Text Generation' } },
|
|
263
|
-
{ name: '@cf/baai/bge-base-en-v1.5', task: { name: 'Text Embeddings' } },
|
|
264
|
-
],
|
|
265
|
-
}),
|
|
266
|
-
});
|
|
267
|
-
// Chat allowlist applies to Text Generation; Text Embeddings always pass (Vectorize lane).
|
|
268
|
-
assert.deepEqual(
|
|
269
|
-
status.providerModels.cloudflare.map((row) => row.provider_model_id).sort(),
|
|
270
|
-
['@cf/baai/bge-base-en-v1.5', '@cf/openai/gpt-oss-120b', '@cf/qwen/qwen2.5-coder-32b-instruct'],
|
|
271
|
-
);
|
|
272
|
-
assert.equal(status.discovery.cloudflare.curation, 'agentsam_workers_ai_allowlist');
|
|
273
|
-
});
|
|
274
|
-
|
|
275
|
-
test('studio vault credential plane never reads machine env when resolver is injected', async t => {
|
|
276
|
-
const home = tempHome(t);
|
|
277
|
-
const status = await collectModelsStatus({
|
|
278
|
-
home,
|
|
279
|
-
credentialPlane: 'studio_vault',
|
|
280
|
-
includeLocal: false,
|
|
281
|
-
env: { OPENAI_API_KEY: 'machine-must-not-be-used', CURSOR_API_KEY: 'machine-cursor' },
|
|
282
|
-
resolveCredential: async (providerId) => {
|
|
283
|
-
if (providerId === 'gemini') {
|
|
284
|
-
return { configured: true, value: 'vault-gemini', source: 'user_vault', env: 'GEMINI_API_KEY' };
|
|
285
|
-
}
|
|
286
|
-
return { configured: false, value: '', source: null, error: null };
|
|
287
|
-
},
|
|
288
|
-
fetchImpl: async () => response({ models: [] }),
|
|
289
|
-
providerFetchImpl: async (url) => {
|
|
290
|
-
if (String(url).includes('generativelanguage.googleapis.com') && String(url).includes('vault-gemini')) {
|
|
291
|
-
return response({
|
|
292
|
-
models: [{
|
|
293
|
-
name: 'models/gemini-vault',
|
|
294
|
-
baseModelId: 'gemini-vault',
|
|
295
|
-
displayName: 'Vault Gemini',
|
|
296
|
-
inputTokenLimit: 1000,
|
|
297
|
-
supportedGenerationMethods: ['generateContent'],
|
|
298
|
-
}],
|
|
299
|
-
});
|
|
300
|
-
}
|
|
301
|
-
throw new Error('machine providers must not be discovered: ' + url);
|
|
302
|
-
},
|
|
303
|
-
});
|
|
304
|
-
assert.equal(status.credential_plane, 'studio_vault');
|
|
305
|
-
assert.equal(status.providers.find((row) => row.id === 'openai')?.configured, false);
|
|
306
|
-
assert.equal(status.providers.find((row) => row.id === 'gemini')?.configured, true);
|
|
307
|
-
assert.equal(status.providers.find((row) => row.id === 'gemini')?.source, 'user_vault');
|
|
308
|
-
assert.deepEqual(status.availableModels.map((row) => row.provider_model_id), ['gemini-vault']);
|
|
309
|
-
});
|
package/test/npm10-lock.test.mjs
DELETED
|
@@ -1,29 +0,0 @@
|
|
|
1
|
-
import assert from 'node:assert/strict';
|
|
2
|
-
import fs from 'node:fs';
|
|
3
|
-
import path from 'node:path';
|
|
4
|
-
import { describe, it } from 'node:test';
|
|
5
|
-
import { spawnSync } from 'node:child_process';
|
|
6
|
-
import { fileURLToPath } from 'node:url';
|
|
7
|
-
|
|
8
|
-
const root = path.resolve(path.dirname(fileURLToPath(import.meta.url)), '..');
|
|
9
|
-
const lockPath = path.join(root, 'apps/local-studio/package-lock.json');
|
|
10
|
-
|
|
11
|
-
describe('local-studio npm 10 lockfile', () => {
|
|
12
|
-
it('pins lru-cache@11.5.2 so Cloudflare npm ci can resolve it', () => {
|
|
13
|
-
const lock = JSON.parse(fs.readFileSync(lockPath, 'utf8'));
|
|
14
|
-
assert.equal(lock.lockfileVersion, 3);
|
|
15
|
-
const pkgs = lock.packages || {};
|
|
16
|
-
const hits = Object.entries(pkgs).filter(([key, meta]) => key.includes('lru-cache') && meta.version === '11.5.2');
|
|
17
|
-
assert.ok(hits.length >= 1, 'Missing: lru-cache@11.5.2 from lock file');
|
|
18
|
-
const [, meta] = hits[0];
|
|
19
|
-
assert.match(meta.resolved || '', /lru-cache-11\.5\.2\.tgz/);
|
|
20
|
-
assert.ok(meta.integrity);
|
|
21
|
-
});
|
|
22
|
-
|
|
23
|
-
it('verify-npm10-lock script exits 0 against the current lock', () => {
|
|
24
|
-
const script = path.join(root, 'apps/local-studio/scripts/verify-npm10-lock.mjs');
|
|
25
|
-
const r = spawnSync(process.execPath, [script], { encoding: 'utf8' });
|
|
26
|
-
assert.equal(r.status, 0, r.stderr || r.stdout);
|
|
27
|
-
assert.match(r.stdout, /lru-cache@11\.5\.2/);
|
|
28
|
-
});
|
|
29
|
-
});
|
package/test/ollama.test.mjs
DELETED
|
@@ -1,137 +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 {
|
|
7
|
-
OLLAMA_DEFAULTS,
|
|
8
|
-
ollamaInstallPlan,
|
|
9
|
-
parseOllamaArgs,
|
|
10
|
-
probeOllama,
|
|
11
|
-
probeOllamaModel,
|
|
12
|
-
resolveOllamaConfig,
|
|
13
|
-
updateProjectOllamaConfig,
|
|
14
|
-
upsertOllamaEnvFile,
|
|
15
|
-
} from '../src/commands/ollama.js';
|
|
16
|
-
import { createProjectManifest } from '../src/lib/project-config.js';
|
|
17
|
-
|
|
18
|
-
test('Ollama defaults are local-only and match the SDK local-dev contract', () => {
|
|
19
|
-
assert.deepEqual(OLLAMA_DEFAULTS, {
|
|
20
|
-
baseUrl: 'http://127.0.0.1:11434',
|
|
21
|
-
model: 'qwen2.5-coder',
|
|
22
|
-
embedModel: 'mxbai-embed-large',
|
|
23
|
-
});
|
|
24
|
-
assert.deepEqual(resolveOllamaConfig({}, {}), OLLAMA_DEFAULTS);
|
|
25
|
-
});
|
|
26
|
-
|
|
27
|
-
test('Ollama endpoints normalize host-only values and honor AgentSam precedence', () => {
|
|
28
|
-
assert.equal(resolveOllamaConfig({}, { OLLAMA_HOST: '0.0.0.0:11434' }).baseUrl, 'http://127.0.0.1:11434');
|
|
29
|
-
assert.equal(resolveOllamaConfig({}, { OLLAMA_HOST: '127.0.0.1:11434' }).baseUrl, 'http://127.0.0.1:11434');
|
|
30
|
-
assert.equal(resolveOllamaConfig({}, { OLLAMA_HOST: 'localhost:11434' }).baseUrl, 'http://localhost:11434');
|
|
31
|
-
assert.equal(resolveOllamaConfig({}, { OLLAMA_HOST: 'http://localhost:11434' }).baseUrl, 'http://localhost:11434');
|
|
32
|
-
|
|
33
|
-
assert.equal(resolveOllamaConfig({}, {
|
|
34
|
-
AGENTSAM_OLLAMA_ENDPOINT: '127.0.0.1:2244',
|
|
35
|
-
OLLAMA_BASE_URL: 'localhost:3344',
|
|
36
|
-
OLLAMA_HOST: '0.0.0.0:4444',
|
|
37
|
-
}).baseUrl, 'http://127.0.0.1:2244');
|
|
38
|
-
|
|
39
|
-
assert.equal(resolveOllamaConfig({}, {
|
|
40
|
-
OLLAMA_BASE_URL: 'localhost:3344',
|
|
41
|
-
OLLAMA_HOST: '0.0.0.0:4444',
|
|
42
|
-
}).baseUrl, 'http://localhost:3344');
|
|
43
|
-
|
|
44
|
-
assert.equal(resolveOllamaConfig({}, {
|
|
45
|
-
OLLAMA_HOST: '0.0.0.0:4444',
|
|
46
|
-
}).baseUrl, 'http://127.0.0.1:4444');
|
|
47
|
-
});
|
|
48
|
-
|
|
49
|
-
test('Ollama setup args require explicit install/pull/start opt-ins', () => {
|
|
50
|
-
assert.deepEqual(parseOllamaArgs(['setup']), {
|
|
51
|
-
command: 'setup',
|
|
52
|
-
cwd: process.cwd(),
|
|
53
|
-
envFile: '',
|
|
54
|
-
baseUrl: '',
|
|
55
|
-
model: '',
|
|
56
|
-
embedModel: '',
|
|
57
|
-
install: false,
|
|
58
|
-
start: false,
|
|
59
|
-
pull: false,
|
|
60
|
-
json: false,
|
|
61
|
-
});
|
|
62
|
-
const opted = parseOllamaArgs(['setup', '--install', '--start', '--pull', '--json']);
|
|
63
|
-
assert.equal(opted.install, true);
|
|
64
|
-
assert.equal(opted.start, true);
|
|
65
|
-
assert.equal(opted.pull, true);
|
|
66
|
-
assert.equal(opted.json, true);
|
|
67
|
-
});
|
|
68
|
-
|
|
69
|
-
test('setup env writer updates only canonical OLLAMA keys and preserves other config', () => {
|
|
70
|
-
const root = fs.mkdtempSync(path.join(os.tmpdir(), 'agentsam-ollama-'));
|
|
71
|
-
const envFile = path.join(root, '.env');
|
|
72
|
-
fs.writeFileSync(envFile, 'EXISTING=value\nOLLAMA_MODEL=old\n');
|
|
73
|
-
upsertOllamaEnvFile(envFile, OLLAMA_DEFAULTS);
|
|
74
|
-
const text = fs.readFileSync(envFile, 'utf8');
|
|
75
|
-
assert.match(text, /^EXISTING=value$/m);
|
|
76
|
-
assert.match(text, /^OLLAMA_BASE_URL=http:\/\/127\.0\.0\.1:11434$/m);
|
|
77
|
-
assert.match(text, /^OLLAMA_MODEL=qwen2\.5-coder$/m);
|
|
78
|
-
assert.match(text, /^OLLAMA_EMBED_MODEL=mxbai-embed-large$/m);
|
|
79
|
-
assert.equal((text.match(/^OLLAMA_MODEL=/gm) || []).length, 1);
|
|
80
|
-
});
|
|
81
|
-
|
|
82
|
-
test('project config records only portable Ollama capability metadata', () => {
|
|
83
|
-
const root = fs.mkdtempSync(path.join(os.tmpdir(), 'agentsam-ollama-config-'));
|
|
84
|
-
fs.mkdirSync(path.join(root, '.agentsam'));
|
|
85
|
-
fs.writeFileSync(path.join(root, '.agentsam', 'config.json'), `${JSON.stringify(createProjectManifest({ projectName: 'demo', repositoryId: 'local:demo' }), null, 2)}\n`);
|
|
86
|
-
const filename = updateProjectOllamaConfig(root, OLLAMA_DEFAULTS);
|
|
87
|
-
const config = JSON.parse(fs.readFileSync(filename, 'utf8'));
|
|
88
|
-
assert.equal(config.models.local.provider, 'ollama');
|
|
89
|
-
assert.equal(config.models.local.base_url_env, 'OLLAMA_BASE_URL');
|
|
90
|
-
assert.equal(config.models.local.model_env, 'OLLAMA_MODEL');
|
|
91
|
-
assert.equal(config.models.local.embed_model_env, 'OLLAMA_EMBED_MODEL');
|
|
92
|
-
assert.equal(JSON.stringify(config).includes('127.0.0.1'), false);
|
|
93
|
-
assert.equal(JSON.stringify(config).includes('qwen2.5-coder'), false);
|
|
94
|
-
assert.equal(JSON.stringify(config).includes('token'), false);
|
|
95
|
-
});
|
|
96
|
-
|
|
97
|
-
test('status probe recognizes configured chat and embedding models', async () => {
|
|
98
|
-
const fakeFetch = async () => new Response(JSON.stringify({ models: [
|
|
99
|
-
{ name: 'qwen2.5-coder:latest' },
|
|
100
|
-
{ name: 'mxbai-embed-large:latest' },
|
|
101
|
-
] }), { status: 200, headers: { 'content-type': 'application/json' } });
|
|
102
|
-
const status = await probeOllama(OLLAMA_DEFAULTS, fakeFetch);
|
|
103
|
-
assert.equal(status.online, true);
|
|
104
|
-
assert.equal(status.chat_ready, true);
|
|
105
|
-
assert.equal(status.embed_ready, true);
|
|
106
|
-
});
|
|
107
|
-
|
|
108
|
-
test('local model metadata is accepted only after Ollama itself verifies the model', async () => {
|
|
109
|
-
let seenBody = null;
|
|
110
|
-
const fakeFetch = async (url, init) => {
|
|
111
|
-
assert.match(url, /\/api\/show$/);
|
|
112
|
-
seenBody = JSON.parse(init.body);
|
|
113
|
-
return new Response(JSON.stringify({
|
|
114
|
-
model_info: { 'qwen2.context_length': 32768 },
|
|
115
|
-
capabilities: ['completion', 'tools'],
|
|
116
|
-
details: { family: 'qwen2' },
|
|
117
|
-
}), { status: 200, headers: { 'content-type': 'application/json' } });
|
|
118
|
-
};
|
|
119
|
-
|
|
120
|
-
const result = await probeOllamaModel('qwen2.5-coder', OLLAMA_DEFAULTS, fakeFetch);
|
|
121
|
-
assert.equal(seenBody.model, 'qwen2.5-coder');
|
|
122
|
-
assert.equal(result.ok, true);
|
|
123
|
-
assert.equal(result.context_window, 32768);
|
|
124
|
-
assert.equal(result.context_window_source, 'local_runtime');
|
|
125
|
-
assert.deepEqual(result.capabilities, ['completion', 'tools']);
|
|
126
|
-
});
|
|
127
|
-
|
|
128
|
-
test('automatic install plans use local package managers, never a remote shell script', () => {
|
|
129
|
-
assert.deepEqual(ollamaInstallPlan('darwin', { brew: true }), {
|
|
130
|
-
command: 'brew', args: ['install', 'ollama'], manager: 'homebrew',
|
|
131
|
-
});
|
|
132
|
-
assert.equal(ollamaInstallPlan('linux', { brew: false }), null);
|
|
133
|
-
assert.equal(ollamaInstallPlan('darwin', { brew: false }), null);
|
|
134
|
-
const win = ollamaInstallPlan('win32', { winget: true });
|
|
135
|
-
assert.equal(win.command, 'winget');
|
|
136
|
-
assert.equal(win.args.includes('Ollama.Ollama'), true);
|
|
137
|
-
});
|
package/test/open-url.test.mjs
DELETED
|
@@ -1,64 +0,0 @@
|
|
|
1
|
-
import test from 'node:test';
|
|
2
|
-
import assert from 'node:assert/strict';
|
|
3
|
-
import { PassThrough } from 'node:stream';
|
|
4
|
-
import { browserCommand, promptToOpenUrl } from '../src/lib/open-url.js';
|
|
5
|
-
|
|
6
|
-
test('browserCommand uses argv-safe platform launchers', () => {
|
|
7
|
-
assert.deepEqual(browserCommand('https://inneranimalmedia.com/auth', 'darwin'), {
|
|
8
|
-
command: 'open',
|
|
9
|
-
args: ['https://inneranimalmedia.com/auth'],
|
|
10
|
-
});
|
|
11
|
-
assert.deepEqual(browserCommand('https://inneranimalmedia.com/auth', 'linux'), {
|
|
12
|
-
command: 'xdg-open',
|
|
13
|
-
args: ['https://inneranimalmedia.com/auth'],
|
|
14
|
-
});
|
|
15
|
-
assert.deepEqual(browserCommand('https://inneranimalmedia.com/auth', 'win32'), {
|
|
16
|
-
command: 'cmd',
|
|
17
|
-
args: ['/c', 'start', '', 'https://inneranimalmedia.com/auth'],
|
|
18
|
-
});
|
|
19
|
-
});
|
|
20
|
-
|
|
21
|
-
test('browserCommand rejects non-http protocols', () => {
|
|
22
|
-
assert.throws(() => browserCommand('file:///tmp/example', 'darwin'), /Unsupported URL protocol/);
|
|
23
|
-
assert.throws(() => browserCommand('javascript:alert(1)', 'darwin'), /Unsupported URL protocol/);
|
|
24
|
-
});
|
|
25
|
-
|
|
26
|
-
test('promptToOpenUrl stays non-interactive when stdin is not a TTY', async () => {
|
|
27
|
-
const input = new PassThrough();
|
|
28
|
-
const output = new PassThrough();
|
|
29
|
-
let text = '';
|
|
30
|
-
output.on('data', chunk => { text += chunk.toString(); });
|
|
31
|
-
let opened = false;
|
|
32
|
-
const result = await promptToOpenUrl('https://www.blender.org/download/', {
|
|
33
|
-
input,
|
|
34
|
-
output,
|
|
35
|
-
openImpl: () => { opened = true; },
|
|
36
|
-
});
|
|
37
|
-
assert.equal(result.interactive, false);
|
|
38
|
-
assert.equal(result.opened, false);
|
|
39
|
-
assert.equal(opened, false);
|
|
40
|
-
assert.match(text, /https:\/\/www\.blender\.org\/download\//);
|
|
41
|
-
assert.match(text, /Open the URL above in a browser/);
|
|
42
|
-
});
|
|
43
|
-
|
|
44
|
-
test('promptToOpenUrl waits for Enter before opening in a TTY', async () => {
|
|
45
|
-
const input = new PassThrough();
|
|
46
|
-
const output = new PassThrough();
|
|
47
|
-
input.isTTY = true;
|
|
48
|
-
output.isTTY = true;
|
|
49
|
-
let text = '';
|
|
50
|
-
output.on('data', chunk => { text += chunk.toString(); });
|
|
51
|
-
let openedUrl = null;
|
|
52
|
-
const pending = promptToOpenUrl('https://inneranimalmedia.com/dashboard', {
|
|
53
|
-
input,
|
|
54
|
-
output,
|
|
55
|
-
openImpl: url => { openedUrl = url; },
|
|
56
|
-
});
|
|
57
|
-
input.write('\n');
|
|
58
|
-
const result = await pending;
|
|
59
|
-
assert.equal(result.interactive, true);
|
|
60
|
-
assert.equal(result.opened, true);
|
|
61
|
-
assert.equal(openedUrl, 'https://inneranimalmedia.com/dashboard');
|
|
62
|
-
assert.match(text, /Press ENTER to open/);
|
|
63
|
-
assert.match(text, /Browser opened/);
|
|
64
|
-
});
|