@inneranimalmedia/agentsam-sdk 2.4.1 → 2.6.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/AGENTSAM.md +55 -0
- package/README.md +17 -12
- package/bin/agentsam +2 -0
- package/docs/AGENTSAM_ASTRA_OPENAI_INTEGRATION.md +1363 -0
- package/docs/AGENTSAM_WORKBENCH.md +30 -0
- package/docs/AUTH_IDENTITY_CONTRACT.md +52 -0
- package/docs/CAPABILITIES.md +5 -3
- package/docs/CLI_SHELL.md +167 -80
- package/docs/CMS_STUDIO.md +101 -0
- package/docs/CONTEXT.md +170 -0
- package/docs/LOCAL_OLLAMA.md +58 -0
- package/docs/MERKLE.md +19 -19
- package/docs/PORTABLE_CONTEXT.md +4 -3
- package/docs/PROJECT_CONFIG.md +72 -0
- package/docs/RELEASES.md +35 -2
- package/docs/REPOSITORY_INTELLIGENCE.md +1 -1
- package/docs/REPOSITORY_KNOWLEDGE.md +114 -0
- package/docs/SDK_WORKER.md +86 -0
- package/docs/SECURITY.md +59 -22
- package/docs/client-cms-editor.md +15 -0
- package/docs/local-studio/WORKMODE_DONOR_NOTES.md +485 -0
- package/package.json +35 -10
- package/packages/connectors/cloudflare/package.json +10 -0
- package/packages/connectors/cloudflare/src/index.js +127 -0
- package/packages/connectors/cloudflare/src/owner.js +76 -0
- package/packages/connectors/cloudflare/src/routes.js +223 -0
- package/packages/connectors/cloudflare/src/vault.js +80 -0
- package/packages/connectors/cloudflare/tests/connector.test.mjs +44 -0
- package/packages/identity/package.json +10 -1
- package/packages/identity/src/contracts/auth-config.js +109 -0
- package/packages/identity/src/index.js +1 -0
- package/packages/identity/src/oauth/README.md +2 -2
- package/packages/identity/src/oauth/credentials.js +11 -4
- package/packages/identity/src/oauth/iam-platform.js +3 -3
- package/packages/identity/src/providers/iam/index.js +7 -7
- package/packages/identity/src/providers/iam/oauth.js +6 -4
- package/packages/identity/src/providers/iam/profile.js +5 -5
- package/packages/identity/tests/auth-config.test.mjs +61 -0
- package/packages/identity/tests/oauth-credentials.test.mjs +13 -2
- package/protocol/FILEMETA_V1.md +95 -0
- package/protocol/INSPECT_VIEWS_V1.md +40 -0
- package/protocol/MERKLE_PERSISTENCE_V1.md +50 -0
- package/protocol/MERKLE_V1.md +3 -1
- package/protocol/README.md +1 -0
- package/protocol/capabilities/cloudflare-cpu-audit-input.schema.json +19 -0
- package/protocol/capabilities/cloudflare-cpu-profile-input.schema.json +13 -0
- package/protocol/capabilities/cloudflare-wrangler-native-input.schema.json +19 -0
- package/protocol/capabilities/manifest.json +79 -3
- package/protocol/capabilities/repository-snapshot.schema.json +1 -0
- package/protocol/context/context-budget.schema.json +36 -0
- package/protocol/context/context-item.schema.json +19 -0
- package/protocol/context/resolved-context-pack.schema.json +47 -0
- package/protocol/context/result-policy.schema.json +17 -0
- package/protocol/knowledge/context-pack.schema.json +33 -0
- package/protocol/knowledge/retrieval-query.schema.json +68 -13
- package/protocol/models/README.md +373 -0
- package/protocol/models/model-inventory-v2.schema.json +212 -0
- package/python/README.md +15 -7
- package/python/agentsam_sdk/cli.py +0 -21
- package/python/agentsam_sdk/tui/README.md +17 -12
- package/python/agentsam_sdk/tui/bootstrap.py +2 -2
- package/python/agentsam_sdk/tui/demo.py +25 -10
- package/python/agentsam_sdk/tui/onboarding.py +208 -0
- package/python/tests/test_tui_cli.py +7 -6
- package/skills/README.md +21 -0
- package/skills/agentsam-app-fundamentals/SKILL.md +165 -0
- package/skills/agentsam-app-fundamentals/references/graphs-contracts-ast-merkle.md +89 -0
- package/skills/agentsam-app-fundamentals/references/trust-credentials-and-destinations.md +99 -0
- package/skills/agentsam-cloudflare-workers/SKILL.md +53 -0
- package/skills/agentsam-cloudflare-workers/references/cpu-profiling.md +16 -0
- package/skills/agentsam-cloudflare-workers/references/errors-and-observability.md +29 -0
- package/skills/agentsam-cloudflare-workers/references/wrangler-native-map.md +28 -0
- package/skills/agentsam-jr-dev/SKILL.md +232 -0
- package/skills/agentsam-jr-dev/references/real-application-logic.md +156 -0
- package/skills/agentsam-jr-dev/references/web-application-fundamentals.md +240 -0
- package/skills/agentsam-progression-guard/SKILL.md +197 -0
- package/skills/agentsam-progression-guard/references/checkpoint-chain.md +111 -0
- package/skills/agentsam-progression-guard/references/hooks-operational-io.md +96 -0
- package/skills/catalog.json +71 -0
- package/src/agent/capability-adapter.js +25 -13
- package/src/agent/index.js +1 -0
- package/src/agent/responses-runner.js +325 -0
- package/src/capabilities/index.js +7 -0
- package/src/capabilities/repository-snapshot-view.js +238 -0
- package/src/capabilities/repository-snapshot.js +28 -14
- package/src/cli.js +198 -76
- package/src/cloudflare/cpu-profile.js +115 -0
- package/src/cloudflare/index.js +14 -0
- package/src/cloudflare/wrangler.js +132 -0
- package/src/commands/account-auth.js +47 -0
- package/src/commands/cloudflare.js +58 -0
- package/src/commands/connections.js +93 -0
- package/src/commands/context-economics.js +114 -0
- package/src/commands/context.js +14 -2
- package/src/commands/db.js +4 -7
- package/src/commands/deploy.js +54 -32
- package/src/commands/eval.js +63 -0
- package/src/commands/interactive.js +18 -0
- package/src/commands/knowledge.js +27 -4
- package/src/commands/merkle-persist.js +118 -0
- package/src/commands/merkle.js +32 -17
- package/src/commands/models.js +152 -0
- package/src/commands/ollama.js +259 -0
- package/src/commands/preferences.js +144 -0
- package/src/commands/product.js +86 -16
- package/src/commands/resume.js +67 -0
- package/src/commands/security.js +8 -6
- package/src/commands/shell.js +405 -100
- package/src/commands/skills.js +66 -0
- package/src/commands/start-local.js +1 -1
- package/src/commands/tunnel.js +5 -4
- package/src/commands/whoami.js +86 -0
- package/src/context/budget.js +120 -0
- package/src/context/compact.js +28 -0
- package/src/context/index.js +7 -0
- package/src/context/rehydrate.js +35 -0
- package/src/context/resolve.js +116 -0
- package/src/context/result-policy.js +66 -0
- package/src/errors/diagnostic.js +160 -0
- package/src/errors/index.js +9 -0
- package/src/eval/context.js +191 -0
- package/src/eval/index.js +1 -0
- package/src/index.js +70 -0
- package/src/indexing/execution-boundary.js +144 -0
- package/src/indexing/index.js +8 -0
- package/src/indexing/provider.js +41 -0
- package/src/knowledge/config.js +2 -2
- package/src/knowledge/context-pack.js +12 -1
- package/src/knowledge/contracts.js +9 -4
- package/src/knowledge/engine.js +7 -3
- package/src/knowledge/service/server.js +1 -1
- package/src/lib/account-session.js +98 -0
- package/src/lib/agent-instructions.js +73 -0
- package/src/lib/auth.js +4 -0
- package/src/lib/bridge-client.js +7 -5
- package/src/lib/cli-preferences.js +78 -0
- package/src/lib/core-client.js +8 -8
- package/src/lib/deploy/git-guard.js +69 -0
- package/src/lib/deploy/health.js +57 -0
- package/src/lib/deploy/local-studio.js +283 -0
- package/src/lib/deploy/secret-scan.js +65 -0
- package/src/lib/deploy-receipt/index.js +5 -2
- package/src/lib/detect-context.js +6 -5
- package/src/lib/execution-approvals.js +59 -0
- package/src/lib/identity-scaffold.js +1 -1
- package/src/lib/local-scaffold.js +35 -33
- package/src/lib/local-sessions.js +127 -0
- package/src/lib/local-status.js +9 -17
- package/src/lib/merkle/cloudflare-persistence.js +321 -0
- package/src/lib/merkle/filemeta.js +43 -0
- package/src/lib/merkle/git-ignore.js +24 -0
- package/src/lib/merkle/hash.js +1 -0
- package/src/lib/merkle/index.js +22 -0
- package/src/lib/merkle/persistence.js +72 -0
- package/src/lib/merkle/semantic.js +359 -0
- package/src/lib/merkle/snapshot.js +9 -3
- package/src/lib/merkle/tree.js +11 -6
- package/src/lib/project-config.js +227 -0
- package/src/lib/project-rules.js +68 -0
- package/src/lib/provider-credentials.js +83 -0
- package/src/lib/save-sdk-token.js +1 -1
- package/src/lib/scaffold/templates/worker-api/index.js +101 -20
- package/src/lib/scaffold/wizards/worker-api.js +27 -11
- package/src/lib/slash-commands.js +22 -15
- package/src/lib/tools.js +11 -5
- package/src/models/catalog.js +135 -0
- package/src/models/index.js +7 -0
- package/src/providers/index.js +5 -0
- package/src/providers/openai-responses.js +275 -0
- package/src/security/index.js +1 -0
- package/src/security/inventory.js +4 -1
- package/src/security/process.js +35 -9
- package/src/security/render.js +27 -5
- package/src/security/scan.js +24 -9
- package/src/security/trust-boundary.js +24 -0
- package/src/skills/index.js +64 -0
- package/src/telemetry/contracts.js +203 -0
- package/src/telemetry/events.js +48 -0
- package/src/telemetry/index.js +8 -0
- package/src/tools/hydrate.js +35 -0
- package/src/tools/index.js +2 -0
- package/src/tools/search.js +70 -0
- package/src/ui/ansi.js +1 -1
- package/src/ui/boot.js +54 -0
- package/src/ui/merkle/render.js +1 -0
- package/src/ui/runtime-activity.js +192 -0
- package/src/ui/theme.js +19 -18
- package/test/account-session.test.mjs +36 -0
- package/test/app-building-skills.test.mjs +61 -0
- package/test/apps-scaffold-contract.test.mjs +56 -0
- package/test/capabilities.test.mjs +53 -4
- package/test/cli-preferences.test.mjs +46 -0
- package/test/cloudflare-connector.test.mjs +96 -0
- package/test/cloudflare-runtime.test.mjs +75 -0
- package/test/context.test.mjs +144 -0
- package/test/deploy-health-scan.test.mjs +67 -0
- package/test/error-diagnostics.test.mjs +59 -0
- package/test/eval-context.test.mjs +37 -0
- package/test/execution-approvals.test.mjs +27 -0
- package/test/indexing-provider.test.mjs +29 -0
- package/test/jr-dev-skill.test.mjs +26 -0
- package/test/knowledge-context-pack.test.mjs +19 -0
- package/test/knowledge.test.mjs +1 -1
- package/test/local-sessions.test.mjs +42 -0
- package/test/local-studio-deploy.test.mjs +83 -0
- package/test/merkle-persistence.test.mjs +91 -0
- package/test/merkle.test.mjs +77 -3
- package/test/model-catalog.test.mjs +43 -0
- package/test/models.test.mjs +51 -0
- package/test/npm10-lock.test.mjs +29 -0
- package/test/ollama.test.mjs +94 -0
- package/test/openai-responses.test.mjs +95 -0
- package/test/project-config.test.mjs +81 -0
- package/test/project-rules.test.mjs +44 -0
- package/test/provider-credentials.test.mjs +52 -0
- package/test/rehydrate.test.mjs +25 -0
- package/test/release-hygiene.test.mjs +34 -0
- package/test/repository-snapshot-view.test.mjs +112 -0
- package/test/responses-runner.test.mjs +148 -0
- package/test/runtime-activity.test.mjs +98 -0
- package/test/sdk-worker-contract.test.mjs +68 -0
- package/test/security.test.mjs +46 -0
- package/test/shell.test.mjs +55 -21
- package/test/skills.test.mjs +22 -0
- package/test/smoke.mjs +5 -2
- package/test/telemetry.test.mjs +79 -0
- package/test/theme-portability.test.mjs +14 -0
- package/test/tools-search.test.mjs +40 -0
- package/test/whoami-resume.test.mjs +56 -0
- package/examples/agentsam-tui-ansi.mjs +0 -149
- package/src/commands/tui.js +0 -120
- package/src/ui/splash-xterm.js +0 -290
- package/src/ui/splash.js +0 -426
|
@@ -0,0 +1,132 @@
|
|
|
1
|
+
import fs from 'node:fs';
|
|
2
|
+
import path from 'node:path';
|
|
3
|
+
import { runProcess } from '../security/process.js';
|
|
4
|
+
import { AgentSamDiagnosticError, redactDiagnosticValue } from '../errors/index.js';
|
|
5
|
+
|
|
6
|
+
function clean(value) { return value == null ? '' : String(value).trim(); }
|
|
7
|
+
function positiveInteger(value, fallback) { const n = Number(value); return Number.isInteger(n) && n > 0 ? n : fallback; }
|
|
8
|
+
|
|
9
|
+
export const WRANGLER_NATIVE_COMMANDS = Object.freeze([
|
|
10
|
+
Object.freeze({ id: 'whoami', argv: ['whoami', '--json'], risk: 'read', output: 'json', description: 'Read authenticated Cloudflare user/account membership without exposing the auth token.' }),
|
|
11
|
+
Object.freeze({ id: 'deployments.list', argv: ['deployments', 'list', '--json'], risk: 'read', output: 'json', description: 'List recent Worker deployments.' }),
|
|
12
|
+
Object.freeze({ id: 'versions.list', argv: ['versions', 'list', '--json'], risk: 'read', output: 'json', description: 'List recent Worker versions.' }),
|
|
13
|
+
Object.freeze({ id: 'types.check', argv: ['types', '--check'], risk: 'read', output: 'text', description: 'Check generated Worker binding/runtime types without rewriting them.' }),
|
|
14
|
+
Object.freeze({ id: 'queues.list', argv: ['queues', 'list'], risk: 'read', output: 'text', description: 'List Workers Queues visible to the active Cloudflare identity.' }),
|
|
15
|
+
]);
|
|
16
|
+
|
|
17
|
+
export const WRANGLER_OPERATION_FAMILIES = Object.freeze([
|
|
18
|
+
Object.freeze({ family: 'identity', examples: ['whoami', 'auth list', 'auth activate'], default_risk: 'read/config' }),
|
|
19
|
+
Object.freeze({ family: 'development', examples: ['dev', 'types --check'], default_risk: 'local-runtime' }),
|
|
20
|
+
Object.freeze({ family: 'observability', examples: ['tail --format json', 'deployments list', 'versions list'], default_risk: 'read/stream' }),
|
|
21
|
+
Object.freeze({ family: 'delivery', examples: ['deploy', 'versions deploy', 'rollback'], default_risk: 'remote-write' }),
|
|
22
|
+
Object.freeze({ family: 'data', examples: ['d1', 'r2', 'kv', 'queues', 'hyperdrive', 'vectorize'], default_risk: 'read-or-remote-write' }),
|
|
23
|
+
Object.freeze({ family: 'compute', examples: ['containers', 'browser', 'ai', 'workflows'], default_risk: 'read-or-remote-write' }),
|
|
24
|
+
]);
|
|
25
|
+
|
|
26
|
+
export function listWranglerNativeCommands() { return WRANGLER_NATIVE_COMMANDS.map((row) => ({ ...row, argv: [...row.argv] })); }
|
|
27
|
+
|
|
28
|
+
function descriptor(id) {
|
|
29
|
+
const row = WRANGLER_NATIVE_COMMANDS.find((item) => item.id === clean(id));
|
|
30
|
+
if (!row) throw new RangeError(`unsupported_wrangler_native_command:${id}`);
|
|
31
|
+
return row;
|
|
32
|
+
}
|
|
33
|
+
|
|
34
|
+
function resolveConfig(cwd, explicit = '') {
|
|
35
|
+
if (clean(explicit)) {
|
|
36
|
+
const file = path.resolve(cwd, explicit);
|
|
37
|
+
if (!file.startsWith(`${cwd}${path.sep}`) && file !== cwd) throw new Error('cloudflare_config_outside_cwd');
|
|
38
|
+
if (!fs.existsSync(file)) throw new Error(`cloudflare_config_not_found:${explicit}`);
|
|
39
|
+
return file;
|
|
40
|
+
}
|
|
41
|
+
for (const name of ['wrangler.jsonc', 'wrangler.json', 'wrangler.toml']) {
|
|
42
|
+
const file = path.join(cwd, name);
|
|
43
|
+
if (fs.existsSync(file)) return file;
|
|
44
|
+
}
|
|
45
|
+
return '';
|
|
46
|
+
}
|
|
47
|
+
|
|
48
|
+
export function buildWranglerInvocation(id, input = {}) {
|
|
49
|
+
const row = descriptor(id);
|
|
50
|
+
const cwd = path.resolve(input.cwd || process.cwd());
|
|
51
|
+
const args = [...row.argv];
|
|
52
|
+
if (id === 'whoami' && clean(input.account)) args.push('--account', clean(input.account));
|
|
53
|
+
if ((id === 'deployments.list' || id === 'versions.list') && clean(input.name)) args.push('--name', clean(input.name));
|
|
54
|
+
if (id === 'types.check' && clean(input.path)) args.splice(1, 0, clean(input.path));
|
|
55
|
+
if (id === 'queues.list' && input.page != null) args.push('--page', String(positiveInteger(input.page, 1)));
|
|
56
|
+
const config = resolveConfig(cwd, input.config);
|
|
57
|
+
if (config) args.push('--config', config);
|
|
58
|
+
if (clean(input.env)) args.push('--env', clean(input.env));
|
|
59
|
+
if (clean(input.profile)) args.push('--profile', clean(input.profile));
|
|
60
|
+
return Object.freeze({ command_id: row.id, command: 'wrangler', args: Object.freeze(args), cwd, risk: row.risk, output: row.output });
|
|
61
|
+
}
|
|
62
|
+
|
|
63
|
+
function parseJsonOutput(text) {
|
|
64
|
+
const source = clean(text);
|
|
65
|
+
if (!source) return null;
|
|
66
|
+
try { return JSON.parse(source); } catch { return null; }
|
|
67
|
+
}
|
|
68
|
+
|
|
69
|
+
function stripAnsi(value) { return String(value || '').replace(/\x1b\[[0-?]*[ -\/]*[@-~]/g, ''); }
|
|
70
|
+
function nestedError(payload) {
|
|
71
|
+
if (!payload || typeof payload !== 'object') return null;
|
|
72
|
+
const rows = [payload.error, ...(Array.isArray(payload.errors) ? payload.errors : [])].filter((row) => row && typeof row === 'object');
|
|
73
|
+
return rows[0] || payload;
|
|
74
|
+
}
|
|
75
|
+
|
|
76
|
+
export function parseWranglerErrorEvidence(stderr = '', stdout = '') {
|
|
77
|
+
const errorText = stripAnsi(stderr);
|
|
78
|
+
const outputText = stripAnsi(stdout);
|
|
79
|
+
let payload = parseJsonOutput(outputText) || parseJsonOutput(errorText);
|
|
80
|
+
const error = nestedError(payload);
|
|
81
|
+
const combined = `${errorText}\n${outputText}`;
|
|
82
|
+
const regexCode = combined.match(/\[code:\s*([A-Za-z0-9_.:-]+)\]/i)?.[1] || combined.match(/\bcode[:=\s]+([A-Za-z0-9_.:-]+)/i)?.[1] || '';
|
|
83
|
+
const code = clean(error?.code || regexCode) || null;
|
|
84
|
+
const requestId = clean(error?.request_id || error?.requestId || combined.match(/\brequest[_ -]?id[:=\s]+([A-Za-z0-9_-]+)/i)?.[1]) || null;
|
|
85
|
+
const rayId = clean(error?.ray_id || error?.rayId || combined.match(/\b(?:cf[- ]?ray|ray id)[:=\s]+([A-Za-z0-9-]+)/i)?.[1]) || null;
|
|
86
|
+
const message = clean(error?.message || error?.error || errorText.split('\n').find((line) => clean(line)) || outputText.split('\n').find((line) => clean(line))) || 'Wrangler operation failed';
|
|
87
|
+
return Object.freeze({ code, request_id: requestId, ray_id: rayId, message, details: payload ? redactDiagnosticValue(payload) : null });
|
|
88
|
+
}
|
|
89
|
+
|
|
90
|
+
export async function runWranglerNative(id, input = {}, options = {}) {
|
|
91
|
+
const plan = buildWranglerInvocation(id, input);
|
|
92
|
+
const runner = options.run || runProcess;
|
|
93
|
+
const timeoutMs = Number.isFinite(options.timeoutMs) ? options.timeoutMs : 30_000;
|
|
94
|
+
const result = await runner(options.bin || 'npx', ['--yes', 'wrangler', ...plan.args], {
|
|
95
|
+
cwd: plan.cwd,
|
|
96
|
+
timeoutMs,
|
|
97
|
+
signal: options.signal,
|
|
98
|
+
maxBytes: options.maxBytes || 2 * 1024 * 1024,
|
|
99
|
+
});
|
|
100
|
+
if (result.code !== 0) {
|
|
101
|
+
const evidence = parseWranglerErrorEvidence(result.stderr, result.stdout);
|
|
102
|
+
throw new AgentSamDiagnosticError({
|
|
103
|
+
source: 'cloudflare',
|
|
104
|
+
kind: 'wrangler_error',
|
|
105
|
+
code: evidence.code || 'wrangler_exit_nonzero',
|
|
106
|
+
message: evidence.message || `Wrangler ${plan.command_id} exited ${result.code}`,
|
|
107
|
+
retriable: false,
|
|
108
|
+
retry_strategy: 'inspect_error',
|
|
109
|
+
operation: plan.command_id,
|
|
110
|
+
exit_code: result.code,
|
|
111
|
+
request_id: evidence.request_id,
|
|
112
|
+
ray_id: evidence.ray_id,
|
|
113
|
+
cwd: plan.cwd,
|
|
114
|
+
stderr: redactDiagnosticValue(String(result.stderr || '').slice(0, 12_000)) || null,
|
|
115
|
+
stdout: redactDiagnosticValue(String(result.stdout || '').slice(0, 4_000)) || null,
|
|
116
|
+
details: evidence.details,
|
|
117
|
+
});
|
|
118
|
+
}
|
|
119
|
+
const parsed = plan.output === 'json' ? parseJsonOutput(result.stdout) : null;
|
|
120
|
+
return Object.freeze({
|
|
121
|
+
ok: true,
|
|
122
|
+
schema_version: 1,
|
|
123
|
+
command_id: plan.command_id,
|
|
124
|
+
risk: plan.risk,
|
|
125
|
+
cwd: plan.cwd,
|
|
126
|
+
exit_code: result.code,
|
|
127
|
+
format: parsed == null ? 'text' : 'json',
|
|
128
|
+
data: parsed == null ? undefined : redactDiagnosticValue(parsed),
|
|
129
|
+
stdout: parsed == null ? String(result.stdout || '').slice(0, 24_000) : undefined,
|
|
130
|
+
stderr: String(result.stderr || '').slice(0, 8_000) || undefined,
|
|
131
|
+
});
|
|
132
|
+
}
|
|
@@ -0,0 +1,47 @@
|
|
|
1
|
+
import { authenticateViaBrowser } from '../lib/auth.js';
|
|
2
|
+
import { clearAccountSession, readAccountSession, saveAccountSession } from '../lib/account-session.js';
|
|
3
|
+
import { collectWhoami, renderWhoami } from './whoami.js';
|
|
4
|
+
|
|
5
|
+
function writeLine(write, value = '') { write(`${value}\n`); }
|
|
6
|
+
|
|
7
|
+
export async function runLogin(argv = [], options = {}) {
|
|
8
|
+
const allowed = new Set(['--json']);
|
|
9
|
+
const unknown = argv.filter((arg) => !allowed.has(arg));
|
|
10
|
+
if (unknown.length) throw new Error(`unknown login option: ${unknown[0]}`);
|
|
11
|
+
const write = options.write || ((text) => process.stdout.write(text));
|
|
12
|
+
const authenticate = options.authenticateImpl || authenticateViaBrowser;
|
|
13
|
+
const session = await authenticate();
|
|
14
|
+
if (!String(session?.access_token || '').trim().startsWith('sdk_')) throw new Error('Agent Sam login did not return a valid SDK session');
|
|
15
|
+
// authenticateViaBrowser persists by default. Keep injected transports/test flows equivalent.
|
|
16
|
+
if (!readAccountSession({ home: options.home })) saveAccountSession(session, { home: options.home });
|
|
17
|
+
const status = await collectWhoami({ home: options.home, env: options.env || process.env, contextLoader: options.contextLoader });
|
|
18
|
+
if (argv.includes('--json')) writeLine(write, JSON.stringify(status, null, 2));
|
|
19
|
+
else {
|
|
20
|
+
writeLine(write, '');
|
|
21
|
+
writeLine(write, ' Agent Sam login complete.');
|
|
22
|
+
write(renderWhoami(status));
|
|
23
|
+
}
|
|
24
|
+
return status;
|
|
25
|
+
}
|
|
26
|
+
|
|
27
|
+
export function runLogout(argv = [], options = {}) {
|
|
28
|
+
const allowed = new Set(['--json']);
|
|
29
|
+
const unknown = argv.filter((arg) => !allowed.has(arg));
|
|
30
|
+
if (unknown.length) throw new Error(`unknown logout option: ${unknown[0]}`);
|
|
31
|
+
const write = options.write || ((text) => process.stdout.write(text));
|
|
32
|
+
const removed = clearAccountSession({ home: options.home });
|
|
33
|
+
const result = {
|
|
34
|
+
schema_version: 1,
|
|
35
|
+
local_session_removed: removed,
|
|
36
|
+
provider_credentials_unchanged: true,
|
|
37
|
+
note: 'Local IAM session removed. Provider credentials were not deleted or revoked.',
|
|
38
|
+
};
|
|
39
|
+
if (argv.includes('--json')) writeLine(write, JSON.stringify(result, null, 2));
|
|
40
|
+
else {
|
|
41
|
+
writeLine(write, '');
|
|
42
|
+
writeLine(write, removed ? ' Signed out of the local Agent Sam IAM session.' : ' No local Agent Sam IAM session was stored.');
|
|
43
|
+
writeLine(write, ' Provider credentials were not deleted or revoked.');
|
|
44
|
+
writeLine(write, '');
|
|
45
|
+
}
|
|
46
|
+
return result;
|
|
47
|
+
}
|
|
@@ -0,0 +1,58 @@
|
|
|
1
|
+
import path from 'node:path';
|
|
2
|
+
import { listWranglerNativeCommands, runWranglerNative, summarizeCloudflareCpuProfileFile, WRANGLER_OPERATION_FAMILIES } from '../cloudflare/index.js';
|
|
3
|
+
import { renderDiagnosticError } from '../errors/index.js';
|
|
4
|
+
|
|
5
|
+
function parse(argv = []) {
|
|
6
|
+
const subcommand = argv[0] || 'status';
|
|
7
|
+
const takesAction = subcommand === 'run' || subcommand === 'cpu';
|
|
8
|
+
const out = { subcommand, action: takesAction ? (argv[1] || '') : '', cwd: process.cwd(), json: false, name: '', account: '', config: '', env: '', profile: '', path: '', page: null, file: '' };
|
|
9
|
+
for (let i = takesAction ? 2 : 1; i < argv.length; i += 1) {
|
|
10
|
+
const arg = argv[i];
|
|
11
|
+
if (arg === '--json') out.json = true;
|
|
12
|
+
else if (arg === '--cwd') out.cwd = argv[++i] || out.cwd;
|
|
13
|
+
else if (arg === '--name') out.name = argv[++i] || '';
|
|
14
|
+
else if (arg === '--account') out.account = argv[++i] || '';
|
|
15
|
+
else if (arg === '--config') out.config = argv[++i] || '';
|
|
16
|
+
else if (arg === '--env') out.env = argv[++i] || '';
|
|
17
|
+
else if (arg === '--profile') out.profile = argv[++i] || '';
|
|
18
|
+
else if (arg === '--path') out.path = argv[++i] || '';
|
|
19
|
+
else if (arg === '--page') out.page = Number(argv[++i] || 1);
|
|
20
|
+
else if (arg === '--file') out.file = argv[++i] || '';
|
|
21
|
+
else if (arg === '--help' || arg === '-h') out.help = true;
|
|
22
|
+
else if (out.subcommand === 'cpu' && out.action === 'analyze' && !out.file) out.file = arg;
|
|
23
|
+
else throw new Error(`unknown cloudflare option: ${arg}`);
|
|
24
|
+
}
|
|
25
|
+
return out;
|
|
26
|
+
}
|
|
27
|
+
|
|
28
|
+
const help = `Agent Sam · Cloudflare\n\n agentsam cloudflare status [--cwd PATH] [--json]\n agentsam cloudflare commands [--json]\n agentsam cloudflare run <whoami|deployments.list|versions.list|types.check|queues.list> [options] [--json]\n agentsam cloudflare cpu analyze <profile.cpuprofile> [--cwd PATH] [--json]\n\nSafe native runner is read-only. Deploy, rollback, secret reads, D1 mutation, R2 writes, and long-running tail/dev sessions remain explicit operator actions.\n`;
|
|
29
|
+
|
|
30
|
+
export async function runCloudflare(argv = [], options = {}) {
|
|
31
|
+
const args = parse(argv);
|
|
32
|
+
if (options.cwd && !argv.includes('--cwd')) args.cwd = path.resolve(options.cwd);
|
|
33
|
+
const write = options.write || ((value) => process.stdout.write(value));
|
|
34
|
+
if (args.help) { write(help); return null; }
|
|
35
|
+
try {
|
|
36
|
+
let result;
|
|
37
|
+
if (args.subcommand === 'status') {
|
|
38
|
+
result = await runWranglerNative('whoami', args, options);
|
|
39
|
+
} else if (args.subcommand === 'commands') {
|
|
40
|
+
result = { schema_version: 1, native: listWranglerNativeCommands(), families: WRANGLER_OPERATION_FAMILIES };
|
|
41
|
+
} else if (args.subcommand === 'run') {
|
|
42
|
+
if (!args.action) throw new Error('cloudflare native command id required');
|
|
43
|
+
result = await runWranglerNative(args.action, args, options);
|
|
44
|
+
} else if (args.subcommand === 'cpu' && args.action === 'analyze') {
|
|
45
|
+
result = summarizeCloudflareCpuProfileFile({ cwd: path.resolve(args.cwd), file: args.file });
|
|
46
|
+
} else {
|
|
47
|
+
write(help);
|
|
48
|
+
return null;
|
|
49
|
+
}
|
|
50
|
+
write(args.json ? `${JSON.stringify(result)}\n` : `${JSON.stringify(result, null, 2)}\n`);
|
|
51
|
+
return result;
|
|
52
|
+
} catch (error) {
|
|
53
|
+
if (args.json) write(`${JSON.stringify({ ok: false, error: error?.diagnostic || { code: error?.code || 'cloudflare_operation_failed', message: error?.message || String(error) } })}\n`);
|
|
54
|
+
else write(`${renderDiagnosticError(error)}\n`);
|
|
55
|
+
error.reported = true;
|
|
56
|
+
throw error;
|
|
57
|
+
}
|
|
58
|
+
}
|
|
@@ -0,0 +1,93 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Operator diagnostics for AgentSam connections (Cloudflare account grant).
|
|
3
|
+
* Identity (who is this user?) is separate from the Cloudflare connector.
|
|
4
|
+
*/
|
|
5
|
+
import {
|
|
6
|
+
CLOUDFLARE_CALLBACK_PATH,
|
|
7
|
+
CLOUDFLARE_FIXTURE_CLIENT_ID,
|
|
8
|
+
cloudflareConnectionSafeStatus,
|
|
9
|
+
resolveCloudflareOAuthClient,
|
|
10
|
+
} from '../../packages/connectors/cloudflare/src/index.js';
|
|
11
|
+
import { resolveIamIssuer } from '../../packages/identity/src/contracts/auth-config.js';
|
|
12
|
+
|
|
13
|
+
const PRODUCTION_CALLBACK = `https://agentsam.inneranimalmedia.com${CLOUDFLARE_CALLBACK_PATH}`;
|
|
14
|
+
|
|
15
|
+
function doctor(env = process.env) {
|
|
16
|
+
const iam = {
|
|
17
|
+
issuer: resolveIamIssuer(env),
|
|
18
|
+
clientId: Boolean(String(env.IAM_CLIENT_ID || '').trim()),
|
|
19
|
+
serverSecret: Boolean(String(env.IAM_CLIENT_SECRET || '').trim()),
|
|
20
|
+
originAlias: Boolean(String(env.IAM_ORIGIN || '').trim()),
|
|
21
|
+
};
|
|
22
|
+
const cf = cloudflareConnectionSafeStatus(env);
|
|
23
|
+
const client = resolveCloudflareOAuthClient(env);
|
|
24
|
+
return { identity: iam, cloudflare: cf, client };
|
|
25
|
+
}
|
|
26
|
+
|
|
27
|
+
function printSetup(env = process.env) {
|
|
28
|
+
const client = resolveCloudflareOAuthClient(env);
|
|
29
|
+
console.log('Cloudflare connector setup');
|
|
30
|
+
console.log('');
|
|
31
|
+
console.log(` callback: ${PRODUCTION_CALLBACK}`);
|
|
32
|
+
console.log(' authorize: https://dash.cloudflare.com/oauth2/auth');
|
|
33
|
+
console.log(' token: https://dash.cloudflare.com/oauth2/token');
|
|
34
|
+
console.log(' revoke: https://dash.cloudflare.com/oauth2/revoke');
|
|
35
|
+
console.log('');
|
|
36
|
+
console.log('This CLI does not mint a real Cloudflare OAuth client.');
|
|
37
|
+
console.log('Fixture client id ' + CLOUDFLARE_FIXTURE_CLIENT_ID + ' is local-only and must never be installed on production.');
|
|
38
|
+
if (client.fixture) {
|
|
39
|
+
console.log('STOP: fixture credentials are loaded. OAuth start will return 503.');
|
|
40
|
+
} else if (client.status === 'not_configured') {
|
|
41
|
+
console.log('status: not_configured — production may deploy; connector stays optional.');
|
|
42
|
+
} else {
|
|
43
|
+
console.log(`status: ${client.status}`);
|
|
44
|
+
}
|
|
45
|
+
return 0;
|
|
46
|
+
}
|
|
47
|
+
|
|
48
|
+
export async function runConnections(args = []) {
|
|
49
|
+
const argv = args.filter((a) => a !== '--json');
|
|
50
|
+
const jsonMode = args.includes('--json');
|
|
51
|
+
const env = process.env;
|
|
52
|
+
if (argv[0] === 'cloudflare' && argv[1] === 'setup') {
|
|
53
|
+
if (jsonMode) {
|
|
54
|
+
console.log(JSON.stringify({
|
|
55
|
+
callback: PRODUCTION_CALLBACK,
|
|
56
|
+
authorize: 'https://dash.cloudflare.com/oauth2/auth',
|
|
57
|
+
token: 'https://dash.cloudflare.com/oauth2/token',
|
|
58
|
+
revoke: 'https://dash.cloudflare.com/oauth2/revoke',
|
|
59
|
+
mintsRealClient: false,
|
|
60
|
+
client: resolveCloudflareOAuthClient(env),
|
|
61
|
+
}, null, 2));
|
|
62
|
+
return 0;
|
|
63
|
+
}
|
|
64
|
+
return printSetup(env);
|
|
65
|
+
}
|
|
66
|
+
const report = doctor(env);
|
|
67
|
+
if (jsonMode) {
|
|
68
|
+
console.log(JSON.stringify({ identity: report.identity, cloudflare: report.cloudflare }, null, 2));
|
|
69
|
+
return 0;
|
|
70
|
+
}
|
|
71
|
+
const iam = report.identity;
|
|
72
|
+
const cf = report.cloudflare;
|
|
73
|
+
const client = report.client;
|
|
74
|
+
console.log('AgentSam Identity');
|
|
75
|
+
console.log('');
|
|
76
|
+
console.log('IAM client');
|
|
77
|
+
console.log(` ${iam.clientId ? '✓' : '•'} client id`);
|
|
78
|
+
console.log(` ✓ issuer ${iam.issuer}`);
|
|
79
|
+
console.log(` ${iam.serverSecret ? '✓' : '•'} server secret configured`);
|
|
80
|
+
if (iam.originAlias) console.log('Compatibility\n IAM_ORIGIN -> deprecated alias');
|
|
81
|
+
console.log('');
|
|
82
|
+
console.log('Cloudflare connection');
|
|
83
|
+
console.log('');
|
|
84
|
+
console.log('OAuth client');
|
|
85
|
+
console.log(` client id: ${cf.clientId}`);
|
|
86
|
+
console.log(` secret: ${cf.secret}`);
|
|
87
|
+
console.log(` status: ${client.status}`);
|
|
88
|
+
if (client.fixture) {
|
|
89
|
+
console.log(' OAuth client fixture configured');
|
|
90
|
+
console.log(' real Cloudflare OAuth client still required');
|
|
91
|
+
}
|
|
92
|
+
return 0;
|
|
93
|
+
}
|
|
@@ -0,0 +1,114 @@
|
|
|
1
|
+
import { createContextBudget, assessContextUsage } from '../context/index.js';
|
|
2
|
+
import { getModelRecord } from '../models/index.js';
|
|
3
|
+
import { readCliPreferences } from '../lib/cli-preferences.js';
|
|
4
|
+
|
|
5
|
+
function formatInteger(value) {
|
|
6
|
+
return Number(value).toLocaleString('en-US');
|
|
7
|
+
}
|
|
8
|
+
|
|
9
|
+
function percent(value) {
|
|
10
|
+
return `${(Number(value) * 100).toFixed(1)}%`;
|
|
11
|
+
}
|
|
12
|
+
|
|
13
|
+
export function buildContextEconomicsReport(cwd, options = {}) {
|
|
14
|
+
const preferences = options.preferences || readCliPreferences(cwd) || {};
|
|
15
|
+
const model = getModelRecord(preferences.modelPreference);
|
|
16
|
+
if (!model) {
|
|
17
|
+
return Object.freeze({
|
|
18
|
+
model: preferences.modelPreference || 'auto',
|
|
19
|
+
resolved: false,
|
|
20
|
+
reason: 'Select an exact catalog model with /model before Agent Sam can calculate model-specific context economics.',
|
|
21
|
+
reasoning_effort: preferences.reasoningEffort || 'auto',
|
|
22
|
+
service_tier: preferences.serviceTier || 'default',
|
|
23
|
+
active_input_tokens: null,
|
|
24
|
+
});
|
|
25
|
+
}
|
|
26
|
+
|
|
27
|
+
const policy = model.context_policy || {};
|
|
28
|
+
const budget = createContextBudget({
|
|
29
|
+
windowTokens: model.context_window,
|
|
30
|
+
targetInputTokens: policy.target_input_tokens,
|
|
31
|
+
compactAtTokens: policy.compact_at_tokens,
|
|
32
|
+
interveneAtTokens: policy.intervene_at_tokens,
|
|
33
|
+
maxNormalInputTokens: policy.max_normal_input_tokens,
|
|
34
|
+
pricingThresholdTokens: policy.pricing_threshold_tokens,
|
|
35
|
+
safetyMarginTokens: policy.safety_margin_tokens,
|
|
36
|
+
});
|
|
37
|
+
const active = Number.isFinite(options.activeInputTokens) && options.activeInputTokens >= 0
|
|
38
|
+
? Math.floor(options.activeInputTokens)
|
|
39
|
+
: null;
|
|
40
|
+
const pressure = active == null ? null : assessContextUsage(active, budget);
|
|
41
|
+
|
|
42
|
+
return Object.freeze({
|
|
43
|
+
model: model.provider_model_id,
|
|
44
|
+
model_key: model.model_key,
|
|
45
|
+
resolved: true,
|
|
46
|
+
reasoning_effort: preferences.reasoningEffort || 'auto',
|
|
47
|
+
service_tier: preferences.serviceTier || 'default',
|
|
48
|
+
active_input_tokens: active,
|
|
49
|
+
estimate_kind: options.estimateKind === 'provider' ? 'provider' : active == null ? null : 'local',
|
|
50
|
+
window_tokens: budget.windowTokens,
|
|
51
|
+
utilization_ratio: pressure?.utilizationRatio ?? null,
|
|
52
|
+
target_input_tokens: budget.targetInputTokens,
|
|
53
|
+
compact_at_tokens: budget.compactAtTokens,
|
|
54
|
+
intervene_at_tokens: budget.interveneAtTokens,
|
|
55
|
+
max_normal_input_tokens: budget.maxNormalInputTokens,
|
|
56
|
+
pricing_threshold_tokens: budget.pricingThresholdTokens,
|
|
57
|
+
tokens_until_pricing_threshold: pressure?.tokensUntilPricingThreshold ?? null,
|
|
58
|
+
pressure: pressure?.stage ?? 'unknown',
|
|
59
|
+
should_compact: pressure?.shouldCompact ?? false,
|
|
60
|
+
should_intervene: pressure?.shouldIntervene ?? false,
|
|
61
|
+
pricing_threshold_crossed: pressure?.pricingThresholdCrossed ?? false,
|
|
62
|
+
batch: model.batch,
|
|
63
|
+
pricing_source: model.pricing?.source || null,
|
|
64
|
+
pricing_as_of: model.pricing?.as_of || null,
|
|
65
|
+
});
|
|
66
|
+
}
|
|
67
|
+
|
|
68
|
+
export function renderContextEconomics(report) {
|
|
69
|
+
if (!report.resolved) {
|
|
70
|
+
return [
|
|
71
|
+
'',
|
|
72
|
+
' Agent Sam · context',
|
|
73
|
+
` model ${report.model}`,
|
|
74
|
+
` reasoning ${report.reasoning_effort}`,
|
|
75
|
+
` processing ${report.service_tier}`,
|
|
76
|
+
'',
|
|
77
|
+
` ${report.reason}`,
|
|
78
|
+
'',
|
|
79
|
+
].join('\n');
|
|
80
|
+
}
|
|
81
|
+
|
|
82
|
+
const active = report.active_input_tokens == null
|
|
83
|
+
? 'unavailable · no provider/local usage snapshot yet'
|
|
84
|
+
: `${report.estimate_kind === 'provider' ? '' : '~'}${formatInteger(report.active_input_tokens)}${report.utilization_ratio == null ? '' : ` · ${percent(report.utilization_ratio)} of window`}`;
|
|
85
|
+
const remaining = report.tokens_until_pricing_threshold == null
|
|
86
|
+
? 'unavailable until active usage is known'
|
|
87
|
+
: `${report.tokens_until_pricing_threshold < 0 ? '-' : ''}${formatInteger(Math.abs(report.tokens_until_pricing_threshold))}`;
|
|
88
|
+
return [
|
|
89
|
+
'',
|
|
90
|
+
' Agent Sam · context',
|
|
91
|
+
` model ${report.model}`,
|
|
92
|
+
` reasoning ${report.reasoning_effort}`,
|
|
93
|
+
` processing ${report.service_tier}`,
|
|
94
|
+
'',
|
|
95
|
+
' Context',
|
|
96
|
+
` active ${active}`,
|
|
97
|
+
` window ${formatInteger(report.window_tokens)}`,
|
|
98
|
+
'',
|
|
99
|
+
' Working-set policy',
|
|
100
|
+
` target ${formatInteger(report.target_input_tokens)}`,
|
|
101
|
+
` compact at ${formatInteger(report.compact_at_tokens)}`,
|
|
102
|
+
` intervene at ${formatInteger(report.intervene_at_tokens)}`,
|
|
103
|
+
` max normal ${formatInteger(report.max_normal_input_tokens)}`,
|
|
104
|
+
'',
|
|
105
|
+
' Economics',
|
|
106
|
+
` price threshold ${formatInteger(report.pricing_threshold_tokens)}`,
|
|
107
|
+
` remaining ${remaining}`,
|
|
108
|
+
` pricing as-of ${report.pricing_as_of || 'unknown'}`,
|
|
109
|
+
'',
|
|
110
|
+
' Batch is a separate asynchronous execution lane; it is not an interactive service tier.',
|
|
111
|
+
' Use `/context repo` for repository/Git bridge context.',
|
|
112
|
+
'',
|
|
113
|
+
].join('\n');
|
|
114
|
+
}
|
package/src/commands/context.js
CHANGED
|
@@ -1,5 +1,6 @@
|
|
|
1
1
|
import { tryResolveGitContext } from '../lib/git-context.js';
|
|
2
2
|
import { resolveAgentSamBaseUrl, resolveBridgeKey } from '../lib/bridge-client.js';
|
|
3
|
+
import { loadProjectRules } from '../lib/project-rules.js';
|
|
3
4
|
|
|
4
5
|
function parseArgs(argv = []) {
|
|
5
6
|
const options = { json: false, cwd: process.cwd(), remote: 'origin' };
|
|
@@ -15,10 +16,20 @@ function parseArgs(argv = []) {
|
|
|
15
16
|
|
|
16
17
|
export function buildContextReport(options = {}) {
|
|
17
18
|
const env = options.env || process.env;
|
|
18
|
-
const
|
|
19
|
+
const cwd = options.cwd || process.cwd();
|
|
20
|
+
const git = tryResolveGitContext({ cwd, remote: options.remote || 'origin' });
|
|
21
|
+
const rules = loadProjectRules(cwd);
|
|
19
22
|
return {
|
|
20
|
-
schemaVersion: 'agentsam-context-
|
|
23
|
+
schemaVersion: 'agentsam-context-v2',
|
|
21
24
|
git,
|
|
25
|
+
rules: {
|
|
26
|
+
found: rules.found,
|
|
27
|
+
path: rules.path,
|
|
28
|
+
chars: rules.chars,
|
|
29
|
+
source_chars: rules.source_chars || 0,
|
|
30
|
+
truncated: rules.truncated,
|
|
31
|
+
hash: rules.hash,
|
|
32
|
+
},
|
|
22
33
|
bridge: {
|
|
23
34
|
baseUrl: resolveAgentSamBaseUrl(env),
|
|
24
35
|
configured: Boolean(resolveBridgeKey(env)),
|
|
@@ -46,6 +57,7 @@ export async function runContext(argv = []) {
|
|
|
46
57
|
} else {
|
|
47
58
|
console.log(' repo not inside a Git repository');
|
|
48
59
|
}
|
|
60
|
+
console.log(` rules ${report.rules.found ? `${report.rules.path} · ${report.rules.chars} chars` : 'none'}`);
|
|
49
61
|
console.log(` core ${report.bridge.baseUrl}`);
|
|
50
62
|
console.log(` bridge ${report.bridge.configured ? 'configured' : 'AGENTSAM_BRIDGE_KEY not set'}`);
|
|
51
63
|
console.log('');
|
package/src/commands/db.js
CHANGED
|
@@ -1,6 +1,7 @@
|
|
|
1
1
|
import fs from 'node:fs';
|
|
2
2
|
import path from 'node:path';
|
|
3
3
|
import { initializeLocalSqlite, inspectLocalSqlite } from '../local/sqlite.js';
|
|
4
|
+
import { getLocalDatabasePath, getLocalSchemaPath, readProjectConfig } from '../lib/project-config.js';
|
|
4
5
|
|
|
5
6
|
function findProjectRoot(startDir) {
|
|
6
7
|
let dir = path.resolve(startDir);
|
|
@@ -13,14 +14,10 @@ function findProjectRoot(startDir) {
|
|
|
13
14
|
throw new Error('Not an Agent Sam project — run `agentsam init` first.');
|
|
14
15
|
}
|
|
15
16
|
|
|
16
|
-
function readConfig(root) {
|
|
17
|
-
return JSON.parse(fs.readFileSync(path.join(root, '.agentsam', 'config.json'), 'utf8'));
|
|
18
|
-
}
|
|
19
|
-
|
|
20
17
|
function resolveDb(root, config) {
|
|
21
18
|
return {
|
|
22
|
-
dbPath: path.resolve(root, config
|
|
23
|
-
schemaPath: path.resolve(root, config
|
|
19
|
+
dbPath: path.resolve(root, getLocalDatabasePath(config)),
|
|
20
|
+
schemaPath: path.resolve(root, getLocalSchemaPath(config)),
|
|
24
21
|
};
|
|
25
22
|
}
|
|
26
23
|
|
|
@@ -31,7 +28,7 @@ export async function runDb(argv = [], opts = {}) {
|
|
|
31
28
|
}
|
|
32
29
|
|
|
33
30
|
const root = findProjectRoot(opts.cwd || process.cwd());
|
|
34
|
-
const config =
|
|
31
|
+
const config = readProjectConfig(root);
|
|
35
32
|
const paths = resolveDb(root, config);
|
|
36
33
|
|
|
37
34
|
if (sub === 'init') {
|
package/src/commands/deploy.js
CHANGED
|
@@ -6,26 +6,17 @@ import path from 'node:path';
|
|
|
6
6
|
import readline from 'node:readline';
|
|
7
7
|
import { authenticateViaBrowser } from '../lib/auth.js';
|
|
8
8
|
import { getJson, streamScaffold } from '../lib/core-client.js';
|
|
9
|
-
|
|
10
|
-
|
|
11
|
-
|
|
12
|
-
if (!fs.existsSync(configPath)) {
|
|
13
|
-
throw new Error('Not an Agent Sam project — run agentsam init first.');
|
|
14
|
-
}
|
|
15
|
-
return JSON.parse(fs.readFileSync(configPath, 'utf8'));
|
|
16
|
-
}
|
|
17
|
-
|
|
18
|
-
function writeConfig(cwd, config) {
|
|
19
|
-
const configPath = path.join(cwd, '.agentsam', 'config.json');
|
|
20
|
-
fs.writeFileSync(configPath, `${JSON.stringify(config, null, 2)}\n`, 'utf8');
|
|
21
|
-
}
|
|
9
|
+
import { resolveAccountSdkKey } from '../lib/account-session.js';
|
|
10
|
+
import { getDefaultProfile, getDeployTarget, getLocalSchemaPath, getProjectName, getProjectPreset, readProjectConfig, setDeployTarget, writeProjectConfig } from '../lib/project-config.js';
|
|
11
|
+
import { isLocalStudioCheckout, runLocalStudioDeploy } from '../lib/deploy/local-studio.js';
|
|
22
12
|
|
|
23
13
|
function writeCloudflareAdapter(cwd, config, cf) {
|
|
24
|
-
const
|
|
14
|
+
const projectName = getProjectName(config, path.basename(cwd));
|
|
15
|
+
const workerName = cf.worker_name || projectName;
|
|
25
16
|
const adapterPath = path.join(cwd, 'src', 'cloudflare-worker.js');
|
|
26
17
|
const migrationDir = path.join(cwd, 'migrations');
|
|
27
18
|
const migrationPath = path.join(migrationDir, '0001_agentsam_core.sql');
|
|
28
|
-
const localSchemaPath = path.join(cwd, config
|
|
19
|
+
const localSchemaPath = path.join(cwd, getLocalSchemaPath(config));
|
|
29
20
|
const tomlPath = path.join(cwd, 'wrangler.toml');
|
|
30
21
|
|
|
31
22
|
fs.mkdirSync(path.dirname(adapterPath), { recursive: true });
|
|
@@ -33,7 +24,7 @@ function writeCloudflareAdapter(cwd, config, cf) {
|
|
|
33
24
|
|
|
34
25
|
fs.writeFileSync(
|
|
35
26
|
adapterPath,
|
|
36
|
-
`import { createAgent } from './agent.js';\n\nexport default {\n async fetch(request, env) {\n const app = createAgent({\n env,\n project: ${JSON.stringify(
|
|
27
|
+
`import { createAgent } from './agent.js';\n\nexport default {\n async fetch(request, env) {\n const app = createAgent({\n env,\n project: ${JSON.stringify(projectName)},\n lane: ${JSON.stringify(getProjectPreset(config))},\n agent: ${JSON.stringify(getDefaultProfile(config))},\n });\n return app.handle(request);\n },\n};\n`,
|
|
37
28
|
'utf8',
|
|
38
29
|
);
|
|
39
30
|
|
|
@@ -51,7 +42,7 @@ function writeCloudflareAdapter(cwd, config, cf) {
|
|
|
51
42
|
if (cf.d1_database_id) {
|
|
52
43
|
lines.push('', '[[d1_databases]]');
|
|
53
44
|
lines.push('binding = "DB"');
|
|
54
|
-
lines.push(`database_name = ${JSON.stringify(cf.d1_database_name || `${
|
|
45
|
+
lines.push(`database_name = ${JSON.stringify(cf.d1_database_name || `${projectName}-db`)}`);
|
|
55
46
|
lines.push(`database_id = ${JSON.stringify(cf.d1_database_id)}`);
|
|
56
47
|
}
|
|
57
48
|
if (cf.kv_namespace_id) {
|
|
@@ -77,7 +68,7 @@ function ask(question) {
|
|
|
77
68
|
async function runCloudflareDeploy(cwd, config, accountId) {
|
|
78
69
|
console.log('\n Cloudflare deploy — browser sign-in + resource provisioning…\n');
|
|
79
70
|
|
|
80
|
-
let token = process.env.
|
|
71
|
+
let token = resolveAccountSdkKey({ env: process.env }).value;
|
|
81
72
|
if (!token) {
|
|
82
73
|
const session = await authenticateViaBrowser();
|
|
83
74
|
token = session.access_token;
|
|
@@ -92,8 +83,8 @@ async function runCloudflareDeploy(cwd, config, accountId) {
|
|
|
92
83
|
let complete = null;
|
|
93
84
|
await streamScaffold(
|
|
94
85
|
{
|
|
95
|
-
project_name: config.
|
|
96
|
-
lane: config
|
|
86
|
+
project_name: getProjectName(config, path.basename(cwd)),
|
|
87
|
+
lane: getProjectPreset(config),
|
|
97
88
|
hosting: 'cloudflare',
|
|
98
89
|
provision_only: true,
|
|
99
90
|
account_id: accountId || undefined,
|
|
@@ -114,13 +105,8 @@ async function runCloudflareDeploy(cwd, config, accountId) {
|
|
|
114
105
|
if (!complete?.cloudflare) throw new Error('deploy incomplete — no cloudflare ids returned');
|
|
115
106
|
|
|
116
107
|
const adapter = writeCloudflareAdapter(cwd, config, complete.cloudflare);
|
|
117
|
-
|
|
118
|
-
|
|
119
|
-
deploy_target: 'cloudflare',
|
|
120
|
-
cloudflare: complete.cloudflare,
|
|
121
|
-
cloud_adapter: path.relative(cwd, adapter.adapterPath),
|
|
122
|
-
deployed_at: new Date().toISOString(),
|
|
123
|
-
});
|
|
108
|
+
setDeployTarget(config, 'cloudflare');
|
|
109
|
+
writeProjectConfig(cwd, config);
|
|
124
110
|
|
|
125
111
|
console.log(`
|
|
126
112
|
✓ Cloudflare resources provisioned in YOUR account
|
|
@@ -137,14 +123,49 @@ async function runCloudflareDeploy(cwd, config, accountId) {
|
|
|
137
123
|
}
|
|
138
124
|
|
|
139
125
|
/**
|
|
140
|
-
* @param {{ cwd?: string, target?: string, accountId?: string }} [opts]
|
|
126
|
+
* @param {{ cwd?: string, target?: string, accountId?: string, dryRun?: boolean, plan?: boolean }} [opts]
|
|
141
127
|
*/
|
|
142
128
|
export async function runDeploy(opts = {}) {
|
|
143
129
|
const cwd = path.resolve(opts.cwd || process.cwd());
|
|
144
|
-
const config = readConfig(cwd);
|
|
145
130
|
|
|
146
|
-
|
|
147
|
-
|
|
131
|
+
if (isLocalStudioCheckout(cwd)) {
|
|
132
|
+
const result = await runLocalStudioDeploy({
|
|
133
|
+
cwd,
|
|
134
|
+
dryRun: Boolean(opts.dryRun),
|
|
135
|
+
planOnly: Boolean(opts.plan),
|
|
136
|
+
execute: !opts.plan,
|
|
137
|
+
});
|
|
138
|
+
const payload = {
|
|
139
|
+
provider: result.plan.provider,
|
|
140
|
+
app: result.plan.app,
|
|
141
|
+
wranglerConfig: result.plan.wranglerConfig,
|
|
142
|
+
wranglerArgs: result.plan.wranglerArgs,
|
|
143
|
+
cwd: result.plan.cwd,
|
|
144
|
+
envLoaded: result.plan.envLoaded,
|
|
145
|
+
fingerprint: result.plan.fingerprint,
|
|
146
|
+
skip: result.plan.skip,
|
|
147
|
+
dryRun: Boolean(opts.dryRun),
|
|
148
|
+
plan: Boolean(opts.plan),
|
|
149
|
+
genericRootDeploy: false,
|
|
150
|
+
receipt: result.receipt,
|
|
151
|
+
};
|
|
152
|
+
console.log(JSON.stringify(payload, null, 2));
|
|
153
|
+
if (result.plan.skip) {
|
|
154
|
+
console.log('skip: unchanged deploy fingerprint');
|
|
155
|
+
} else if (opts.plan) {
|
|
156
|
+
console.log('plan only — no wrangler deploy');
|
|
157
|
+
} else if (opts.dryRun) {
|
|
158
|
+
console.log('wrangler dry-run complete');
|
|
159
|
+
} else {
|
|
160
|
+
console.log('local-studio deploy complete');
|
|
161
|
+
}
|
|
162
|
+
return result;
|
|
163
|
+
}
|
|
164
|
+
|
|
165
|
+
const config = readProjectConfig(cwd);
|
|
166
|
+
|
|
167
|
+
let target = opts.target || getDeployTarget(config) || 'cloudflare';
|
|
168
|
+
if (!opts.target && !getDeployTarget(config)) {
|
|
148
169
|
console.log(`
|
|
149
170
|
Where do you want to deploy?
|
|
150
171
|
|
|
@@ -166,7 +187,8 @@ export async function runDeploy(opts = {}) {
|
|
|
166
187
|
Your local project keeps running with npm run dev.
|
|
167
188
|
Container/Worker deploy scripts are project-specific — add when ready.
|
|
168
189
|
`);
|
|
169
|
-
|
|
190
|
+
setDeployTarget(config, 'gcp');
|
|
191
|
+
writeProjectConfig(cwd, config);
|
|
170
192
|
return;
|
|
171
193
|
}
|
|
172
194
|
|