@runcofactor/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.
- package/dist/{api-catalog-GFGCLVS4.js → api-catalog-7HLEN7C2.js} +5 -4
- package/dist/{api-catalog-GFGCLVS4.js.map → api-catalog-7HLEN7C2.js.map} +1 -1
- package/dist/{attachment-SJC7D7FY.js → attachment-OVNQD6Z2.js} +5 -4
- package/dist/{attachment-SJC7D7FY.js.map → attachment-OVNQD6Z2.js.map} +1 -1
- package/dist/{auth-EN6NQCJY.js → auth-VUHL74FH.js} +3 -2
- package/dist/{chunk-IMPZAX6L.js → chunk-5GD47G2D.js} +37 -1
- package/dist/{chunk-IMPZAX6L.js.map → chunk-5GD47G2D.js.map} +1 -1
- package/dist/{chunk-WOHL4FTB.js → chunk-CQE46HSM.js} +5 -5
- package/dist/chunk-CQE46HSM.js.map +1 -0
- package/dist/{chunk-52IO7ACJ.js → chunk-CRHPDPRS.js} +39 -3
- package/dist/{chunk-52IO7ACJ.js.map → chunk-CRHPDPRS.js.map} +1 -1
- package/dist/{chunk-XQXVG7RA.js → chunk-EEN2TZUQ.js} +3 -3
- package/dist/{chunk-I4QLI3JO.js → chunk-EJ4U242G.js} +2 -2
- package/dist/{chunk-CLAWT7BJ.js → chunk-ENDHMYEJ.js} +3 -3
- package/dist/chunk-G4UYGRZR.js +2 -0
- package/dist/chunk-JZMJUPZP.js +92 -0
- package/dist/chunk-JZMJUPZP.js.map +1 -0
- package/dist/{chunk-GKY2KXO5.js → chunk-NL7CVG56.js} +105 -35
- package/dist/chunk-NL7CVG56.js.map +1 -0
- package/dist/{chunk-A4OFTUVV.js → chunk-PZ4LCN6K.js} +7 -4
- package/dist/chunk-PZ4LCN6K.js.map +1 -0
- package/dist/{chunk-SJJW77WN.js → chunk-QGI4UCJX.js} +69 -5
- package/dist/chunk-QGI4UCJX.js.map +1 -0
- package/dist/{chunk-4PNOV7OV.js → chunk-QQVWGWPI.js} +1023 -150
- package/dist/chunk-QQVWGWPI.js.map +1 -0
- package/dist/{chunk-N7HFALX3.js → chunk-VGTKUOYS.js} +2 -2
- package/dist/{chunk-B2VISN2V.js → chunk-YN763NWQ.js} +230 -66
- package/dist/chunk-YN763NWQ.js.map +1 -0
- package/dist/{chunk-QFDOWABX.js → chunk-Z5LUTUDN.js} +6 -3
- package/dist/chunk-Z5LUTUDN.js.map +1 -0
- package/dist/{chunk-Q4BO4Z5V.js → chunk-ZTOE3ND3.js} +4 -4
- package/dist/{credential-COLTBV6D.js → credential-LO2SEEHU.js} +24 -20
- package/dist/credential-LO2SEEHU.js.map +1 -0
- package/dist/{credential-template-EEPYFG7R.js → credential-template-ZN7W7734.js} +30 -28
- package/dist/credential-template-ZN7W7734.js.map +1 -0
- package/dist/{debug-workflow-KOVH5GOP.js → debug-workflow-R3RYYAXK.js} +5 -4
- package/dist/{debug-workflow-KOVH5GOP.js.map → debug-workflow-R3RYYAXK.js.map} +1 -1
- package/dist/{docs-3SSORHB5.js → docs-DIAFBDXQ.js} +5 -4
- package/dist/{docs-3SSORHB5.js.map → docs-DIAFBDXQ.js.map} +1 -1
- package/dist/{doctor-OTSIWV6G.js → doctor-NZPUSCRE.js} +9 -5
- package/dist/doctor-NZPUSCRE.js.map +1 -0
- package/dist/environment-RQVU4P5M.js +221 -0
- package/dist/environment-RQVU4P5M.js.map +1 -0
- package/dist/{feature-flag-T2LRZME3.js → feature-flag-XG26RURR.js} +72 -10
- package/dist/feature-flag-XG26RURR.js.map +1 -0
- package/dist/index.js +57 -48
- package/dist/index.js.map +1 -1
- package/dist/{init-TGWRECT2.js → init-EDNLKGPT.js} +5 -4
- package/dist/{init-TGWRECT2.js.map → init-EDNLKGPT.js.map} +1 -1
- package/dist/{install-DXSNWZKO.js → install-FYZ3HNZK.js} +7 -7
- package/dist/{issues-XIZOPX6T.js → issues-NNRVTJ4L.js} +5 -4
- package/dist/{issues-XIZOPX6T.js.map → issues-NNRVTJ4L.js.map} +1 -1
- package/dist/{knobs-NBINZIUB.js → knobs-A2BOBH22.js} +5 -4
- package/dist/{knobs-NBINZIUB.js.map → knobs-A2BOBH22.js.map} +1 -1
- package/dist/{list-3TDHK637.js → list-F33VZ4BJ.js} +5 -4
- package/dist/{list-3TDHK637.js.map → list-F33VZ4BJ.js.map} +1 -1
- package/dist/{local-HICVD6PU.js → local-DQDTM3XA.js} +7 -6
- package/dist/{local-HICVD6PU.js.map → local-DQDTM3XA.js.map} +1 -1
- package/dist/{login-UOIUXVUK.js → login-BUMVIB36.js} +5 -4
- package/dist/{login-UOIUXVUK.js.map → login-BUMVIB36.js.map} +1 -1
- package/dist/{mcp-54IJEOUA.js → mcp-B5Y5CDMQ.js} +23 -24
- package/dist/mcp-B5Y5CDMQ.js.map +1 -0
- package/dist/{property-UXLOLPTD.js → property-NJ4SRXQG.js} +76 -4
- package/dist/property-NJ4SRXQG.js.map +1 -0
- package/dist/{psql-BYUUNLGG.js → psql-VBZFCMNR.js} +3 -2
- package/dist/{psql-BYUUNLGG.js.map → psql-VBZFCMNR.js.map} +1 -1
- package/dist/{record-4TR2UIIS.js → record-WAO36O7G.js} +16 -17
- package/dist/record-WAO36O7G.js.map +1 -0
- package/dist/{redis-35VBUYW7.js → redis-DHZXHL4S.js} +3 -2
- package/dist/{redis-35VBUYW7.js.map → redis-DHZXHL4S.js.map} +1 -1
- package/dist/{release-OOLTUBUT.js → release-STJKUKTE.js} +5 -4
- package/dist/{release-OOLTUBUT.js.map → release-STJKUKTE.js.map} +1 -1
- package/dist/{sandbox-XGSUU6G7.js → sandbox-DWSGLY7B.js} +9 -8
- package/dist/{sandbox-XGSUU6G7.js.map → sandbox-DWSGLY7B.js.map} +1 -1
- package/dist/{scenarios-GWLJEGHA.js → scenarios-HCIDY725.js} +5 -4
- package/dist/{scenarios-GWLJEGHA.js.map → scenarios-HCIDY725.js.map} +1 -1
- package/dist/{session-MYFNZPRP.js → session-Y5RHU54D.js} +76 -8
- package/dist/session-Y5RHU54D.js.map +1 -0
- package/dist/{skill-KM34LDMO.js → skill-23WAHUOB.js} +217 -67
- package/dist/skill-23WAHUOB.js.map +1 -0
- package/dist/skills/debug-run/SKILL.md +33 -22
- package/dist/skills/debug-run/history/1.2.0.md +262 -0
- package/dist/skills/debug-run/history/1.3.0.md +273 -0
- package/dist/skills/debug-run/version.json +1 -1
- package/dist/skills/optimize-cache/SKILL.md +206 -0
- package/dist/{spec-RA3CFEKG.js → spec-LM5XHOQ5.js} +54 -25
- package/dist/spec-LM5XHOQ5.js.map +1 -0
- package/dist/{src-LB4HBTJQ.js → src-22RI5VP2.js} +19 -11
- package/dist/src-22RI5VP2.js.map +1 -0
- package/dist/src-BGDRMOKC.js +5748 -0
- package/dist/src-BGDRMOKC.js.map +1 -0
- package/dist/{src-N3TPKGTY.js → src-NCJPUAE6.js} +3 -2
- package/dist/{src-UVDX5UP6.js → src-Y3K7UJEF.js} +4 -2
- package/dist/{start-PSEQSQA3.js → start-SWY55CZX.js} +5 -4
- package/dist/{start-PSEQSQA3.js.map → start-SWY55CZX.js.map} +1 -1
- package/dist/{tag-YY6YAABQ.js → tag-YSU2XXPI.js} +6 -5
- package/dist/{task-IQC3YR5K.js → task-NLBKLD7D.js} +5 -4
- package/dist/{task-IQC3YR5K.js.map → task-NLBKLD7D.js.map} +1 -1
- package/dist/{test-suite-DZNJFXDW.js → test-suite-QCPWZ2LS.js} +9 -6
- package/dist/{test-suite-DZNJFXDW.js.map → test-suite-QCPWZ2LS.js.map} +1 -1
- package/dist/{trace-HXIW7U2D.js → trace-A3ZY6K26.js} +6 -4
- package/dist/{triage-ORG45R5W.js → triage-TT4BMDBU.js} +6 -5
- package/dist/triage-TT4BMDBU.js.map +1 -0
- package/dist/{upgrade-L2VYMP2V.js → upgrade-6ZUFETKX.js} +3 -3
- package/dist/{workflow-XYFH5LTP.js → workflow-2CX3ZNOQ.js} +241 -237
- package/dist/workflow-2CX3ZNOQ.js.map +1 -0
- package/dist/{workflow-cache-NQJQFWMV.js → workflow-cache-GXNE6SU2.js} +140 -7
- package/dist/workflow-cache-GXNE6SU2.js.map +1 -0
- package/dist/{workflow-debug-BGD4UIXU.js → workflow-debug-PRX3DWGD.js} +8 -7
- package/dist/{workflow-debug-BGD4UIXU.js.map → workflow-debug-PRX3DWGD.js.map} +1 -1
- package/dist/{workflow-proposals-MTUDX46O.js → workflow-proposals-BW327WGL.js} +5 -4
- package/dist/{workflow-proposals-MTUDX46O.js.map → workflow-proposals-BW327WGL.js.map} +1 -1
- package/package.json +2 -1
- package/dist/chunk-4PNOV7OV.js.map +0 -1
- package/dist/chunk-A4OFTUVV.js.map +0 -1
- package/dist/chunk-B2VISN2V.js.map +0 -1
- package/dist/chunk-GKY2KXO5.js.map +0 -1
- package/dist/chunk-JICSYFRJ.js +0 -46
- package/dist/chunk-JICSYFRJ.js.map +0 -1
- package/dist/chunk-QFDOWABX.js.map +0 -1
- package/dist/chunk-SJJW77WN.js.map +0 -1
- package/dist/chunk-WOHL4FTB.js.map +0 -1
- package/dist/credential-COLTBV6D.js.map +0 -1
- package/dist/credential-template-EEPYFG7R.js.map +0 -1
- package/dist/doctor-OTSIWV6G.js.map +0 -1
- package/dist/feature-flag-T2LRZME3.js.map +0 -1
- package/dist/mcp-54IJEOUA.js.map +0 -1
- package/dist/property-UXLOLPTD.js.map +0 -1
- package/dist/record-4TR2UIIS.js.map +0 -1
- package/dist/session-MYFNZPRP.js.map +0 -1
- package/dist/skill-KM34LDMO.js.map +0 -1
- package/dist/spec-RA3CFEKG.js.map +0 -1
- package/dist/src-LB4HBTJQ.js.map +0 -1
- package/dist/workflow-XYFH5LTP.js.map +0 -1
- package/dist/workflow-cache-NQJQFWMV.js.map +0 -1
- /package/dist/{auth-EN6NQCJY.js.map → auth-VUHL74FH.js.map} +0 -0
- /package/dist/{chunk-XQXVG7RA.js.map → chunk-EEN2TZUQ.js.map} +0 -0
- /package/dist/{chunk-I4QLI3JO.js.map → chunk-EJ4U242G.js.map} +0 -0
- /package/dist/{chunk-CLAWT7BJ.js.map → chunk-ENDHMYEJ.js.map} +0 -0
- /package/dist/{src-N3TPKGTY.js.map → chunk-G4UYGRZR.js.map} +0 -0
- /package/dist/{chunk-N7HFALX3.js.map → chunk-VGTKUOYS.js.map} +0 -0
- /package/dist/{chunk-Q4BO4Z5V.js.map → chunk-ZTOE3ND3.js.map} +0 -0
- /package/dist/{install-DXSNWZKO.js.map → install-FYZ3HNZK.js.map} +0 -0
- /package/dist/{src-UVDX5UP6.js.map → src-NCJPUAE6.js.map} +0 -0
- /package/dist/{tag-YY6YAABQ.js.map → src-Y3K7UJEF.js.map} +0 -0
- /package/dist/{trace-HXIW7U2D.js.map → tag-YSU2XXPI.js.map} +0 -0
- /package/dist/{triage-ORG45R5W.js.map → trace-A3ZY6K26.js.map} +0 -0
- /package/dist/{upgrade-L2VYMP2V.js.map → upgrade-6ZUFETKX.js.map} +0 -0
|
@@ -4,22 +4,17 @@ import {
|
|
|
4
4
|
} from "./chunk-4NRDONSC.js";
|
|
5
5
|
import {
|
|
6
6
|
workflowToSpec
|
|
7
|
-
} from "./chunk-
|
|
7
|
+
} from "./chunk-YN763NWQ.js";
|
|
8
8
|
import {
|
|
9
9
|
applyWorkflowTagFlags
|
|
10
|
-
} from "./chunk-
|
|
10
|
+
} from "./chunk-EEN2TZUQ.js";
|
|
11
11
|
import {
|
|
12
12
|
alignSnapshotNodeIds
|
|
13
13
|
} from "./chunk-JDBCZ3Z2.js";
|
|
14
14
|
import {
|
|
15
15
|
apiRequest,
|
|
16
16
|
renderWorkflowUserError
|
|
17
|
-
} from "./chunk-
|
|
18
|
-
import {
|
|
19
|
-
NODE_TYPE_LABEL,
|
|
20
|
-
USER_SETTABLE_WORKFLOW_STATUSES,
|
|
21
|
-
normalizeNodeType
|
|
22
|
-
} from "./chunk-SJJW77WN.js";
|
|
17
|
+
} from "./chunk-CQE46HSM.js";
|
|
23
18
|
import {
|
|
24
19
|
apiFetch,
|
|
25
20
|
exitOnFailure,
|
|
@@ -30,8 +25,16 @@ import {
|
|
|
30
25
|
hasFlag,
|
|
31
26
|
resolveAppUrl,
|
|
32
27
|
resolveConfig
|
|
33
|
-
} from "./chunk-
|
|
28
|
+
} from "./chunk-PZ4LCN6K.js";
|
|
29
|
+
import {
|
|
30
|
+
specExtension
|
|
31
|
+
} from "./chunk-JZMJUPZP.js";
|
|
34
32
|
import "./chunk-JWHYXEA2.js";
|
|
33
|
+
import {
|
|
34
|
+
NODE_TYPE_LABEL,
|
|
35
|
+
USER_SETTABLE_WORKFLOW_STATUSES,
|
|
36
|
+
normalizeNodeType
|
|
37
|
+
} from "./chunk-QGI4UCJX.js";
|
|
35
38
|
import "./chunk-VKVL7WBN.js";
|
|
36
39
|
|
|
37
40
|
// src/workflow.ts
|
|
@@ -41,7 +44,6 @@ import process9 from "process";
|
|
|
41
44
|
// src/workflow-create.ts
|
|
42
45
|
import fs from "fs/promises";
|
|
43
46
|
import process2 from "process";
|
|
44
|
-
import { createParser } from "eventsource-parser";
|
|
45
47
|
async function readFromStdin() {
|
|
46
48
|
const chunks = [];
|
|
47
49
|
const stdin = process2.stdin;
|
|
@@ -144,165 +146,6 @@ Available credentials:
|
|
|
144
146
|
${lines.join("\n")}`
|
|
145
147
|
);
|
|
146
148
|
}
|
|
147
|
-
async function fetchSuiteLiveState(apiUrl, token, suiteId) {
|
|
148
|
-
try {
|
|
149
|
-
const res = await fetch(`${apiUrl}/workflows/test-executions/${suiteId}/live-state`, {
|
|
150
|
-
headers: { Authorization: `Bearer ${token}` }
|
|
151
|
-
});
|
|
152
|
-
if (!res.ok) return null;
|
|
153
|
-
return await res.json();
|
|
154
|
-
} catch {
|
|
155
|
-
return null;
|
|
156
|
-
}
|
|
157
|
-
}
|
|
158
|
-
async function runAndPublish(opts) {
|
|
159
|
-
const { apiUrl, token, workflowId, workflowName, timeoutMs } = opts;
|
|
160
|
-
const body = {};
|
|
161
|
-
if (opts.propertyId) body.propertyId = opts.propertyId;
|
|
162
|
-
if (opts.environmentId) body.environmentId = opts.environmentId;
|
|
163
|
-
const triggerUrl = `${apiUrl}/workflows/test-runs?namePattern=${encodeURIComponent(workflowName)}`;
|
|
164
|
-
const triggerRes = await fetchOrExit(triggerUrl, {
|
|
165
|
-
method: "POST",
|
|
166
|
-
headers: {
|
|
167
|
-
Authorization: `Bearer ${token}`,
|
|
168
|
-
"Content-Type": "application/json"
|
|
169
|
-
},
|
|
170
|
-
token,
|
|
171
|
-
body: JSON.stringify(body)
|
|
172
|
-
});
|
|
173
|
-
if (!triggerRes.ok) {
|
|
174
|
-
const errorText = await triggerRes.text();
|
|
175
|
-
console.error(`Failed to trigger test run: ${triggerRes.status} ${errorText}`);
|
|
176
|
-
return false;
|
|
177
|
-
}
|
|
178
|
-
const triggerData = await triggerRes.json();
|
|
179
|
-
if (!triggerData.ok || !triggerData.suiteId) {
|
|
180
|
-
console.error(`Failed to trigger test run: ${triggerData.error ?? "Unknown error"}`);
|
|
181
|
-
return false;
|
|
182
|
-
}
|
|
183
|
-
const { suiteId } = triggerData;
|
|
184
|
-
console.log(`Test run started (suite: ${suiteId})`);
|
|
185
|
-
console.log("Streaming results...\n");
|
|
186
|
-
const streamUrl = `${apiUrl}/workflows/test-runs/stream?suiteId=${suiteId}`;
|
|
187
|
-
const streamRes = await fetchOrExit(streamUrl, {
|
|
188
|
-
headers: {
|
|
189
|
-
Authorization: `Bearer ${token}`,
|
|
190
|
-
Accept: "text/event-stream"
|
|
191
|
-
},
|
|
192
|
-
token,
|
|
193
|
-
// SSE connections stay open; don't let the default 30s timeout cut them off.
|
|
194
|
-
timeoutMs: 0
|
|
195
|
-
});
|
|
196
|
-
if (!streamRes.ok || !streamRes.body) {
|
|
197
|
-
console.error(`Failed to connect to event stream: ${streamRes.status}`);
|
|
198
|
-
return false;
|
|
199
|
-
}
|
|
200
|
-
let success = false;
|
|
201
|
-
let hasCompleted = false;
|
|
202
|
-
const parser = createParser({
|
|
203
|
-
onEvent: (event) => {
|
|
204
|
-
if (!event.data) return;
|
|
205
|
-
try {
|
|
206
|
-
const data = JSON.parse(event.data);
|
|
207
|
-
if (event.event === "workflow-test") {
|
|
208
|
-
const testEvent = data;
|
|
209
|
-
if (testEvent.status === "success") {
|
|
210
|
-
console.log(` \u2713 ${workflowName}`);
|
|
211
|
-
success = true;
|
|
212
|
-
} else if (testEvent.status === "failed") {
|
|
213
|
-
console.log(` \u2717 ${workflowName}`);
|
|
214
|
-
if (testEvent.errorMessage) {
|
|
215
|
-
console.log(` Error: ${testEvent.errorMessage.slice(0, 200)}`);
|
|
216
|
-
}
|
|
217
|
-
success = false;
|
|
218
|
-
} else if (testEvent.status === "running") {
|
|
219
|
-
console.log(` \u25B6 Running ${workflowName}...`);
|
|
220
|
-
}
|
|
221
|
-
}
|
|
222
|
-
if (event.event === "workflow-test-suite") {
|
|
223
|
-
const suiteEvent = data;
|
|
224
|
-
if (suiteEvent.status === "completed") {
|
|
225
|
-
hasCompleted = true;
|
|
226
|
-
}
|
|
227
|
-
}
|
|
228
|
-
} catch {
|
|
229
|
-
}
|
|
230
|
-
}
|
|
231
|
-
});
|
|
232
|
-
const reader = streamRes.body.getReader();
|
|
233
|
-
const decoder = new TextDecoder();
|
|
234
|
-
let timedOut = false;
|
|
235
|
-
const timeoutHandle = setTimeout(() => {
|
|
236
|
-
timedOut = true;
|
|
237
|
-
reader.cancel().catch(() => {
|
|
238
|
-
});
|
|
239
|
-
}, timeoutMs);
|
|
240
|
-
try {
|
|
241
|
-
while (!hasCompleted) {
|
|
242
|
-
const { done, value } = await reader.read();
|
|
243
|
-
if (done) break;
|
|
244
|
-
parser.feed(decoder.decode(value, { stream: true }));
|
|
245
|
-
}
|
|
246
|
-
} finally {
|
|
247
|
-
clearTimeout(timeoutHandle);
|
|
248
|
-
try {
|
|
249
|
-
reader.releaseLock();
|
|
250
|
-
} catch {
|
|
251
|
-
}
|
|
252
|
-
}
|
|
253
|
-
if (!hasCompleted) {
|
|
254
|
-
const reason = timedOut ? `Timed out after ${Math.round(timeoutMs / 1e3)}s waiting for test completion` : "Event stream closed before completion";
|
|
255
|
-
console.warn(`
|
|
256
|
-
\u26A0 ${reason}. Polling final state...`);
|
|
257
|
-
const live = await fetchSuiteLiveState(apiUrl, token, suiteId);
|
|
258
|
-
const exec = live?.execution;
|
|
259
|
-
if (exec && (exec.status === "completed" || exec.status === "completed_with_errors")) {
|
|
260
|
-
success = exec.failedWorkflows === 0;
|
|
261
|
-
const match = live?.runs?.find((r) => r.workflowId === workflowId);
|
|
262
|
-
if (match) {
|
|
263
|
-
console.log(
|
|
264
|
-
success ? ` \u2713 ${workflowName}` : ` \u2717 ${workflowName}`
|
|
265
|
-
);
|
|
266
|
-
if (!success && match.errorMessage) {
|
|
267
|
-
console.log(` Error: ${match.errorMessage.slice(0, 200)}`);
|
|
268
|
-
}
|
|
269
|
-
}
|
|
270
|
-
} else {
|
|
271
|
-
console.error(
|
|
272
|
-
`Suite ${suiteId} is still ${exec?.status ?? "unknown"} on the server. Check it in the web app.`
|
|
273
|
-
);
|
|
274
|
-
return false;
|
|
275
|
-
}
|
|
276
|
-
}
|
|
277
|
-
if (success) {
|
|
278
|
-
try {
|
|
279
|
-
const publishRes = await fetchOrExit(`${apiUrl}/workflows/${workflowId}/publish`, {
|
|
280
|
-
method: "POST",
|
|
281
|
-
headers: {
|
|
282
|
-
Authorization: `Bearer ${token}`,
|
|
283
|
-
"Content-Type": "application/json"
|
|
284
|
-
},
|
|
285
|
-
token
|
|
286
|
-
});
|
|
287
|
-
if (publishRes.ok) {
|
|
288
|
-
console.log(`
|
|
289
|
-
\u2713 Workflow published successfully`);
|
|
290
|
-
return true;
|
|
291
|
-
} else {
|
|
292
|
-
console.error(`
|
|
293
|
-
Failed to publish workflow: ${publishRes.status}`);
|
|
294
|
-
return false;
|
|
295
|
-
}
|
|
296
|
-
} catch (err) {
|
|
297
|
-
console.error(`
|
|
298
|
-
Failed to publish workflow: ${err}`);
|
|
299
|
-
return false;
|
|
300
|
-
}
|
|
301
|
-
}
|
|
302
|
-
console.log(`
|
|
303
|
-
\u2717 Test failed \u2014 workflow left in draft for manual review`);
|
|
304
|
-
return false;
|
|
305
|
-
}
|
|
306
149
|
async function readApiSequenceConfig(argv) {
|
|
307
150
|
const fromFile = getArgValue(argv, "--sequence-from-file");
|
|
308
151
|
const fromStdin = hasFlag(argv, "--sequence-from-stdin");
|
|
@@ -409,13 +252,10 @@ async function handleWorkflowCreate(argv, apiUrl, token) {
|
|
|
409
252
|
await handleApiOnlyCreate(argv, apiUrl, token);
|
|
410
253
|
return;
|
|
411
254
|
}
|
|
412
|
-
|
|
413
|
-
|
|
414
|
-
|
|
415
|
-
|
|
416
|
-
const timeoutSec = timeoutArg ? Number.parseInt(timeoutArg, 10) : 900;
|
|
417
|
-
if (!Number.isFinite(timeoutSec) || timeoutSec <= 0) {
|
|
418
|
-
console.error(`Error: --publish-timeout must be a positive integer (seconds), got "${timeoutArg}"`);
|
|
255
|
+
if (hasFlag(argv, "--run-and-publish")) {
|
|
256
|
+
console.error(
|
|
257
|
+
"Error: --run-and-publish was removed. Run the test (canary workflow run <id>), then\napprove it (canary workflow approve <id> --yes) and promote it (canary workflow promote <id>)."
|
|
258
|
+
);
|
|
419
259
|
process2.exit(1);
|
|
420
260
|
}
|
|
421
261
|
let input;
|
|
@@ -495,21 +335,10 @@ Error applying tags:
|
|
|
495
335
|
${err instanceof Error ? err.message : String(err)}`);
|
|
496
336
|
process2.exit(1);
|
|
497
337
|
}
|
|
498
|
-
|
|
499
|
-
|
|
500
|
-
|
|
501
|
-
|
|
502
|
-
token,
|
|
503
|
-
workflowId: workflow.id,
|
|
504
|
-
workflowName: workflow.name,
|
|
505
|
-
propertyId: propertyArg ?? input.propertyId,
|
|
506
|
-
environmentId: environmentArg,
|
|
507
|
-
timeoutMs: timeoutSec * 1e3
|
|
508
|
-
});
|
|
509
|
-
if (!passed) {
|
|
510
|
-
process2.exit(1);
|
|
511
|
-
}
|
|
512
|
-
}
|
|
338
|
+
console.log(
|
|
339
|
+
`
|
|
340
|
+
Next: run it (canary workflow run ${workflow.id}), approve it (canary workflow approve ${workflow.id} --yes), then promote it into suites (canary workflow promote ${workflow.id}).`
|
|
341
|
+
);
|
|
513
342
|
}
|
|
514
343
|
|
|
515
344
|
// src/workflow-run.ts
|
|
@@ -1246,7 +1075,7 @@ async function handleWorkflowSync(argv, apiUrl, token) {
|
|
|
1246
1075
|
|
|
1247
1076
|
// src/workflow-api-sequence.ts
|
|
1248
1077
|
import process6 from "process";
|
|
1249
|
-
import { createParser
|
|
1078
|
+
import { createParser } from "eventsource-parser";
|
|
1250
1079
|
async function handleWorkflowGenerateApiSequence(argv, apiUrl, token) {
|
|
1251
1080
|
const workflowId = argv.find((a) => !a.startsWith("-"));
|
|
1252
1081
|
const prompt = getArgValue(argv, "--prompt");
|
|
@@ -1331,7 +1160,7 @@ async function handleWorkflowGenerateApiSequence(argv, apiUrl, token) {
|
|
|
1331
1160
|
let resultSummary = "";
|
|
1332
1161
|
let hasCompleted = false;
|
|
1333
1162
|
let exitCode = 0;
|
|
1334
|
-
const parser =
|
|
1163
|
+
const parser = createParser({
|
|
1335
1164
|
onEvent: (event) => {
|
|
1336
1165
|
if (!event.data || event.event !== "api-sequence-generation") return;
|
|
1337
1166
|
try {
|
|
@@ -2086,7 +1915,7 @@ ACTION
|
|
|
2086
1915
|
|
|
2087
1916
|
ASSERTION
|
|
2088
1917
|
Verifies expected outcomes. Define a condition to check.
|
|
2089
|
-
|
|
1918
|
+
What happens on failure depends on the severity.
|
|
2090
1919
|
|
|
2091
1920
|
Prefer inline assertions on action nodes over standalone assertion nodes.
|
|
2092
1921
|
Inline assertions keep the test on track and produce cleaner failure
|
|
@@ -2098,8 +1927,11 @@ ASSERTION
|
|
|
2098
1927
|
confirming data absence after a sequence of steps.
|
|
2099
1928
|
|
|
2100
1929
|
Severity levels:
|
|
2101
|
-
|
|
2102
|
-
|
|
1930
|
+
fatal The test must end now \u2014 the run halts at this step.
|
|
1931
|
+
Use for preconditions later steps depend on.
|
|
1932
|
+
fail The test may continue \u2014 the run finishes marked failed,
|
|
1933
|
+
but later steps still run and produce signal.
|
|
1934
|
+
warn The test should continue \u2014 logged as a warning, run passes.
|
|
2103
1935
|
|
|
2104
1936
|
Agentic assertions: for visual/layout checks that can't be mechanically
|
|
2105
1937
|
validated, enable agent evaluation. These require the AI agent during
|
|
@@ -2157,6 +1989,37 @@ API SEQUENCE
|
|
|
2157
1989
|
browser-based seed to discover the right API calls, then convert
|
|
2158
1990
|
to an API sequence for speed and reliability.
|
|
2159
1991
|
|
|
1992
|
+
SANDBOX ACTION
|
|
1993
|
+
Executes a sandbox action \u2014 a server-side script defined on the
|
|
1994
|
+
environment template \u2014 directly on the run environment's sandbox
|
|
1995
|
+
instance. No browser involved. The action's structured output is
|
|
1996
|
+
registered as workflow variables: each output key becomes
|
|
1997
|
+
$var.{key} for downstream steps.
|
|
1998
|
+
|
|
1999
|
+
Config:
|
|
2000
|
+
actionSlug Slug of the action (required; discover via
|
|
2001
|
+
list_sandbox_actions)
|
|
2002
|
+
params Input values keyed by the action's inputSchema
|
|
2003
|
+
property names; values may use $var.{name} / macros
|
|
2004
|
+
outputKeys Output variable keys (defaults to the action's
|
|
2005
|
+
outputSchema keys)
|
|
2006
|
+
|
|
2007
|
+
Output registration is allowlisted by declared intent: the action's
|
|
2008
|
+
outputSchema keys, else the node's outputKeys. If neither declares
|
|
2009
|
+
anything, NO result keys register \u2014 declare outputs explicitly for
|
|
2010
|
+
schema-less actions.
|
|
2011
|
+
|
|
2012
|
+
Environment constraint: the action runs on the environment's
|
|
2013
|
+
backing sandbox instance. On a non-sandbox environment (static
|
|
2014
|
+
staging/prod) the node SKIPS with a warning and registers no
|
|
2015
|
+
variables \u2014 so workflows containing one are effectively
|
|
2016
|
+
sandbox-only.
|
|
2017
|
+
|
|
2018
|
+
Seeds: a seed workflow whose body is a single sandbox action node
|
|
2019
|
+
is the fastest way to provision data \u2014 it runs entirely
|
|
2020
|
+
server-side (no browser session), and its outputs satisfy the
|
|
2021
|
+
seed's declared outputs like any captured value.
|
|
2022
|
+
|
|
2160
2023
|
NOTIFICATION
|
|
2161
2024
|
Sends notifications (Slack, email, etc.) at a point in the workflow.
|
|
2162
2025
|
|
|
@@ -2634,6 +2497,23 @@ TEARDOWN WORKFLOWS
|
|
|
2634
2497
|
Teardowns are the cleanest way to handle cleanup \u2014 they keep cleanup
|
|
2635
2498
|
logic separate from test logic and run automatically.
|
|
2636
2499
|
|
|
2500
|
+
SANDBOX-ACTION-BACKED SEEDS
|
|
2501
|
+
|
|
2502
|
+
When the property has a verified sandbox template with actions, a seed
|
|
2503
|
+
workflow can provision data by running a SANDBOX ACTION node instead of
|
|
2504
|
+
driving the UI or composing API calls. The seed's body is a single
|
|
2505
|
+
sandbox_action node (plus End); the action's outputs register as
|
|
2506
|
+
$var.{key} and satisfy the seed's declared outputs directly.
|
|
2507
|
+
|
|
2508
|
+
- Fastest seed form: runs entirely server-side, no browser session
|
|
2509
|
+
- Discover actions with list_sandbox_actions; outputs come from the
|
|
2510
|
+
action's outputSchema
|
|
2511
|
+
- Constraint: consuming workflows become sandbox-only \u2014 on a
|
|
2512
|
+
non-sandbox environment the action node skips with a warning and
|
|
2513
|
+
produces no variables
|
|
2514
|
+
- Teardown is usually unnecessary: sandbox environments are destroyed
|
|
2515
|
+
after the suite, taking provisioned data with them
|
|
2516
|
+
|
|
2637
2517
|
SEED BEST PRACTICES
|
|
2638
2518
|
|
|
2639
2519
|
- Use macros in all created data ($EMAIL, $RANDOM_STRING, etc.)
|
|
@@ -2643,6 +2523,8 @@ SEED BEST PRACTICES
|
|
|
2643
2523
|
- Export only what downstream workflows need \u2014 don't over-export
|
|
2644
2524
|
- Start with browser-based seeds, then use auto-conversion to generate
|
|
2645
2525
|
an API sequence from a completed run
|
|
2526
|
+
- For sandbox-backed properties, prefer a sandbox-action-backed seed
|
|
2527
|
+
(see above) \u2014 server-side, fast, and reliable
|
|
2646
2528
|
- Pair seeds with teardown workflows for automatic cleanup
|
|
2647
2529
|
- Use suite-level setup nodes to share seed data across multiple
|
|
2648
2530
|
workflows in the same test suite
|
|
@@ -2771,13 +2653,31 @@ INLINE ASSERTIONS (PREFERRED)
|
|
|
2771
2653
|
Action: "Submit the support ticket"
|
|
2772
2654
|
Inline assertions:
|
|
2773
2655
|
- "Success toast appears" (severity: warn)
|
|
2774
|
-
- "
|
|
2775
|
-
|
|
2776
|
-
|
|
2777
|
-
|
|
2778
|
-
|
|
2779
|
-
|
|
2780
|
-
|
|
2656
|
+
- "Ticket appears in the ticket list" (severity: fail)
|
|
2657
|
+
- "Form is no longer visible" (severity: fatal)
|
|
2658
|
+
|
|
2659
|
+
Severity levels \u2014 what a failure means for the run:
|
|
2660
|
+
fatal The test must end now. The run halts at this step.
|
|
2661
|
+
Use when continuing is pointless: login succeeded, the page
|
|
2662
|
+
loaded, a precondition every later step depends on.
|
|
2663
|
+
Example: "User is logged in and the dashboard is visible"
|
|
2664
|
+
fail The test may continue. The step is marked failed and the run
|
|
2665
|
+
finishes marked failed, but later steps still execute and
|
|
2666
|
+
produce signal.
|
|
2667
|
+
Use for independent checks: data saved, expected row present,
|
|
2668
|
+
error absent.
|
|
2669
|
+
Example: "The new record appears in the table"
|
|
2670
|
+
warn The test should continue. The failure is recorded as a warning
|
|
2671
|
+
and the run still passes.
|
|
2672
|
+
Use for cosmetic or non-critical checks: toast appeared,
|
|
2673
|
+
animation completed.
|
|
2674
|
+
Example: "Success toast appears"
|
|
2675
|
+
|
|
2676
|
+
Choosing a severity: ask "if this is wrong, is there any value in
|
|
2677
|
+
running the rest of the test?" No \u2192 fatal. "Does this being wrong mean
|
|
2678
|
+
the feature is broken?" Yes \u2192 fail. Otherwise \u2192 warn. When unsure,
|
|
2679
|
+
prefer fatal for preconditions and fail for feature claims. Always set
|
|
2680
|
+
a severity explicitly \u2014 don't leave it unspecified.
|
|
2781
2681
|
|
|
2782
2682
|
If verifying something requires significant interaction (scrolling,
|
|
2783
2683
|
navigating, expanding sections), model that as an action node with
|
|
@@ -2876,8 +2776,8 @@ var WORKFLOW_GUIDE_SECTIONS = [
|
|
|
2876
2776
|
|
|
2877
2777
|
// src/workflow.ts
|
|
2878
2778
|
var WORKFLOW_STATUS_DESCRIPTIONS = {
|
|
2879
|
-
draft: "
|
|
2880
|
-
|
|
2779
|
+
draft: "not yet approved \u2014 no human has signed off on the spec",
|
|
2780
|
+
approved: "a human verified the test checks the right thing"
|
|
2881
2781
|
};
|
|
2882
2782
|
var formatWorkflowStatusList = () => USER_SETTABLE_WORKFLOW_STATUSES.map(
|
|
2883
2783
|
(s) => `${s} (${WORKFLOW_STATUS_DESCRIPTIONS[s]})`
|
|
@@ -3288,41 +3188,129 @@ async function handleUnarchive(argv, apiUrl, token) {
|
|
|
3288
3188
|
console.log(`Restored workflow ${workflowId}.`);
|
|
3289
3189
|
}
|
|
3290
3190
|
}
|
|
3291
|
-
|
|
3191
|
+
var APPROVAL_GUIDANCE = [
|
|
3192
|
+
"Approving a test asserts that a HUMAN has verified it tests the right thing.",
|
|
3193
|
+
"",
|
|
3194
|
+
"If you are an agent running this command on behalf of a user:",
|
|
3195
|
+
" - Describe to the user what this test does and what approval means.",
|
|
3196
|
+
" - Confirm the user has personally verified the test is correct.",
|
|
3197
|
+
" - Only re-run with --yes after the user explicitly confirms.",
|
|
3198
|
+
"",
|
|
3199
|
+
"Approval does NOT put the test into suites \u2014 use `canary workflow promote` for that."
|
|
3200
|
+
].join("\n");
|
|
3201
|
+
async function handleApprove(argv, apiUrl, token) {
|
|
3202
|
+
const workflowId = argv.find((a) => !a.startsWith("-"));
|
|
3203
|
+
if (!workflowId) {
|
|
3204
|
+
console.error("Error: Missing workflow ID.");
|
|
3205
|
+
console.error("Usage: canary workflow approve <workflowId> [--yes] [--json]");
|
|
3206
|
+
process9.exit(1);
|
|
3207
|
+
}
|
|
3208
|
+
const jsonOutput = hasFlag(argv, "--json");
|
|
3209
|
+
if (!hasFlag(argv, "--yes")) {
|
|
3210
|
+
console.error(APPROVAL_GUIDANCE);
|
|
3211
|
+
console.error(`
|
|
3212
|
+
Re-run with --yes to approve: canary workflow approve ${workflowId} --yes`);
|
|
3213
|
+
process9.exit(1);
|
|
3214
|
+
}
|
|
3215
|
+
const result = await apiRequest(
|
|
3216
|
+
apiUrl,
|
|
3217
|
+
token,
|
|
3218
|
+
"POST",
|
|
3219
|
+
`/workflows/${workflowId}/approve`,
|
|
3220
|
+
{}
|
|
3221
|
+
);
|
|
3222
|
+
if (result.error) {
|
|
3223
|
+
if (jsonOutput) {
|
|
3224
|
+
console.log(JSON.stringify(result, null, 2));
|
|
3225
|
+
} else {
|
|
3226
|
+
console.error(`Error: ${result.error}`);
|
|
3227
|
+
}
|
|
3228
|
+
process9.exit(1);
|
|
3229
|
+
}
|
|
3230
|
+
if (jsonOutput) {
|
|
3231
|
+
console.log(
|
|
3232
|
+
JSON.stringify({ ok: true, workflowId, workflow: result.workflow ?? null }, null, 2)
|
|
3233
|
+
);
|
|
3234
|
+
return;
|
|
3235
|
+
}
|
|
3236
|
+
console.log(`Workflow ${workflowId} approved.`);
|
|
3237
|
+
console.log(`Promote it into suites with: canary workflow promote ${workflowId}`);
|
|
3238
|
+
}
|
|
3239
|
+
async function handlePromote(argv, apiUrl, token, options) {
|
|
3292
3240
|
const workflowId = argv.find((a) => !a.startsWith("-"));
|
|
3293
3241
|
if (!workflowId) {
|
|
3294
3242
|
console.error("Error: Missing workflow ID.");
|
|
3295
|
-
console.error("Usage: canary workflow
|
|
3243
|
+
console.error("Usage: canary workflow promote <workflowId> [--force] [--json]");
|
|
3296
3244
|
process9.exit(1);
|
|
3297
3245
|
}
|
|
3298
3246
|
const force = hasFlag(argv, "--force");
|
|
3299
3247
|
const jsonOutput = hasFlag(argv, "--json");
|
|
3248
|
+
if (options?.deprecatedAlias && !jsonOutput) {
|
|
3249
|
+
console.error(
|
|
3250
|
+
`Note: \`canary workflow ${options.deprecatedAlias}\` is deprecated \u2014 use \`canary workflow promote\`.`
|
|
3251
|
+
);
|
|
3252
|
+
}
|
|
3300
3253
|
const result = await apiRequest(
|
|
3301
3254
|
apiUrl,
|
|
3302
3255
|
token,
|
|
3303
3256
|
"POST",
|
|
3304
|
-
`/workflows/${workflowId}/
|
|
3257
|
+
`/workflows/${workflowId}/promote`,
|
|
3305
3258
|
force ? { force: true } : {}
|
|
3306
3259
|
);
|
|
3307
3260
|
if (result.error) {
|
|
3308
3261
|
if (jsonOutput) {
|
|
3309
3262
|
console.log(JSON.stringify(result, null, 2));
|
|
3310
3263
|
} else {
|
|
3311
|
-
const hint = result.code === "FLOW_NOT_READY_TO_PUBLISH" ? "\n Trigger a successful run first (canary workflow run <id>), or pass --force." : ""
|
|
3264
|
+
const hint = result.code === "FLOW_NOT_READY_TO_PUBLISH" ? "\n Trigger a successful run first (canary workflow run <id>), or pass --force." : result.code === "PROMOTION_REQUIRES_APPROVAL" ? `
|
|
3265
|
+
Approve the test first: canary workflow approve ${workflowId} --yes
|
|
3266
|
+
(Approval asserts a human verified the test checks the right thing \u2014 it cannot be forced.)` : "";
|
|
3312
3267
|
console.error(`Error: ${result.error}${hint}`);
|
|
3313
3268
|
}
|
|
3314
3269
|
process9.exit(1);
|
|
3315
3270
|
}
|
|
3316
|
-
const version = result.workflow?.snapshotVersion;
|
|
3317
3271
|
if (jsonOutput) {
|
|
3318
3272
|
console.log(
|
|
3319
3273
|
JSON.stringify({ ok: true, workflowId, workflow: result.workflow ?? null }, null, 2)
|
|
3320
3274
|
);
|
|
3321
3275
|
return;
|
|
3322
3276
|
}
|
|
3323
|
-
console.log(
|
|
3324
|
-
|
|
3277
|
+
console.log(`Workflow ${workflowId} promoted \u2014 it will run when test suites run.`);
|
|
3278
|
+
}
|
|
3279
|
+
async function handlePause(argv, apiUrl, token) {
|
|
3280
|
+
const workflowId = argv.find((a) => !a.startsWith("-"));
|
|
3281
|
+
if (!workflowId) {
|
|
3282
|
+
console.error("Error: Missing workflow ID.");
|
|
3283
|
+
console.error("Usage: canary workflow pause <workflowId> [--json]");
|
|
3284
|
+
process9.exit(1);
|
|
3285
|
+
}
|
|
3286
|
+
const jsonOutput = hasFlag(argv, "--json");
|
|
3287
|
+
const result = await apiRequest(
|
|
3288
|
+
apiUrl,
|
|
3289
|
+
token,
|
|
3290
|
+
"POST",
|
|
3291
|
+
`/workflows/${workflowId}/pause`,
|
|
3292
|
+
{}
|
|
3325
3293
|
);
|
|
3294
|
+
if (result.error) {
|
|
3295
|
+
if (jsonOutput) {
|
|
3296
|
+
console.log(JSON.stringify(result, null, 2));
|
|
3297
|
+
} else {
|
|
3298
|
+
console.error(`Error: ${result.error}`);
|
|
3299
|
+
}
|
|
3300
|
+
process9.exit(1);
|
|
3301
|
+
}
|
|
3302
|
+
if (jsonOutput) {
|
|
3303
|
+
console.log(
|
|
3304
|
+
JSON.stringify({ ok: true, workflowId, workflow: result.workflow ?? null }, null, 2)
|
|
3305
|
+
);
|
|
3306
|
+
return;
|
|
3307
|
+
}
|
|
3308
|
+
const promotion = result.workflow?.promotion ?? null;
|
|
3309
|
+
if (promotion === "paused") {
|
|
3310
|
+
console.log(`Workflow ${workflowId} paused \u2014 excluded from suite runs until re-promoted.`);
|
|
3311
|
+
} else {
|
|
3312
|
+
console.log(`Workflow ${workflowId} was not promoted; nothing to pause.`);
|
|
3313
|
+
}
|
|
3326
3314
|
}
|
|
3327
3315
|
function getAllArgValues2(argv, flag) {
|
|
3328
3316
|
const values = [];
|
|
@@ -3455,7 +3443,10 @@ function printWorkflowHelp() {
|
|
|
3455
3443
|
" create [options] Create workflow from JSON",
|
|
3456
3444
|
" sync <workflowId> [options] Replace all nodes (same format as create)",
|
|
3457
3445
|
" patch <workflowId> [options] Update workflow properties",
|
|
3458
|
-
"
|
|
3446
|
+
" approve <workflowId> [--yes] [--json] Mark the test as human-verified (spec is right)",
|
|
3447
|
+
" promote <workflowId> [--force] [--json] Include the test in suite runs (requires approval)",
|
|
3448
|
+
" pause <workflowId> [--json] Exclude a promoted test from suite runs",
|
|
3449
|
+
" publish <workflowId> [--force] [--json] (deprecated alias for promote)",
|
|
3459
3450
|
" archive <workflowId> [--yes] [--json] Soft-delete: hide from lists, skip in test suites (reversible)",
|
|
3460
3451
|
" unarchive <workflowId> [--json] Restore a previously archived workflow",
|
|
3461
3452
|
" run <workflowId> [options] Trigger a workflow execution",
|
|
@@ -3469,7 +3460,7 @@ function printWorkflowHelp() {
|
|
|
3469
3460
|
"List options:",
|
|
3470
3461
|
" --search <query> Search by name",
|
|
3471
3462
|
" --flow-type <type> Filter: standard, setup, seed, teardown",
|
|
3472
|
-
" --status <status> Filter: draft,
|
|
3463
|
+
" --status <status> Filter: draft, approved",
|
|
3473
3464
|
" --page <n> Page number (default: 1)",
|
|
3474
3465
|
" --page-size <n> Page size (default: 25)",
|
|
3475
3466
|
" --json Output raw JSON",
|
|
@@ -3477,7 +3468,7 @@ function printWorkflowHelp() {
|
|
|
3477
3468
|
"Get options:",
|
|
3478
3469
|
" --format json|markdown|spec Output format (default: json)",
|
|
3479
3470
|
" --json Shorthand for --format json",
|
|
3480
|
-
|
|
3471
|
+
` --markdown Shorthand for editable ${specExtension} spec output`,
|
|
3481
3472
|
" --output <file> Write output to file",
|
|
3482
3473
|
"",
|
|
3483
3474
|
"Create options:",
|
|
@@ -3489,10 +3480,6 @@ function printWorkflowHelp() {
|
|
|
3489
3480
|
" --sequence-from-file <path> or --sequence-from-stdin",
|
|
3490
3481
|
" Input shape: { steps, description?, stopOnFailure?, exports? }",
|
|
3491
3482
|
" Returns: { workflowId, apiSequenceId, nodeId }",
|
|
3492
|
-
" --run-and-publish Run test first, publish on success",
|
|
3493
|
-
" --publish-timeout <sec> Timeout waiting for the test to finish (default: 900)",
|
|
3494
|
-
" --property <name|id> Property for run-and-publish",
|
|
3495
|
-
" --environment <name|id> Environment for run-and-publish",
|
|
3496
3483
|
" --tags <names> Comma-separated tag names to assign (names, not IDs)",
|
|
3497
3484
|
" --tag-id <ids> Comma-separated raw tag IDs (escape hatch)",
|
|
3498
3485
|
"",
|
|
@@ -3521,10 +3508,11 @@ function printWorkflowHelp() {
|
|
|
3521
3508
|
"Patch options:",
|
|
3522
3509
|
" --name <name> Update workflow name",
|
|
3523
3510
|
" --description <desc> Update description",
|
|
3524
|
-
" --status <status> Set status. Valid:",
|
|
3525
|
-
" draft \u2014
|
|
3526
|
-
"
|
|
3527
|
-
" (
|
|
3511
|
+
" --status <status> Set status (approval axis). Valid:",
|
|
3512
|
+
" draft \u2014 not yet approved",
|
|
3513
|
+
" approved \u2014 a human verified the test checks the right thing",
|
|
3514
|
+
" (suite inclusion is the separate promote/pause axis;",
|
|
3515
|
+
" reliability is tracked automatically by health)",
|
|
3528
3516
|
" --flow-type <type> Set type: standard, setup, seed, teardown",
|
|
3529
3517
|
" --seed-outputs-json <json> Replace seedOutputsJson (array) \u2014 seed flows only",
|
|
3530
3518
|
" --seed-outputs-file <path> Replace seedOutputsJson from a JSON file",
|
|
@@ -3534,15 +3522,22 @@ function printWorkflowHelp() {
|
|
|
3534
3522
|
" --tag-id <ids> Raw tag IDs (comma-separated)",
|
|
3535
3523
|
" --json Output raw JSON",
|
|
3536
3524
|
"",
|
|
3537
|
-
"
|
|
3538
|
-
" --
|
|
3539
|
-
"
|
|
3525
|
+
"Approve options:",
|
|
3526
|
+
" --yes Confirm approval (required non-interactively)",
|
|
3527
|
+
" --json Output raw JSON",
|
|
3528
|
+
"",
|
|
3529
|
+
" Approval asserts a human verified the test checks the right thing.",
|
|
3530
|
+
" Agents: describe the test to the user and confirm they personally",
|
|
3531
|
+
" verified it before re-running with --yes.",
|
|
3532
|
+
"",
|
|
3533
|
+
"Promote options:",
|
|
3534
|
+
" --force Promote without requiring a successful run (skips the",
|
|
3535
|
+
" run gate; the approval gate can never be forced)",
|
|
3540
3536
|
" --json Output raw JSON",
|
|
3541
3537
|
"",
|
|
3542
|
-
"
|
|
3543
|
-
"
|
|
3544
|
-
"
|
|
3545
|
-
" only sets a column and does NOT create a new snapshot.",
|
|
3538
|
+
" Promote includes the test in suite runs. Suites always execute the",
|
|
3539
|
+
" live definition \u2014 edits take effect immediately. Requires the test",
|
|
3540
|
+
" to be approved, and (without --force) a passing run.",
|
|
3546
3541
|
"",
|
|
3547
3542
|
"Run options:",
|
|
3548
3543
|
" --stream Follow execution until completion",
|
|
@@ -3591,7 +3586,7 @@ function printWorkflowHelp() {
|
|
|
3591
3586
|
" Targeted cache invalidation (rows kept, isValid=false)",
|
|
3592
3587
|
" cache clear <workflowId> --mode hard --yes DESTRUCTIVE: delete cache rows, strip playbookSteps,",
|
|
3593
3588
|
' null lastRunId. Same as the UI "Reset flow" button',
|
|
3594
|
-
" cache optimize <workflowId>
|
|
3589
|
+
" cache optimize <workflowId> [--run <runId>] Enqueue the async cache-optimizer job",
|
|
3595
3590
|
"",
|
|
3596
3591
|
"Common options:",
|
|
3597
3592
|
" --env <env> Target environment (prod, dev, local)",
|
|
@@ -3607,7 +3602,7 @@ async function runWorkflow(argv) {
|
|
|
3607
3602
|
return;
|
|
3608
3603
|
}
|
|
3609
3604
|
if (subCommand === "debug" && hasFlag(rest, "--help", "-h")) {
|
|
3610
|
-
const { handleWorkflowDebug } = await import("./workflow-debug-
|
|
3605
|
+
const { handleWorkflowDebug } = await import("./workflow-debug-PRX3DWGD.js");
|
|
3611
3606
|
await handleWorkflowDebug(rest, "", "");
|
|
3612
3607
|
return;
|
|
3613
3608
|
}
|
|
@@ -3635,8 +3630,17 @@ async function runWorkflow(argv) {
|
|
|
3635
3630
|
case "patch":
|
|
3636
3631
|
await handlePatch(rest, apiUrl, token);
|
|
3637
3632
|
break;
|
|
3633
|
+
case "approve":
|
|
3634
|
+
await handleApprove(rest, apiUrl, token);
|
|
3635
|
+
break;
|
|
3636
|
+
case "promote":
|
|
3637
|
+
await handlePromote(rest, apiUrl, token);
|
|
3638
|
+
break;
|
|
3639
|
+
case "pause":
|
|
3640
|
+
await handlePause(rest, apiUrl, token);
|
|
3641
|
+
break;
|
|
3638
3642
|
case "publish":
|
|
3639
|
-
await
|
|
3643
|
+
await handlePromote(rest, apiUrl, token, { deprecatedAlias: "publish" });
|
|
3640
3644
|
break;
|
|
3641
3645
|
case "archive":
|
|
3642
3646
|
await handleArchive(rest, apiUrl, token);
|
|
@@ -3676,7 +3680,7 @@ async function runWorkflow(argv) {
|
|
|
3676
3680
|
await handleWorkflowSync(rest, apiUrl, token);
|
|
3677
3681
|
break;
|
|
3678
3682
|
case "proposals": {
|
|
3679
|
-
const { handleWorkflowProposals } = await import("./workflow-proposals-
|
|
3683
|
+
const { handleWorkflowProposals } = await import("./workflow-proposals-BW327WGL.js");
|
|
3680
3684
|
await handleWorkflowProposals(rest, apiUrl, token);
|
|
3681
3685
|
break;
|
|
3682
3686
|
}
|
|
@@ -3687,12 +3691,12 @@ async function runWorkflow(argv) {
|
|
|
3687
3691
|
await handleWorkflowApiSequence(rest, apiUrl, token);
|
|
3688
3692
|
break;
|
|
3689
3693
|
case "cache": {
|
|
3690
|
-
const { handleWorkflowCache } = await import("./workflow-cache-
|
|
3694
|
+
const { handleWorkflowCache } = await import("./workflow-cache-GXNE6SU2.js");
|
|
3691
3695
|
await handleWorkflowCache(rest, apiUrl, token);
|
|
3692
3696
|
break;
|
|
3693
3697
|
}
|
|
3694
3698
|
case "debug": {
|
|
3695
|
-
const { handleWorkflowDebug } = await import("./workflow-debug-
|
|
3699
|
+
const { handleWorkflowDebug } = await import("./workflow-debug-PRX3DWGD.js");
|
|
3696
3700
|
await handleWorkflowDebug(rest, apiUrl, token);
|
|
3697
3701
|
break;
|
|
3698
3702
|
}
|
|
@@ -3705,4 +3709,4 @@ async function runWorkflow(argv) {
|
|
|
3705
3709
|
export {
|
|
3706
3710
|
runWorkflow
|
|
3707
3711
|
};
|
|
3708
|
-
//# sourceMappingURL=workflow-
|
|
3712
|
+
//# sourceMappingURL=workflow-2CX3ZNOQ.js.map
|