@getstackrun/cli 0.6.1 → 0.8.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.
Files changed (58) hide show
  1. package/dist/agent.d.ts.map +1 -1
  2. package/dist/agent.js +113 -3
  3. package/dist/agent.js.map +1 -1
  4. package/dist/api.d.ts +26 -0
  5. package/dist/api.d.ts.map +1 -0
  6. package/dist/api.js +90 -0
  7. package/dist/api.js.map +1 -0
  8. package/dist/audit.d.ts +2 -0
  9. package/dist/audit.d.ts.map +1 -0
  10. package/dist/audit.js +69 -0
  11. package/dist/audit.js.map +1 -0
  12. package/dist/detectors.d.ts +2 -0
  13. package/dist/detectors.d.ts.map +1 -0
  14. package/dist/detectors.js +104 -0
  15. package/dist/detectors.js.map +1 -0
  16. package/dist/dropoffs.d.ts +2 -0
  17. package/dist/dropoffs.d.ts.map +1 -0
  18. package/dist/dropoffs.js +140 -0
  19. package/dist/dropoffs.js.map +1 -0
  20. package/dist/events.d.ts +2 -0
  21. package/dist/events.d.ts.map +1 -0
  22. package/dist/events.js +77 -0
  23. package/dist/events.js.map +1 -0
  24. package/dist/format.d.ts +16 -0
  25. package/dist/format.d.ts.map +1 -0
  26. package/dist/format.js +77 -0
  27. package/dist/format.js.map +1 -0
  28. package/dist/identity.d.ts +2 -0
  29. package/dist/identity.d.ts.map +1 -0
  30. package/dist/identity.js +102 -0
  31. package/dist/identity.js.map +1 -0
  32. package/dist/index.js +130 -4
  33. package/dist/index.js.map +1 -1
  34. package/dist/me.d.ts +2 -0
  35. package/dist/me.d.ts.map +1 -0
  36. package/dist/me.js +11 -0
  37. package/dist/me.js.map +1 -0
  38. package/dist/notifications.d.ts +2 -0
  39. package/dist/notifications.d.ts.map +1 -0
  40. package/dist/notifications.js +179 -0
  41. package/dist/notifications.js.map +1 -0
  42. package/dist/passports.d.ts +2 -0
  43. package/dist/passports.d.ts.map +1 -0
  44. package/dist/passports.js +205 -0
  45. package/dist/passports.js.map +1 -0
  46. package/dist/services.d.ts +2 -0
  47. package/dist/services.d.ts.map +1 -0
  48. package/dist/services.js +167 -0
  49. package/dist/services.js.map +1 -0
  50. package/dist/skills.d.ts +2 -0
  51. package/dist/skills.d.ts.map +1 -0
  52. package/dist/skills.js +240 -0
  53. package/dist/skills.js.map +1 -0
  54. package/dist/team.d.ts +2 -0
  55. package/dist/team.d.ts.map +1 -0
  56. package/dist/team.js +86 -0
  57. package/dist/team.js.map +1 -0
  58. package/package.json +1 -1
@@ -0,0 +1,140 @@
1
+ // dropoffs subcommands.
2
+ //
3
+ // Drop-offs are point-to-point schema-validated handoffs between agents.
4
+ // Schema files passed via --schema must be a path to a JSON file; the
5
+ // CLI reads + parses it before POSTing.
6
+ import { stdout, stderr, exit } from 'node:process';
7
+ import { readFile } from 'node:fs/promises';
8
+ import { api, takeFlag } from './api.js';
9
+ import { invokeHint } from './auth.js';
10
+ import { printJson, printTable, printRecord, fmt, fmtTs } from './format.js';
11
+ async function readJsonFile(path) {
12
+ const raw = await readFile(path, 'utf8');
13
+ return JSON.parse(raw);
14
+ }
15
+ async function cmdList(json) {
16
+ const list = await api('GET', '/v1/dropoffs');
17
+ if (json)
18
+ return printJson(list);
19
+ if (list.length === 0) {
20
+ stdout.write('(no drop-offs)\n');
21
+ return;
22
+ }
23
+ const rows = list.map((d) => [d.id, d.from_agent_id, d.to_agent_id, statusBadge(d.status), fmtTs(d.created_at), fmtTs(d.expires_at)]);
24
+ printTable(['ID', 'FROM', 'TO', 'STATUS', 'CREATED', 'EXPIRES'], rows);
25
+ }
26
+ async function cmdShow(id, json) {
27
+ const out = await api('GET', `/v1/dropoffs/${encodeURIComponent(id)}`);
28
+ if (json)
29
+ return printJson(out);
30
+ printRecord(out);
31
+ }
32
+ async function cmdCreate(args, json) {
33
+ const from = takeFlag(args, '--from');
34
+ const to = takeFlag(args, '--to');
35
+ const schemaPath = takeFlag(args, '--schema');
36
+ const ttl = takeFlag(args, '--ttl');
37
+ const onExpire = takeFlag(args, '--on-expire');
38
+ if (typeof from !== 'string' || typeof to !== 'string' || typeof schemaPath !== 'string') {
39
+ stderr.write(`usage: ${invokeHint('dropoff create --from <agent-id> --to <agent-id> --schema <file.json> [--ttl <seconds>] [--on-expire notify|retry|fail]')}\n`);
40
+ exit(2);
41
+ }
42
+ const schema = await readJsonFile(schemaPath);
43
+ const body = {
44
+ from_agent_id: from,
45
+ to_agent_id: to,
46
+ schema,
47
+ };
48
+ if (typeof ttl === 'string')
49
+ body.ttl_seconds = parseInt(ttl, 10);
50
+ if (typeof onExpire === 'string')
51
+ body.on_expire = onExpire;
52
+ const out = await api('POST', '/v1/dropoffs', { body });
53
+ if (json)
54
+ return printJson(out);
55
+ stdout.write(`created ${out.id}\n from ${out.from_agent_id} → ${out.to_agent_id}\n expires ${fmtTs(out.expires_at)}\n`);
56
+ }
57
+ async function cmdDeposit(id, args, json) {
58
+ const agentId = takeFlag(args, '--agent');
59
+ const payloadPath = takeFlag(args, '--payload');
60
+ if (typeof agentId !== 'string' || typeof payloadPath !== 'string') {
61
+ stderr.write(`usage: ${invokeHint('dropoff deposit <id> --agent <agent-id> --payload <file.json>')}\n`);
62
+ exit(2);
63
+ }
64
+ const payload = await readJsonFile(payloadPath);
65
+ const out = await api('POST', `/v1/dropoffs/${encodeURIComponent(id)}/deposit`, {
66
+ body: { agent_id: agentId, payload },
67
+ });
68
+ if (json)
69
+ return printJson(out);
70
+ stdout.write(`deposited to ${id}\n`);
71
+ }
72
+ async function cmdCollect(id, args, json) {
73
+ const agentId = takeFlag(args, '--agent');
74
+ if (typeof agentId !== 'string') {
75
+ stderr.write(`usage: ${invokeHint('dropoff collect <id> --agent <agent-id>')}\n`);
76
+ exit(2);
77
+ }
78
+ const out = await api('POST', `/v1/dropoffs/${encodeURIComponent(id)}/collect`, {
79
+ body: { agent_id: agentId },
80
+ });
81
+ if (json)
82
+ return printJson(out);
83
+ stdout.write(JSON.stringify(out.payload, null, 2) + '\n');
84
+ }
85
+ async function cmdExpire(id, json) {
86
+ const out = await api('POST', `/v1/dropoffs/${encodeURIComponent(id)}/expire`);
87
+ if (json)
88
+ return printJson(out);
89
+ stdout.write(`expired ${id}\n`);
90
+ }
91
+ function statusBadge(s) {
92
+ if (s === 'collected')
93
+ return fmt.ok(s);
94
+ if (s === 'expired')
95
+ return fmt.dim(s);
96
+ if (s === 'deposited')
97
+ return fmt.warn(s);
98
+ return s;
99
+ }
100
+ export async function cmdDropoff(args) {
101
+ const json = !!takeFlag(args, '--json');
102
+ const sub = args[0];
103
+ const arg1 = args[1];
104
+ if (sub === 'list' || sub === 'ls')
105
+ return cmdList(json);
106
+ if (sub === 'show' || sub === 'status') {
107
+ if (!arg1) {
108
+ stderr.write(`usage: ${invokeHint('dropoff show <id>')}\n`);
109
+ exit(2);
110
+ }
111
+ return cmdShow(arg1, json);
112
+ }
113
+ if (sub === 'create')
114
+ return cmdCreate(args.slice(1), json);
115
+ if (sub === 'deposit') {
116
+ if (!arg1) {
117
+ stderr.write(`usage: ${invokeHint('dropoff deposit <id> --agent <agent-id> --payload <file.json>')}\n`);
118
+ exit(2);
119
+ }
120
+ return cmdDeposit(arg1, args.slice(2), json);
121
+ }
122
+ if (sub === 'collect') {
123
+ if (!arg1) {
124
+ stderr.write(`usage: ${invokeHint('dropoff collect <id> --agent <agent-id>')}\n`);
125
+ exit(2);
126
+ }
127
+ return cmdCollect(arg1, args.slice(2), json);
128
+ }
129
+ if (sub === 'expire') {
130
+ if (!arg1) {
131
+ stderr.write(`usage: ${invokeHint('dropoff expire <id>')}\n`);
132
+ exit(2);
133
+ }
134
+ return cmdExpire(arg1, json);
135
+ }
136
+ stderr.write(`error: unknown dropoff subcommand "${sub ?? ''}".\n` +
137
+ `Use list | show | create | deposit | collect | expire\n`);
138
+ exit(2);
139
+ }
140
+ //# sourceMappingURL=dropoffs.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"dropoffs.js","sourceRoot":"","sources":["../src/dropoffs.ts"],"names":[],"mappings":"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"}
@@ -0,0 +1,2 @@
1
+ export declare function cmdEvent(args: string[]): Promise<void>;
2
+ //# sourceMappingURL=events.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"events.d.ts","sourceRoot":"","sources":["../src/events.ts"],"names":[],"mappings":"AAgEA,wBAAsB,QAAQ,CAAC,IAAI,EAAE,MAAM,EAAE,GAAG,OAAO,CAAC,IAAI,CAAC,CAwB5D"}
package/dist/events.js ADDED
@@ -0,0 +1,77 @@
1
+ // security-events subcommands.
2
+ import { stdout, stderr, exit } from 'node:process';
3
+ import { api, takeFlag } from './api.js';
4
+ import { invokeHint } from './auth.js';
5
+ import { printJson, printTable, printRecord, fmt, fmtTs } from './format.js';
6
+ async function cmdList(args, json) {
7
+ const agentId = takeFlag(args, '--agent');
8
+ const limit = takeFlag(args, '--limit');
9
+ const out = await api('GET', '/v1/security-events', {
10
+ query: {
11
+ agent_id: typeof agentId === 'string' ? agentId : undefined,
12
+ limit: typeof limit === 'string' ? limit : undefined,
13
+ },
14
+ });
15
+ const list = Array.isArray(out) ? out : (out?.events ?? []);
16
+ if (json)
17
+ return printJson(list);
18
+ if (list.length === 0) {
19
+ stdout.write('(no security events)\n');
20
+ return;
21
+ }
22
+ const rows = list.map((e) => [
23
+ e.id,
24
+ severityBadge(e.severity),
25
+ e.signal_type,
26
+ e.agent_id ?? '—',
27
+ e.resolved ? fmt.ok('yes') : fmt.warn('no'),
28
+ fmtTs(e.created_at ?? null),
29
+ (e.message ?? '').slice(0, 60),
30
+ ]);
31
+ printTable(['ID', 'SEV', 'SIGNAL', 'AGENT', 'RESOLVED', 'CREATED', 'MESSAGE'], rows);
32
+ }
33
+ async function cmdShow(id, json) {
34
+ const out = await api('GET', `/v1/security-events/${encodeURIComponent(id)}`);
35
+ if (json)
36
+ return printJson(out);
37
+ printRecord(out);
38
+ }
39
+ async function cmdResolve(id, json) {
40
+ const out = await api('POST', `/v1/security-events/${encodeURIComponent(id)}/resolve`);
41
+ if (json)
42
+ return printJson(out);
43
+ stdout.write(`resolved ${id}\n`);
44
+ }
45
+ function severityBadge(s) {
46
+ if (s === 'critical')
47
+ return fmt.err(s);
48
+ if (s === 'warning')
49
+ return fmt.warn(s);
50
+ if (s === 'info')
51
+ return fmt.dim(s);
52
+ return s;
53
+ }
54
+ export async function cmdEvent(args) {
55
+ const json = !!takeFlag(args, '--json');
56
+ const sub = args[0];
57
+ const arg1 = args[1];
58
+ if (sub === 'list' || sub === 'ls')
59
+ return cmdList(args.slice(1), json);
60
+ if (sub === 'show' || sub === 'get') {
61
+ if (!arg1) {
62
+ stderr.write(`usage: ${invokeHint('event show <id>')}\n`);
63
+ exit(2);
64
+ }
65
+ return cmdShow(arg1, json);
66
+ }
67
+ if (sub === 'resolve') {
68
+ if (!arg1) {
69
+ stderr.write(`usage: ${invokeHint('event resolve <id>')}\n`);
70
+ exit(2);
71
+ }
72
+ return cmdResolve(arg1, json);
73
+ }
74
+ stderr.write(`error: unknown event subcommand "${sub ?? ''}".\nUse list | show | resolve\n`);
75
+ exit(2);
76
+ }
77
+ //# sourceMappingURL=events.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"events.js","sourceRoot":"","sources":["../src/events.ts"],"names":[],"mappings":"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"}
@@ -0,0 +1,16 @@
1
+ /** Print rows as an aligned table. Headers are bold/dim. */
2
+ export declare function printTable(headers: string[], rows: string[][]): void;
3
+ export declare function printJson(data: unknown): void;
4
+ /** Render a single record as label/value lines. */
5
+ export declare function printRecord(record: Record<string, unknown>): void;
6
+ /** Tone helpers for table cells. */
7
+ export declare const fmt: {
8
+ ok: (s: string) => string;
9
+ warn: (s: string) => string;
10
+ err: (s: string) => string;
11
+ dim: (s: string) => string;
12
+ bold: (s: string) => string;
13
+ };
14
+ /** Render a timestamp (ISO string or unix-ms) as a compact short form. */
15
+ export declare function fmtTs(ts: string | number | null | undefined): string;
16
+ //# sourceMappingURL=format.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"format.d.ts","sourceRoot":"","sources":["../src/format.ts"],"names":[],"mappings":"AAmBA,4DAA4D;AAC5D,wBAAgB,UAAU,CAAC,OAAO,EAAE,MAAM,EAAE,EAAE,IAAI,EAAE,MAAM,EAAE,EAAE,GAAG,IAAI,CAqBpE;AAMD,wBAAgB,SAAS,CAAC,IAAI,EAAE,OAAO,GAAG,IAAI,CAE7C;AAED,mDAAmD;AACnD,wBAAgB,WAAW,CAAC,MAAM,EAAE,MAAM,CAAC,MAAM,EAAE,OAAO,CAAC,GAAG,IAAI,CAUjE;AAED,oCAAoC;AACpC,eAAO,MAAM,GAAG;YACN,MAAM;cACJ,MAAM;aACP,MAAM;aACN,MAAM;cACL,MAAM;CACjB,CAAC;AAEF,0EAA0E;AAC1E,wBAAgB,KAAK,CAAC,EAAE,EAAE,MAAM,GAAG,MAAM,GAAG,IAAI,GAAG,SAAS,GAAG,MAAM,CASpE"}
package/dist/format.js ADDED
@@ -0,0 +1,77 @@
1
+ // Output formatting helpers — table for terminal humans, JSON for
2
+ // pipes + scripts. Every command supports `--json` to switch from
3
+ // the table to a machine-readable dump.
4
+ import { stdout, env } from 'node:process';
5
+ const useColor = stdout.isTTY === true && !env['NO_COLOR'];
6
+ const color = (n) => (useColor ? `\x1b[${n}m` : '');
7
+ const C = {
8
+ reset: color('0'),
9
+ bold: color('1'),
10
+ dim: color('2'),
11
+ gray: color('90'),
12
+ cyan: color('36'),
13
+ green: color('32'),
14
+ yellow: color('33'),
15
+ red: color('31'),
16
+ };
17
+ /** Print rows as an aligned table. Headers are bold/dim. */
18
+ export function printTable(headers, rows) {
19
+ if (rows.length === 0) {
20
+ stdout.write(`${C.gray}(no results)${C.reset}\n`);
21
+ return;
22
+ }
23
+ const widths = headers.map((h, i) => Math.max(h.length, ...rows.map((r) => stripAnsi(r[i] ?? '').length)));
24
+ const headerLine = headers.map((h, i) => `${C.dim}${C.bold}${h.padEnd(widths[i] ?? 0)}${C.reset}`).join(' ');
25
+ stdout.write(`${headerLine}\n`);
26
+ for (const row of rows) {
27
+ const line = row.map((cell, i) => {
28
+ const visibleLen = stripAnsi(cell ?? '').length;
29
+ const pad = ' '.repeat(Math.max(0, (widths[i] ?? 0) - visibleLen));
30
+ return `${cell ?? ''}${pad}`;
31
+ }).join(' ');
32
+ stdout.write(`${line}\n`);
33
+ }
34
+ }
35
+ function stripAnsi(s) {
36
+ return s.replace(/\x1b\[[0-9;]*m/g, '');
37
+ }
38
+ export function printJson(data) {
39
+ stdout.write(JSON.stringify(data, null, 2) + '\n');
40
+ }
41
+ /** Render a single record as label/value lines. */
42
+ export function printRecord(record) {
43
+ const labelWidth = Math.max(...Object.keys(record).map((k) => k.length));
44
+ for (const [k, v] of Object.entries(record)) {
45
+ const value = v === null || v === undefined
46
+ ? `${C.gray}—${C.reset}`
47
+ : typeof v === 'object'
48
+ ? JSON.stringify(v)
49
+ : String(v);
50
+ stdout.write(` ${C.gray}${k.padEnd(labelWidth)}${C.reset} ${value}\n`);
51
+ }
52
+ }
53
+ /** Tone helpers for table cells. */
54
+ export const fmt = {
55
+ ok: (s) => `${C.green}${s}${C.reset}`,
56
+ warn: (s) => `${C.yellow}${s}${C.reset}`,
57
+ err: (s) => `${C.red}${s}${C.reset}`,
58
+ dim: (s) => `${C.gray}${s}${C.reset}`,
59
+ bold: (s) => `${C.bold}${s}${C.reset}`,
60
+ };
61
+ /** Render a timestamp (ISO string or unix-ms) as a compact short form. */
62
+ export function fmtTs(ts) {
63
+ if (ts === null || ts === undefined)
64
+ return fmt.dim('—');
65
+ const d = typeof ts === 'number' ? new Date(ts) : new Date(ts);
66
+ if (Number.isNaN(d.getTime()))
67
+ return fmt.dim('—');
68
+ const now = new Date();
69
+ if (d.toDateString() === now.toDateString()) {
70
+ return `${pad(d.getHours())}:${pad(d.getMinutes())}`;
71
+ }
72
+ return `${d.toLocaleDateString('en-CA')}`;
73
+ }
74
+ function pad(n) {
75
+ return String(n).padStart(2, '0');
76
+ }
77
+ //# sourceMappingURL=format.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"format.js","sourceRoot":"","sources":["../src/format.ts"],"names":[],"mappings":"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"}
@@ -0,0 +1,2 @@
1
+ export declare function cmdIdentity(args: string[]): Promise<void>;
2
+ //# sourceMappingURL=identity.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"identity.d.ts","sourceRoot":"","sources":["../src/identity.ts"],"names":[],"mappings":"AA0FA,wBAAsB,WAAW,CAAC,IAAI,EAAE,MAAM,EAAE,GAAG,OAAO,CAAC,IAAI,CAAC,CAsB/D"}
@@ -0,0 +1,102 @@
1
+ // identity subcommands.
2
+ import { stdout, stderr, exit } from 'node:process';
3
+ import { api, takeFlag } from './api.js';
4
+ import { invokeHint } from './auth.js';
5
+ import { printJson, printTable, printRecord, fmt, fmtTs } from './format.js';
6
+ async function cmdSettings(json) {
7
+ const out = await api('GET', '/v1/operators/me/identity-settings');
8
+ if (json)
9
+ return printJson(out);
10
+ printRecord(out);
11
+ }
12
+ async function cmdUpdateSettings(args, json) {
13
+ const inheritance = takeFlag(args, '--inheritance');
14
+ const ttl = takeFlag(args, '--ttl');
15
+ const autoRevoke = takeFlag(args, '--auto-revoke');
16
+ const body = {};
17
+ if (typeof inheritance === 'string')
18
+ body.identity_claim_inheritance = inheritance;
19
+ if (typeof ttl === 'string')
20
+ body.identity_claim_ttl = ttl;
21
+ if (autoRevoke !== undefined)
22
+ body.identity_auto_revoke = autoRevoke === true || autoRevoke === 'true';
23
+ if (Object.keys(body).length === 0) {
24
+ stderr.write(`usage: ${invokeHint('identity update-settings [--inheritance auto|opt_in] [--ttl 30d|90d|180d|1y] [--auto-revoke true|false]')}\n`);
25
+ exit(2);
26
+ }
27
+ const out = await api('PATCH', '/v1/operators/me/identity-settings', { body });
28
+ if (json)
29
+ return printJson(out);
30
+ printRecord(out);
31
+ }
32
+ async function cmdProviders(json) {
33
+ const out = await api('GET', '/v1/identity/providers');
34
+ if (json)
35
+ return printJson(out);
36
+ printJson(out);
37
+ }
38
+ async function cmdClaims(json) {
39
+ const out = await api('GET', '/v1/identity/claims');
40
+ const list = Array.isArray(out) ? out : (out?.claims ?? []);
41
+ if (json)
42
+ return printJson(list);
43
+ if (list.length === 0) {
44
+ stdout.write('(no claims)\n');
45
+ return;
46
+ }
47
+ const rows = list.map((c) => [
48
+ c.id,
49
+ c.provider_key,
50
+ c.layer,
51
+ c.assurance_level,
52
+ c.revoked_at ? fmt.dim('revoked') : fmt.ok('active'),
53
+ fmtTs(c.verified_at ?? null),
54
+ ]);
55
+ printTable(['ID', 'PROVIDER', 'LAYER', 'ASSURANCE', 'STATUS', 'VERIFIED'], rows);
56
+ }
57
+ async function cmdRevokeClaim(id, json) {
58
+ const out = await api('DELETE', `/v1/identity/claims/${encodeURIComponent(id)}`);
59
+ if (json)
60
+ return printJson(out);
61
+ stdout.write(`revoked ${id}\n`);
62
+ }
63
+ async function cmdSendVerificationCode(args, json) {
64
+ const channel = takeFlag(args, '--channel');
65
+ const destination = takeFlag(args, '--destination');
66
+ if (typeof channel !== 'string' || typeof destination !== 'string') {
67
+ stderr.write(`usage: ${invokeHint('identity send-code --channel email|sms --destination <addr>')}\n`);
68
+ exit(2);
69
+ }
70
+ const out = await api('POST', '/v1/identity/verification-codes', {
71
+ body: { channel, destination },
72
+ });
73
+ if (json)
74
+ return printJson(out);
75
+ stdout.write(`verification code sent to ${destination}\n`);
76
+ }
77
+ export async function cmdIdentity(args) {
78
+ const json = !!takeFlag(args, '--json');
79
+ const sub = args[0];
80
+ const arg1 = args[1];
81
+ if (sub === 'settings' || sub === 'get-settings')
82
+ return cmdSettings(json);
83
+ if (sub === 'update-settings')
84
+ return cmdUpdateSettings(args.slice(1), json);
85
+ if (sub === 'providers')
86
+ return cmdProviders(json);
87
+ if (sub === 'claims' || sub === 'list')
88
+ return cmdClaims(json);
89
+ if (sub === 'revoke-claim') {
90
+ if (!arg1) {
91
+ stderr.write(`usage: ${invokeHint('identity revoke-claim <claim-id>')}\n`);
92
+ exit(2);
93
+ }
94
+ return cmdRevokeClaim(arg1, json);
95
+ }
96
+ if (sub === 'send-code')
97
+ return cmdSendVerificationCode(args.slice(1), json);
98
+ stderr.write(`error: unknown identity subcommand "${sub ?? ''}".\n` +
99
+ `Use settings | update-settings | providers | claims | revoke-claim | send-code\n`);
100
+ exit(2);
101
+ }
102
+ //# sourceMappingURL=identity.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"identity.js","sourceRoot":"","sources":["../src/identity.ts"],"names":[],"mappings":"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"}
package/dist/index.js CHANGED
@@ -2,6 +2,17 @@
2
2
  import { argv, env, stdout, stderr } from 'node:process';
3
3
  import { cmdLogin, cmdLogout, cmdStatus, getAccessToken } from './auth.js';
4
4
  import { cmdAgent } from './agent.js';
5
+ import { cmdPassport } from './passports.js';
6
+ import { cmdService } from './services.js';
7
+ import { cmdDropoff } from './dropoffs.js';
8
+ import { cmdSkill } from './skills.js';
9
+ import { cmdIdentity } from './identity.js';
10
+ import { cmdAudit } from './audit.js';
11
+ import { cmdEvent } from './events.js';
12
+ import { cmdTeam } from './team.js';
13
+ import { cmdMe } from './me.js';
14
+ import { cmdNotifications } from './notifications.js';
15
+ import { cmdDetector } from './detectors.js';
5
16
  const DASHBOARD_URL = 'https://getstack.run';
6
17
  const API_URL = env['STACK_API_URL'] ?? 'https://api.getstack.run';
7
18
  // ── ANSI helpers ────────────────────────────────────────────────────
@@ -251,15 +262,86 @@ ${C.gray}https://getstack.run${C.reset}
251
262
  ${C.white}Usage${C.reset}
252
263
  npx @getstackrun/cli ${C.cyan}<command>${C.reset} [options]
253
264
 
254
- ${C.white}Commands${C.reset}
265
+ ${C.white}Account${C.reset}
255
266
  ${C.cyan}auth login${C.reset} Sign in via browser (Device flow, RFC 8628)
256
267
  ${C.cyan}auth status${C.reset} Show current sign-in state
257
268
  ${C.cyan}auth logout${C.reset} Revoke session and clear local credentials
258
- ${C.cyan}agent enroll${C.reset} <name|id> Generate keypair + enroll an agent (operator-side)
259
- ${C.cyan}agent rotate${C.reset} <name|id> Rotate an enrolled agent's keypair (admin only)
269
+ ${C.cyan}me${C.reset} Print your operator profile
270
+
271
+ ${C.white}Agents${C.reset}
272
+ ${C.cyan}agent list${C.reset} List all your agents
273
+ ${C.cyan}agent show${C.reset} <name|id> Detail on one agent
274
+ ${C.cyan}agent register${C.reset} <name> Register a new agent
275
+ ${C.cyan}agent enroll${C.reset} <name|id> Generate keypair + enroll (operator-side)
276
+ ${C.cyan}agent rotate${C.reset} <name|id> Rotate keypair (admin only)
277
+ ${C.cyan}agent suspend${C.reset} <name|id> Suspend an agent
278
+ ${C.cyan}agent unsuspend${C.reset} <name|id> Re-activate a suspended agent
279
+ ${C.cyan}agent delete${C.reset} <name|id> Delete an agent
280
+
281
+ ${C.white}Passports${C.reset}
282
+ ${C.cyan}passport list${C.reset} List active passports
283
+ ${C.cyan}passport issue${C.reset} --agent ... --intent ... --services ...
284
+ ${C.cyan}passport verify${C.reset} <token> Verify a passport JWT
285
+ ${C.cyan}passport refresh${C.reset} <jti> --token <jwt>
286
+ ${C.cyan}passport revoke${C.reset} <jti> Revoke one passport
287
+ ${C.cyan}passport revoke-agent${C.reset} <id> Revoke all passports for an agent
288
+ ${C.cyan}passport revoke-all${C.reset} --yes Revoke every active passport
289
+
290
+ ${C.white}Services${C.reset}
291
+ ${C.cyan}service catalog${C.reset} Browse available service catalog
292
+ ${C.cyan}service connections${C.reset} List your connected services
293
+ ${C.cyan}service show${C.reset} <connection-id> Detail on one connection
294
+ ${C.cyan}service verify${C.reset} <connection-id> Re-test connection health
295
+ ${C.cyan}service disconnect${C.reset} <id> Disconnect a service
296
+ ${C.cyan}service credential${C.reset} <provider> Retrieve raw credential (operator only)
297
+
298
+ ${C.white}Drop-offs${C.reset}
299
+ ${C.cyan}dropoff list${C.reset} List your drop-offs
300
+ ${C.cyan}dropoff show${C.reset} <id> Detail on one drop-off
301
+ ${C.cyan}dropoff create${C.reset} --from <a> --to <b> --schema <f>
302
+ ${C.cyan}dropoff deposit${C.reset} <id> --agent <a> --payload <f>
303
+ ${C.cyan}dropoff collect${C.reset} <id> --agent <a>
304
+ ${C.cyan}dropoff expire${C.reset} <id> Force-expire a drop-off
305
+
306
+ ${C.white}Skills${C.reset}
307
+ ${C.cyan}skill list${C.reset} [--q "..."] Browse the skills marketplace
308
+ ${C.cyan}skill mine${C.reset} List your own published skills
309
+ ${C.cyan}skill show${C.reset} <id> Detail on one skill
310
+ ${C.cyan}skill suspend${C.reset} <id> Suspend a published skill
311
+ ${C.cyan}skill activate${C.reset} <id> Re-activate a suspended skill
312
+ ${C.cyan}skill requests${C.reset} List skill requests
313
+ ${C.cyan}skill post-request${C.reset} "<desc>" Post a new skill request
314
+
315
+ ${C.white}Identity${C.reset}
316
+ ${C.cyan}identity settings${C.reset} Get operator identity settings
317
+ ${C.cyan}identity update-settings${C.reset} [--inheritance ...] [--ttl ...] [--auto-revoke ...]
318
+ ${C.cyan}identity providers${C.reset} List identity-verification providers
319
+ ${C.cyan}identity claims${C.reset} List your verified identity claims
320
+ ${C.cyan}identity revoke-claim${C.reset} <id> Revoke an identity claim
321
+
322
+ ${C.white}Audit${C.reset}
323
+ ${C.cyan}audit list${C.reset} [--limit N] [--agent <id>]
324
+ ${C.cyan}audit chain-head${C.reset} Current audit-chain head hash
325
+ ${C.cyan}audit verify-chain${C.reset} Verify your audit chain integrity
326
+
327
+ ${C.white}Security events${C.reset}
328
+ ${C.cyan}event list${C.reset} [--agent <id>]
329
+ ${C.cyan}event show${C.reset} <id>
330
+ ${C.cyan}event resolve${C.reset} <id>
331
+
332
+ ${C.white}Team${C.reset}
333
+ ${C.cyan}team list${C.reset} List team members
334
+ ${C.cyan}team invite${C.reset} <email> [--role ...]
335
+ ${C.cyan}team update${C.reset} <id> [--role ...] [--status ...]
336
+ ${C.cyan}team revoke${C.reset} <id>
337
+
338
+ ${C.white}Other${C.reset}
260
339
  ${C.cyan}register${C.reset} Print signup + MCP install instructions
261
340
  ${C.cyan}monitor${C.reset} [--demo|--follow] Tail STACK activity in your terminal
262
341
 
342
+ ${C.white}Global flags${C.reset}
343
+ --json Emit raw JSON instead of formatted tables.
344
+
263
345
  ${C.white}monitor flags${C.reset}
264
346
  --demo Replay a real-shape mission (no auth needed).
265
347
  Same row format as --follow, just scripted.
@@ -308,10 +390,54 @@ async function main() {
308
390
  stderr.write(`error: unknown auth subcommand "${sub ?? ''}". Use login | logout | status.\n`);
309
391
  process.exit(2);
310
392
  }
311
- if (command === 'agent') {
393
+ if (command === 'agent' || command === 'agents') {
312
394
  await cmdAgent(argv.slice(3));
313
395
  return;
314
396
  }
397
+ if (command === 'passport' || command === 'passports') {
398
+ await cmdPassport(argv.slice(3));
399
+ return;
400
+ }
401
+ if (command === 'service' || command === 'services') {
402
+ await cmdService(argv.slice(3));
403
+ return;
404
+ }
405
+ if (command === 'dropoff' || command === 'dropoffs') {
406
+ await cmdDropoff(argv.slice(3));
407
+ return;
408
+ }
409
+ if (command === 'skill' || command === 'skills') {
410
+ await cmdSkill(argv.slice(3));
411
+ return;
412
+ }
413
+ if (command === 'identity') {
414
+ await cmdIdentity(argv.slice(3));
415
+ return;
416
+ }
417
+ if (command === 'audit') {
418
+ await cmdAudit(argv.slice(3));
419
+ return;
420
+ }
421
+ if (command === 'event' || command === 'events' || command === 'security-event' || command === 'security-events') {
422
+ await cmdEvent(argv.slice(3));
423
+ return;
424
+ }
425
+ if (command === 'team' || command === 'members' || command === 'member') {
426
+ await cmdTeam(argv.slice(3));
427
+ return;
428
+ }
429
+ if (command === 'me' || command === 'whoami') {
430
+ await cmdMe(argv.slice(3));
431
+ return;
432
+ }
433
+ if (command === 'notifications' || command === 'notification' || command === 'notify') {
434
+ await cmdNotifications(argv.slice(3));
435
+ return;
436
+ }
437
+ if (command === 'detector' || command === 'detectors') {
438
+ await cmdDetector(argv.slice(3));
439
+ return;
440
+ }
315
441
  if (command === 'register') {
316
442
  stdout.write(`
317
443
  STACK — Infrastructure for agents