@sente-labs/cli 0.10.0 → 0.13.0

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.
@@ -1,245 +0,0 @@
1
- "use strict";
2
- var __createBinding = (this && this.__createBinding) || (Object.create ? (function(o, m, k, k2) {
3
- if (k2 === undefined) k2 = k;
4
- var desc = Object.getOwnPropertyDescriptor(m, k);
5
- if (!desc || ("get" in desc ? !m.__esModule : desc.writable || desc.configurable)) {
6
- desc = { enumerable: true, get: function() { return m[k]; } };
7
- }
8
- Object.defineProperty(o, k2, desc);
9
- }) : (function(o, m, k, k2) {
10
- if (k2 === undefined) k2 = k;
11
- o[k2] = m[k];
12
- }));
13
- var __setModuleDefault = (this && this.__setModuleDefault) || (Object.create ? (function(o, v) {
14
- Object.defineProperty(o, "default", { enumerable: true, value: v });
15
- }) : function(o, v) {
16
- o["default"] = v;
17
- });
18
- var __importStar = (this && this.__importStar) || (function () {
19
- var ownKeys = function(o) {
20
- ownKeys = Object.getOwnPropertyNames || function (o) {
21
- var ar = [];
22
- for (var k in o) if (Object.prototype.hasOwnProperty.call(o, k)) ar[ar.length] = k;
23
- return ar;
24
- };
25
- return ownKeys(o);
26
- };
27
- return function (mod) {
28
- if (mod && mod.__esModule) return mod;
29
- var result = {};
30
- if (mod != null) for (var k = ownKeys(mod), i = 0; i < k.length; i++) if (k[i] !== "default") __createBinding(result, mod, k[i]);
31
- __setModuleDefault(result, mod);
32
- return result;
33
- };
34
- })();
35
- Object.defineProperty(exports, "__esModule", { value: true });
36
- exports.registerSecretCommands = registerSecretCommands;
37
- const readline = __importStar(require("readline"));
38
- const client_1 = require("../client");
39
- const output_1 = require("../output");
40
- /**
41
- * Read a secret value securely from the user. Two paths:
42
- * - TTY interactive: prompt with input masking (no echo). User pastes value.
43
- * - Non-TTY / --value-stdin: read entire stdin until EOF, strip trailing newline.
44
- *
45
- * We intentionally do NOT accept a `--value <plain>` flag because it leaks the
46
- * value to shell history. `--value-stdin` is the only programmatic path.
47
- */
48
- async function readSecretValue(useStdin) {
49
- if (useStdin || !process.stdin.isTTY) {
50
- return readAllStdin();
51
- }
52
- return promptHidden('Secret value (input hidden): ');
53
- }
54
- function readAllStdin() {
55
- return new Promise((resolve, reject) => {
56
- let data = '';
57
- process.stdin.setEncoding('utf8');
58
- process.stdin.on('data', (chunk) => (data += chunk));
59
- process.stdin.on('end', () => resolve(data.replace(/\n+$/, '')));
60
- process.stdin.on('error', reject);
61
- });
62
- }
63
- /**
64
- * readline-based hidden prompt. Echoes nothing while the user types so the
65
- * secret never appears on-screen or in scrollback. Falls back to plain prompt
66
- * if stdin isn't a TTY (shouldn't happen since the caller already gates this).
67
- */
68
- function promptHidden(question) {
69
- return new Promise((resolve) => {
70
- const rl = readline.createInterface({
71
- input: process.stdin,
72
- output: process.stdout,
73
- terminal: true,
74
- });
75
- // Mute the output stream during input so keystrokes don't echo.
76
- const stdoutWrite = process.stdout.write.bind(process.stdout);
77
- let muted = false;
78
- rl._writeToOutput = (str) => {
79
- if (muted) {
80
- // After we mute, only let the newline at the end pass.
81
- if (str.includes('\n'))
82
- stdoutWrite('\n');
83
- return;
84
- }
85
- stdoutWrite(str);
86
- };
87
- rl.question(question, (answer) => {
88
- rl.close();
89
- resolve(answer);
90
- });
91
- muted = true;
92
- });
93
- }
94
- function promptText(question, fallback) {
95
- return new Promise((resolve) => {
96
- const rl = readline.createInterface({ input: process.stdin, output: process.stdout });
97
- const suffix = fallback ? ` [${fallback}]` : '';
98
- rl.question(`${question}${suffix}: `, (answer) => {
99
- rl.close();
100
- resolve(answer.trim() || fallback || '');
101
- });
102
- });
103
- }
104
- function registerSecretCommands(program, globalOpts) {
105
- const secret = program.command('secret').description('Secret commands');
106
- secret
107
- .command('create')
108
- .description('Create a new secret in the current organization')
109
- .requiredOption('--name <key>', 'secret key (referenced in steps as {{secret.name}})')
110
- .option('--description <text>', 'human-readable description')
111
- .option('--target-url <url>', 'restrict secret to matching URLs')
112
- .option('--project <id>', 'link the new secret to this project (repeatable)', collect, [])
113
- .option('--value-stdin', 'read the secret value from stdin (use for piping)')
114
- .action(async (cmdOpts) => {
115
- const opts = globalOpts();
116
- try {
117
- const value = await readSecretValue(!!cmdOpts.valueStdin);
118
- if (!value) {
119
- throw new Error('Secret value is required.');
120
- }
121
- // Description is required by the gateway. Prompt for one if missing.
122
- let description = cmdOpts.description;
123
- if (!description) {
124
- if (process.stdin.isTTY && !cmdOpts.valueStdin && !(0, output_1.isJson)(opts)) {
125
- description = await promptText('Description (visible to the agent)');
126
- }
127
- if (!description) {
128
- // Use the key as a fallback so the create still works in
129
- // non-interactive contexts without a separate flag.
130
- description = cmdOpts.name;
131
- }
132
- }
133
- const client = new client_1.GatewayClient();
134
- const res = await client.request('/api/secrets', {
135
- method: 'POST',
136
- body: {
137
- key: cmdOpts.name,
138
- description,
139
- type: 'simple',
140
- value,
141
- targetUrl: cmdOpts.targetUrl,
142
- projectIds: cmdOpts.project.length > 0 ? cmdOpts.project : undefined,
143
- },
144
- });
145
- (0, output_1.printSuccess)({ secret: redact(res.secret) }, () => {
146
- const s = res.secret;
147
- process.stdout.write(`Created secret: ${s.key} (${s.id})\n`);
148
- if (s.targetUrl)
149
- process.stdout.write(`Target URL: ${s.targetUrl}\n`);
150
- if (cmdOpts.project.length > 0) {
151
- process.stdout.write(`Linked to ${cmdOpts.project.length} project(s).\n`);
152
- }
153
- process.stdout.write(`Reference in steps as: {{secret.${s.key}}}\n`);
154
- }, opts);
155
- }
156
- catch (err) {
157
- process.exit((0, output_1.printError)(err, opts));
158
- }
159
- });
160
- secret
161
- .command('list')
162
- .description('List secrets visible to the current user')
163
- .action(async () => {
164
- const opts = globalOpts();
165
- try {
166
- const client = new client_1.GatewayClient();
167
- const res = await client.request('/api/secrets');
168
- (0, output_1.printSuccess)({ secrets: res.secrets.map(redact) }, () => {
169
- if (res.secrets.length === 0) {
170
- process.stdout.write('No secrets found.\n');
171
- return;
172
- }
173
- for (const s of res.secrets) {
174
- const projects = s.linkedProjects?.length
175
- ? ` -> ${s.linkedProjects.map((p) => p.name).join(', ')}`
176
- : '';
177
- process.stdout.write(`${s.id} ${s.key.padEnd(28)} ${s.type}${projects}\n`);
178
- }
179
- }, opts);
180
- }
181
- catch (err) {
182
- process.exit((0, output_1.printError)(err, opts));
183
- }
184
- });
185
- secret
186
- .command('link')
187
- .description('Link a secret to a project')
188
- .argument('<secretId>', 'secret id')
189
- .argument('<projectId>', 'project id')
190
- .action(async (secretId, projectId) => {
191
- const opts = globalOpts();
192
- try {
193
- const client = new client_1.GatewayClient();
194
- await client.request(`/api/secrets/${secretId}/link/${projectId}`, { method: 'POST' });
195
- (0, output_1.printSuccess)({ ok: true, secretId, projectId }, `Linked secret ${secretId} to project ${projectId}`, opts);
196
- }
197
- catch (err) {
198
- process.exit((0, output_1.printError)(err, opts));
199
- }
200
- });
201
- secret
202
- .command('unlink')
203
- .description('Unlink a secret from a project')
204
- .argument('<secretId>', 'secret id')
205
- .argument('<projectId>', 'project id')
206
- .action(async (secretId, projectId) => {
207
- const opts = globalOpts();
208
- try {
209
- const client = new client_1.GatewayClient();
210
- await client.request(`/api/secrets/${secretId}/link/${projectId}`, { method: 'DELETE' });
211
- (0, output_1.printSuccess)({ ok: true, secretId, projectId }, `Unlinked secret ${secretId} from project ${projectId}`, opts);
212
- }
213
- catch (err) {
214
- process.exit((0, output_1.printError)(err, opts));
215
- }
216
- });
217
- secret
218
- .command('delete')
219
- .description('Delete a secret (removes it from all linked projects)')
220
- .argument('<secretId>', 'secret id')
221
- .action(async (secretId) => {
222
- const opts = globalOpts();
223
- try {
224
- const client = new client_1.GatewayClient();
225
- await client.request(`/api/secrets/${secretId}`, { method: 'DELETE' });
226
- (0, output_1.printSuccess)({ ok: true, secretId }, `Deleted secret ${secretId}`, opts);
227
- }
228
- catch (err) {
229
- process.exit((0, output_1.printError)(err, opts));
230
- }
231
- });
232
- }
233
- /**
234
- * Strip anything that could contain the raw value from server responses before
235
- * we print or return them. The gateway never sends values (only metadata), but
236
- * defending in depth costs nothing.
237
- */
238
- function redact(s) {
239
- const { ...safe } = s;
240
- return safe;
241
- }
242
- function collect(value, previous) {
243
- return previous.concat([value]);
244
- }
245
- //# sourceMappingURL=secret.js.map
@@ -1 +0,0 @@
1
- {"version":3,"file":"secret.js","sourceRoot":"","sources":["../../src/commands/secret.ts"],"names":[],"mappings":"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"}
@@ -1,425 +0,0 @@
1
- "use strict";
2
- var __createBinding = (this && this.__createBinding) || (Object.create ? (function(o, m, k, k2) {
3
- if (k2 === undefined) k2 = k;
4
- var desc = Object.getOwnPropertyDescriptor(m, k);
5
- if (!desc || ("get" in desc ? !m.__esModule : desc.writable || desc.configurable)) {
6
- desc = { enumerable: true, get: function() { return m[k]; } };
7
- }
8
- Object.defineProperty(o, k2, desc);
9
- }) : (function(o, m, k, k2) {
10
- if (k2 === undefined) k2 = k;
11
- o[k2] = m[k];
12
- }));
13
- var __setModuleDefault = (this && this.__setModuleDefault) || (Object.create ? (function(o, v) {
14
- Object.defineProperty(o, "default", { enumerable: true, value: v });
15
- }) : function(o, v) {
16
- o["default"] = v;
17
- });
18
- var __importStar = (this && this.__importStar) || (function () {
19
- var ownKeys = function(o) {
20
- ownKeys = Object.getOwnPropertyNames || function (o) {
21
- var ar = [];
22
- for (var k in o) if (Object.prototype.hasOwnProperty.call(o, k)) ar[ar.length] = k;
23
- return ar;
24
- };
25
- return ownKeys(o);
26
- };
27
- return function (mod) {
28
- if (mod && mod.__esModule) return mod;
29
- var result = {};
30
- if (mod != null) for (var k = ownKeys(mod), i = 0; i < k.length; i++) if (k[i] !== "default") __createBinding(result, mod, k[i]);
31
- __setModuleDefault(result, mod);
32
- return result;
33
- };
34
- })();
35
- Object.defineProperty(exports, "__esModule", { value: true });
36
- exports.registerTaskCommands = registerTaskCommands;
37
- const fs = __importStar(require("fs"));
38
- const client_1 = require("../client");
39
- const output_1 = require("../output");
40
- /**
41
- * Translate raw gateway shape into the CLI-stable results envelope
42
- * documented in plans/sente-cc-skill.md. Insulates CC from DB drift.
43
- */
44
- function buildResultsPayload(task, opts) {
45
- const steps = (task.steps ?? []).map((s) => {
46
- const result = (s.result || {});
47
- return {
48
- index: s.stepOrder,
49
- action: s.action,
50
- assertion: s.assertion ?? '',
51
- status: s.status,
52
- actual: result.actual ?? null,
53
- reasoning: result.reasoning ?? null,
54
- failureCategory: result.failureCategory ?? null,
55
- suggestedFix: result.suggestedFix ?? null,
56
- adapted: result.adapted ?? false,
57
- adaptationNote: result.adaptationNote ?? null,
58
- screenshot: s.screenshot ?? null,
59
- };
60
- });
61
- const failedStep = steps.find((s) => s.status === 'failed');
62
- const overallStatus = task.status;
63
- const base = {
64
- taskId: task.id,
65
- taskName: task.name,
66
- status: overallStatus,
67
- reportUrl: task.shortId ? `https://app.sente.run/report/${task.shortId}` : null,
68
- };
69
- if (opts.failedOnly) {
70
- return { ...base, failedStep: failedStep ?? null };
71
- }
72
- return { ...base, steps };
73
- }
74
- function registerTaskCommands(program, globalOpts) {
75
- const task = program.command('task').description('Task commands');
76
- task
77
- .command('list')
78
- .description('List tasks in the current organization (optionally scoped to a project)')
79
- .option('--project <projectId>', 'Filter by project id')
80
- .action(async (cmdOpts) => {
81
- const opts = globalOpts();
82
- try {
83
- const client = new client_1.GatewayClient();
84
- const res = await client.request('/api/tasks/list', {
85
- query: { projectId: cmdOpts.project },
86
- });
87
- (0, output_1.printSuccess)({ tasks: res.tasks }, () => {
88
- if (res.tasks.length === 0) {
89
- process.stdout.write('No tasks found.\n');
90
- return;
91
- }
92
- for (const t of res.tasks) {
93
- process.stdout.write(`${t.id} ${t.status.padEnd(12)} ${t.workflow.project.name} / ${t.workflow.name} / ${t.name}\n`);
94
- }
95
- }, opts);
96
- }
97
- catch (err) {
98
- process.exit((0, output_1.printError)(err, opts));
99
- }
100
- });
101
- task
102
- .command('show')
103
- .description('Show a task by id (or shortId)')
104
- .argument('<taskId>', 'task id or short id')
105
- .action(async (taskId) => {
106
- const opts = globalOpts();
107
- try {
108
- const client = new client_1.GatewayClient();
109
- const res = await client.request(`/api/tasks/${taskId}`);
110
- (0, output_1.printSuccess)({ task: res.task }, () => {
111
- const t = res.task;
112
- process.stdout.write(`${t.name} (${t.id})\n`);
113
- process.stdout.write(`Status: ${t.status}\n`);
114
- if (t.description)
115
- process.stdout.write(`Description: ${t.description}\n`);
116
- if (t.instruction)
117
- process.stdout.write(`Instruction:\n ${t.instruction}\n`);
118
- if (t.qaInstruction)
119
- process.stdout.write(`QA Instruction:\n ${t.qaInstruction}\n`);
120
- if (t.steps && t.steps.length > 0) {
121
- process.stdout.write(`\nSteps:\n`);
122
- for (const s of t.steps) {
123
- process.stdout.write(` ${s.stepOrder}. [${s.status}] ${s.action}\n` +
124
- (s.assertion ? ` assert: ${s.assertion}\n` : ''));
125
- }
126
- }
127
- }, opts);
128
- }
129
- catch (err) {
130
- process.exit((0, output_1.printError)(err, opts));
131
- }
132
- });
133
- task
134
- .command('create')
135
- .description('Create a new QA task with steps')
136
- .requiredOption('--workflow <id>', 'workflow id this task belongs to')
137
- .requiredOption('--name <name>', 'task name')
138
- .option('--instruction <text>', 'top-level task instruction (preserves UI mechanism)')
139
- .option('--description <text>', 'optional description')
140
- .option('--type <type>', 'task type (qa)', 'qa')
141
- .option('--steps-from <file>', 'JSON file containing the step array')
142
- .action(async (cmdOpts) => {
143
- const opts = globalOpts();
144
- try {
145
- const steps = cmdOpts.stepsFrom ? readStepsFile(cmdOpts.stepsFrom) : undefined;
146
- const body = {
147
- name: cmdOpts.name,
148
- description: cmdOpts.description,
149
- qaInstruction: cmdOpts.instruction,
150
- steps,
151
- };
152
- const client = new client_1.GatewayClient();
153
- const res = await client.request(`/api/workflows/${cmdOpts.workflow}/tasks`, { method: 'POST', body });
154
- const taskId = res.task?.id;
155
- const warnings = res.warnings ?? [];
156
- (0, output_1.printSuccess)({ task: res.task, warnings }, () => {
157
- process.stdout.write(`Created task: ${res.task.name} (${taskId})\n`);
158
- renderWarnings(warnings);
159
- }, opts);
160
- }
161
- catch (err) {
162
- renderValidationErrors(err, opts);
163
- process.exit((0, output_1.printError)(err, opts));
164
- }
165
- });
166
- task
167
- .command('update')
168
- .description('Update an existing task')
169
- .argument('<taskId>', 'task id')
170
- .option('--name <name>', 'new name')
171
- .option('--instruction <text>', 'new instruction')
172
- .option('--description <text>', 'new description')
173
- .option('--steps-from <file>', 'replace steps with the JSON file contents')
174
- // Mark this task as a critical flow that fires on a deploy webhook. `--no-on-deploy` unsets it.
175
- // Commander folds `--on-deploy` / `--no-on-deploy` into a single `onDeploy` boolean; it stays
176
- // undefined when neither is passed, so existing callers are unaffected.
177
- .option('--on-deploy', 'run this task automatically on a deploy webhook (critical flow)')
178
- .option('--no-on-deploy', 'stop running this task on a deploy webhook')
179
- .action(async (taskId, cmdOpts) => {
180
- const opts = globalOpts();
181
- try {
182
- const body = {};
183
- if (cmdOpts.name)
184
- body.name = cmdOpts.name;
185
- if (cmdOpts.instruction)
186
- body.qaInstruction = cmdOpts.instruction;
187
- if (cmdOpts.description !== undefined)
188
- body.description = cmdOpts.description;
189
- if (cmdOpts.stepsFrom)
190
- body.steps = readStepsFile(cmdOpts.stepsFrom);
191
- if (cmdOpts.onDeploy !== undefined)
192
- body.runOnDeploy = cmdOpts.onDeploy;
193
- if (Object.keys(body).length === 0) {
194
- throw new Error('No fields to update. Pass --name, --instruction, --description, --steps-from, or --on-deploy.');
195
- }
196
- const client = new client_1.GatewayClient();
197
- const res = await client.request(`/api/tasks/${taskId}`, { method: 'PUT', body });
198
- (0, output_1.printSuccess)({ task: res.task, warnings: res.warnings ?? [] }, () => {
199
- process.stdout.write(`Updated task: ${res.task.name} (${res.task.id})\n`);
200
- renderWarnings(res.warnings ?? []);
201
- }, opts);
202
- }
203
- catch (err) {
204
- renderValidationErrors(err, opts);
205
- process.exit((0, output_1.printError)(err, opts));
206
- }
207
- });
208
- task
209
- .command('delete')
210
- .description('Delete a task')
211
- .argument('<taskId>', 'task id')
212
- .action(async (taskId) => {
213
- const opts = globalOpts();
214
- try {
215
- const client = new client_1.GatewayClient();
216
- await client.request(`/api/tasks/${taskId}`, { method: 'DELETE' });
217
- (0, output_1.printSuccess)({ ok: true, taskId }, `Deleted task ${taskId}`, opts);
218
- }
219
- catch (err) {
220
- process.exit((0, output_1.printError)(err, opts));
221
- }
222
- });
223
- task
224
- .command('run')
225
- .description('Queue a task run against the configured staging URL')
226
- .argument('<taskId>', 'task id')
227
- .action(async (taskId) => {
228
- const opts = globalOpts();
229
- try {
230
- // Surface the staging-deploy caveat before firing. Skipped in --json mode
231
- // so machine consumers (CC) don't choke on free-form text.
232
- if (!(0, output_1.isJson)(opts)) {
233
- process.stderr.write('Note: this runs against the current staging URL. Ensure the deploy you want to test has landed.\n');
234
- }
235
- const client = new client_1.GatewayClient();
236
- const res = await client.request(`/api/tasks/${taskId}/run`, {
237
- method: 'POST',
238
- body: {},
239
- });
240
- (0, output_1.printSuccess)(res, () => {
241
- const status = res.session?.status ?? res.status ?? 'queued';
242
- process.stdout.write(`Queued task ${taskId}: status=${status}\n`);
243
- if (res.session?.id)
244
- process.stdout.write(`Session: ${res.session.id}\n`);
245
- }, opts);
246
- }
247
- catch (err) {
248
- process.exit((0, output_1.printError)(err, opts));
249
- }
250
- });
251
- task
252
- .command('results')
253
- .description('Show step-by-step results for a task')
254
- .argument('<taskId>', 'task id or short id')
255
- .option('--latest', 'Latest run summary (default)')
256
- .option('--failed-step', 'Return only the failed step + minimal context')
257
- .action(async (taskId, cmdOpts) => {
258
- const opts = globalOpts();
259
- try {
260
- const client = new client_1.GatewayClient();
261
- const res = await client.request(`/api/tasks/${taskId}`);
262
- const payload = buildResultsPayload(res.task, { failedOnly: !!cmdOpts.failedStep });
263
- (0, output_1.printSuccess)(payload, () => {
264
- const p = payload;
265
- process.stdout.write(`Task: ${p.taskName} (${p.taskId})\n`);
266
- process.stdout.write(`Status: ${p.status}\n`);
267
- if (p.reportUrl)
268
- process.stdout.write(`Report: ${p.reportUrl}\n`);
269
- if (p.failedStep !== undefined) {
270
- if (p.failedStep) {
271
- process.stdout.write(`\nFailed step ${p.failedStep.index}:\n`);
272
- process.stdout.write(` Action: ${p.failedStep.action}\n`);
273
- process.stdout.write(` Assertion: ${p.failedStep.assertion}\n`);
274
- if (p.failedStep.actual)
275
- process.stdout.write(` Actual: ${p.failedStep.actual}\n`);
276
- if (p.failedStep.reasoning)
277
- process.stdout.write(` Reasoning: ${p.failedStep.reasoning}\n`);
278
- if (p.failedStep.failureCategory)
279
- process.stdout.write(` Category: ${p.failedStep.failureCategory}\n`);
280
- if (p.failedStep.suggestedFix)
281
- process.stdout.write(` Suggested fix: ${p.failedStep.suggestedFix}\n`);
282
- }
283
- else {
284
- process.stdout.write('\nNo failed step.\n');
285
- }
286
- }
287
- else {
288
- for (const s of p.steps) {
289
- process.stdout.write(` ${s.index}. [${s.status.padEnd(7)}] ${s.action}` +
290
- (s.failureCategory ? ` (${s.failureCategory})` : '') +
291
- '\n');
292
- }
293
- }
294
- }, opts);
295
- }
296
- catch (err) {
297
- process.exit((0, output_1.printError)(err, opts));
298
- }
299
- });
300
- task
301
- .command('push-recording')
302
- .description("Upload a hardened recording (selectors + assertions) for a task's steps")
303
- .argument('<taskId>', 'task id or short id')
304
- .requiredOption('--from <file>', 'JSON file: array of { stepOrder, recording } objects')
305
- .option('--source <source>', 'recording source: skill | interactive | heal', 'skill')
306
- .action(async (taskId, cmdOpts) => {
307
- const opts = globalOpts();
308
- try {
309
- const steps = readRecordingFile(cmdOpts.from);
310
- const client = new client_1.GatewayClient();
311
- const res = await client.request(`/api/tasks/${taskId}/recording`, { method: 'PUT', body: { steps, source: cmdOpts.source } });
312
- (0, output_1.printSuccess)({ updated: res.updated }, () => {
313
- process.stdout.write(`Pushed recording for ${res.updated} step(s) of task ${taskId}.\n`);
314
- process.stdout.write('It stays unverified until it passes verification before scheduling.\n');
315
- }, opts);
316
- }
317
- catch (err) {
318
- process.exit((0, output_1.printError)(err, opts));
319
- }
320
- });
321
- }
322
- /**
323
- * Read a JSON array of `{ stepOrder, recording }` from disk. The `recording`
324
- * payload is the hardened replay recipe (selectors, assertion predicate, wait,
325
- * stability grade) and is passed through to the gateway as-is.
326
- */
327
- function readRecordingFile(path) {
328
- let raw;
329
- try {
330
- raw = fs.readFileSync(path, 'utf8');
331
- }
332
- catch (e) {
333
- throw new Error(`Cannot read recording file ${path}: ${e.message}`);
334
- }
335
- let parsed;
336
- try {
337
- parsed = JSON.parse(raw);
338
- }
339
- catch (e) {
340
- throw new Error(`Recording file ${path} is not valid JSON: ${e.message}`);
341
- }
342
- if (!Array.isArray(parsed)) {
343
- throw new Error(`Recording file ${path} must be a JSON array of { stepOrder, recording } objects.`);
344
- }
345
- return parsed.map((s, i) => {
346
- if (typeof s?.stepOrder !== 'number') {
347
- throw new Error(`Entry ${i + 1} in ${path} is missing a numeric "stepOrder" field.`);
348
- }
349
- if (s.recording == null || typeof s.recording !== 'object') {
350
- throw new Error(`Entry ${i + 1} in ${path} is missing an object "recording" field.`);
351
- }
352
- return { stepOrder: s.stepOrder, recording: s.recording };
353
- });
354
- }
355
- /**
356
- * Read a JSON array of `{action, assertion}` from disk. Throws a clear error
357
- * if the file is missing, malformed, or has the wrong shape.
358
- */
359
- function readStepsFile(path) {
360
- let raw;
361
- try {
362
- raw = fs.readFileSync(path, 'utf8');
363
- }
364
- catch (e) {
365
- throw new Error(`Cannot read steps file ${path}: ${e.message}`);
366
- }
367
- let parsed;
368
- try {
369
- parsed = JSON.parse(raw);
370
- }
371
- catch (e) {
372
- throw new Error(`Steps file ${path} is not valid JSON: ${e.message}`);
373
- }
374
- if (!Array.isArray(parsed)) {
375
- throw new Error(`Steps file ${path} must be a JSON array of {action, assertion} objects.`);
376
- }
377
- return parsed.map((s, i) => {
378
- if (typeof s?.action !== 'string') {
379
- throw new Error(`Step ${i + 1} in ${path} is missing a string "action" field.`);
380
- }
381
- return {
382
- action: s.action,
383
- assertion: typeof s.assertion === 'string' ? s.assertion : undefined,
384
- };
385
- });
386
- }
387
- /**
388
- * Pretty-print validator warnings in human mode. No-op in --json mode --
389
- * warnings are already in the JSON payload.
390
- */
391
- function renderWarnings(warnings) {
392
- if (!warnings || warnings.length === 0)
393
- return;
394
- process.stderr.write(`\n${warnings.length} warning(s):\n`);
395
- for (const w of warnings) {
396
- process.stderr.write(` - [${w.code}] ${w.message}\n`);
397
- }
398
- }
399
- /**
400
- * When the gateway returns 400 STEP_VALIDATION_FAILED, ApiError.body carries the
401
- * structured errors + warnings. Surface them clearly before the generic error
402
- * message so the user sees what to fix.
403
- */
404
- function renderValidationErrors(err, opts) {
405
- if ((0, output_1.isJson)(opts))
406
- return;
407
- if (!(err instanceof client_1.ApiError))
408
- return;
409
- const body = err.body;
410
- if (!body || err.code !== 'STEP_VALIDATION_FAILED')
411
- return;
412
- if (Array.isArray(body.errors)) {
413
- process.stderr.write(`Validation errors (${body.errors.length}):\n`);
414
- for (const e of body.errors) {
415
- process.stderr.write(` - [${e.code}] ${e.message}\n`);
416
- }
417
- }
418
- if (Array.isArray(body.warnings) && body.warnings.length > 0) {
419
- process.stderr.write(`\nWarnings (${body.warnings.length}):\n`);
420
- for (const w of body.warnings) {
421
- process.stderr.write(` - [${w.code}] ${w.message}\n`);
422
- }
423
- }
424
- }
425
- //# sourceMappingURL=task.js.map