@trydreamstate/cli 1.2.0 → 1.2.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/README.md +5 -1
- package/dist/client.d.ts +3 -1
- package/dist/client.d.ts.map +1 -1
- package/dist/client.js +6 -3
- package/dist/commands/sequences.d.ts +1 -1
- package/dist/commands/sequences.d.ts.map +1 -1
- package/dist/commands/sequences.js +3 -3
- package/dist/commands/shared.d.ts +2 -1
- package/dist/commands/shared.d.ts.map +1 -1
- package/dist/commands/shared.js +98 -20
- package/dist/commands/workflows.d.ts +1 -1
- package/dist/commands/workflows.d.ts.map +1 -1
- package/dist/commands/workflows.js +9 -9
- package/dist/config.d.ts +10 -0
- package/dist/config.d.ts.map +1 -1
- package/dist/config.js +95 -2
- package/dist/index.d.ts +36 -1
- package/dist/index.d.ts.map +1 -1
- package/dist/index.js +330 -59
- package/dist/runWait.d.ts +9 -0
- package/dist/runWait.d.ts.map +1 -0
- package/dist/runWait.js +76 -0
- package/dist/skillInstaller.d.ts +1 -0
- package/dist/skillInstaller.d.ts.map +1 -1
- package/dist/skillInstaller.js +18 -0
- package/package.json +1 -1
package/dist/index.js
CHANGED
|
@@ -4,6 +4,8 @@ Object.defineProperty(exports, "__esModule", { value: true });
|
|
|
4
4
|
exports.CliUsageError = exports.CLI_EXIT = void 0;
|
|
5
5
|
exports.parseCliArgs = parseCliArgs;
|
|
6
6
|
exports.toolTurnToken = toolTurnToken;
|
|
7
|
+
exports.omitsToolTurnForInlineTableRead = omitsToolTurnForInlineTableRead;
|
|
8
|
+
exports.capabilityIdempotencyKey = capabilityIdempotencyKey;
|
|
7
9
|
exports.refusalEnvelope = refusalEnvelope;
|
|
8
10
|
exports.openWebUrl = openWebUrl;
|
|
9
11
|
exports.exitCodeForError = exitCodeForError;
|
|
@@ -17,6 +19,7 @@ const node_os_1 = require("node:os");
|
|
|
17
19
|
const node_util_1 = require("node:util");
|
|
18
20
|
const config_1 = require("./config");
|
|
19
21
|
const turnCache_1 = require("./turnCache");
|
|
22
|
+
const runWait_1 = require("./runWait");
|
|
20
23
|
const client_1 = require("./client");
|
|
21
24
|
const skillInstaller_1 = require("./skillInstaller");
|
|
22
25
|
exports.CLI_EXIT = { SUCCESS: 0, UNCLASSIFIED: 1, USAGE: 2, AUTH: 3, NOT_FOUND: 4, SERVER: 5, RATE_LIMITED: 6, APPROVAL: 7, TIMEOUT: 8, REFUSED: 9, TRANSPORT: 10 };
|
|
@@ -26,13 +29,15 @@ const USAGE = `Dreamstate CLI
|
|
|
26
29
|
Usage:
|
|
27
30
|
dreamstate --help
|
|
28
31
|
dreamstate --version
|
|
29
|
-
dreamstate login
|
|
30
|
-
dreamstate login --token <ds_user_...|ds_live_...>
|
|
32
|
+
dreamstate login [--no-skills]
|
|
33
|
+
dreamstate login [--profile <name>] --token <ds_user_...|ds_live_...> [--no-skills]
|
|
31
34
|
dreamstate logout
|
|
35
|
+
dreamstate status [--json-output|--json]
|
|
36
|
+
dreamstate profiles <list|use|current|remove|env> [name] [--json-output|--json]
|
|
32
37
|
dreamstate whoami [--json-output|--json]
|
|
33
38
|
dreamstate workspaces list [--json-output|--json]
|
|
34
39
|
dreamstate workspaces use <id|slug>
|
|
35
|
-
dreamstate auth login [--api-key-file <path>]
|
|
40
|
+
dreamstate auth login [--api-key-file <path>] [--no-skills]
|
|
36
41
|
dreamstate auth whoami [--json-output|--json]
|
|
37
42
|
dreamstate packs list [--json-output|--json]
|
|
38
43
|
dreamstate packs get <pack_id> [--json-output|--json]
|
|
@@ -45,7 +50,7 @@ Usage:
|
|
|
45
50
|
dreamstate commands search <term> [--json-output|--json]
|
|
46
51
|
dreamstate tools search --goal <goal> [--terms <csv>] [--limit <n>] [--toolset <pack_id>] [--json-output|--json]
|
|
47
52
|
dreamstate tools get <capability_id> [--json-output|--json]
|
|
48
|
-
dreamstate tools run <capability_id> [--params <object>|--json <body>] [--turn-token <token>] (--live | --dry-run | --mode <smoke_test|dry_run|live>) [--agent-session-id <uuid>] [--approved] [--approved-effect-unknown] [--max-credits <n>] [--idempotency-key <key>] [--open] [--json-output|--json]
|
|
53
|
+
dreamstate tools run <capability_id> [--params <object>|--json <body>] [--turn-token <token>] (--live | --dry-run | --mode <smoke_test|dry_run|live>) [--agent-session-id <uuid>] [--approved] [--approved-effect-unknown] [--max-credits <n>] [--idempotency-key <key>] [--wait-timeout <seconds>] [--no-wait] [--open] [--json-output|--json]
|
|
49
54
|
dreamstate sequences <verb> [args] [flags]
|
|
50
55
|
dreamstate workflows <verb> [args] [flags]
|
|
51
56
|
dreamstate tables import --table-id <uuid> --file <path> [--format <csv|json|jsonl|xlsx>] [--preview] [--upsert-key <header>] [--background] [--json-output|--json]
|
|
@@ -53,10 +58,11 @@ Usage:
|
|
|
53
58
|
dreamstate runs get <run_id> [--json-output|--json]
|
|
54
59
|
dreamstate runs resume <run_id> --state-version <n> [--reason <text>] [--idempotency-key <key>] [--open] [--json-output|--json]
|
|
55
60
|
dreamstate runs events <run_id> [--json-output|--json]
|
|
56
|
-
dreamstate runs cancel <run_id> --json <body> [--idempotency-key <key>] [--json-output|--json]
|
|
61
|
+
dreamstate runs cancel <run_id> [--state-version <n>] [--reason <text>] [--json <body>] [--idempotency-key <key>] [--json-output|--json]
|
|
57
62
|
|
|
58
63
|
All catalog discovery reads live API records. Set DREAMSTATE_API_URL and DREAMSTATE_API_KEY.
|
|
59
|
-
|
|
64
|
+
Run responses wait for terminal run status by default, timeout default is 120 seconds, --no-wait returns immediate response. Timeout prints latest run envelope and exits ${runWait_1.RUN_WAIT_TIMEOUT_EXIT_CODE}.
|
|
65
|
+
login opens browser approval and installs Dreamstate skills for detected agents; --no-skills skips installation. login --token stores a ds_user_ session or ds_live_ key (for SSH or remote machines) after verifying it with whoami.
|
|
60
66
|
Global flag --workspace <id|slug> (any command) or DREAMSTATE_WORKSPACE picks the workspace for one call; workspaces use stores a default. Flag beats env beats stored. A ds_live_ key is bound to one workspace and cannot switch.
|
|
61
67
|
logout deletes the stored credentials file. --agents takes space-separated, comma-separated or repeated values.
|
|
62
68
|
`;
|
|
@@ -106,6 +112,22 @@ function nonNegativeInteger(raw, flag) {
|
|
|
106
112
|
throw new CliUsageError(`${flag} must be a non-negative integer`);
|
|
107
113
|
return value;
|
|
108
114
|
}
|
|
115
|
+
// runs.get returns { data: { run: { state_version } } }. Cancel posts
|
|
116
|
+
// expected_state_version, and a missing read must not invent 0.
|
|
117
|
+
function stateVersionFromRunRead(payload) {
|
|
118
|
+
const record = payload && typeof payload === 'object' && !Array.isArray(payload) ? payload : null;
|
|
119
|
+
const data = record && record.data && typeof record.data === 'object' && !Array.isArray(record.data)
|
|
120
|
+
? record.data
|
|
121
|
+
: null;
|
|
122
|
+
const run = data && data.run && typeof data.run === 'object' && !Array.isArray(data.run)
|
|
123
|
+
? data.run
|
|
124
|
+
: null;
|
|
125
|
+
const version = run?.state_version;
|
|
126
|
+
if (typeof version !== 'number' || !Number.isSafeInteger(version) || version < 0) {
|
|
127
|
+
throw new client_1.CliError('runs cancel could not read state_version from the run. Pass --state-version <n>.', 'invalid_response', 0);
|
|
128
|
+
}
|
|
129
|
+
return version;
|
|
130
|
+
}
|
|
109
131
|
function parsePacks(argv) {
|
|
110
132
|
const { values, positionals } = (0, node_util_1.parseArgs)({ args: argv, options: { goal: { type: 'string' }, 'json-output': { type: 'boolean' }, help: { type: 'boolean', short: 'h' } }, allowPositionals: true, strict: true });
|
|
111
133
|
if (values.help)
|
|
@@ -215,7 +237,7 @@ function parseTools(argv) {
|
|
|
215
237
|
'idempotency-key': { type: 'string' }, 'json-output': { type: 'boolean' }, open: { type: 'boolean' },
|
|
216
238
|
'dry-run': { type: 'boolean' }, live: { type: 'boolean' }, mode: { type: 'string' },
|
|
217
239
|
'agent-session-id': { type: 'string' }, approved: { type: 'boolean' }, 'approved-effect-unknown': { type: 'boolean' },
|
|
218
|
-
'max-credits': { type: 'string' }, 'turn-token': { type: 'string' }, help: { type: 'boolean', short: 'h' },
|
|
240
|
+
'max-credits': { type: 'string' }, 'turn-token': { type: 'string' }, 'wait-timeout': { type: 'string' }, 'no-wait': { type: 'boolean' }, help: { type: 'boolean', short: 'h' },
|
|
219
241
|
}, allowPositionals: true, strict: true });
|
|
220
242
|
if (values.help)
|
|
221
243
|
return { command: 'help' };
|
|
@@ -268,7 +290,8 @@ function parseTools(argv) {
|
|
|
268
290
|
// run without one. What was missing was any way to ASK for live.
|
|
269
291
|
if (body.mode !== undefined)
|
|
270
292
|
requireToolsRunMode(body);
|
|
271
|
-
|
|
293
|
+
const waitTimeout = values['wait-timeout'] === undefined ? 120 : nonNegativeNumber(values['wait-timeout'], '--wait-timeout');
|
|
294
|
+
return { command: 'tools_run', capabilityId, body, waitTimeout, ...(values['no-wait'] ? { noWait: true } : {}), ...(values['turn-token'] ? { turnToken: values['turn-token'] } : {}), ...(values['idempotency-key'] ? { idempotencyKey: values['idempotency-key'] } : {}), ...(values.open ? { open: true } : {}), ...output };
|
|
272
295
|
}
|
|
273
296
|
throw new CliUsageError('Usage: dreamstate tools <search|get|run>');
|
|
274
297
|
}
|
|
@@ -323,9 +346,20 @@ function parseRuns(argv) {
|
|
|
323
346
|
return { command: 'runs_resume', runId, stateVersion: nonNegativeInteger(values['state-version'], '--state-version'), ...(values.reason ? { reason: values.reason } : {}), ...(values['idempotency-key'] ? { idempotencyKey: values['idempotency-key'] } : {}), ...(values.open ? { open: true } : {}), ...output };
|
|
324
347
|
}
|
|
325
348
|
if (positionals[0] === 'cancel') {
|
|
326
|
-
|
|
327
|
-
|
|
328
|
-
|
|
349
|
+
const idempotency = values['idempotency-key'] ? { idempotencyKey: values['idempotency-key'] } : {};
|
|
350
|
+
if (values.json && (values['state-version'] !== undefined || values.reason)) {
|
|
351
|
+
throw new CliUsageError('Use either --json <body> or --state-version and --reason with runs cancel, not both.');
|
|
352
|
+
}
|
|
353
|
+
if (values.json)
|
|
354
|
+
return { command: 'runs_cancel', runId, body: parseJsonObject(values.json), ...idempotency, ...output };
|
|
355
|
+
return {
|
|
356
|
+
command: 'runs_cancel',
|
|
357
|
+
runId,
|
|
358
|
+
...(values['state-version'] !== undefined ? { stateVersion: nonNegativeInteger(values['state-version'], '--state-version') } : {}),
|
|
359
|
+
...(values.reason ? { reason: values.reason } : {}),
|
|
360
|
+
...idempotency,
|
|
361
|
+
...output,
|
|
362
|
+
};
|
|
329
363
|
}
|
|
330
364
|
throw new CliUsageError('Usage: dreamstate runs <get|events|cancel> <run_id>');
|
|
331
365
|
}
|
|
@@ -342,14 +376,14 @@ function parseCliArgs(argv) {
|
|
|
342
376
|
return { command: 'version' };
|
|
343
377
|
const [group, ...rest] = argv;
|
|
344
378
|
if (group === 'login') {
|
|
345
|
-
const { values, positionals } = (0, node_util_1.parseArgs)({ args: rest, options: { token: { type: 'string' }, 'api-key-file': { type: 'string' }, 'json-output': { type: 'boolean' }, help: { type: 'boolean', short: 'h' } }, allowPositionals: true, strict: true });
|
|
379
|
+
const { values, positionals } = (0, node_util_1.parseArgs)({ args: rest, options: { token: { type: 'string' }, profile: { type: 'string' }, 'api-key-file': { type: 'string' }, 'no-skills': { type: 'boolean' }, 'json-output': { type: 'boolean' }, help: { type: 'boolean', short: 'h' } }, allowPositionals: true, strict: true });
|
|
346
380
|
if (values.help)
|
|
347
381
|
return { command: 'help' };
|
|
348
382
|
if (positionals.length)
|
|
349
383
|
throw new CliUsageError('Usage: dreamstate login [--token <ds_user_...|ds_live_...>]');
|
|
350
384
|
if (values.token !== undefined && values['api-key-file'])
|
|
351
385
|
throw new CliUsageError('Use either --token or --api-key-file, not both.');
|
|
352
|
-
return { command: 'login', ...(values.token !== undefined ? { token: values.token } : {}), ...(values['api-key-file'] ? { apiKeyFile: values['api-key-file'] } : {}), ...outputOption(values) };
|
|
386
|
+
return { command: 'login', ...(values.token !== undefined ? { token: values.token } : {}), ...(values['api-key-file'] ? { apiKeyFile: values['api-key-file'] } : {}), ...(values.profile ? { profile: (0, config_1.validateProfileName)(values.profile) } : {}), ...(values['no-skills'] ? { noSkills: true } : {}), ...outputOption(values) };
|
|
353
387
|
}
|
|
354
388
|
if (group === 'logout') {
|
|
355
389
|
const { values, positionals } = (0, node_util_1.parseArgs)({ args: rest, options: { 'json-output': { type: 'boolean' }, help: { type: 'boolean', short: 'h' } }, allowPositionals: true, strict: true });
|
|
@@ -359,6 +393,27 @@ function parseCliArgs(argv) {
|
|
|
359
393
|
throw new CliUsageError('Usage: dreamstate logout');
|
|
360
394
|
return { command: 'logout', ...outputOption(values) };
|
|
361
395
|
}
|
|
396
|
+
if (group === 'status') {
|
|
397
|
+
const { values, positionals } = (0, node_util_1.parseArgs)({ args: rest, options: { 'json-output': { type: 'boolean' } }, allowPositionals: true, strict: true });
|
|
398
|
+
if (!positionals.length)
|
|
399
|
+
return { command: 'status', ...outputOption(values) };
|
|
400
|
+
throw new CliUsageError('Usage: dreamstate status [--json-output]');
|
|
401
|
+
}
|
|
402
|
+
if (group === 'profiles') {
|
|
403
|
+
const { values, positionals } = (0, node_util_1.parseArgs)({ args: rest, options: { 'json-output': { type: 'boolean' } }, allowPositionals: true, strict: true });
|
|
404
|
+
const output = outputOption(values);
|
|
405
|
+
if (positionals.length === 1 && positionals[0] === 'list')
|
|
406
|
+
return { command: 'profiles_list', ...output };
|
|
407
|
+
if (positionals.length === 1 && positionals[0] === 'current')
|
|
408
|
+
return { command: 'profiles_current', ...output };
|
|
409
|
+
if (positionals.length === 2 && positionals[0] === 'use')
|
|
410
|
+
return { command: 'profiles_use', name: (0, config_1.validateProfileName)(positionals[1]), ...output };
|
|
411
|
+
if (positionals.length === 2 && positionals[0] === 'remove')
|
|
412
|
+
return { command: 'profiles_remove', name: (0, config_1.validateProfileName)(positionals[1]), ...output };
|
|
413
|
+
if (positionals.length === 2 && positionals[0] === 'env')
|
|
414
|
+
return { command: 'profiles_env', name: (0, config_1.validateProfileName)(positionals[1]), ...output };
|
|
415
|
+
throw new CliUsageError('Usage: dreamstate profiles <list|use <name>|current|remove <name>|env <name>>');
|
|
416
|
+
}
|
|
362
417
|
if (group === 'whoami') {
|
|
363
418
|
const { values, positionals } = (0, node_util_1.parseArgs)({ args: rest, options: { 'json-output': { type: 'boolean' } }, allowPositionals: true, strict: true });
|
|
364
419
|
if (positionals.length === 0)
|
|
@@ -376,9 +431,9 @@ function parseCliArgs(argv) {
|
|
|
376
431
|
throw new CliUsageError('Usage: dreamstate workspaces <list|use <id|slug>>');
|
|
377
432
|
}
|
|
378
433
|
if (group === 'auth') {
|
|
379
|
-
const { values, positionals } = (0, node_util_1.parseArgs)({ args: rest, options: { 'api-key-file': { type: 'string' }, 'json-output': { type: 'boolean' } }, allowPositionals: true, strict: true });
|
|
434
|
+
const { values, positionals } = (0, node_util_1.parseArgs)({ args: rest, options: { 'api-key-file': { type: 'string' }, 'no-skills': { type: 'boolean' }, 'json-output': { type: 'boolean' } }, allowPositionals: true, strict: true });
|
|
380
435
|
if (positionals.length === 1 && positionals[0] === 'login')
|
|
381
|
-
return { command: 'login', ...(values['api-key-file'] ? { apiKeyFile: values['api-key-file'] } : {}), ...outputOption(values) };
|
|
436
|
+
return { command: 'login', ...(values['api-key-file'] ? { apiKeyFile: values['api-key-file'] } : {}), ...(values['no-skills'] ? { noSkills: true } : {}), ...outputOption(values) };
|
|
382
437
|
if (positionals.length === 1 && positionals[0] === 'whoami')
|
|
383
438
|
return { command: 'whoami', ...outputOption(values) };
|
|
384
439
|
throw new CliUsageError('Usage: dreamstate auth <login|whoami>');
|
|
@@ -438,6 +493,57 @@ function toolTurnToken(value) {
|
|
|
438
493
|
return data.tool_turn_token;
|
|
439
494
|
throw new client_1.CliError('tools get did not return a tool_turn_token.', 'invalid_tool_turn_token', 0);
|
|
440
495
|
}
|
|
496
|
+
/**
|
|
497
|
+
* null suppresses Idempotency-Key. undefined lets runCapability mint one.
|
|
498
|
+
* A fresh random key never replays, but the server treats any Idempotency-Key
|
|
499
|
+
* as a replay request and refuses the inline read (isInlineReadEligible).
|
|
500
|
+
* Omit the key only when the fetched contract says mutates === false and
|
|
501
|
+
* idempotency_required is not true. Missing flags keep the auto key: a
|
|
502
|
+
* caller-supplied turn token skips tools get, and live writes still need one.
|
|
503
|
+
*/
|
|
504
|
+
/**
|
|
505
|
+
* Free sync reads. The server runs these on the inline read path when
|
|
506
|
+
* the body has no tool_turn_token and the request has no Idempotency-Key
|
|
507
|
+
* (isInlineReadEligible). A tools get before the run is a second HTTP the
|
|
508
|
+
* read does not need. Measured 2026-10-04: tables.workbooks.get full live CLI
|
|
509
|
+
* 0.726s against whoami 0.455s, about 0.27s of tools get per harness read-back.
|
|
510
|
+
* knowledge.brain.context.get is the same class (catalog: credit_class free,
|
|
511
|
+
* async_policy.mode sync, mutates not set). Live 2026-10-05 a standalone
|
|
512
|
+
* tools get of that id was 0.400s including node startup, next to whoami
|
|
513
|
+
* 0.422s, so the same-process skip is one HTTP, not a second process.
|
|
514
|
+
* The set name is historical. Writes are not in this set: they stay fetch-first.
|
|
515
|
+
*/
|
|
516
|
+
const INLINE_READ_CAPABILITIES = new Set([
|
|
517
|
+
'tables.workbooks.get',
|
|
518
|
+
'tables.workbooks.overview',
|
|
519
|
+
'tables.workbooks.list',
|
|
520
|
+
'tables.columns.list',
|
|
521
|
+
'tables.columns.stats',
|
|
522
|
+
'tables.rows.query',
|
|
523
|
+
'tables.rows.get',
|
|
524
|
+
'tables.rows.count',
|
|
525
|
+
'knowledge.brain.context.get',
|
|
526
|
+
// Both are stored, free, synchronous inbox reads. Keeping either behind a
|
|
527
|
+
// tools_get turns one list or thread open into two HTTP requests, while the
|
|
528
|
+
// canonical inline-read gate already validates their read-only contract.
|
|
529
|
+
'unibox.inbox.unified_list',
|
|
530
|
+
'unibox.inbox.conversation_get',
|
|
531
|
+
]);
|
|
532
|
+
function omitsToolTurnForInlineTableRead(capabilityId) {
|
|
533
|
+
return INLINE_READ_CAPABILITIES.has(capabilityId);
|
|
534
|
+
}
|
|
535
|
+
function capabilityIdempotencyKey(fetched) {
|
|
536
|
+
const root = fetched && typeof fetched === 'object' ? fetched : {};
|
|
537
|
+
const data = root.data && typeof root.data === 'object' && !Array.isArray(root.data)
|
|
538
|
+
? root.data
|
|
539
|
+
: {};
|
|
540
|
+
const capability = data.capability && typeof data.capability === 'object' && !Array.isArray(data.capability)
|
|
541
|
+
? data.capability
|
|
542
|
+
: {};
|
|
543
|
+
if (capability.mutates === false && capability.idempotency_required !== true)
|
|
544
|
+
return null;
|
|
545
|
+
return undefined;
|
|
546
|
+
}
|
|
441
547
|
function code(error) {
|
|
442
548
|
return error && typeof error === 'object' && typeof error.code === 'string'
|
|
443
549
|
? error.code
|
|
@@ -617,14 +723,94 @@ function whoamiData(value) {
|
|
|
617
723
|
const data = value && typeof value === 'object' ? value.data : undefined;
|
|
618
724
|
return data && typeof data === 'object' ? data : {};
|
|
619
725
|
}
|
|
726
|
+
function statusData(whoami, health) {
|
|
727
|
+
const meta = whoami && typeof whoami === 'object' ? whoami.meta : null;
|
|
728
|
+
const serverVersion = meta && typeof meta === 'object' ? meta.server_version : null;
|
|
729
|
+
const minimumCliVersion = meta && typeof meta === 'object' ? meta.minimum_cli_version : null;
|
|
730
|
+
const healthData = health && typeof health === 'object' ? health.data : null;
|
|
731
|
+
const healthVersion = healthData && typeof healthData === 'object' ? healthData.version : null;
|
|
732
|
+
const version = typeof serverVersion === 'string' ? serverVersion : typeof healthVersion === 'string' ? healthVersion : null;
|
|
733
|
+
const minimum = typeof minimumCliVersion === 'string' ? minimumCliVersion : null;
|
|
734
|
+
const parts = (value) => value.replace(/^v/, '').split('-')[0].split('.').map((part) => Number(part));
|
|
735
|
+
const [minimumMajor = 0, minimumMinor = 0, minimumPatch = 0] = minimum ? parts(minimum) : [];
|
|
736
|
+
const [cliMajor = 0, cliMinor = 0, cliPatch = 0] = parts(client_1.CLI_VERSION);
|
|
737
|
+
const compatible = !minimum || minimumMajor < cliMajor || (minimumMajor === cliMajor && (minimumMinor < cliMinor || (minimumMinor === cliMinor && minimumPatch <= cliPatch)));
|
|
738
|
+
return {
|
|
739
|
+
cli_version: client_1.CLI_VERSION,
|
|
740
|
+
api_version: version,
|
|
741
|
+
minimum_cli_version: minimum,
|
|
742
|
+
minimum_cli_version_published: minimum !== null,
|
|
743
|
+
compatible,
|
|
744
|
+
upgrade_hint: compatible ? null : 'Run: npm install -g @trydreamstate/cli@latest',
|
|
745
|
+
health,
|
|
746
|
+
whoami: whoamiData(whoami),
|
|
747
|
+
};
|
|
748
|
+
}
|
|
620
749
|
function activeWorkspace(data) {
|
|
621
|
-
const activeId = data.workspace_id
|
|
750
|
+
const activeId = data.workspace_id;
|
|
622
751
|
return activeId ? data.workspaces?.find((workspace) => workspace.id === activeId) : undefined;
|
|
623
752
|
}
|
|
624
753
|
function wait(milliseconds) {
|
|
625
754
|
return new Promise((resolve) => setTimeout(resolve, milliseconds));
|
|
626
755
|
}
|
|
627
|
-
async function
|
|
756
|
+
async function installHostedSkills(client, agents, runtime, options = {}) {
|
|
757
|
+
const listed = await client.listAllSkills();
|
|
758
|
+
const entries = listed && typeof listed === 'object' && listed.data?.skills;
|
|
759
|
+
const ids = Array.isArray(entries) ? entries.map((skill) => skill && typeof skill === 'object' ? skill.id : undefined).filter((id) => typeof id === 'string') : [];
|
|
760
|
+
if (!ids.length)
|
|
761
|
+
throw new client_1.CliError('Dreamstate API returned no installable skills.', 'invalid_response', 200);
|
|
762
|
+
if (ids.some((id) => !/^[a-z0-9][a-z0-9_-]*$/i.test(id)))
|
|
763
|
+
throw new CliUsageError('Dreamstate API returned an invalid skill id.');
|
|
764
|
+
const skills = [];
|
|
765
|
+
for (const id of ids) {
|
|
766
|
+
const skill = hostedSkill(await client.getSkill(id));
|
|
767
|
+
if (!/^[a-z0-9][a-z0-9_-]*$/i.test(skill.id))
|
|
768
|
+
throw new CliUsageError('Dreamstate API returned an invalid skill id.');
|
|
769
|
+
if (skill.id !== id)
|
|
770
|
+
throw new client_1.CliError('Dreamstate API returned a mismatched skill id.', 'invalid_response', 200);
|
|
771
|
+
skills.push(skill);
|
|
772
|
+
}
|
|
773
|
+
const packs = await client.listPacks();
|
|
774
|
+
const whoami = await client.getWhoami();
|
|
775
|
+
const workspaceId = typeof whoami?.data?.workspace_id === 'string' ? whoami.data.workspace_id : 'unknown';
|
|
776
|
+
const indexVersion = (0, node_crypto_1.createHash)('sha256')
|
|
777
|
+
.update(JSON.stringify(skills.map((skill) => [skill.id, skill.description, skill.body, skill.frontmatter ?? {}])))
|
|
778
|
+
.digest('hex').slice(0, 16);
|
|
779
|
+
const installed = await (0, skillInstaller_1.installSkills)([...skills, (0, skillInstaller_1.routerSkill)(packs)], {
|
|
780
|
+
agents,
|
|
781
|
+
homeDirectory: runtime.homeDirectory,
|
|
782
|
+
project: Boolean(options.project),
|
|
783
|
+
copy: Boolean(options.copy) || process.platform === 'win32',
|
|
784
|
+
workspaceId,
|
|
785
|
+
indexVersion,
|
|
786
|
+
});
|
|
787
|
+
return { files: installed.files, skillIds: [...ids, 'router'] };
|
|
788
|
+
}
|
|
789
|
+
async function installLoginSkills(client, runtime, skip, stderr) {
|
|
790
|
+
if (skip)
|
|
791
|
+
return { skipped: 'disabled' };
|
|
792
|
+
const agents = await (0, skillInstaller_1.detectInstalledSkillAgents)(runtime.homeDirectory);
|
|
793
|
+
if (!agents.length) {
|
|
794
|
+
stderr.write('Run dreamstate skills install to install Dreamstate skills.\n');
|
|
795
|
+
return { skipped: 'no_agents_detected' };
|
|
796
|
+
}
|
|
797
|
+
try {
|
|
798
|
+
const installed = await installHostedSkills(client, agents, runtime);
|
|
799
|
+
stderr.write(`Installed Dreamstate skills into: ${agents.join(', ')}.\n`);
|
|
800
|
+
return { installed: agents, files: installed.files.length };
|
|
801
|
+
}
|
|
802
|
+
catch {
|
|
803
|
+
stderr.write('Run dreamstate skills install to install Dreamstate skills.\n');
|
|
804
|
+
return { skipped: 'installation_failed' };
|
|
805
|
+
}
|
|
806
|
+
}
|
|
807
|
+
function loginResult(value, skills) {
|
|
808
|
+
if (!value || typeof value !== 'object')
|
|
809
|
+
return value;
|
|
810
|
+
const envelope = value;
|
|
811
|
+
return { ...envelope, data: { ...(envelope.data && typeof envelope.data === 'object' ? envelope.data : {}), skills } };
|
|
812
|
+
}
|
|
813
|
+
async function loginWithDeviceAuthorization(runtime, stdout, stderr, profile, noSkills = false, jsonOutput = false) {
|
|
628
814
|
const environment = runtime.env ?? process.env;
|
|
629
815
|
const baseUrl = (0, config_1.resolveApiBaseUrl)(environment);
|
|
630
816
|
const state = runtime.deviceState ?? deviceState();
|
|
@@ -637,14 +823,19 @@ async function loginWithDeviceAuthorization(runtime, stdout, stderr) {
|
|
|
637
823
|
for (;;) {
|
|
638
824
|
const claim = await (0, client_1.claimDeviceAuthorization)(baseUrl, authorization.device_code);
|
|
639
825
|
if (claim.status === 'ready') {
|
|
640
|
-
|
|
826
|
+
if (profile)
|
|
827
|
+
await (0, config_1.storeCredentialProfile)(profile, claim.token, runtimeCredentialsPath(runtime), claim.workspace.id);
|
|
828
|
+
else
|
|
829
|
+
await (0, config_1.storeApiKey)(claim.token, runtimeCredentialsPath(runtime), claim.workspace.id);
|
|
641
830
|
const client = new client_1.DreamstateClient({
|
|
642
831
|
baseUrl,
|
|
643
832
|
apiKey: claim.token,
|
|
644
833
|
requestTimeoutMs: runtime.requestTimeoutMs,
|
|
645
834
|
onVersionWarning: (message) => (runtime.stderr ?? process.stderr).write(`${message}\n`),
|
|
646
835
|
});
|
|
647
|
-
|
|
836
|
+
const whoami = await client.getWhoami();
|
|
837
|
+
const skills = await installLoginSkills(client, runtime, noSkills, stderr);
|
|
838
|
+
print(loginResult(whoami, skills), stdout, jsonOutput);
|
|
648
839
|
return;
|
|
649
840
|
}
|
|
650
841
|
await (runtime.sleep ?? wait)(authorization.interval_seconds * 1_000);
|
|
@@ -670,8 +861,9 @@ async function runCli(argv = process.argv.slice(2), runtime = {}) {
|
|
|
670
861
|
try {
|
|
671
862
|
const extracted = extractWorkspaceFlag(argv);
|
|
672
863
|
const command = parseCliArgs(extracted.argv);
|
|
673
|
-
if (command.command === 'help') {
|
|
674
|
-
|
|
864
|
+
if (command.command === 'help' || command.command === 'pack_help') {
|
|
865
|
+
const packHelp = command.command === 'pack_help' ? command : undefined;
|
|
866
|
+
print({ ok: true, data: { usage: packHelp?.usage ?? USAGE }, meta: {} }, stdout, Boolean(packHelp?.jsonOutput));
|
|
675
867
|
process.exitCode = exports.CLI_EXIT.SUCCESS;
|
|
676
868
|
return;
|
|
677
869
|
}
|
|
@@ -699,6 +891,38 @@ async function runCli(argv = process.argv.slice(2), runtime = {}) {
|
|
|
699
891
|
process.exitCode = exports.CLI_EXIT.SUCCESS;
|
|
700
892
|
return;
|
|
701
893
|
}
|
|
894
|
+
if (command.command === 'profiles_list' || command.command === 'profiles_current' || command.command === 'profiles_use' || command.command === 'profiles_remove' || command.command === 'profiles_env') {
|
|
895
|
+
const path = runtimeCredentialsPath(runtime);
|
|
896
|
+
const environment = runtime.env ?? process.env;
|
|
897
|
+
if (command.command === 'profiles_list') {
|
|
898
|
+
const current = await (0, config_1.currentCredentialProfile)(path, environment);
|
|
899
|
+
const profiles = await (0, config_1.listCredentialProfiles)(path);
|
|
900
|
+
print({ ok: true, data: { current_profile: current, profiles: profiles.map(({ name, workspace }) => ({ name, workspace, active: name === current })) }, meta: {} }, stdout, Boolean(command.jsonOutput));
|
|
901
|
+
}
|
|
902
|
+
else if (command.command === 'profiles_current') {
|
|
903
|
+
print({ ok: true, data: { profile: await (0, config_1.currentCredentialProfile)(path, environment) }, meta: {} }, stdout, Boolean(command.jsonOutput));
|
|
904
|
+
}
|
|
905
|
+
else if (command.command === 'profiles_use') {
|
|
906
|
+
await (0, config_1.useCredentialProfile)(command.name, path);
|
|
907
|
+
print({ ok: true, data: { profile: command.name }, meta: {} }, stdout, Boolean(command.jsonOutput));
|
|
908
|
+
}
|
|
909
|
+
else if (command.command === 'profiles_remove') {
|
|
910
|
+
const removed = await (0, config_1.removeCredentialProfile)(command.name, path);
|
|
911
|
+
print({ ok: true, data: { profile: command.name, removed }, meta: {} }, stdout, Boolean(command.jsonOutput));
|
|
912
|
+
}
|
|
913
|
+
else {
|
|
914
|
+
const profiles = await (0, config_1.listCredentialProfiles)(path);
|
|
915
|
+
if (!profiles.some((profile) => profile.name === command.name))
|
|
916
|
+
throw new CliUsageError(`Profile not found: ${command.name}.`);
|
|
917
|
+
const result = { ok: true, data: { profile: command.name, exports: [`DREAMSTATE_PROFILE=${command.name}`] }, meta: {} };
|
|
918
|
+
if (command.jsonOutput)
|
|
919
|
+
print(result, stdout, true);
|
|
920
|
+
else
|
|
921
|
+
stdout.write(`export DREAMSTATE_PROFILE=${command.name}\n`);
|
|
922
|
+
}
|
|
923
|
+
process.exitCode = exports.CLI_EXIT.SUCCESS;
|
|
924
|
+
return;
|
|
925
|
+
}
|
|
702
926
|
if (command.command === 'login' && command.token !== undefined) {
|
|
703
927
|
const token = command.token.trim();
|
|
704
928
|
if (!(0, config_1.isDreamstateToken)(token))
|
|
@@ -715,8 +939,23 @@ async function runCli(argv = process.argv.slice(2), runtime = {}) {
|
|
|
715
939
|
onVersionWarning: (message) => stderr.write(`${message}\n`),
|
|
716
940
|
});
|
|
717
941
|
const whoami = await client.getWhoami();
|
|
718
|
-
|
|
719
|
-
|
|
942
|
+
if (command.profile)
|
|
943
|
+
await (0, config_1.storeCredentialProfile)(command.profile, token, runtimeCredentialsPath(runtime));
|
|
944
|
+
else
|
|
945
|
+
await (0, config_1.storeApiKey)(token, runtimeCredentialsPath(runtime));
|
|
946
|
+
const skills = await installLoginSkills(client, runtime, Boolean(command.noSkills), stderr);
|
|
947
|
+
print(loginResult(whoami, skills), stdout, Boolean(command.jsonOutput));
|
|
948
|
+
process.exitCode = exports.CLI_EXIT.SUCCESS;
|
|
949
|
+
return;
|
|
950
|
+
}
|
|
951
|
+
if (command.command === 'status') {
|
|
952
|
+
const environment = runtime.env ?? process.env;
|
|
953
|
+
const credentialFilePath = runtimeCredentialsPath(runtime);
|
|
954
|
+
const apiKey = await (0, config_1.resolveApiKey)(environment, credentialFilePath);
|
|
955
|
+
const workspace = await (0, config_1.resolveWorkspace)(extracted.workspace, environment, credentialFilePath);
|
|
956
|
+
const client = new client_1.DreamstateClient({ baseUrl: (0, config_1.resolveApiBaseUrl)(environment), apiKey, ...(workspace ? { workspace } : {}), requestTimeoutMs: runtime.requestTimeoutMs });
|
|
957
|
+
const [whoami, health] = await Promise.all([client.getStatusWhoami(), client.getHealth()]);
|
|
958
|
+
print({ ok: true, data: statusData(whoami, health), meta: {} }, stdout, Boolean(command.jsonOutput));
|
|
720
959
|
process.exitCode = exports.CLI_EXIT.SUCCESS;
|
|
721
960
|
return;
|
|
722
961
|
}
|
|
@@ -725,14 +964,16 @@ async function runCli(argv = process.argv.slice(2), runtime = {}) {
|
|
|
725
964
|
const key = await readLoginKey(command, runtime);
|
|
726
965
|
if (!(0, config_1.isDreamstateToken)(key))
|
|
727
966
|
throw new CliUsageError('Dreamstate API keys must start with ds_user_ or ds_live_.');
|
|
728
|
-
const path =
|
|
729
|
-
|
|
730
|
-
|
|
967
|
+
const path = command.profile
|
|
968
|
+
? await (0, config_1.storeCredentialProfile)(command.profile, key, runtimeCredentialsPath(runtime))
|
|
969
|
+
: await (0, config_1.storeApiKey)(key, runtimeCredentialsPath(runtime));
|
|
970
|
+
const client = new client_1.DreamstateClient({ baseUrl: (0, config_1.resolveApiBaseUrl)(runtime.env ?? process.env), apiKey: key, requestTimeoutMs: runtime.requestTimeoutMs, onVersionWarning: (message) => stderr.write(`${message}\n`) });
|
|
971
|
+
const skills = await installLoginSkills(client, runtime, Boolean(command.noSkills), stderr);
|
|
972
|
+
print({ ok: true, data: { credentials_path: path, skills }, meta: {} }, stdout, Boolean(command.jsonOutput));
|
|
731
973
|
process.exitCode = exports.CLI_EXIT.SUCCESS;
|
|
732
974
|
return;
|
|
733
975
|
}
|
|
734
|
-
await loginWithDeviceAuthorization(runtime, stdout, stderr);
|
|
735
|
-
stderr.write('Run dreamstate skills install to install Dreamstate skills.\n');
|
|
976
|
+
await loginWithDeviceAuthorization(runtime, stdout, stderr, command.profile, Boolean(command.noSkills), Boolean(command.jsonOutput));
|
|
736
977
|
process.exitCode = exports.CLI_EXIT.SUCCESS;
|
|
737
978
|
return;
|
|
738
979
|
}
|
|
@@ -824,7 +1065,7 @@ async function runCli(argv = process.argv.slice(2), runtime = {}) {
|
|
|
824
1065
|
result = await client.getWhoami();
|
|
825
1066
|
if (!command.jsonOutput) {
|
|
826
1067
|
const data = whoamiData(result);
|
|
827
|
-
const activeId = data.workspace_id ??
|
|
1068
|
+
const activeId = data.workspace_id ?? null;
|
|
828
1069
|
const rows = data.workspaces ?? [];
|
|
829
1070
|
stdout.write(rows.length
|
|
830
1071
|
? `${rows.map((row) => `${row.id === activeId ? '*' : ' '} ${row.slug ?? '-'} ${row.name} ${row.role ?? '-'} ${row.id}`).join('\n')}\n`
|
|
@@ -841,10 +1082,10 @@ async function runCli(argv = process.argv.slice(2), runtime = {}) {
|
|
|
841
1082
|
const match = data.workspaces?.find((row) => row.id.toLowerCase() === wanted || row.slug?.toLowerCase() === wanted);
|
|
842
1083
|
if (!match)
|
|
843
1084
|
throw new CliUsageError(`You are not a member of workspace "${command.workspace}". Run dreamstate workspaces list to see the workspaces you can use.`);
|
|
844
|
-
const stored = await (0, config_1.readStoredCredentials)(credentialFilePath);
|
|
1085
|
+
const stored = await (0, config_1.readStoredCredentials)(await (0, config_1.selectedCredentialsPath)(credentialFilePath, environment));
|
|
845
1086
|
if (!stored)
|
|
846
1087
|
throw new CliUsageError('workspaces use saves the default next to a stored login. Run dreamstate login or dreamstate login --token first.');
|
|
847
|
-
await (0, config_1.storeApiKey)(stored.token, credentialFilePath, match.id);
|
|
1088
|
+
await (0, config_1.storeApiKey)(stored.token, await (0, config_1.selectedCredentialsPath)(credentialFilePath, environment), match.id);
|
|
848
1089
|
stderr.write(`Default workspace: ${match.name} (${match.slug})\n`);
|
|
849
1090
|
result = { ok: true, data: { workspace: { id: match.id, name: match.name, slug: match.slug }, credentials_path: credentialFilePath }, meta: {} };
|
|
850
1091
|
break;
|
|
@@ -868,18 +1109,17 @@ async function runCli(argv = process.argv.slice(2), runtime = {}) {
|
|
|
868
1109
|
result = await client.searchSkillDocuments(command.query);
|
|
869
1110
|
break;
|
|
870
1111
|
case 'skills_install': {
|
|
871
|
-
|
|
872
|
-
|
|
873
|
-
|
|
874
|
-
|
|
875
|
-
|
|
876
|
-
|
|
877
|
-
throw new client_1.CliError('Dreamstate API returned no installable skills.', 'invalid_response', 200);
|
|
1112
|
+
if (command.skillId === '*') {
|
|
1113
|
+
const installed = await installHostedSkills(client, command.agents, runtime, { project: command.project, copy: command.copy });
|
|
1114
|
+
result = { ok: true, data: { installed_files: installed.files, skill_ids: installed.skillIds, agents: command.agents, ...(command.project ? { lock_file: 'skills-lock.json' } : {}) }, meta: {} };
|
|
1115
|
+
break;
|
|
1116
|
+
}
|
|
1117
|
+
const ids = [command.skillId];
|
|
878
1118
|
// A remote id becomes a directory name; refuse traversal before any request or write.
|
|
879
1119
|
if (ids.some((id) => !/^[a-z0-9][a-z0-9_-]*$/i.test(id)))
|
|
880
1120
|
throw new CliUsageError('Dreamstate API returned an invalid skill id.');
|
|
881
|
-
//
|
|
882
|
-
//
|
|
1121
|
+
// Read each skill one at a time because the workspace's private vault
|
|
1122
|
+
// admits two reads at once, and fifteen parallel reads failed in production.
|
|
883
1123
|
const skills = [];
|
|
884
1124
|
for (const id of ids) {
|
|
885
1125
|
const skill = hostedSkill(await client.getSkill(id));
|
|
@@ -937,42 +1177,67 @@ async function runCli(argv = process.argv.slice(2), runtime = {}) {
|
|
|
937
1177
|
const pending = command.turnToken
|
|
938
1178
|
? null
|
|
939
1179
|
: await (0, turnCache_1.reusableTurnToken)(turns, baseUrl, turnKey, command.capabilityId, Date.now(), warnTurnCache);
|
|
940
|
-
const
|
|
941
|
-
const
|
|
1180
|
+
const inlineRead = !command.turnToken && !pending && !command.idempotencyKey && omitsToolTurnForInlineTableRead(command.capabilityId);
|
|
1181
|
+
const fetchedForRun = command.turnToken || pending || inlineRead ? null : await client.getTool(command.capabilityId);
|
|
1182
|
+
let turnToken = command.turnToken ?? pending ?? (inlineRead ? undefined : toolTurnToken(fetchedForRun));
|
|
1183
|
+
let idempotencyKey = command.idempotencyKey ?? (inlineRead ? null : (fetchedForRun ? capabilityIdempotencyKey(fetchedForRun) : undefined));
|
|
1184
|
+
let recoveredInlineRead = false;
|
|
1185
|
+
const run = () => client.runCapability(command.capabilityId, {
|
|
1186
|
+
...command.body,
|
|
1187
|
+
...(turnToken ? { tool_turn_token: turnToken } : {}),
|
|
1188
|
+
}, idempotencyKey);
|
|
942
1189
|
try {
|
|
943
1190
|
try {
|
|
944
1191
|
result = await run();
|
|
945
1192
|
}
|
|
946
1193
|
catch (error) {
|
|
947
|
-
//
|
|
948
|
-
//
|
|
949
|
-
//
|
|
950
|
-
if (
|
|
1194
|
+
// The inline skip is only valid while the server still treats this
|
|
1195
|
+
// capability as a free sync read. capability_not_fetched means the
|
|
1196
|
+
// fetch-first fence is on, so retry once on the old get-then-run path.
|
|
1197
|
+
if (inlineRead && !recoveredInlineRead && code(error) === 'capability_not_fetched') {
|
|
1198
|
+
recoveredInlineRead = true;
|
|
1199
|
+
const fetched = await client.getTool(command.capabilityId);
|
|
1200
|
+
turnToken = toolTurnToken(fetched);
|
|
1201
|
+
idempotencyKey = command.idempotencyKey ?? capabilityIdempotencyKey(fetched);
|
|
1202
|
+
result = await run();
|
|
1203
|
+
}
|
|
1204
|
+
else if (command.body.mode !== 'live' || code(error) !== 'quote_required') {
|
|
1205
|
+
// A quote_required refusal binds a fresh quote to this turn, so the
|
|
1206
|
+
// identical call admits on the next try. Retry once here instead of
|
|
1207
|
+
// making the caller rerun the same command by hand.
|
|
951
1208
|
throw error;
|
|
952
|
-
|
|
1209
|
+
}
|
|
1210
|
+
else {
|
|
1211
|
+
result = await run();
|
|
1212
|
+
}
|
|
953
1213
|
}
|
|
954
1214
|
}
|
|
955
1215
|
catch (error) {
|
|
956
|
-
if (!command.turnToken && code(error) === 'quote_required') {
|
|
1216
|
+
if (!command.turnToken && turnToken && code(error) === 'quote_required') {
|
|
957
1217
|
await (0, turnCache_1.rememberTurnToken)(turns, baseUrl, turnKey, command.capabilityId, turnToken, Date.now(), warnTurnCache);
|
|
958
1218
|
}
|
|
959
1219
|
throw error;
|
|
960
1220
|
}
|
|
961
1221
|
if (!command.turnToken) {
|
|
962
|
-
if (command.body.mode === 'dry_run')
|
|
1222
|
+
if (command.body.mode === 'dry_run' && turnToken)
|
|
963
1223
|
await (0, turnCache_1.rememberTurnToken)(turns, baseUrl, turnKey, command.capabilityId, turnToken, Date.now(), warnTurnCache);
|
|
964
1224
|
else if (pending)
|
|
965
1225
|
await (0, turnCache_1.forgetTurnToken)(turns, baseUrl, turnKey, command.capabilityId, warnTurnCache);
|
|
966
1226
|
}
|
|
1227
|
+
if (!command.noWait && !(0, runWait_1.columnRunReturnsRunId)(command.capabilityId)) {
|
|
1228
|
+
const waited = await (0, runWait_1.waitForRun)(client, result, command.waitTimeout, runtime.sleep ?? wait);
|
|
1229
|
+
result = waited.value;
|
|
1230
|
+
if (waited.timedOut)
|
|
1231
|
+
process.exitCode = runWait_1.RUN_WAIT_TIMEOUT_EXIT_CODE;
|
|
1232
|
+
}
|
|
967
1233
|
break;
|
|
968
1234
|
}
|
|
969
1235
|
case 'tables_import': {
|
|
970
1236
|
await (0, promises_1.access)(command.file);
|
|
971
|
-
|
|
972
|
-
|
|
973
|
-
|
|
974
|
-
|
|
975
|
-
const importCapabilityId = discoveredCapabilityId(discovered);
|
|
1237
|
+
// Search ranking is not an import contract. This exact capability owns the
|
|
1238
|
+
// prepare handoff for caller-local files, while nearby upload capabilities
|
|
1239
|
+
// can also match these words and made a real import fail after local work.
|
|
1240
|
+
const importCapabilityId = 'tables.table_sources.csv_import_prepare';
|
|
976
1241
|
result = await client.runCapability(importCapabilityId, {
|
|
977
1242
|
// A mutation run needs the turn token its own get minted; without it
|
|
978
1243
|
// an API-key import was refused after the local file work.
|
|
@@ -1002,15 +1267,20 @@ async function runCli(argv = process.argv.slice(2), runtime = {}) {
|
|
|
1002
1267
|
case 'runs_events':
|
|
1003
1268
|
result = await client.getRunEvents(command.runId);
|
|
1004
1269
|
break;
|
|
1005
|
-
case 'runs_cancel':
|
|
1006
|
-
|
|
1270
|
+
case 'runs_cancel': {
|
|
1271
|
+
const body = command.body ?? {
|
|
1272
|
+
expected_state_version: command.stateVersion ?? stateVersionFromRunRead(await client.getRun(command.runId)),
|
|
1273
|
+
...(command.reason ? { reason: command.reason } : {}),
|
|
1274
|
+
};
|
|
1275
|
+
result = await client.cancelRun(command.runId, body, command.idempotencyKey);
|
|
1007
1276
|
break;
|
|
1277
|
+
}
|
|
1008
1278
|
case 'pack': {
|
|
1009
1279
|
if (command.pack === 'sequences') {
|
|
1010
|
-
await require('./commands/sequences').runSequencesCommand(client, command, stdout);
|
|
1280
|
+
await require('./commands/sequences').runSequencesCommand(client, command, stdout, runtime.sleep ?? wait);
|
|
1011
1281
|
}
|
|
1012
1282
|
else {
|
|
1013
|
-
await require('./commands/workflows').runWorkflowsCommand(client, command, stdout);
|
|
1283
|
+
await require('./commands/workflows').runWorkflowsCommand(client, command, stdout, runtime.sleep ?? wait);
|
|
1014
1284
|
}
|
|
1015
1285
|
return;
|
|
1016
1286
|
}
|
|
@@ -1022,7 +1292,8 @@ async function runCli(argv = process.argv.slice(2), runtime = {}) {
|
|
|
1022
1292
|
printPackRoute(result, stdout);
|
|
1023
1293
|
else
|
|
1024
1294
|
print(result, stdout, Boolean(command.jsonOutput));
|
|
1025
|
-
process.exitCode
|
|
1295
|
+
if (process.exitCode !== runWait_1.RUN_WAIT_TIMEOUT_EXIT_CODE)
|
|
1296
|
+
process.exitCode = exports.CLI_EXIT.SUCCESS;
|
|
1026
1297
|
}
|
|
1027
1298
|
catch (error) {
|
|
1028
1299
|
const exitCode = exitCodeForError(error);
|
|
@@ -0,0 +1,9 @@
|
|
|
1
|
+
import type { DreamstateClient } from './client';
|
|
2
|
+
export declare const RUN_WAIT_TIMEOUT_EXIT_CODE = 8;
|
|
3
|
+
export declare function columnRunReturnsRunId(capabilityId: string): boolean;
|
|
4
|
+
export interface RunWaitResult {
|
|
5
|
+
value: unknown;
|
|
6
|
+
timedOut: boolean;
|
|
7
|
+
}
|
|
8
|
+
export declare function waitForRun(client: DreamstateClient, initial: unknown, timeoutSeconds: number, sleep: (milliseconds: number) => Promise<void>): Promise<RunWaitResult>;
|
|
9
|
+
//# sourceMappingURL=runWait.d.ts.map
|