@agentworkforce/cli 3.0.3 → 3.0.5
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/CHANGELOG.md +16 -0
- package/README.md +6 -0
- package/dist/cli.d.ts.map +1 -1
- package/dist/cli.js +56 -9
- package/dist/cli.js.map +1 -1
- package/dist/deploy-command.d.ts +15 -1
- package/dist/deploy-command.d.ts.map +1 -1
- package/dist/deploy-command.js +217 -20
- package/dist/deploy-command.js.map +1 -1
- package/dist/deploy-command.test.js +136 -3
- package/dist/deploy-command.test.js.map +1 -1
- package/dist/destroy-command.d.ts +19 -0
- package/dist/destroy-command.d.ts.map +1 -0
- package/dist/destroy-command.js +288 -0
- package/dist/destroy-command.js.map +1 -0
- package/dist/destroy-command.test.d.ts +2 -0
- package/dist/destroy-command.test.d.ts.map +1 -0
- package/dist/destroy-command.test.js +312 -0
- package/dist/destroy-command.test.js.map +1 -0
- package/dist/list-command.d.ts +23 -0
- package/dist/list-command.d.ts.map +1 -0
- package/dist/list-command.js +228 -0
- package/dist/list-command.js.map +1 -0
- package/dist/list-command.test.d.ts +2 -0
- package/dist/list-command.test.d.ts.map +1 -0
- package/dist/list-command.test.js +42 -0
- package/dist/list-command.test.js.map +1 -0
- package/dist/runtime-picker.d.ts +8 -0
- package/dist/runtime-picker.d.ts.map +1 -0
- package/dist/runtime-picker.js +35 -0
- package/dist/runtime-picker.js.map +1 -0
- package/dist/runtime-picker.test.d.ts +2 -0
- package/dist/runtime-picker.test.d.ts.map +1 -0
- package/dist/runtime-picker.test.js +27 -0
- package/dist/runtime-picker.test.js.map +1 -0
- package/package.json +5 -4
|
@@ -0,0 +1,288 @@
|
|
|
1
|
+
import { readFile, stat } from 'node:fs/promises';
|
|
2
|
+
import path from 'node:path';
|
|
3
|
+
import { createTerminalIO, resolveWorkspaceToken } from '@agentworkforce/deploy';
|
|
4
|
+
const DEFAULT_CLOUD_URL = 'https://agentrelay.com';
|
|
5
|
+
const USER_AGENT = 'agentworkforce-cli/destroy';
|
|
6
|
+
// UUID v1-v5, what the cloud agents.id column emits.
|
|
7
|
+
const UUID_RE = /^[0-9a-f]{8}-[0-9a-f]{4}-[1-5][0-9a-f]{3}-[89ab][0-9a-f]{3}-[0-9a-f]{12}$/i;
|
|
8
|
+
/**
|
|
9
|
+
* Internal sentinel error: lets `executeDestroy` choose a specific exit
|
|
10
|
+
* code (1 = generic error, 2 = not-found / already-destroyed) without
|
|
11
|
+
* calling `process.exit` directly inside helpers — which would clash
|
|
12
|
+
* with test traps that turn `exit` into a throw.
|
|
13
|
+
*/
|
|
14
|
+
class DestroyExit extends Error {
|
|
15
|
+
exitCode;
|
|
16
|
+
userMessage;
|
|
17
|
+
constructor(exitCode, userMessage) {
|
|
18
|
+
super(userMessage);
|
|
19
|
+
this.exitCode = exitCode;
|
|
20
|
+
this.userMessage = userMessage;
|
|
21
|
+
this.name = 'DestroyExit';
|
|
22
|
+
}
|
|
23
|
+
}
|
|
24
|
+
/**
|
|
25
|
+
* Argv parser + dispatcher for `agentworkforce destroy <persona-or-agent-id> [flags]`.
|
|
26
|
+
* Mirrors the shape of runDeploy so cli.ts stays slim — destroy is a single
|
|
27
|
+
* remote DELETE plus user-friendly resolution from persona file -> agentId.
|
|
28
|
+
*/
|
|
29
|
+
export async function runDestroy(args) {
|
|
30
|
+
if (args.length === 0 || args[0] === '-h' || args[0] === '--help') {
|
|
31
|
+
process.stdout.write(DESTROY_USAGE);
|
|
32
|
+
process.exit(args.length === 0 ? 1 : 0);
|
|
33
|
+
}
|
|
34
|
+
const parsed = parseDestroyArgs(args);
|
|
35
|
+
let exitCode = 0;
|
|
36
|
+
try {
|
|
37
|
+
await executeDestroy(parsed);
|
|
38
|
+
}
|
|
39
|
+
catch (err) {
|
|
40
|
+
if (err instanceof DestroyExit) {
|
|
41
|
+
if (err.userMessage) {
|
|
42
|
+
process.stderr.write(err.userMessage);
|
|
43
|
+
}
|
|
44
|
+
exitCode = err.exitCode;
|
|
45
|
+
}
|
|
46
|
+
else {
|
|
47
|
+
process.stderr.write(`\nagentworkforce destroy failed: ${err instanceof Error ? err.message : String(err)}\n`);
|
|
48
|
+
exitCode = 1;
|
|
49
|
+
}
|
|
50
|
+
}
|
|
51
|
+
process.exit(exitCode);
|
|
52
|
+
}
|
|
53
|
+
async function executeDestroy(opts) {
|
|
54
|
+
const workspace = (opts.workspace ?? process.env.WORKFORCE_WORKSPACE_ID ?? '').trim();
|
|
55
|
+
if (!workspace) {
|
|
56
|
+
throw new DestroyExit(1, '\nagentworkforce destroy failed: no workspace resolved: pass --workspace or set WORKFORCE_WORKSPACE_ID\n');
|
|
57
|
+
}
|
|
58
|
+
const cloudUrl = normalizeCloudUrl(opts.cloudUrl ??
|
|
59
|
+
process.env.WORKFORCE_DEPLOY_CLOUD_URL ??
|
|
60
|
+
process.env.WORKFORCE_CLOUD_URL ??
|
|
61
|
+
DEFAULT_CLOUD_URL);
|
|
62
|
+
const io = createTerminalIO();
|
|
63
|
+
const { token } = await resolveWorkspaceToken({
|
|
64
|
+
workspace,
|
|
65
|
+
cloudUrl,
|
|
66
|
+
io,
|
|
67
|
+
...(opts.noPrompt ? { noPrompt: true } : {})
|
|
68
|
+
});
|
|
69
|
+
const agentId = await resolveAgentId({
|
|
70
|
+
target: opts.target,
|
|
71
|
+
cloudUrl,
|
|
72
|
+
workspace,
|
|
73
|
+
token
|
|
74
|
+
});
|
|
75
|
+
const url = `${cloudUrl}/api/v1/workspaces/${encodeURIComponent(workspace)}/deployments/${encodeURIComponent(agentId)}`;
|
|
76
|
+
const res = await fetch(url, {
|
|
77
|
+
method: 'DELETE',
|
|
78
|
+
headers: {
|
|
79
|
+
authorization: `Bearer ${token}`,
|
|
80
|
+
'user-agent': USER_AGENT
|
|
81
|
+
}
|
|
82
|
+
});
|
|
83
|
+
if (res.status === 401) {
|
|
84
|
+
throw new DestroyExit(1, '\nagentworkforce destroy failed: unauthorized. Run `agentworkforce login` and retry.\n');
|
|
85
|
+
}
|
|
86
|
+
if (res.status === 404) {
|
|
87
|
+
// Exit 2 is the documented "not found / already destroyed" signal so
|
|
88
|
+
// scripts can distinguish it from a generic 1.
|
|
89
|
+
throw new DestroyExit(2, `\nagent not found or already destroyed: ${agentId}\n`);
|
|
90
|
+
}
|
|
91
|
+
if (!res.ok) {
|
|
92
|
+
throw new DestroyExit(1, `\nagentworkforce destroy failed: ${res.status} ${await responseExcerpt(res)}\n`);
|
|
93
|
+
}
|
|
94
|
+
const body = (await res.json().catch(() => null));
|
|
95
|
+
if (!body || body.status !== 'destroyed' || typeof body.agentId !== 'string') {
|
|
96
|
+
throw new DestroyExit(1, '\nagentworkforce destroy failed: server returned an unexpected response shape\n');
|
|
97
|
+
}
|
|
98
|
+
const count = Array.isArray(body.cancelledScheduleIds) ? body.cancelledScheduleIds.length : 0;
|
|
99
|
+
process.stdout.write(`destroyed: ${body.agentId}\ncancelled schedules: ${count}\n`);
|
|
100
|
+
}
|
|
101
|
+
async function resolveAgentId(args) {
|
|
102
|
+
if (UUID_RE.test(args.target)) {
|
|
103
|
+
return args.target;
|
|
104
|
+
}
|
|
105
|
+
const looksLikePersonaFile = args.target.endsWith('.json') || (await pathExists(args.target));
|
|
106
|
+
if (!looksLikePersonaFile) {
|
|
107
|
+
// Neither a UUID nor an obvious persona path — accept as-is so callers
|
|
108
|
+
// can pass deterministic slugs the server understands, but it will most
|
|
109
|
+
// likely 404 below and surface a clean error.
|
|
110
|
+
return args.target;
|
|
111
|
+
}
|
|
112
|
+
const absPath = path.resolve(args.target);
|
|
113
|
+
const raw = await readFile(absPath, 'utf8').catch((err) => {
|
|
114
|
+
if (err.code === 'ENOENT') {
|
|
115
|
+
throw new Error(`persona JSON not found at ${absPath}`);
|
|
116
|
+
}
|
|
117
|
+
throw err;
|
|
118
|
+
});
|
|
119
|
+
let parsed;
|
|
120
|
+
try {
|
|
121
|
+
parsed = JSON.parse(raw);
|
|
122
|
+
}
|
|
123
|
+
catch (err) {
|
|
124
|
+
throw new Error(`persona JSON at ${absPath} is not valid JSON: ${err instanceof Error ? err.message : String(err)}`);
|
|
125
|
+
}
|
|
126
|
+
if (typeof parsed !== 'object' || parsed === null) {
|
|
127
|
+
throw new Error(`persona JSON at ${absPath} must be a top-level object`);
|
|
128
|
+
}
|
|
129
|
+
const slug = parsed.slug;
|
|
130
|
+
const id = parsed.id;
|
|
131
|
+
const lookupSlug = typeof slug === 'string' && slug.trim()
|
|
132
|
+
? slug.trim()
|
|
133
|
+
: typeof id === 'string' && id.trim()
|
|
134
|
+
? id.trim()
|
|
135
|
+
: null;
|
|
136
|
+
if (!lookupSlug) {
|
|
137
|
+
throw new Error(`persona JSON at ${absPath} is missing "id" / "slug"`);
|
|
138
|
+
}
|
|
139
|
+
const url = `${args.cloudUrl}/api/v1/workspaces/${encodeURIComponent(args.workspace)}/agents?persona_slug=${encodeURIComponent(lookupSlug)}`;
|
|
140
|
+
const res = await fetch(url, {
|
|
141
|
+
method: 'GET',
|
|
142
|
+
headers: {
|
|
143
|
+
authorization: `Bearer ${args.token}`,
|
|
144
|
+
'user-agent': USER_AGENT
|
|
145
|
+
}
|
|
146
|
+
});
|
|
147
|
+
if (res.status === 401) {
|
|
148
|
+
throw new Error('unauthorized while looking up the deployed agent: run `agentworkforce login` and retry');
|
|
149
|
+
}
|
|
150
|
+
// 404/405 here means the server doesn't have a deployed agent for this
|
|
151
|
+
// persona — surface as the same exit-2 signal we use for explicit
|
|
152
|
+
// already-destroyed targets.
|
|
153
|
+
if (res.status === 404 || res.status === 405) {
|
|
154
|
+
throw new DestroyExit(2, `\nno deployed agent found for persona "${lookupSlug}"\n`);
|
|
155
|
+
}
|
|
156
|
+
if (!res.ok) {
|
|
157
|
+
throw new Error(`agent lookup failed: ${res.status} ${await responseExcerpt(res)}; pass the agent UUID directly`);
|
|
158
|
+
}
|
|
159
|
+
const body = (await res.json().catch(() => null));
|
|
160
|
+
const resolved = extractAgentId(body);
|
|
161
|
+
if (!resolved) {
|
|
162
|
+
throw new Error(`agent lookup for "${lookupSlug}" returned no agent id; pass the agent UUID directly`);
|
|
163
|
+
}
|
|
164
|
+
return resolved;
|
|
165
|
+
}
|
|
166
|
+
function extractAgentId(body) {
|
|
167
|
+
if (!body)
|
|
168
|
+
return null;
|
|
169
|
+
if (typeof body.id === 'string' && body.id.trim())
|
|
170
|
+
return body.id.trim();
|
|
171
|
+
if (body.agent && typeof body.agent.id === 'string' && body.agent.id.trim()) {
|
|
172
|
+
return body.agent.id.trim();
|
|
173
|
+
}
|
|
174
|
+
if (Array.isArray(body.agents)) {
|
|
175
|
+
for (const candidate of body.agents) {
|
|
176
|
+
if (candidate && typeof candidate.id === 'string' && candidate.id.trim()) {
|
|
177
|
+
return candidate.id.trim();
|
|
178
|
+
}
|
|
179
|
+
}
|
|
180
|
+
}
|
|
181
|
+
return null;
|
|
182
|
+
}
|
|
183
|
+
async function pathExists(target) {
|
|
184
|
+
try {
|
|
185
|
+
const stats = await stat(path.resolve(target));
|
|
186
|
+
return stats.isFile();
|
|
187
|
+
}
|
|
188
|
+
catch {
|
|
189
|
+
return false;
|
|
190
|
+
}
|
|
191
|
+
}
|
|
192
|
+
async function responseExcerpt(res) {
|
|
193
|
+
try {
|
|
194
|
+
const text = (await res.text()).trim();
|
|
195
|
+
return text.length > 200 ? `${text.slice(0, 200)}…` : text;
|
|
196
|
+
}
|
|
197
|
+
catch {
|
|
198
|
+
return '';
|
|
199
|
+
}
|
|
200
|
+
}
|
|
201
|
+
function normalizeCloudUrl(url) {
|
|
202
|
+
const trimmed = url.trim();
|
|
203
|
+
return trimmed ? trimmed.replace(/\/+$/, '') : DEFAULT_CLOUD_URL;
|
|
204
|
+
}
|
|
205
|
+
export const DESTROY_USAGE = `usage: agentworkforce destroy <persona-or-agent-id> [flags]
|
|
206
|
+
|
|
207
|
+
Tear down a deployed agent: cancel all relaycron schedules and mark the
|
|
208
|
+
agent as destroyed in the workspace. Accepts either a persona JSON path
|
|
209
|
+
(slug/id is resolved via the workspace's agents index) or a literal agent
|
|
210
|
+
UUID.
|
|
211
|
+
|
|
212
|
+
Flags:
|
|
213
|
+
--workspace <id> Workforce workspace; defaults to WORKFORCE_WORKSPACE_ID
|
|
214
|
+
--cloud-url <url> Override the workforce cloud base URL
|
|
215
|
+
--no-prompt Fail instead of opening the browser to log in
|
|
216
|
+
-h, --help Print this message
|
|
217
|
+
|
|
218
|
+
Exit codes:
|
|
219
|
+
0 destroyed
|
|
220
|
+
2 agent not found or already destroyed
|
|
221
|
+
1 any other error
|
|
222
|
+
`;
|
|
223
|
+
export function parseDestroyArgs(args) {
|
|
224
|
+
let target;
|
|
225
|
+
let workspace;
|
|
226
|
+
let cloudUrl;
|
|
227
|
+
let noPrompt = false;
|
|
228
|
+
for (let i = 0; i < args.length; i += 1) {
|
|
229
|
+
const a = args[i];
|
|
230
|
+
if (a === '-h' || a === '--help') {
|
|
231
|
+
process.stdout.write(DESTROY_USAGE);
|
|
232
|
+
process.exit(0);
|
|
233
|
+
}
|
|
234
|
+
else if (a === '--workspace') {
|
|
235
|
+
workspace = expectValue('--workspace', args[++i]);
|
|
236
|
+
}
|
|
237
|
+
else if (a.startsWith('--workspace=')) {
|
|
238
|
+
workspace = expectInlineValue('--workspace', a.slice('--workspace='.length));
|
|
239
|
+
}
|
|
240
|
+
else if (a === '--cloud-url') {
|
|
241
|
+
cloudUrl = expectValue('--cloud-url', args[++i]);
|
|
242
|
+
}
|
|
243
|
+
else if (a.startsWith('--cloud-url=')) {
|
|
244
|
+
cloudUrl = expectInlineValue('--cloud-url', a.slice('--cloud-url='.length));
|
|
245
|
+
}
|
|
246
|
+
else if (a === '--no-prompt') {
|
|
247
|
+
noPrompt = true;
|
|
248
|
+
}
|
|
249
|
+
else if (a.startsWith('--')) {
|
|
250
|
+
die(`destroy: unknown flag "${a}"`);
|
|
251
|
+
}
|
|
252
|
+
else if (!target) {
|
|
253
|
+
target = a;
|
|
254
|
+
}
|
|
255
|
+
else {
|
|
256
|
+
die(`destroy: unexpected positional argument "${a}"`);
|
|
257
|
+
}
|
|
258
|
+
}
|
|
259
|
+
if (!target) {
|
|
260
|
+
die('destroy: missing persona path or agent id. Usage: agentworkforce destroy <persona-or-agent-id>');
|
|
261
|
+
}
|
|
262
|
+
return {
|
|
263
|
+
target,
|
|
264
|
+
...(workspace ? { workspace } : {}),
|
|
265
|
+
...(cloudUrl ? { cloudUrl } : {}),
|
|
266
|
+
...(noPrompt ? { noPrompt: true } : {})
|
|
267
|
+
};
|
|
268
|
+
}
|
|
269
|
+
function expectValue(flag, value) {
|
|
270
|
+
if (typeof value !== 'string' || !value.trim()) {
|
|
271
|
+
die(`${flag}: missing value`);
|
|
272
|
+
}
|
|
273
|
+
if (value.startsWith('-')) {
|
|
274
|
+
die(`${flag}: missing value (got "${value}", which looks like a flag)`);
|
|
275
|
+
}
|
|
276
|
+
return value;
|
|
277
|
+
}
|
|
278
|
+
function expectInlineValue(flag, value) {
|
|
279
|
+
if (!value.trim()) {
|
|
280
|
+
die(`${flag}: missing value`);
|
|
281
|
+
}
|
|
282
|
+
return value;
|
|
283
|
+
}
|
|
284
|
+
function die(message) {
|
|
285
|
+
process.stderr.write(`${message}\n`);
|
|
286
|
+
process.exit(1);
|
|
287
|
+
}
|
|
288
|
+
//# sourceMappingURL=destroy-command.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"destroy-command.js","sourceRoot":"","sources":["../src/destroy-command.ts"],"names":[],"mappings":"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"}
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"destroy-command.test.d.ts","sourceRoot":"","sources":["../src/destroy-command.test.ts"],"names":[],"mappings":""}
|
|
@@ -0,0 +1,312 @@
|
|
|
1
|
+
import test from 'node:test';
|
|
2
|
+
import assert from 'node:assert/strict';
|
|
3
|
+
import { mkdtemp, writeFile, rm } from 'node:fs/promises';
|
|
4
|
+
import os from 'node:os';
|
|
5
|
+
import path from 'node:path';
|
|
6
|
+
import { parseDestroyArgs, runDestroy } from './destroy-command.js';
|
|
7
|
+
function trapIO() {
|
|
8
|
+
const trap = {
|
|
9
|
+
exits: [],
|
|
10
|
+
stderr: '',
|
|
11
|
+
stdout: '',
|
|
12
|
+
restore: () => {
|
|
13
|
+
/* replaced below */
|
|
14
|
+
}
|
|
15
|
+
};
|
|
16
|
+
const origExit = process.exit;
|
|
17
|
+
const origErr = process.stderr.write.bind(process.stderr);
|
|
18
|
+
const origOut = process.stdout.write.bind(process.stdout);
|
|
19
|
+
const fakeExit = ((code) => {
|
|
20
|
+
trap.exits.push(code ?? 0);
|
|
21
|
+
throw new Error(`__exit_trap__:${code ?? 0}`);
|
|
22
|
+
});
|
|
23
|
+
process.exit = fakeExit;
|
|
24
|
+
process.stderr.write = ((chunk) => {
|
|
25
|
+
trap.stderr += typeof chunk === 'string' ? chunk : chunk.toString();
|
|
26
|
+
return true;
|
|
27
|
+
});
|
|
28
|
+
process.stdout.write = ((chunk) => {
|
|
29
|
+
trap.stdout += typeof chunk === 'string' ? chunk : chunk.toString();
|
|
30
|
+
return true;
|
|
31
|
+
});
|
|
32
|
+
trap.restore = () => {
|
|
33
|
+
process.exit = origExit;
|
|
34
|
+
process.stderr.write = origErr;
|
|
35
|
+
process.stdout.write = origOut;
|
|
36
|
+
};
|
|
37
|
+
return trap;
|
|
38
|
+
}
|
|
39
|
+
function trapFetch(handler) {
|
|
40
|
+
const calls = [];
|
|
41
|
+
const orig = globalThis.fetch;
|
|
42
|
+
globalThis.fetch = (async (input, init) => {
|
|
43
|
+
const url = typeof input === 'string' ? input : input.toString();
|
|
44
|
+
const call = { url, init };
|
|
45
|
+
calls.push(call);
|
|
46
|
+
return await handler(call);
|
|
47
|
+
});
|
|
48
|
+
return {
|
|
49
|
+
calls,
|
|
50
|
+
restore: () => {
|
|
51
|
+
globalThis.fetch = orig;
|
|
52
|
+
}
|
|
53
|
+
};
|
|
54
|
+
}
|
|
55
|
+
function withTokenEnv(token, workspace) {
|
|
56
|
+
const prevToken = process.env.WORKFORCE_WORKSPACE_TOKEN;
|
|
57
|
+
const prevWs = process.env.WORKFORCE_WORKSPACE_ID;
|
|
58
|
+
const prevCloudA = process.env.WORKFORCE_DEPLOY_CLOUD_URL;
|
|
59
|
+
const prevCloudB = process.env.WORKFORCE_CLOUD_URL;
|
|
60
|
+
process.env.WORKFORCE_WORKSPACE_TOKEN = token;
|
|
61
|
+
process.env.WORKFORCE_WORKSPACE_ID = workspace;
|
|
62
|
+
delete process.env.WORKFORCE_DEPLOY_CLOUD_URL;
|
|
63
|
+
delete process.env.WORKFORCE_CLOUD_URL;
|
|
64
|
+
return () => {
|
|
65
|
+
if (prevToken === undefined)
|
|
66
|
+
delete process.env.WORKFORCE_WORKSPACE_TOKEN;
|
|
67
|
+
else
|
|
68
|
+
process.env.WORKFORCE_WORKSPACE_TOKEN = prevToken;
|
|
69
|
+
if (prevWs === undefined)
|
|
70
|
+
delete process.env.WORKFORCE_WORKSPACE_ID;
|
|
71
|
+
else
|
|
72
|
+
process.env.WORKFORCE_WORKSPACE_ID = prevWs;
|
|
73
|
+
if (prevCloudA !== undefined)
|
|
74
|
+
process.env.WORKFORCE_DEPLOY_CLOUD_URL = prevCloudA;
|
|
75
|
+
if (prevCloudB !== undefined)
|
|
76
|
+
process.env.WORKFORCE_CLOUD_URL = prevCloudB;
|
|
77
|
+
};
|
|
78
|
+
}
|
|
79
|
+
const AGENT_UUID = '11111111-2222-4333-8444-555555555555';
|
|
80
|
+
const WORKSPACE = 'ws-test';
|
|
81
|
+
const CLOUD = 'https://cloud.example.test';
|
|
82
|
+
test('parseDestroyArgs: positional agent uuid only', () => {
|
|
83
|
+
const parsed = parseDestroyArgs([AGENT_UUID]);
|
|
84
|
+
assert.equal(parsed.target, AGENT_UUID);
|
|
85
|
+
assert.equal(parsed.workspace, undefined);
|
|
86
|
+
assert.equal(parsed.cloudUrl, undefined);
|
|
87
|
+
assert.equal(parsed.noPrompt, undefined);
|
|
88
|
+
});
|
|
89
|
+
test('parseDestroyArgs: persona path positional + flags', () => {
|
|
90
|
+
const parsed = parseDestroyArgs([
|
|
91
|
+
'./weekly.json',
|
|
92
|
+
'--workspace',
|
|
93
|
+
'ws-1',
|
|
94
|
+
'--cloud-url=https://c.test',
|
|
95
|
+
'--no-prompt'
|
|
96
|
+
]);
|
|
97
|
+
assert.equal(parsed.target, './weekly.json');
|
|
98
|
+
assert.equal(parsed.workspace, 'ws-1');
|
|
99
|
+
assert.equal(parsed.cloudUrl, 'https://c.test');
|
|
100
|
+
assert.equal(parsed.noPrompt, true);
|
|
101
|
+
});
|
|
102
|
+
test('parseDestroyArgs: missing positional exits 1', () => {
|
|
103
|
+
const trap = trapIO();
|
|
104
|
+
try {
|
|
105
|
+
assert.throws(() => parseDestroyArgs(['--workspace', 'ws-1']), /__exit_trap__:1/);
|
|
106
|
+
assert.deepEqual(trap.exits, [1]);
|
|
107
|
+
assert.match(trap.stderr, /missing persona path or agent id/);
|
|
108
|
+
}
|
|
109
|
+
finally {
|
|
110
|
+
trap.restore();
|
|
111
|
+
}
|
|
112
|
+
});
|
|
113
|
+
test('parseDestroyArgs: unknown flag exits 1', () => {
|
|
114
|
+
const trap = trapIO();
|
|
115
|
+
try {
|
|
116
|
+
assert.throws(() => parseDestroyArgs([AGENT_UUID, '--bogus']), /__exit_trap__:1/);
|
|
117
|
+
assert.match(trap.stderr, /unknown flag "--bogus"/);
|
|
118
|
+
}
|
|
119
|
+
finally {
|
|
120
|
+
trap.restore();
|
|
121
|
+
}
|
|
122
|
+
});
|
|
123
|
+
test('runDestroy: happy path with agent UUID positional', async () => {
|
|
124
|
+
const restoreEnv = withTokenEnv('tok-1', WORKSPACE);
|
|
125
|
+
const fetchTrap = trapFetch(async (call) => {
|
|
126
|
+
assert.equal(call.url, `${CLOUD}/api/v1/workspaces/${WORKSPACE}/deployments/${AGENT_UUID}`);
|
|
127
|
+
assert.equal(call.init?.method, 'DELETE');
|
|
128
|
+
assert.equal(call.init?.headers?.authorization, 'Bearer tok-1');
|
|
129
|
+
return new Response(JSON.stringify({
|
|
130
|
+
agentId: AGENT_UUID,
|
|
131
|
+
status: 'destroyed',
|
|
132
|
+
destroyedAt: '2026-05-13T00:00:00.000Z',
|
|
133
|
+
cancelledScheduleIds: ['sched_a', 'sched_b']
|
|
134
|
+
}), { status: 200, headers: { 'content-type': 'application/json' } });
|
|
135
|
+
});
|
|
136
|
+
const trap = trapIO();
|
|
137
|
+
try {
|
|
138
|
+
await assert.rejects(runDestroy([AGENT_UUID, '--cloud-url', CLOUD]), /__exit_trap__:0/);
|
|
139
|
+
assert.deepEqual(trap.exits, [0]);
|
|
140
|
+
assert.match(trap.stdout, new RegExp(`destroyed: ${AGENT_UUID}`));
|
|
141
|
+
assert.match(trap.stdout, /cancelled schedules: 2/);
|
|
142
|
+
assert.equal(fetchTrap.calls.length, 1);
|
|
143
|
+
}
|
|
144
|
+
finally {
|
|
145
|
+
trap.restore();
|
|
146
|
+
fetchTrap.restore();
|
|
147
|
+
restoreEnv();
|
|
148
|
+
}
|
|
149
|
+
});
|
|
150
|
+
test('runDestroy: 404 maps to exit 2 (not-found / already destroyed)', async () => {
|
|
151
|
+
const restoreEnv = withTokenEnv('tok-1', WORKSPACE);
|
|
152
|
+
const fetchTrap = trapFetch(async () => new Response(JSON.stringify({ error: 'Agent not found', code: 'agent_not_found' }), {
|
|
153
|
+
status: 404,
|
|
154
|
+
headers: { 'content-type': 'application/json' }
|
|
155
|
+
}));
|
|
156
|
+
const trap = trapIO();
|
|
157
|
+
try {
|
|
158
|
+
await assert.rejects(runDestroy([AGENT_UUID, '--cloud-url', CLOUD]), /__exit_trap__:2/);
|
|
159
|
+
assert.deepEqual(trap.exits, [2]);
|
|
160
|
+
assert.match(trap.stderr, /agent not found or already destroyed/);
|
|
161
|
+
}
|
|
162
|
+
finally {
|
|
163
|
+
trap.restore();
|
|
164
|
+
fetchTrap.restore();
|
|
165
|
+
restoreEnv();
|
|
166
|
+
}
|
|
167
|
+
});
|
|
168
|
+
test('runDestroy: 401 maps to exit 1 with a login hint', async () => {
|
|
169
|
+
const restoreEnv = withTokenEnv('tok-bad', WORKSPACE);
|
|
170
|
+
const fetchTrap = trapFetch(async () => new Response(JSON.stringify({ error: 'Unauthorized', code: 'unauthorized' }), {
|
|
171
|
+
status: 401,
|
|
172
|
+
headers: { 'content-type': 'application/json' }
|
|
173
|
+
}));
|
|
174
|
+
const trap = trapIO();
|
|
175
|
+
try {
|
|
176
|
+
await assert.rejects(runDestroy([AGENT_UUID, '--cloud-url', CLOUD]), /__exit_trap__:1/);
|
|
177
|
+
assert.deepEqual(trap.exits, [1]);
|
|
178
|
+
assert.match(trap.stderr, /unauthorized/i);
|
|
179
|
+
assert.match(trap.stderr, /workforce login/i);
|
|
180
|
+
}
|
|
181
|
+
finally {
|
|
182
|
+
trap.restore();
|
|
183
|
+
fetchTrap.restore();
|
|
184
|
+
restoreEnv();
|
|
185
|
+
}
|
|
186
|
+
});
|
|
187
|
+
test('runDestroy: missing workspace exits 1', async () => {
|
|
188
|
+
// No WORKFORCE_WORKSPACE_ID, no --workspace.
|
|
189
|
+
const prevToken = process.env.WORKFORCE_WORKSPACE_TOKEN;
|
|
190
|
+
const prevWs = process.env.WORKFORCE_WORKSPACE_ID;
|
|
191
|
+
process.env.WORKFORCE_WORKSPACE_TOKEN = 'tok-1';
|
|
192
|
+
delete process.env.WORKFORCE_WORKSPACE_ID;
|
|
193
|
+
const fetchTrap = trapFetch(async () => {
|
|
194
|
+
throw new Error('fetch must not be called when workspace is missing');
|
|
195
|
+
});
|
|
196
|
+
const trap = trapIO();
|
|
197
|
+
try {
|
|
198
|
+
await assert.rejects(runDestroy([AGENT_UUID]), /__exit_trap__:1/);
|
|
199
|
+
assert.deepEqual(trap.exits, [1]);
|
|
200
|
+
assert.match(trap.stderr, /no workspace resolved/);
|
|
201
|
+
assert.equal(fetchTrap.calls.length, 0);
|
|
202
|
+
}
|
|
203
|
+
finally {
|
|
204
|
+
trap.restore();
|
|
205
|
+
fetchTrap.restore();
|
|
206
|
+
if (prevToken === undefined)
|
|
207
|
+
delete process.env.WORKFORCE_WORKSPACE_TOKEN;
|
|
208
|
+
else
|
|
209
|
+
process.env.WORKFORCE_WORKSPACE_TOKEN = prevToken;
|
|
210
|
+
if (prevWs !== undefined)
|
|
211
|
+
process.env.WORKFORCE_WORKSPACE_ID = prevWs;
|
|
212
|
+
}
|
|
213
|
+
});
|
|
214
|
+
test('runDestroy: persona path resolves to agent id via /agents lookup', async () => {
|
|
215
|
+
const restoreEnv = withTokenEnv('tok-1', WORKSPACE);
|
|
216
|
+
const tmp = await mkdtemp(path.join(os.tmpdir(), 'aw-destroy-'));
|
|
217
|
+
const personaPath = path.join(tmp, 'weekly-digest.json');
|
|
218
|
+
await writeFile(personaPath, JSON.stringify({ id: 'weekly-digest', slug: 'weekly-digest', intent: 'review' }), 'utf8');
|
|
219
|
+
const fetchTrap = trapFetch(async (call) => {
|
|
220
|
+
if (call.url.includes('/agents?')) {
|
|
221
|
+
assert.equal(call.url, `${CLOUD}/api/v1/workspaces/${WORKSPACE}/agents?persona_slug=weekly-digest`);
|
|
222
|
+
assert.equal(call.init?.method, 'GET');
|
|
223
|
+
return new Response(JSON.stringify({ agent: { id: AGENT_UUID } }), {
|
|
224
|
+
status: 200,
|
|
225
|
+
headers: { 'content-type': 'application/json' }
|
|
226
|
+
});
|
|
227
|
+
}
|
|
228
|
+
assert.equal(call.url, `${CLOUD}/api/v1/workspaces/${WORKSPACE}/deployments/${AGENT_UUID}`);
|
|
229
|
+
assert.equal(call.init?.method, 'DELETE');
|
|
230
|
+
return new Response(JSON.stringify({
|
|
231
|
+
agentId: AGENT_UUID,
|
|
232
|
+
status: 'destroyed',
|
|
233
|
+
destroyedAt: '2026-05-13T00:00:00.000Z',
|
|
234
|
+
cancelledScheduleIds: []
|
|
235
|
+
}), { status: 200, headers: { 'content-type': 'application/json' } });
|
|
236
|
+
});
|
|
237
|
+
const trap = trapIO();
|
|
238
|
+
try {
|
|
239
|
+
await assert.rejects(runDestroy([personaPath, '--cloud-url', CLOUD]), /__exit_trap__:0/);
|
|
240
|
+
assert.deepEqual(trap.exits, [0]);
|
|
241
|
+
assert.match(trap.stdout, new RegExp(`destroyed: ${AGENT_UUID}`));
|
|
242
|
+
assert.match(trap.stdout, /cancelled schedules: 0/);
|
|
243
|
+
assert.equal(fetchTrap.calls.length, 2);
|
|
244
|
+
}
|
|
245
|
+
finally {
|
|
246
|
+
trap.restore();
|
|
247
|
+
fetchTrap.restore();
|
|
248
|
+
restoreEnv();
|
|
249
|
+
await rm(tmp, { recursive: true, force: true });
|
|
250
|
+
}
|
|
251
|
+
});
|
|
252
|
+
test('runDestroy: directory target is not treated as a persona file', async () => {
|
|
253
|
+
const restoreEnv = withTokenEnv('tok-1', WORKSPACE);
|
|
254
|
+
const tmp = await mkdtemp(path.join(os.tmpdir(), 'aw-destroy-dir-'));
|
|
255
|
+
const fetchTrap = trapFetch(async (call) => {
|
|
256
|
+
assert.equal(call.url, `${CLOUD}/api/v1/workspaces/${WORKSPACE}/deployments/${encodeURIComponent(tmp)}`);
|
|
257
|
+
assert.equal(call.init?.method, 'DELETE');
|
|
258
|
+
return new Response(JSON.stringify({
|
|
259
|
+
agentId: tmp,
|
|
260
|
+
status: 'destroyed',
|
|
261
|
+
destroyedAt: '2026-05-13T00:00:00.000Z',
|
|
262
|
+
cancelledScheduleIds: []
|
|
263
|
+
}), { status: 200, headers: { 'content-type': 'application/json' } });
|
|
264
|
+
});
|
|
265
|
+
const trap = trapIO();
|
|
266
|
+
try {
|
|
267
|
+
await assert.rejects(runDestroy([tmp, '--cloud-url', CLOUD]), /__exit_trap__:0/);
|
|
268
|
+
assert.deepEqual(trap.exits, [0]);
|
|
269
|
+
assert.equal(fetchTrap.calls.length, 1);
|
|
270
|
+
}
|
|
271
|
+
finally {
|
|
272
|
+
trap.restore();
|
|
273
|
+
fetchTrap.restore();
|
|
274
|
+
restoreEnv();
|
|
275
|
+
await rm(tmp, { recursive: true, force: true });
|
|
276
|
+
}
|
|
277
|
+
});
|
|
278
|
+
test('runDestroy: persona path with no deployed agent returns exit 2', async () => {
|
|
279
|
+
const restoreEnv = withTokenEnv('tok-1', WORKSPACE);
|
|
280
|
+
const tmp = await mkdtemp(path.join(os.tmpdir(), 'aw-destroy-'));
|
|
281
|
+
const personaPath = path.join(tmp, 'orphan.json');
|
|
282
|
+
await writeFile(personaPath, JSON.stringify({ id: 'orphan', slug: 'orphan', intent: 'review' }), 'utf8');
|
|
283
|
+
const fetchTrap = trapFetch(async () => new Response('', { status: 404 }));
|
|
284
|
+
const trap = trapIO();
|
|
285
|
+
try {
|
|
286
|
+
await assert.rejects(runDestroy([personaPath, '--cloud-url', CLOUD]), /__exit_trap__:2/);
|
|
287
|
+
assert.deepEqual(trap.exits, [2]);
|
|
288
|
+
assert.match(trap.stderr, /no deployed agent found for persona "orphan"/);
|
|
289
|
+
}
|
|
290
|
+
finally {
|
|
291
|
+
trap.restore();
|
|
292
|
+
fetchTrap.restore();
|
|
293
|
+
restoreEnv();
|
|
294
|
+
await rm(tmp, { recursive: true, force: true });
|
|
295
|
+
}
|
|
296
|
+
});
|
|
297
|
+
test('runDestroy: 5xx server error exits 1 and surfaces the status', async () => {
|
|
298
|
+
const restoreEnv = withTokenEnv('tok-1', WORKSPACE);
|
|
299
|
+
const fetchTrap = trapFetch(async () => new Response('boom', { status: 500 }));
|
|
300
|
+
const trap = trapIO();
|
|
301
|
+
try {
|
|
302
|
+
await assert.rejects(runDestroy([AGENT_UUID, '--cloud-url', CLOUD]), /__exit_trap__:1/);
|
|
303
|
+
assert.deepEqual(trap.exits, [1]);
|
|
304
|
+
assert.match(trap.stderr, /500/);
|
|
305
|
+
}
|
|
306
|
+
finally {
|
|
307
|
+
trap.restore();
|
|
308
|
+
fetchTrap.restore();
|
|
309
|
+
restoreEnv();
|
|
310
|
+
}
|
|
311
|
+
});
|
|
312
|
+
//# sourceMappingURL=destroy-command.test.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"destroy-command.test.js","sourceRoot":"","sources":["../src/destroy-command.test.ts"],"names":[],"mappings":"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"}
|