@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,82 +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 { buildWranglerInvocation, listWranglerNativeCommands, runWranglerNative, summarizeCloudflareCpuProfile, summarizeCloudflareCpuProfileFile } from '../src/cloudflare/index.js';
|
|
7
|
-
import { createCapabilityAdapter } from '../src/agent/capability-adapter.js';
|
|
8
|
-
|
|
9
|
-
function tempRoot() { return fs.mkdtempSync(path.join(os.tmpdir(), 'agentsam-cf-')); }
|
|
10
|
-
|
|
11
|
-
test('Cloudflare native command catalog exposes bounded read operations and never an auth-token secret read', () => {
|
|
12
|
-
const ids = listWranglerNativeCommands().map((row) => row.id);
|
|
13
|
-
assert.deepEqual(ids, ['whoami', 'deployments.list', 'versions.list', 'versions.view', 'types.check', 'queues.list', 'tunnel.list', 'tunnel.info']);
|
|
14
|
-
assert.ok(!ids.some((id) => id.includes('token') || id.includes('secret') || id === 'deploy'));
|
|
15
|
-
});
|
|
16
|
-
|
|
17
|
-
test('Wrangler version view requires an exact version and keeps secret values unavailable', () => {
|
|
18
|
-
const root = tempRoot();
|
|
19
|
-
const plan = buildWranglerInvocation('versions.view', { cwd: root, name: 'demo', version_id: 'ver_123' });
|
|
20
|
-
assert.deepEqual(plan.args, ['versions', 'view', 'ver_123', '--json', '--name', 'demo']);
|
|
21
|
-
assert.throws(() => buildWranglerInvocation('versions.view', { cwd: root, name: 'demo' }), /version_id_required/);
|
|
22
|
-
});
|
|
23
|
-
|
|
24
|
-
test('Wrangler native invocation is argv-based and cwd/config scoped', () => {
|
|
25
|
-
const root = tempRoot();
|
|
26
|
-
fs.writeFileSync(path.join(root, 'wrangler.jsonc'), '{}');
|
|
27
|
-
const plan = buildWranglerInvocation('deployments.list', { cwd: root, name: 'demo' });
|
|
28
|
-
assert.equal(plan.cwd, root);
|
|
29
|
-
assert.deepEqual(plan.args.slice(0, 4), ['deployments', 'list', '--json', '--name']);
|
|
30
|
-
assert.equal(plan.args[4], 'demo');
|
|
31
|
-
assert.ok(plan.args.includes('--config'));
|
|
32
|
-
assert.throws(() => buildWranglerInvocation('whoami', { cwd: root, config: '../outside.toml' }), /outside_cwd/);
|
|
33
|
-
});
|
|
34
|
-
|
|
35
|
-
test('Wrangler native result preserves JSON and real exit code on failure', async () => {
|
|
36
|
-
const root = tempRoot();
|
|
37
|
-
const success = await runWranglerNative('whoami', { cwd: root }, { run: async () => ({ code: 0, stdout: JSON.stringify({ email: 'dev@example.com' }), stderr: '' }) });
|
|
38
|
-
assert.equal(success.data.email, 'dev@example.com');
|
|
39
|
-
await assert.rejects(
|
|
40
|
-
runWranglerNative('versions.list', { cwd: root }, { run: async () => ({ code: 7, stdout: '', stderr: 'upstream failed' }) }),
|
|
41
|
-
(error) => error.diagnostic?.exit_code === 7 && error.diagnostic?.code === 'wrangler_exit_nonzero',
|
|
42
|
-
);
|
|
43
|
-
await assert.rejects(
|
|
44
|
-
runWranglerNative('deployments.list', { cwd: root }, { run: async () => ({ code: 1, stdout: '', stderr: 'Authentication error [code: 10000]\nRequest ID: req_cf_1\nCF-Ray: ray-123' }) }),
|
|
45
|
-
(error) => error.diagnostic?.code === '10000' && error.diagnostic?.request_id === 'req_cf_1' && error.diagnostic?.ray_id === 'ray-123',
|
|
46
|
-
);
|
|
47
|
-
});
|
|
48
|
-
|
|
49
|
-
test('CPU profile summary ranks self-time hotspots and explicitly rejects production timer inference', () => {
|
|
50
|
-
const profile = {
|
|
51
|
-
nodes: [
|
|
52
|
-
{ id: 1, callFrame: { functionName: 'fetch', url: 'worker.js', lineNumber: 0, columnNumber: 0 } },
|
|
53
|
-
{ id: 2, callFrame: { functionName: 'heavyLoop', url: 'worker.js', lineNumber: 10, columnNumber: 2 } },
|
|
54
|
-
{ id: 3, callFrame: { functionName: '(garbage collector)', url: '', lineNumber: -1, columnNumber: -1 } },
|
|
55
|
-
],
|
|
56
|
-
samples: [1, 2, 2, 3],
|
|
57
|
-
timeDeltas: [100, 1200, 800, 400],
|
|
58
|
-
};
|
|
59
|
-
const summary = summarizeCloudflareCpuProfile(profile);
|
|
60
|
-
assert.equal(summary.top_frames[0].function, 'heavyLoop');
|
|
61
|
-
assert.equal(summary.top_frames[0].self_us, 2000);
|
|
62
|
-
assert.equal(summary.garbage_collection_ms, 0.4);
|
|
63
|
-
assert.match(summary.timer_semantics, /do not advance during CPU-only execution/);
|
|
64
|
-
});
|
|
65
|
-
|
|
66
|
-
test('CPU profile file cannot escape runtime cwd', () => {
|
|
67
|
-
const root = tempRoot();
|
|
68
|
-
fs.writeFileSync(path.join(root, 'profile.cpuprofile'), JSON.stringify({ nodes: [], samples: [], timeDeltas: [] }));
|
|
69
|
-
assert.equal(summarizeCloudflareCpuProfileFile({ cwd: root, file: 'profile.cpuprofile' }).file, 'profile.cpuprofile');
|
|
70
|
-
assert.throws(() => summarizeCloudflareCpuProfileFile({ cwd: root, file: '../profile.cpuprofile' }), /outside_cwd/);
|
|
71
|
-
});
|
|
72
|
-
|
|
73
|
-
test('explicitly executable experimental Cloudflare capabilities enter cards-first discovery without exposing unavailable commands', () => {
|
|
74
|
-
const adapter = createCapabilityAdapter();
|
|
75
|
-
const rows = adapter.toolDescriptors();
|
|
76
|
-
const ids = rows.map((row) => row.name);
|
|
77
|
-
assert.ok(ids.includes('cloudflare.wrangler.native'));
|
|
78
|
-
assert.ok(ids.includes('cloudflare.cpu.profile'));
|
|
79
|
-
assert.ok(!ids.includes('cloudflare.cpu.audit'));
|
|
80
|
-
assert.ok(!ids.includes('blender.build'));
|
|
81
|
-
assert.equal(rows.find((row) => row.name === 'cloudflare.wrangler.native').risk, 'read');
|
|
82
|
-
});
|
package/test/context.test.mjs
DELETED
|
@@ -1,159 +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
|
-
DEFAULT_RESULT_POLICY,
|
|
8
|
-
assessContextUsage,
|
|
9
|
-
compileAgentInstructions,
|
|
10
|
-
createContextBudget,
|
|
11
|
-
normalizeResultPolicy,
|
|
12
|
-
resolveContext,
|
|
13
|
-
resolveProjectContext,
|
|
14
|
-
} from '../src/context/index.js';
|
|
15
|
-
|
|
16
|
-
test('default result policy is bounded and callers may request less', () => {
|
|
17
|
-
assert.deepEqual(DEFAULT_RESULT_POLICY, { max_items: 8, max_chars: 24_000, detail: 'excerpt' });
|
|
18
|
-
assert.deepEqual(normalizeResultPolicy({ max_items: 3, max_chars: 8_000, detail: 'card' }), { max_items: 3, max_chars: 8_000, detail: 'card' });
|
|
19
|
-
assert.throws(() => normalizeResultPolicy({ max_items: 9 }), /higher_detail_required:max_items/);
|
|
20
|
-
assert.throws(() => normalizeResultPolicy({ max_chars: 24_001 }), /higher_detail_required:max_chars/);
|
|
21
|
-
assert.throws(() => normalizeResultPolicy({ detail: 'full' }), /higher_detail_required:detail/);
|
|
22
|
-
assert.equal(normalizeResultPolicy({ detail: 'full', max_items: 20, max_chars: 100_000 }, { operation: 'higher-detail' }).detail, 'full');
|
|
23
|
-
});
|
|
24
|
-
|
|
25
|
-
test('legacy ratio context budget remains compatible for ordinary windows', () => {
|
|
26
|
-
const budget = createContextBudget({ windowTokens: 250_000 });
|
|
27
|
-
assert.equal(budget.targetInputTokens, 150_000);
|
|
28
|
-
assert.equal(budget.hardInputTokens, 212_500);
|
|
29
|
-
assert.equal(budget.windowChars, 1_000_000);
|
|
30
|
-
assert.equal(budget.maxSystemChars, 50_000);
|
|
31
|
-
assert.equal(budget.maxToolSchemaChars, 40_000);
|
|
32
|
-
assert.equal(budget.maxEvidenceChars, 100_000);
|
|
33
|
-
assert.equal(budget.maxFileCharsPerRead, 32_768);
|
|
34
|
-
assert.equal(budget.maxFileCharsPerTurn, 131_072);
|
|
35
|
-
assert.equal(budget.maxToolResultChars, 24_000);
|
|
36
|
-
});
|
|
37
|
-
|
|
38
|
-
test('large model capacity is independent from AgentSam working-set and pricing policy', () => {
|
|
39
|
-
const budget = createContextBudget({
|
|
40
|
-
windowTokens: 1_050_000,
|
|
41
|
-
targetInputTokens: 120_000,
|
|
42
|
-
compactAtTokens: 180_000,
|
|
43
|
-
interveneAtTokens: 220_000,
|
|
44
|
-
maxNormalInputTokens: 250_000,
|
|
45
|
-
pricingThresholdTokens: 272_000,
|
|
46
|
-
safetyMarginTokens: 22_000,
|
|
47
|
-
});
|
|
48
|
-
assert.equal(budget.windowTokens, 1_050_000);
|
|
49
|
-
assert.equal(budget.targetInputTokens, 120_000);
|
|
50
|
-
assert.equal(budget.compactAtTokens, 180_000);
|
|
51
|
-
assert.equal(budget.interveneAtTokens, 220_000);
|
|
52
|
-
assert.equal(budget.maxNormalInputTokens, 250_000);
|
|
53
|
-
assert.equal(budget.pricingThresholdTokens, 272_000);
|
|
54
|
-
assert.ok(budget.targetInputRatio < 0.12);
|
|
55
|
-
|
|
56
|
-
assert.equal(assessContextUsage(179_999, budget).shouldCompact, false);
|
|
57
|
-
assert.equal(assessContextUsage(180_000, budget).shouldCompact, true);
|
|
58
|
-
assert.equal(assessContextUsage(272_000, budget).pricingThresholdCrossed, false);
|
|
59
|
-
const crossed = assessContextUsage(272_001, budget);
|
|
60
|
-
assert.equal(crossed.pricingThresholdCrossed, true);
|
|
61
|
-
assert.equal(crossed.tokensUntilPricingThreshold, -1);
|
|
62
|
-
});
|
|
63
|
-
|
|
64
|
-
test('context.resolve separates composition classes and returns an economic receipt', () => {
|
|
65
|
-
const budget = createContextBudget({
|
|
66
|
-
windowTokens: 32_000,
|
|
67
|
-
maxEvidenceChars: 90,
|
|
68
|
-
maxFileCharsPerRead: 50,
|
|
69
|
-
maxFileCharsPerTurn: 60,
|
|
70
|
-
maxToolResultChars: 30,
|
|
71
|
-
});
|
|
72
|
-
const pack = resolveContext({
|
|
73
|
-
objective: 'fix terminal cwd persistence',
|
|
74
|
-
refs: ['repo:demo'],
|
|
75
|
-
budget,
|
|
76
|
-
instructionChars: 20,
|
|
77
|
-
toolSchemaChars: 12,
|
|
78
|
-
historyChars: 8,
|
|
79
|
-
items: [
|
|
80
|
-
{ ref: 'file:low', kind: 'file', priority: 1, content: 'L'.repeat(50) },
|
|
81
|
-
{ ref: 'tool:high', kind: 'tool_result', priority: 10, content: 'T'.repeat(50) },
|
|
82
|
-
{ ref: 'file:high', kind: 'file', priority: 8, content: 'F'.repeat(80) },
|
|
83
|
-
{ ref: 'memory:later', kind: 'memory', priority: 0, content: 'M'.repeat(40) },
|
|
84
|
-
],
|
|
85
|
-
});
|
|
86
|
-
|
|
87
|
-
assert.deepEqual(pack.items.map((item) => item.ref), ['tool:high', 'file:high', 'file:low']);
|
|
88
|
-
assert.equal(pack.items[0].chars, 30);
|
|
89
|
-
assert.equal(pack.items[1].chars, 50);
|
|
90
|
-
assert.equal(pack.items[2].chars, 10);
|
|
91
|
-
assert.equal(pack.receipt.tool_result_chars, 30);
|
|
92
|
-
assert.equal(pack.receipt.evidence_chars, 60);
|
|
93
|
-
assert.equal(pack.receipt.instruction_chars, 20);
|
|
94
|
-
assert.equal(pack.receipt.tool_schema_chars, 12);
|
|
95
|
-
assert.equal(pack.receipt.history_chars, 8);
|
|
96
|
-
assert.equal(pack.receipt.chars, 130);
|
|
97
|
-
assert.equal(pack.receipt.estimate_kind, 'local');
|
|
98
|
-
assert.equal(pack.receipt.window_tokens, 32_000);
|
|
99
|
-
assert.equal(pack.receipt.sources_considered, 4);
|
|
100
|
-
assert.equal(pack.receipt.sources_included, 3);
|
|
101
|
-
assert.ok(pack.receipt.sources_deferred >= 3);
|
|
102
|
-
assert.ok(pack.receipt.deferred_refs.includes('memory:later'));
|
|
103
|
-
assert.deepEqual(pack.receipt.rehydratable_refs, ['tool:high', 'file:high', 'file:low']);
|
|
104
|
-
});
|
|
105
|
-
|
|
106
|
-
test('AgentSam instructions compile in stable then repository-specific precedence', t => {
|
|
107
|
-
const root = fs.mkdtempSync(path.join(os.tmpdir(), 'agentsam-instructions-'));
|
|
108
|
-
t.after(() => fs.rmSync(root, { recursive: true, force: true }));
|
|
109
|
-
fs.mkdirSync(path.join(root, '.git'));
|
|
110
|
-
fs.writeFileSync(path.join(root, 'AGENTSAM.md'), '# Stable\nbase law\n');
|
|
111
|
-
fs.writeFileSync(path.join(root, '.agentsamrules'), '# Repo\nlocal law\n');
|
|
112
|
-
const compiled = compileAgentInstructions(root);
|
|
113
|
-
assert.deepEqual(compiled.precedence, ['AGENTSAM.md', '.agentsamrules']);
|
|
114
|
-
assert.equal(compiled.sources.length, 2);
|
|
115
|
-
assert.ok(compiled.content.indexOf('base law') < compiled.content.indexOf('local law'));
|
|
116
|
-
});
|
|
117
|
-
|
|
118
|
-
test('compatibility shims are not compiled into AgentSam instruction authority', t => {
|
|
119
|
-
const root = fs.mkdtempSync(path.join(os.tmpdir(), 'agentsam-instruction-shims-'));
|
|
120
|
-
t.after(() => fs.rmSync(root, { recursive: true, force: true }));
|
|
121
|
-
fs.mkdirSync(path.join(root, '.git'));
|
|
122
|
-
fs.writeFileSync(path.join(root, 'AGENTSAM.md'), '# Stable\ncanonical only\n');
|
|
123
|
-
fs.writeFileSync(path.join(root, 'AGENTS.md'), 'shim should not become policy\n');
|
|
124
|
-
fs.writeFileSync(path.join(root, 'CLAUDE.md'), 'claude shim should not become policy\n');
|
|
125
|
-
const compiled = compileAgentInstructions(root);
|
|
126
|
-
assert.equal(compiled.sources.length, 1);
|
|
127
|
-
assert.equal(compiled.sources[0].filename, 'AGENTSAM.md');
|
|
128
|
-
assert.match(compiled.content, /canonical only/);
|
|
129
|
-
assert.doesNotMatch(compiled.content, /shim should not become policy/);
|
|
130
|
-
assert.doesNotMatch(compiled.content, /claude shim should not become policy/);
|
|
131
|
-
});
|
|
132
|
-
|
|
133
|
-
test('project context loads bounded compiled AgentSam instructions', t => {
|
|
134
|
-
const root = fs.mkdtempSync(path.join(os.tmpdir(), 'agentsam-context-rules-'));
|
|
135
|
-
t.after(() => fs.rmSync(root, { recursive: true, force: true }));
|
|
136
|
-
fs.mkdirSync(path.join(root, '.git'));
|
|
137
|
-
fs.writeFileSync(path.join(root, 'AGENTSAM.md'), '# stable\n' + 'a'.repeat(300));
|
|
138
|
-
fs.writeFileSync(path.join(root, '.agentsamrules'), '# rules\n' + 'x'.repeat(5000) + '\n');
|
|
139
|
-
const pack = resolveProjectContext({
|
|
140
|
-
cwd: root,
|
|
141
|
-
objective: 'inspect repository',
|
|
142
|
-
budget: createContextBudget({ windowTokens: 8_000, maxSystemChars: 1_000, maxEvidenceChars: 1_000 }),
|
|
143
|
-
items: [],
|
|
144
|
-
});
|
|
145
|
-
assert.equal(pack.rules.found, true);
|
|
146
|
-
assert.equal(pack.rules.chars, 1_000);
|
|
147
|
-
assert.equal(pack.rules.truncated, true);
|
|
148
|
-
assert.equal(pack.receipt.system_chars, 1_000);
|
|
149
|
-
});
|
|
150
|
-
|
|
151
|
-
test('consumed tool results compact to 4k while preserving rehydration identity', async () => {
|
|
152
|
-
const { compactConsumedToolResult } = await import('../src/context/index.js');
|
|
153
|
-
const item = compactConsumedToolResult('x'.repeat(10_000), { ref: 'tool:call_123', hash: 'sha256:abc' });
|
|
154
|
-
assert.equal(item.ref, 'tool:call_123');
|
|
155
|
-
assert.equal(item.hash, 'sha256:abc');
|
|
156
|
-
assert.equal(item.chars, 4_000);
|
|
157
|
-
assert.equal(item.compacted, true);
|
|
158
|
-
assert.equal(item.source_chars, 10_000);
|
|
159
|
-
});
|
|
@@ -1,113 +0,0 @@
|
|
|
1
|
-
import assert from 'node:assert/strict';
|
|
2
|
-
import test from 'node:test';
|
|
3
|
-
import {
|
|
4
|
-
remediateGcloudEdgeServiceAccountKey,
|
|
5
|
-
remediateGcloudPermissionDenied,
|
|
6
|
-
remediateGithubTokenShadow,
|
|
7
|
-
remediateProviderFailure,
|
|
8
|
-
renderRemediationCard,
|
|
9
|
-
recommendedCommand,
|
|
10
|
-
} from '../src/lib/provider-command-remediation.js';
|
|
11
|
-
import { runCredentials } from '../src/commands/credentials.js';
|
|
12
|
-
import { listCheatSheetGroups, renderCheatSheet } from '../src/commands/cheat-sheet.js';
|
|
13
|
-
import { collectCredentialsAudit } from '../src/lib/credentials-audit.js';
|
|
14
|
-
|
|
15
|
-
test('edge-cloud service-account key create remediates to IAM / compute intents', () => {
|
|
16
|
-
const card = remediateGcloudEdgeServiceAccountKey({
|
|
17
|
-
argv: ['gcloud', 'edge-cloud', 'service-accounts', 'keys', 'create'],
|
|
18
|
-
projectId: 'gen-lang-client-0684066529',
|
|
19
|
-
instance: 'iam-tunnel',
|
|
20
|
-
zone: 'us-central1-f',
|
|
21
|
-
});
|
|
22
|
-
assert.ok(card);
|
|
23
|
-
assert.equal(card.provider, 'google_cloud');
|
|
24
|
-
assert.equal(card.kind, 'command_incomplete_wrong_family');
|
|
25
|
-
assert.match(card.summary, /Distributed Cloud Edge/i);
|
|
26
|
-
assert.match(card.summary, /Compute Engine/i);
|
|
27
|
-
const commands = card.actions.map((row) => row.command).join('\n');
|
|
28
|
-
assert.match(commands, /gcloud compute instances describe iam-tunnel/);
|
|
29
|
-
assert.match(commands, /gcloud iam service-accounts list/);
|
|
30
|
-
assert.match(commands, /gcloud iam service-accounts keys create/);
|
|
31
|
-
assert.match(commands, /agentsam connections/);
|
|
32
|
-
const rendered = renderRemediationCard(card);
|
|
33
|
-
assert.match(rendered, /Command incomplete/);
|
|
34
|
-
assert.match(rendered, /\[enter\]/);
|
|
35
|
-
assert.equal(recommendedCommand(card), card.actions[0].command);
|
|
36
|
-
});
|
|
37
|
-
|
|
38
|
-
test('remediateProviderFailure matches edge-cloud argv fixture', () => {
|
|
39
|
-
const card = remediateProviderFailure({
|
|
40
|
-
argv: ['gcloud', 'edge-cloud', 'service-accounts', 'keys', 'create'],
|
|
41
|
-
stderr: 'ERROR: argument OUTPUT_FILE (--service-account : --location): Must be specified.',
|
|
42
|
-
});
|
|
43
|
-
assert.ok(card);
|
|
44
|
-
assert.equal(card.kind, 'command_incomplete_wrong_family');
|
|
45
|
-
});
|
|
46
|
-
|
|
47
|
-
test('permission denied remediation exposes reauth + IAM console actions', () => {
|
|
48
|
-
const card = remediateGcloudPermissionDenied({
|
|
49
|
-
operation: 'compute.instances.list',
|
|
50
|
-
projectId: 'gen-lang-client-0684066529',
|
|
51
|
-
connection: 'Google Cloud · InnerAnimalMedia',
|
|
52
|
-
});
|
|
53
|
-
assert.equal(card.kind, 'permission_denied');
|
|
54
|
-
assert.match(renderRemediationCard(card), /Permission missing/);
|
|
55
|
-
assert.match(renderRemediationCard(card), /Re-authorize Google Cloud/);
|
|
56
|
-
assert.ok(card.actions.some((row) => /console\.cloud\.google\.com\/iam-admin/i.test(row.docs_url || '')));
|
|
57
|
-
});
|
|
58
|
-
|
|
59
|
-
test('github token shadow remediation prefers unset + keyring status', () => {
|
|
60
|
-
const card = remediateGithubTokenShadow({
|
|
61
|
-
envTokenPresent: true,
|
|
62
|
-
keyringHealthy: true,
|
|
63
|
-
scopes: ['repo', 'read:org'],
|
|
64
|
-
});
|
|
65
|
-
assert.ok(card);
|
|
66
|
-
assert.equal(card.kind, 'credential_shadow');
|
|
67
|
-
assert.match(recommendedCommand(card), /unset GITHUB_TOKEN/);
|
|
68
|
-
});
|
|
69
|
-
|
|
70
|
-
test('credentials remediate CLI prints edge-cloud card without secrets', async () => {
|
|
71
|
-
const chunks = [];
|
|
72
|
-
const code = await runCredentials(
|
|
73
|
-
['remediate', '--', 'gcloud', 'edge-cloud', 'service-accounts', 'keys', 'create'],
|
|
74
|
-
{ write: (s) => chunks.push(s) },
|
|
75
|
-
);
|
|
76
|
-
assert.equal(code, 0);
|
|
77
|
-
const out = chunks.join('');
|
|
78
|
-
assert.match(out, /Google Cloud/);
|
|
79
|
-
assert.match(out, /gcloud iam service-accounts list/);
|
|
80
|
-
assert.doesNotMatch(out, /gho_/);
|
|
81
|
-
assert.doesNotMatch(out, /AIza/);
|
|
82
|
-
});
|
|
83
|
-
|
|
84
|
-
test('credentials audit --names-only never includes secret-looking values', async () => {
|
|
85
|
-
const report = await collectCredentialsAudit({
|
|
86
|
-
env: {
|
|
87
|
-
HOME: process.env.HOME,
|
|
88
|
-
AGENTSAM_API_KEY: 'aak_test_should_never_appear_in_output_fields_as_value',
|
|
89
|
-
GITHUB_TOKEN: 'ghp_should_never_be_echoed',
|
|
90
|
-
OPENAI_API_KEY: 'sk-should-never-be-echoed',
|
|
91
|
-
},
|
|
92
|
-
verify: false,
|
|
93
|
-
drift: true,
|
|
94
|
-
namesOnly: true,
|
|
95
|
-
noNetwork: true,
|
|
96
|
-
});
|
|
97
|
-
const blob = JSON.stringify(report);
|
|
98
|
-
assert.doesNotMatch(blob, /aak_test_should_never/);
|
|
99
|
-
assert.doesNotMatch(blob, /ghp_should_never/);
|
|
100
|
-
assert.doesNotMatch(blob, /sk-should-never/);
|
|
101
|
-
assert.equal(report.shell_presence.GITHUB_TOKEN, true);
|
|
102
|
-
assert.equal(report.shell_presence.AGENTSAM_API_KEY, true);
|
|
103
|
-
assert.ok(report.drift.some((row) => row.code === 'github_env_token_present'));
|
|
104
|
-
});
|
|
105
|
-
|
|
106
|
-
test('cheat-sheet exposes System + Providers groups', () => {
|
|
107
|
-
const groups = listCheatSheetGroups();
|
|
108
|
-
assert.ok(groups.some((g) => g.id === 'system'));
|
|
109
|
-
assert.ok(groups.some((g) => g.id === 'providers'));
|
|
110
|
-
const text = renderCheatSheet('2.6.4');
|
|
111
|
-
assert.match(text, /credentials audit/);
|
|
112
|
-
assert.match(text, /cheat-sheet/);
|
|
113
|
-
});
|
|
@@ -1,95 +0,0 @@
|
|
|
1
|
-
import assert from 'node:assert/strict';
|
|
2
|
-
import { describe, it } from 'node:test';
|
|
3
|
-
import { scanTextForSecrets } from '../src/lib/deploy/secret-scan.js';
|
|
4
|
-
import { HEALTH_USER_AGENT, parseWranglerVersionId, probeDeployHealth, resolveHealthOrigin } from '../src/lib/deploy/health.js';
|
|
5
|
-
|
|
6
|
-
describe('deploy secret scan', () => {
|
|
7
|
-
it('allows fixture oauth values', () => {
|
|
8
|
-
const findings = scanTextForSecrets(
|
|
9
|
-
'CLOUDFLARE_OAUTH_CLIENT_ID=sillynotreal\nCLOUDFLARE_OAUTH_CLIENT_SECRET=sillynotreal-secret\n',
|
|
10
|
-
{ filename: 'apps/local-studio/.env.cloudflare.example' },
|
|
11
|
-
);
|
|
12
|
-
assert.equal(findings.length, 0);
|
|
13
|
-
});
|
|
14
|
-
|
|
15
|
-
it('flags live openai-like keys', () => {
|
|
16
|
-
const findings = scanTextForSecrets('OPENAI_API_KEY=sk-abcdefghijklmnopqrstuvwxyz012345');
|
|
17
|
-
assert.equal(findings.some((f) => f.label === 'openai-like'), true);
|
|
18
|
-
});
|
|
19
|
-
});
|
|
20
|
-
|
|
21
|
-
describe('deploy health', () => {
|
|
22
|
-
it('parses wrangler version ids', () => {
|
|
23
|
-
assert.equal(
|
|
24
|
-
parseWranglerVersionId('Current Version ID: e9747d3a-4db6-4e02-b6fe-aa5a47f1588b'),
|
|
25
|
-
'e9747d3a-4db6-4e02-b6fe-aa5a47f1588b',
|
|
26
|
-
);
|
|
27
|
-
});
|
|
28
|
-
|
|
29
|
-
it('reads hostname from wrangler.jsonc', () => {
|
|
30
|
-
const origin = resolveHealthOrigin({
|
|
31
|
-
wranglerConfigText: '{"routes":[{"pattern":"agentsam.inneranimalmedia.com","custom_domain":true}]}',
|
|
32
|
-
});
|
|
33
|
-
assert.equal(origin, 'https://agentsam.inneranimalmedia.com');
|
|
34
|
-
});
|
|
35
|
-
|
|
36
|
-
it('fails loud when wrangler routes pattern is missing', () => {
|
|
37
|
-
assert.throws(
|
|
38
|
-
() => resolveHealthOrigin({ wranglerConfigText: '{}' }),
|
|
39
|
-
(err) => err?.code === 'health_origin_required',
|
|
40
|
-
);
|
|
41
|
-
});
|
|
42
|
-
|
|
43
|
-
it('treats /health ok:true with connector unconfigured as healthy', async () => {
|
|
44
|
-
const fetchImpl = async (url) => {
|
|
45
|
-
if (String(url).endsWith('/health')) {
|
|
46
|
-
return {
|
|
47
|
-
status: 200,
|
|
48
|
-
json: async () => ({ ok: true, connections: { cloudflare: { configured: false } } }),
|
|
49
|
-
};
|
|
50
|
-
}
|
|
51
|
-
return { status: 200, json: async () => ({}) };
|
|
52
|
-
};
|
|
53
|
-
const health = await probeDeployHealth('https://agentsam.inneranimalmedia.com', { fetchImpl });
|
|
54
|
-
assert.equal(health.ok, true);
|
|
55
|
-
assert.equal(health.results['/health'].appOk, true);
|
|
56
|
-
assert.equal(health.results['/health'].cloudflareConfigured, false);
|
|
57
|
-
assert.equal(health.results['/privacy'].ok, true);
|
|
58
|
-
assert.equal(health.results['/terms'].ok, true);
|
|
59
|
-
});
|
|
60
|
-
|
|
61
|
-
it('fails deploy health when /privacy or /terms are not HTTP 200', async () => {
|
|
62
|
-
const fetchImpl = async (url) => {
|
|
63
|
-
const path = String(url).replace(/^https?:\/\/[^/]+/, '');
|
|
64
|
-
if (path === '/health') {
|
|
65
|
-
return {
|
|
66
|
-
status: 200,
|
|
67
|
-
json: async () => ({ ok: true, connections: { cloudflare: { configured: true } } }),
|
|
68
|
-
};
|
|
69
|
-
}
|
|
70
|
-
if (path === '/privacy' || path === '/terms') {
|
|
71
|
-
return { status: 404, json: async () => ({}) };
|
|
72
|
-
}
|
|
73
|
-
return { status: 200, json: async () => ({}) };
|
|
74
|
-
};
|
|
75
|
-
const health = await probeDeployHealth('https://agentsam.inneranimalmedia.com', { fetchImpl });
|
|
76
|
-
assert.equal(health.ok, false);
|
|
77
|
-
assert.equal(health.results['/privacy'].ok, false);
|
|
78
|
-
assert.equal(health.results['/terms'].ok, false);
|
|
79
|
-
});
|
|
80
|
-
|
|
81
|
-
it('sends a browser-safe User-Agent so WAF does not 403 the probe', async () => {
|
|
82
|
-
const seen = [];
|
|
83
|
-
const fetchImpl = async (url, init = {}) => {
|
|
84
|
-
seen.push({ url, init });
|
|
85
|
-
return {
|
|
86
|
-
status: 200,
|
|
87
|
-
json: async () => ({ ok: true, connections: { cloudflare: { configured: false } } }),
|
|
88
|
-
};
|
|
89
|
-
};
|
|
90
|
-
await probeDeployHealth('https://agentsam.inneranimalmedia.com', { fetchImpl, paths: ['/health'] });
|
|
91
|
-
assert.equal(seen.length, 1);
|
|
92
|
-
assert.equal(seen[0].init.headers['User-Agent'], HEALTH_USER_AGENT);
|
|
93
|
-
assert.match(seen[0].init.headers.Accept, /application\/json/);
|
|
94
|
-
});
|
|
95
|
-
});
|
|
@@ -1,91 +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 { execFileSync, spawnSync } from 'node:child_process';
|
|
7
|
-
import { fileURLToPath } from 'node:url';
|
|
8
|
-
import {
|
|
9
|
-
captureDeployReceipt,
|
|
10
|
-
finalizeDeployReceipt,
|
|
11
|
-
showLatestDeployReceipt,
|
|
12
|
-
} from '../src/lib/deploy-receipt/index.js';
|
|
13
|
-
|
|
14
|
-
const cli = fileURLToPath(new URL('../src/cli.js', import.meta.url));
|
|
15
|
-
|
|
16
|
-
async function fixture(t) {
|
|
17
|
-
const root = await fs.mkdtemp(path.join(os.tmpdir(), 'agentsam-deploy-receipt-'));
|
|
18
|
-
t.after(() => fs.rm(root, { recursive: true, force: true }));
|
|
19
|
-
execFileSync('git', ['init', '-q', root]);
|
|
20
|
-
execFileSync('git', ['-C', root, 'config', 'user.email', 'receipt-test@example.invalid']);
|
|
21
|
-
execFileSync('git', ['-C', root, 'config', 'user.name', 'Receipt Test']);
|
|
22
|
-
await fs.mkdir(path.join(root, 'src'), { recursive: true });
|
|
23
|
-
await fs.writeFile(path.join(root, 'src/app.js'), 'export const value = 1;\n');
|
|
24
|
-
execFileSync('git', ['-C', root, 'add', '.']);
|
|
25
|
-
execFileSync('git', ['-C', root, 'commit', '-qm', 'fixture']);
|
|
26
|
-
return root;
|
|
27
|
-
}
|
|
28
|
-
|
|
29
|
-
function run(args, cwd) {
|
|
30
|
-
return spawnSync(process.execPath, [cli, 'deploy-receipt', ...args], { cwd, encoding: 'utf8', timeout: 15000 });
|
|
31
|
-
}
|
|
32
|
-
|
|
33
|
-
test('successful finalize advances baseline while failure preserves the last trusted tree', async (t) => {
|
|
34
|
-
const root = await fixture(t);
|
|
35
|
-
const first = await captureDeployReceipt({ root, project: 'fixture' });
|
|
36
|
-
assert.equal(first.receipt.has_baseline, false);
|
|
37
|
-
assert.equal(first.receipt.baseline_source, 'none');
|
|
38
|
-
assert.equal(first.receipt.working_tree_dirty, false);
|
|
39
|
-
assert.ok(!first.snapshot.entries.some((entry) => entry.path.startsWith('.agentsam/deploy-merkle')));
|
|
40
|
-
|
|
41
|
-
const promoted = await finalizeDeployReceipt({ root, status: 'success', deploymentId: 'dep_1' });
|
|
42
|
-
assert.equal(promoted.receipt.status, 'success');
|
|
43
|
-
assert.equal(promoted.receipt.deployment_id, 'dep_1');
|
|
44
|
-
assert.equal((await showLatestDeployReceipt({ root })).root_hash, first.receipt.root_hash);
|
|
45
|
-
|
|
46
|
-
const clean = await captureDeployReceipt({ root, project: 'fixture' });
|
|
47
|
-
assert.equal(clean.receipt.has_baseline, true);
|
|
48
|
-
assert.equal(clean.receipt.baseline_source, 'local');
|
|
49
|
-
assert.deepEqual(clean.receipt.diff_stats, { unchanged: 1, modified: 0, added: 0, removed: 0 });
|
|
50
|
-
assert.deepEqual(clean.receipt.changed_files, []);
|
|
51
|
-
assert.equal(clean.receipt.root_hash, first.receipt.root_hash);
|
|
52
|
-
assert.equal(clean.receipt.working_tree_dirty, false, 'runtime receipt state must not make the source tree dirty');
|
|
53
|
-
|
|
54
|
-
await fs.writeFile(path.join(root, 'src/app.js'), 'export const value = 2;\n');
|
|
55
|
-
const changed = await captureDeployReceipt({ root, project: 'fixture' });
|
|
56
|
-
assert.equal(changed.receipt.working_tree_dirty, true);
|
|
57
|
-
assert.deepEqual(changed.receipt.diff_stats, { unchanged: 0, modified: 1, added: 0, removed: 0 });
|
|
58
|
-
assert.deepEqual(changed.receipt.changed_files, ['src/app.js']);
|
|
59
|
-
assert.notEqual(changed.receipt.root_hash, first.receipt.root_hash);
|
|
60
|
-
|
|
61
|
-
await finalizeDeployReceipt({ root, status: 'failed', deploymentId: 'dep_2' });
|
|
62
|
-
assert.equal((await showLatestDeployReceipt({ root })).root_hash, first.receipt.root_hash, 'failed run must not advance baseline');
|
|
63
|
-
|
|
64
|
-
const retry = await captureDeployReceipt({ root, project: 'fixture' });
|
|
65
|
-
assert.deepEqual(retry.receipt.changed_files, ['src/app.js']);
|
|
66
|
-
await finalizeDeployReceipt({ root, status: 'success', deploymentId: 'dep_3' });
|
|
67
|
-
const settled = await captureDeployReceipt({ root, project: 'fixture' });
|
|
68
|
-
assert.deepEqual(settled.receipt.diff_stats, { unchanged: 1, modified: 0, added: 0, removed: 0 });
|
|
69
|
-
assert.deepEqual(settled.receipt.changed_files, []);
|
|
70
|
-
});
|
|
71
|
-
|
|
72
|
-
test('deploy-receipt CLI emits machine-readable capture/finalize/show receipts', async (t) => {
|
|
73
|
-
const root = await fixture(t);
|
|
74
|
-
const capture = run(['capture', '.', '--project', 'cli-fixture', '--json'], root);
|
|
75
|
-
assert.equal(capture.status, 0, capture.stderr);
|
|
76
|
-
const captured = JSON.parse(capture.stdout);
|
|
77
|
-
assert.equal(captured.format, 'agentsam-deploy-merkle');
|
|
78
|
-
assert.equal(captured.project, 'cli-fixture');
|
|
79
|
-
assert.equal(captured.status, 'captured');
|
|
80
|
-
|
|
81
|
-
const success = run(['success', '.', '--deployment-id', 'dep_cli', '--worker-version', 'worker_v1', '--json'], root);
|
|
82
|
-
assert.equal(success.status, 0, success.stderr);
|
|
83
|
-
const finalized = JSON.parse(success.stdout);
|
|
84
|
-
assert.equal(finalized.status, 'success');
|
|
85
|
-
assert.equal(finalized.deployment_id, 'dep_cli');
|
|
86
|
-
assert.equal(finalized.worker_version_id, 'worker_v1');
|
|
87
|
-
|
|
88
|
-
const show = run(['show', '.', '--json'], root);
|
|
89
|
-
assert.equal(show.status, 0, show.stderr);
|
|
90
|
-
assert.equal(JSON.parse(show.stdout).root_hash, finalized.root_hash);
|
|
91
|
-
});
|
package/test/dockerize.test.mjs
DELETED
|
@@ -1,93 +0,0 @@
|
|
|
1
|
-
// Pure unit tests — no Docker daemon required, safe for CI/smoke.
|
|
2
|
-
// Integration coverage (actual docker build/run) is manual: see docs/DOCKERIZE.md.
|
|
3
|
-
import { test } from 'node:test';
|
|
4
|
-
import assert from 'node:assert/strict';
|
|
5
|
-
import fs from 'node:fs';
|
|
6
|
-
import os from 'node:os';
|
|
7
|
-
import path from 'node:path';
|
|
8
|
-
import {
|
|
9
|
-
DOCKER_APP_TYPES,
|
|
10
|
-
DOCKER_APP_TYPE_LABELS,
|
|
11
|
-
slugifyForDocker,
|
|
12
|
-
generateDockerFileSet,
|
|
13
|
-
computeFileSetHash,
|
|
14
|
-
buildDockerDeployPlan,
|
|
15
|
-
writeDockerFileSet,
|
|
16
|
-
readManifest,
|
|
17
|
-
} from '../src/lib/dockerize.js';
|
|
18
|
-
|
|
19
|
-
test('slugifyForDocker normalizes to a safe image/container name', () => {
|
|
20
|
-
assert.equal(slugifyForDocker('My Cool App!'), 'my-cool-app');
|
|
21
|
-
assert.equal(slugifyForDocker(' --leading-- '), 'leading');
|
|
22
|
-
assert.equal(slugifyForDocker(''), 'app');
|
|
23
|
-
});
|
|
24
|
-
|
|
25
|
-
test('every declared app type has a label and generates a valid file set', () => {
|
|
26
|
-
for (const type of DOCKER_APP_TYPES) {
|
|
27
|
-
assert.ok(DOCKER_APP_TYPE_LABELS[type]?.label, `missing label for ${type}`);
|
|
28
|
-
const files = generateDockerFileSet(type, { appSlug: 'test-app', port: 9999 });
|
|
29
|
-
assert.match(files.dockerfile, /^FROM /m, `${type} Dockerfile must start with FROM`);
|
|
30
|
-
assert.ok(files.dockerignore.includes('node_modules'), `${type} .dockerignore should ignore node_modules`);
|
|
31
|
-
assert.ok(files.compose.includes('services:'), `${type} compose file must define services`);
|
|
32
|
-
}
|
|
33
|
-
});
|
|
34
|
-
|
|
35
|
-
test('unknown app type throws a clear error instead of generating garbage', () => {
|
|
36
|
-
assert.throws(() => generateDockerFileSet('not_a_real_type', { appSlug: 'x' }), /Unknown Docker app type/);
|
|
37
|
-
});
|
|
38
|
-
|
|
39
|
-
test('buildDockerDeployPlan picks correct container port for static/vite (80) vs service types (host port)', () => {
|
|
40
|
-
const staticPlan = buildDockerDeployPlan('static', { appSlug: 'x', port: 8080 });
|
|
41
|
-
assert.equal(staticPlan.containerPort, 80);
|
|
42
|
-
assert.equal(staticPlan.hostPort, 8080);
|
|
43
|
-
|
|
44
|
-
const nodePlan = buildDockerDeployPlan('node_service', { appSlug: 'x', port: 4000 });
|
|
45
|
-
assert.equal(nodePlan.containerPort, 4000);
|
|
46
|
-
assert.equal(nodePlan.hostPort, 4000);
|
|
47
|
-
});
|
|
48
|
-
|
|
49
|
-
test('buildDockerDeployPlan falls back to sensible default ports when none given', () => {
|
|
50
|
-
const plan = buildDockerDeployPlan('wrangler_dev', { appSlug: 'x' });
|
|
51
|
-
assert.equal(plan.hostPort, 8787);
|
|
52
|
-
assert.equal(plan.imageTag, 'x:local'.replace('local', plan.hash));
|
|
53
|
-
});
|
|
54
|
-
|
|
55
|
-
test('computeFileSetHash is deterministic: identical content -> identical hash', () => {
|
|
56
|
-
const a = generateDockerFileSet('node_service', { appSlug: 'same', port: 3000 });
|
|
57
|
-
const b = generateDockerFileSet('node_service', { appSlug: 'same', port: 3000 });
|
|
58
|
-
assert.equal(computeFileSetHash(a), computeFileSetHash(b));
|
|
59
|
-
});
|
|
60
|
-
|
|
61
|
-
test('computeFileSetHash changes when content changes (different port -> different hash)', () => {
|
|
62
|
-
const a = generateDockerFileSet('node_service', { appSlug: 'same', port: 3000 });
|
|
63
|
-
const b = generateDockerFileSet('node_service', { appSlug: 'same', port: 4000 });
|
|
64
|
-
assert.notEqual(computeFileSetHash(a), computeFileSetHash(b));
|
|
65
|
-
});
|
|
66
|
-
|
|
67
|
-
test('buildDockerDeployPlan image tag and hashtag are hash-derived and match the slug', () => {
|
|
68
|
-
const plan = buildDockerDeployPlan('static', { appSlug: 'My App', port: 8080 });
|
|
69
|
-
assert.equal(plan.slug, 'my-app');
|
|
70
|
-
assert.equal(plan.imageTag, `my-app:${plan.hash}`);
|
|
71
|
-
assert.equal(plan.latestTag, 'my-app:latest');
|
|
72
|
-
assert.equal(plan.hashtag, `#docker-my-app-${plan.hash}`);
|
|
73
|
-
});
|
|
74
|
-
|
|
75
|
-
test('writeDockerFileSet writes into .agentsam/docker/<hash>/ and .dockerignore at root, and the manifest round-trips', () => {
|
|
76
|
-
const tmp = fs.mkdtempSync(path.join(os.tmpdir(), 'agentsam-dockerize-test-'));
|
|
77
|
-
try {
|
|
78
|
-
const files = generateDockerFileSet('static', { appSlug: 'tmp-app', port: 9090 });
|
|
79
|
-
const hash = computeFileSetHash(files);
|
|
80
|
-
const written = writeDockerFileSet(tmp, files, hash);
|
|
81
|
-
|
|
82
|
-
assert.equal(written.dockerfilePath, path.join(tmp, '.agentsam', 'docker', hash, 'Dockerfile'));
|
|
83
|
-
assert.ok(fs.existsSync(written.dockerfilePath));
|
|
84
|
-
assert.ok(fs.existsSync(written.composePath));
|
|
85
|
-
assert.ok(fs.existsSync(path.join(tmp, '.dockerignore')));
|
|
86
|
-
|
|
87
|
-
// manifest is populated by dockerize()/writeManifestEntry, not writeDockerFileSet itself —
|
|
88
|
-
// confirm readManifest returns {} when nothing has written to it yet
|
|
89
|
-
assert.deepEqual(readManifest(tmp), {});
|
|
90
|
-
} finally {
|
|
91
|
-
fs.rmSync(tmp, { recursive: true, force: true });
|
|
92
|
-
}
|
|
93
|
-
});
|