@inneranimalmedia/agentsam-sdk 2.5.0 → 2.6.1
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 +12 -8
- package/bin/agentsam +2 -0
- package/docs/AGENTSAM_ASTRA_OPENAI_INTEGRATION.md +1363 -0
- package/docs/CLI_SHELL.md +163 -53
- package/docs/PLATFORM_RUNTIME_EVENTS.md +48 -0
- package/docs/RELEASES.md +16 -7
- package/docs/SOURCE_ARCHITECTURE.md +58 -0
- package/docs/TEST_TIERS.md +26 -0
- package/migrations/runtime/0001_cli_runtime.sql +298 -0
- package/package.json +45 -12
- package/packages/agentsam-repository/README.md +15 -0
- package/packages/agentsam-repository/package.json +25 -0
- package/packages/agentsam-repository/src/contracts.js +113 -0
- package/packages/agentsam-repository/src/index.js +3 -0
- package/{src/lib → packages/agentsam-repository/src}/merkle/cloudflare-persistence.js +14 -24
- package/{src/lib → packages/agentsam-repository/src}/merkle/index.js +1 -0
- package/{src/lib → packages/agentsam-repository/src}/merkle/persistence.js +6 -4
- package/{src/lib → packages/agentsam-repository/src}/merkle/policy.js +1 -0
- package/packages/agentsam-repository/test/contracts.test.mjs +40 -0
- package/packages/agentsam-repository/test/git-context.test.mjs +24 -0
- package/{test/merkle.test.mjs → packages/agentsam-repository/test/merkle-core.test.mjs} +2 -32
- package/{test → packages/agentsam-repository/test}/merkle-persistence.test.mjs +11 -6
- 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 +2 -2
- package/packages/identity/src/contracts/auth-config.js +18 -7
- package/packages/identity/tests/auth-config.test.mjs +9 -5
- package/packages/identity/tests/oauth-credentials.test.mjs +4 -4
- package/protocol/COMPANY_REPOSITORY_GRAPH_V1.md +91 -0
- package/protocol/MERKLE_PERSISTENCE_V1.md +2 -0
- package/protocol/MERKLE_PERSISTENCE_V2.md +40 -0
- 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 +47 -0
- package/protocol/context/context-budget.schema.json +10 -15
- package/protocol/context/context-item.schema.json +4 -5
- package/protocol/context/resolved-context-pack.schema.json +19 -14
- package/protocol/models/README.md +373 -0
- package/protocol/models/model-inventory-v2.schema.json +212 -0
- package/protocol/repository/repository-contract.schema.json +24 -0
- package/protocol/repository/repository-dependency.schema.json +24 -0
- package/protocol/repository/repository-identity.schema.json +17 -0
- package/protocol/rpc/v1/common.proto +16 -0
- package/protocol/rpc/v1/errors.proto +35 -0
- package/protocol/rpc/v1/knowledge.proto +77 -0
- package/services/knowledge/package-lock.json +333 -0
- package/services/knowledge/package.json +5 -1
- 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/catalog.json +18 -0
- package/src/agent/capability-adapter.js +25 -13
- package/src/agent/index.js +1 -0
- package/src/agent/responses-runner.js +353 -0
- package/src/capabilities/repository-snapshot.js +3 -3
- package/src/cli.js +118 -31
- 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 +129 -0
- package/src/commands/context.js +1 -1
- package/src/commands/db.js +20 -3
- package/src/commands/deploy.js +39 -3
- package/src/commands/env.js +90 -0
- package/src/commands/eval.js +63 -0
- package/src/commands/interactive.js +2 -5
- package/src/commands/knowledge.js +12 -4
- package/src/commands/merkle-persist.js +30 -11
- package/src/commands/merkle.js +1 -1
- package/src/commands/models.js +149 -46
- package/src/commands/ollama.js +26 -0
- package/src/commands/preferences.js +130 -61
- package/src/commands/resume.js +67 -0
- package/src/commands/security.js +5 -3
- package/src/commands/shell.js +568 -119
- package/src/commands/tunnel.js +2 -2
- package/src/commands/whoami.js +86 -0
- package/src/context/budget.js +68 -6
- package/src/context/index.js +3 -1
- package/src/context/rehydrate.js +35 -0
- package/src/context/resolve.js +44 -12
- package/src/errors/contract.js +236 -0
- package/src/errors/diagnostic.js +160 -0
- package/src/errors/index.js +23 -0
- package/src/eval/context.js +191 -0
- package/src/eval/index.js +1 -0
- package/src/index.js +68 -2
- package/src/knowledge/service/auth.js +13 -0
- package/src/knowledge/service/grpc-client.js +115 -0
- package/src/knowledge/service/grpc-codec.js +237 -0
- package/src/knowledge/service/grpc-server.js +83 -0
- package/src/knowledge/service/job-engine.js +248 -0
- package/src/knowledge/service/server.js +87 -135
- package/src/knowledge/source.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/cli-preferences.js +55 -24
- 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 +2 -2
- package/src/lib/detect-context.js +2 -2
- package/src/lib/execution-approvals.js +59 -0
- package/src/lib/knowledge-docker.js +6 -3
- package/src/lib/local-sessions.js +148 -0
- package/src/lib/local-status.js +1 -1
- package/src/lib/project-config.js +1 -1
- package/src/lib/provider-credentials.js +183 -0
- 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 +23 -16
- package/src/local/migrations.js +93 -0
- package/src/local/runtime-store.js +141 -0
- package/src/local/sqlite.js +2 -0
- package/src/local-pty/server.js +113 -51
- package/src/models/catalog.js +135 -0
- package/src/models/discovery.js +292 -0
- package/src/models/index.js +7 -0
- package/src/providers/anthropic-messages.js +192 -0
- package/src/providers/cloudflare-chat.js +183 -0
- package/src/providers/factory.js +69 -0
- package/src/providers/gemini-generate-content.js +208 -0
- package/src/providers/index.js +10 -0
- package/src/providers/ollama-chat.js +148 -0
- package/src/providers/openai-responses.js +426 -0
- package/src/repository/index.js +14 -2
- package/src/rpc/generated/common_grpc_pb.js +1 -0
- package/src/rpc/generated/common_pb.js +536 -0
- package/src/rpc/generated/errors_grpc_pb.js +1 -0
- package/src/rpc/generated/errors_pb.js +482 -0
- package/src/rpc/generated/knowledge_grpc_pb.js +135 -0
- package/src/rpc/generated/knowledge_pb.js +2168 -0
- package/src/rpc/generated/package.json +3 -0
- package/src/security/process.js +35 -9
- package/src/security/trust-boundary.js +2 -2
- package/src/telemetry/contracts.js +203 -0
- package/src/telemetry/events.js +51 -0
- package/src/telemetry/index.js +8 -0
- package/src/tools/hydrate.js +35 -0
- package/src/tools/index.js +1 -0
- package/src/ui/boot.js +15 -17
- package/src/ui/cli/activity.js +76 -0
- package/src/ui/cli/compaction.js +15 -0
- package/src/ui/cli/footer.js +39 -0
- package/src/ui/cli/help.js +192 -0
- package/src/ui/cli/plan.js +20 -0
- package/src/ui/cli/runtime-events.js +110 -0
- package/src/ui/cli/waiting.js +16 -0
- package/src/ui/merkle/render.js +1 -1
- package/test/account-session.test.mjs +36 -0
- package/test/cli/preferences-runtime.test.mjs +11 -0
- package/test/cli/runtime-ui.test.mjs +74 -0
- package/test/cli-preferences.test.mjs +26 -5
- package/test/cloudflare-connector.test.mjs +96 -0
- package/test/cloudflare-runtime.test.mjs +75 -0
- package/test/context.test.mjs +61 -12
- package/test/deploy-health-scan.test.mjs +67 -0
- package/test/error-diagnostics.test.mjs +115 -0
- package/test/eval-context.test.mjs +37 -0
- package/test/execution-approvals.test.mjs +27 -0
- package/test/fixtures/knowledge-rpc-worker.mjs +16 -0
- package/test/integration/cli-help.test.mjs +37 -0
- package/test/integration/knowledge-rpc.test.mjs +112 -0
- package/test/integration/merkle-cli.test.mjs +61 -0
- package/test/integration/merkle-persistence-identity.test.mjs +48 -0
- package/test/integration/provider-env-cli.test.mjs +49 -0
- package/test/integration/provider-factory.test.mjs +197 -0
- package/test/integration/repository-company-graph.test.mjs +90 -0
- package/test/integration/runtime-migrations.test.mjs +82 -0
- package/test/knowledge-service.test.mjs +5 -0
- package/test/knowledge.test.mjs +16 -0
- package/test/live/terminal-transport.live.test.mjs +24 -0
- package/test/local-sessions.test.mjs +48 -0
- package/test/local-studio-deploy.test.mjs +83 -0
- package/test/model-catalog.test.mjs +43 -0
- package/test/models.test.mjs +127 -16
- package/test/npm10-lock.test.mjs +29 -0
- package/test/ollama.test.mjs +21 -0
- package/test/openai-responses.test.mjs +95 -0
- package/test/portable-context.test.mjs +1 -1
- package/test/provider-credentials.test.mjs +96 -0
- package/test/rehydrate.test.mjs +25 -0
- package/test/release-hygiene.test.mjs +13 -5
- package/test/responses-runner.test.mjs +150 -0
- package/test/shell.test.mjs +92 -23
- package/test/smoke.mjs +4 -1
- package/test/telemetry.test.mjs +79 -0
- package/test/terminal/local-pty.mock.test.mjs +151 -0
- package/test/tools-search.test.mjs +14 -1
- package/test/whoami-resume.test.mjs +56 -0
- /package/{src/lib → packages/agentsam-repository/src}/git-context.js +0 -0
- /package/{src/lib → packages/agentsam-repository/src}/merkle/diff.js +0 -0
- /package/{src/lib → packages/agentsam-repository/src}/merkle/filemeta.js +0 -0
- /package/{src/lib → packages/agentsam-repository/src}/merkle/git-ignore.js +0 -0
- /package/{src/lib → packages/agentsam-repository/src}/merkle/hash.js +0 -0
- /package/{src/lib → packages/agentsam-repository/src}/merkle/semantic.js +0 -0
- /package/{src/lib → packages/agentsam-repository/src}/merkle/snapshot.js +0 -0
- /package/{src/lib → packages/agentsam-repository/src}/merkle/tree.js +0 -0
package/src/cli.js
CHANGED
|
@@ -13,8 +13,10 @@ import { promptOptionalByokKeys } from './lib/prompt-byok.js';
|
|
|
13
13
|
import { runStartLocal } from './commands/start-local.js';
|
|
14
14
|
import { runOllama } from './commands/ollama.js';
|
|
15
15
|
import { runModels } from './commands/models.js';
|
|
16
|
+
import { runEnv } from './commands/env.js';
|
|
16
17
|
import { runTunnel } from './commands/tunnel.js';
|
|
17
18
|
import { runDeploy } from './commands/deploy.js';
|
|
19
|
+
import { runConnections } from './commands/connections.js';
|
|
18
20
|
import { runIdentityPreview } from './commands/identity-preview.js';
|
|
19
21
|
import { runIdentityInit } from './commands/identity-init.js';
|
|
20
22
|
import { runContext } from './commands/context.js';
|
|
@@ -30,14 +32,27 @@ import { runSecurity } from './commands/security.js';
|
|
|
30
32
|
import { runRecon } from './commands/recon.js';
|
|
31
33
|
import { runCad } from './commands/cad.js';
|
|
32
34
|
import { runSkills } from './commands/skills.js';
|
|
35
|
+
import { runEval } from './commands/eval.js';
|
|
36
|
+
import { runCloudflare } from './commands/cloudflare.js';
|
|
37
|
+
import { runWhoami } from './commands/whoami.js';
|
|
38
|
+
import { runResume } from './commands/resume.js';
|
|
39
|
+
import { runLogin, runLogout } from './commands/account-auth.js';
|
|
33
40
|
import { applyPresetSelection, runAdd, runCapabilities, runDev, runInspect } from './commands/product.js';
|
|
34
41
|
import { listPresets, resolvePreset } from './presets/index.js';
|
|
35
42
|
import fs from 'node:fs';
|
|
36
43
|
import { repositoryRoot } from './knowledge/config.js';
|
|
37
|
-
import {
|
|
44
|
+
import { resolveAccountSdkKey } from './lib/account-session.js';
|
|
45
|
+
import { renderDiagnosticError } from './errors/index.js';
|
|
46
|
+
import { renderHelpOverview, runHelp } from './ui/cli/help.js';
|
|
38
47
|
|
|
39
48
|
const VERSION = pkg.version;
|
|
40
49
|
|
|
50
|
+
function reportCliError(error) {
|
|
51
|
+
if (error?.reported) return;
|
|
52
|
+
const rendered = renderDiagnosticError(error).split('\n').map((line) => ` ${line}`).join('\n');
|
|
53
|
+
console.error(`\n${rendered}\n`);
|
|
54
|
+
}
|
|
55
|
+
|
|
41
56
|
function createPrompt() {
|
|
42
57
|
const rl = readline.createInterface({ input: process.stdin, output: process.stdout });
|
|
43
58
|
return {
|
|
@@ -47,6 +62,10 @@ function createPrompt() {
|
|
|
47
62
|
}
|
|
48
63
|
|
|
49
64
|
function printHelp() {
|
|
65
|
+
console.log(renderHelpOverview(VERSION));
|
|
66
|
+
}
|
|
67
|
+
|
|
68
|
+
function printLegacyHelp() {
|
|
50
69
|
console.log(`
|
|
51
70
|
Agent Sam SDK — CLI v${VERSION}
|
|
52
71
|
|
|
@@ -76,15 +95,23 @@ function printHelp() {
|
|
|
76
95
|
agentsam security Dependency scan, log triage, and verified repair (--help)
|
|
77
96
|
agentsam status [--json] Live local Git + DB + API + PTY status
|
|
78
97
|
agentsam db init|status Manage the project-local SQLite database
|
|
79
|
-
agentsam models
|
|
98
|
+
agentsam models Verify configured providers and selectable hosted/local models
|
|
99
|
+
agentsam env init <name> Create a secure provider profile + reusable shell loader
|
|
100
|
+
agentsam login Sign in to Inner Animal Media and persist a secure machine-local session
|
|
101
|
+
agentsam logout Sign out locally; provider credentials stay untouched
|
|
102
|
+
agentsam whoami [--json] Authenticated account identity + safe credential status
|
|
103
|
+
agentsam resume [session] Resume a saved Agent Sam session; omit id for picker
|
|
104
|
+
agentsam eval context Offline context-strategy/economics fixtures (--help)
|
|
105
|
+
agentsam cloudflare Native Wrangler reads + Worker CPU profile analysis (--help)
|
|
80
106
|
agentsam start-local Local PTY on ws://127.0.0.1:3099 (no tunnel, no Cloudflare)
|
|
81
107
|
agentsam ollama Opt-in local Ollama setup/status/model management
|
|
82
108
|
agentsam shell Interactive Agent Sam slash-command shell
|
|
83
109
|
agentsam tunnel Explicitly expose local PTY when remote access is wanted
|
|
84
110
|
agentsam deploy Graduate to Cloudflare / GCP when ready
|
|
85
111
|
agentsam dockerize Build/run app, knowledge, or CAD containers (--help)
|
|
86
|
-
agentsam identity preview
|
|
112
|
+
agentsam identity preview Preview the reusable local auth portal (not production login)
|
|
87
113
|
agentsam identity init Add reusable identity package surfaces
|
|
114
|
+
agentsam help
|
|
88
115
|
agentsam --version
|
|
89
116
|
agentsam --help
|
|
90
117
|
|
|
@@ -108,8 +135,8 @@ function printHelp() {
|
|
|
108
135
|
--pretty Pretty-print JSON; machine JSON is compact by default
|
|
109
136
|
--remote <name> Preferred Git remote (default origin; falls back to first remote)
|
|
110
137
|
|
|
111
|
-
|
|
112
|
-
|
|
138
|
+
Run agentsam from any project to enter the account-aware interactive experience.
|
|
139
|
+
Account, model-provider, terminal, and deploy permissions are requested only when the related capability needs them.
|
|
113
140
|
|
|
114
141
|
Tunnel options:
|
|
115
142
|
--quick Quick tunnel (default) — trycloudflare.com URL
|
|
@@ -143,11 +170,13 @@ function parseInitArgs(argv) {
|
|
|
143
170
|
}
|
|
144
171
|
|
|
145
172
|
function parseDeployArgs(argv) {
|
|
146
|
-
const opts = { target: '', accountId: '' };
|
|
173
|
+
const opts = { target: '', accountId: '', dryRun: false, plan: false };
|
|
147
174
|
for (let i = 0; i < argv.length; i += 1) {
|
|
148
175
|
const arg = argv[i];
|
|
149
176
|
if (arg === '--target') opts.target = argv[++i] || '';
|
|
150
177
|
else if (arg === '--account-id') opts.accountId = argv[++i] || '';
|
|
178
|
+
else if (arg === '--dry-run') opts.dryRun = true;
|
|
179
|
+
else if (arg === '--plan') opts.plan = true;
|
|
151
180
|
}
|
|
152
181
|
return opts;
|
|
153
182
|
}
|
|
@@ -206,7 +235,7 @@ async function runLocalInit(config) {
|
|
|
206
235
|
console.log(` ${step}`);
|
|
207
236
|
}
|
|
208
237
|
|
|
209
|
-
const sdkKey =
|
|
238
|
+
const sdkKey = resolveAccountSdkKey({ env: process.env }).value;
|
|
210
239
|
if (prompt && sdkKey) {
|
|
211
240
|
console.log('\n Optional — BYOK keys for IAM dashboard Agent Sam (skip with Enter):\n');
|
|
212
241
|
await promptOptionalByokKeys(sdkKey, prompt);
|
|
@@ -262,12 +291,12 @@ async function initInteractive(partial = {}) {
|
|
|
262
291
|
if (runTarget !== 'local') {
|
|
263
292
|
const { detectContext, missingForInit } = await import('./lib/detect-context.js');
|
|
264
293
|
const ctx = await detectContext();
|
|
265
|
-
if (missingForInit(ctx,
|
|
294
|
+
if (missingForInit(ctx, resolveAccountSdkKey({ env: process.env }).value, { runTarget }).length) {
|
|
266
295
|
printContextSummary(ctx);
|
|
267
296
|
}
|
|
268
297
|
}
|
|
269
298
|
|
|
270
|
-
const prompt =
|
|
299
|
+
const prompt = resolveAccountSdkKey({ env: process.env }).value ? createPrompt() : null;
|
|
271
300
|
try {
|
|
272
301
|
await runLocalInit({ projectName, lane: laneKey, runTarget, prompt });
|
|
273
302
|
} finally {
|
|
@@ -290,6 +319,8 @@ const rest = process.argv.slice(3);
|
|
|
290
319
|
|
|
291
320
|
if (command === '--version' || command === '-v') {
|
|
292
321
|
console.log(VERSION);
|
|
322
|
+
} else if (command === 'help') {
|
|
323
|
+
await runHelp(rest, { version: VERSION });
|
|
293
324
|
} else if (command === '--help' || command === '-h') {
|
|
294
325
|
printHelp();
|
|
295
326
|
} else if (!command) {
|
|
@@ -297,7 +328,7 @@ if (command === '--version' || command === '-v') {
|
|
|
297
328
|
try { await runInteractive(); }
|
|
298
329
|
catch (e) {
|
|
299
330
|
if (e?.code !== 'AGENTSAM_SETUP_CANCELLED') {
|
|
300
|
-
|
|
331
|
+
reportCliError(e);
|
|
301
332
|
process.exitCode = 1;
|
|
302
333
|
}
|
|
303
334
|
}
|
|
@@ -315,52 +346,101 @@ if (command === '--version' || command === '-v') {
|
|
|
315
346
|
applyPresetSelection(created.dir, preset);
|
|
316
347
|
console.log(` ✓ Preset ${preset.id}\n ✓ Features ${preset.features.join(', ') || 'none'}\n ✓ Capabilities ${preset.capabilities.length}\n`);
|
|
317
348
|
}
|
|
318
|
-
} catch (e) {
|
|
349
|
+
} catch (e) { reportCliError(e); process.exitCode = 1; }
|
|
319
350
|
} else if (command === 'add') {
|
|
320
351
|
try { await runAdd(rest); }
|
|
321
|
-
catch (e) {
|
|
352
|
+
catch (e) { reportCliError(e); process.exitCode = 1; }
|
|
322
353
|
} else if (command === 'dev') {
|
|
323
354
|
try { await runDev(rest); }
|
|
324
|
-
catch (e) {
|
|
355
|
+
catch (e) { reportCliError(e); process.exitCode = 1; }
|
|
325
356
|
} else if (command === 'inspect') {
|
|
326
357
|
try { await runInspect(rest); }
|
|
327
|
-
catch (e) {
|
|
358
|
+
catch (e) { reportCliError(e); process.exitCode = 1; }
|
|
328
359
|
} else if (command === 'capabilities') {
|
|
329
360
|
try { await runCapabilities(rest); }
|
|
330
|
-
catch (e) {
|
|
361
|
+
catch (e) { reportCliError(e); process.exitCode = 1; }
|
|
331
362
|
} else if (command === 'context') {
|
|
332
363
|
try {
|
|
333
364
|
await runContext(rest);
|
|
334
365
|
} catch (e) {
|
|
335
|
-
|
|
366
|
+
reportCliError(e);
|
|
336
367
|
process.exit(1);
|
|
337
368
|
}
|
|
338
369
|
} else if (command === 'status') {
|
|
339
370
|
try {
|
|
340
371
|
await runStatus(rest);
|
|
341
372
|
} catch (e) {
|
|
342
|
-
|
|
373
|
+
reportCliError(e);
|
|
343
374
|
process.exit(1);
|
|
344
375
|
}
|
|
345
376
|
} else if (command === 'db') {
|
|
346
377
|
try {
|
|
347
378
|
await runDb(rest);
|
|
348
379
|
} catch (e) {
|
|
349
|
-
|
|
380
|
+
reportCliError(e);
|
|
350
381
|
process.exit(1);
|
|
351
382
|
}
|
|
352
383
|
} else if (command === 'models') {
|
|
353
384
|
try {
|
|
354
385
|
await runModels(rest);
|
|
355
386
|
} catch (e) {
|
|
356
|
-
|
|
387
|
+
reportCliError(e);
|
|
388
|
+
process.exit(1);
|
|
389
|
+
}
|
|
390
|
+
} else if (command === 'env') {
|
|
391
|
+
try {
|
|
392
|
+
await runEnv(rest);
|
|
393
|
+
} catch (e) {
|
|
394
|
+
reportCliError(e);
|
|
395
|
+
process.exit(1);
|
|
396
|
+
}
|
|
397
|
+
} else if (command === 'eval') {
|
|
398
|
+
try {
|
|
399
|
+
await runEval(rest);
|
|
400
|
+
} catch (e) {
|
|
401
|
+
reportCliError(e);
|
|
357
402
|
process.exit(1);
|
|
358
403
|
}
|
|
404
|
+
} else if (command === 'cloudflare' || command === 'cf') {
|
|
405
|
+
try {
|
|
406
|
+
await runCloudflare(rest);
|
|
407
|
+
} catch (e) {
|
|
408
|
+
if (!e?.reported) reportCliError(e);
|
|
409
|
+
process.exitCode = 1;
|
|
410
|
+
}
|
|
411
|
+
} else if (command === 'login') {
|
|
412
|
+
try {
|
|
413
|
+
await runLogin(rest);
|
|
414
|
+
} catch (e) {
|
|
415
|
+
reportCliError(e);
|
|
416
|
+
process.exitCode = 1;
|
|
417
|
+
}
|
|
418
|
+
} else if (command === 'logout') {
|
|
419
|
+
try {
|
|
420
|
+
runLogout(rest);
|
|
421
|
+
} catch (e) {
|
|
422
|
+
reportCliError(e);
|
|
423
|
+
process.exitCode = 1;
|
|
424
|
+
}
|
|
425
|
+
} else if (command === 'whoami') {
|
|
426
|
+
try {
|
|
427
|
+
await runWhoami(rest);
|
|
428
|
+
} catch (e) {
|
|
429
|
+
reportCliError(e);
|
|
430
|
+
process.exitCode = 1;
|
|
431
|
+
}
|
|
432
|
+
} else if (command === 'resume') {
|
|
433
|
+
try {
|
|
434
|
+
await runResume(rest);
|
|
435
|
+
} catch (e) {
|
|
436
|
+
reportCliError(e);
|
|
437
|
+
process.exitCode = 1;
|
|
438
|
+
}
|
|
359
439
|
} else if (command === 'shell') {
|
|
360
440
|
try {
|
|
361
441
|
await runShell(rest);
|
|
362
442
|
} catch (e) {
|
|
363
|
-
|
|
443
|
+
reportCliError(e);
|
|
364
444
|
process.exit(1);
|
|
365
445
|
}
|
|
366
446
|
} else if (command === 'start-local') {
|
|
@@ -369,35 +449,42 @@ if (command === '--version' || command === '-v') {
|
|
|
369
449
|
try {
|
|
370
450
|
await runOllama(rest);
|
|
371
451
|
} catch (e) {
|
|
372
|
-
|
|
452
|
+
reportCliError(e);
|
|
373
453
|
process.exitCode = 1;
|
|
374
454
|
}
|
|
375
455
|
} else if (command === 'tunnel') {
|
|
376
456
|
try {
|
|
377
457
|
await runTunnel(rest);
|
|
378
458
|
} catch (e) {
|
|
379
|
-
|
|
459
|
+
reportCliError(e);
|
|
460
|
+
process.exit(1);
|
|
461
|
+
}
|
|
462
|
+
} else if (command === 'connections' || command === 'connection') {
|
|
463
|
+
try {
|
|
464
|
+
await runConnections(rest);
|
|
465
|
+
} catch (e) {
|
|
466
|
+
reportCliError(e);
|
|
380
467
|
process.exit(1);
|
|
381
468
|
}
|
|
382
469
|
} else if (command === 'deploy') {
|
|
383
470
|
try {
|
|
384
471
|
await runDeploy(parseDeployArgs(rest));
|
|
385
472
|
} catch (e) {
|
|
386
|
-
|
|
473
|
+
reportCliError(e);
|
|
387
474
|
process.exit(1);
|
|
388
475
|
}
|
|
389
476
|
} else if (command === 'dockerize') {
|
|
390
477
|
try {
|
|
391
478
|
await runDockerize(rest);
|
|
392
479
|
} catch (e) {
|
|
393
|
-
|
|
480
|
+
reportCliError(e);
|
|
394
481
|
process.exit(1);
|
|
395
482
|
}
|
|
396
483
|
} else if (command === 'cad') {
|
|
397
484
|
try {
|
|
398
485
|
await runCad(rest);
|
|
399
486
|
} catch (e) {
|
|
400
|
-
|
|
487
|
+
reportCliError(e);
|
|
401
488
|
process.exitCode = 1;
|
|
402
489
|
}
|
|
403
490
|
} else if (command === 'security' || command === 'sca') {
|
|
@@ -406,7 +493,7 @@ if (command === '--version' || command === '-v') {
|
|
|
406
493
|
try {
|
|
407
494
|
runSkills(rest);
|
|
408
495
|
} catch (e) {
|
|
409
|
-
|
|
496
|
+
reportCliError(e);
|
|
410
497
|
process.exitCode = 1;
|
|
411
498
|
}
|
|
412
499
|
} else if (command === 'merkle') {
|
|
@@ -419,14 +506,14 @@ if (command === '--version' || command === '-v') {
|
|
|
419
506
|
try {
|
|
420
507
|
await runMini(rest);
|
|
421
508
|
} catch (e) {
|
|
422
|
-
|
|
509
|
+
reportCliError(e);
|
|
423
510
|
process.exitCode = 1;
|
|
424
511
|
}
|
|
425
512
|
} else if (['index', 'search', 'repo'].includes(command)) {
|
|
426
513
|
try {
|
|
427
514
|
const commands = await import('./commands/knowledge.js');
|
|
428
515
|
await ({ index: commands.runKnowledge, search: commands.runSearch, repo: commands.runRepository })[command](rest);
|
|
429
|
-
} catch (e) {
|
|
516
|
+
} catch (e) { reportCliError(e); process.exitCode = 1; }
|
|
430
517
|
} else if (command === 'init') {
|
|
431
518
|
try {
|
|
432
519
|
const existing = !rest.includes('--name') && (rest.includes('.') || rest.includes('--existing') || rest.includes('--cwd') || fs.existsSync(path.join(repositoryRoot(), '.git')));
|
|
@@ -434,21 +521,21 @@ if (command === '--version' || command === '-v') {
|
|
|
434
521
|
else if (rest.includes('--help') || rest.includes('-h')) printHelp();
|
|
435
522
|
else if (rest.some((a) => a.startsWith('--'))) await initFromArgs(rest);
|
|
436
523
|
else await initInteractive({});
|
|
437
|
-
} catch (e) {
|
|
524
|
+
} catch (e) { reportCliError(e); process.exitCode = 1; }
|
|
438
525
|
} else if (command === 'identity') {
|
|
439
526
|
const sub = rest[0];
|
|
440
527
|
if (sub === 'preview') {
|
|
441
528
|
try {
|
|
442
529
|
await runIdentityPreview(rest.slice(1));
|
|
443
530
|
} catch (e) {
|
|
444
|
-
|
|
531
|
+
reportCliError(e);
|
|
445
532
|
process.exit(1);
|
|
446
533
|
}
|
|
447
534
|
} else if (sub === 'init') {
|
|
448
535
|
try {
|
|
449
536
|
await runIdentityInit(rest);
|
|
450
537
|
} catch (e) {
|
|
451
|
-
|
|
538
|
+
reportCliError(e);
|
|
452
539
|
process.exit(1);
|
|
453
540
|
}
|
|
454
541
|
} else {
|
|
@@ -0,0 +1,115 @@
|
|
|
1
|
+
import fs from 'node:fs';
|
|
2
|
+
import path from 'node:path';
|
|
3
|
+
|
|
4
|
+
function clean(value) { return value == null ? '' : String(value).trim(); }
|
|
5
|
+
function number(value) { const n = Number(value ?? 0); return Number.isFinite(n) && n >= 0 ? n : 0; }
|
|
6
|
+
|
|
7
|
+
function parseProfile(value) {
|
|
8
|
+
if (typeof value === 'string') return JSON.parse(value);
|
|
9
|
+
if (!value || typeof value !== 'object' || Array.isArray(value)) throw new TypeError('Cloudflare CPU profile must be a Chrome .cpuprofile object');
|
|
10
|
+
return value;
|
|
11
|
+
}
|
|
12
|
+
|
|
13
|
+
function frameOf(node = {}) {
|
|
14
|
+
const frame = node.callFrame || {};
|
|
15
|
+
return {
|
|
16
|
+
node_id: node.id,
|
|
17
|
+
function: clean(frame.functionName) || '(anonymous)',
|
|
18
|
+
url: clean(frame.url) || null,
|
|
19
|
+
line: Number.isInteger(frame.lineNumber) && frame.lineNumber >= 0 ? frame.lineNumber + 1 : null,
|
|
20
|
+
column: Number.isInteger(frame.columnNumber) && frame.columnNumber >= 0 ? frame.columnNumber + 1 : null,
|
|
21
|
+
};
|
|
22
|
+
}
|
|
23
|
+
|
|
24
|
+
export function summarizeCloudflareCpuProfile(value, options = {}) {
|
|
25
|
+
const profile = parseProfile(value);
|
|
26
|
+
if (!Array.isArray(profile.nodes) || !Array.isArray(profile.samples)) throw new TypeError('CPU profile requires nodes[] and samples[]');
|
|
27
|
+
const deltas = Array.isArray(profile.timeDeltas) ? profile.timeDeltas : [];
|
|
28
|
+
const byId = new Map(profile.nodes.map((node) => [node.id, node]));
|
|
29
|
+
const totals = new Map();
|
|
30
|
+
let totalUs = 0;
|
|
31
|
+
for (let index = 0; index < profile.samples.length; index += 1) {
|
|
32
|
+
const id = profile.samples[index];
|
|
33
|
+
const deltaUs = number(deltas[index]);
|
|
34
|
+
totalUs += deltaUs;
|
|
35
|
+
totals.set(id, (totals.get(id) || 0) + deltaUs);
|
|
36
|
+
}
|
|
37
|
+
if (!totalUs && Number.isFinite(profile.endTime) && Number.isFinite(profile.startTime)) totalUs = Math.max(0, Number(profile.endTime) - Number(profile.startTime));
|
|
38
|
+
const maxFrames = Number.isInteger(options.maxFrames) && options.maxFrames > 0 ? Math.min(options.maxFrames, 100) : 25;
|
|
39
|
+
const frames = [...totals.entries()].map(([id, selfUs]) => {
|
|
40
|
+
const frame = frameOf(byId.get(id));
|
|
41
|
+
return Object.freeze({
|
|
42
|
+
...frame,
|
|
43
|
+
self_us: selfUs,
|
|
44
|
+
self_ms: selfUs / 1000,
|
|
45
|
+
percent: totalUs > 0 ? (selfUs / totalUs) * 100 : 0,
|
|
46
|
+
garbage_collection: /(?:garbage collector|\bgc\b)/i.test(frame.function),
|
|
47
|
+
});
|
|
48
|
+
}).sort((a, b) => b.self_us - a.self_us).slice(0, maxFrames);
|
|
49
|
+
return Object.freeze({
|
|
50
|
+
schema_version: 1,
|
|
51
|
+
profile_kind: 'chrome-cpu-profile',
|
|
52
|
+
samples: profile.samples.length,
|
|
53
|
+
total_profile_us: totalUs,
|
|
54
|
+
total_profile_ms: totalUs / 1000,
|
|
55
|
+
top_frames: Object.freeze(frames),
|
|
56
|
+
garbage_collection_ms: frames.filter((row) => row.garbage_collection).reduce((sum, row) => sum + row.self_ms, 0),
|
|
57
|
+
timer_semantics: 'Deployed Workers timers do not advance during CPU-only execution; use local workerd/DevTools CPU profiles plus production CPU metrics.',
|
|
58
|
+
});
|
|
59
|
+
}
|
|
60
|
+
|
|
61
|
+
function within(root, file) { return file === root || file.startsWith(`${root}${path.sep}`); }
|
|
62
|
+
|
|
63
|
+
export function summarizeCloudflareCpuProfileFile(input = {}) {
|
|
64
|
+
const cwd = path.resolve(input.cwd || process.cwd());
|
|
65
|
+
const file = path.resolve(cwd, clean(input.file));
|
|
66
|
+
if (!clean(input.file)) throw new TypeError('cpu profile file is required');
|
|
67
|
+
if (!within(cwd, file)) throw new Error('cpu_profile_outside_cwd');
|
|
68
|
+
const stat = fs.statSync(file);
|
|
69
|
+
if (!stat.isFile()) throw new Error('cpu_profile_not_file');
|
|
70
|
+
if (stat.size > 64 * 1024 * 1024) throw new Error('cpu_profile_too_large');
|
|
71
|
+
return Object.freeze({ file: path.relative(cwd, file) || path.basename(file), ...summarizeCloudflareCpuProfile(fs.readFileSync(file, 'utf8'), input) });
|
|
72
|
+
}
|
|
73
|
+
|
|
74
|
+
function sourceItems(cwd, sources = [], maxChars = 24_000) {
|
|
75
|
+
const rows = [];
|
|
76
|
+
let chars = 0;
|
|
77
|
+
for (const source of sources.slice(0, 12)) {
|
|
78
|
+
const file = path.resolve(cwd, String(source));
|
|
79
|
+
if (!within(cwd, file) || !fs.existsSync(file) || !fs.statSync(file).isFile()) continue;
|
|
80
|
+
const text = fs.readFileSync(file, 'utf8');
|
|
81
|
+
const excerpt = text.slice(0, Math.min(8_000, Math.max(0, maxChars - chars)));
|
|
82
|
+
if (!excerpt) break;
|
|
83
|
+
rows.push(Object.freeze({ ref: `file:${path.relative(cwd, file)}`, chars: excerpt.length, content: excerpt }));
|
|
84
|
+
chars += excerpt.length;
|
|
85
|
+
if (chars >= maxChars) break;
|
|
86
|
+
}
|
|
87
|
+
return Object.freeze(rows);
|
|
88
|
+
}
|
|
89
|
+
|
|
90
|
+
export function buildCloudflareCpuAuditPacket(input = {}) {
|
|
91
|
+
const cwd = path.resolve(input.cwd || process.cwd());
|
|
92
|
+
const profile = input.profile ? summarizeCloudflareCpuProfile(input.profile, input) : summarizeCloudflareCpuProfileFile({ ...input, cwd });
|
|
93
|
+
return Object.freeze({
|
|
94
|
+
schema_version: 1,
|
|
95
|
+
primitive: 'cloudflare.cpu.audit',
|
|
96
|
+
rules: Object.freeze({ read_only: true, may_edit: false, may_deploy: false, production_timer_cpu_measurement_valid: false }),
|
|
97
|
+
profile,
|
|
98
|
+
source_evidence: sourceItems(cwd, input.sources || [], Number(input.maxSourceChars || 24_000)),
|
|
99
|
+
questions: Object.freeze([
|
|
100
|
+
'Which frames dominate self CPU time?',
|
|
101
|
+
'Is garbage collection material?',
|
|
102
|
+
'Which source changes are most likely to reduce CPU without changing behavior?',
|
|
103
|
+
'What local production-like request should reproduce the hotspot?',
|
|
104
|
+
'What production metric/log evidence should confirm improvement?',
|
|
105
|
+
]),
|
|
106
|
+
});
|
|
107
|
+
}
|
|
108
|
+
|
|
109
|
+
export async function runCloudflareCpuAudit(input = {}) {
|
|
110
|
+
if (typeof input.reasoner !== 'function') throw new TypeError('cloudflare.cpu.audit requires an injected reasoner(packet) function');
|
|
111
|
+
const packet = buildCloudflareCpuAuditPacket(input);
|
|
112
|
+
const result = await input.reasoner(structuredClone(packet));
|
|
113
|
+
if (!result || typeof result !== 'object' || Array.isArray(result)) throw new TypeError('cloudflare.cpu.audit reasoner must return an object');
|
|
114
|
+
return Object.freeze({ schema_version: 1, primitive: 'cloudflare.cpu.audit', profile: packet.profile, analysis: result });
|
|
115
|
+
}
|
|
@@ -0,0 +1,14 @@
|
|
|
1
|
+
export {
|
|
2
|
+
WRANGLER_NATIVE_COMMANDS,
|
|
3
|
+
WRANGLER_OPERATION_FAMILIES,
|
|
4
|
+
buildWranglerInvocation,
|
|
5
|
+
listWranglerNativeCommands,
|
|
6
|
+
parseWranglerErrorEvidence,
|
|
7
|
+
runWranglerNative,
|
|
8
|
+
} from './wrangler.js';
|
|
9
|
+
export {
|
|
10
|
+
summarizeCloudflareCpuProfile,
|
|
11
|
+
summarizeCloudflareCpuProfileFile,
|
|
12
|
+
buildCloudflareCpuAuditPacket,
|
|
13
|
+
runCloudflareCpuAudit,
|
|
14
|
+
} from './cpu-profile.js';
|
|
@@ -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
|
+
}
|