@runcofactor/cli 0.10.0 → 0.15.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/account-22LMP5PX.js +255 -0
- package/dist/account-22LMP5PX.js.map +1 -0
- package/dist/{api-catalog-GFGCLVS4.js → api-catalog-WTFQNLK6.js} +5 -4
- package/dist/{api-catalog-GFGCLVS4.js.map → api-catalog-WTFQNLK6.js.map} +1 -1
- package/dist/{attachment-SJC7D7FY.js → attachment-U3NKVPEY.js} +5 -4
- package/dist/{attachment-SJC7D7FY.js.map → attachment-U3NKVPEY.js.map} +1 -1
- package/dist/augmentor-5GMNAX4M.js +198 -0
- package/dist/augmentor-5GMNAX4M.js.map +1 -0
- package/dist/{auth-EN6NQCJY.js → auth-VQG2CDUD.js} +3 -2
- package/dist/{chunk-A4OFTUVV.js → chunk-3X3NW7QA.js} +7 -4
- package/dist/chunk-3X3NW7QA.js.map +1 -0
- package/dist/{chunk-N7HFALX3.js → chunk-46IUJXSD.js} +2 -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-B2VISN2V.js → chunk-7VMO2WOZ.js} +238 -68
- package/dist/chunk-7VMO2WOZ.js.map +1 -0
- package/dist/{chunk-QFDOWABX.js → chunk-CMGI7UZD.js} +6 -3
- package/dist/chunk-CMGI7UZD.js.map +1 -0
- package/dist/{chunk-XQXVG7RA.js → chunk-FNPMWDUQ.js} +3 -3
- package/dist/chunk-G4UYGRZR.js +2 -0
- package/dist/{chunk-I4QLI3JO.js → chunk-HDFYUFBI.js} +2 -2
- package/dist/chunk-JMJVGMXI.js +92 -0
- package/dist/chunk-JMJVGMXI.js.map +1 -0
- package/dist/{chunk-SJJW77WN.js → chunk-JYGNMKZ5.js} +129 -38
- package/dist/chunk-JYGNMKZ5.js.map +1 -0
- package/dist/{chunk-52IO7ACJ.js → chunk-KCHKFYVX.js} +68 -10
- package/dist/{chunk-52IO7ACJ.js.map → chunk-KCHKFYVX.js.map} +1 -1
- package/dist/{chunk-ZD3KHESI.js → chunk-KRWRUU6R.js} +27 -7
- package/dist/chunk-KRWRUU6R.js.map +1 -0
- package/dist/{chunk-CLAWT7BJ.js → chunk-NHTEKEYE.js} +3 -3
- package/dist/{chunk-WOHL4FTB.js → chunk-PRBRSIZP.js} +16 -10
- package/dist/chunk-PRBRSIZP.js.map +1 -0
- package/dist/{chunk-GKY2KXO5.js → chunk-UETBLPKM.js} +154 -37
- package/dist/chunk-UETBLPKM.js.map +1 -0
- package/dist/{chunk-4PNOV7OV.js → chunk-VGYN2KU2.js} +9284 -1421
- package/dist/chunk-VGYN2KU2.js.map +1 -0
- package/dist/{chunk-Q4BO4Z5V.js → chunk-XJ5YYYGC.js} +4 -4
- package/dist/{credential-COLTBV6D.js → credential-E6KUHRGU.js} +24 -20
- package/dist/credential-E6KUHRGU.js.map +1 -0
- package/dist/{credential-template-EEPYFG7R.js → credential-template-4GPOPBGD.js} +30 -28
- package/dist/credential-template-4GPOPBGD.js.map +1 -0
- package/dist/{debug-workflow-KOVH5GOP.js → debug-workflow-XCLCY6S7.js} +5 -4
- package/dist/{debug-workflow-KOVH5GOP.js.map → debug-workflow-XCLCY6S7.js.map} +1 -1
- package/dist/{docs-3SSORHB5.js → docs-COCZYMW6.js} +95 -10
- package/dist/docs-COCZYMW6.js.map +1 -0
- package/dist/{doctor-OTSIWV6G.js → doctor-ERIVTCQS.js} +9 -5
- package/dist/doctor-ERIVTCQS.js.map +1 -0
- package/dist/environment-7Y4BV6XY.js +221 -0
- package/dist/environment-7Y4BV6XY.js.map +1 -0
- package/dist/{feature-flag-T2LRZME3.js → feature-flag-MHONEX6T.js} +164 -16
- package/dist/feature-flag-MHONEX6T.js.map +1 -0
- package/dist/index.js +123 -58
- package/dist/index.js.map +1 -1
- package/dist/{init-TGWRECT2.js → init-OROOM4HF.js} +5 -4
- package/dist/{init-TGWRECT2.js.map → init-OROOM4HF.js.map} +1 -1
- package/dist/{install-DXSNWZKO.js → install-OJFXHY6U.js} +7 -7
- package/dist/{issues-XIZOPX6T.js → issues-32GONR6C.js} +5 -4
- package/dist/{issues-XIZOPX6T.js.map → issues-32GONR6C.js.map} +1 -1
- package/dist/{knobs-NBINZIUB.js → knobs-UQGGY3CP.js} +7 -5
- package/dist/knobs-UQGGY3CP.js.map +1 -0
- package/dist/{list-3TDHK637.js → list-ZMIKEC5P.js} +5 -4
- package/dist/{list-3TDHK637.js.map → list-ZMIKEC5P.js.map} +1 -1
- package/dist/{local-HICVD6PU.js → local-PUD24GGQ.js} +7 -6
- package/dist/{local-HICVD6PU.js.map → local-PUD24GGQ.js.map} +1 -1
- package/dist/{login-UOIUXVUK.js → login-BSO7YX2D.js} +5 -4
- package/dist/{login-UOIUXVUK.js.map → login-BSO7YX2D.js.map} +1 -1
- package/dist/{mcp-54IJEOUA.js → mcp-4LS7OJUT.js} +24 -25
- package/dist/mcp-4LS7OJUT.js.map +1 -0
- package/dist/{pdf-extract-ABWV3L5X.js → pdf-extract-YHE54XU4.js} +2 -2
- package/dist/product-3JKSJCBC.js +346 -0
- package/dist/product-3JKSJCBC.js.map +1 -0
- package/dist/{property-UXLOLPTD.js → property-K5DBL4UE.js} +76 -4
- package/dist/property-K5DBL4UE.js.map +1 -0
- package/dist/{psql-BYUUNLGG.js → psql-PQFUFTSE.js} +3 -2
- package/dist/{psql-BYUUNLGG.js.map → psql-PQFUFTSE.js.map} +1 -1
- package/dist/{record-4TR2UIIS.js → record-EIIYLFJ4.js} +16 -17
- package/dist/record-EIIYLFJ4.js.map +1 -0
- package/dist/{redis-35VBUYW7.js → redis-BU36EZZI.js} +3 -2
- package/dist/redis-BU36EZZI.js.map +1 -0
- package/dist/{release-OOLTUBUT.js → release-LYC2P7DZ.js} +5 -4
- package/dist/{release-OOLTUBUT.js.map → release-LYC2P7DZ.js.map} +1 -1
- package/dist/{sandbox-XGSUU6G7.js → sandbox-CKHXXZHU.js} +55 -10
- package/dist/sandbox-CKHXXZHU.js.map +1 -0
- package/dist/{scenarios-GWLJEGHA.js → scenarios-2XJ2G3KR.js} +5 -4
- package/dist/{scenarios-GWLJEGHA.js.map → scenarios-2XJ2G3KR.js.map} +1 -1
- package/dist/{session-MYFNZPRP.js → session-UTOD5ZYH.js} +77 -10
- package/dist/session-UTOD5ZYH.js.map +1 -0
- package/dist/{skill-KM34LDMO.js → skill-GMAERMQL.js} +220 -70
- package/dist/skill-GMAERMQL.js.map +1 -0
- package/dist/skills/debug-run/SKILL.md +40 -23
- 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/history/1.3.1.md +279 -0
- package/dist/skills/debug-run/version.json +1 -1
- package/dist/skills/optimize-cache/SKILL.md +233 -0
- package/dist/{spec-RA3CFEKG.js → spec-2NP36U3Y.js} +54 -25
- package/dist/spec-2NP36U3Y.js.map +1 -0
- package/dist/{src-LB4HBTJQ.js → src-4T6GHXVO.js} +19 -11
- package/dist/src-4T6GHXVO.js.map +1 -0
- package/dist/{src-N3TPKGTY.js → src-CG52HEE7.js} +10 -7
- package/dist/{src-UVDX5UP6.js → src-PK5OZXCM.js} +4 -2
- package/dist/src-UEOOC425.js +5941 -0
- package/dist/src-UEOOC425.js.map +1 -0
- package/dist/{start-PSEQSQA3.js → start-3C7EEFW2.js} +5 -4
- package/dist/{start-PSEQSQA3.js.map → start-3C7EEFW2.js.map} +1 -1
- package/dist/{tag-YY6YAABQ.js → tag-JSHOMLBR.js} +6 -5
- package/dist/{task-IQC3YR5K.js → task-YGWVYTBJ.js} +5 -4
- package/dist/{task-IQC3YR5K.js.map → task-YGWVYTBJ.js.map} +1 -1
- package/dist/{test-suite-DZNJFXDW.js → test-suite-LI7ZH367.js} +12 -7
- package/dist/{test-suite-DZNJFXDW.js.map → test-suite-LI7ZH367.js.map} +1 -1
- package/dist/trace-UMLOSIIR.js +16 -0
- package/dist/{triage-ORG45R5W.js → triage-ZWJG4NBJ.js} +6 -5
- package/dist/triage-ZWJG4NBJ.js.map +1 -0
- package/dist/{upgrade-L2VYMP2V.js → upgrade-S7CGEK6H.js} +3 -3
- package/dist/{workflow-XYFH5LTP.js → workflow-T4HSAOGW.js} +316 -241
- package/dist/workflow-T4HSAOGW.js.map +1 -0
- package/dist/{workflow-cache-NQJQFWMV.js → workflow-cache-XVEZ36KF.js} +140 -7
- package/dist/workflow-cache-XVEZ36KF.js.map +1 -0
- package/dist/{workflow-debug-BGD4UIXU.js → workflow-debug-T2BULXZ7.js} +9 -8
- package/dist/{workflow-debug-BGD4UIXU.js.map → workflow-debug-T2BULXZ7.js.map} +1 -1
- package/dist/{workflow-proposals-MTUDX46O.js → workflow-proposals-XXEZICN2.js} +5 -6
- package/dist/workflow-proposals-XXEZICN2.js.map +1 -0
- 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/chunk-ZD3KHESI.js.map +0 -1
- package/dist/credential-COLTBV6D.js.map +0 -1
- package/dist/credential-template-EEPYFG7R.js.map +0 -1
- package/dist/docs-3SSORHB5.js.map +0 -1
- package/dist/doctor-OTSIWV6G.js.map +0 -1
- package/dist/feature-flag-T2LRZME3.js.map +0 -1
- package/dist/knobs-NBINZIUB.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/redis-35VBUYW7.js.map +0 -1
- package/dist/sandbox-XGSUU6G7.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/trace-HXIW7U2D.js +0 -14
- package/dist/workflow-XYFH5LTP.js.map +0 -1
- package/dist/workflow-cache-NQJQFWMV.js.map +0 -1
- package/dist/workflow-proposals-MTUDX46O.js.map +0 -1
- /package/dist/{auth-EN6NQCJY.js.map → auth-VQG2CDUD.js.map} +0 -0
- /package/dist/{chunk-N7HFALX3.js.map → chunk-46IUJXSD.js.map} +0 -0
- /package/dist/{chunk-XQXVG7RA.js.map → chunk-FNPMWDUQ.js.map} +0 -0
- /package/dist/{pdf-extract-ABWV3L5X.js.map → chunk-G4UYGRZR.js.map} +0 -0
- /package/dist/{chunk-I4QLI3JO.js.map → chunk-HDFYUFBI.js.map} +0 -0
- /package/dist/{chunk-CLAWT7BJ.js.map → chunk-NHTEKEYE.js.map} +0 -0
- /package/dist/{chunk-Q4BO4Z5V.js.map → chunk-XJ5YYYGC.js.map} +0 -0
- /package/dist/{install-DXSNWZKO.js.map → install-OJFXHY6U.js.map} +0 -0
- /package/dist/{src-N3TPKGTY.js.map → pdf-extract-YHE54XU4.js.map} +0 -0
- /package/dist/{src-UVDX5UP6.js.map → src-CG52HEE7.js.map} +0 -0
- /package/dist/{tag-YY6YAABQ.js.map → src-PK5OZXCM.js.map} +0 -0
- /package/dist/{trace-HXIW7U2D.js.map → tag-JSHOMLBR.js.map} +0 -0
- /package/dist/{triage-ORG45R5W.js.map → trace-UMLOSIIR.js.map} +0 -0
- /package/dist/{upgrade-L2VYMP2V.js.map → upgrade-S7CGEK6H.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
|
InlineAssertionSchema
|
|
4
|
-
} from "./chunk-
|
|
4
|
+
} from "./chunk-JYGNMKZ5.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({
|
|
@@ -342,7 +370,13 @@ function parseCredentialRef(raw) {
|
|
|
342
370
|
if (trimmed.startsWith("seed-output ")) {
|
|
343
371
|
return { kind: "seedOutput", ref: trimmed.slice("seed-output ".length).trim() };
|
|
344
372
|
}
|
|
345
|
-
|
|
373
|
+
let explicitTemplatePrefix = null;
|
|
374
|
+
if (trimmed.startsWith("template ")) {
|
|
375
|
+
explicitTemplatePrefix = "template ";
|
|
376
|
+
} else if (trimmed.startsWith("persona ")) {
|
|
377
|
+
explicitTemplatePrefix = "persona ";
|
|
378
|
+
}
|
|
379
|
+
const role = explicitTemplatePrefix ? trimmed.slice(explicitTemplatePrefix.length).trim() : trimmed;
|
|
346
380
|
return { kind: "template", role };
|
|
347
381
|
}
|
|
348
382
|
function normalizeActor(raw) {
|
|
@@ -604,6 +638,7 @@ function parseJourneyBlock(lines, start, end, baseIndent, startLine, issues) {
|
|
|
604
638
|
const subBullets = readBullets(lines, i + 1 + descLineCount, end, baseIndent);
|
|
605
639
|
consumedMain += subBullets.consumed;
|
|
606
640
|
const opts = parseKvBullets(subBullets.bullets);
|
|
641
|
+
const inputs = parseSeedInputBullets(subBullets.bullets);
|
|
607
642
|
nodes.push({
|
|
608
643
|
...idMeta,
|
|
609
644
|
kind: "seed",
|
|
@@ -614,7 +649,8 @@ function parseJourneyBlock(lines, start, end, baseIndent, startLine, issues) {
|
|
|
614
649
|
mode: opts.mode,
|
|
615
650
|
apiTimeoutSeconds: opts.apiTimeoutSeconds === void 0 ? void 0 : Number(opts.apiTimeoutSeconds),
|
|
616
651
|
scope: opts.scope,
|
|
617
|
-
runTeardown: typeof opts.runTeardown === "string" ? opts.runTeardown !== "false" : void 0
|
|
652
|
+
runTeardown: typeof opts.runTeardown === "string" ? opts.runTeardown !== "false" : void 0,
|
|
653
|
+
inputs
|
|
618
654
|
});
|
|
619
655
|
i += consumedMain;
|
|
620
656
|
continue;
|
|
@@ -683,7 +719,7 @@ function parseJourneyBlock(lines, start, end, baseIndent, startLine, issues) {
|
|
|
683
719
|
kind: "assertion",
|
|
684
720
|
condition: stripPunctuation(condition),
|
|
685
721
|
description,
|
|
686
|
-
severity: opts.severity ?? "
|
|
722
|
+
severity: opts.severity ?? "fatal",
|
|
687
723
|
expectedOutcome: typeof opts.expectedOutcome === "string" ? opts.expectedOutcome : void 0,
|
|
688
724
|
alwaysUseAgent: opts.alwaysUseAgent === "true" ? true : void 0
|
|
689
725
|
});
|
|
@@ -728,6 +764,26 @@ function parseJourneyBlock(lines, start, end, baseIndent, startLine, issues) {
|
|
|
728
764
|
i += consumedMain;
|
|
729
765
|
continue;
|
|
730
766
|
}
|
|
767
|
+
if (lower.startsWith("sandbox action")) {
|
|
768
|
+
const slug = stripPunctuation(
|
|
769
|
+
leadIn.replace(/^sandbox action\s*[—-]\s*/i, "").trim() || remainder
|
|
770
|
+
);
|
|
771
|
+
const subBullets = readBullets(lines, i + 1 + descLineCount, end, baseIndent);
|
|
772
|
+
consumedMain += subBullets.consumed;
|
|
773
|
+
const opts = parseKvBullets(subBullets.bullets);
|
|
774
|
+
const params = parseActionParamBullets(subBullets.bullets);
|
|
775
|
+
nodes.push({
|
|
776
|
+
...idMeta,
|
|
777
|
+
kind: "sandboxAction",
|
|
778
|
+
actionSlug: slug,
|
|
779
|
+
description,
|
|
780
|
+
label: typeof opts.label === "string" ? opts.label : void 0,
|
|
781
|
+
params,
|
|
782
|
+
outputs: typeof opts.outputs === "string" ? opts.outputs.split(",").map((s) => s.trim()).filter((s) => s.length > 0) : void 0
|
|
783
|
+
});
|
|
784
|
+
i += consumedMain;
|
|
785
|
+
continue;
|
|
786
|
+
}
|
|
731
787
|
if (lower.startsWith("api sequence")) {
|
|
732
788
|
const title = leadIn.replace(/^api sequence\s*[—-]\s*/i, "").trim();
|
|
733
789
|
const subBullets = readBullets(lines, i + 1 + descLineCount, end, baseIndent);
|
|
@@ -847,10 +903,11 @@ function parseActionBullets(bullets, lineNo, issues) {
|
|
|
847
903
|
let captureExtraMs;
|
|
848
904
|
let alwaysUseAgent;
|
|
849
905
|
for (const b of bullets) {
|
|
850
|
-
const fieldM = /^field\s+(?:"([^"]+)"|(
|
|
906
|
+
const fieldM = /^field\s+(?:"([^"]+)"|(.+?))\s*(?:\(([^)]+)\))?\s*:\s*(.+)$/i.exec(b);
|
|
851
907
|
if (fieldM) {
|
|
908
|
+
const name = (fieldM[1] ?? fieldM[2] ?? "").trim();
|
|
852
909
|
fields.push({
|
|
853
|
-
name
|
|
910
|
+
name,
|
|
854
911
|
type: fieldM[3],
|
|
855
912
|
value: stripQuotes(fieldM[4].trim())
|
|
856
913
|
});
|
|
@@ -864,7 +921,7 @@ function parseActionBullets(bullets, lineNo, issues) {
|
|
|
864
921
|
const assertM = /^assert\s*\(([^)]+)\)\s*:\s*(.+)$/i.exec(b);
|
|
865
922
|
if (assertM) {
|
|
866
923
|
const flags = assertM[1].split(",").map((s) => s.trim().toLowerCase());
|
|
867
|
-
const severity = flags.includes("fail") ? "fail" : "warn";
|
|
924
|
+
const severity = flags.includes("fatal") ? "fatal" : flags.includes("fail") ? "fail" : flags.includes("warn") ? "warn" : "fatal";
|
|
868
925
|
const agentic = flags.includes("agentic") || void 0;
|
|
869
926
|
assertions.push({ condition: stripQuotes(assertM[2].trim()), severity, agentic });
|
|
870
927
|
continue;
|
|
@@ -893,6 +950,26 @@ function parseKvBullets(bullets) {
|
|
|
893
950
|
}
|
|
894
951
|
return out;
|
|
895
952
|
}
|
|
953
|
+
function parseSeedInputBullets(bullets) {
|
|
954
|
+
let out;
|
|
955
|
+
for (const b of bullets) {
|
|
956
|
+
const m = /^input\.([A-Za-z_][A-Za-z0-9_]*)\s*:\s*(.+)$/.exec(b);
|
|
957
|
+
if (!m) continue;
|
|
958
|
+
out ??= {};
|
|
959
|
+
out[m[1]] = stripQuotes(m[2].trim());
|
|
960
|
+
}
|
|
961
|
+
return out;
|
|
962
|
+
}
|
|
963
|
+
function parseActionParamBullets(bullets) {
|
|
964
|
+
let out;
|
|
965
|
+
for (const b of bullets) {
|
|
966
|
+
const m = /^param\.([A-Za-z_][A-Za-z0-9_]*)\s*:\s*(.+)$/.exec(b);
|
|
967
|
+
if (!m) continue;
|
|
968
|
+
out ??= {};
|
|
969
|
+
out[m[1]] = stripQuotes(m[2].trim());
|
|
970
|
+
}
|
|
971
|
+
return out;
|
|
972
|
+
}
|
|
896
973
|
function numOpt(v) {
|
|
897
974
|
if (v === void 0) return void 0;
|
|
898
975
|
const n = Number(v);
|
|
@@ -923,17 +1000,18 @@ var RESERVED_MACROS = /* @__PURE__ */ new Set([
|
|
|
923
1000
|
]);
|
|
924
1001
|
function lintSpec(ast) {
|
|
925
1002
|
const issues = [];
|
|
1003
|
+
const isRunFailing = (severity) => severity === "fail" || severity === "fatal";
|
|
926
1004
|
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
|
|
1005
|
+
if (n.kind === "action") return n.assertions.some((a) => isRunFailing(a.severity));
|
|
1006
|
+
if (n.kind === "assertion") return isRunFailing(n.severity);
|
|
1007
|
+
if (n.kind === "audioAssertion") return isRunFailing(n.severity);
|
|
930
1008
|
return false;
|
|
931
1009
|
});
|
|
932
1010
|
if (!hasFailAssertion) {
|
|
933
1011
|
issues.push({
|
|
934
1012
|
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."
|
|
1013
|
+
message: "Spec has no fail- or fatal-severity assertions \u2014 the case will pass even if the feature is broken.",
|
|
1014
|
+
hint: "Add `- assert (fail): \u2026` (or `(fatal)` for must-stop preconditions) under at least one action."
|
|
937
1015
|
});
|
|
938
1016
|
}
|
|
939
1017
|
if (!ast.frontmatter.requirementRef) {
|
|
@@ -944,6 +1022,7 @@ function lintSpec(ast) {
|
|
|
944
1022
|
}
|
|
945
1023
|
const declaredInputs = new Set(ast.inputs.map((i) => i.name));
|
|
946
1024
|
const promotedVars = /* @__PURE__ */ new Set();
|
|
1025
|
+
declaredInputs.forEach((input) => promotedVars.add(input));
|
|
947
1026
|
walkNodes(ast.journey, (n) => {
|
|
948
1027
|
if (n.kind === "action") {
|
|
949
1028
|
n.capture.forEach((c) => promotedVars.add(c));
|
|
@@ -958,7 +1037,7 @@ function lintSpec(ast) {
|
|
|
958
1037
|
if (!promotedVars.has(name)) {
|
|
959
1038
|
issues.push({
|
|
960
1039
|
severity: "warn",
|
|
961
|
-
message: `\`$var.${name}\` referenced in ${ctx} but not declared via \`- capture
|
|
1040
|
+
message: `\`$var.${name}\` referenced in ${ctx} but not declared in \`## Inputs\`, via \`- capture:\`, or as a field.`,
|
|
962
1041
|
hint: "If this is authored data, add `- capture: " + name + "` to the action that produces it."
|
|
963
1042
|
});
|
|
964
1043
|
}
|
|
@@ -1086,11 +1165,29 @@ function extractMacroRefs(s) {
|
|
|
1086
1165
|
return out;
|
|
1087
1166
|
}
|
|
1088
1167
|
|
|
1168
|
+
// ../canary-spec/src/input-refs.ts
|
|
1169
|
+
function normalizeDeclaredInputReferences(value, inputNames) {
|
|
1170
|
+
if (inputNames.size === 0 || !value.includes("$")) return value;
|
|
1171
|
+
return value.replace(
|
|
1172
|
+
/(^|[^\\])\$([A-Za-z_][A-Za-z0-9_-]*)/g,
|
|
1173
|
+
(match, prefix, name, offset, full) => {
|
|
1174
|
+
if (!inputNames.has(name)) return match;
|
|
1175
|
+
const next = full[offset + match.length];
|
|
1176
|
+
const afterDot = full[offset + match.length + 1];
|
|
1177
|
+
if (next === "." && afterDot !== void 0 && /[A-Za-z0-9_-]/.test(afterDot)) {
|
|
1178
|
+
return match;
|
|
1179
|
+
}
|
|
1180
|
+
return `${prefix}$var.${name}`;
|
|
1181
|
+
}
|
|
1182
|
+
);
|
|
1183
|
+
}
|
|
1184
|
+
|
|
1089
1185
|
// ../canary-spec/src/emit.ts
|
|
1090
1186
|
function emitSpec(ast, opts = {}) {
|
|
1091
1187
|
const { appendDefaultEnd = true } = opts;
|
|
1092
1188
|
const nodes = [];
|
|
1093
|
-
|
|
1189
|
+
const inputNames = new Set(ast.inputs.map((i) => i.name));
|
|
1190
|
+
for (const n of ast.journey) emitNode(n, nodes, inputNames);
|
|
1094
1191
|
if (ast.frontmatter.authenticated) {
|
|
1095
1192
|
let insertAt = 0;
|
|
1096
1193
|
while (insertAt < nodes.length && (nodes[insertAt].nodeType === "seed" || nodes[insertAt].nodeType === "setup")) {
|
|
@@ -1214,24 +1311,27 @@ function loginConfig(ref, opts) {
|
|
|
1214
1311
|
...performLogin ? { performLogin: true } : {}
|
|
1215
1312
|
};
|
|
1216
1313
|
}
|
|
1217
|
-
function emitNode(n, out) {
|
|
1314
|
+
function emitNode(n, out, inputNames) {
|
|
1315
|
+
const inputRef = (value) => normalizeDeclaredInputReferences(value, inputNames);
|
|
1218
1316
|
const meta = {
|
|
1219
1317
|
...n.nodeId ? { nodeId: n.nodeId } : {},
|
|
1220
1318
|
...n.sourceLine !== void 0 ? { sourceLine: n.sourceLine } : {}
|
|
1221
1319
|
};
|
|
1222
1320
|
switch (n.kind) {
|
|
1223
|
-
case "navigate":
|
|
1321
|
+
case "navigate": {
|
|
1322
|
+
const pageUrl = inputRef(n.pageUrl);
|
|
1224
1323
|
out.push({
|
|
1225
1324
|
...meta,
|
|
1226
1325
|
nodeType: "navigate",
|
|
1227
1326
|
configJson: {
|
|
1228
|
-
title: `Go to ${shortPath(
|
|
1229
|
-
description: n.description ?? `Navigate to ${
|
|
1230
|
-
pageUrl
|
|
1327
|
+
title: `Go to ${shortPath(pageUrl)}`,
|
|
1328
|
+
description: inputRef(n.description ?? `Navigate to ${pageUrl}`),
|
|
1329
|
+
pageUrl,
|
|
1231
1330
|
...n.openInNewTab ? { openInNewTab: true } : {}
|
|
1232
1331
|
}
|
|
1233
1332
|
});
|
|
1234
1333
|
return;
|
|
1334
|
+
}
|
|
1235
1335
|
case "switchRole": {
|
|
1236
1336
|
const ref = n.credentialRef;
|
|
1237
1337
|
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 +1340,7 @@ function emitNode(n, out) {
|
|
|
1240
1340
|
nodeType: "login",
|
|
1241
1341
|
configJson: loginConfig(ref, {
|
|
1242
1342
|
titlePrefix: "Switch role to",
|
|
1243
|
-
description: n.description ?? fallbackDesc,
|
|
1343
|
+
description: inputRef(n.description ?? fallbackDesc),
|
|
1244
1344
|
performLogin: true
|
|
1245
1345
|
})
|
|
1246
1346
|
});
|
|
@@ -1251,7 +1351,7 @@ function emitNode(n, out) {
|
|
|
1251
1351
|
name: f.name,
|
|
1252
1352
|
label: humanizeLabel(f.name),
|
|
1253
1353
|
type: f.type ?? "text",
|
|
1254
|
-
value: f.value
|
|
1354
|
+
value: inputRef(f.value)
|
|
1255
1355
|
}));
|
|
1256
1356
|
const inputValues = fieldEntries.length > 0 ? Object.fromEntries(
|
|
1257
1357
|
fieldEntries.filter((f) => f.value !== void 0 && f.value !== "").map((f) => [f.name, f.value])
|
|
@@ -1260,8 +1360,8 @@ function emitNode(n, out) {
|
|
|
1260
1360
|
...meta,
|
|
1261
1361
|
nodeType: "action",
|
|
1262
1362
|
configJson: {
|
|
1263
|
-
customActionTitle: n.title,
|
|
1264
|
-
actionDescription: n.description ?? n.title,
|
|
1363
|
+
customActionTitle: inputRef(n.title),
|
|
1364
|
+
actionDescription: inputRef(n.description ?? n.title),
|
|
1265
1365
|
...fieldEntries.length > 0 ? {
|
|
1266
1366
|
formFields: fieldEntries,
|
|
1267
1367
|
dataRequirements: fieldEntries.map(({ name, label, type }) => ({
|
|
@@ -1275,7 +1375,7 @@ function emitNode(n, out) {
|
|
|
1275
1375
|
...n.capture.length > 0 ? { declaredOutputs: n.capture } : {},
|
|
1276
1376
|
...n.assertions.length > 0 ? {
|
|
1277
1377
|
inlineAssertions: n.assertions.map((a) => ({
|
|
1278
|
-
condition: a.condition,
|
|
1378
|
+
condition: inputRef(a.condition),
|
|
1279
1379
|
severity: a.severity,
|
|
1280
1380
|
...a.agentic ? { agentic: true } : {}
|
|
1281
1381
|
}))
|
|
@@ -1296,8 +1396,8 @@ function emitNode(n, out) {
|
|
|
1296
1396
|
nodeType: "assertion",
|
|
1297
1397
|
configJson: {
|
|
1298
1398
|
title: "Assert",
|
|
1299
|
-
description: n.description ?? n.condition,
|
|
1300
|
-
condition: n.condition,
|
|
1399
|
+
description: inputRef(n.description ?? n.condition),
|
|
1400
|
+
condition: inputRef(n.condition),
|
|
1301
1401
|
severity: n.severity,
|
|
1302
1402
|
...n.expectedOutcome ? { expectedOutcome: n.expectedOutcome } : {},
|
|
1303
1403
|
...n.alwaysUseAgent ? { alwaysUseAgent: true } : {}
|
|
@@ -1323,7 +1423,10 @@ function emitNode(n, out) {
|
|
|
1323
1423
|
...n.mode ? { executionMode: n.mode } : {},
|
|
1324
1424
|
...n.apiTimeoutSeconds ? { apiTimeoutSeconds: n.apiTimeoutSeconds } : {},
|
|
1325
1425
|
...n.scope ? { scope: n.scope } : {},
|
|
1326
|
-
...n.runTeardown !== void 0 ? { runTeardown: n.runTeardown } : {}
|
|
1426
|
+
...n.runTeardown !== void 0 ? { runTeardown: n.runTeardown } : {},
|
|
1427
|
+
// Spec `inputs` → runtime config key `inputValues` (same remap
|
|
1428
|
+
// convention as the other canonical-key mappings above).
|
|
1429
|
+
...n.inputs && Object.keys(n.inputs).length > 0 ? { inputValues: n.inputs } : {}
|
|
1327
1430
|
}
|
|
1328
1431
|
});
|
|
1329
1432
|
return;
|
|
@@ -1359,26 +1462,26 @@ function emitNode(n, out) {
|
|
|
1359
1462
|
nodeType: "condition",
|
|
1360
1463
|
configJson: {
|
|
1361
1464
|
title: "If",
|
|
1362
|
-
description: n.description ?? n.expression,
|
|
1465
|
+
description: inputRef(n.description ?? n.expression),
|
|
1363
1466
|
// Canonical runtime key is `conditionDescription`.
|
|
1364
|
-
conditionDescription: n.expression,
|
|
1365
|
-
...n.hints ? { evaluationHints: n.hints } : {}
|
|
1467
|
+
conditionDescription: inputRef(n.expression),
|
|
1468
|
+
...n.hints ? { evaluationHints: inputRef(n.hints) } : {}
|
|
1366
1469
|
}
|
|
1367
1470
|
});
|
|
1368
|
-
n.thenBranch.forEach((c) => emitNode(c, out));
|
|
1369
|
-
n.elseBranch.forEach((c) => emitNode(c, out));
|
|
1471
|
+
n.thenBranch.forEach((c) => emitNode(c, out, inputNames));
|
|
1472
|
+
n.elseBranch.forEach((c) => emitNode(c, out, inputNames));
|
|
1370
1473
|
return;
|
|
1371
1474
|
case "notification":
|
|
1372
1475
|
out.push({
|
|
1373
1476
|
...meta,
|
|
1374
1477
|
nodeType: "notification",
|
|
1375
1478
|
configJson: {
|
|
1376
|
-
title: `Notify ${n.to}`,
|
|
1377
|
-
description: n.description ?? n.body,
|
|
1479
|
+
title: `Notify ${inputRef(n.to)}`,
|
|
1480
|
+
description: inputRef(n.description ?? n.body),
|
|
1378
1481
|
channel: n.channel,
|
|
1379
|
-
to: n.to,
|
|
1380
|
-
body: n.body,
|
|
1381
|
-
...n.subject ? { subject: n.subject } : {},
|
|
1482
|
+
to: inputRef(n.to),
|
|
1483
|
+
body: inputRef(n.body),
|
|
1484
|
+
...n.subject ? { subject: inputRef(n.subject) } : {},
|
|
1382
1485
|
...n.attach ? { attachmentRef: n.attach } : {}
|
|
1383
1486
|
}
|
|
1384
1487
|
});
|
|
@@ -1403,10 +1506,15 @@ function emitNode(n, out) {
|
|
|
1403
1506
|
nodeType: "audio-assertion",
|
|
1404
1507
|
configJson: {
|
|
1405
1508
|
title: `Assert audio: ${n.label}`,
|
|
1406
|
-
description: n.description ?? n.label,
|
|
1509
|
+
description: inputRef(n.description ?? n.label),
|
|
1407
1510
|
label: n.label,
|
|
1408
1511
|
severity: n.severity,
|
|
1409
|
-
...n.prompt ? {
|
|
1512
|
+
...n.prompt ? {
|
|
1513
|
+
naturalLanguage: {
|
|
1514
|
+
prompt: inputRef(n.prompt),
|
|
1515
|
+
...n.model ? { model: n.model } : {}
|
|
1516
|
+
}
|
|
1517
|
+
} : {},
|
|
1410
1518
|
...hasDeterministicAudioAssertion(n) ? {
|
|
1411
1519
|
deterministic: {
|
|
1412
1520
|
...n.minDurationMs !== void 0 ? { minDurationMs: n.minDurationMs } : {},
|
|
@@ -1425,9 +1533,9 @@ function emitNode(n, out) {
|
|
|
1425
1533
|
...meta,
|
|
1426
1534
|
nodeType: "api_sequence",
|
|
1427
1535
|
configJson: {
|
|
1428
|
-
customActionTitle: n.title,
|
|
1429
|
-
description: n.description ?? n.title,
|
|
1430
|
-
apiEndpointContext: n.apiEndpointContext,
|
|
1536
|
+
customActionTitle: inputRef(n.title),
|
|
1537
|
+
description: inputRef(n.description ?? n.title),
|
|
1538
|
+
apiEndpointContext: inputRef(n.apiEndpointContext),
|
|
1431
1539
|
...n.credentialInputName ? { credentialInputName: n.credentialInputName } : {},
|
|
1432
1540
|
// Sidecar reference is metadata for the CLI sync layer — runtime
|
|
1433
1541
|
// ignores unknown configJson keys, and the node-hash projection
|
|
@@ -1437,6 +1545,22 @@ function emitNode(n, out) {
|
|
|
1437
1545
|
}
|
|
1438
1546
|
});
|
|
1439
1547
|
return;
|
|
1548
|
+
case "sandboxAction":
|
|
1549
|
+
out.push({
|
|
1550
|
+
...meta,
|
|
1551
|
+
nodeType: "sandbox_action",
|
|
1552
|
+
configJson: {
|
|
1553
|
+
title: n.label ?? `Sandbox action: ${n.actionSlug}`,
|
|
1554
|
+
description: inputRef(n.description ?? n.label ?? n.actionSlug),
|
|
1555
|
+
actionSlug: n.actionSlug,
|
|
1556
|
+
...n.label ? { actionLabel: n.label } : {},
|
|
1557
|
+
// Param values pass through verbatim — $var.* / macro tokens resolve
|
|
1558
|
+
// at run time against the execution state.
|
|
1559
|
+
...n.params && Object.keys(n.params).length > 0 ? { params: n.params } : {},
|
|
1560
|
+
...n.outputs && n.outputs.length > 0 ? { outputKeys: n.outputs } : {}
|
|
1561
|
+
}
|
|
1562
|
+
});
|
|
1563
|
+
return;
|
|
1440
1564
|
case "end":
|
|
1441
1565
|
out.push({
|
|
1442
1566
|
...meta,
|
|
@@ -1523,7 +1647,9 @@ function authoredProjection(nodeType, raw) {
|
|
|
1523
1647
|
onFailure: str(c.onFailure) ?? str(c.seedOnFailure) ?? null,
|
|
1524
1648
|
executionMode: str(c.executionMode) ?? str(c.seedExecutionMode) ?? null,
|
|
1525
1649
|
scope: str(c.scope) ?? null,
|
|
1526
|
-
runTeardown: typeof c.runTeardown === "boolean" ? c.runTeardown : null
|
|
1650
|
+
runTeardown: typeof c.runTeardown === "boolean" ? c.runTeardown : null,
|
|
1651
|
+
// Input overrides change what the seed provisions — authored identity.
|
|
1652
|
+
inputValues: seedInputValues(c)
|
|
1527
1653
|
};
|
|
1528
1654
|
case "setup":
|
|
1529
1655
|
return {
|
|
@@ -1573,6 +1699,20 @@ function authoredProjection(nodeType, raw) {
|
|
|
1573
1699
|
}
|
|
1574
1700
|
case "api_sequence":
|
|
1575
1701
|
return {};
|
|
1702
|
+
case "sandbox_action": {
|
|
1703
|
+
const params = obj(c.params) ?? {};
|
|
1704
|
+
const paramEntries = {};
|
|
1705
|
+
for (const key of Object.keys(params).sort()) {
|
|
1706
|
+
paramEntries[key] = str(params[key]) ?? null;
|
|
1707
|
+
}
|
|
1708
|
+
const outputKeys = Array.isArray(c.outputKeys) ? c.outputKeys.filter((k) => typeof k === "string").sort() : [];
|
|
1709
|
+
return {
|
|
1710
|
+
actionSlug: str(c.actionSlug) ?? null,
|
|
1711
|
+
label: str(c.actionLabel) ?? null,
|
|
1712
|
+
params: paramEntries,
|
|
1713
|
+
outputs: outputKeys
|
|
1714
|
+
};
|
|
1715
|
+
}
|
|
1576
1716
|
case "end":
|
|
1577
1717
|
return { outcome: str(c.outcome) ?? "pass" };
|
|
1578
1718
|
default:
|
|
@@ -1638,6 +1778,13 @@ function trimText(v) {
|
|
|
1638
1778
|
function str(v) {
|
|
1639
1779
|
return typeof v === "string" ? v : void 0;
|
|
1640
1780
|
}
|
|
1781
|
+
function seedInputValues(c) {
|
|
1782
|
+
if (!c.inputValues || typeof c.inputValues !== "object") return null;
|
|
1783
|
+
const entries = Object.entries(c.inputValues).filter(
|
|
1784
|
+
(e) => typeof e[1] === "string"
|
|
1785
|
+
);
|
|
1786
|
+
return entries.length > 0 ? Object.fromEntries(entries) : null;
|
|
1787
|
+
}
|
|
1641
1788
|
function num(v) {
|
|
1642
1789
|
return typeof v === "number" && Number.isFinite(v) ? v : void 0;
|
|
1643
1790
|
}
|
|
@@ -1761,7 +1908,7 @@ function diffWorkflow(spec, live) {
|
|
|
1761
1908
|
if (specApiOnly !== liveApiOnly) workflowFieldChanges.apiOnly = specApiOnly;
|
|
1762
1909
|
if (spec.tags !== void 0) {
|
|
1763
1910
|
const specSet = [...spec.tags].sort();
|
|
1764
|
-
const liveSet =
|
|
1911
|
+
const liveSet = (live.tags ?? []).map((t) => t.name).sort();
|
|
1765
1912
|
if (specSet.length !== liveSet.length || specSet.some((v, i) => v !== liveSet[i])) {
|
|
1766
1913
|
workflowFieldChanges.tags = spec.tags;
|
|
1767
1914
|
}
|
|
@@ -1978,6 +2125,8 @@ function reconcileLinearEdges(finalNodeIds, liveEdges) {
|
|
|
1978
2125
|
function workflowToSpec(workflow, opts = {}) {
|
|
1979
2126
|
const lines = [];
|
|
1980
2127
|
const sorted = [...workflow.nodes].sort((a, b) => a.orderIndex - b.orderIndex);
|
|
2128
|
+
const inputs = readInputs(workflow.inputsJson);
|
|
2129
|
+
const inputNames = new Set(inputs.map((i) => i.name));
|
|
1981
2130
|
let firstNonSeed = 0;
|
|
1982
2131
|
while (firstNonSeed < sorted.length && (sorted[firstNonSeed].nodeType === "seed" || sorted[firstNonSeed].nodeType === "setup")) {
|
|
1983
2132
|
firstNonSeed++;
|
|
@@ -1988,7 +2137,7 @@ function workflowToSpec(workflow, opts = {}) {
|
|
|
1988
2137
|
lines.push("---");
|
|
1989
2138
|
lines.push(`name: ${yamlScalar(workflow.name)}`);
|
|
1990
2139
|
lines.push(`workflowId: ${workflow.id}`);
|
|
1991
|
-
if (workflow.status === "draft" || workflow.status === "
|
|
2140
|
+
if (workflow.status === "draft" || workflow.status === "approved") {
|
|
1992
2141
|
lines.push(`status: ${workflow.status}`);
|
|
1993
2142
|
}
|
|
1994
2143
|
if (workflow.flowType && workflow.flowType !== "standard") {
|
|
@@ -2026,7 +2175,6 @@ function workflowToSpec(workflow, opts = {}) {
|
|
|
2026
2175
|
lines.push(workflow.cleanup.trim());
|
|
2027
2176
|
lines.push("");
|
|
2028
2177
|
}
|
|
2029
|
-
const inputs = readInputs(workflow.inputsJson);
|
|
2030
2178
|
if (inputs.length > 0) {
|
|
2031
2179
|
lines.push("## Inputs");
|
|
2032
2180
|
for (const i of inputs) {
|
|
@@ -2072,7 +2220,7 @@ function workflowToSpec(workflow, opts = {}) {
|
|
|
2072
2220
|
lines.push("");
|
|
2073
2221
|
for (const node of sorted) {
|
|
2074
2222
|
if (node === authLogin) continue;
|
|
2075
|
-
const block = renderNode(node);
|
|
2223
|
+
const block = renderNode(node, inputNames);
|
|
2076
2224
|
if (block.length === 0) continue;
|
|
2077
2225
|
block[0] = `${block[0]} <!-- @id ${node.id} -->`;
|
|
2078
2226
|
lines.push(...block);
|
|
@@ -2082,23 +2230,24 @@ function workflowToSpec(workflow, opts = {}) {
|
|
|
2082
2230
|
lines.push("");
|
|
2083
2231
|
return lines.join("\n");
|
|
2084
2232
|
}
|
|
2085
|
-
function renderNode(node) {
|
|
2233
|
+
function renderNode(node, inputNames) {
|
|
2086
2234
|
const c = node.configJson ?? {};
|
|
2235
|
+
const inputRef = (value) => normalizeDeclaredInputReferences(value, inputNames);
|
|
2087
2236
|
switch (node.nodeType) {
|
|
2088
2237
|
case "login": {
|
|
2089
2238
|
return [`**Switch role to ${renderLoginRef(c)}**`];
|
|
2090
2239
|
}
|
|
2091
2240
|
case "navigate":
|
|
2092
|
-
return [`**Navigate to** \`${str2(c.pageUrl) ?? "/"}\`.`];
|
|
2241
|
+
return [`**Navigate to** \`${inputRef(str2(c.pageUrl) ?? "/")}\`.`];
|
|
2093
2242
|
case "action": {
|
|
2094
|
-
const title = authoredActionTitle(c);
|
|
2243
|
+
const title = inputRef(authoredActionTitle(c));
|
|
2095
2244
|
const out = [`**Action \u2014 ${title}**`];
|
|
2096
2245
|
const desc = str2(c.actionDescription);
|
|
2097
|
-
if (desc && desc !== title) out.push(blockquote(desc));
|
|
2246
|
+
if (desc && inputRef(desc) !== title) out.push(blockquote(inputRef(desc)));
|
|
2098
2247
|
for (const f of authoredActionFields(c)) {
|
|
2099
2248
|
const typeSuffix = f.type && f.type !== "text" ? ` (${f.type})` : "";
|
|
2100
2249
|
const name = /^[A-Za-z0-9_-]+$/.test(f.name) ? f.name : `"${f.name}"`;
|
|
2101
|
-
out.push(`- field ${name}${typeSuffix}: ${inputValue(f.value)}`);
|
|
2250
|
+
out.push(`- field ${name}${typeSuffix}: ${inputValue(inputRef(f.value))}`);
|
|
2102
2251
|
}
|
|
2103
2252
|
for (const cap of arr2(c.declaredOutputs)) {
|
|
2104
2253
|
if (typeof cap === "string") out.push(`- capture: ${cap}`);
|
|
@@ -2108,7 +2257,7 @@ function renderNode(node) {
|
|
|
2108
2257
|
if (!cond) continue;
|
|
2109
2258
|
const sev = str2(prop2(a, "severity")) ?? "fail";
|
|
2110
2259
|
const flags = prop2(a, "agentic") === true ? `${sev}, agentic` : sev;
|
|
2111
|
-
out.push(`- assert (${flags}): ${cond}`);
|
|
2260
|
+
out.push(`- assert (${flags}): ${inputRef(cond)}`);
|
|
2112
2261
|
}
|
|
2113
2262
|
if (c.captureAudio === true) {
|
|
2114
2263
|
out.push("- captureAudio: true");
|
|
@@ -2120,10 +2269,10 @@ function renderNode(node) {
|
|
|
2120
2269
|
return out;
|
|
2121
2270
|
}
|
|
2122
2271
|
case "assertion": {
|
|
2123
|
-
const cond = str2(c.condition) ?? "?";
|
|
2272
|
+
const cond = inputRef(str2(c.condition) ?? "?");
|
|
2124
2273
|
const out = [`**Assert** ${cond}`];
|
|
2125
2274
|
const desc = str2(c.description);
|
|
2126
|
-
if (desc && desc !== cond) out.push(blockquote(desc));
|
|
2275
|
+
if (desc && inputRef(desc) !== cond) out.push(blockquote(inputRef(desc)));
|
|
2127
2276
|
const severity = str2(c.severity) ?? (c.strict === true ? "fail" : "warn");
|
|
2128
2277
|
out.push(`- severity: ${severity}`);
|
|
2129
2278
|
if (str2(c.expectedOutcome)) out.push(`- expectedOutcome: ${str2(c.expectedOutcome)}`);
|
|
@@ -2141,6 +2290,11 @@ function renderNode(node) {
|
|
|
2141
2290
|
if (mode) out.push(`- mode: ${mode}`);
|
|
2142
2291
|
if (str2(c.scope)) out.push(`- scope: ${str2(c.scope)}`);
|
|
2143
2292
|
if (typeof c.runTeardown === "boolean") out.push(`- runTeardown: ${c.runTeardown}`);
|
|
2293
|
+
if (c.inputValues && typeof c.inputValues === "object") {
|
|
2294
|
+
for (const [key, value] of Object.entries(c.inputValues)) {
|
|
2295
|
+
if (typeof value === "string") out.push(`- input.${key}: ${value}`);
|
|
2296
|
+
}
|
|
2297
|
+
}
|
|
2144
2298
|
return out;
|
|
2145
2299
|
}
|
|
2146
2300
|
case "setup": {
|
|
@@ -2156,14 +2310,15 @@ function renderNode(node) {
|
|
|
2156
2310
|
}
|
|
2157
2311
|
case "condition": {
|
|
2158
2312
|
const expr = str2(c.conditionDescription) ?? str2(c.conditionExpression) ?? str2(c.description) ?? "?";
|
|
2159
|
-
|
|
2313
|
+
const normalized = inputRef(expr);
|
|
2314
|
+
return normalized.includes("\n") ? ["**If**", blockquote(normalized)] : [`**If ${normalized}**`];
|
|
2160
2315
|
}
|
|
2161
2316
|
case "notification": {
|
|
2162
2317
|
const channel = str2(c.channel) ?? "email";
|
|
2163
|
-
const to = str2(c.to) ?? "?";
|
|
2318
|
+
const to = inputRef(str2(c.to) ?? "?");
|
|
2164
2319
|
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)}`);
|
|
2320
|
+
if (str2(c.body)) out.push(blockquote(inputRef(str2(c.body))));
|
|
2321
|
+
if (str2(c.subject)) out.push(`- subject: ${inputRef(str2(c.subject))}`);
|
|
2167
2322
|
if (str2(c.attachmentRef)) out.push(`- attach: ${str2(c.attachmentRef)}`);
|
|
2168
2323
|
return out;
|
|
2169
2324
|
}
|
|
@@ -2182,7 +2337,7 @@ function renderNode(node) {
|
|
|
2182
2337
|
const model = str2(nl?.model) ?? str2(c.model);
|
|
2183
2338
|
const out = [`**Assert audio** ${str2(c.label) ?? "?"}`];
|
|
2184
2339
|
out.push(`- severity: ${str2(c.severity) ?? "fail"}`);
|
|
2185
|
-
if (prompt) out.push(`- prompt: ${prompt}`);
|
|
2340
|
+
if (prompt) out.push(`- prompt: ${inputRef(prompt)}`);
|
|
2186
2341
|
if (model) out.push(`- model: ${model}`);
|
|
2187
2342
|
for (const [cfgKey, bulletKey] of [
|
|
2188
2343
|
["minDurationMs", "minDurationMs"],
|
|
@@ -2198,15 +2353,30 @@ function renderNode(node) {
|
|
|
2198
2353
|
return out;
|
|
2199
2354
|
}
|
|
2200
2355
|
case "api_sequence": {
|
|
2201
|
-
const title = str2(c.customActionTitle) ?? str2(c.title) ?? "API sequence";
|
|
2356
|
+
const title = inputRef(str2(c.customActionTitle) ?? str2(c.title) ?? "API sequence");
|
|
2202
2357
|
const out = [`**API sequence \u2014 ${title}**`];
|
|
2203
|
-
if (str2(c.apiEndpointContext)) out.push(blockquote(str2(c.apiEndpointContext)));
|
|
2358
|
+
if (str2(c.apiEndpointContext)) out.push(blockquote(inputRef(str2(c.apiEndpointContext))));
|
|
2204
2359
|
if (str2(c.credentialInputName)) out.push(`- credential: ${str2(c.credentialInputName)}`);
|
|
2205
2360
|
if (str2(c.__apiSequenceSidecar)) {
|
|
2206
2361
|
out.push(`- apiSequence: ${str2(c.__apiSequenceSidecar)}`);
|
|
2207
2362
|
}
|
|
2208
2363
|
return out;
|
|
2209
2364
|
}
|
|
2365
|
+
case "sandbox_action": {
|
|
2366
|
+
const slug = str2(c.actionSlug) ?? "?";
|
|
2367
|
+
const out = [`**Sandbox action \u2014 ${slug}**`];
|
|
2368
|
+
if (str2(c.description)) out.push(blockquote(inputRef(str2(c.description))));
|
|
2369
|
+
if (str2(c.actionLabel)) out.push(`- label: ${str2(c.actionLabel)}`);
|
|
2370
|
+
const params = obj2(c.params);
|
|
2371
|
+
if (params) {
|
|
2372
|
+
for (const [key, value] of Object.entries(params)) {
|
|
2373
|
+
if (typeof value === "string") out.push(`- param.${key}: ${value}`);
|
|
2374
|
+
}
|
|
2375
|
+
}
|
|
2376
|
+
const outputKeys = Array.isArray(c.outputKeys) ? c.outputKeys.filter((k) => typeof k === "string") : [];
|
|
2377
|
+
if (outputKeys.length > 0) out.push(`- outputs: ${outputKeys.join(", ")}`);
|
|
2378
|
+
return out;
|
|
2379
|
+
}
|
|
2210
2380
|
case "end":
|
|
2211
2381
|
return [str2(c.outcome) === "fail" ? "**End (fail)**." : "**End**."];
|
|
2212
2382
|
default:
|
|
@@ -2456,4 +2626,4 @@ export {
|
|
|
2456
2626
|
writeWorkflowId,
|
|
2457
2627
|
writeNodeIds
|
|
2458
2628
|
};
|
|
2459
|
-
//# sourceMappingURL=chunk-
|
|
2629
|
+
//# sourceMappingURL=chunk-7VMO2WOZ.js.map
|