@trydreamstate/cli 1.3.2 → 1.3.4
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 +36 -16
- package/agent-plugin/.claude-plugin/plugin.json +1 -1
- package/agent-plugin/.codex-plugin/plugin.json +1 -1
- package/agent-plugin/hooks/approve-readonly.sh +15 -0
- package/agent-plugin/hooks/hooks.json +17 -0
- package/agent-plugin/skills/crm/SKILL.md +2 -2
- package/agent-plugin/skills/diagnostics/SKILL.md +3 -1
- package/agent-plugin/skills/dreamstate/SKILL.md +15 -5
- package/agent-plugin/skills/first-win/SKILL.md +2 -2
- package/agent-plugin/skills/inbox-replies/SKILL.md +3 -1
- package/agent-plugin/skills/knowledge/SKILL.md +3 -5
- package/agent-plugin/skills/linkedin-posts/SKILL.md +3 -1
- package/agent-plugin/skills/linkedin-warm-signals/SKILL.md +2 -2
- package/agent-plugin/skills/list-building/SKILL.md +5 -10
- package/agent-plugin/skills/list-building/column-authoring.md +1 -1
- package/agent-plugin/skills/list-building/sourcing.md +2 -2
- package/agent-plugin/skills/outreach/SKILL.md +2 -2
- package/agent-plugin/skills/outreach/steps-and-timing.md +1 -1
- package/agent-plugin/skills/plays/SKILL.md +3 -3
- package/agent-plugin/skills/reddit-posts/SKILL.md +3 -1
- package/agent-plugin/skills/skill-authoring/SKILL.md +3 -1
- package/agent-plugin/skills/social/SKILL.md +4 -6
- package/agent-plugin/skills/visibility/SKILL.md +2 -6
- package/agent-plugin/skills/workflows/SKILL.md +3 -3
- package/agent-plugin/skills/workflows/lifecycle-and-enrollment.md +1 -1
- package/agent-plugin/skills/worksheet-tidy/SKILL.md +3 -1
- package/agent-plugin/skills/writing/SKILL.md +3 -5
- package/agent-plugin/skills/x-posts/SKILL.md +3 -1
- package/dist/agentGuidance.generated.json +35 -0
- package/dist/capabilityPosture.d.ts +12 -0
- package/dist/capabilityPosture.d.ts.map +1 -0
- package/dist/capabilityPosture.js +39 -0
- package/dist/client.d.ts +33 -2
- package/dist/client.d.ts.map +1 -1
- package/dist/client.js +155 -64
- package/dist/commandTable.d.ts +26 -0
- package/dist/commandTable.d.ts.map +1 -0
- package/dist/commandTable.js +54 -0
- package/dist/commands/sequences.d.ts +3 -2
- package/dist/commands/sequences.d.ts.map +1 -1
- package/dist/commands/sequences.js +17 -34
- package/dist/commands/shared.d.ts +4 -26
- package/dist/commands/shared.d.ts.map +1 -1
- package/dist/commands/shared.js +136 -158
- package/dist/commands/workflows.d.ts +3 -2
- package/dist/commands/workflows.d.ts.map +1 -1
- package/dist/commands/workflows.js +17 -39
- package/dist/errors.d.ts +74 -0
- package/dist/errors.d.ts.map +1 -0
- package/dist/errors.js +84 -0
- package/dist/gatedRun.d.ts +79 -0
- package/dist/gatedRun.d.ts.map +1 -0
- package/dist/gatedRun.js +346 -0
- package/dist/generated/packVerbs.generated.json +492 -0
- package/dist/generated/runContract.generated.d.ts +4 -0
- package/dist/generated/runContract.generated.d.ts.map +1 -0
- package/dist/generated/runContract.generated.js +7 -0
- package/dist/idempotency.d.ts +38 -0
- package/dist/idempotency.d.ts.map +1 -0
- package/dist/idempotency.js +106 -0
- package/dist/index.d.ts +22 -35
- package/dist/index.d.ts.map +1 -1
- package/dist/index.js +405 -378
- package/dist/registryManifest.d.ts +6 -0
- package/dist/registryManifest.d.ts.map +1 -0
- package/dist/registryManifest.js +66 -0
- package/dist/runContract.d.ts +10 -0
- package/dist/runContract.d.ts.map +1 -0
- package/dist/runContract.js +13 -0
- package/dist/runWait.d.ts +2 -2
- package/dist/runWait.d.ts.map +1 -1
- package/dist/runWait.js +3 -14
- package/dist/schemaCoercion.d.ts +20 -0
- package/dist/schemaCoercion.d.ts.map +1 -0
- package/dist/schemaCoercion.js +123 -0
- package/dist/skillInstaller.d.ts +40 -0
- package/dist/skillInstaller.d.ts.map +1 -1
- package/dist/skillInstaller.js +108 -9
- package/dist/tableFilePreview.d.ts +14 -0
- package/dist/tableFilePreview.d.ts.map +1 -1
- package/dist/tableFilePreview.js +19 -8
- package/dist/tableFileReader.d.ts +26 -0
- package/dist/tableFileReader.d.ts.map +1 -0
- package/dist/tableFileReader.js +108 -0
- package/dist/tablesImport.d.ts +57 -0
- package/dist/tablesImport.d.ts.map +1 -0
- package/dist/tablesImport.js +263 -0
- package/dist/turnCache.d.ts +14 -1
- package/dist/turnCache.d.ts.map +1 -1
- package/dist/turnCache.js +25 -8
- package/package.json +6 -3
package/dist/commands/shared.js
CHANGED
|
@@ -11,9 +11,11 @@ const node_util_1 = require("node:util");
|
|
|
11
11
|
// main and no generator, so they still carry pre-cutover spellings, and
|
|
12
12
|
// audit:canonical-cutover:clean treats importing them as a release blocker.
|
|
13
13
|
const index_1 = require("../index");
|
|
14
|
+
const errors_1 = require("../errors");
|
|
15
|
+
const gatedRun_1 = require("../gatedRun");
|
|
14
16
|
const node_fs_1 = require("node:fs");
|
|
15
17
|
const runWait_1 = require("../runWait");
|
|
16
|
-
const
|
|
18
|
+
const runContract_1 = require("../runContract");
|
|
17
19
|
function parseObject(raw, flag) {
|
|
18
20
|
try {
|
|
19
21
|
const value = JSON.parse(raw);
|
|
@@ -22,153 +24,147 @@ function parseObject(raw, flag) {
|
|
|
22
24
|
return value;
|
|
23
25
|
}
|
|
24
26
|
catch (error) {
|
|
25
|
-
throw new
|
|
27
|
+
throw new errors_1.CliUsageError(`${flag} ${error instanceof Error ? error.message : 'is invalid JSON'}`);
|
|
26
28
|
}
|
|
27
29
|
}
|
|
28
|
-
|
|
29
|
-
|
|
30
|
-
|
|
31
|
-
|
|
32
|
-
|
|
33
|
-
|
|
30
|
+
/**
|
|
31
|
+
* Canonical parameter flags are deliberately open-ended. A pack verb only owns
|
|
32
|
+
* its route and positional aliases; `--field-name value` becomes `field_name` and
|
|
33
|
+
* is checked against the live `tools get` schema before execution. This keeps a
|
|
34
|
+
* newly published schema field usable without another CLI flag-table release.
|
|
35
|
+
*/
|
|
36
|
+
function takeSchemaFlags(argv, known) {
|
|
37
|
+
const kept = [];
|
|
38
|
+
const params = {};
|
|
39
|
+
for (let index = 0; index < argv.length; index += 1) {
|
|
40
|
+
const token = argv[index];
|
|
41
|
+
if (!token.startsWith('--') || token === '--' || known.has(token.slice(2).split('=', 1)[0])) {
|
|
42
|
+
kept.push(token);
|
|
43
|
+
continue;
|
|
44
|
+
}
|
|
45
|
+
const equals = token.indexOf('=');
|
|
46
|
+
const name = (equals < 0 ? token.slice(2) : token.slice(2, equals)).replace(/-/g, '_');
|
|
47
|
+
if (!name) {
|
|
48
|
+
kept.push(token);
|
|
49
|
+
continue;
|
|
50
|
+
}
|
|
51
|
+
if (name === 'agent_session_id') {
|
|
52
|
+
throw new errors_1.CliUsageError('--agent-session-id is not accepted by the CLI: only the in-app Architect may name an Architect session.');
|
|
53
|
+
}
|
|
54
|
+
if (equals >= 0) {
|
|
55
|
+
params[name] = token.slice(equals + 1);
|
|
56
|
+
continue;
|
|
57
|
+
}
|
|
58
|
+
const value = argv[index + 1];
|
|
59
|
+
if (value !== undefined && !value.startsWith('--')) {
|
|
60
|
+
params[name] = value;
|
|
61
|
+
index += 1;
|
|
62
|
+
}
|
|
63
|
+
else
|
|
64
|
+
params[name] = true;
|
|
34
65
|
}
|
|
66
|
+
return { argv: kept, params };
|
|
35
67
|
}
|
|
36
68
|
function parseMode(value) {
|
|
37
69
|
if (value === undefined)
|
|
38
70
|
return undefined;
|
|
39
|
-
if (
|
|
71
|
+
if (runContract_1.RUN_MODES.includes(value))
|
|
40
72
|
return value;
|
|
41
|
-
throw new
|
|
73
|
+
throw new errors_1.CliUsageError(`--mode must be one of: ${runContract_1.RUN_MODES.join(', ')}`);
|
|
42
74
|
}
|
|
43
75
|
function buildPackParser(pack, kind, specs, usage) {
|
|
44
76
|
return (argv) => {
|
|
45
77
|
const spec = specs.find((candidate) => candidate.verb === argv[0]);
|
|
46
78
|
if (!spec)
|
|
47
|
-
throw new
|
|
79
|
+
throw new errors_1.CliUsageError(`Unknown ${pack} verb: ${argv[0] ?? '(missing)'}\n${usage}`);
|
|
80
|
+
// The door inputs here are the same ones `tools run` takes (parseTools in index.ts),
|
|
81
|
+
// and they reach the same gate (runGated): a verb is never a quieter way to run.
|
|
48
82
|
const options = {
|
|
49
|
-
mode: { type: 'string' }, 'dry-run': { type: 'boolean' }, live: { type: 'boolean' },
|
|
83
|
+
mode: { type: 'string' }, 'dry-run': { type: 'boolean' }, live: { type: 'boolean' },
|
|
50
84
|
'idempotency-key': { type: 'string' }, 'max-credits': { type: 'string' }, params: { type: 'string' },
|
|
85
|
+
'max-live-sends': { type: 'string' },
|
|
86
|
+
approved: { type: 'boolean' }, 'approval-id': { type: 'string' }, 'approved-effect-unknown': { type: 'boolean' },
|
|
87
|
+
'quote-hash': { type: 'string' }, 'turn-token': { type: 'string' },
|
|
51
88
|
'wait-timeout': { type: 'string' }, 'no-wait': { type: 'boolean' }, 'json-output': { type: 'boolean' }, open: { type: 'boolean' }, help: { type: 'boolean', short: 'h' },
|
|
52
89
|
};
|
|
53
|
-
|
|
54
|
-
// whole authored document can be linted or imported straight off disk instead of
|
|
55
|
-
// being pasted through the shell. The competitor authors this way and it is the
|
|
56
|
-
// only thing their file workflow had that ours did not.
|
|
57
|
-
// A verb that declares its own `file` flag owns the name, for example init, whose
|
|
58
|
-
// --file is where the scaffold is written rather than a document to read.
|
|
59
|
-
const declaresOwnFile = Object.keys(spec.flags ?? {}).includes('file');
|
|
60
|
-
const jsonFlag = declaresOwnFile
|
|
61
|
-
? undefined
|
|
62
|
-
: Object.entries(spec.flags ?? {}).find(([, definition]) => definition.document === true);
|
|
63
|
-
if (!declaresOwnFile)
|
|
64
|
-
options.file = { type: 'string' };
|
|
65
|
-
for (const [flag, definition] of Object.entries(spec.flags ?? {}))
|
|
66
|
-
options[flag] = { type: definition.type };
|
|
90
|
+
const schemaFlags = takeSchemaFlags(argv.slice(1), new Set(Object.keys(options)));
|
|
67
91
|
let values;
|
|
68
92
|
let positionals;
|
|
69
93
|
try {
|
|
70
|
-
({ values, positionals } = (0, node_util_1.parseArgs)({ args: argv
|
|
94
|
+
({ values, positionals } = (0, node_util_1.parseArgs)({ args: schemaFlags.argv, options, allowPositionals: true, strict: true }));
|
|
71
95
|
}
|
|
72
96
|
catch (error) {
|
|
73
|
-
|
|
97
|
+
// parseArgs raises a TypeError whose class can come from another realm, so read the message
|
|
98
|
+
// instead of trusting instanceof: otherwise the user sees 'Invalid arguments.' and not the flag.
|
|
99
|
+
const reason = error?.message;
|
|
100
|
+
throw new errors_1.CliUsageError(`${typeof reason === 'string' && reason ? reason : 'Invalid arguments.'}\n${usage}`);
|
|
74
101
|
}
|
|
75
102
|
const mode = values.mode;
|
|
76
103
|
const dryRun = values['dry-run'];
|
|
77
104
|
const live = values.live;
|
|
78
|
-
const agentSessionId = values['agent-session-id'];
|
|
79
105
|
const idempotencyKey = values['idempotency-key'];
|
|
106
|
+
if (idempotencyKey !== undefined && idempotencyKey.length > runContract_1.IDEMPOTENCY_KEY_MAX_LENGTH) {
|
|
107
|
+
throw new errors_1.CliUsageError(`--idempotency-key must be at most ${runContract_1.IDEMPOTENCY_KEY_MAX_LENGTH} characters`);
|
|
108
|
+
}
|
|
80
109
|
const rawParams = values.params;
|
|
81
110
|
const rawMaxCredits = values['max-credits'];
|
|
111
|
+
const rawMaxLiveSends = values['max-live-sends'];
|
|
82
112
|
const rawWaitTimeout = values['wait-timeout'];
|
|
83
113
|
if (values.help)
|
|
84
114
|
return { command: 'pack_help', usage, ...(values['json-output'] ? { jsonOutput: true } : {}) };
|
|
85
|
-
for (const [flag, definition] of Object.entries(spec.flags ?? {})) {
|
|
86
|
-
if (definition.required && values[flag] === undefined)
|
|
87
|
-
throw new index_1.CliUsageError(`--${flag} is required for ${pack} ${spec.verb}.\n${usage}`);
|
|
88
|
-
}
|
|
89
115
|
const positional = spec.positional ?? [];
|
|
90
|
-
// A document supplied inline or from a file is authored, not saved, so there is no
|
|
91
|
-
// id to name yet. lint and its kin accept a hypothetical document, which is the
|
|
92
|
-
// whole point of authoring in a file before anything exists in the workspace.
|
|
93
|
-
const documentSupplied = values.file !== undefined
|
|
94
|
-
|| (jsonFlag !== undefined && values[jsonFlag[0]] !== undefined);
|
|
95
116
|
const requiredPositionals = positional.filter((definition) => definition.optional !== true).length;
|
|
96
117
|
const positionalsAcceptable = positionals.length <= positional.length
|
|
97
|
-
&&
|
|
118
|
+
&& positionals.length >= requiredPositionals;
|
|
98
119
|
if (!positionalsAcceptable)
|
|
99
|
-
throw new
|
|
120
|
+
throw new errors_1.CliUsageError(`Usage: ${usage}`);
|
|
100
121
|
if ((mode && (dryRun || live)) || (dryRun && live)) {
|
|
101
|
-
throw new
|
|
122
|
+
throw new errors_1.CliUsageError('Use exactly one of --mode, --dry-run, or --live.');
|
|
102
123
|
}
|
|
103
|
-
const input = rawParams ? parseObject(rawParams, '--params') : {};
|
|
124
|
+
const input = { ...(rawParams ? parseObject(rawParams, '--params') : {}), ...schemaFlags.params };
|
|
104
125
|
positional.forEach((definition, index) => {
|
|
105
126
|
const value = positionals[index];
|
|
106
127
|
if (value !== undefined)
|
|
107
128
|
input[definition.into] = value;
|
|
108
129
|
});
|
|
109
|
-
for (const [flag, definition] of Object.entries(spec.flags ?? {})) {
|
|
110
|
-
const value = values[flag];
|
|
111
|
-
if (value === undefined)
|
|
112
|
-
continue;
|
|
113
|
-
if (definition.json) {
|
|
114
|
-
input[definition.into] = parseJson(String(value), `--${flag}`);
|
|
115
|
-
}
|
|
116
|
-
else if (definition.number) {
|
|
117
|
-
const parsedNumber = Number(String(value));
|
|
118
|
-
if (!Number.isFinite(parsedNumber))
|
|
119
|
-
throw new index_1.CliUsageError(`--${flag} must be a number`);
|
|
120
|
-
input[definition.into] = parsedNumber;
|
|
121
|
-
}
|
|
122
|
-
else {
|
|
123
|
-
input[definition.into] = value;
|
|
124
|
-
}
|
|
125
|
-
}
|
|
126
|
-
const filePath = declaresOwnFile ? undefined : values.file;
|
|
127
|
-
if (filePath !== undefined) {
|
|
128
|
-
if (jsonFlag && values[jsonFlag[0]] !== undefined) {
|
|
129
|
-
throw new index_1.CliUsageError(`Use either --${jsonFlag[0]} or --file, not both.`);
|
|
130
|
-
}
|
|
131
|
-
let contents;
|
|
132
|
-
try {
|
|
133
|
-
contents = (0, node_fs_1.readFileSync)(filePath, 'utf8');
|
|
134
|
-
}
|
|
135
|
-
catch (error) {
|
|
136
|
-
throw new index_1.CliUsageError(`--file could not be read: ${error instanceof Error ? error.message : String(error)}`);
|
|
137
|
-
}
|
|
138
|
-
const parsed = parseJson(contents, `--file ${filePath}`);
|
|
139
|
-
if (jsonFlag) {
|
|
140
|
-
input[jsonFlag[1].into] = parsed;
|
|
141
|
-
}
|
|
142
|
-
else if (parsed && typeof parsed === 'object' && !Array.isArray(parsed)) {
|
|
143
|
-
// A verb with no single document flag spreads the file's fields across its
|
|
144
|
-
// params, which is what `dreamstate <pack> init` writes and what `create`
|
|
145
|
-
// needs: name and steps are separate params there, not one document. Without
|
|
146
|
-
// this, the scaffold composed with no verb at all.
|
|
147
|
-
Object.assign(input, parsed);
|
|
148
|
-
}
|
|
149
|
-
else {
|
|
150
|
-
throw new index_1.CliUsageError(`--file for ${pack} ${spec.verb} must contain a JSON object of params.`);
|
|
151
|
-
}
|
|
152
|
-
}
|
|
153
130
|
// kind is the discriminator of the SHARED authoring family only. The
|
|
154
131
|
// family-specific capabilities have strict schemas that do not declare it,
|
|
155
132
|
// so injecting it everywhere made every one of those verbs fail validation
|
|
156
133
|
// with an unrecognized key before it reached the server's real work.
|
|
157
134
|
if (spec.capabilityId.startsWith('workflow.automations.'))
|
|
158
135
|
input.kind = kind;
|
|
136
|
+
// No default mode. A mutating verb run with no mode used to be rewritten to dry_run
|
|
137
|
+
// silently, where `tools run` sends none and lets the server answer mode_required
|
|
138
|
+
// with its repair; one rule for both now, so a person is told to choose.
|
|
159
139
|
const explicitMode = dryRun ? 'dry_run' : live ? 'live' : parseMode(mode);
|
|
160
140
|
const maxCredits = rawMaxCredits === undefined ? undefined : Number(rawMaxCredits);
|
|
161
141
|
if (maxCredits !== undefined && (!Number.isFinite(maxCredits) || maxCredits < 0))
|
|
162
|
-
throw new
|
|
142
|
+
throw new errors_1.CliUsageError('--max-credits must be a non-negative number');
|
|
143
|
+
const maxLiveSends = rawMaxLiveSends === undefined ? undefined : Number(rawMaxLiveSends);
|
|
144
|
+
if (maxLiveSends !== undefined && (!Number.isInteger(maxLiveSends) || maxLiveSends < 1))
|
|
145
|
+
throw new errors_1.CliUsageError('--max-live-sends must be an integer greater than or equal to 1');
|
|
146
|
+
const quoteHash = values['quote-hash'];
|
|
147
|
+
if (quoteHash !== undefined && !runContract_1.QUOTE_HASH_PATTERN.test(quoteHash))
|
|
148
|
+
throw new errors_1.CliUsageError('--quote-hash must be the sha256:<64 hex> quote_hash a dry run returned');
|
|
149
|
+
const approvalId = values['approval-id'];
|
|
150
|
+
if (approvalId !== undefined && !/^[0-9a-f]{8}-[0-9a-f]{4}-[0-9a-f]{4}-[0-9a-f]{4}-[0-9a-f]{12}$/i.test(approvalId))
|
|
151
|
+
throw new errors_1.CliUsageError('--approval-id must be the uuid of a recorded approval');
|
|
163
152
|
const waitTimeout = rawWaitTimeout === undefined ? 120 : Number(rawWaitTimeout);
|
|
164
153
|
if (!Number.isFinite(waitTimeout) || waitTimeout < 0)
|
|
165
|
-
throw new
|
|
154
|
+
throw new errors_1.CliUsageError('--wait-timeout must be a non-negative number');
|
|
166
155
|
return {
|
|
167
156
|
command: 'pack', pack, verb: spec.verb, capabilityId: spec.capabilityId, input,
|
|
168
|
-
...(explicitMode ? { mode: explicitMode } :
|
|
169
|
-
|
|
157
|
+
...(explicitMode ? { mode: explicitMode } : {}),
|
|
158
|
+
// --approved is the caller's assertion that a person saw the dry run and agreed. It only
|
|
159
|
+
// means something on a live run, so no other mode ever sends it (same rule as tools run).
|
|
160
|
+
...(values.approved && explicitMode === 'live' ? { approved: true } : {}),
|
|
161
|
+
...(approvalId ? { approvalId } : {}),
|
|
162
|
+
...(values['approved-effect-unknown'] ? { approvedEffectUnknown: true } : {}),
|
|
163
|
+
...(quoteHash ? { quoteHash } : {}),
|
|
164
|
+
...(values['turn-token'] ? { turnToken: values['turn-token'] } : {}),
|
|
170
165
|
...(idempotencyKey ? { idempotencyKey } : {}),
|
|
171
166
|
...(maxCredits === undefined ? {} : { maxCredits }), ...(values['json-output'] ? { jsonOutput: true } : {}),
|
|
167
|
+
...(maxLiveSends === undefined ? {} : { maxLiveSends }),
|
|
172
168
|
waitTimeout, ...(values['no-wait'] ? { noWait: true } : {}),
|
|
173
169
|
...(values.open ? { open: true } : {}),
|
|
174
170
|
};
|
|
@@ -181,47 +177,21 @@ function buildPackParser(pack, kind, specs, usage) {
|
|
|
181
177
|
* usefully, rather than to guess a valid sequence on the caller's behalf.
|
|
182
178
|
*/
|
|
183
179
|
function packScaffold(kind, name) {
|
|
184
|
-
//
|
|
185
|
-
// channel/action under `fields` and omitted the id, and the document it wrote was
|
|
186
|
-
// refused by our own lint with `node_contract_unresolved: Node unknown has no
|
|
187
|
-
// canonical node-contract mapping`, because canonicalSequenceStepContractNode reads
|
|
188
|
-
// step.kind and step.action off the step itself. A scaffold whose output the next
|
|
189
|
-
// command in its own printed next_steps rejects is worse than no scaffold.
|
|
180
|
+
// Empty graph. Step and node shapes belong to the server contract, not a second copy here.
|
|
190
181
|
return kind === 'sequence'
|
|
191
|
-
? {
|
|
192
|
-
|
|
193
|
-
name,
|
|
194
|
-
steps: [
|
|
195
|
-
{
|
|
196
|
-
id: 'step_1',
|
|
197
|
-
kind: 'email',
|
|
198
|
-
channel: 'email',
|
|
199
|
-
action: 'send_email',
|
|
200
|
-
subject_template: 'Quick question, {{first_name}}',
|
|
201
|
-
body_template: 'Hi {{first_name}},\n\nWould this be useful to you?',
|
|
202
|
-
},
|
|
203
|
-
],
|
|
204
|
-
}
|
|
205
|
-
: {
|
|
206
|
-
kind: 'workflow',
|
|
207
|
-
name,
|
|
208
|
-
nodes: [
|
|
209
|
-
{ id: 'trigger-root', type: 'trigger', position: { x: 0, y: 0 }, data: { kind: 'trigger', subtype: 'table', config: {} } },
|
|
210
|
-
{ id: 'action-example', type: 'action', position: { x: 0, y: 160 }, data: { kind: 'action', subtype: 'send_connection_request_to_contact', config: {} } },
|
|
211
|
-
],
|
|
212
|
-
edges: [{ id: 'edge-trigger-action', source: 'trigger-root', target: 'action-example' }],
|
|
213
|
-
};
|
|
182
|
+
? { kind: 'sequence', name, steps: [] }
|
|
183
|
+
: { kind: 'workflow', name, nodes: [], edges: [] };
|
|
214
184
|
}
|
|
215
185
|
function runPackInit(kind, command, stdout) {
|
|
216
186
|
if (command.command !== 'pack')
|
|
217
|
-
throw new
|
|
187
|
+
throw new errors_1.CliUsageError('Pack command required.');
|
|
218
188
|
const input = command.input;
|
|
219
189
|
const name = typeof input.name === 'string' && input.name.trim() ? input.name.trim() : `My ${kind}`;
|
|
220
190
|
const target = typeof input.file === 'string' && input.file.trim()
|
|
221
191
|
? input.file.trim()
|
|
222
192
|
: `./${kind}.json`;
|
|
223
193
|
if ((0, node_fs_1.existsSync)(target)) {
|
|
224
|
-
throw new
|
|
194
|
+
throw new errors_1.CliUsageError(`${target} already exists. Pass --file <path> to write somewhere else.`);
|
|
225
195
|
}
|
|
226
196
|
const document = packScaffold(kind, name);
|
|
227
197
|
(0, node_fs_1.writeFileSync)(target, `${JSON.stringify(document, null, 2)}\n`, 'utf8');
|
|
@@ -237,27 +207,25 @@ function runPackInit(kind, command, stdout) {
|
|
|
237
207
|
},
|
|
238
208
|
}, null, command.jsonOutput ? 0 : 2)}\n`);
|
|
239
209
|
}
|
|
240
|
-
|
|
210
|
+
/**
|
|
211
|
+
* Verbs whose request needs the current version ids of the thing they act on.
|
|
212
|
+
* Keyed by the capability the verb runs, never by the verb's name: `sequences
|
|
213
|
+
* publish` and `workflows publish` share a name and nothing else (the sequence
|
|
214
|
+
* one takes sequence_id and needs no read; it was once caught by the workflow
|
|
215
|
+
* branch and refused with "workflows publish requires <id>").
|
|
216
|
+
*/
|
|
217
|
+
const WORKFLOW_PUBLISH = 'workflow.workflows.draft_publish';
|
|
218
|
+
const WORKFLOW_ACTIVATE = 'workflow.workflows.activate';
|
|
219
|
+
async function runPackCommand(context, command, stdout) {
|
|
241
220
|
if (command.command !== 'pack')
|
|
242
|
-
throw new
|
|
243
|
-
|
|
244
|
-
// tools run path does. Without it the server refuses capability_not_fetched,
|
|
245
|
-
// which made every pack verb unusable even though its capability id was right.
|
|
246
|
-
const { toolTurnToken, capabilityIdempotencyKey } = require('../index');
|
|
247
|
-
if (command.verb === 'activate' && command.input.max_credits === undefined) {
|
|
248
|
-
throw new index_1.CliUsageError('workflows activate requires --max-credits <n>.');
|
|
249
|
-
}
|
|
250
|
-
if (command.verb === 'publish' || command.verb === 'activate') {
|
|
221
|
+
throw new errors_1.CliUsageError('Pack command required.');
|
|
222
|
+
if (command.capabilityId === WORKFLOW_PUBLISH || command.capabilityId === WORKFLOW_ACTIVATE) {
|
|
251
223
|
const workflowId = command.input.workflow_id;
|
|
252
224
|
if (typeof workflowId !== 'string')
|
|
253
|
-
throw new
|
|
254
|
-
const
|
|
255
|
-
const current = await client.runCapability('workflow.automations.get', {
|
|
256
|
-
params: { kind: 'workflow', automation_id: workflowId },
|
|
257
|
-
tool_turn_token: toolTurnToken(readFetched),
|
|
258
|
-
}, capabilityIdempotencyKey(readFetched));
|
|
225
|
+
throw new errors_1.CliUsageError(`${command.pack} ${command.verb} requires <id>.`);
|
|
226
|
+
const current = await (0, gatedRun_1.readCapability)(context, 'workflow.automations.get', { kind: 'workflow', automation_id: workflowId }, command.waitTimeout);
|
|
259
227
|
const workflow = workflowFromGet(current);
|
|
260
|
-
if (command.
|
|
228
|
+
if (command.capabilityId === WORKFLOW_PUBLISH) {
|
|
261
229
|
command.input.expected_draft_version_id ??= nullableString(workflow.latest_draft_version_id, 'latest_draft_version_id');
|
|
262
230
|
command.input.expected_active_version_id ??= nullableString(workflow.active_version_id, 'active_version_id');
|
|
263
231
|
}
|
|
@@ -265,19 +233,30 @@ async function runPackCommand(client, command, stdout, sleep = (milliseconds) =>
|
|
|
265
233
|
command.input.expected_version_id ??= requiredString(workflow.active_version_id, 'active_version_id');
|
|
266
234
|
}
|
|
267
235
|
}
|
|
268
|
-
const
|
|
269
|
-
const
|
|
270
|
-
|
|
271
|
-
|
|
272
|
-
|
|
273
|
-
|
|
274
|
-
|
|
275
|
-
|
|
276
|
-
|
|
277
|
-
|
|
278
|
-
|
|
279
|
-
|
|
280
|
-
|
|
236
|
+
const maxCredits = command.maxCredits;
|
|
237
|
+
const outcome = await (0, gatedRun_1.runGated)(context, {
|
|
238
|
+
capabilityId: command.capabilityId,
|
|
239
|
+
body: {
|
|
240
|
+
params: {
|
|
241
|
+
...command.input,
|
|
242
|
+
...(command.maxLiveSends === undefined ? {} : { max_live_sends: command.maxLiveSends }),
|
|
243
|
+
},
|
|
244
|
+
...(command.mode ? { mode: command.mode } : {}),
|
|
245
|
+
...(maxCredits === undefined ? {} : { max_credits: maxCredits }),
|
|
246
|
+
...(command.approved ? { approved: true } : {}),
|
|
247
|
+
...(command.approvalId ? { approval_id: command.approvalId } : {}),
|
|
248
|
+
...(command.approvedEffectUnknown ? { approved_effect_unknown: true } : {}),
|
|
249
|
+
...(command.quoteHash ? { quote_hash: command.quoteHash } : {}),
|
|
250
|
+
},
|
|
251
|
+
...(command.turnToken ? { turnToken: command.turnToken } : {}),
|
|
252
|
+
...(command.idempotencyKey ? { idempotencyKey: command.idempotencyKey } : {}),
|
|
253
|
+
waitTimeout: command.waitTimeout,
|
|
254
|
+
...(command.noWait ? { noWait: true } : {}),
|
|
255
|
+
coerceParams: true,
|
|
256
|
+
});
|
|
257
|
+
const result = outcome.value;
|
|
258
|
+
if (outcome.timedOut)
|
|
259
|
+
process.exitCode = runWait_1.RUN_WAIT_TIMEOUT_EXIT_CODE;
|
|
281
260
|
const output = command.mode === 'dry_run' && result && typeof result === 'object' && !Array.isArray(result)
|
|
282
261
|
? { ...result, meta: { ...(result.meta ?? {}), dry_run: true, note: 'dry_run: true, rerun with --live to apply' } }
|
|
283
262
|
: result;
|
|
@@ -292,15 +271,14 @@ async function runPackCommand(client, command, stdout, sleep = (milliseconds) =>
|
|
|
292
271
|
const root = result && typeof result === 'object' ? result : {};
|
|
293
272
|
const webUrl = root.meta?.web_url ?? root.data?.web_url;
|
|
294
273
|
if (typeof webUrl !== 'string')
|
|
295
|
-
throw new
|
|
274
|
+
throw new errors_1.CliUsageError('The API response did not include a web_url.');
|
|
296
275
|
(0, index_1.openWebUrl)(webUrl);
|
|
297
276
|
}
|
|
298
277
|
}
|
|
299
278
|
function renderPackUsage(pack, specs) {
|
|
300
|
-
return `Usage: dreamstate ${pack} <verb> [args] [
|
|
279
|
+
return `Usage: dreamstate ${pack} <verb> [args] [--canonical-field value]\nRequired positionals use <name:field>. Optional positionals use [name:field]. Remote fields, types, required fields and descriptions come from \`dreamstate tools get <capability_id>\`. Run responses wait by default, use --wait-timeout <seconds> (default 120) or --no-wait.\n\nVerbs:\n${specs.map((spec) => {
|
|
301
280
|
const positionals = (spec.positional ?? []).map(({ name, into, optional }) => `${optional ? '[' : '<'}${name}:${into}${optional ? ']' : '>'}`).join(' ');
|
|
302
|
-
|
|
303
|
-
return ` ${spec.verb.padEnd(18)} ${[positionals, flags].filter(Boolean).join(' ')}\n${' '.repeat(20)}${spec.summary} Capability: ${spec.capabilityId}`;
|
|
281
|
+
return ` ${spec.verb.padEnd(18)} ${positionals}\n${' '.repeat(20)}Capability: ${spec.capabilityId}${spec.local ? ' (local scaffold)' : ''}`;
|
|
304
282
|
}).join('\n')}`;
|
|
305
283
|
}
|
|
306
284
|
function workflowFromGet(value) {
|
|
@@ -312,16 +290,16 @@ function workflowFromGet(value) {
|
|
|
312
290
|
const outputs = run?.steps?.[0]?.outputs;
|
|
313
291
|
const workflow = outputs ?? data;
|
|
314
292
|
if (!workflow || typeof workflow !== 'object' || Array.isArray(workflow))
|
|
315
|
-
throw new
|
|
293
|
+
throw new errors_1.CliUsageError('workflow get returned no workflow version data.');
|
|
316
294
|
return workflow;
|
|
317
295
|
}
|
|
318
296
|
function nullableString(value, name) {
|
|
319
297
|
if (value === null || typeof value === 'string')
|
|
320
298
|
return value;
|
|
321
|
-
throw new
|
|
299
|
+
throw new errors_1.CliUsageError(`workflow get returned no ${name}.`);
|
|
322
300
|
}
|
|
323
301
|
function requiredString(value, name) {
|
|
324
302
|
if (typeof value === 'string' && value)
|
|
325
303
|
return value;
|
|
326
|
-
throw new
|
|
304
|
+
throw new errors_1.CliUsageError(`workflow get returned no ${name}; publish workflow before activation.`);
|
|
327
305
|
}
|
|
@@ -1,7 +1,8 @@
|
|
|
1
|
-
import {
|
|
1
|
+
import { type PackVerbSpec } from './shared';
|
|
2
2
|
import type { CliCommand } from '../index';
|
|
3
|
+
import type { GatedRunContext } from '../gatedRun';
|
|
3
4
|
export declare const WORKFLOW_VERBS: PackVerbSpec[];
|
|
4
5
|
export declare const WORKFLOWS_USAGE: string;
|
|
5
6
|
export declare const parseWorkflowsCommand: (argv: string[]) => CliCommand;
|
|
6
|
-
export declare function runWorkflowsCommand(
|
|
7
|
+
export declare function runWorkflowsCommand(context: GatedRunContext | undefined, command: CliCommand, stdout: NodeJS.WritableStream): Promise<void>;
|
|
7
8
|
//# sourceMappingURL=workflows.d.ts.map
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"workflows.d.ts","sourceRoot":"","sources":["../../src/commands/workflows.ts"],"names":[],"mappings":"AAAA,OAAO,
|
|
1
|
+
{"version":3,"file":"workflows.d.ts","sourceRoot":"","sources":["../../src/commands/workflows.ts"],"names":[],"mappings":"AAAA,OAAO,EAAiE,KAAK,YAAY,EAAE,MAAM,UAAU,CAAC;AAC5G,OAAO,KAAK,EAAE,UAAU,EAAE,MAAM,UAAU,CAAC;AAC3C,OAAO,KAAK,EAAE,eAAe,EAAE,MAAM,aAAa,CAAC;AAInD,eAAO,MAAM,cAAc,EAAE,YAAY,EAMpC,CAAC;AAEN,eAAO,MAAM,eAAe,QAA+C,CAAC;AAC5E,eAAO,MAAM,qBAAqB,gCAA4E,CAAC;AAC/G,wBAAsB,mBAAmB,CAAC,OAAO,EAAE,eAAe,GAAG,SAAS,EAAE,OAAO,EAAE,UAAU,EAAE,MAAM,EAAE,MAAM,CAAC,cAAc,GAAG,OAAO,CAAC,IAAI,CAAC,CAQjJ"}
|
|
@@ -1,51 +1,29 @@
|
|
|
1
1
|
"use strict";
|
|
2
|
+
var __importDefault = (this && this.__importDefault) || function (mod) {
|
|
3
|
+
return (mod && mod.__esModule) ? mod : { "default": mod };
|
|
4
|
+
};
|
|
2
5
|
Object.defineProperty(exports, "__esModule", { value: true });
|
|
3
6
|
exports.parseWorkflowsCommand = exports.WORKFLOWS_USAGE = exports.WORKFLOW_VERBS = void 0;
|
|
4
7
|
exports.runWorkflowsCommand = runWorkflowsCommand;
|
|
5
8
|
const shared_1 = require("./shared");
|
|
6
|
-
const
|
|
7
|
-
const
|
|
8
|
-
|
|
9
|
-
|
|
10
|
-
|
|
11
|
-
|
|
12
|
-
|
|
13
|
-
|
|
14
|
-
|
|
15
|
-
// begin from a file. capabilityId names the verb this scaffold is meant to feed.
|
|
16
|
-
{ verb: 'init', capabilityId: 'workflow.automations.lint', summary: 'Write a starter workflow document to a local file. Calls no API and changes nothing.', flags: { name: { type: 'string', into: 'name' }, file: { type: 'string', into: 'file' } }, mutating: false },
|
|
17
|
-
{ verb: 'get', capabilityId: 'workflow.automations.get', summary: 'Get workflow.', positional: id, mutating: false },
|
|
18
|
-
{ verb: 'create', capabilityId: 'workflow.automations.compose', summary: 'Create workflow.', flags: { name: { type: 'string', into: 'name' }, description: { type: 'string', into: 'description' }, trigger: { type: 'string', into: 'trigger', json: true }, steps: { type: 'string', into: 'steps', json: true } }, mutating: true },
|
|
19
|
-
{ verb: 'update', capabilityId: 'workflow.automations.update', summary: 'Update workflow.', positional: id, flags: { ...workflowVersion, patch: { type: 'string', into: 'patch', json: true, document: true } }, mutating: true },
|
|
20
|
-
{ verb: 'lint', capabilityId: 'workflow.automations.lint', summary: 'Lint workflow.', positional: id, flags: { phase: { type: 'string', into: 'phase' }, document: { type: 'string', into: 'document', json: true, document: true } }, mutating: false },
|
|
21
|
-
{ verb: 'preview', capabilityId: 'workflow.automations.preview', summary: 'Preview workflow effects.', positional: id, mutating: false },
|
|
22
|
-
{ verb: 'variables', capabilityId: 'workflow.automations.variables_list', summary: 'List workflow variables.', positional: id, flags: { 'node-id': { type: 'string', into: 'node_id' }, query: { type: 'string', into: 'query' }, limit: { type: 'string', into: 'limit' }, document: { type: 'string', into: 'document', json: true, document: true } }, mutating: false },
|
|
23
|
-
{ verb: 'node-catalog', capabilityId: 'workflow.automations.node_catalog', summary: 'List workflow node types.', flags: { 'node-kind': { type: 'string', into: 'node_kind' }, query: { type: 'string', into: 'query' }, family: { type: 'string', into: 'family' }, 'include-blocked': { type: 'boolean', into: 'include_blocked' } }, mutating: false },
|
|
24
|
-
{ verb: 'node-inspect', capabilityId: 'workflow.automations.node_inspect', summary: 'Inspect workflow node type.', flags: { 'node-kind': { type: 'string', into: 'node_kind' }, subtype: { type: 'string', into: 'subtype' }, config: { type: 'string', into: 'config', json: true }, 'automation-id': { type: 'string', into: 'automation_id' }, 'node-id': { type: 'string', into: 'node_id' } }, mutating: false },
|
|
25
|
-
{ verb: 'node-add', capabilityId: 'workflow.automations.node_add', summary: 'Add workflow node.', positional: id, flags: { ...workflowVersion, 'after-node-id': { type: 'string', into: 'after_node_id' }, branch: { type: 'string', into: 'branch' }, node: { type: 'string', into: 'node', json: true, document: true } }, mutating: true },
|
|
26
|
-
{ verb: 'node-patch', capabilityId: 'workflow.automations.node_patch', summary: 'Patch workflow node.', positional: id, flags: { ...workflowVersion, 'node-id': { type: 'string', into: 'node_id' }, fields: { type: 'string', into: 'fields', json: true } }, mutating: true },
|
|
27
|
-
{ verb: 'node-remove', capabilityId: 'workflow.automations.node_remove', summary: 'Remove workflow node.', positional: id, flags: { ...workflowVersion, 'node-id': { type: 'string', into: 'node_id' } }, mutating: true },
|
|
28
|
-
{ verb: 'node-move', capabilityId: 'workflow.automations.node_move', summary: 'Move workflow node.', positional: id, flags: { ...workflowVersion, 'node-id': { type: 'string', into: 'node_id' }, 'after-node-id': { type: 'string', into: 'after_node_id' }, branch: { type: 'string', into: 'branch' } }, mutating: true },
|
|
29
|
-
{ verb: 'field-options', capabilityId: 'workflow.automations.field_options', summary: 'Resolve workflow node field options.', flags: { 'node-kind': { type: 'string', into: 'node_kind' }, subtype: { type: 'string', into: 'subtype' }, 'automation-id': { type: 'string', into: 'automation_id' }, 'node-id': { type: 'string', into: 'node_id' }, 'field-key': { type: 'string', into: 'field_key' }, 'field-keys': { type: 'string', into: 'field_keys', json: true }, query: { type: 'string', into: 'query' }, limit: { type: 'string', into: 'limit' }, cursor: { type: 'string', into: 'cursor' }, 'field-context': { type: 'string', into: 'field_context', json: true } }, mutating: false },
|
|
30
|
-
{ verb: 'draft-save', capabilityId: 'workflow.workflows.draft_save', summary: 'Save workflow draft.', positional: workflowId, flags: { graph: { type: 'string', into: 'graph', json: true, document: true }, 'expected-latest-draft-version-id': { type: 'string', into: 'expected_latest_draft_version_id' } }, mutating: true },
|
|
31
|
-
{ verb: 'publish', capabilityId: 'workflow.workflows.draft_publish', summary: 'Publish workflow draft.', positional: workflowId, flags: { 'expected-draft-version-id': { type: 'string', into: 'expected_draft_version_id' }, 'expected-active-version-id': { type: 'string', into: 'expected_active_version_id' } }, mutating: true },
|
|
32
|
-
{ verb: 'activate', capabilityId: 'workflow.workflows.activate', summary: 'Activate workflow.', positional: workflowId, flags: { 'expected-version-id': { type: 'string', into: 'expected_version_id' }, 'max-credits': { type: 'string', into: 'max_credits', number: true, required: true }, 'delivery-binding': { type: 'string', into: 'delivery_binding', json: true } }, mutating: true },
|
|
33
|
-
{ verb: 'deactivate', capabilityId: 'workflow.workflows.deactivate', summary: 'Deactivate workflow.', positional: workflowId, mutating: true },
|
|
34
|
-
{ verb: 'enroll', capabilityId: 'workflow.workflows.enroll_selection', summary: 'Enroll saved worksheet selection in workflow.', positional: workflowId, flags: { 'workbook-id': { type: 'string', into: 'workbook_id' }, 'worksheet-id': { type: 'string', into: 'worksheet_id' }, 'saved-view-id': { type: 'string', into: 'saved_view_id' }, 'selection-snapshot-id': { type: 'string', into: 'selection_snapshot_id' }, 'trigger-node-id': { type: 'string', into: 'trigger_node_id' }, 'audience-filter': { type: 'string', into: 'audience_filter', json: true }, 'enrollment-priority': { type: 'string', into: 'enrollment_priority', json: true }, 'enrollment-sort': { type: 'string', into: 'enrollment_sort', json: true }, 'max-live-sends': { type: 'string', into: 'max_live_sends', number: true } }, mutating: true },
|
|
35
|
-
{ verb: 'runs', capabilityId: 'workflow.workflows.runs_list', summary: 'List workflow runs.', positional: workflowId, flags: { workflow: { type: 'string', into: 'workflow_id' }, limit: { type: 'string', into: 'limit' } }, mutating: false },
|
|
36
|
-
{ verb: 'run', capabilityId: 'workflow.workflows.run_trace_get', summary: 'Get workflow run trace.', positional: workflowId, flags: { 'subject-id': { type: 'string', into: 'subject_id' } }, mutating: false },
|
|
37
|
-
{ verb: 'retry', capabilityId: 'workflow.workflows.run_retry', summary: 'Retry failed workflow run event.', positional: workflowId, flags: { 'subject-id': { type: 'string', into: 'subject_id' }, 'failed-event-id': { type: 'string', into: 'failed_event_id' }, 'failed-node-id': { type: 'string', into: 'failed_node_id' } }, mutating: true },
|
|
38
|
-
{ verb: 'duplicate', capabilityId: 'workflow.automations.duplicate', summary: 'Duplicate workflow.', positional: id, flags: { ...workflowVersion, name: { type: 'string', into: 'name' } }, mutating: true },
|
|
39
|
-
{ verb: 'archive', capabilityId: 'workflow.automations.archive', summary: 'Archive workflow.', positional: id, flags: { ...workflowVersion, reason: { type: 'string', into: 'reason' } }, mutating: true },
|
|
40
|
-
{ verb: 'export', capabilityId: 'workflow.automations.export', summary: 'Export workflow.', positional: id, mutating: false },
|
|
41
|
-
{ verb: 'import', capabilityId: 'workflow.automations.import', summary: 'Import workflow.', flags: { name: { type: 'string', into: 'name' }, document: { type: 'string', into: 'document', json: true, document: true } }, mutating: true },
|
|
42
|
-
];
|
|
9
|
+
const errors_1 = require("../errors");
|
|
10
|
+
const packVerbs_generated_json_1 = __importDefault(require("../generated/packVerbs.generated.json"));
|
|
11
|
+
exports.WORKFLOW_VERBS = packVerbs_generated_json_1.default.verbs
|
|
12
|
+
.filter(({ command }) => command.startsWith('workflows '))
|
|
13
|
+
.map(({ command, capabilityId, positional, local }) => ({
|
|
14
|
+
verb: command.slice('workflows '.length), capabilityId,
|
|
15
|
+
...(positional ? { positional } : {}),
|
|
16
|
+
...(local === 'init' ? { local: 'init' } : {}),
|
|
17
|
+
}));
|
|
43
18
|
exports.WORKFLOWS_USAGE = (0, shared_1.renderPackUsage)('workflows', exports.WORKFLOW_VERBS);
|
|
44
19
|
exports.parseWorkflowsCommand = (0, shared_1.buildPackParser)('workflows', 'workflow', exports.WORKFLOW_VERBS, exports.WORKFLOWS_USAGE);
|
|
45
|
-
async function runWorkflowsCommand(
|
|
20
|
+
async function runWorkflowsCommand(context, command, stdout) {
|
|
21
|
+
// init writes a local file and calls no API, so it has no gated context.
|
|
46
22
|
if (command.command === 'pack' && command.verb === 'init') {
|
|
47
23
|
(0, shared_1.runPackInit)('workflow', command, stdout);
|
|
48
24
|
return;
|
|
49
25
|
}
|
|
50
|
-
|
|
26
|
+
if (!context)
|
|
27
|
+
throw new errors_1.CliUsageError('workflows commands other than init require an authenticated session.');
|
|
28
|
+
await (0, shared_1.runPackCommand)(context, command, stdout);
|
|
51
29
|
}
|
package/dist/errors.d.ts
ADDED
|
@@ -0,0 +1,74 @@
|
|
|
1
|
+
export declare class CliUsageError extends Error {
|
|
2
|
+
constructor(message: string);
|
|
3
|
+
}
|
|
4
|
+
/**
|
|
5
|
+
* Process exit codes. The numbers are a published contract; change them only
|
|
6
|
+
* with a major version. `dreamstate --help` renders their stable meanings.
|
|
7
|
+
*
|
|
8
|
+
* Contract C5 (cross-surface): 0 ok, 1 generic, 2 usage, 3 auth, 4 not found,
|
|
9
|
+
* 5 conflict/validation, 6 rate limited, 7 repair.kind ask_user (a person must decide),
|
|
10
|
+
* 8 cli_update_required, 9 other refusal. Where this CLI had already published a
|
|
11
|
+
* different meaning it kept the published one and the mapping is documented:
|
|
12
|
+
*
|
|
13
|
+
* - 5 stays "server failure" (HTTP 5xx and unreadable responses). A 4xx
|
|
14
|
+
* conflict or validation refusal exits 9, as published and pinned by
|
|
15
|
+
* exitCodes.test.ts: a script must not read a caller mistake as a broken server.
|
|
16
|
+
* - 8 is cli_update_required. It was "request timeout" before; timeouts are 11
|
|
17
|
+
* now, so a script can tell "update the CLI" from "try again later".
|
|
18
|
+
*/
|
|
19
|
+
export declare const CLI_EXIT: {
|
|
20
|
+
readonly SUCCESS: 0;
|
|
21
|
+
readonly UNCLASSIFIED: 1;
|
|
22
|
+
readonly USAGE: 2;
|
|
23
|
+
readonly AUTH: 3;
|
|
24
|
+
readonly NOT_FOUND: 4;
|
|
25
|
+
readonly SERVER: 5;
|
|
26
|
+
readonly RATE_LIMITED: 6;
|
|
27
|
+
readonly APPROVAL: 7;
|
|
28
|
+
readonly UPDATE_REQUIRED: 8;
|
|
29
|
+
readonly REFUSED: 9;
|
|
30
|
+
readonly TRANSPORT: 10;
|
|
31
|
+
readonly TIMEOUT: 11;
|
|
32
|
+
};
|
|
33
|
+
/**
|
|
34
|
+
* Codes the CLI process raises itself, with no server answer behind them.
|
|
35
|
+
* The server never emits these. They are declared here, once, so the README
|
|
36
|
+
* table and the tests that keep every code in CLI source accounted for
|
|
37
|
+
* (errorCodes.test.ts) read one list. A code that is not in this table must be
|
|
38
|
+
* a member of the shared API_ERROR_CODES.
|
|
39
|
+
*/
|
|
40
|
+
export declare const CLI_LOCAL_ERROR_CODES: Readonly<Record<string, string>>;
|
|
41
|
+
/** Recovery metadata for failures raised by this CLI, rather than the API. */
|
|
42
|
+
export declare const CLI_LOCAL_ERROR_REPAIRS: {
|
|
43
|
+
readonly network_error: {
|
|
44
|
+
readonly kind: "wait";
|
|
45
|
+
readonly hint: "Retry the unchanged request when network connectivity is available.";
|
|
46
|
+
};
|
|
47
|
+
readonly request_timeout: {
|
|
48
|
+
readonly kind: "ask_user";
|
|
49
|
+
readonly hint: "Read the target back first. If absent, repeat once with the same idempotency key; otherwise ask the person.";
|
|
50
|
+
};
|
|
51
|
+
readonly invalid_response: {
|
|
52
|
+
readonly kind: "server_defect";
|
|
53
|
+
readonly hint: "The API response was not a Dreamstate envelope; report the trace id if one was returned.";
|
|
54
|
+
};
|
|
55
|
+
readonly invalid_web_url: {
|
|
56
|
+
readonly kind: "server_defect";
|
|
57
|
+
readonly hint: "The API returned an invalid web URL; report the response trace id.";
|
|
58
|
+
};
|
|
59
|
+
readonly web_url_unavailable: {
|
|
60
|
+
readonly kind: "not_possible";
|
|
61
|
+
readonly hint: "This result has no web URL to open.";
|
|
62
|
+
};
|
|
63
|
+
readonly plugin_install_failed: {
|
|
64
|
+
readonly kind: "ask_user";
|
|
65
|
+
readonly hint: "Install a supported agent, then retry plugin installation.";
|
|
66
|
+
};
|
|
67
|
+
readonly skills_authentication_required: {
|
|
68
|
+
readonly kind: "ask_user";
|
|
69
|
+
readonly hint: "Sign in with dreamstate login, then retry.";
|
|
70
|
+
};
|
|
71
|
+
};
|
|
72
|
+
export declare function isApprovalRepair(error: unknown): boolean;
|
|
73
|
+
export declare function isLocalRefusalCode(code: string | undefined): boolean;
|
|
74
|
+
//# sourceMappingURL=errors.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"errors.d.ts","sourceRoot":"","sources":["../src/errors.ts"],"names":[],"mappings":"AAAA,qBAAa,aAAc,SAAQ,KAAK;gBAC1B,OAAO,EAAE,MAAM;CAI5B;AAED;;;;;;;;;;;;;;GAcG;AACH,eAAO,MAAM,QAAQ;;;;;;;;;;;;;CAaX,CAAC;AAEX;;;;;;GAMG;AACH,eAAO,MAAM,qBAAqB,EAAE,QAAQ,CAAC,MAAM,CAAC,MAAM,EAAE,MAAM,CAAC,CAQlE,CAAC;AAEF,8EAA8E;AAC9E,eAAO,MAAM,uBAAuB;;;;;;;;;;;;;;;;;;;;;;;;;;;;;CAQ1B,CAAC;AAEX,wBAAgB,gBAAgB,CAAC,KAAK,EAAE,OAAO,GAAG,OAAO,CAMxD;AAQD,wBAAgB,kBAAkB,CAAC,IAAI,EAAE,MAAM,GAAG,SAAS,GAAG,OAAO,CAEpE"}
|