@trydreamstate/cli 1.3.3 → 1.3.5
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 +14 -7
- 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 +2 -2
- package/agent-plugin/hooks/hooks.json +1 -1
- 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 +5 -3
- 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 +3 -3
- package/agent-plugin/skills/list-building/SKILL.md +4 -9
- package/agent-plugin/skills/list-building/column-authoring.md +3 -2
- package/agent-plugin/skills/list-building/sourcing.md +2 -2
- package/agent-plugin/skills/outreach/SKILL.md +3 -3
- 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 +3 -5
- package/agent-plugin/skills/visibility/SKILL.md +2 -6
- package/agent-plugin/skills/workflows/SKILL.md +2 -2
- 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 +4 -4
- 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 +9 -3
- package/dist/client.d.ts.map +1 -1
- package/dist/client.js +110 -63
- package/dist/commands/sequences.d.ts +3 -2
- package/dist/commands/sequences.d.ts.map +1 -1
- package/dist/commands/sequences.js +19 -37
- package/dist/commands/shared.d.ts.map +1 -1
- package/dist/commands/shared.js +22 -45
- package/dist/commands/workflows.d.ts +3 -2
- package/dist/commands/workflows.d.ts.map +1 -1
- package/dist/commands/workflows.js +19 -35
- package/dist/config.d.ts +5 -1
- package/dist/config.d.ts.map +1 -1
- package/dist/config.js +12 -2
- package/dist/errors.d.ts +2 -6
- package/dist/errors.d.ts.map +1 -1
- package/dist/errors.js +10 -43
- package/dist/gatedRun.d.ts +2 -2
- package/dist/gatedRun.d.ts.map +1 -1
- package/dist/gatedRun.js +157 -60
- 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/index.d.ts +9 -2
- package/dist/index.d.ts.map +1 -1
- package/dist/index.js +164 -59
- package/dist/money.d.ts +10 -0
- package/dist/money.d.ts.map +1 -0
- package/dist/money.js +75 -0
- 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 +0 -1
- package/dist/runWait.d.ts.map +1 -1
- package/dist/runWait.js +2 -13
- package/dist/turnCache.d.ts +3 -1
- package/dist/turnCache.d.ts.map +1 -1
- package/dist/turnCache.js +6 -2
- package/package.json +4 -2
package/dist/index.js
CHANGED
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
#!/usr/bin/env node
|
|
2
2
|
"use strict";
|
|
3
3
|
Object.defineProperty(exports, "__esModule", { value: true });
|
|
4
|
-
exports.
|
|
4
|
+
exports.capabilityIdempotencyKey = exports.CliUsageError = exports.CLI_EXIT = void 0;
|
|
5
5
|
exports.parseCliArgs = parseCliArgs;
|
|
6
6
|
exports.refusalEnvelope = refusalEnvelope;
|
|
7
7
|
exports.openWebUrl = openWebUrl;
|
|
@@ -20,6 +20,7 @@ const config_1 = require("./config");
|
|
|
20
20
|
const pluginInstaller_1 = require("./pluginInstaller");
|
|
21
21
|
const turnCache_1 = require("./turnCache");
|
|
22
22
|
const idempotency_1 = require("./idempotency");
|
|
23
|
+
const money_1 = require("./money");
|
|
23
24
|
const runWait_1 = require("./runWait");
|
|
24
25
|
const client_1 = require("./client");
|
|
25
26
|
const errors_1 = require("./errors");
|
|
@@ -27,12 +28,10 @@ Object.defineProperty(exports, "CLI_EXIT", { enumerable: true, get: function ()
|
|
|
27
28
|
Object.defineProperty(exports, "CliUsageError", { enumerable: true, get: function () { return errors_1.CliUsageError; } });
|
|
28
29
|
const gatedRun_1 = require("./gatedRun");
|
|
29
30
|
Object.defineProperty(exports, "capabilityIdempotencyKey", { enumerable: true, get: function () { return gatedRun_1.capabilityIdempotencyKey; } });
|
|
30
|
-
Object.defineProperty(exports, "omitsToolTurnForInlineTableRead", { enumerable: true, get: function () { return gatedRun_1.omitsToolTurnForInlineTableRead; } });
|
|
31
|
-
Object.defineProperty(exports, "toolTurnToken", { enumerable: true, get: function () { return gatedRun_1.toolTurnToken; } });
|
|
32
31
|
const tablesImport_1 = require("./tablesImport");
|
|
33
32
|
const commandTable_1 = require("./commandTable");
|
|
34
33
|
const skillInstaller_1 = require("./skillInstaller");
|
|
35
|
-
const
|
|
34
|
+
const runContract_1 = require("./runContract");
|
|
36
35
|
const UUID_PATTERN = /^[0-9a-f]{8}-[0-9a-f]{4}-[0-9a-f]{4}-[0-9a-f]{4}-[0-9a-f]{12}$/i;
|
|
37
36
|
const USAGE = `Dreamstate CLI
|
|
38
37
|
|
|
@@ -53,26 +52,28 @@ Usage:
|
|
|
53
52
|
dreamstate packs list [--json-output|--json]
|
|
54
53
|
dreamstate packs get <pack_id> [--json-output|--json]
|
|
55
54
|
dreamstate packs route --goal <text> [--json-output|--json]
|
|
56
|
-
dreamstate skills list [--query <query>] [--limit <n>] [--json-output|--json]
|
|
55
|
+
dreamstate skills list [--query <query>] [--limit <n>] [--cursor <cursor>] [--json-output|--json]
|
|
57
56
|
dreamstate skills get <skill_id> [--file <path>] [--json-output|--json]
|
|
58
57
|
dreamstate skills search <query> [--limit <n>] [--json-output|--json]
|
|
59
58
|
dreamstate skills install [--skill <skill_id|*>] [--agents <codex claude-code cursor>] [--project] [--copy] [--json-output|--json]
|
|
60
59
|
dreamstate skills doctor [--agents <codex claude-code cursor>] [--project] [--json-output|--json]
|
|
61
60
|
dreamstate commands search <term> [--json-output|--json]
|
|
62
|
-
dreamstate tools search --goal <goal> [--terms <csv>] [--limit <n>] [--toolset <pack_id>] [--json-output|--json]
|
|
61
|
+
dreamstate tools search --goal <goal> [--terms <csv>] [--limit <n>] [--cursor <cursor>] [--toolset <pack_id>] [--json-output|--json]
|
|
63
62
|
dreamstate tools get <capability_id> [--json-output|--json]
|
|
64
|
-
dreamstate tools run <capability_id> [--params <object>|--json <body>] [--turn-token <token>] (--live | --dry-run | --mode <smoke_test|dry_run|live>) [--approved] [--approval-id <uuid>] [--approved-effect-unknown] [--max-credits <n>] [--quote-hash <sha256:...>] [--idempotency-key <key>] [--wait-timeout <seconds>] [--no-wait] [--open] [--json-output
|
|
63
|
+
dreamstate tools run <capability_id> [--params <object>|--json <body>] [--turn-token <token>] (--live | --dry-run | --mode <smoke_test|dry_run|live>) [--approved] [--approval-id <uuid>] [--approved-effect-unknown] [--max-credits <n>] [--max-live-sends <n>] [--quote-hash <sha256:...>] [--idempotency-key <key>] [--wait-timeout <seconds>] [--no-wait] [--open] [--json-output]
|
|
65
64
|
dreamstate sequences <verb> [args] [flags]
|
|
66
65
|
dreamstate workflows <verb> [args] [flags]
|
|
67
66
|
dreamstate tables import --table-id <uuid> --file <path> [--format <csv|json|jsonl|xlsx>] [--preview] [--upsert-key <header>] [--row-kind <person|company>] [--keep-unmapped-columns <true|false>] [--json-output|--json]
|
|
68
67
|
dreamstate runs list [--limit <n>] [--cursor <cursor>] [--json <query>] [--json-output|--json]
|
|
69
68
|
dreamstate runs get <run_id> [--json-output|--json]
|
|
70
|
-
dreamstate runs
|
|
69
|
+
dreamstate runs status <run_id> [--json-output|--json]
|
|
70
|
+
dreamstate runs wait <run_id> [--wait-timeout <seconds>] [--json-output|--json]
|
|
71
|
+
dreamstate runs events <run_id> [--limit <n>] [--cursor <cursor>] [--json-output|--json]
|
|
71
72
|
dreamstate runs cancel <run_id> [--state-version <n>] [--reason <text>] [--json <body>] [--idempotency-key <key>] [--json-output|--json]
|
|
72
73
|
|
|
73
74
|
All catalog discovery reads live API records. Set DREAMSTATE_API_URL and DREAMSTATE_API_KEY.
|
|
74
75
|
Run responses wait for terminal run status by default, timeout default is 120 seconds, --no-wait returns immediate response. Timeout prints latest run envelope and exits ${runWait_1.RUN_WAIT_TIMEOUT_EXIT_CODE}.
|
|
75
|
-
A write you re-run unchanged presents the same Idempotency-Key (printed as meta.idempotency_key), so the server replays instead of running it twice; --idempotency-key sets one yourself. Exit codes: 0 ok, 2 usage, 3 auth, 4 not found, 5 server failure, 6 rate limited, 7
|
|
76
|
+
A write you re-run unchanged presents the same Idempotency-Key (printed as meta.idempotency_key), so the server replays instead of running it twice; --idempotency-key sets one yourself. Exit codes: 0 ok, 2 usage, 3 auth, 4 not found, 5 server failure, 6 rate limited, 7 repair.kind ask_user, 8 CLI update required, 9 refused, 10 transport, 11 timeout.
|
|
76
77
|
login opens browser approval and installs Dreamstate skills for detected agents; --no-skills skips installation. login --token stores a ds_user_ session or ds_live_ key (for SSH or remote machines) after verifying it with whoami.
|
|
77
78
|
Global flag --workspace <id|slug> (any command) or DREAMSTATE_WORKSPACE picks the workspace for one call; workspaces use stores a default. Flag beats env beats stored. A ds_live_ key is bound to one workspace and cannot switch.
|
|
78
79
|
logout deletes the stored credentials file. --agents takes space-separated, comma-separated or repeated values.
|
|
@@ -103,7 +104,7 @@ function csv(raw, flag = '--terms') {
|
|
|
103
104
|
return [...new Set(values)];
|
|
104
105
|
}
|
|
105
106
|
function requireToolsRunMode(body) {
|
|
106
|
-
if (
|
|
107
|
+
if (runContract_1.RUN_MODES.includes(body.mode))
|
|
107
108
|
return;
|
|
108
109
|
throw new errors_1.CliUsageError('mode must be one of: smoke_test, dry_run, live.');
|
|
109
110
|
}
|
|
@@ -119,6 +120,12 @@ function nonNegativeInteger(raw, flag) {
|
|
|
119
120
|
throw new errors_1.CliUsageError(`${flag} must be a non-negative integer`);
|
|
120
121
|
return value;
|
|
121
122
|
}
|
|
123
|
+
function positiveInteger(raw, flag) {
|
|
124
|
+
const value = Number(raw);
|
|
125
|
+
if (!Number.isSafeInteger(value) || value < 1)
|
|
126
|
+
throw new errors_1.CliUsageError(`${flag} must be an integer greater than or equal to 1`);
|
|
127
|
+
return value;
|
|
128
|
+
}
|
|
122
129
|
// runs.get returns { data: { run: { state_version } } }. Cancel posts
|
|
123
130
|
// expected_state_version, and a missing read must not invent 0.
|
|
124
131
|
function stateVersionFromRunRead(payload) {
|
|
@@ -143,8 +150,13 @@ function parsePacks(argv) {
|
|
|
143
150
|
return { command: 'packs_list', ...outputOption(values) };
|
|
144
151
|
if (positionals[0] === 'get')
|
|
145
152
|
return { command: 'packs_get', packId: requireOne(positionals, 'dreamstate packs get <pack_id>'), ...outputOption(values) };
|
|
146
|
-
if (positionals
|
|
147
|
-
|
|
153
|
+
if (positionals[0] === 'route') {
|
|
154
|
+
// `packs route "find work emails"` used to fall through to the generic
|
|
155
|
+
// usage line, which never said the goal belongs in --goal.
|
|
156
|
+
if (positionals.length === 1 && values.goal?.trim())
|
|
157
|
+
return { command: 'packs_route', goal: values.goal.trim(), ...outputOption(values) };
|
|
158
|
+
throw new errors_1.CliUsageError('Usage: dreamstate packs route --goal <text>. Pass the goal as --goal, not as a positional argument.');
|
|
159
|
+
}
|
|
148
160
|
throw new errors_1.CliUsageError('Usage: dreamstate packs <list|get|route>');
|
|
149
161
|
}
|
|
150
162
|
/** Rewrites `--agents a b c` into `--agents=a --agents=b --agents=c` so parseArgs sees every value. */
|
|
@@ -167,7 +179,7 @@ function spaceSeparatedAgents(argv) {
|
|
|
167
179
|
return out;
|
|
168
180
|
}
|
|
169
181
|
function parseSkills(argv) {
|
|
170
|
-
const { values, positionals } = (0, node_util_1.parseArgs)({ args: spaceSeparatedAgents(argv), options: { query: { type: 'string' }, limit: { type: 'string' }, skill: { type: 'string' }, file: { type: 'string' }, agents: { type: 'string', multiple: true }, project: { type: 'boolean' }, copy: { type: 'boolean' }, 'json-output': { type: 'boolean' }, help: { type: 'boolean', short: 'h' } }, allowPositionals: true, strict: true });
|
|
182
|
+
const { values, positionals } = (0, node_util_1.parseArgs)({ args: spaceSeparatedAgents(argv), options: { query: { type: 'string' }, limit: { type: 'string' }, cursor: { type: 'string' }, skill: { type: 'string' }, file: { type: 'string' }, agents: { type: 'string', multiple: true }, project: { type: 'boolean' }, copy: { type: 'boolean' }, 'json-output': { type: 'boolean' }, help: { type: 'boolean', short: 'h' } }, allowPositionals: true, strict: true });
|
|
171
183
|
if (values.help)
|
|
172
184
|
return { command: 'help' };
|
|
173
185
|
const agents = () => {
|
|
@@ -185,8 +197,16 @@ function parseSkills(argv) {
|
|
|
185
197
|
query.query = values.query;
|
|
186
198
|
if (values.limit !== undefined)
|
|
187
199
|
query.limit = nonNegativeInteger(values.limit, '--limit');
|
|
200
|
+
if (values.cursor !== undefined) {
|
|
201
|
+
const cursor = values.cursor.trim();
|
|
202
|
+
if (!cursor)
|
|
203
|
+
throw new errors_1.CliUsageError('--cursor must be a non-empty string');
|
|
204
|
+
query.cursor = cursor;
|
|
205
|
+
}
|
|
188
206
|
return { command: 'skills_list', query, ...outputOption(values) };
|
|
189
207
|
}
|
|
208
|
+
if (values.cursor !== undefined)
|
|
209
|
+
throw new errors_1.CliUsageError('--cursor is only valid on skills list');
|
|
190
210
|
if (positionals[0] === 'get')
|
|
191
211
|
return { command: 'skills_get', skillId: requireOne(positionals, 'dreamstate skills get <skill_id>'), ...(values.file?.trim() ? { file: values.file.trim() } : {}), ...outputOption(values) };
|
|
192
212
|
if (positionals[0] === 'search' && positionals.length > 1) {
|
|
@@ -225,8 +245,8 @@ function toolsRunMode(values) {
|
|
|
225
245
|
chosen.add('live');
|
|
226
246
|
if (values.mode !== undefined) {
|
|
227
247
|
const mode = values.mode.trim();
|
|
228
|
-
if (!
|
|
229
|
-
throw new errors_1.CliUsageError(`--mode must be one of: ${
|
|
248
|
+
if (!runContract_1.RUN_MODES.includes(mode)) {
|
|
249
|
+
throw new errors_1.CliUsageError(`--mode must be one of: ${runContract_1.RUN_MODES.join(', ')}`);
|
|
230
250
|
}
|
|
231
251
|
chosen.add(mode);
|
|
232
252
|
}
|
|
@@ -238,12 +258,12 @@ function toolsRunMode(values) {
|
|
|
238
258
|
function parseTools(argv) {
|
|
239
259
|
const { values, positionals } = (0, node_util_1.parseArgs)({ args: argv, options: {
|
|
240
260
|
json: { type: 'string' }, params: { type: 'string' }, goal: { type: 'string' }, terms: { type: 'string' },
|
|
241
|
-
limit: { type: 'string' }, toolset: { type: 'string' },
|
|
261
|
+
limit: { type: 'string' }, cursor: { type: 'string' }, toolset: { type: 'string' },
|
|
242
262
|
'idempotency-key': { type: 'string' }, 'json-output': { type: 'boolean' }, open: { type: 'boolean' },
|
|
243
263
|
'dry-run': { type: 'boolean' }, live: { type: 'boolean' }, mode: { type: 'string' },
|
|
244
264
|
approved: { type: 'boolean' }, 'approved-effect-unknown': { type: 'boolean' },
|
|
245
265
|
'quote-hash': { type: 'string' }, 'approval-id': { type: 'string' },
|
|
246
|
-
'max-credits': { type: 'string' }, 'turn-token': { type: 'string' }, 'wait-timeout': { type: 'string' }, 'no-wait': { type: 'boolean' }, help: { type: 'boolean', short: 'h' },
|
|
266
|
+
'max-credits': { type: 'string' }, 'max-live-sends': { type: 'string' }, 'turn-token': { type: 'string' }, 'wait-timeout': { type: 'string' }, 'no-wait': { type: 'boolean' }, help: { type: 'boolean', short: 'h' },
|
|
247
267
|
}, allowPositionals: true, strict: true });
|
|
248
268
|
if (values.help)
|
|
249
269
|
return { command: 'help' };
|
|
@@ -256,12 +276,20 @@ function parseTools(argv) {
|
|
|
256
276
|
query.query_terms = csv(values.terms);
|
|
257
277
|
if (values.limit !== undefined)
|
|
258
278
|
query.limit = nonNegativeInteger(values.limit, '--limit');
|
|
279
|
+
if (values.cursor !== undefined) {
|
|
280
|
+
const cursor = values.cursor.trim();
|
|
281
|
+
if (!cursor)
|
|
282
|
+
throw new errors_1.CliUsageError('--cursor must be a non-empty string');
|
|
283
|
+
query.cursor = cursor;
|
|
284
|
+
}
|
|
259
285
|
if (values.toolset !== undefined)
|
|
260
286
|
query.toolset = values.toolset;
|
|
261
287
|
if (typeof query.goal !== 'string' && !Array.isArray(query.query_terms))
|
|
262
288
|
throw new errors_1.CliUsageError('tools search requires --goal, --terms, or --json query fields');
|
|
263
289
|
return { command: 'tools_search', query, ...output };
|
|
264
290
|
}
|
|
291
|
+
if (values.cursor !== undefined)
|
|
292
|
+
throw new errors_1.CliUsageError('--cursor is only valid on tools search');
|
|
265
293
|
if (positionals[0] === 'get')
|
|
266
294
|
return { command: 'tools_get', capabilityId: requireOne(positionals, 'dreamstate tools get <capability_id>'), ...output };
|
|
267
295
|
if (positionals[0] === 'run') {
|
|
@@ -293,8 +321,17 @@ function parseTools(argv) {
|
|
|
293
321
|
body.approved_effect_unknown = true;
|
|
294
322
|
if (values['max-credits'] !== undefined)
|
|
295
323
|
body.max_credits = nonNegativeNumber(values['max-credits'], '--max-credits');
|
|
324
|
+
if (body.max_live_sends !== undefined) {
|
|
325
|
+
throw new errors_1.CliUsageError('max_live_sends is a capability parameter. Put it in params.max_live_sends or pass --max-live-sends.');
|
|
326
|
+
}
|
|
327
|
+
if (values['max-live-sends'] !== undefined) {
|
|
328
|
+
const params = body.params;
|
|
329
|
+
if (!params || typeof params !== 'object' || Array.isArray(params))
|
|
330
|
+
throw new errors_1.CliUsageError('tools run params must be an object');
|
|
331
|
+
params.max_live_sends = positiveInteger(values['max-live-sends'], '--max-live-sends');
|
|
332
|
+
}
|
|
296
333
|
if (values['quote-hash'] !== undefined) {
|
|
297
|
-
if (
|
|
334
|
+
if (!runContract_1.QUOTE_HASH_PATTERN.test(values['quote-hash']))
|
|
298
335
|
throw new errors_1.CliUsageError('--quote-hash must be the sha256:<64 hex> quote_hash a dry run returned');
|
|
299
336
|
body.quote_hash = values['quote-hash'];
|
|
300
337
|
}
|
|
@@ -317,6 +354,9 @@ function parseTools(argv) {
|
|
|
317
354
|
if (body.mode !== undefined)
|
|
318
355
|
requireToolsRunMode(body);
|
|
319
356
|
const waitTimeout = values['wait-timeout'] === undefined ? 120 : nonNegativeNumber(values['wait-timeout'], '--wait-timeout');
|
|
357
|
+
if (values['idempotency-key'] !== undefined && values['idempotency-key'].length > runContract_1.IDEMPOTENCY_KEY_MAX_LENGTH) {
|
|
358
|
+
throw new errors_1.CliUsageError(`--idempotency-key must be at most ${runContract_1.IDEMPOTENCY_KEY_MAX_LENGTH} characters`);
|
|
359
|
+
}
|
|
320
360
|
return { command: 'tools_run', capabilityId, body, waitTimeout, ...(values['no-wait'] ? { noWait: true } : {}), ...(values['turn-token'] ? { turnToken: values['turn-token'] } : {}), ...(values['idempotency-key'] ? { idempotencyKey: values['idempotency-key'] } : {}), ...(values.open ? { open: true } : {}), ...output };
|
|
321
361
|
}
|
|
322
362
|
throw new errors_1.CliUsageError('Usage: dreamstate tools <search|get|run>');
|
|
@@ -374,7 +414,7 @@ function runsListLimit(raw) {
|
|
|
374
414
|
return value;
|
|
375
415
|
}
|
|
376
416
|
function parseRuns(argv) {
|
|
377
|
-
const { values, positionals } = (0, node_util_1.parseArgs)({ args: argv, options: { json: { type: 'string' }, limit: { type: 'string' }, cursor: { type: 'string' }, reason: { type: 'string' }, 'state-version': { type: 'string' }, 'idempotency-key': { type: 'string' }, open: { type: 'boolean' }, 'json-output': { type: 'boolean' }, help: { type: 'boolean', short: 'h' } }, allowPositionals: true, strict: true });
|
|
417
|
+
const { values, positionals } = (0, node_util_1.parseArgs)({ args: argv, options: { json: { type: 'string' }, limit: { type: 'string' }, cursor: { type: 'string' }, reason: { type: 'string' }, 'state-version': { type: 'string' }, 'idempotency-key': { type: 'string' }, 'wait-timeout': { type: 'string' }, open: { type: 'boolean' }, 'json-output': { type: 'boolean' }, help: { type: 'boolean', short: 'h' } }, allowPositionals: true, strict: true });
|
|
378
418
|
if (values.help)
|
|
379
419
|
return { command: 'help' };
|
|
380
420
|
const output = outputOption(values);
|
|
@@ -390,19 +430,39 @@ function parseRuns(argv) {
|
|
|
390
430
|
}
|
|
391
431
|
return { command: 'runs_list', query, ...output };
|
|
392
432
|
}
|
|
433
|
+
if (positionals[0] === 'events') {
|
|
434
|
+
const runId = requireOne(positionals, 'dreamstate runs events <run_id>');
|
|
435
|
+
const query = {};
|
|
436
|
+
if (values.limit !== undefined)
|
|
437
|
+
query.limit = runsListLimit(values.limit);
|
|
438
|
+
if (values.cursor !== undefined) {
|
|
439
|
+
const cursor = values.cursor.trim();
|
|
440
|
+
if (!cursor)
|
|
441
|
+
throw new errors_1.CliUsageError('--cursor must be a non-empty string');
|
|
442
|
+
query.cursor = cursor;
|
|
443
|
+
}
|
|
444
|
+
return { command: 'runs_events', runId, ...(Object.keys(query).length ? { query } : {}), ...output };
|
|
445
|
+
}
|
|
393
446
|
if (values.limit !== undefined || values.cursor !== undefined) {
|
|
394
|
-
throw new errors_1.CliUsageError('--limit and --cursor are only valid on runs list');
|
|
447
|
+
throw new errors_1.CliUsageError('--limit and --cursor are only valid on runs list and runs events');
|
|
395
448
|
}
|
|
396
449
|
if (positionals[0] === 'resume') {
|
|
397
450
|
// The server retired generic run resume (verifyExecutionDoorCollapse.ts blocks the
|
|
398
451
|
// route), so there is nothing to call. Say where the replacement is.
|
|
399
452
|
throw new errors_1.CliUsageError('runs resume was retired: the server has no generic run resume. A table run checkpoint resumes with: dreamstate tools run tables.table_runs.resume --params \'{...}\' --live. Start a new run for anything else.');
|
|
400
453
|
}
|
|
401
|
-
const runId = requireOne(positionals, `dreamstate runs ${positionals[0] ?? '<get|events|cancel>'} <run_id>`);
|
|
402
|
-
if (positionals[0] === 'get')
|
|
454
|
+
const runId = requireOne(positionals, `dreamstate runs ${positionals[0] ?? '<get|status|wait|events|cancel>'} <run_id>`);
|
|
455
|
+
if (positionals[0] === 'get' || positionals[0] === 'status') {
|
|
456
|
+
if (values['wait-timeout'] !== undefined)
|
|
457
|
+
throw new errors_1.CliUsageError('--wait-timeout is only valid on runs wait');
|
|
403
458
|
return { command: 'runs_get', runId, ...output };
|
|
404
|
-
|
|
405
|
-
|
|
459
|
+
}
|
|
460
|
+
if (positionals[0] === 'wait') {
|
|
461
|
+
const waitTimeout = values['wait-timeout'] === undefined ? 120 : nonNegativeNumber(values['wait-timeout'], '--wait-timeout');
|
|
462
|
+
return { command: 'runs_wait', runId, waitTimeout, ...output };
|
|
463
|
+
}
|
|
464
|
+
if (values['wait-timeout'] !== undefined)
|
|
465
|
+
throw new errors_1.CliUsageError('--wait-timeout is only valid on runs wait');
|
|
406
466
|
if (positionals[0] === 'cancel') {
|
|
407
467
|
const idempotency = values['idempotency-key'] ? { idempotencyKey: values['idempotency-key'] } : {};
|
|
408
468
|
if (values.json && (values['state-version'] !== undefined || values.reason)) {
|
|
@@ -419,7 +479,13 @@ function parseRuns(argv) {
|
|
|
419
479
|
...output,
|
|
420
480
|
};
|
|
421
481
|
}
|
|
422
|
-
throw new errors_1.CliUsageError('Usage: dreamstate runs <list|get|events|cancel> <run_id>');
|
|
482
|
+
throw new errors_1.CliUsageError('Usage: dreamstate runs <list|get|status|wait|events|cancel> <run_id>');
|
|
483
|
+
}
|
|
484
|
+
function sequencesCommands() {
|
|
485
|
+
return require('./commands/sequences');
|
|
486
|
+
}
|
|
487
|
+
function workflowsCommands() {
|
|
488
|
+
return require('./commands/workflows');
|
|
423
489
|
}
|
|
424
490
|
function normalizeJsonOutputAlias(argv) {
|
|
425
491
|
return argv.map((argument, index) => argument === '--json' && (index === argv.length - 1 || argv[index + 1]?.startsWith('-'))
|
|
@@ -521,17 +587,15 @@ function parseCliArgs(argv) {
|
|
|
521
587
|
if (group === 'runs')
|
|
522
588
|
return parseRuns(rest);
|
|
523
589
|
if (group === 'sequences')
|
|
524
|
-
return
|
|
590
|
+
return sequencesCommands().parseSequencesCommand(rest);
|
|
525
591
|
if (group === 'workflows')
|
|
526
|
-
return
|
|
592
|
+
return workflowsCommands().parseWorkflowsCommand(rest);
|
|
527
593
|
throw new errors_1.CliUsageError(`Unknown command: ${group}`);
|
|
528
594
|
}
|
|
529
595
|
function print(value, stdout, compact) {
|
|
530
|
-
//
|
|
531
|
-
//
|
|
532
|
-
|
|
533
|
-
// to the caller's own session, not a credential, and MCP and REST return it too.
|
|
534
|
-
stdout.write(`${JSON.stringify(value, null, compact ? 0 : 2)}\n`);
|
|
596
|
+
// tool_turn_token stays: it is a short-lived fetch fence, not a credential.
|
|
597
|
+
// Provider USD does not. Customer maps (values, cells, params, ...) are left whole.
|
|
598
|
+
stdout.write(`${JSON.stringify((0, money_1.scrubCliOutput)(value), null, compact ? 0 : 2)}\n`);
|
|
535
599
|
}
|
|
536
600
|
function printPackRoute(value, stdout) {
|
|
537
601
|
const data = value && typeof value === 'object' && !Array.isArray(value)
|
|
@@ -557,7 +621,7 @@ function printPackRoute(value, stdout) {
|
|
|
557
621
|
continue;
|
|
558
622
|
const { pack_id: packId, reason } = alternate;
|
|
559
623
|
if (typeof packId === 'string')
|
|
560
|
-
stdout.write(`${packId}${typeof reason === 'string' ? `: ${reason}` : ''}\n`);
|
|
624
|
+
stdout.write(`${(0, money_1.scrubDollarText)(packId)}${typeof reason === 'string' ? `: ${(0, money_1.scrubDollarText)(reason)}` : ''}\n`);
|
|
561
625
|
}
|
|
562
626
|
}
|
|
563
627
|
/**
|
|
@@ -721,12 +785,16 @@ function exitCodeForError(error) {
|
|
|
721
785
|
// "a person has to decide", and an update-required refusal is 426.
|
|
722
786
|
if (errorCode === 'cli_update_required')
|
|
723
787
|
return errors_1.CLI_EXIT.UPDATE_REQUIRED;
|
|
724
|
-
|
|
725
|
-
|
|
788
|
+
// Local transport failures stamp repair.kind ask_user (read the target back,
|
|
789
|
+
// then ask a person). Their published exits win over that repair.
|
|
726
790
|
if (errorCode === 'request_timeout')
|
|
727
791
|
return errors_1.CLI_EXIT.TIMEOUT;
|
|
792
|
+
if (errorCode === 'network_error')
|
|
793
|
+
return errors_1.CLI_EXIT.TRANSPORT;
|
|
728
794
|
if ((0, errors_1.isLocalRefusalCode)(errorCode))
|
|
729
795
|
return errors_1.CLI_EXIT.REFUSED;
|
|
796
|
+
if ((0, errors_1.isApprovalRepair)(error))
|
|
797
|
+
return errors_1.CLI_EXIT.APPROVAL;
|
|
730
798
|
const status = error instanceof client_1.CliError ? error.status : 0;
|
|
731
799
|
if (status === 401 || status === 403)
|
|
732
800
|
return errors_1.CLI_EXIT.AUTH;
|
|
@@ -734,8 +802,6 @@ function exitCodeForError(error) {
|
|
|
734
802
|
return errors_1.CLI_EXIT.NOT_FOUND;
|
|
735
803
|
if (status === 429)
|
|
736
804
|
return errors_1.CLI_EXIT.RATE_LIMITED;
|
|
737
|
-
if (errorCode === 'network_error')
|
|
738
|
-
return errors_1.CLI_EXIT.TRANSPORT;
|
|
739
805
|
if (status >= 500 || errorCode === 'invalid_response')
|
|
740
806
|
return errors_1.CLI_EXIT.SERVER;
|
|
741
807
|
if (status >= 400)
|
|
@@ -797,6 +863,23 @@ function whoamiData(value) {
|
|
|
797
863
|
const data = value && typeof value === 'object' ? value.data : undefined;
|
|
798
864
|
return data && typeof data === 'object' ? data : {};
|
|
799
865
|
}
|
|
866
|
+
const WORKSPACE_MISMATCH_MESSAGE = 'The server acted in a different workspace than the one you approved.';
|
|
867
|
+
/** Canonical workspace id the whoami request actually acted in, or a refusal. */
|
|
868
|
+
function workspacePinFromWhoami(whoami, requested) {
|
|
869
|
+
const data = whoamiData(whoami);
|
|
870
|
+
const acted = typeof data.workspace_id === 'string' ? data.workspace_id : '';
|
|
871
|
+
const wanted = requested.trim().toLowerCase();
|
|
872
|
+
const rows = data.workspaces ?? [];
|
|
873
|
+
const match = rows.find((row) => row.id.toLowerCase() === wanted || row.slug?.toLowerCase() === wanted);
|
|
874
|
+
if (match) {
|
|
875
|
+
if (acted !== match.id)
|
|
876
|
+
throw new client_1.CliError(WORKSPACE_MISMATCH_MESSAGE, 'workspace_mismatch', 400);
|
|
877
|
+
return match.id;
|
|
878
|
+
}
|
|
879
|
+
if (rows.length === 0 && acted.toLowerCase() === wanted)
|
|
880
|
+
return acted;
|
|
881
|
+
throw new client_1.CliError(WORKSPACE_MISMATCH_MESSAGE, 'workspace_mismatch', 400);
|
|
882
|
+
}
|
|
800
883
|
/**
|
|
801
884
|
* What `dreamstate status` reports. The release identity comes from the server's
|
|
802
885
|
* own answers (envelope meta and X-Dreamstate-* headers on every response), so
|
|
@@ -804,16 +887,15 @@ function whoamiData(value) {
|
|
|
804
887
|
* "unknown", never "compatible".
|
|
805
888
|
*/
|
|
806
889
|
function statusData(whoami, health, info) {
|
|
807
|
-
|
|
808
|
-
const
|
|
809
|
-
const
|
|
810
|
-
const resolved = { ...info, server_version: serverVersion };
|
|
811
|
-
const skew = (0, client_1.describeVersionSkew)(resolved);
|
|
890
|
+
// health.data.version is not the release. server_version comes only from envelope meta.
|
|
891
|
+
const serverVersion = info.server_version;
|
|
892
|
+
const skew = (0, client_1.describeVersionSkew)(info);
|
|
812
893
|
const compatible = skew !== 'cli_below_minimum';
|
|
813
894
|
return {
|
|
814
895
|
cli_version: client_1.CLI_VERSION,
|
|
815
896
|
api_version: serverVersion,
|
|
816
897
|
server_version: serverVersion,
|
|
898
|
+
registry_hash: info.registry_hash,
|
|
817
899
|
release_sha: info.release_sha,
|
|
818
900
|
minimum_cli_version: info.minimum_cli_version,
|
|
819
901
|
minimum_cli_version_published: info.minimum_cli_version !== null,
|
|
@@ -899,17 +981,21 @@ async function loginWithDeviceAuthorization(runtime, stdout, stderr, profile, no
|
|
|
899
981
|
for (;;) {
|
|
900
982
|
const claim = await (0, client_1.claimDeviceAuthorization)(baseUrl, authorization.device_code);
|
|
901
983
|
if (claim.status === 'ready') {
|
|
902
|
-
if (profile)
|
|
903
|
-
await (0, config_1.storeCredentialProfile)(profile, claim.token, runtimeCredentialsPath(runtime), claim.workspace.id);
|
|
904
|
-
else
|
|
905
|
-
await (0, config_1.storeApiKey)(claim.token, runtimeCredentialsPath(runtime), claim.workspace.id);
|
|
906
984
|
const client = new client_1.DreamstateClient({
|
|
907
985
|
baseUrl,
|
|
908
986
|
apiKey: claim.token,
|
|
987
|
+
workspace: claim.workspace.id,
|
|
909
988
|
requestTimeoutMs: runtime.requestTimeoutMs,
|
|
910
989
|
onVersionWarning: (message) => (runtime.stderr ?? process.stderr).write(`${message}\n`),
|
|
911
990
|
});
|
|
912
991
|
const whoami = await client.getWhoami();
|
|
992
|
+
if (whoamiData(whoami).workspace_id !== claim.workspace.id) {
|
|
993
|
+
throw new client_1.CliError(WORKSPACE_MISMATCH_MESSAGE, 'workspace_mismatch', 400);
|
|
994
|
+
}
|
|
995
|
+
if (profile)
|
|
996
|
+
await (0, config_1.storeCredentialProfile)(profile, claim.token, runtimeCredentialsPath(runtime), claim.workspace.id);
|
|
997
|
+
else
|
|
998
|
+
await (0, config_1.storeApiKey)(claim.token, runtimeCredentialsPath(runtime), claim.workspace.id);
|
|
913
999
|
const skills = await installLoginSkills(client, runtime, noSkills, stderr);
|
|
914
1000
|
print(loginResult(whoami, skills), stdout, jsonOutput);
|
|
915
1001
|
return;
|
|
@@ -1028,10 +1114,11 @@ async function runCli(argv = process.argv.slice(2), runtime = {}) {
|
|
|
1028
1114
|
onVersionWarning: (message) => stderr.write(`${message}\n`),
|
|
1029
1115
|
});
|
|
1030
1116
|
const whoami = await client.getWhoami();
|
|
1117
|
+
const pinned = requested ? workspacePinFromWhoami(whoami, requested) : null;
|
|
1031
1118
|
if (command.profile)
|
|
1032
|
-
await (0, config_1.storeCredentialProfile)(command.profile, token, runtimeCredentialsPath(runtime));
|
|
1119
|
+
await (0, config_1.storeCredentialProfile)(command.profile, token, runtimeCredentialsPath(runtime), pinned);
|
|
1033
1120
|
else
|
|
1034
|
-
await (0, config_1.storeApiKey)(token, runtimeCredentialsPath(runtime));
|
|
1121
|
+
await (0, config_1.storeApiKey)(token, runtimeCredentialsPath(runtime), pinned);
|
|
1035
1122
|
const skills = await installLoginSkills(client, runtime, Boolean(command.noSkills), stderr);
|
|
1036
1123
|
print(loginResult(whoami, skills), stdout, Boolean(command.jsonOutput));
|
|
1037
1124
|
process.exitCode = errors_1.CLI_EXIT.SUCCESS;
|
|
@@ -1073,10 +1160,19 @@ async function runCli(argv = process.argv.slice(2), runtime = {}) {
|
|
|
1073
1160
|
const key = await readLoginKey(command, runtime);
|
|
1074
1161
|
if (!(0, config_1.isDreamstateToken)(key))
|
|
1075
1162
|
throw new errors_1.CliUsageError('Dreamstate API keys must start with ds_user_ or ds_live_.');
|
|
1163
|
+
const environment = runtime.env ?? process.env;
|
|
1164
|
+
const requested = extracted.workspace ?? environment.DREAMSTATE_WORKSPACE?.trim();
|
|
1165
|
+
const client = new client_1.DreamstateClient({
|
|
1166
|
+
baseUrl: (0, config_1.resolveApiBaseUrl)(environment),
|
|
1167
|
+
apiKey: key,
|
|
1168
|
+
...(requested ? { workspace: requested } : {}),
|
|
1169
|
+
requestTimeoutMs: runtime.requestTimeoutMs,
|
|
1170
|
+
onVersionWarning: (message) => stderr.write(`${message}\n`),
|
|
1171
|
+
});
|
|
1172
|
+
const pinned = requested ? workspacePinFromWhoami(await client.getWhoami(), requested) : null;
|
|
1076
1173
|
const path = command.profile
|
|
1077
|
-
? await (0, config_1.storeCredentialProfile)(command.profile, key, runtimeCredentialsPath(runtime))
|
|
1078
|
-
: await (0, config_1.storeApiKey)(key, runtimeCredentialsPath(runtime));
|
|
1079
|
-
const client = new client_1.DreamstateClient({ baseUrl: (0, config_1.resolveApiBaseUrl)(runtime.env ?? process.env), apiKey: key, requestTimeoutMs: runtime.requestTimeoutMs, onVersionWarning: (message) => stderr.write(`${message}\n`) });
|
|
1174
|
+
? await (0, config_1.storeCredentialProfile)(command.profile, key, runtimeCredentialsPath(runtime), pinned)
|
|
1175
|
+
: await (0, config_1.storeApiKey)(key, runtimeCredentialsPath(runtime), pinned);
|
|
1080
1176
|
const skills = await installLoginSkills(client, runtime, Boolean(command.noSkills), stderr);
|
|
1081
1177
|
print({ ok: true, data: { credentials_path: path, skills }, meta: {} }, stdout, Boolean(command.jsonOutput));
|
|
1082
1178
|
process.exitCode = errors_1.CLI_EXIT.SUCCESS;
|
|
@@ -1168,12 +1264,10 @@ async function runCli(argv = process.argv.slice(2), runtime = {}) {
|
|
|
1168
1264
|
// Resolving credentials first would refuse it with not_authenticated.
|
|
1169
1265
|
if (command.command === 'pack' && command.verb === 'init') {
|
|
1170
1266
|
if (command.pack === 'sequences') {
|
|
1171
|
-
await
|
|
1172
|
-
.runSequencesCommand(undefined, command, stdout);
|
|
1267
|
+
await sequencesCommands().runSequencesCommand(undefined, command, stdout);
|
|
1173
1268
|
}
|
|
1174
1269
|
else {
|
|
1175
|
-
await
|
|
1176
|
-
.runWorkflowsCommand(undefined, command, stdout);
|
|
1270
|
+
await workflowsCommands().runWorkflowsCommand(undefined, command, stdout);
|
|
1177
1271
|
}
|
|
1178
1272
|
process.exitCode = errors_1.CLI_EXIT.SUCCESS;
|
|
1179
1273
|
return;
|
|
@@ -1341,8 +1435,19 @@ async function runCli(argv = process.argv.slice(2), runtime = {}) {
|
|
|
1341
1435
|
case 'runs_get':
|
|
1342
1436
|
result = await client.getRun(command.runId);
|
|
1343
1437
|
break;
|
|
1438
|
+
case 'runs_wait': {
|
|
1439
|
+
const initial = await client.getRun(command.runId);
|
|
1440
|
+
const waited = await (0, runWait_1.waitForRun)(client, initial, command.waitTimeout, runtime.sleep ?? wait);
|
|
1441
|
+
const blocked = (0, gatedRun_1.refusalFromRunResult)(waited.value);
|
|
1442
|
+
if (blocked)
|
|
1443
|
+
throw blocked;
|
|
1444
|
+
result = waited.value;
|
|
1445
|
+
if (waited.timedOut)
|
|
1446
|
+
process.exitCode = runWait_1.RUN_WAIT_TIMEOUT_EXIT_CODE;
|
|
1447
|
+
break;
|
|
1448
|
+
}
|
|
1344
1449
|
case 'runs_events':
|
|
1345
|
-
result = await client.getRunEvents(command.runId);
|
|
1450
|
+
result = await client.getRunEvents(command.runId, command.query ?? {});
|
|
1346
1451
|
break;
|
|
1347
1452
|
case 'runs_cancel': {
|
|
1348
1453
|
const body = command.body ?? {
|
|
@@ -1366,10 +1471,10 @@ async function runCli(argv = process.argv.slice(2), runtime = {}) {
|
|
|
1366
1471
|
}
|
|
1367
1472
|
case 'pack': {
|
|
1368
1473
|
if (command.pack === 'sequences') {
|
|
1369
|
-
await
|
|
1474
|
+
await sequencesCommands().runSequencesCommand(gatedContext(), command, stdout);
|
|
1370
1475
|
}
|
|
1371
1476
|
else {
|
|
1372
|
-
await
|
|
1477
|
+
await workflowsCommands().runWorkflowsCommand(gatedContext(), command, stdout);
|
|
1373
1478
|
}
|
|
1374
1479
|
return;
|
|
1375
1480
|
}
|
|
@@ -1386,7 +1491,7 @@ async function runCli(argv = process.argv.slice(2), runtime = {}) {
|
|
|
1386
1491
|
}
|
|
1387
1492
|
catch (error) {
|
|
1388
1493
|
const exitCode = exitCodeForError(error);
|
|
1389
|
-
stdout.write(`${JSON.stringify(refusalEnvelope(error, exitCode))}\n`);
|
|
1494
|
+
stdout.write(`${JSON.stringify((0, money_1.scrubCliOutput)(refusalEnvelope(error, exitCode)))}\n`);
|
|
1390
1495
|
process.exitCode = exitCode;
|
|
1391
1496
|
throw error;
|
|
1392
1497
|
}
|
package/dist/money.d.ts
ADDED
|
@@ -0,0 +1,10 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Customers see credits. Provider USD (a key that pairs usd with a cost word,
|
|
3
|
+
* a cogs key other than cogs_credits, or a provider_cost / provider_spend
|
|
4
|
+
* prefix) is dropped. Dollar amounts in our own sentences become "an amount".
|
|
5
|
+
* Customer maps are not entered: annual_revenue_usd and price_usd stay.
|
|
6
|
+
*/
|
|
7
|
+
export declare function isProviderCostKey(key: string): boolean;
|
|
8
|
+
export declare function scrubDollarText(text: string): string;
|
|
9
|
+
export declare function scrubCliOutput(value: unknown, depth?: number): unknown;
|
|
10
|
+
//# sourceMappingURL=money.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"money.d.ts","sourceRoot":"","sources":["../src/money.ts"],"names":[],"mappings":"AAAA;;;;;GAKG;AAwBH,wBAAgB,iBAAiB,CAAC,GAAG,EAAE,MAAM,GAAG,OAAO,CAQtD;AAED,wBAAgB,eAAe,CAAC,IAAI,EAAE,MAAM,GAAG,MAAM,CAGpD;AAeD,wBAAgB,cAAc,CAAC,KAAK,EAAE,OAAO,EAAE,KAAK,SAAI,GAAG,OAAO,CAWjE"}
|
package/dist/money.js
ADDED
|
@@ -0,0 +1,75 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
/**
|
|
3
|
+
* Customers see credits. Provider USD (a key that pairs usd with a cost word,
|
|
4
|
+
* a cogs key other than cogs_credits, or a provider_cost / provider_spend
|
|
5
|
+
* prefix) is dropped. Dollar amounts in our own sentences become "an amount".
|
|
6
|
+
* Customer maps are not entered: annual_revenue_usd and price_usd stay.
|
|
7
|
+
*/
|
|
8
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
9
|
+
exports.isProviderCostKey = isProviderCostKey;
|
|
10
|
+
exports.scrubDollarText = scrubDollarText;
|
|
11
|
+
exports.scrubCliOutput = scrubCliOutput;
|
|
12
|
+
const PROVIDER_COST_WORDS = new Set([
|
|
13
|
+
'provider', 'cost', 'spend', 'spent', 'worst', 'reserved', 'counted', 'settled', 'ledger',
|
|
14
|
+
'snapshot', 'actual', 'platform', 'vendor', 'upstream', 'internal',
|
|
15
|
+
]);
|
|
16
|
+
const MARGIN_CONTEXT = new Set(['provider', 'platform', 'cogs', 'vendor']);
|
|
17
|
+
const CUSTOMER_DATA_CONTAINERS = new Set([
|
|
18
|
+
'values', 'cells', 'cell_values', 'row_values', 'field_values', 'record_values',
|
|
19
|
+
'fields', 'custom_fields', 'attributes', 'payload', 'params',
|
|
20
|
+
]);
|
|
21
|
+
const SCHEMA_KEYWORDS = new Set([
|
|
22
|
+
'type', '$ref', 'anyOf', 'oneOf', 'allOf', 'enum', 'const', 'properties', 'items', 'description', 'not',
|
|
23
|
+
]);
|
|
24
|
+
const DOLLAR_AMOUNT_TEXT = /(?:US\$|\$)\s?\d[\d,]*(?:\.\d+)?(?:\s?(?:USD|dollars?))?|\b\d[\d,]*(?:\.\d+)?\s?(?:USD|dollars?)\b|\bUSD\s?\d[\d,]*(?:\.\d+)?/gi;
|
|
25
|
+
function snake(key) {
|
|
26
|
+
return key.replace(/([a-z0-9])([A-Z])/g, '$1_$2').replace(/[-\s.]+/g, '_').toLowerCase();
|
|
27
|
+
}
|
|
28
|
+
function isPlainObject(value) {
|
|
29
|
+
return Boolean(value) && typeof value === 'object' && !Array.isArray(value);
|
|
30
|
+
}
|
|
31
|
+
function isProviderCostKey(key) {
|
|
32
|
+
const normalized = snake(key);
|
|
33
|
+
const tokens = normalized.split('_');
|
|
34
|
+
if (tokens.includes('cogs') && !tokens.includes('credits'))
|
|
35
|
+
return true;
|
|
36
|
+
if (normalized.startsWith('provider_cost') || normalized.startsWith('provider_spend'))
|
|
37
|
+
return true;
|
|
38
|
+
if (tokens.includes('usd') && tokens.some((token) => PROVIDER_COST_WORDS.has(token)))
|
|
39
|
+
return true;
|
|
40
|
+
if (tokens.includes('margin') && tokens.some((token) => MARGIN_CONTEXT.has(token)))
|
|
41
|
+
return true;
|
|
42
|
+
return false;
|
|
43
|
+
}
|
|
44
|
+
function scrubDollarText(text) {
|
|
45
|
+
DOLLAR_AMOUNT_TEXT.lastIndex = 0;
|
|
46
|
+
return text.replace(DOLLAR_AMOUNT_TEXT, 'an amount').replace(/\s{2,}/g, ' ');
|
|
47
|
+
}
|
|
48
|
+
function looksLikeSchemaProperties(value) {
|
|
49
|
+
if (!isPlainObject(value))
|
|
50
|
+
return false;
|
|
51
|
+
const entries = Object.values(value);
|
|
52
|
+
return entries.length > 0 && entries.every((entry) => isPlainObject(entry) && Object.keys(entry).some((key) => SCHEMA_KEYWORDS.has(key)));
|
|
53
|
+
}
|
|
54
|
+
function isCustomerContainer(key, value) {
|
|
55
|
+
if (key === 'properties')
|
|
56
|
+
return !looksLikeSchemaProperties(value);
|
|
57
|
+
return CUSTOMER_DATA_CONTAINERS.has(snake(key)) && isPlainObject(value);
|
|
58
|
+
}
|
|
59
|
+
function scrubCliOutput(value, depth = 0) {
|
|
60
|
+
if (depth > 32)
|
|
61
|
+
return value;
|
|
62
|
+
if (typeof value === 'string')
|
|
63
|
+
return scrubDollarText(value);
|
|
64
|
+
if (Array.isArray(value))
|
|
65
|
+
return value.map((entry) => scrubCliOutput(entry, depth + 1));
|
|
66
|
+
if (!isPlainObject(value))
|
|
67
|
+
return value;
|
|
68
|
+
const output = {};
|
|
69
|
+
for (const [key, child] of Object.entries(value)) {
|
|
70
|
+
if (isProviderCostKey(key))
|
|
71
|
+
continue;
|
|
72
|
+
output[key] = isCustomerContainer(key, child) ? child : scrubCliOutput(child, depth + 1);
|
|
73
|
+
}
|
|
74
|
+
return output;
|
|
75
|
+
}
|
|
@@ -0,0 +1,6 @@
|
|
|
1
|
+
import type { CapabilityPosture } from './capabilityPosture';
|
|
2
|
+
export declare function lookupPosture(capabilityId: string): CapabilityPosture | null;
|
|
3
|
+
export declare function rememberPosture(capabilityId: string, posture: CapabilityPosture): void;
|
|
4
|
+
/** Records the hash from a response. A change clears cached postures. */
|
|
5
|
+
export declare function noteRegistryHash(hash: string | null): void;
|
|
6
|
+
//# sourceMappingURL=registryManifest.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"registryManifest.d.ts","sourceRoot":"","sources":["../src/registryManifest.ts"],"names":[],"mappings":"AAGA,OAAO,KAAK,EAAE,iBAAiB,EAAE,MAAM,qBAAqB,CAAC;AAuD7D,wBAAgB,aAAa,CAAC,YAAY,EAAE,MAAM,GAAG,iBAAiB,GAAG,IAAI,CAE5E;AAED,wBAAgB,eAAe,CAAC,YAAY,EAAE,MAAM,EAAE,OAAO,EAAE,iBAAiB,GAAG,IAAI,CAItF;AAED,yEAAyE;AACzE,wBAAgB,gBAAgB,CAAC,IAAI,EAAE,MAAM,GAAG,IAAI,GAAG,IAAI,CAK1D"}
|