@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.
Files changed (91) hide show
  1. package/README.md +36 -16
  2. package/agent-plugin/.claude-plugin/plugin.json +1 -1
  3. package/agent-plugin/.codex-plugin/plugin.json +1 -1
  4. package/agent-plugin/hooks/approve-readonly.sh +15 -0
  5. package/agent-plugin/hooks/hooks.json +17 -0
  6. package/agent-plugin/skills/crm/SKILL.md +2 -2
  7. package/agent-plugin/skills/diagnostics/SKILL.md +3 -1
  8. package/agent-plugin/skills/dreamstate/SKILL.md +15 -5
  9. package/agent-plugin/skills/first-win/SKILL.md +2 -2
  10. package/agent-plugin/skills/inbox-replies/SKILL.md +3 -1
  11. package/agent-plugin/skills/knowledge/SKILL.md +3 -5
  12. package/agent-plugin/skills/linkedin-posts/SKILL.md +3 -1
  13. package/agent-plugin/skills/linkedin-warm-signals/SKILL.md +2 -2
  14. package/agent-plugin/skills/list-building/SKILL.md +5 -10
  15. package/agent-plugin/skills/list-building/column-authoring.md +1 -1
  16. package/agent-plugin/skills/list-building/sourcing.md +2 -2
  17. package/agent-plugin/skills/outreach/SKILL.md +2 -2
  18. package/agent-plugin/skills/outreach/steps-and-timing.md +1 -1
  19. package/agent-plugin/skills/plays/SKILL.md +3 -3
  20. package/agent-plugin/skills/reddit-posts/SKILL.md +3 -1
  21. package/agent-plugin/skills/skill-authoring/SKILL.md +3 -1
  22. package/agent-plugin/skills/social/SKILL.md +4 -6
  23. package/agent-plugin/skills/visibility/SKILL.md +2 -6
  24. package/agent-plugin/skills/workflows/SKILL.md +3 -3
  25. package/agent-plugin/skills/workflows/lifecycle-and-enrollment.md +1 -1
  26. package/agent-plugin/skills/worksheet-tidy/SKILL.md +3 -1
  27. package/agent-plugin/skills/writing/SKILL.md +3 -5
  28. package/agent-plugin/skills/x-posts/SKILL.md +3 -1
  29. package/dist/agentGuidance.generated.json +35 -0
  30. package/dist/capabilityPosture.d.ts +12 -0
  31. package/dist/capabilityPosture.d.ts.map +1 -0
  32. package/dist/capabilityPosture.js +39 -0
  33. package/dist/client.d.ts +33 -2
  34. package/dist/client.d.ts.map +1 -1
  35. package/dist/client.js +155 -64
  36. package/dist/commandTable.d.ts +26 -0
  37. package/dist/commandTable.d.ts.map +1 -0
  38. package/dist/commandTable.js +54 -0
  39. package/dist/commands/sequences.d.ts +3 -2
  40. package/dist/commands/sequences.d.ts.map +1 -1
  41. package/dist/commands/sequences.js +17 -34
  42. package/dist/commands/shared.d.ts +4 -26
  43. package/dist/commands/shared.d.ts.map +1 -1
  44. package/dist/commands/shared.js +136 -158
  45. package/dist/commands/workflows.d.ts +3 -2
  46. package/dist/commands/workflows.d.ts.map +1 -1
  47. package/dist/commands/workflows.js +17 -39
  48. package/dist/errors.d.ts +74 -0
  49. package/dist/errors.d.ts.map +1 -0
  50. package/dist/errors.js +84 -0
  51. package/dist/gatedRun.d.ts +79 -0
  52. package/dist/gatedRun.d.ts.map +1 -0
  53. package/dist/gatedRun.js +346 -0
  54. package/dist/generated/packVerbs.generated.json +492 -0
  55. package/dist/generated/runContract.generated.d.ts +4 -0
  56. package/dist/generated/runContract.generated.d.ts.map +1 -0
  57. package/dist/generated/runContract.generated.js +7 -0
  58. package/dist/idempotency.d.ts +38 -0
  59. package/dist/idempotency.d.ts.map +1 -0
  60. package/dist/idempotency.js +106 -0
  61. package/dist/index.d.ts +22 -35
  62. package/dist/index.d.ts.map +1 -1
  63. package/dist/index.js +405 -378
  64. package/dist/registryManifest.d.ts +6 -0
  65. package/dist/registryManifest.d.ts.map +1 -0
  66. package/dist/registryManifest.js +66 -0
  67. package/dist/runContract.d.ts +10 -0
  68. package/dist/runContract.d.ts.map +1 -0
  69. package/dist/runContract.js +13 -0
  70. package/dist/runWait.d.ts +2 -2
  71. package/dist/runWait.d.ts.map +1 -1
  72. package/dist/runWait.js +3 -14
  73. package/dist/schemaCoercion.d.ts +20 -0
  74. package/dist/schemaCoercion.d.ts.map +1 -0
  75. package/dist/schemaCoercion.js +123 -0
  76. package/dist/skillInstaller.d.ts +40 -0
  77. package/dist/skillInstaller.d.ts.map +1 -1
  78. package/dist/skillInstaller.js +108 -9
  79. package/dist/tableFilePreview.d.ts +14 -0
  80. package/dist/tableFilePreview.d.ts.map +1 -1
  81. package/dist/tableFilePreview.js +19 -8
  82. package/dist/tableFileReader.d.ts +26 -0
  83. package/dist/tableFileReader.d.ts.map +1 -0
  84. package/dist/tableFileReader.js +108 -0
  85. package/dist/tablesImport.d.ts +57 -0
  86. package/dist/tablesImport.d.ts.map +1 -0
  87. package/dist/tablesImport.js +263 -0
  88. package/dist/turnCache.d.ts +14 -1
  89. package/dist/turnCache.d.ts.map +1 -1
  90. package/dist/turnCache.js +25 -8
  91. package/package.json +6 -3
@@ -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 MODES = ['dry_run', 'live', 'smoke_test'];
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 index_1.CliUsageError(`${flag} ${error instanceof Error ? error.message : 'is invalid JSON'}`);
27
+ throw new errors_1.CliUsageError(`${flag} ${error instanceof Error ? error.message : 'is invalid JSON'}`);
26
28
  }
27
29
  }
28
- function parseJson(raw, flag) {
29
- try {
30
- return JSON.parse(raw);
31
- }
32
- catch {
33
- throw new index_1.CliUsageError(`${flag} must contain valid JSON`);
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 (MODES.includes(value))
71
+ if (runContract_1.RUN_MODES.includes(value))
40
72
  return value;
41
- throw new index_1.CliUsageError(`--mode must be one of: ${MODES.join(', ')}`);
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 index_1.CliUsageError(`Unknown ${pack} verb: ${argv[0] ?? '(missing)'}\n${usage}`);
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' }, 'agent-session-id': { type: 'string' },
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
- // A verb that takes a JSON document on a flag also takes it from a file, so a
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.slice(1), options, allowPositionals: true, strict: true }));
94
+ ({ values, positionals } = (0, node_util_1.parseArgs)({ args: schemaFlags.argv, options, allowPositionals: true, strict: true }));
71
95
  }
72
96
  catch (error) {
73
- throw new index_1.CliUsageError(`${error instanceof Error ? error.message : 'Invalid arguments.'}\n${usage}`);
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
- && (positionals.length >= requiredPositionals || (documentSupplied && positionals.length === 0));
118
+ && positionals.length >= requiredPositionals;
98
119
  if (!positionalsAcceptable)
99
- throw new index_1.CliUsageError(`Usage: ${usage}`);
120
+ throw new errors_1.CliUsageError(`Usage: ${usage}`);
100
121
  if ((mode && (dryRun || live)) || (dryRun && live)) {
101
- throw new index_1.CliUsageError('Use exactly one of --mode, --dry-run, or --live.');
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 index_1.CliUsageError('--max-credits must be a non-negative number');
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 index_1.CliUsageError('--wait-timeout must be a non-negative number');
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 } : spec.mutating ? { mode: 'dry_run' } : {}),
169
- ...(agentSessionId ? { agentSessionId } : {}),
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
- // The step fields are FLAT and the step carries an id. An earlier scaffold nested
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
- kind: 'sequence',
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 index_1.CliUsageError('Pack command required.');
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 index_1.CliUsageError(`${target} already exists. Pass --file <path> to write somewhere else.`);
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
- async function runPackCommand(client, command, stdout, sleep = (milliseconds) => new Promise((resolve) => setTimeout(resolve, milliseconds))) {
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 index_1.CliUsageError('Pack command required.');
243
- // Every run needs a tool_turn_token from tools_get, exactly as the generic
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 index_1.CliUsageError(`workflows ${command.verb} requires <id>.`);
254
- const readFetched = await client.getTool('workflow.automations.get');
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.verb === 'publish') {
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 fetched = await client.getTool(command.capabilityId);
269
- const turnToken = toolTurnToken(fetched);
270
- let result = await client.runCapability(command.capabilityId, {
271
- params: command.input, tool_turn_token: turnToken, ...(command.mode ? { mode: command.mode } : {}),
272
- ...(command.agentSessionId ? { agent_session_id: command.agentSessionId } : {}),
273
- ...(command.maxCredits === undefined ? {} : { max_credits: command.maxCredits }),
274
- }, capabilityIdempotencyKey(fetched, command.idempotencyKey));
275
- if (!command.noWait && !(0, runWait_1.columnRunReturnsRunId)(command.capabilityId)) {
276
- const waited = await (0, runWait_1.waitForRun)(client, result, command.waitTimeout, sleep);
277
- result = waited.value;
278
- if (waited.timedOut)
279
- process.exitCode = runWait_1.RUN_WAIT_TIMEOUT_EXIT_CODE;
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 index_1.CliUsageError('The API response did not include a web_url.');
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] [flags]\nRequired positionals use <name:field>. Optional positionals use [name:field]. Flags list target input fields. Run responses wait by default, use --wait-timeout <seconds> (default 120) or --no-wait.\n\nVerbs:\n${specs.map((spec) => {
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
- const flags = Object.entries(spec.flags ?? {}).map(([flag, definition]) => `--${flag} <${definition.into}>${definition.required ? ' (required)' : ''}`).join(' ');
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 index_1.CliUsageError('workflow get returned no workflow version data.');
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 index_1.CliUsageError(`workflow get returned no ${name}.`);
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 index_1.CliUsageError(`workflow get returned no ${name}; publish workflow before activation.`);
304
+ throw new errors_1.CliUsageError(`workflow get returned no ${name}; publish workflow before activation.`);
327
305
  }
@@ -1,7 +1,8 @@
1
- import { runPackCommand, type PackVerbSpec } from './shared';
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(client: Parameters<typeof runPackCommand>[0], command: CliCommand, stdout: NodeJS.WritableStream, sleep?: Parameters<typeof runPackCommand>[3]): Promise<void>;
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,EAGL,cAAc,EAEd,KAAK,YAAY,EAClB,MAAM,UAAU,CAAC;AAClB,OAAO,KAAK,EAAE,UAAU,EAAE,MAAM,UAAU,CAAC;AAS3C,eAAO,MAAM,cAAc,EAAE,YAAY,EA8BxC,CAAC;AAEF,eAAO,MAAM,eAAe,EAAE,MAAqD,CAAC;AACpF,eAAO,MAAM,qBAAqB,gCAA4E,CAAC;AAC/G,wBAAsB,mBAAmB,CACvC,MAAM,EAAE,UAAU,CAAC,OAAO,cAAc,CAAC,CAAC,CAAC,CAAC,EAC5C,OAAO,EAAE,UAAU,EACnB,MAAM,EAAE,MAAM,CAAC,cAAc,EAC7B,KAAK,CAAC,EAAE,UAAU,CAAC,OAAO,cAAc,CAAC,CAAC,CAAC,CAAC,GAC3C,OAAO,CAAC,IAAI,CAAC,CAMf"}
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 id = [{ name: 'id', into: 'automation_id' }];
7
- const workflowId = [{ name: 'id', into: 'workflow_id' }];
8
- const campaignId = [{ name: 'id', into: 'campaign_id' }];
9
- const workflowVersion = {
10
- 'expected-latest-draft-version-id': { type: 'string', into: 'expected_latest_draft_version_id' },
11
- };
12
- exports.WORKFLOW_VERBS = [
13
- { verb: 'list', capabilityId: 'workflow.automations.list', summary: 'List workflows.', flags: { limit: { type: 'string', into: 'limit' }, cursor: { type: 'string', into: 'cursor' }, lifecycle: { type: 'string', into: 'lifecycle' }, 'include-archived': { type: 'boolean', into: 'include_archived' }, search: { type: 'string', into: 'search' } }, mutating: false },
14
- // Local only: writes a starter document to disk and calls no API, so authoring can
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(client, command, stdout, sleep) {
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
- await (0, shared_1.runPackCommand)(client, command, stdout, sleep);
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
  }
@@ -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"}