@trydreamstate/cli 1.3.1 → 1.3.3
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 +29 -16
- package/agent-plugin/.claude-plugin/plugin.json +1 -1
- package/agent-plugin/.codex-plugin/plugin.json +4 -1
- package/agent-plugin/assets/logo.png +0 -0
- 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 +1 -1
- package/agent-plugin/skills/dreamstate/SKILL.md +13 -5
- package/agent-plugin/skills/first-win/SKILL.md +2 -2
- package/agent-plugin/skills/inbox-replies/SKILL.md +1 -1
- package/agent-plugin/skills/knowledge/SKILL.md +1 -1
- package/agent-plugin/skills/linkedin-posts/SKILL.md +1 -1
- package/agent-plugin/skills/linkedin-warm-signals/SKILL.md +2 -2
- package/agent-plugin/skills/list-building/SKILL.md +4 -4
- package/agent-plugin/skills/outreach/SKILL.md +1 -1
- package/agent-plugin/skills/outreach/steps-and-timing.md +1 -1
- package/agent-plugin/skills/plays/SKILL.md +2 -2
- package/agent-plugin/skills/reddit-posts/SKILL.md +1 -1
- package/agent-plugin/skills/skill-authoring/SKILL.md +1 -1
- package/agent-plugin/skills/social/SKILL.md +2 -2
- package/agent-plugin/skills/visibility/SKILL.md +2 -2
- package/agent-plugin/skills/workflows/SKILL.md +3 -3
- package/agent-plugin/skills/worksheet-tidy/SKILL.md +1 -1
- package/agent-plugin/skills/writing/SKILL.md +1 -1
- package/agent-plugin/skills/x-posts/SKILL.md +1 -1
- package/dist/agentGuidance.generated.json +35 -0
- package/dist/client.d.ts +31 -2
- package/dist/client.d.ts.map +1 -1
- package/dist/client.js +115 -33
- 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 +1 -1
- package/dist/commands/sequences.d.ts.map +1 -1
- package/dist/commands/sequences.js +37 -36
- package/dist/commands/shared.d.ts +4 -26
- package/dist/commands/shared.d.ts.map +1 -1
- package/dist/commands/shared.js +129 -127
- package/dist/commands/workflows.d.ts +1 -1
- package/dist/commands/workflows.d.ts.map +1 -1
- package/dist/commands/workflows.js +35 -41
- package/dist/errors.d.ts +78 -0
- package/dist/errors.d.ts.map +1 -0
- package/dist/errors.js +117 -0
- package/dist/gatedRun.d.ts +81 -0
- package/dist/gatedRun.d.ts.map +1 -0
- package/dist/gatedRun.js +370 -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 +21 -35
- package/dist/index.d.ts.map +1 -1
- package/dist/index.js +372 -366
- package/dist/runWait.d.ts +2 -1
- package/dist/runWait.d.ts.map +1 -1
- package/dist/runWait.js +3 -1
- 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 +3 -2
package/dist/commands/shared.js
CHANGED
|
@@ -11,6 +11,8 @@ 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
18
|
const MODES = ['dry_run', 'live', 'smoke_test'];
|
|
@@ -22,151 +24,136 @@ 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
71
|
if (MODES.includes(value))
|
|
40
72
|
return value;
|
|
41
|
-
throw new
|
|
73
|
+
throw new errors_1.CliUsageError(`--mode must be one of: ${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
|
+
approved: { type: 'boolean' }, 'approval-id': { type: 'string' }, 'approved-effect-unknown': { type: 'boolean' },
|
|
86
|
+
'quote-hash': { type: 'string' }, 'turn-token': { type: 'string' },
|
|
51
87
|
'wait-timeout': { type: 'string' }, 'no-wait': { type: 'boolean' }, 'json-output': { type: 'boolean' }, open: { type: 'boolean' }, help: { type: 'boolean', short: 'h' },
|
|
52
88
|
};
|
|
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 };
|
|
89
|
+
const schemaFlags = takeSchemaFlags(argv.slice(1), new Set(Object.keys(options)));
|
|
67
90
|
let values;
|
|
68
91
|
let positionals;
|
|
69
92
|
try {
|
|
70
|
-
({ values, positionals } = (0, node_util_1.parseArgs)({ args: argv
|
|
93
|
+
({ values, positionals } = (0, node_util_1.parseArgs)({ args: schemaFlags.argv, options, allowPositionals: true, strict: true }));
|
|
71
94
|
}
|
|
72
95
|
catch (error) {
|
|
73
|
-
|
|
96
|
+
// parseArgs raises a TypeError whose class can come from another realm, so read the message
|
|
97
|
+
// instead of trusting instanceof: otherwise the user sees 'Invalid arguments.' and not the flag.
|
|
98
|
+
const reason = error?.message;
|
|
99
|
+
throw new errors_1.CliUsageError(`${typeof reason === 'string' && reason ? reason : 'Invalid arguments.'}\n${usage}`);
|
|
74
100
|
}
|
|
75
101
|
const mode = values.mode;
|
|
76
102
|
const dryRun = values['dry-run'];
|
|
77
103
|
const live = values.live;
|
|
78
|
-
const agentSessionId = values['agent-session-id'];
|
|
79
104
|
const idempotencyKey = values['idempotency-key'];
|
|
80
105
|
const rawParams = values.params;
|
|
81
106
|
const rawMaxCredits = values['max-credits'];
|
|
82
107
|
const rawWaitTimeout = values['wait-timeout'];
|
|
83
108
|
if (values.help)
|
|
84
109
|
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
110
|
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
111
|
const requiredPositionals = positional.filter((definition) => definition.optional !== true).length;
|
|
96
112
|
const positionalsAcceptable = positionals.length <= positional.length
|
|
97
|
-
&&
|
|
113
|
+
&& positionals.length >= requiredPositionals;
|
|
98
114
|
if (!positionalsAcceptable)
|
|
99
|
-
throw new
|
|
115
|
+
throw new errors_1.CliUsageError(`Usage: ${usage}`);
|
|
100
116
|
if ((mode && (dryRun || live)) || (dryRun && live)) {
|
|
101
|
-
throw new
|
|
117
|
+
throw new errors_1.CliUsageError('Use exactly one of --mode, --dry-run, or --live.');
|
|
102
118
|
}
|
|
103
|
-
const input = rawParams ? parseObject(rawParams, '--params') : {};
|
|
119
|
+
const input = { ...(rawParams ? parseObject(rawParams, '--params') : {}), ...schemaFlags.params };
|
|
104
120
|
positional.forEach((definition, index) => {
|
|
105
121
|
const value = positionals[index];
|
|
106
122
|
if (value !== undefined)
|
|
107
123
|
input[definition.into] = value;
|
|
108
124
|
});
|
|
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
125
|
// kind is the discriminator of the SHARED authoring family only. The
|
|
154
126
|
// family-specific capabilities have strict schemas that do not declare it,
|
|
155
127
|
// so injecting it everywhere made every one of those verbs fail validation
|
|
156
128
|
// with an unrecognized key before it reached the server's real work.
|
|
157
129
|
if (spec.capabilityId.startsWith('workflow.automations.'))
|
|
158
130
|
input.kind = kind;
|
|
131
|
+
// No default mode. A mutating verb run with no mode used to be rewritten to dry_run
|
|
132
|
+
// silently, where `tools run` sends none and lets the server answer mode_required
|
|
133
|
+
// with its repair; one rule for both now, so a person is told to choose.
|
|
159
134
|
const explicitMode = dryRun ? 'dry_run' : live ? 'live' : parseMode(mode);
|
|
160
135
|
const maxCredits = rawMaxCredits === undefined ? undefined : Number(rawMaxCredits);
|
|
161
136
|
if (maxCredits !== undefined && (!Number.isFinite(maxCredits) || maxCredits < 0))
|
|
162
|
-
throw new
|
|
137
|
+
throw new errors_1.CliUsageError('--max-credits must be a non-negative number');
|
|
138
|
+
const quoteHash = values['quote-hash'];
|
|
139
|
+
if (quoteHash !== undefined && !/^sha256:[a-f0-9]{64}$/.test(quoteHash))
|
|
140
|
+
throw new errors_1.CliUsageError('--quote-hash must be the sha256:<64 hex> quote_hash a dry run returned');
|
|
141
|
+
const approvalId = values['approval-id'];
|
|
142
|
+
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))
|
|
143
|
+
throw new errors_1.CliUsageError('--approval-id must be the uuid of a recorded approval');
|
|
163
144
|
const waitTimeout = rawWaitTimeout === undefined ? 120 : Number(rawWaitTimeout);
|
|
164
145
|
if (!Number.isFinite(waitTimeout) || waitTimeout < 0)
|
|
165
|
-
throw new
|
|
146
|
+
throw new errors_1.CliUsageError('--wait-timeout must be a non-negative number');
|
|
166
147
|
return {
|
|
167
148
|
command: 'pack', pack, verb: spec.verb, capabilityId: spec.capabilityId, input,
|
|
168
|
-
...(explicitMode ? { mode: explicitMode } :
|
|
169
|
-
|
|
149
|
+
...(explicitMode ? { mode: explicitMode } : {}),
|
|
150
|
+
// --approved is the caller's assertion that a person saw the dry run and agreed. It only
|
|
151
|
+
// means something on a live run, so no other mode ever sends it (same rule as tools run).
|
|
152
|
+
...(values.approved && explicitMode === 'live' ? { approved: true } : {}),
|
|
153
|
+
...(approvalId ? { approvalId } : {}),
|
|
154
|
+
...(values['approved-effect-unknown'] ? { approvedEffectUnknown: true } : {}),
|
|
155
|
+
...(quoteHash ? { quoteHash } : {}),
|
|
156
|
+
...(values['turn-token'] ? { turnToken: values['turn-token'] } : {}),
|
|
170
157
|
...(idempotencyKey ? { idempotencyKey } : {}),
|
|
171
158
|
...(maxCredits === undefined ? {} : { maxCredits }), ...(values['json-output'] ? { jsonOutput: true } : {}),
|
|
172
159
|
waitTimeout, ...(values['no-wait'] ? { noWait: true } : {}),
|
|
@@ -214,14 +201,14 @@ function packScaffold(kind, name) {
|
|
|
214
201
|
}
|
|
215
202
|
function runPackInit(kind, command, stdout) {
|
|
216
203
|
if (command.command !== 'pack')
|
|
217
|
-
throw new
|
|
204
|
+
throw new errors_1.CliUsageError('Pack command required.');
|
|
218
205
|
const input = command.input;
|
|
219
206
|
const name = typeof input.name === 'string' && input.name.trim() ? input.name.trim() : `My ${kind}`;
|
|
220
207
|
const target = typeof input.file === 'string' && input.file.trim()
|
|
221
208
|
? input.file.trim()
|
|
222
209
|
: `./${kind}.json`;
|
|
223
210
|
if ((0, node_fs_1.existsSync)(target)) {
|
|
224
|
-
throw new
|
|
211
|
+
throw new errors_1.CliUsageError(`${target} already exists. Pass --file <path> to write somewhere else.`);
|
|
225
212
|
}
|
|
226
213
|
const document = packScaffold(kind, name);
|
|
227
214
|
(0, node_fs_1.writeFileSync)(target, `${JSON.stringify(document, null, 2)}\n`, 'utf8');
|
|
@@ -237,27 +224,25 @@ function runPackInit(kind, command, stdout) {
|
|
|
237
224
|
},
|
|
238
225
|
}, null, command.jsonOutput ? 0 : 2)}\n`);
|
|
239
226
|
}
|
|
240
|
-
|
|
227
|
+
/**
|
|
228
|
+
* Verbs whose request needs the current version ids of the thing they act on.
|
|
229
|
+
* Keyed by the capability the verb runs, never by the verb's name: `sequences
|
|
230
|
+
* publish` and `workflows publish` share a name and nothing else (the sequence
|
|
231
|
+
* one takes sequence_id and needs no read; it was once caught by the workflow
|
|
232
|
+
* branch and refused with "workflows publish requires <id>").
|
|
233
|
+
*/
|
|
234
|
+
const WORKFLOW_PUBLISH = 'workflow.workflows.draft_publish';
|
|
235
|
+
const WORKFLOW_ACTIVATE = 'workflow.workflows.activate';
|
|
236
|
+
async function runPackCommand(context, command, stdout) {
|
|
241
237
|
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') {
|
|
238
|
+
throw new errors_1.CliUsageError('Pack command required.');
|
|
239
|
+
if (command.capabilityId === WORKFLOW_PUBLISH || command.capabilityId === WORKFLOW_ACTIVATE) {
|
|
251
240
|
const workflowId = command.input.workflow_id;
|
|
252
241
|
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));
|
|
242
|
+
throw new errors_1.CliUsageError(`${command.pack} ${command.verb} requires <id>.`);
|
|
243
|
+
const current = await (0, gatedRun_1.readCapability)(context, 'workflow.automations.get', { kind: 'workflow', automation_id: workflowId }, command.waitTimeout);
|
|
259
244
|
const workflow = workflowFromGet(current);
|
|
260
|
-
if (command.
|
|
245
|
+
if (command.capabilityId === WORKFLOW_PUBLISH) {
|
|
261
246
|
command.input.expected_draft_version_id ??= nullableString(workflow.latest_draft_version_id, 'latest_draft_version_id');
|
|
262
247
|
command.input.expected_active_version_id ??= nullableString(workflow.active_version_id, 'active_version_id');
|
|
263
248
|
}
|
|
@@ -265,19 +250,37 @@ async function runPackCommand(client, command, stdout, sleep = (milliseconds) =>
|
|
|
265
250
|
command.input.expected_version_id ??= requiredString(workflow.active_version_id, 'active_version_id');
|
|
266
251
|
}
|
|
267
252
|
}
|
|
268
|
-
const
|
|
269
|
-
const
|
|
270
|
-
|
|
271
|
-
|
|
272
|
-
|
|
273
|
-
|
|
274
|
-
|
|
275
|
-
|
|
276
|
-
|
|
277
|
-
|
|
278
|
-
|
|
279
|
-
|
|
280
|
-
|
|
253
|
+
const maxCredits = command.maxCredits;
|
|
254
|
+
const outcome = await (0, gatedRun_1.runGated)(context, {
|
|
255
|
+
capabilityId: command.capabilityId,
|
|
256
|
+
body: {
|
|
257
|
+
params: command.input,
|
|
258
|
+
...(command.mode ? { mode: command.mode } : {}),
|
|
259
|
+
...(maxCredits === undefined ? {} : { max_credits: maxCredits }),
|
|
260
|
+
...(command.approved ? { approved: true } : {}),
|
|
261
|
+
...(command.approvalId ? { approval_id: command.approvalId } : {}),
|
|
262
|
+
...(command.approvedEffectUnknown ? { approved_effect_unknown: true } : {}),
|
|
263
|
+
...(command.quoteHash ? { quote_hash: command.quoteHash } : {}),
|
|
264
|
+
},
|
|
265
|
+
...(command.turnToken ? { turnToken: command.turnToken } : {}),
|
|
266
|
+
...(command.idempotencyKey ? { idempotencyKey: command.idempotencyKey } : {}),
|
|
267
|
+
waitTimeout: command.waitTimeout,
|
|
268
|
+
...(command.noWait ? { noWait: true } : {}),
|
|
269
|
+
coerceParams: true,
|
|
270
|
+
// Bridge for a capability that still lists max_credits among its params (contract C6 keeps
|
|
271
|
+
// the ceiling at the door). The value is copied only while the live schema declares it, so
|
|
272
|
+
// the day the catalog removes the param this stops sending it with no change here.
|
|
273
|
+
adjustParams: (params, capability) => {
|
|
274
|
+
const schema = capability?.input_json_schema;
|
|
275
|
+
const properties = schema && typeof schema === 'object' ? schema.properties : undefined;
|
|
276
|
+
return maxCredits !== undefined && properties && 'max_credits' in properties && params.max_credits === undefined
|
|
277
|
+
? { ...params, max_credits: maxCredits }
|
|
278
|
+
: params;
|
|
279
|
+
},
|
|
280
|
+
});
|
|
281
|
+
const result = outcome.value;
|
|
282
|
+
if (outcome.timedOut)
|
|
283
|
+
process.exitCode = runWait_1.RUN_WAIT_TIMEOUT_EXIT_CODE;
|
|
281
284
|
const output = command.mode === 'dry_run' && result && typeof result === 'object' && !Array.isArray(result)
|
|
282
285
|
? { ...result, meta: { ...(result.meta ?? {}), dry_run: true, note: 'dry_run: true, rerun with --live to apply' } }
|
|
283
286
|
: result;
|
|
@@ -292,15 +295,14 @@ async function runPackCommand(client, command, stdout, sleep = (milliseconds) =>
|
|
|
292
295
|
const root = result && typeof result === 'object' ? result : {};
|
|
293
296
|
const webUrl = root.meta?.web_url ?? root.data?.web_url;
|
|
294
297
|
if (typeof webUrl !== 'string')
|
|
295
|
-
throw new
|
|
298
|
+
throw new errors_1.CliUsageError('The API response did not include a web_url.');
|
|
296
299
|
(0, index_1.openWebUrl)(webUrl);
|
|
297
300
|
}
|
|
298
301
|
}
|
|
299
302
|
function renderPackUsage(pack, specs) {
|
|
300
|
-
return `Usage: dreamstate ${pack} <verb> [args] [
|
|
303
|
+
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
304
|
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}`;
|
|
305
|
+
return ` ${spec.verb.padEnd(18)} ${positionals}\n${' '.repeat(20)}Capability: ${spec.capabilityId}${spec.local ? ' (local scaffold)' : ''}`;
|
|
304
306
|
}).join('\n')}`;
|
|
305
307
|
}
|
|
306
308
|
function workflowFromGet(value) {
|
|
@@ -312,16 +314,16 @@ function workflowFromGet(value) {
|
|
|
312
314
|
const outputs = run?.steps?.[0]?.outputs;
|
|
313
315
|
const workflow = outputs ?? data;
|
|
314
316
|
if (!workflow || typeof workflow !== 'object' || Array.isArray(workflow))
|
|
315
|
-
throw new
|
|
317
|
+
throw new errors_1.CliUsageError('workflow get returned no workflow version data.');
|
|
316
318
|
return workflow;
|
|
317
319
|
}
|
|
318
320
|
function nullableString(value, name) {
|
|
319
321
|
if (value === null || typeof value === 'string')
|
|
320
322
|
return value;
|
|
321
|
-
throw new
|
|
323
|
+
throw new errors_1.CliUsageError(`workflow get returned no ${name}.`);
|
|
322
324
|
}
|
|
323
325
|
function requiredString(value, name) {
|
|
324
326
|
if (typeof value === 'string' && value)
|
|
325
327
|
return value;
|
|
326
|
-
throw new
|
|
328
|
+
throw new errors_1.CliUsageError(`workflow get returned no ${name}; publish workflow before activation.`);
|
|
327
329
|
}
|
|
@@ -3,5 +3,5 @@ import type { CliCommand } from '../index';
|
|
|
3
3
|
export declare const WORKFLOW_VERBS: PackVerbSpec[];
|
|
4
4
|
export declare const WORKFLOWS_USAGE: string;
|
|
5
5
|
export declare const parseWorkflowsCommand: (argv: string[]) => CliCommand;
|
|
6
|
-
export declare function runWorkflowsCommand(
|
|
6
|
+
export declare function runWorkflowsCommand(context: Parameters<typeof runPackCommand>[0], command: CliCommand, stdout: NodeJS.WritableStream): Promise<void>;
|
|
7
7
|
//# 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,EAAoC,cAAc,EAAe,KAAK,YAAY,EAAE,MAAM,UAAU,CAAC;AAC5G,OAAO,KAAK,EAAE,UAAU,EAAE,MAAM,UAAU,CAAC;AAO3C,eAAO,MAAM,cAAc,EAAE,YAAY,EA4BxC,CAAC;AAEF,eAAO,MAAM,eAAe,QAA+C,CAAC;AAC5E,eAAO,MAAM,qBAAqB,gCAA4E,CAAC;AAC/G,wBAAsB,mBAAmB,CAAC,OAAO,EAAE,UAAU,CAAC,OAAO,cAAc,CAAC,CAAC,CAAC,CAAC,EAAE,OAAO,EAAE,UAAU,EAAE,MAAM,EAAE,MAAM,CAAC,cAAc,GAAG,OAAO,CAAC,IAAI,CAAC,CAG1J"}
|
|
@@ -3,49 +3,43 @@ Object.defineProperty(exports, "__esModule", { value: true });
|
|
|
3
3
|
exports.parseWorkflowsCommand = exports.WORKFLOWS_USAGE = exports.WORKFLOW_VERBS = void 0;
|
|
4
4
|
exports.runWorkflowsCommand = runWorkflowsCommand;
|
|
5
5
|
const shared_1 = require("./shared");
|
|
6
|
-
const
|
|
7
|
-
const
|
|
8
|
-
|
|
9
|
-
|
|
10
|
-
'expected-latest-draft-version-id': { type: 'string', into: 'expected_latest_draft_version_id' },
|
|
11
|
-
};
|
|
6
|
+
const automation = [{ name: 'id', into: 'automation_id' }];
|
|
7
|
+
const workflow = [{ name: 'id', into: 'workflow_id' }];
|
|
8
|
+
// Route map only. `tools get` owns every remote parameter, type, requirement and
|
|
9
|
+
// description. Positionals are documented CLI aliases for canonical input fields.
|
|
12
10
|
exports.WORKFLOW_VERBS = [
|
|
13
|
-
{ verb: 'list', capabilityId: 'workflow.automations.list'
|
|
14
|
-
|
|
15
|
-
|
|
16
|
-
{ verb: '
|
|
17
|
-
{ verb: '
|
|
18
|
-
{ verb: '
|
|
19
|
-
{ verb: '
|
|
20
|
-
{ verb: '
|
|
21
|
-
{ verb: '
|
|
22
|
-
{ verb: '
|
|
23
|
-
{ verb: 'node-
|
|
24
|
-
{ verb: 'node-
|
|
25
|
-
{ verb: 'node-
|
|
26
|
-
{ verb: 'node-
|
|
27
|
-
{ verb: '
|
|
28
|
-
{ verb: '
|
|
29
|
-
{ verb: '
|
|
30
|
-
{ verb: '
|
|
31
|
-
{ verb: '
|
|
32
|
-
{ verb: '
|
|
33
|
-
{ verb: '
|
|
34
|
-
{ verb: '
|
|
35
|
-
{ verb: '
|
|
36
|
-
{ verb: '
|
|
37
|
-
{ verb: '
|
|
38
|
-
{ verb: '
|
|
39
|
-
{ verb: '
|
|
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 },
|
|
11
|
+
{ verb: 'list', capabilityId: 'workflow.automations.list' },
|
|
12
|
+
{ verb: 'init', capabilityId: 'workflow.automations.lint', local: 'init' },
|
|
13
|
+
{ verb: 'get', capabilityId: 'workflow.automations.get', positional: automation },
|
|
14
|
+
{ verb: 'create', capabilityId: 'workflow.automations.compose' },
|
|
15
|
+
{ verb: 'update', capabilityId: 'workflow.automations.update', positional: automation },
|
|
16
|
+
{ verb: 'lint', capabilityId: 'workflow.automations.lint', positional: automation },
|
|
17
|
+
{ verb: 'preview', capabilityId: 'workflow.automations.preview', positional: automation },
|
|
18
|
+
{ verb: 'variables', capabilityId: 'workflow.automations.variables_list', positional: automation },
|
|
19
|
+
{ verb: 'node-catalog', capabilityId: 'workflow.automations.node_catalog' },
|
|
20
|
+
{ verb: 'node-inspect', capabilityId: 'workflow.automations.node_inspect' },
|
|
21
|
+
{ verb: 'node-add', capabilityId: 'workflow.automations.node_add', positional: automation },
|
|
22
|
+
{ verb: 'node-patch', capabilityId: 'workflow.automations.node_patch', positional: automation },
|
|
23
|
+
{ verb: 'node-remove', capabilityId: 'workflow.automations.node_remove', positional: automation },
|
|
24
|
+
{ verb: 'node-move', capabilityId: 'workflow.automations.node_move', positional: automation },
|
|
25
|
+
{ verb: 'field-options', capabilityId: 'workflow.automations.field_options' },
|
|
26
|
+
{ verb: 'draft-save', capabilityId: 'workflow.workflows.draft_save', positional: workflow },
|
|
27
|
+
{ verb: 'publish', capabilityId: 'workflow.workflows.draft_publish', positional: workflow },
|
|
28
|
+
{ verb: 'activate', capabilityId: 'workflow.workflows.activate', positional: workflow },
|
|
29
|
+
{ verb: 'deactivate', capabilityId: 'workflow.workflows.deactivate', positional: workflow },
|
|
30
|
+
{ verb: 'enroll', capabilityId: 'workflow.workflows.enroll_selection', positional: workflow },
|
|
31
|
+
{ verb: 'runs', capabilityId: 'workflow.workflows.runs_list', positional: workflow },
|
|
32
|
+
{ verb: 'run', capabilityId: 'workflow.workflows.run_trace_get', positional: workflow },
|
|
33
|
+
{ verb: 'retry', capabilityId: 'workflow.workflows.run_retry', positional: workflow },
|
|
34
|
+
{ verb: 'duplicate', capabilityId: 'workflow.automations.duplicate', positional: automation },
|
|
35
|
+
{ verb: 'archive', capabilityId: 'workflow.automations.archive', positional: automation },
|
|
36
|
+
{ verb: 'export', capabilityId: 'workflow.automations.export', positional: automation },
|
|
37
|
+
{ verb: 'import', capabilityId: 'workflow.automations.import' },
|
|
42
38
|
];
|
|
43
39
|
exports.WORKFLOWS_USAGE = (0, shared_1.renderPackUsage)('workflows', exports.WORKFLOW_VERBS);
|
|
44
40
|
exports.parseWorkflowsCommand = (0, shared_1.buildPackParser)('workflows', 'workflow', exports.WORKFLOW_VERBS, exports.WORKFLOWS_USAGE);
|
|
45
|
-
async function runWorkflowsCommand(
|
|
46
|
-
if (command.command === 'pack' && command.verb === 'init')
|
|
47
|
-
(0, shared_1.runPackInit)('workflow', command, stdout);
|
|
48
|
-
|
|
49
|
-
}
|
|
50
|
-
await (0, shared_1.runPackCommand)(client, command, stdout, sleep);
|
|
41
|
+
async function runWorkflowsCommand(context, command, stdout) {
|
|
42
|
+
if (command.command === 'pack' && command.verb === 'init')
|
|
43
|
+
return (0, shared_1.runPackInit)('workflow', command, stdout);
|
|
44
|
+
await (0, shared_1.runPackCommand)(context, command, stdout);
|
|
51
45
|
}
|
package/dist/errors.d.ts
ADDED
|
@@ -0,0 +1,78 @@
|
|
|
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 approval/consent/spend gate required,
|
|
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_tool_turn_token: {
|
|
56
|
+
readonly kind: "server_defect";
|
|
57
|
+
readonly hint: "The API did not provide a runnable tool turn; retry after reporting the response trace id.";
|
|
58
|
+
};
|
|
59
|
+
readonly invalid_web_url: {
|
|
60
|
+
readonly kind: "server_defect";
|
|
61
|
+
readonly hint: "The API returned an invalid web URL; report the response trace id.";
|
|
62
|
+
};
|
|
63
|
+
readonly web_url_unavailable: {
|
|
64
|
+
readonly kind: "not_possible";
|
|
65
|
+
readonly hint: "This result has no web URL to open.";
|
|
66
|
+
};
|
|
67
|
+
readonly plugin_install_failed: {
|
|
68
|
+
readonly kind: "ask_user";
|
|
69
|
+
readonly hint: "Install a supported agent, then retry plugin installation.";
|
|
70
|
+
};
|
|
71
|
+
readonly skills_authentication_required: {
|
|
72
|
+
readonly kind: "ask_user";
|
|
73
|
+
readonly hint: "Sign in with dreamstate login, then retry.";
|
|
74
|
+
};
|
|
75
|
+
};
|
|
76
|
+
export declare function isApprovalGateCode(code: string | undefined): boolean;
|
|
77
|
+
export declare function isLocalRefusalCode(code: string | undefined): boolean;
|
|
78
|
+
//# 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,CASlE,CAAC;AAEF,8EAA8E;AAC9E,eAAO,MAAM,uBAAuB;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;CAS1B,CAAC;AAyCX,wBAAgB,kBAAkB,CAAC,IAAI,EAAE,MAAM,GAAG,SAAS,GAAG,OAAO,CAEpE;AAQD,wBAAgB,kBAAkB,CAAC,IAAI,EAAE,MAAM,GAAG,SAAS,GAAG,OAAO,CAEpE"}
|