@inneranimalmedia/agentsam-sdk 2.6.7 → 2.6.8
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/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 +16 -6
- package/packages/agentsam-errors/package.json +1 -1
- 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-nav/dist/Nav.d.ts +43 -0
- package/packages/agentsam-nav/dist/NavCollapsible.d.ts +10 -0
- package/packages/agentsam-nav/dist/NavContent.d.ts +2 -0
- package/packages/agentsam-nav/dist/NavFooter.d.ts +2 -0
- package/packages/agentsam-nav/dist/NavGroup.d.ts +3 -0
- package/packages/agentsam-nav/dist/NavHeader.d.ts +2 -0
- package/packages/agentsam-nav/dist/NavMenu.d.ts +22 -0
- package/packages/agentsam-nav/dist/NavProvider.d.ts +35 -0
- package/packages/agentsam-nav/dist/NavTrigger.d.ts +2 -0
- package/packages/agentsam-nav/dist/Surfaces.d.ts +41 -0
- package/packages/agentsam-nav/dist/browser.d.ts +11 -0
- package/packages/agentsam-nav/dist/browser.global.js +135 -0
- package/packages/agentsam-nav/dist/browser.js +7290 -0
- package/packages/agentsam-nav/dist/contracts.d.ts +76 -0
- package/packages/agentsam-nav/dist/index.d.ts +11 -0
- package/packages/agentsam-nav/dist/index.js +7291 -0
- package/packages/agentsam-nav/dist/legacy.css +83 -0
- package/packages/agentsam-nav/dist/shell.css +113 -0
- package/packages/agentsam-nav/dist/theme.css +113 -0
- package/packages/agentsam-nav/dist/utils.d.ts +1 -0
- package/packages/agentsam-repository/src/goap.js +13 -14
- package/packages/agentsam-repository/src/goap.js.bak-20260922011251 +670 -0
- package/packages/agentsam-repository/src/tickets.js +15 -22
- package/packages/agentsam-repository/test/goap-tickets-workspace-state.test.mjs +19 -8
- package/packages/connectors/cloudflare/package.json +3 -1
- package/packages/identity/tests/lane1-packed-consumer.test.mjs +1 -1
- 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 +2 -1
- package/src/cli.js +10 -1
- 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 +122 -51
- package/src/commands/package.js +530 -0
- package/src/commands/plan-ledger.js +370 -0
- package/src/commands/plan.js +183 -0
- package/src/commands/skill.js +78 -17
- package/src/knowledge/source.js +1 -1
- 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/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
|
@@ -1,59 +0,0 @@
|
|
|
1
|
-
import test from 'node:test';
|
|
2
|
-
import assert from 'node:assert/strict';
|
|
3
|
-
|
|
4
|
-
import { discoverOpenAIModels, discoverGeminiModels, discoverCursorModels } from '../../src/models/discovery.js';
|
|
5
|
-
import { sanitizeInventoryForClient } from '../../src/models/inventory-core.js';
|
|
6
|
-
|
|
7
|
-
function json(body) {
|
|
8
|
-
return new Response(JSON.stringify(body), { status: 200, headers: { 'content-type': 'application/json' } });
|
|
9
|
-
}
|
|
10
|
-
|
|
11
|
-
function sanitized(models) {
|
|
12
|
-
return sanitizeInventoryForClient({
|
|
13
|
-
providers: [],
|
|
14
|
-
discovery: {},
|
|
15
|
-
availableModels: models,
|
|
16
|
-
}).availableModels;
|
|
17
|
-
}
|
|
18
|
-
|
|
19
|
-
test('known OpenAI Responses reference is selectable while unknown live models stay visible', async () => {
|
|
20
|
-
const result = await discoverOpenAIModels('user-key', async () => json({
|
|
21
|
-
data: [{ id: 'gpt-5.6-sol' }, { id: 'brand-new-unclassified-model' }],
|
|
22
|
-
}));
|
|
23
|
-
const rows = sanitized(result.models);
|
|
24
|
-
assert.equal(rows.length, 2);
|
|
25
|
-
assert.equal(rows.find((row) => row.model_id === 'gpt-5.6-sol')?.chat_eligible, true);
|
|
26
|
-
const unknown = rows.find((row) => row.model_id === 'brand-new-unclassified-model');
|
|
27
|
-
assert.equal(unknown?.chat_eligible, false);
|
|
28
|
-
assert.equal(unknown?.eligibility_reason, 'capability_unknown');
|
|
29
|
-
});
|
|
30
|
-
|
|
31
|
-
test('Cursor inventory is preserved but reports adapter unavailability', async () => {
|
|
32
|
-
const result = await discoverCursorModels('cursor-key', async () => json({
|
|
33
|
-
items: [{ id: 'gpt-5.6-sol', displayName: 'GPT-5.6 Sol', parameters: [] }],
|
|
34
|
-
}));
|
|
35
|
-
const [row] = sanitized(result.models);
|
|
36
|
-
assert.equal(row.provider, 'cursor');
|
|
37
|
-
assert.equal(row.model_id, 'gpt-5.6-sol');
|
|
38
|
-
assert.equal(row.chat_eligible, false);
|
|
39
|
-
assert.equal(row.eligibility_reason, 'provider_adapter_unavailable');
|
|
40
|
-
});
|
|
41
|
-
|
|
42
|
-
test('Gemini provider description keeps TTS visible outside the chat picker', async () => {
|
|
43
|
-
const result = await discoverGeminiModels('gemini-key', async () => json({
|
|
44
|
-
models: [{
|
|
45
|
-
name: 'models/gemini-tts-fixture',
|
|
46
|
-
baseModelId: 'gemini-tts-fixture',
|
|
47
|
-
displayName: 'Voice fixture',
|
|
48
|
-
description: 'Preview Text-to-Speech model',
|
|
49
|
-
supportedGenerationMethods: ['generateContent'],
|
|
50
|
-
inputTokenLimit: 8192,
|
|
51
|
-
outputTokenLimit: 8192,
|
|
52
|
-
}],
|
|
53
|
-
}));
|
|
54
|
-
const [row] = sanitized(result.models);
|
|
55
|
-
assert.equal(row.model_id, 'gemini-tts-fixture');
|
|
56
|
-
assert.equal(row.chat_eligible, false);
|
|
57
|
-
assert.equal(row.eligibility_reason, 'specialized_output_model');
|
|
58
|
-
assert.equal(row.eligibility_source, 'provider_api');
|
|
59
|
-
});
|
|
@@ -1,125 +0,0 @@
|
|
|
1
|
-
import { describe, it } from 'node:test';
|
|
2
|
-
import assert from 'node:assert/strict';
|
|
3
|
-
import fs from 'node:fs';
|
|
4
|
-
import os from 'node:os';
|
|
5
|
-
import path from 'node:path';
|
|
6
|
-
import { execFileSync } from 'node:child_process';
|
|
7
|
-
import { buildInventory } from '../../src/indexing/ingest/inventory.js';
|
|
8
|
-
import {
|
|
9
|
-
extractStyleEvidence,
|
|
10
|
-
finalizeStyleEvidence,
|
|
11
|
-
mergeStyleEvidence,
|
|
12
|
-
} from '../../src/indexing/ingest/style-evidence.js';
|
|
13
|
-
import { inventory as knowledgeInventory } from '../../src/knowledge/source.js';
|
|
14
|
-
|
|
15
|
-
function write(root, rel, text = '') {
|
|
16
|
-
const abs = path.join(root, rel);
|
|
17
|
-
fs.mkdirSync(path.dirname(abs), { recursive: true });
|
|
18
|
-
fs.writeFileSync(abs, text);
|
|
19
|
-
}
|
|
20
|
-
|
|
21
|
-
describe('inventory classifies by evidence', () => {
|
|
22
|
-
it('uses dominant evidence, root files, tooling LOC, and git ignore state', () => {
|
|
23
|
-
const root = fs.mkdtempSync(path.join(os.tmpdir(), 'inv-evidence-'));
|
|
24
|
-
try {
|
|
25
|
-
execFileSync('git', ['init', '-q'], { cwd: root });
|
|
26
|
-
write(root, '.gitignore', '.sites-runtime/\n');
|
|
27
|
-
|
|
28
|
-
write(root, 'app/page.tsx', Array.from({ length: 30 }, (_, i) => `export const x${i} = ${i};`).join('\n'));
|
|
29
|
-
write(root, 'db/schema.sql', 'create table t (id integer);\n');
|
|
30
|
-
write(root, 'drizzle/meta/_journal.json', '{"version":"1"}\n');
|
|
31
|
-
for (let i = 1; i <= 9; i += 1) write(root, `plans/p${i}.md`, `# plan ${i}\ntext\n`);
|
|
32
|
-
write(root, 'plans/schema.sql', 'create table plan (id integer);\n');
|
|
33
|
-
write(root, 'public/logo.png', 'x');
|
|
34
|
-
write(root, 'scripts/harvest.py', Array.from({ length: 80 }, (_, i) => `x_${i} = ${i}`).join('\n'));
|
|
35
|
-
write(root, '.sites-runtime/cache/blob.bin', 'x'.repeat(2048));
|
|
36
|
-
|
|
37
|
-
write(root, 'package.json', '{"name":"fixture"}\n');
|
|
38
|
-
write(root, 'wrangler.jsonc', '{}\n');
|
|
39
|
-
write(root, 'drizzle.config.ts', 'export default {};\n');
|
|
40
|
-
write(root, 'README.md', '# Fixture\n');
|
|
41
|
-
write(root, 'entry.ts', 'export const root = true;\n');
|
|
42
|
-
write(root, 'package-lock.json', '{"lockfileVersion":3}\n');
|
|
43
|
-
write(root, '.env', 'SECRET=do-not-index\n');
|
|
44
|
-
write(root, '.dev.vars', 'TOKEN=do-not-index\n');
|
|
45
|
-
write(root, 'tls.pem', 'private material\n');
|
|
46
|
-
|
|
47
|
-
execFileSync('git', ['add', '.'], { cwd: root });
|
|
48
|
-
|
|
49
|
-
const inventory = buildInventory({ root });
|
|
50
|
-
const categories = inventory.categories;
|
|
51
|
-
|
|
52
|
-
assert.ok(categories.source.includes('app'));
|
|
53
|
-
assert.ok(categories.source.includes('db'));
|
|
54
|
-
assert.ok(categories.docs.includes('plans'), '9 markdown + 1 SQL is dominantly docs');
|
|
55
|
-
assert.ok(categories.data.includes('drizzle'), 'JSON-only drizzle metadata is data');
|
|
56
|
-
assert.ok(categories.assets.includes('public'));
|
|
57
|
-
assert.ok(categories.operational.includes('.sites-runtime'));
|
|
58
|
-
assert.ok(categories.tooling.includes('scripts'));
|
|
59
|
-
assert.deepEqual(categories.unknown, []);
|
|
60
|
-
|
|
61
|
-
assert.ok(inventory.suggested.include.includes('scripts'), 'tracked top-2 language tooling is promoted');
|
|
62
|
-
assert.ok(inventory.top_level_details.scripts.loc >= 80);
|
|
63
|
-
assert.equal(inventory.top_level_details.scripts.dominant_language, 'Python');
|
|
64
|
-
|
|
65
|
-
assert.ok(inventory.root_files.manifest.includes('package.json'));
|
|
66
|
-
assert.ok(inventory.root_files.manifest.includes('wrangler.jsonc'));
|
|
67
|
-
assert.ok(inventory.root_files.manifest.includes('drizzle.config.ts'));
|
|
68
|
-
assert.ok(inventory.root_files.docs.includes('README.md'));
|
|
69
|
-
assert.ok(inventory.root_files.source.includes('entry.ts'));
|
|
70
|
-
assert.ok(inventory.root_files.lockfile.includes('package-lock.json'));
|
|
71
|
-
assert.ok(inventory.root_files.secret.includes('.env'));
|
|
72
|
-
assert.ok(inventory.root_files.secret.includes('.dev.vars'));
|
|
73
|
-
assert.ok(inventory.root_files.secret.includes('tls.pem'));
|
|
74
|
-
|
|
75
|
-
for (const wanted of ['package.json', 'wrangler.jsonc', 'drizzle.config.ts', 'README.md', 'entry.ts']) {
|
|
76
|
-
assert.ok(inventory.suggested.include_files.includes(wanted), wanted);
|
|
77
|
-
}
|
|
78
|
-
for (const forbidden of ['package-lock.json', '.env', '.dev.vars', 'tls.pem']) {
|
|
79
|
-
assert.ok(!inventory.suggested.include_files.includes(forbidden), forbidden);
|
|
80
|
-
}
|
|
81
|
-
|
|
82
|
-
const files = knowledgeInventory(root, { include: ['.'], exclude: [] });
|
|
83
|
-
assert.ok(files.includes('entry.ts'));
|
|
84
|
-
assert.ok(!files.includes('.env'));
|
|
85
|
-
assert.ok(!files.includes('.dev.vars'));
|
|
86
|
-
assert.ok(!files.includes('tls.pem'));
|
|
87
|
-
assert.ok(!files.includes('package-lock.json'));
|
|
88
|
-
} finally {
|
|
89
|
-
fs.rmSync(root, { recursive: true, force: true });
|
|
90
|
-
}
|
|
91
|
-
});
|
|
92
|
-
|
|
93
|
-
it('detects coherent theme signatures from markup and CSS evidence', () => {
|
|
94
|
-
const evidence = extractStyleEvidence(`
|
|
95
|
-
<html data-theme-preset="fuel-free-time" data-header-preset="adaptive-bar">
|
|
96
|
-
<link rel="stylesheet" href="/css/heuristic-theme.css">
|
|
97
|
-
<body>
|
|
98
|
-
<header class="fnf-header fnf-header--adaptive-bar">
|
|
99
|
-
<a class="fnf-logo"></a>
|
|
100
|
-
<nav class="fnf-primary"></nav>
|
|
101
|
-
</header>
|
|
102
|
-
</body>
|
|
103
|
-
</html>
|
|
104
|
-
<style>
|
|
105
|
-
:root { --fnf-accent: #ff4d00; --fnf-logo-height: 58px; }
|
|
106
|
-
.fnf-header { color: var(--fnf-accent); }
|
|
107
|
-
.fnf-logo { height: var(--fnf-logo-height); }
|
|
108
|
-
</style>
|
|
109
|
-
`);
|
|
110
|
-
|
|
111
|
-
assert.equal(evidence.theme_presets['fuel-free-time'], 1);
|
|
112
|
-
assert.equal(evidence.header_presets['adaptive-bar'], 1);
|
|
113
|
-
assert.equal(evidence.stylesheets['/css/heuristic-theme.css'], 1);
|
|
114
|
-
const fnf = evidence.namespaces.find((row) => row.prefix === 'fnf');
|
|
115
|
-
assert.ok(fnf);
|
|
116
|
-
assert.ok(fnf.signal_kinds >= 2);
|
|
117
|
-
assert.ok(fnf.signals.class_tokens >= 3);
|
|
118
|
-
assert.ok(fnf.signals.custom_properties >= 2);
|
|
119
|
-
|
|
120
|
-
const final = finalizeStyleEvidence(mergeStyleEvidence(null, evidence));
|
|
121
|
-
const finalFnf = final.namespaces.find((row) => row.prefix === 'fnf');
|
|
122
|
-
assert.equal(final.theme_candidate, true);
|
|
123
|
-
assert.equal(finalFnf?.candidate, true);
|
|
124
|
-
});
|
|
125
|
-
});
|
|
@@ -1,112 +0,0 @@
|
|
|
1
|
-
import test from 'node:test';
|
|
2
|
-
import assert from 'node:assert/strict';
|
|
3
|
-
import fs from 'node:fs';
|
|
4
|
-
import os from 'node:os';
|
|
5
|
-
import path from 'node:path';
|
|
6
|
-
import { fileURLToPath } from 'node:url';
|
|
7
|
-
import { defaultConfig } from '../../src/knowledge/config.js';
|
|
8
|
-
import { createKnowledgeJobEngine } from '../../src/knowledge/service/job-engine.js';
|
|
9
|
-
import { startKnowledgeHttpServer } from '../../src/knowledge/service/server.js';
|
|
10
|
-
import { startKnowledgeGrpcServer } from '../../src/knowledge/service/grpc-server.js';
|
|
11
|
-
import { createKnowledgeServiceClient } from '../../src/knowledge/service/client.js';
|
|
12
|
-
import { createKnowledgeGrpcClient } from '../../src/knowledge/service/grpc-client.js';
|
|
13
|
-
import { grpc } from '../../src/knowledge/service/grpc-codec.js';
|
|
14
|
-
|
|
15
|
-
const fixtureWorker = fileURLToPath(new URL('../fixtures/knowledge-rpc-worker.mjs', import.meta.url));
|
|
16
|
-
const sleep = ms => new Promise(resolve => setTimeout(resolve, ms));
|
|
17
|
-
|
|
18
|
-
async function waitFor(client, id, wanted = new Set(['completed', 'failed'])) {
|
|
19
|
-
for (let i = 0; i < 200; i++) {
|
|
20
|
-
const job = await client.job(id);
|
|
21
|
-
if (wanted.has(job.status)) return job;
|
|
22
|
-
await sleep(10);
|
|
23
|
-
}
|
|
24
|
-
throw new Error(`Job ${id} did not reach ${[...wanted].join('/')}.`);
|
|
25
|
-
}
|
|
26
|
-
|
|
27
|
-
async function collect(stream) {
|
|
28
|
-
const events = [];
|
|
29
|
-
for await (const event of stream) events.push(event);
|
|
30
|
-
return events;
|
|
31
|
-
}
|
|
32
|
-
|
|
33
|
-
test('knowledge HTTP and gRPC adapters share auth, validation, idempotency, lifecycle, cancellation, and durable jobs', async t => {
|
|
34
|
-
const tmp = fs.mkdtempSync(path.join(os.tmpdir(), 'agentsam-rpc-'));
|
|
35
|
-
t.after(() => fs.rmSync(tmp, { recursive: true, force: true }));
|
|
36
|
-
const root = path.join(tmp, 'repo');
|
|
37
|
-
const stateDir = path.join(tmp, 'state');
|
|
38
|
-
fs.mkdirSync(path.join(root, 'src'), { recursive: true });
|
|
39
|
-
fs.writeFileSync(path.join(root, 'src', 'sample.js'), 'export const sample = true;\n');
|
|
40
|
-
const config = defaultConfig({ include: ['src'] });
|
|
41
|
-
const repositories = { sample: { root, config } };
|
|
42
|
-
const token = 'r'.repeat(64);
|
|
43
|
-
const engine = createKnowledgeJobEngine({ stateDir, repositories, workerPath: fixtureWorker, jobTimeoutMs: 2_000 });
|
|
44
|
-
const http = await startKnowledgeHttpServer({ engine, token, port: 0 });
|
|
45
|
-
const rpcServer = await startKnowledgeGrpcServer({ engine, token, port: 0 });
|
|
46
|
-
const httpClient = createKnowledgeServiceClient({ baseUrl: `http://127.0.0.1:${http.address.port}`, token });
|
|
47
|
-
const rpc = createKnowledgeGrpcClient({ target: rpcServer.target, token });
|
|
48
|
-
const unauthorized = createKnowledgeGrpcClient({ target: rpcServer.target, token: 'x'.repeat(64) });
|
|
49
|
-
t.after(async () => {
|
|
50
|
-
unauthorized.close();
|
|
51
|
-
rpc.close();
|
|
52
|
-
await rpcServer.close();
|
|
53
|
-
await http.close();
|
|
54
|
-
await engine.close();
|
|
55
|
-
});
|
|
56
|
-
|
|
57
|
-
const repos = await rpc.repositories();
|
|
58
|
-
assert.deepEqual(repos.repositories, ['sample']);
|
|
59
|
-
assert.equal(repos.repository_details[0].repository_id, config.repository_id);
|
|
60
|
-
assert.equal(repos.embeddings_enabled, false);
|
|
61
|
-
await assert.rejects(unauthorized.repositories(), error => error.status === 401 && error.grpcCode === grpc.status.UNAUTHENTICATED);
|
|
62
|
-
await assert.rejects(
|
|
63
|
-
rpc.submit({ repository: 'sample', operation: 'bogus' }),
|
|
64
|
-
error => error.status === 400 && error.grpcCode === grpc.status.INVALID_ARGUMENT,
|
|
65
|
-
);
|
|
66
|
-
|
|
67
|
-
const request = { repository: 'sample', operation: 'index', generation_id: 'equivalent' };
|
|
68
|
-
const fromHttp = await httpClient.submit(request, 'cross-transport');
|
|
69
|
-
const fromGrpc = await rpc.submit(request, 'cross-transport');
|
|
70
|
-
assert.equal(fromGrpc.id, fromHttp.id);
|
|
71
|
-
await assert.rejects(
|
|
72
|
-
rpc.submit({ ...request, scope: 'different' }, 'cross-transport'),
|
|
73
|
-
error => error.status === 409 && error.grpcCode === grpc.status.ABORTED,
|
|
74
|
-
);
|
|
75
|
-
const completed = await waitFor(rpc, fromGrpc.id);
|
|
76
|
-
assert.equal(completed.status, 'completed');
|
|
77
|
-
assert.equal((await httpClient.job(fromGrpc.id)).result.repository_id, completed.result.repository_id);
|
|
78
|
-
|
|
79
|
-
const blocker = await rpc.submit({ repository: 'sample', operation: 'index', generation_id: 'slow' }, 'blocker');
|
|
80
|
-
await waitFor(rpc, blocker.id, new Set(['running']));
|
|
81
|
-
const watched = await rpc.submit({ repository: 'sample', operation: 'index', generation_id: 'watch' }, 'watched');
|
|
82
|
-
const lifecycle = await collect(rpc.watch(watched.id));
|
|
83
|
-
assert.deepEqual(lifecycle.map(event => event.job.status), ['queued', 'running', 'completed']);
|
|
84
|
-
assert.deepEqual(lifecycle.map(event => event.sequence), [1, 2, 3]);
|
|
85
|
-
|
|
86
|
-
const failed = await rpc.submit({ repository: 'sample', operation: 'index', generation_id: 'fail' }, 'failed');
|
|
87
|
-
const failureEvents = await collect(rpc.watch(failed.id));
|
|
88
|
-
assert.equal(failureEvents.at(-1).job.status, 'failed');
|
|
89
|
-
assert.match(failureEvents.at(-1).job.error, /fixture knowledge failure/);
|
|
90
|
-
|
|
91
|
-
const cancellable = await rpc.submit({ repository: 'sample', operation: 'index', generation_id: 'slow' }, 'cancel-watch');
|
|
92
|
-
const controller = new AbortController();
|
|
93
|
-
const iterator = rpc.watch(cancellable.id, { signal: controller.signal })[Symbol.asyncIterator]();
|
|
94
|
-
const first = await iterator.next();
|
|
95
|
-
assert.equal(first.done, false);
|
|
96
|
-
controller.abort();
|
|
97
|
-
const afterAbort = await iterator.next();
|
|
98
|
-
assert.equal(afterAbort.done, true);
|
|
99
|
-
assert.equal((await waitFor(rpc, cancellable.id)).status, 'completed');
|
|
100
|
-
|
|
101
|
-
const deadlineJob = await rpc.submit({ repository: 'sample', operation: 'index', generation_id: 'slow' }, 'deadline-watch');
|
|
102
|
-
let deadlineError = null;
|
|
103
|
-
try {
|
|
104
|
-
await collect(rpc.watch(deadlineJob.id, { timeoutMs: 15 }));
|
|
105
|
-
} catch (error) {
|
|
106
|
-
deadlineError = error;
|
|
107
|
-
}
|
|
108
|
-
assert.ok(deadlineError);
|
|
109
|
-
assert.equal(deadlineError.grpcCode, grpc.status.DEADLINE_EXCEEDED);
|
|
110
|
-
assert.equal(deadlineError.status, 504);
|
|
111
|
-
assert.equal((await waitFor(rpc, deadlineJob.id)).status, 'completed');
|
|
112
|
-
});
|
|
@@ -1,113 +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, before, after } from 'node:test';
|
|
5
|
-
import {
|
|
6
|
-
createLocalFilesystem,
|
|
7
|
-
createTempWorkspaceRoot,
|
|
8
|
-
LOCAL_FS_ENGINE,
|
|
9
|
-
} from '../../src/local-fs/index.js';
|
|
10
|
-
import { resolveContainedPath } from '../../src/local-fs/paths.js';
|
|
11
|
-
|
|
12
|
-
describe('local-fs path containment', () => {
|
|
13
|
-
/** @type {string} */
|
|
14
|
-
let root;
|
|
15
|
-
before(() => {
|
|
16
|
-
root = createTempWorkspaceRoot();
|
|
17
|
-
fs.writeFileSync(path.join(root, 'ok.txt'), 'hello\n');
|
|
18
|
-
fs.mkdirSync(path.join(root, 'sub'));
|
|
19
|
-
});
|
|
20
|
-
after(() => {
|
|
21
|
-
fs.rmSync(root, { recursive: true, force: true });
|
|
22
|
-
});
|
|
23
|
-
|
|
24
|
-
it('resolves relative paths inside root', () => {
|
|
25
|
-
const r = resolveContainedPath(root, 'ok.txt');
|
|
26
|
-
assert.equal(r.ok, true);
|
|
27
|
-
assert.equal(r.rel, 'ok.txt');
|
|
28
|
-
});
|
|
29
|
-
|
|
30
|
-
it('rejects traversal', () => {
|
|
31
|
-
const r = resolveContainedPath(root, '../outside.txt');
|
|
32
|
-
assert.equal(r.ok, false);
|
|
33
|
-
assert.equal(r.code, 'path_escape');
|
|
34
|
-
});
|
|
35
|
-
|
|
36
|
-
it('rejects NUL', () => {
|
|
37
|
-
const r = resolveContainedPath(root, 'a\0b.txt');
|
|
38
|
-
assert.equal(r.ok, false);
|
|
39
|
-
assert.equal(r.code, 'invalid_path');
|
|
40
|
-
});
|
|
41
|
-
|
|
42
|
-
it('rejects symlink escape when possible', () => {
|
|
43
|
-
const outside = createTempWorkspaceRoot('agentsam-fs-out-');
|
|
44
|
-
try {
|
|
45
|
-
fs.writeFileSync(path.join(outside, 'secret.txt'), 'nope');
|
|
46
|
-
const link = path.join(root, 'escape-link');
|
|
47
|
-
try {
|
|
48
|
-
fs.symlinkSync(path.join(outside, 'secret.txt'), link);
|
|
49
|
-
} catch {
|
|
50
|
-
// Windows may lack symlink privilege — skip
|
|
51
|
-
return;
|
|
52
|
-
}
|
|
53
|
-
const r = resolveContainedPath(root, 'escape-link');
|
|
54
|
-
assert.equal(r.ok, false);
|
|
55
|
-
assert.equal(r.code, 'path_escape');
|
|
56
|
-
} finally {
|
|
57
|
-
fs.rmSync(outside, { recursive: true, force: true });
|
|
58
|
-
}
|
|
59
|
-
});
|
|
60
|
-
});
|
|
61
|
-
|
|
62
|
-
describe('local-fs operations', () => {
|
|
63
|
-
/** @type {string} */
|
|
64
|
-
let root;
|
|
65
|
-
/** @type {ReturnType<typeof createLocalFilesystem>} */
|
|
66
|
-
let fsApi;
|
|
67
|
-
|
|
68
|
-
before(() => {
|
|
69
|
-
root = createTempWorkspaceRoot();
|
|
70
|
-
fsApi = createLocalFilesystem(root);
|
|
71
|
-
});
|
|
72
|
-
after(() => {
|
|
73
|
-
fs.rmSync(root, { recursive: true, force: true });
|
|
74
|
-
});
|
|
75
|
-
|
|
76
|
-
it('create / read / write with version conflict detection', () => {
|
|
77
|
-
assert.equal(fsApi.engine, LOCAL_FS_ENGINE);
|
|
78
|
-
const created = fsApi.create('README.md', '# one\n');
|
|
79
|
-
assert.equal(created.ok, true);
|
|
80
|
-
const v1 = created.version;
|
|
81
|
-
|
|
82
|
-
const read1 = fsApi.read('README.md');
|
|
83
|
-
assert.equal(read1.ok, true);
|
|
84
|
-
assert.equal(read1.content, '# one\n');
|
|
85
|
-
assert.equal(read1.version, v1);
|
|
86
|
-
|
|
87
|
-
const conflict = fsApi.write('README.md', '# stale\n', { expectedVersion: 'sha256:dead' });
|
|
88
|
-
assert.equal(conflict.ok, false);
|
|
89
|
-
assert.equal(conflict.code, 'version_conflict');
|
|
90
|
-
|
|
91
|
-
const wrote = fsApi.write('README.md', '# two\n', { expectedVersion: v1 });
|
|
92
|
-
assert.equal(wrote.ok, true);
|
|
93
|
-
assert.notEqual(wrote.version, v1);
|
|
94
|
-
assert.equal(fs.readFileSync(path.join(root, 'README.md'), 'utf8'), '# two\n');
|
|
95
|
-
});
|
|
96
|
-
|
|
97
|
-
it('list / rename / remove', () => {
|
|
98
|
-
fsApi.create('a.txt', 'a');
|
|
99
|
-
fsApi.mkdir('dir');
|
|
100
|
-
const listed = fsApi.list('.');
|
|
101
|
-
assert.equal(listed.ok, true);
|
|
102
|
-
assert.ok(listed.entries.some((e) => e.path === 'a.txt'));
|
|
103
|
-
|
|
104
|
-
const renamed = fsApi.rename('a.txt', 'b.txt');
|
|
105
|
-
assert.equal(renamed.ok, true);
|
|
106
|
-
assert.ok(fs.existsSync(path.join(root, 'b.txt')));
|
|
107
|
-
assert.equal(fs.existsSync(path.join(root, 'a.txt')), false);
|
|
108
|
-
|
|
109
|
-
const removed = fsApi.remove('b.txt');
|
|
110
|
-
assert.equal(removed.ok, true);
|
|
111
|
-
assert.equal(fs.existsSync(path.join(root, 'b.txt')), false);
|
|
112
|
-
});
|
|
113
|
-
});
|
|
@@ -1,65 +0,0 @@
|
|
|
1
|
-
import test from 'node:test';
|
|
2
|
-
import assert from 'node:assert/strict';
|
|
3
|
-
import { executeLocalProviderBridge } from '../../packages/agentsam-desktop-shell/scripts/local-provider-bridge.mjs';
|
|
4
|
-
|
|
5
|
-
const CANARY = 'sk-test-CANARY-123456';
|
|
6
|
-
|
|
7
|
-
function json(body, status = 200) {
|
|
8
|
-
return new Response(JSON.stringify(body), { status, headers: { 'content-type': 'application/json' } });
|
|
9
|
-
}
|
|
10
|
-
|
|
11
|
-
function openAiFetch(url, init = {}) {
|
|
12
|
-
assert.equal(init.headers?.authorization, `Bearer ${CANARY}`);
|
|
13
|
-
if (String(url).endsWith('/v1/models')) {
|
|
14
|
-
return Promise.resolve(json({ data: [{ id: 'gpt-5.6-sol', object: 'model' }] }));
|
|
15
|
-
}
|
|
16
|
-
if (String(url).endsWith('/v1/responses')) {
|
|
17
|
-
return Promise.resolve(json({
|
|
18
|
-
id: 'resp_local_fixture',
|
|
19
|
-
status: 'completed',
|
|
20
|
-
output_text: 'offline bridge works',
|
|
21
|
-
output: [],
|
|
22
|
-
usage: { input_tokens: 3, output_tokens: 4 },
|
|
23
|
-
}));
|
|
24
|
-
}
|
|
25
|
-
throw new Error(`unexpected_url:${url}`);
|
|
26
|
-
}
|
|
27
|
-
|
|
28
|
-
test('device OpenAI credential discovers live inventory without leaking the key', async () => {
|
|
29
|
-
const result = await executeLocalProviderBridge({
|
|
30
|
-
operation: 'inventory',
|
|
31
|
-
credentials: { openai: CANARY },
|
|
32
|
-
}, { fetchImpl: openAiFetch });
|
|
33
|
-
assert.equal(result.ok, true);
|
|
34
|
-
assert.equal(result.credential_plane, 'device_keychain');
|
|
35
|
-
assert.equal(result.providers.find((row) => row.id === 'openai')?.configured, true);
|
|
36
|
-
assert.equal(result.availableModels.some((row) => row.provider === 'openai' && row.model_id === 'gpt-5.6-sol'), true);
|
|
37
|
-
assert.equal(JSON.stringify(result).includes(CANARY), false);
|
|
38
|
-
});
|
|
39
|
-
|
|
40
|
-
test('device OpenAI credential chats through canonical Responses adapter without leaking the key', async () => {
|
|
41
|
-
const result = await executeLocalProviderBridge({
|
|
42
|
-
operation: 'chat',
|
|
43
|
-
provider: 'openai',
|
|
44
|
-
model_id: 'gpt-5.6-sol',
|
|
45
|
-
messages: [{ role: 'user', content: 'hello' }],
|
|
46
|
-
credentials: { openai: CANARY },
|
|
47
|
-
}, { fetchImpl: openAiFetch });
|
|
48
|
-
assert.deepEqual(result, {
|
|
49
|
-
ok: true,
|
|
50
|
-
provider: 'openai',
|
|
51
|
-
model_id: 'gpt-5.6-sol',
|
|
52
|
-
text: 'offline bridge works',
|
|
53
|
-
});
|
|
54
|
-
assert.equal(JSON.stringify(result).includes(CANARY), false);
|
|
55
|
-
});
|
|
56
|
-
|
|
57
|
-
test('provider rejection is sanitized and never echoes credential material', async () => {
|
|
58
|
-
const result = await executeLocalProviderBridge({
|
|
59
|
-
operation: 'inventory',
|
|
60
|
-
credentials: { openai: CANARY },
|
|
61
|
-
}, {
|
|
62
|
-
fetchImpl: async () => json({ error: { message: `bad ${CANARY}` } }, 401),
|
|
63
|
-
});
|
|
64
|
-
assert.equal(JSON.stringify(result).includes(CANARY), false);
|
|
65
|
-
});
|
|
@@ -1,40 +0,0 @@
|
|
|
1
|
-
import test from 'node:test';
|
|
2
|
-
import assert from 'node:assert/strict';
|
|
3
|
-
import { readFileSync } from 'node:fs';
|
|
4
|
-
|
|
5
|
-
function read(path) {
|
|
6
|
-
return readFileSync(new URL(`../../${path}`, import.meta.url), 'utf8');
|
|
7
|
-
}
|
|
8
|
-
|
|
9
|
-
const settingsPage = read('apps/local-studio/frontend/src/components/settings/LocalStudioSettingsPage.tsx');
|
|
10
|
-
const settingsHost = read('apps/local-studio/frontend/src/components/settings/localStudioSettingsHost.ts');
|
|
11
|
-
const shell = read('apps/local-studio/frontend/agentsam/AgentSamShell.tsx');
|
|
12
|
-
const keysPage = read('apps/local-studio/frontend/src/components/settings/LiveKeysSettingsPage.tsx');
|
|
13
|
-
const apiKeys = read('apps/local-studio/frontend/src/components/settings/ApiKeysTable.tsx');
|
|
14
|
-
const settingsFrontend = read('packages/agentsam-settings/src/frontend/index.tsx');
|
|
15
|
-
|
|
16
|
-
test('production Settings never mounts fixture data', () => {
|
|
17
|
-
assert.doesNotMatch(settingsPage, /createFixtureSettingsHost|getSettingsFixture|SettingsFixtureName/);
|
|
18
|
-
assert.doesNotMatch(settingsHost, /demo-app|Demo Org|health:\s*["']healthy["']/i);
|
|
19
|
-
assert.match(settingsHost, /repositoryLabel:\s*["']Not connected["']/);
|
|
20
|
-
assert.match(settingsHost, /browser:\s*["']Not checked["']/);
|
|
21
|
-
assert.match(settingsHost, /health:\s*["']unknown["']/);
|
|
22
|
-
assert.doesNotMatch(settingsFrontend, /demo-app|Demo Org/);
|
|
23
|
-
});
|
|
24
|
-
|
|
25
|
-
test('Settings route suppresses the outer application sidenav', () => {
|
|
26
|
-
assert.match(shell, /const isSettings = pathname === ['"]\/settings['"] \|\| pathname\.startsWith\(['"]\/settings\/['"]\)/);
|
|
27
|
-
assert.match(shell, /!isSettings \? <Nav\.Sidenav \/> : null/);
|
|
28
|
-
});
|
|
29
|
-
|
|
30
|
-
test('Keys page has a visible explicit AgentSam key trigger', () => {
|
|
31
|
-
assert.match(keysPage, /variant="secondary"/);
|
|
32
|
-
assert.match(keysPage, /Create AgentSam key/);
|
|
33
|
-
});
|
|
34
|
-
|
|
35
|
-
test('account provider rows show live discovery trust status', () => {
|
|
36
|
-
assert.match(apiKeys, /accountInventoryRequest/);
|
|
37
|
-
assert.match(apiKeys, /Connected · \$\{count\} model/);
|
|
38
|
-
assert.match(apiKeys, /rejected this key/);
|
|
39
|
-
assert.match(apiKeys, /Not selected/);
|
|
40
|
-
});
|
|
@@ -1,26 +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
|
-
|
|
7
|
-
const root = path.resolve(path.dirname(fileURLToPath(import.meta.url)), '../..');
|
|
8
|
-
|
|
9
|
-
test('every workspace and link path in package-lock.json exists on disk', () => {
|
|
10
|
-
const lock = JSON.parse(fs.readFileSync(path.join(root, 'package-lock.json'), 'utf8'));
|
|
11
|
-
const paths = new Set();
|
|
12
|
-
for (const [key, value] of Object.entries(lock.packages)) {
|
|
13
|
-
if (key && !key.includes('node_modules/')) paths.add(key);
|
|
14
|
-
if (value.link && value.resolved) paths.add(value.resolved);
|
|
15
|
-
}
|
|
16
|
-
const missing = [...paths].filter((p) => !fs.existsSync(path.join(root, p)));
|
|
17
|
-
assert.deepEqual(missing, []);
|
|
18
|
-
});
|
|
19
|
-
|
|
20
|
-
test('package.json bin map matches package-lock packages[""].bin', () => {
|
|
21
|
-
const pkg = JSON.parse(fs.readFileSync(path.join(root, 'package.json'), 'utf8'));
|
|
22
|
-
const lock = JSON.parse(fs.readFileSync(path.join(root, 'package-lock.json'), 'utf8'));
|
|
23
|
-
const pkgBin = pkg.bin || {};
|
|
24
|
-
const lockBin = (lock.packages && lock.packages[''] && lock.packages[''].bin) || {};
|
|
25
|
-
assert.deepEqual(lockBin, pkgBin);
|
|
26
|
-
});
|
|
@@ -1,61 +0,0 @@
|
|
|
1
|
-
import assert from 'node:assert/strict';
|
|
2
|
-
import { test } from 'node:test';
|
|
3
|
-
import fs from 'node:fs/promises';
|
|
4
|
-
import os from 'node:os';
|
|
5
|
-
import path from 'node:path';
|
|
6
|
-
import { spawnSync } from 'node:child_process';
|
|
7
|
-
import { fileURLToPath } from 'node:url';
|
|
8
|
-
|
|
9
|
-
const cli = fileURLToPath(new URL('../../src/cli.js', import.meta.url));
|
|
10
|
-
|
|
11
|
-
async function fixture(t) {
|
|
12
|
-
const root = await fs.mkdtemp(path.join(os.tmpdir(), 'agentsam-merkle-cli-test-'));
|
|
13
|
-
t.after(() => fs.rm(root, { recursive: true, force: true }));
|
|
14
|
-
return root;
|
|
15
|
-
}
|
|
16
|
-
|
|
17
|
-
async function write(root, name, content = name) {
|
|
18
|
-
await fs.mkdir(path.dirname(path.join(root, name)), { recursive: true });
|
|
19
|
-
await fs.writeFile(path.join(root, name), content);
|
|
20
|
-
}
|
|
21
|
-
|
|
22
|
-
function run(args, cwd) {
|
|
23
|
-
return spawnSync(process.execPath, [cli, 'merkle', ...args], {
|
|
24
|
-
cwd,
|
|
25
|
-
encoding: 'utf8',
|
|
26
|
-
timeout: 15000,
|
|
27
|
-
});
|
|
28
|
-
}
|
|
29
|
-
|
|
30
|
-
test('CLI snapshot/verify/diff supports JSON, moved roots, and distinct mismatch/error exit codes', async (t) => {
|
|
31
|
-
const root = await fixture(t), moved = await fixture(t);
|
|
32
|
-
await write(root, 'a.txt', 'hello');
|
|
33
|
-
await write(moved, 'a.txt', 'hello');
|
|
34
|
-
|
|
35
|
-
const saved = run(['snapshot', '.', '--json'], root);
|
|
36
|
-
assert.equal(saved.status, 0, saved.stderr);
|
|
37
|
-
const manifest = JSON.parse(saved.stdout);
|
|
38
|
-
assert.ok(manifest.output.endsWith('merkle.json'));
|
|
39
|
-
|
|
40
|
-
const matching = run(['verify', manifest.output, '--root', moved, '--json'], root);
|
|
41
|
-
assert.equal(matching.status, 0, matching.stderr);
|
|
42
|
-
assert.equal(JSON.parse(matching.stdout).equal, true);
|
|
43
|
-
|
|
44
|
-
await write(moved, 'a.txt', 'changed');
|
|
45
|
-
await write(moved, 'b.txt', 'new');
|
|
46
|
-
const changed = run(['verify', manifest.output, '--root', moved, '--json'], root);
|
|
47
|
-
assert.equal(changed.status, 1, changed.stderr);
|
|
48
|
-
assert.deepEqual(JSON.parse(changed.stdout).stats, { unchanged: 0, modified: 1, added: 1, removed: 0 });
|
|
49
|
-
|
|
50
|
-
const diff = run(['diff', root, moved, '--json'], root);
|
|
51
|
-
assert.equal(diff.status, 1, diff.stderr);
|
|
52
|
-
|
|
53
|
-
const invalid = run(['root', '.', '--typo', '--json'], root);
|
|
54
|
-
assert.equal(invalid.status, 2);
|
|
55
|
-
assert.equal(invalid.stdout, '');
|
|
56
|
-
assert.match(JSON.parse(invalid.stderr).error, /Unknown option/);
|
|
57
|
-
|
|
58
|
-
const piped = run(['inspect', '.', '--tui'], root);
|
|
59
|
-
assert.equal(piped.status, 0, piped.stderr);
|
|
60
|
-
assert.ok(!piped.stdout.includes('\x1b'));
|
|
61
|
-
});
|
|
@@ -1,48 +0,0 @@
|
|
|
1
|
-
import assert from 'node:assert/strict';
|
|
2
|
-
import fs from 'node:fs/promises';
|
|
3
|
-
import os from 'node:os';
|
|
4
|
-
import path from 'node:path';
|
|
5
|
-
import { execFileSync } from 'node:child_process';
|
|
6
|
-
import { test } from 'node:test';
|
|
7
|
-
import { resolveMerklePersistenceIdentity } from '../../src/commands/merkle-persist.js';
|
|
8
|
-
|
|
9
|
-
async function gitFixture(t, remote = null) {
|
|
10
|
-
const root = await fs.mkdtemp(path.join(os.tmpdir(), 'agentsam-merkle-identity-'));
|
|
11
|
-
t.after(() => fs.rm(root, { recursive: true, force: true }));
|
|
12
|
-
execFileSync('git', ['init', '-q', root]);
|
|
13
|
-
if (remote) execFileSync('git', ['-C', root, 'remote', 'add', 'origin', remote]);
|
|
14
|
-
return root;
|
|
15
|
-
}
|
|
16
|
-
|
|
17
|
-
test('Merkle persistence identity uses authenticated session + Git provider identity', async (t) => {
|
|
18
|
-
const root = await gitFixture(t, 'git@github.com:SamPrimeaux/agentsam-sdk.git');
|
|
19
|
-
const identity = resolveMerklePersistenceIdentity(root, {
|
|
20
|
-
session: { account_id: 'au_test' },
|
|
21
|
-
projectConfig: { repository: { id: 'local:should-not-win' } },
|
|
22
|
-
});
|
|
23
|
-
assert.deepEqual(identity, {
|
|
24
|
-
accountId: 'au_test',
|
|
25
|
-
repositoryId: 'github:samprimeaux/agentsam-sdk',
|
|
26
|
-
repositoryIdentitySource: 'git',
|
|
27
|
-
});
|
|
28
|
-
});
|
|
29
|
-
|
|
30
|
-
test('local repositories fall back to committed project identity', async (t) => {
|
|
31
|
-
const root = await gitFixture(t);
|
|
32
|
-
const identity = resolveMerklePersistenceIdentity(root, {
|
|
33
|
-
session: { account_id: 'au_test' },
|
|
34
|
-
projectConfig: { repository: { id: 'local:fixture-repository' } },
|
|
35
|
-
});
|
|
36
|
-
assert.equal(identity.repositoryId, 'local:fixture-repository');
|
|
37
|
-
assert.equal(identity.repositoryIdentitySource, 'project_manifest');
|
|
38
|
-
});
|
|
39
|
-
|
|
40
|
-
test('Merkle persistence refuses unauthenticated ownership', async (t) => {
|
|
41
|
-
const root = await gitFixture(t, 'https://github.com/SamPrimeaux/agentsam-sdk.git');
|
|
42
|
-
assert.throws(() => resolveMerklePersistenceIdentity(root, { session: null }), /agentsam_login_required_for_merkle_persistence/);
|
|
43
|
-
});
|
|
44
|
-
|
|
45
|
-
test('Merkle persistence CLI has no account/repository ownership env shortcuts', async () => {
|
|
46
|
-
const source = await fs.readFile(new URL('../../src/commands/merkle-persist.js', import.meta.url), 'utf8');
|
|
47
|
-
assert.doesNotMatch(source, /AGENTSAM_ACCOUNT_ID|AGENTSAM_REPOSITORY_ID|--account-id|--repository-id/);
|
|
48
|
-
});
|