@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
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
import { createRequire as __cr } from "module"; const require = __cr(import.meta.url);
|
|
2
2
|
import {
|
|
3
3
|
packageName
|
|
4
|
-
} from "./chunk-
|
|
4
|
+
} from "./chunk-JZMJUPZP.js";
|
|
5
5
|
|
|
6
6
|
// src/update-check.ts
|
|
7
7
|
import fs from "fs/promises";
|
|
@@ -85,4 +85,4 @@ export {
|
|
|
85
85
|
checkForUpdate,
|
|
86
86
|
clearUpdateCache
|
|
87
87
|
};
|
|
88
|
-
//# sourceMappingURL=chunk-
|
|
88
|
+
//# sourceMappingURL=chunk-VGTKUOYS.js.map
|
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
import { createRequire as __cr } from "module"; const require = __cr(import.meta.url);
|
|
2
2
|
import {
|
|
3
3
|
InlineAssertionSchema
|
|
4
|
-
} from "./chunk-
|
|
4
|
+
} from "./chunk-QGI4UCJX.js";
|
|
5
5
|
|
|
6
6
|
// ../canary-spec/src/parse.ts
|
|
7
7
|
import yaml from "yaml";
|
|
@@ -26,7 +26,9 @@ var FrontmatterSchema = z.object({
|
|
|
26
26
|
* create. On recompile, the compiler keys the diff on this ID.
|
|
27
27
|
*/
|
|
28
28
|
workflowId: z.string().uuid().optional(),
|
|
29
|
-
|
|
29
|
+
// 'published' is a deprecated legacy value (pre approval/promotion split);
|
|
30
|
+
// accepted for old spec files and normalized to 'draft'.
|
|
31
|
+
status: z.enum(["draft", "approved", "published"]).transform((s) => s === "published" ? "draft" : s).optional(),
|
|
30
32
|
flowType: z.enum(["standard", "setup", "seed", "teardown"]).optional(),
|
|
31
33
|
/**
|
|
32
34
|
* Credential the journey runs as. Required for authenticated specs (the
|
|
@@ -41,7 +43,7 @@ var FrontmatterSchema = z.object({
|
|
|
41
43
|
sandboxTemplate: z.string().optional(),
|
|
42
44
|
environments: z.union([
|
|
43
45
|
z.object({ only: z.array(z.string()).min(1) }),
|
|
44
|
-
z.object({ types: z.array(z.enum(["permanent", "ephemeral", "local"])).min(1) })
|
|
46
|
+
z.object({ types: z.array(z.enum(["permanent", "ephemeral", "local", "sandbox"])).min(1) })
|
|
45
47
|
]).optional(),
|
|
46
48
|
/**
|
|
47
49
|
* Teardown linkage for `flowType: seed` workflows. Two surface forms:
|
|
@@ -145,7 +147,7 @@ var ActionNodeSchema = NodeBase.extend({
|
|
|
145
147
|
var AssertionNodeSchema = NodeBase.extend({
|
|
146
148
|
kind: z.literal("assertion"),
|
|
147
149
|
condition: z.string().min(1),
|
|
148
|
-
severity: z.enum(["warn", "fail"]).default("
|
|
150
|
+
severity: z.enum(["warn", "fail", "fatal"]).default("fatal"),
|
|
149
151
|
expectedOutcome: z.string().optional(),
|
|
150
152
|
alwaysUseAgent: z.boolean().optional()
|
|
151
153
|
});
|
|
@@ -158,7 +160,14 @@ var SeedNodeSchema = NodeBase.extend({
|
|
|
158
160
|
/** Per-request timeout (seconds) for the seed/teardown api_sequence calls (API mode only). */
|
|
159
161
|
apiTimeoutSeconds: z.number().int().positive().optional(),
|
|
160
162
|
scope: z.enum(["inline", "suite"]).optional(),
|
|
161
|
-
runTeardown: z.boolean().optional()
|
|
163
|
+
runTeardown: z.boolean().optional(),
|
|
164
|
+
/**
|
|
165
|
+
* Per-node overrides for the seed flow's `kind: 'value'` workflow inputs,
|
|
166
|
+
* keyed by input name. Only honored for inline-scoped seeds — suite-scoped
|
|
167
|
+
* seeds run with the seed flow's input defaults. Spec syntax:
|
|
168
|
+
* `- input.<name>: <value>` sub-bullets.
|
|
169
|
+
*/
|
|
170
|
+
inputs: z.record(z.string(), z.string()).optional()
|
|
162
171
|
});
|
|
163
172
|
var SetupNodeSchema = NodeBase.extend({
|
|
164
173
|
kind: z.literal("setup"),
|
|
@@ -195,7 +204,10 @@ var AudioPlayNodeSchema = NodeBase.extend({
|
|
|
195
204
|
var AudioAssertionNodeSchema = NodeBase.extend({
|
|
196
205
|
kind: z.literal("audioAssertion"),
|
|
197
206
|
label: z.string().min(1),
|
|
198
|
-
|
|
207
|
+
// Audio default stays 'fail' (not 'fatal' like standalone assertions):
|
|
208
|
+
// audio assertions never halt mid-run, so fail ≈ fatal here and fail is the
|
|
209
|
+
// historical default.
|
|
210
|
+
severity: z.enum(["warn", "fail", "fatal"]).default("fail"),
|
|
199
211
|
prompt: z.string().optional(),
|
|
200
212
|
model: z.enum(["gpt-audio", "gemini-2.x"]).optional(),
|
|
201
213
|
minDurationMs: z.number().int().nonnegative().optional(),
|
|
@@ -221,6 +233,21 @@ var ApiSequenceNodeSchema = NodeBase.extend({
|
|
|
221
233
|
*/
|
|
222
234
|
sidecar: z.string().min(1).optional()
|
|
223
235
|
});
|
|
236
|
+
var SandboxActionNodeSchema = NodeBase.extend({
|
|
237
|
+
kind: z.literal("sandboxAction"),
|
|
238
|
+
/** Slug of the sandbox action; resolved against the run env's template at run time. */
|
|
239
|
+
actionSlug: z.string().min(1),
|
|
240
|
+
/** Cosmetic display label. */
|
|
241
|
+
label: z.string().optional(),
|
|
242
|
+
/** Input params; values may carry `$var.*` / macro tokens (passed verbatim). */
|
|
243
|
+
params: z.record(z.string(), z.string()).optional(),
|
|
244
|
+
/**
|
|
245
|
+
* Output variable keys the action produces (denormalized from its
|
|
246
|
+
* outputSchema). Optional — compile resolves them from the action when
|
|
247
|
+
* omitted and a verified template declares the slug.
|
|
248
|
+
*/
|
|
249
|
+
outputs: z.array(z.string().min(1)).optional()
|
|
250
|
+
});
|
|
224
251
|
var EndNodeSchema = NodeBase.extend({
|
|
225
252
|
kind: z.literal("end"),
|
|
226
253
|
outcome: z.enum(["pass", "fail"]).default("pass")
|
|
@@ -238,6 +265,7 @@ var JourneyNodeSchema = z.union([
|
|
|
238
265
|
AudioPlayNodeSchema,
|
|
239
266
|
AudioAssertionNodeSchema,
|
|
240
267
|
ApiSequenceNodeSchema,
|
|
268
|
+
SandboxActionNodeSchema,
|
|
241
269
|
EndNodeSchema
|
|
242
270
|
]);
|
|
243
271
|
var SpecAstSchema = z.object({
|
|
@@ -604,6 +632,7 @@ function parseJourneyBlock(lines, start, end, baseIndent, startLine, issues) {
|
|
|
604
632
|
const subBullets = readBullets(lines, i + 1 + descLineCount, end, baseIndent);
|
|
605
633
|
consumedMain += subBullets.consumed;
|
|
606
634
|
const opts = parseKvBullets(subBullets.bullets);
|
|
635
|
+
const inputs = parseSeedInputBullets(subBullets.bullets);
|
|
607
636
|
nodes.push({
|
|
608
637
|
...idMeta,
|
|
609
638
|
kind: "seed",
|
|
@@ -614,7 +643,8 @@ function parseJourneyBlock(lines, start, end, baseIndent, startLine, issues) {
|
|
|
614
643
|
mode: opts.mode,
|
|
615
644
|
apiTimeoutSeconds: opts.apiTimeoutSeconds === void 0 ? void 0 : Number(opts.apiTimeoutSeconds),
|
|
616
645
|
scope: opts.scope,
|
|
617
|
-
runTeardown: typeof opts.runTeardown === "string" ? opts.runTeardown !== "false" : void 0
|
|
646
|
+
runTeardown: typeof opts.runTeardown === "string" ? opts.runTeardown !== "false" : void 0,
|
|
647
|
+
inputs
|
|
618
648
|
});
|
|
619
649
|
i += consumedMain;
|
|
620
650
|
continue;
|
|
@@ -683,7 +713,7 @@ function parseJourneyBlock(lines, start, end, baseIndent, startLine, issues) {
|
|
|
683
713
|
kind: "assertion",
|
|
684
714
|
condition: stripPunctuation(condition),
|
|
685
715
|
description,
|
|
686
|
-
severity: opts.severity ?? "
|
|
716
|
+
severity: opts.severity ?? "fatal",
|
|
687
717
|
expectedOutcome: typeof opts.expectedOutcome === "string" ? opts.expectedOutcome : void 0,
|
|
688
718
|
alwaysUseAgent: opts.alwaysUseAgent === "true" ? true : void 0
|
|
689
719
|
});
|
|
@@ -728,6 +758,26 @@ function parseJourneyBlock(lines, start, end, baseIndent, startLine, issues) {
|
|
|
728
758
|
i += consumedMain;
|
|
729
759
|
continue;
|
|
730
760
|
}
|
|
761
|
+
if (lower.startsWith("sandbox action")) {
|
|
762
|
+
const slug = stripPunctuation(
|
|
763
|
+
leadIn.replace(/^sandbox action\s*[—-]\s*/i, "").trim() || remainder
|
|
764
|
+
);
|
|
765
|
+
const subBullets = readBullets(lines, i + 1 + descLineCount, end, baseIndent);
|
|
766
|
+
consumedMain += subBullets.consumed;
|
|
767
|
+
const opts = parseKvBullets(subBullets.bullets);
|
|
768
|
+
const params = parseActionParamBullets(subBullets.bullets);
|
|
769
|
+
nodes.push({
|
|
770
|
+
...idMeta,
|
|
771
|
+
kind: "sandboxAction",
|
|
772
|
+
actionSlug: slug,
|
|
773
|
+
description,
|
|
774
|
+
label: typeof opts.label === "string" ? opts.label : void 0,
|
|
775
|
+
params,
|
|
776
|
+
outputs: typeof opts.outputs === "string" ? opts.outputs.split(",").map((s) => s.trim()).filter((s) => s.length > 0) : void 0
|
|
777
|
+
});
|
|
778
|
+
i += consumedMain;
|
|
779
|
+
continue;
|
|
780
|
+
}
|
|
731
781
|
if (lower.startsWith("api sequence")) {
|
|
732
782
|
const title = leadIn.replace(/^api sequence\s*[—-]\s*/i, "").trim();
|
|
733
783
|
const subBullets = readBullets(lines, i + 1 + descLineCount, end, baseIndent);
|
|
@@ -847,10 +897,11 @@ function parseActionBullets(bullets, lineNo, issues) {
|
|
|
847
897
|
let captureExtraMs;
|
|
848
898
|
let alwaysUseAgent;
|
|
849
899
|
for (const b of bullets) {
|
|
850
|
-
const fieldM = /^field\s+(?:"([^"]+)"|(
|
|
900
|
+
const fieldM = /^field\s+(?:"([^"]+)"|(.+?))\s*(?:\(([^)]+)\))?\s*:\s*(.+)$/i.exec(b);
|
|
851
901
|
if (fieldM) {
|
|
902
|
+
const name = (fieldM[1] ?? fieldM[2] ?? "").trim();
|
|
852
903
|
fields.push({
|
|
853
|
-
name
|
|
904
|
+
name,
|
|
854
905
|
type: fieldM[3],
|
|
855
906
|
value: stripQuotes(fieldM[4].trim())
|
|
856
907
|
});
|
|
@@ -864,7 +915,7 @@ function parseActionBullets(bullets, lineNo, issues) {
|
|
|
864
915
|
const assertM = /^assert\s*\(([^)]+)\)\s*:\s*(.+)$/i.exec(b);
|
|
865
916
|
if (assertM) {
|
|
866
917
|
const flags = assertM[1].split(",").map((s) => s.trim().toLowerCase());
|
|
867
|
-
const severity = flags.includes("fail") ? "fail" : "warn";
|
|
918
|
+
const severity = flags.includes("fatal") ? "fatal" : flags.includes("fail") ? "fail" : flags.includes("warn") ? "warn" : "fatal";
|
|
868
919
|
const agentic = flags.includes("agentic") || void 0;
|
|
869
920
|
assertions.push({ condition: stripQuotes(assertM[2].trim()), severity, agentic });
|
|
870
921
|
continue;
|
|
@@ -893,6 +944,26 @@ function parseKvBullets(bullets) {
|
|
|
893
944
|
}
|
|
894
945
|
return out;
|
|
895
946
|
}
|
|
947
|
+
function parseSeedInputBullets(bullets) {
|
|
948
|
+
let out;
|
|
949
|
+
for (const b of bullets) {
|
|
950
|
+
const m = /^input\.([A-Za-z_][A-Za-z0-9_]*)\s*:\s*(.+)$/.exec(b);
|
|
951
|
+
if (!m) continue;
|
|
952
|
+
out ??= {};
|
|
953
|
+
out[m[1]] = stripQuotes(m[2].trim());
|
|
954
|
+
}
|
|
955
|
+
return out;
|
|
956
|
+
}
|
|
957
|
+
function parseActionParamBullets(bullets) {
|
|
958
|
+
let out;
|
|
959
|
+
for (const b of bullets) {
|
|
960
|
+
const m = /^param\.([A-Za-z_][A-Za-z0-9_]*)\s*:\s*(.+)$/.exec(b);
|
|
961
|
+
if (!m) continue;
|
|
962
|
+
out ??= {};
|
|
963
|
+
out[m[1]] = stripQuotes(m[2].trim());
|
|
964
|
+
}
|
|
965
|
+
return out;
|
|
966
|
+
}
|
|
896
967
|
function numOpt(v) {
|
|
897
968
|
if (v === void 0) return void 0;
|
|
898
969
|
const n = Number(v);
|
|
@@ -923,17 +994,18 @@ var RESERVED_MACROS = /* @__PURE__ */ new Set([
|
|
|
923
994
|
]);
|
|
924
995
|
function lintSpec(ast) {
|
|
925
996
|
const issues = [];
|
|
997
|
+
const isRunFailing = (severity) => severity === "fail" || severity === "fatal";
|
|
926
998
|
const hasFailAssertion = anyNode(ast.journey, (n) => {
|
|
927
|
-
if (n.kind === "action") return n.assertions.some((a) => a.severity
|
|
928
|
-
if (n.kind === "assertion") return n.severity
|
|
929
|
-
if (n.kind === "audioAssertion") return n.severity
|
|
999
|
+
if (n.kind === "action") return n.assertions.some((a) => isRunFailing(a.severity));
|
|
1000
|
+
if (n.kind === "assertion") return isRunFailing(n.severity);
|
|
1001
|
+
if (n.kind === "audioAssertion") return isRunFailing(n.severity);
|
|
930
1002
|
return false;
|
|
931
1003
|
});
|
|
932
1004
|
if (!hasFailAssertion) {
|
|
933
1005
|
issues.push({
|
|
934
1006
|
severity: "warn",
|
|
935
|
-
message: "Spec has no fail-severity assertions \u2014 the case will pass even if the feature is broken.",
|
|
936
|
-
hint: "Add `- assert (fail): \u2026` under at least one action."
|
|
1007
|
+
message: "Spec has no fail- or fatal-severity assertions \u2014 the case will pass even if the feature is broken.",
|
|
1008
|
+
hint: "Add `- assert (fail): \u2026` (or `(fatal)` for must-stop preconditions) under at least one action."
|
|
937
1009
|
});
|
|
938
1010
|
}
|
|
939
1011
|
if (!ast.frontmatter.requirementRef) {
|
|
@@ -944,6 +1016,7 @@ function lintSpec(ast) {
|
|
|
944
1016
|
}
|
|
945
1017
|
const declaredInputs = new Set(ast.inputs.map((i) => i.name));
|
|
946
1018
|
const promotedVars = /* @__PURE__ */ new Set();
|
|
1019
|
+
declaredInputs.forEach((input) => promotedVars.add(input));
|
|
947
1020
|
walkNodes(ast.journey, (n) => {
|
|
948
1021
|
if (n.kind === "action") {
|
|
949
1022
|
n.capture.forEach((c) => promotedVars.add(c));
|
|
@@ -958,7 +1031,7 @@ function lintSpec(ast) {
|
|
|
958
1031
|
if (!promotedVars.has(name)) {
|
|
959
1032
|
issues.push({
|
|
960
1033
|
severity: "warn",
|
|
961
|
-
message: `\`$var.${name}\` referenced in ${ctx} but not declared via \`- capture
|
|
1034
|
+
message: `\`$var.${name}\` referenced in ${ctx} but not declared in \`## Inputs\`, via \`- capture:\`, or as a field.`,
|
|
962
1035
|
hint: "If this is authored data, add `- capture: " + name + "` to the action that produces it."
|
|
963
1036
|
});
|
|
964
1037
|
}
|
|
@@ -1086,11 +1159,29 @@ function extractMacroRefs(s) {
|
|
|
1086
1159
|
return out;
|
|
1087
1160
|
}
|
|
1088
1161
|
|
|
1162
|
+
// ../canary-spec/src/input-refs.ts
|
|
1163
|
+
function normalizeDeclaredInputReferences(value, inputNames) {
|
|
1164
|
+
if (inputNames.size === 0 || !value.includes("$")) return value;
|
|
1165
|
+
return value.replace(
|
|
1166
|
+
/(^|[^\\])\$([A-Za-z_][A-Za-z0-9_-]*)/g,
|
|
1167
|
+
(match, prefix, name, offset, full) => {
|
|
1168
|
+
if (!inputNames.has(name)) return match;
|
|
1169
|
+
const next = full[offset + match.length];
|
|
1170
|
+
const afterDot = full[offset + match.length + 1];
|
|
1171
|
+
if (next === "." && afterDot !== void 0 && /[A-Za-z0-9_-]/.test(afterDot)) {
|
|
1172
|
+
return match;
|
|
1173
|
+
}
|
|
1174
|
+
return `${prefix}$var.${name}`;
|
|
1175
|
+
}
|
|
1176
|
+
);
|
|
1177
|
+
}
|
|
1178
|
+
|
|
1089
1179
|
// ../canary-spec/src/emit.ts
|
|
1090
1180
|
function emitSpec(ast, opts = {}) {
|
|
1091
1181
|
const { appendDefaultEnd = true } = opts;
|
|
1092
1182
|
const nodes = [];
|
|
1093
|
-
|
|
1183
|
+
const inputNames = new Set(ast.inputs.map((i) => i.name));
|
|
1184
|
+
for (const n of ast.journey) emitNode(n, nodes, inputNames);
|
|
1094
1185
|
if (ast.frontmatter.authenticated) {
|
|
1095
1186
|
let insertAt = 0;
|
|
1096
1187
|
while (insertAt < nodes.length && (nodes[insertAt].nodeType === "seed" || nodes[insertAt].nodeType === "setup")) {
|
|
@@ -1214,24 +1305,27 @@ function loginConfig(ref, opts) {
|
|
|
1214
1305
|
...performLogin ? { performLogin: true } : {}
|
|
1215
1306
|
};
|
|
1216
1307
|
}
|
|
1217
|
-
function emitNode(n, out) {
|
|
1308
|
+
function emitNode(n, out, inputNames) {
|
|
1309
|
+
const inputRef = (value) => normalizeDeclaredInputReferences(value, inputNames);
|
|
1218
1310
|
const meta = {
|
|
1219
1311
|
...n.nodeId ? { nodeId: n.nodeId } : {},
|
|
1220
1312
|
...n.sourceLine !== void 0 ? { sourceLine: n.sourceLine } : {}
|
|
1221
1313
|
};
|
|
1222
1314
|
switch (n.kind) {
|
|
1223
|
-
case "navigate":
|
|
1315
|
+
case "navigate": {
|
|
1316
|
+
const pageUrl = inputRef(n.pageUrl);
|
|
1224
1317
|
out.push({
|
|
1225
1318
|
...meta,
|
|
1226
1319
|
nodeType: "navigate",
|
|
1227
1320
|
configJson: {
|
|
1228
|
-
title: `Go to ${shortPath(
|
|
1229
|
-
description: n.description ?? `Navigate to ${
|
|
1230
|
-
pageUrl
|
|
1321
|
+
title: `Go to ${shortPath(pageUrl)}`,
|
|
1322
|
+
description: inputRef(n.description ?? `Navigate to ${pageUrl}`),
|
|
1323
|
+
pageUrl,
|
|
1231
1324
|
...n.openInNewTab ? { openInNewTab: true } : {}
|
|
1232
1325
|
}
|
|
1233
1326
|
});
|
|
1234
1327
|
return;
|
|
1328
|
+
}
|
|
1235
1329
|
case "switchRole": {
|
|
1236
1330
|
const ref = n.credentialRef;
|
|
1237
1331
|
const fallbackDesc = ref.kind === "credential" ? `Re-authenticate as ${ref.name}` : ref.kind === "seedOutput" ? `Re-authenticate as seed-provisioned ${ref.ref}` : `Re-authenticate as ${ref.role}`;
|
|
@@ -1240,7 +1334,7 @@ function emitNode(n, out) {
|
|
|
1240
1334
|
nodeType: "login",
|
|
1241
1335
|
configJson: loginConfig(ref, {
|
|
1242
1336
|
titlePrefix: "Switch role to",
|
|
1243
|
-
description: n.description ?? fallbackDesc,
|
|
1337
|
+
description: inputRef(n.description ?? fallbackDesc),
|
|
1244
1338
|
performLogin: true
|
|
1245
1339
|
})
|
|
1246
1340
|
});
|
|
@@ -1251,7 +1345,7 @@ function emitNode(n, out) {
|
|
|
1251
1345
|
name: f.name,
|
|
1252
1346
|
label: humanizeLabel(f.name),
|
|
1253
1347
|
type: f.type ?? "text",
|
|
1254
|
-
value: f.value
|
|
1348
|
+
value: inputRef(f.value)
|
|
1255
1349
|
}));
|
|
1256
1350
|
const inputValues = fieldEntries.length > 0 ? Object.fromEntries(
|
|
1257
1351
|
fieldEntries.filter((f) => f.value !== void 0 && f.value !== "").map((f) => [f.name, f.value])
|
|
@@ -1260,8 +1354,8 @@ function emitNode(n, out) {
|
|
|
1260
1354
|
...meta,
|
|
1261
1355
|
nodeType: "action",
|
|
1262
1356
|
configJson: {
|
|
1263
|
-
customActionTitle: n.title,
|
|
1264
|
-
actionDescription: n.description ?? n.title,
|
|
1357
|
+
customActionTitle: inputRef(n.title),
|
|
1358
|
+
actionDescription: inputRef(n.description ?? n.title),
|
|
1265
1359
|
...fieldEntries.length > 0 ? {
|
|
1266
1360
|
formFields: fieldEntries,
|
|
1267
1361
|
dataRequirements: fieldEntries.map(({ name, label, type }) => ({
|
|
@@ -1275,7 +1369,7 @@ function emitNode(n, out) {
|
|
|
1275
1369
|
...n.capture.length > 0 ? { declaredOutputs: n.capture } : {},
|
|
1276
1370
|
...n.assertions.length > 0 ? {
|
|
1277
1371
|
inlineAssertions: n.assertions.map((a) => ({
|
|
1278
|
-
condition: a.condition,
|
|
1372
|
+
condition: inputRef(a.condition),
|
|
1279
1373
|
severity: a.severity,
|
|
1280
1374
|
...a.agentic ? { agentic: true } : {}
|
|
1281
1375
|
}))
|
|
@@ -1296,8 +1390,8 @@ function emitNode(n, out) {
|
|
|
1296
1390
|
nodeType: "assertion",
|
|
1297
1391
|
configJson: {
|
|
1298
1392
|
title: "Assert",
|
|
1299
|
-
description: n.description ?? n.condition,
|
|
1300
|
-
condition: n.condition,
|
|
1393
|
+
description: inputRef(n.description ?? n.condition),
|
|
1394
|
+
condition: inputRef(n.condition),
|
|
1301
1395
|
severity: n.severity,
|
|
1302
1396
|
...n.expectedOutcome ? { expectedOutcome: n.expectedOutcome } : {},
|
|
1303
1397
|
...n.alwaysUseAgent ? { alwaysUseAgent: true } : {}
|
|
@@ -1323,7 +1417,10 @@ function emitNode(n, out) {
|
|
|
1323
1417
|
...n.mode ? { executionMode: n.mode } : {},
|
|
1324
1418
|
...n.apiTimeoutSeconds ? { apiTimeoutSeconds: n.apiTimeoutSeconds } : {},
|
|
1325
1419
|
...n.scope ? { scope: n.scope } : {},
|
|
1326
|
-
...n.runTeardown !== void 0 ? { runTeardown: n.runTeardown } : {}
|
|
1420
|
+
...n.runTeardown !== void 0 ? { runTeardown: n.runTeardown } : {},
|
|
1421
|
+
// Spec `inputs` → runtime config key `inputValues` (same remap
|
|
1422
|
+
// convention as the other canonical-key mappings above).
|
|
1423
|
+
...n.inputs && Object.keys(n.inputs).length > 0 ? { inputValues: n.inputs } : {}
|
|
1327
1424
|
}
|
|
1328
1425
|
});
|
|
1329
1426
|
return;
|
|
@@ -1359,26 +1456,26 @@ function emitNode(n, out) {
|
|
|
1359
1456
|
nodeType: "condition",
|
|
1360
1457
|
configJson: {
|
|
1361
1458
|
title: "If",
|
|
1362
|
-
description: n.description ?? n.expression,
|
|
1459
|
+
description: inputRef(n.description ?? n.expression),
|
|
1363
1460
|
// Canonical runtime key is `conditionDescription`.
|
|
1364
|
-
conditionDescription: n.expression,
|
|
1365
|
-
...n.hints ? { evaluationHints: n.hints } : {}
|
|
1461
|
+
conditionDescription: inputRef(n.expression),
|
|
1462
|
+
...n.hints ? { evaluationHints: inputRef(n.hints) } : {}
|
|
1366
1463
|
}
|
|
1367
1464
|
});
|
|
1368
|
-
n.thenBranch.forEach((c) => emitNode(c, out));
|
|
1369
|
-
n.elseBranch.forEach((c) => emitNode(c, out));
|
|
1465
|
+
n.thenBranch.forEach((c) => emitNode(c, out, inputNames));
|
|
1466
|
+
n.elseBranch.forEach((c) => emitNode(c, out, inputNames));
|
|
1370
1467
|
return;
|
|
1371
1468
|
case "notification":
|
|
1372
1469
|
out.push({
|
|
1373
1470
|
...meta,
|
|
1374
1471
|
nodeType: "notification",
|
|
1375
1472
|
configJson: {
|
|
1376
|
-
title: `Notify ${n.to}`,
|
|
1377
|
-
description: n.description ?? n.body,
|
|
1473
|
+
title: `Notify ${inputRef(n.to)}`,
|
|
1474
|
+
description: inputRef(n.description ?? n.body),
|
|
1378
1475
|
channel: n.channel,
|
|
1379
|
-
to: n.to,
|
|
1380
|
-
body: n.body,
|
|
1381
|
-
...n.subject ? { subject: n.subject } : {},
|
|
1476
|
+
to: inputRef(n.to),
|
|
1477
|
+
body: inputRef(n.body),
|
|
1478
|
+
...n.subject ? { subject: inputRef(n.subject) } : {},
|
|
1382
1479
|
...n.attach ? { attachmentRef: n.attach } : {}
|
|
1383
1480
|
}
|
|
1384
1481
|
});
|
|
@@ -1403,10 +1500,15 @@ function emitNode(n, out) {
|
|
|
1403
1500
|
nodeType: "audio-assertion",
|
|
1404
1501
|
configJson: {
|
|
1405
1502
|
title: `Assert audio: ${n.label}`,
|
|
1406
|
-
description: n.description ?? n.label,
|
|
1503
|
+
description: inputRef(n.description ?? n.label),
|
|
1407
1504
|
label: n.label,
|
|
1408
1505
|
severity: n.severity,
|
|
1409
|
-
...n.prompt ? {
|
|
1506
|
+
...n.prompt ? {
|
|
1507
|
+
naturalLanguage: {
|
|
1508
|
+
prompt: inputRef(n.prompt),
|
|
1509
|
+
...n.model ? { model: n.model } : {}
|
|
1510
|
+
}
|
|
1511
|
+
} : {},
|
|
1410
1512
|
...hasDeterministicAudioAssertion(n) ? {
|
|
1411
1513
|
deterministic: {
|
|
1412
1514
|
...n.minDurationMs !== void 0 ? { minDurationMs: n.minDurationMs } : {},
|
|
@@ -1425,9 +1527,9 @@ function emitNode(n, out) {
|
|
|
1425
1527
|
...meta,
|
|
1426
1528
|
nodeType: "api_sequence",
|
|
1427
1529
|
configJson: {
|
|
1428
|
-
customActionTitle: n.title,
|
|
1429
|
-
description: n.description ?? n.title,
|
|
1430
|
-
apiEndpointContext: n.apiEndpointContext,
|
|
1530
|
+
customActionTitle: inputRef(n.title),
|
|
1531
|
+
description: inputRef(n.description ?? n.title),
|
|
1532
|
+
apiEndpointContext: inputRef(n.apiEndpointContext),
|
|
1431
1533
|
...n.credentialInputName ? { credentialInputName: n.credentialInputName } : {},
|
|
1432
1534
|
// Sidecar reference is metadata for the CLI sync layer — runtime
|
|
1433
1535
|
// ignores unknown configJson keys, and the node-hash projection
|
|
@@ -1437,6 +1539,22 @@ function emitNode(n, out) {
|
|
|
1437
1539
|
}
|
|
1438
1540
|
});
|
|
1439
1541
|
return;
|
|
1542
|
+
case "sandboxAction":
|
|
1543
|
+
out.push({
|
|
1544
|
+
...meta,
|
|
1545
|
+
nodeType: "sandbox_action",
|
|
1546
|
+
configJson: {
|
|
1547
|
+
title: n.label ?? `Sandbox action: ${n.actionSlug}`,
|
|
1548
|
+
description: inputRef(n.description ?? n.label ?? n.actionSlug),
|
|
1549
|
+
actionSlug: n.actionSlug,
|
|
1550
|
+
...n.label ? { actionLabel: n.label } : {},
|
|
1551
|
+
// Param values pass through verbatim — $var.* / macro tokens resolve
|
|
1552
|
+
// at run time against the execution state.
|
|
1553
|
+
...n.params && Object.keys(n.params).length > 0 ? { params: n.params } : {},
|
|
1554
|
+
...n.outputs && n.outputs.length > 0 ? { outputKeys: n.outputs } : {}
|
|
1555
|
+
}
|
|
1556
|
+
});
|
|
1557
|
+
return;
|
|
1440
1558
|
case "end":
|
|
1441
1559
|
out.push({
|
|
1442
1560
|
...meta,
|
|
@@ -1523,7 +1641,9 @@ function authoredProjection(nodeType, raw) {
|
|
|
1523
1641
|
onFailure: str(c.onFailure) ?? str(c.seedOnFailure) ?? null,
|
|
1524
1642
|
executionMode: str(c.executionMode) ?? str(c.seedExecutionMode) ?? null,
|
|
1525
1643
|
scope: str(c.scope) ?? null,
|
|
1526
|
-
runTeardown: typeof c.runTeardown === "boolean" ? c.runTeardown : null
|
|
1644
|
+
runTeardown: typeof c.runTeardown === "boolean" ? c.runTeardown : null,
|
|
1645
|
+
// Input overrides change what the seed provisions — authored identity.
|
|
1646
|
+
inputValues: seedInputValues(c)
|
|
1527
1647
|
};
|
|
1528
1648
|
case "setup":
|
|
1529
1649
|
return {
|
|
@@ -1573,6 +1693,20 @@ function authoredProjection(nodeType, raw) {
|
|
|
1573
1693
|
}
|
|
1574
1694
|
case "api_sequence":
|
|
1575
1695
|
return {};
|
|
1696
|
+
case "sandbox_action": {
|
|
1697
|
+
const params = obj(c.params) ?? {};
|
|
1698
|
+
const paramEntries = {};
|
|
1699
|
+
for (const key of Object.keys(params).sort()) {
|
|
1700
|
+
paramEntries[key] = str(params[key]) ?? null;
|
|
1701
|
+
}
|
|
1702
|
+
const outputKeys = Array.isArray(c.outputKeys) ? c.outputKeys.filter((k) => typeof k === "string").sort() : [];
|
|
1703
|
+
return {
|
|
1704
|
+
actionSlug: str(c.actionSlug) ?? null,
|
|
1705
|
+
label: str(c.actionLabel) ?? null,
|
|
1706
|
+
params: paramEntries,
|
|
1707
|
+
outputs: outputKeys
|
|
1708
|
+
};
|
|
1709
|
+
}
|
|
1576
1710
|
case "end":
|
|
1577
1711
|
return { outcome: str(c.outcome) ?? "pass" };
|
|
1578
1712
|
default:
|
|
@@ -1638,6 +1772,13 @@ function trimText(v) {
|
|
|
1638
1772
|
function str(v) {
|
|
1639
1773
|
return typeof v === "string" ? v : void 0;
|
|
1640
1774
|
}
|
|
1775
|
+
function seedInputValues(c) {
|
|
1776
|
+
if (!c.inputValues || typeof c.inputValues !== "object") return null;
|
|
1777
|
+
const entries = Object.entries(c.inputValues).filter(
|
|
1778
|
+
(e) => typeof e[1] === "string"
|
|
1779
|
+
);
|
|
1780
|
+
return entries.length > 0 ? Object.fromEntries(entries) : null;
|
|
1781
|
+
}
|
|
1641
1782
|
function num(v) {
|
|
1642
1783
|
return typeof v === "number" && Number.isFinite(v) ? v : void 0;
|
|
1643
1784
|
}
|
|
@@ -1978,6 +2119,8 @@ function reconcileLinearEdges(finalNodeIds, liveEdges) {
|
|
|
1978
2119
|
function workflowToSpec(workflow, opts = {}) {
|
|
1979
2120
|
const lines = [];
|
|
1980
2121
|
const sorted = [...workflow.nodes].sort((a, b) => a.orderIndex - b.orderIndex);
|
|
2122
|
+
const inputs = readInputs(workflow.inputsJson);
|
|
2123
|
+
const inputNames = new Set(inputs.map((i) => i.name));
|
|
1981
2124
|
let firstNonSeed = 0;
|
|
1982
2125
|
while (firstNonSeed < sorted.length && (sorted[firstNonSeed].nodeType === "seed" || sorted[firstNonSeed].nodeType === "setup")) {
|
|
1983
2126
|
firstNonSeed++;
|
|
@@ -1988,7 +2131,7 @@ function workflowToSpec(workflow, opts = {}) {
|
|
|
1988
2131
|
lines.push("---");
|
|
1989
2132
|
lines.push(`name: ${yamlScalar(workflow.name)}`);
|
|
1990
2133
|
lines.push(`workflowId: ${workflow.id}`);
|
|
1991
|
-
if (workflow.status === "draft" || workflow.status === "
|
|
2134
|
+
if (workflow.status === "draft" || workflow.status === "approved") {
|
|
1992
2135
|
lines.push(`status: ${workflow.status}`);
|
|
1993
2136
|
}
|
|
1994
2137
|
if (workflow.flowType && workflow.flowType !== "standard") {
|
|
@@ -2026,7 +2169,6 @@ function workflowToSpec(workflow, opts = {}) {
|
|
|
2026
2169
|
lines.push(workflow.cleanup.trim());
|
|
2027
2170
|
lines.push("");
|
|
2028
2171
|
}
|
|
2029
|
-
const inputs = readInputs(workflow.inputsJson);
|
|
2030
2172
|
if (inputs.length > 0) {
|
|
2031
2173
|
lines.push("## Inputs");
|
|
2032
2174
|
for (const i of inputs) {
|
|
@@ -2072,7 +2214,7 @@ function workflowToSpec(workflow, opts = {}) {
|
|
|
2072
2214
|
lines.push("");
|
|
2073
2215
|
for (const node of sorted) {
|
|
2074
2216
|
if (node === authLogin) continue;
|
|
2075
|
-
const block = renderNode(node);
|
|
2217
|
+
const block = renderNode(node, inputNames);
|
|
2076
2218
|
if (block.length === 0) continue;
|
|
2077
2219
|
block[0] = `${block[0]} <!-- @id ${node.id} -->`;
|
|
2078
2220
|
lines.push(...block);
|
|
@@ -2082,23 +2224,24 @@ function workflowToSpec(workflow, opts = {}) {
|
|
|
2082
2224
|
lines.push("");
|
|
2083
2225
|
return lines.join("\n");
|
|
2084
2226
|
}
|
|
2085
|
-
function renderNode(node) {
|
|
2227
|
+
function renderNode(node, inputNames) {
|
|
2086
2228
|
const c = node.configJson ?? {};
|
|
2229
|
+
const inputRef = (value) => normalizeDeclaredInputReferences(value, inputNames);
|
|
2087
2230
|
switch (node.nodeType) {
|
|
2088
2231
|
case "login": {
|
|
2089
2232
|
return [`**Switch role to ${renderLoginRef(c)}**`];
|
|
2090
2233
|
}
|
|
2091
2234
|
case "navigate":
|
|
2092
|
-
return [`**Navigate to** \`${str2(c.pageUrl) ?? "/"}\`.`];
|
|
2235
|
+
return [`**Navigate to** \`${inputRef(str2(c.pageUrl) ?? "/")}\`.`];
|
|
2093
2236
|
case "action": {
|
|
2094
|
-
const title = authoredActionTitle(c);
|
|
2237
|
+
const title = inputRef(authoredActionTitle(c));
|
|
2095
2238
|
const out = [`**Action \u2014 ${title}**`];
|
|
2096
2239
|
const desc = str2(c.actionDescription);
|
|
2097
|
-
if (desc && desc !== title) out.push(blockquote(desc));
|
|
2240
|
+
if (desc && inputRef(desc) !== title) out.push(blockquote(inputRef(desc)));
|
|
2098
2241
|
for (const f of authoredActionFields(c)) {
|
|
2099
2242
|
const typeSuffix = f.type && f.type !== "text" ? ` (${f.type})` : "";
|
|
2100
2243
|
const name = /^[A-Za-z0-9_-]+$/.test(f.name) ? f.name : `"${f.name}"`;
|
|
2101
|
-
out.push(`- field ${name}${typeSuffix}: ${inputValue(f.value)}`);
|
|
2244
|
+
out.push(`- field ${name}${typeSuffix}: ${inputValue(inputRef(f.value))}`);
|
|
2102
2245
|
}
|
|
2103
2246
|
for (const cap of arr2(c.declaredOutputs)) {
|
|
2104
2247
|
if (typeof cap === "string") out.push(`- capture: ${cap}`);
|
|
@@ -2108,7 +2251,7 @@ function renderNode(node) {
|
|
|
2108
2251
|
if (!cond) continue;
|
|
2109
2252
|
const sev = str2(prop2(a, "severity")) ?? "fail";
|
|
2110
2253
|
const flags = prop2(a, "agentic") === true ? `${sev}, agentic` : sev;
|
|
2111
|
-
out.push(`- assert (${flags}): ${cond}`);
|
|
2254
|
+
out.push(`- assert (${flags}): ${inputRef(cond)}`);
|
|
2112
2255
|
}
|
|
2113
2256
|
if (c.captureAudio === true) {
|
|
2114
2257
|
out.push("- captureAudio: true");
|
|
@@ -2120,10 +2263,10 @@ function renderNode(node) {
|
|
|
2120
2263
|
return out;
|
|
2121
2264
|
}
|
|
2122
2265
|
case "assertion": {
|
|
2123
|
-
const cond = str2(c.condition) ?? "?";
|
|
2266
|
+
const cond = inputRef(str2(c.condition) ?? "?");
|
|
2124
2267
|
const out = [`**Assert** ${cond}`];
|
|
2125
2268
|
const desc = str2(c.description);
|
|
2126
|
-
if (desc && desc !== cond) out.push(blockquote(desc));
|
|
2269
|
+
if (desc && inputRef(desc) !== cond) out.push(blockquote(inputRef(desc)));
|
|
2127
2270
|
const severity = str2(c.severity) ?? (c.strict === true ? "fail" : "warn");
|
|
2128
2271
|
out.push(`- severity: ${severity}`);
|
|
2129
2272
|
if (str2(c.expectedOutcome)) out.push(`- expectedOutcome: ${str2(c.expectedOutcome)}`);
|
|
@@ -2141,6 +2284,11 @@ function renderNode(node) {
|
|
|
2141
2284
|
if (mode) out.push(`- mode: ${mode}`);
|
|
2142
2285
|
if (str2(c.scope)) out.push(`- scope: ${str2(c.scope)}`);
|
|
2143
2286
|
if (typeof c.runTeardown === "boolean") out.push(`- runTeardown: ${c.runTeardown}`);
|
|
2287
|
+
if (c.inputValues && typeof c.inputValues === "object") {
|
|
2288
|
+
for (const [key, value] of Object.entries(c.inputValues)) {
|
|
2289
|
+
if (typeof value === "string") out.push(`- input.${key}: ${value}`);
|
|
2290
|
+
}
|
|
2291
|
+
}
|
|
2144
2292
|
return out;
|
|
2145
2293
|
}
|
|
2146
2294
|
case "setup": {
|
|
@@ -2156,14 +2304,15 @@ function renderNode(node) {
|
|
|
2156
2304
|
}
|
|
2157
2305
|
case "condition": {
|
|
2158
2306
|
const expr = str2(c.conditionDescription) ?? str2(c.conditionExpression) ?? str2(c.description) ?? "?";
|
|
2159
|
-
|
|
2307
|
+
const normalized = inputRef(expr);
|
|
2308
|
+
return normalized.includes("\n") ? ["**If**", blockquote(normalized)] : [`**If ${normalized}**`];
|
|
2160
2309
|
}
|
|
2161
2310
|
case "notification": {
|
|
2162
2311
|
const channel = str2(c.channel) ?? "email";
|
|
2163
|
-
const to = str2(c.to) ?? "?";
|
|
2312
|
+
const to = inputRef(str2(c.to) ?? "?");
|
|
2164
2313
|
const out = [`**Notify ${channel}: ${to}**`];
|
|
2165
|
-
if (str2(c.body)) out.push(blockquote(str2(c.body)));
|
|
2166
|
-
if (str2(c.subject)) out.push(`- subject: ${str2(c.subject)}`);
|
|
2314
|
+
if (str2(c.body)) out.push(blockquote(inputRef(str2(c.body))));
|
|
2315
|
+
if (str2(c.subject)) out.push(`- subject: ${inputRef(str2(c.subject))}`);
|
|
2167
2316
|
if (str2(c.attachmentRef)) out.push(`- attach: ${str2(c.attachmentRef)}`);
|
|
2168
2317
|
return out;
|
|
2169
2318
|
}
|
|
@@ -2182,7 +2331,7 @@ function renderNode(node) {
|
|
|
2182
2331
|
const model = str2(nl?.model) ?? str2(c.model);
|
|
2183
2332
|
const out = [`**Assert audio** ${str2(c.label) ?? "?"}`];
|
|
2184
2333
|
out.push(`- severity: ${str2(c.severity) ?? "fail"}`);
|
|
2185
|
-
if (prompt) out.push(`- prompt: ${prompt}`);
|
|
2334
|
+
if (prompt) out.push(`- prompt: ${inputRef(prompt)}`);
|
|
2186
2335
|
if (model) out.push(`- model: ${model}`);
|
|
2187
2336
|
for (const [cfgKey, bulletKey] of [
|
|
2188
2337
|
["minDurationMs", "minDurationMs"],
|
|
@@ -2198,15 +2347,30 @@ function renderNode(node) {
|
|
|
2198
2347
|
return out;
|
|
2199
2348
|
}
|
|
2200
2349
|
case "api_sequence": {
|
|
2201
|
-
const title = str2(c.customActionTitle) ?? str2(c.title) ?? "API sequence";
|
|
2350
|
+
const title = inputRef(str2(c.customActionTitle) ?? str2(c.title) ?? "API sequence");
|
|
2202
2351
|
const out = [`**API sequence \u2014 ${title}**`];
|
|
2203
|
-
if (str2(c.apiEndpointContext)) out.push(blockquote(str2(c.apiEndpointContext)));
|
|
2352
|
+
if (str2(c.apiEndpointContext)) out.push(blockquote(inputRef(str2(c.apiEndpointContext))));
|
|
2204
2353
|
if (str2(c.credentialInputName)) out.push(`- credential: ${str2(c.credentialInputName)}`);
|
|
2205
2354
|
if (str2(c.__apiSequenceSidecar)) {
|
|
2206
2355
|
out.push(`- apiSequence: ${str2(c.__apiSequenceSidecar)}`);
|
|
2207
2356
|
}
|
|
2208
2357
|
return out;
|
|
2209
2358
|
}
|
|
2359
|
+
case "sandbox_action": {
|
|
2360
|
+
const slug = str2(c.actionSlug) ?? "?";
|
|
2361
|
+
const out = [`**Sandbox action \u2014 ${slug}**`];
|
|
2362
|
+
if (str2(c.description)) out.push(blockquote(inputRef(str2(c.description))));
|
|
2363
|
+
if (str2(c.actionLabel)) out.push(`- label: ${str2(c.actionLabel)}`);
|
|
2364
|
+
const params = obj2(c.params);
|
|
2365
|
+
if (params) {
|
|
2366
|
+
for (const [key, value] of Object.entries(params)) {
|
|
2367
|
+
if (typeof value === "string") out.push(`- param.${key}: ${value}`);
|
|
2368
|
+
}
|
|
2369
|
+
}
|
|
2370
|
+
const outputKeys = Array.isArray(c.outputKeys) ? c.outputKeys.filter((k) => typeof k === "string") : [];
|
|
2371
|
+
if (outputKeys.length > 0) out.push(`- outputs: ${outputKeys.join(", ")}`);
|
|
2372
|
+
return out;
|
|
2373
|
+
}
|
|
2210
2374
|
case "end":
|
|
2211
2375
|
return [str2(c.outcome) === "fail" ? "**End (fail)**." : "**End**."];
|
|
2212
2376
|
default:
|
|
@@ -2456,4 +2620,4 @@ export {
|
|
|
2456
2620
|
writeWorkflowId,
|
|
2457
2621
|
writeNodeIds
|
|
2458
2622
|
};
|
|
2459
|
-
//# sourceMappingURL=chunk-
|
|
2623
|
+
//# sourceMappingURL=chunk-YN763NWQ.js.map
|