@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.
Files changed (166) hide show
  1. package/dist/account-22LMP5PX.js +255 -0
  2. package/dist/account-22LMP5PX.js.map +1 -0
  3. package/dist/{api-catalog-GFGCLVS4.js → api-catalog-WTFQNLK6.js} +5 -4
  4. package/dist/{api-catalog-GFGCLVS4.js.map → api-catalog-WTFQNLK6.js.map} +1 -1
  5. package/dist/{attachment-SJC7D7FY.js → attachment-U3NKVPEY.js} +5 -4
  6. package/dist/{attachment-SJC7D7FY.js.map → attachment-U3NKVPEY.js.map} +1 -1
  7. package/dist/augmentor-5GMNAX4M.js +198 -0
  8. package/dist/augmentor-5GMNAX4M.js.map +1 -0
  9. package/dist/{auth-EN6NQCJY.js → auth-VQG2CDUD.js} +3 -2
  10. package/dist/{chunk-A4OFTUVV.js → chunk-3X3NW7QA.js} +7 -4
  11. package/dist/chunk-3X3NW7QA.js.map +1 -0
  12. package/dist/{chunk-N7HFALX3.js → chunk-46IUJXSD.js} +2 -2
  13. package/dist/{chunk-IMPZAX6L.js → chunk-5GD47G2D.js} +37 -1
  14. package/dist/{chunk-IMPZAX6L.js.map → chunk-5GD47G2D.js.map} +1 -1
  15. package/dist/{chunk-B2VISN2V.js → chunk-7VMO2WOZ.js} +238 -68
  16. package/dist/chunk-7VMO2WOZ.js.map +1 -0
  17. package/dist/{chunk-QFDOWABX.js → chunk-CMGI7UZD.js} +6 -3
  18. package/dist/chunk-CMGI7UZD.js.map +1 -0
  19. package/dist/{chunk-XQXVG7RA.js → chunk-FNPMWDUQ.js} +3 -3
  20. package/dist/chunk-G4UYGRZR.js +2 -0
  21. package/dist/{chunk-I4QLI3JO.js → chunk-HDFYUFBI.js} +2 -2
  22. package/dist/chunk-JMJVGMXI.js +92 -0
  23. package/dist/chunk-JMJVGMXI.js.map +1 -0
  24. package/dist/{chunk-SJJW77WN.js → chunk-JYGNMKZ5.js} +129 -38
  25. package/dist/chunk-JYGNMKZ5.js.map +1 -0
  26. package/dist/{chunk-52IO7ACJ.js → chunk-KCHKFYVX.js} +68 -10
  27. package/dist/{chunk-52IO7ACJ.js.map → chunk-KCHKFYVX.js.map} +1 -1
  28. package/dist/{chunk-ZD3KHESI.js → chunk-KRWRUU6R.js} +27 -7
  29. package/dist/chunk-KRWRUU6R.js.map +1 -0
  30. package/dist/{chunk-CLAWT7BJ.js → chunk-NHTEKEYE.js} +3 -3
  31. package/dist/{chunk-WOHL4FTB.js → chunk-PRBRSIZP.js} +16 -10
  32. package/dist/chunk-PRBRSIZP.js.map +1 -0
  33. package/dist/{chunk-GKY2KXO5.js → chunk-UETBLPKM.js} +154 -37
  34. package/dist/chunk-UETBLPKM.js.map +1 -0
  35. package/dist/{chunk-4PNOV7OV.js → chunk-VGYN2KU2.js} +9284 -1421
  36. package/dist/chunk-VGYN2KU2.js.map +1 -0
  37. package/dist/{chunk-Q4BO4Z5V.js → chunk-XJ5YYYGC.js} +4 -4
  38. package/dist/{credential-COLTBV6D.js → credential-E6KUHRGU.js} +24 -20
  39. package/dist/credential-E6KUHRGU.js.map +1 -0
  40. package/dist/{credential-template-EEPYFG7R.js → credential-template-4GPOPBGD.js} +30 -28
  41. package/dist/credential-template-4GPOPBGD.js.map +1 -0
  42. package/dist/{debug-workflow-KOVH5GOP.js → debug-workflow-XCLCY6S7.js} +5 -4
  43. package/dist/{debug-workflow-KOVH5GOP.js.map → debug-workflow-XCLCY6S7.js.map} +1 -1
  44. package/dist/{docs-3SSORHB5.js → docs-COCZYMW6.js} +95 -10
  45. package/dist/docs-COCZYMW6.js.map +1 -0
  46. package/dist/{doctor-OTSIWV6G.js → doctor-ERIVTCQS.js} +9 -5
  47. package/dist/doctor-ERIVTCQS.js.map +1 -0
  48. package/dist/environment-7Y4BV6XY.js +221 -0
  49. package/dist/environment-7Y4BV6XY.js.map +1 -0
  50. package/dist/{feature-flag-T2LRZME3.js → feature-flag-MHONEX6T.js} +164 -16
  51. package/dist/feature-flag-MHONEX6T.js.map +1 -0
  52. package/dist/index.js +123 -58
  53. package/dist/index.js.map +1 -1
  54. package/dist/{init-TGWRECT2.js → init-OROOM4HF.js} +5 -4
  55. package/dist/{init-TGWRECT2.js.map → init-OROOM4HF.js.map} +1 -1
  56. package/dist/{install-DXSNWZKO.js → install-OJFXHY6U.js} +7 -7
  57. package/dist/{issues-XIZOPX6T.js → issues-32GONR6C.js} +5 -4
  58. package/dist/{issues-XIZOPX6T.js.map → issues-32GONR6C.js.map} +1 -1
  59. package/dist/{knobs-NBINZIUB.js → knobs-UQGGY3CP.js} +7 -5
  60. package/dist/knobs-UQGGY3CP.js.map +1 -0
  61. package/dist/{list-3TDHK637.js → list-ZMIKEC5P.js} +5 -4
  62. package/dist/{list-3TDHK637.js.map → list-ZMIKEC5P.js.map} +1 -1
  63. package/dist/{local-HICVD6PU.js → local-PUD24GGQ.js} +7 -6
  64. package/dist/{local-HICVD6PU.js.map → local-PUD24GGQ.js.map} +1 -1
  65. package/dist/{login-UOIUXVUK.js → login-BSO7YX2D.js} +5 -4
  66. package/dist/{login-UOIUXVUK.js.map → login-BSO7YX2D.js.map} +1 -1
  67. package/dist/{mcp-54IJEOUA.js → mcp-4LS7OJUT.js} +24 -25
  68. package/dist/mcp-4LS7OJUT.js.map +1 -0
  69. package/dist/{pdf-extract-ABWV3L5X.js → pdf-extract-YHE54XU4.js} +2 -2
  70. package/dist/product-3JKSJCBC.js +346 -0
  71. package/dist/product-3JKSJCBC.js.map +1 -0
  72. package/dist/{property-UXLOLPTD.js → property-K5DBL4UE.js} +76 -4
  73. package/dist/property-K5DBL4UE.js.map +1 -0
  74. package/dist/{psql-BYUUNLGG.js → psql-PQFUFTSE.js} +3 -2
  75. package/dist/{psql-BYUUNLGG.js.map → psql-PQFUFTSE.js.map} +1 -1
  76. package/dist/{record-4TR2UIIS.js → record-EIIYLFJ4.js} +16 -17
  77. package/dist/record-EIIYLFJ4.js.map +1 -0
  78. package/dist/{redis-35VBUYW7.js → redis-BU36EZZI.js} +3 -2
  79. package/dist/redis-BU36EZZI.js.map +1 -0
  80. package/dist/{release-OOLTUBUT.js → release-LYC2P7DZ.js} +5 -4
  81. package/dist/{release-OOLTUBUT.js.map → release-LYC2P7DZ.js.map} +1 -1
  82. package/dist/{sandbox-XGSUU6G7.js → sandbox-CKHXXZHU.js} +55 -10
  83. package/dist/sandbox-CKHXXZHU.js.map +1 -0
  84. package/dist/{scenarios-GWLJEGHA.js → scenarios-2XJ2G3KR.js} +5 -4
  85. package/dist/{scenarios-GWLJEGHA.js.map → scenarios-2XJ2G3KR.js.map} +1 -1
  86. package/dist/{session-MYFNZPRP.js → session-UTOD5ZYH.js} +77 -10
  87. package/dist/session-UTOD5ZYH.js.map +1 -0
  88. package/dist/{skill-KM34LDMO.js → skill-GMAERMQL.js} +220 -70
  89. package/dist/skill-GMAERMQL.js.map +1 -0
  90. package/dist/skills/debug-run/SKILL.md +40 -23
  91. package/dist/skills/debug-run/history/1.2.0.md +262 -0
  92. package/dist/skills/debug-run/history/1.3.0.md +273 -0
  93. package/dist/skills/debug-run/history/1.3.1.md +279 -0
  94. package/dist/skills/debug-run/version.json +1 -1
  95. package/dist/skills/optimize-cache/SKILL.md +233 -0
  96. package/dist/{spec-RA3CFEKG.js → spec-2NP36U3Y.js} +54 -25
  97. package/dist/spec-2NP36U3Y.js.map +1 -0
  98. package/dist/{src-LB4HBTJQ.js → src-4T6GHXVO.js} +19 -11
  99. package/dist/src-4T6GHXVO.js.map +1 -0
  100. package/dist/{src-N3TPKGTY.js → src-CG52HEE7.js} +10 -7
  101. package/dist/{src-UVDX5UP6.js → src-PK5OZXCM.js} +4 -2
  102. package/dist/src-UEOOC425.js +5941 -0
  103. package/dist/src-UEOOC425.js.map +1 -0
  104. package/dist/{start-PSEQSQA3.js → start-3C7EEFW2.js} +5 -4
  105. package/dist/{start-PSEQSQA3.js.map → start-3C7EEFW2.js.map} +1 -1
  106. package/dist/{tag-YY6YAABQ.js → tag-JSHOMLBR.js} +6 -5
  107. package/dist/{task-IQC3YR5K.js → task-YGWVYTBJ.js} +5 -4
  108. package/dist/{task-IQC3YR5K.js.map → task-YGWVYTBJ.js.map} +1 -1
  109. package/dist/{test-suite-DZNJFXDW.js → test-suite-LI7ZH367.js} +12 -7
  110. package/dist/{test-suite-DZNJFXDW.js.map → test-suite-LI7ZH367.js.map} +1 -1
  111. package/dist/trace-UMLOSIIR.js +16 -0
  112. package/dist/{triage-ORG45R5W.js → triage-ZWJG4NBJ.js} +6 -5
  113. package/dist/triage-ZWJG4NBJ.js.map +1 -0
  114. package/dist/{upgrade-L2VYMP2V.js → upgrade-S7CGEK6H.js} +3 -3
  115. package/dist/{workflow-XYFH5LTP.js → workflow-T4HSAOGW.js} +316 -241
  116. package/dist/workflow-T4HSAOGW.js.map +1 -0
  117. package/dist/{workflow-cache-NQJQFWMV.js → workflow-cache-XVEZ36KF.js} +140 -7
  118. package/dist/workflow-cache-XVEZ36KF.js.map +1 -0
  119. package/dist/{workflow-debug-BGD4UIXU.js → workflow-debug-T2BULXZ7.js} +9 -8
  120. package/dist/{workflow-debug-BGD4UIXU.js.map → workflow-debug-T2BULXZ7.js.map} +1 -1
  121. package/dist/{workflow-proposals-MTUDX46O.js → workflow-proposals-XXEZICN2.js} +5 -6
  122. package/dist/workflow-proposals-XXEZICN2.js.map +1 -0
  123. package/package.json +2 -1
  124. package/dist/chunk-4PNOV7OV.js.map +0 -1
  125. package/dist/chunk-A4OFTUVV.js.map +0 -1
  126. package/dist/chunk-B2VISN2V.js.map +0 -1
  127. package/dist/chunk-GKY2KXO5.js.map +0 -1
  128. package/dist/chunk-JICSYFRJ.js +0 -46
  129. package/dist/chunk-JICSYFRJ.js.map +0 -1
  130. package/dist/chunk-QFDOWABX.js.map +0 -1
  131. package/dist/chunk-SJJW77WN.js.map +0 -1
  132. package/dist/chunk-WOHL4FTB.js.map +0 -1
  133. package/dist/chunk-ZD3KHESI.js.map +0 -1
  134. package/dist/credential-COLTBV6D.js.map +0 -1
  135. package/dist/credential-template-EEPYFG7R.js.map +0 -1
  136. package/dist/docs-3SSORHB5.js.map +0 -1
  137. package/dist/doctor-OTSIWV6G.js.map +0 -1
  138. package/dist/feature-flag-T2LRZME3.js.map +0 -1
  139. package/dist/knobs-NBINZIUB.js.map +0 -1
  140. package/dist/mcp-54IJEOUA.js.map +0 -1
  141. package/dist/property-UXLOLPTD.js.map +0 -1
  142. package/dist/record-4TR2UIIS.js.map +0 -1
  143. package/dist/redis-35VBUYW7.js.map +0 -1
  144. package/dist/sandbox-XGSUU6G7.js.map +0 -1
  145. package/dist/session-MYFNZPRP.js.map +0 -1
  146. package/dist/skill-KM34LDMO.js.map +0 -1
  147. package/dist/spec-RA3CFEKG.js.map +0 -1
  148. package/dist/src-LB4HBTJQ.js.map +0 -1
  149. package/dist/trace-HXIW7U2D.js +0 -14
  150. package/dist/workflow-XYFH5LTP.js.map +0 -1
  151. package/dist/workflow-cache-NQJQFWMV.js.map +0 -1
  152. package/dist/workflow-proposals-MTUDX46O.js.map +0 -1
  153. /package/dist/{auth-EN6NQCJY.js.map → auth-VQG2CDUD.js.map} +0 -0
  154. /package/dist/{chunk-N7HFALX3.js.map → chunk-46IUJXSD.js.map} +0 -0
  155. /package/dist/{chunk-XQXVG7RA.js.map → chunk-FNPMWDUQ.js.map} +0 -0
  156. /package/dist/{pdf-extract-ABWV3L5X.js.map → chunk-G4UYGRZR.js.map} +0 -0
  157. /package/dist/{chunk-I4QLI3JO.js.map → chunk-HDFYUFBI.js.map} +0 -0
  158. /package/dist/{chunk-CLAWT7BJ.js.map → chunk-NHTEKEYE.js.map} +0 -0
  159. /package/dist/{chunk-Q4BO4Z5V.js.map → chunk-XJ5YYYGC.js.map} +0 -0
  160. /package/dist/{install-DXSNWZKO.js.map → install-OJFXHY6U.js.map} +0 -0
  161. /package/dist/{src-N3TPKGTY.js.map → pdf-extract-YHE54XU4.js.map} +0 -0
  162. /package/dist/{src-UVDX5UP6.js.map → src-CG52HEE7.js.map} +0 -0
  163. /package/dist/{tag-YY6YAABQ.js.map → src-PK5OZXCM.js.map} +0 -0
  164. /package/dist/{trace-HXIW7U2D.js.map → tag-JSHOMLBR.js.map} +0 -0
  165. /package/dist/{triage-ORG45R5W.js.map → trace-UMLOSIIR.js.map} +0 -0
  166. /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-SJJW77WN.js";
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
- status: z.enum(["draft", "published"]).optional(),
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("warn"),
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
- severity: z.enum(["warn", "fail"]).default("fail"),
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
- const role = trimmed.startsWith("template ") ? trimmed.slice("template ".length).trim() : trimmed;
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 ?? "warn",
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+(?:"([^"]+)"|([A-Za-z0-9_-]+))\s*(?:\(([^)]+)\))?\s*:\s*(.+)$/i.exec(b);
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: fieldM[1] ?? fieldM[2],
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 === "fail");
928
- if (n.kind === "assertion") return n.severity === "fail";
929
- if (n.kind === "audioAssertion") return n.severity === "fail";
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:\` or a field.`,
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
- for (const n of ast.journey) emitNode(n, nodes);
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(n.pageUrl)}`,
1229
- description: n.description ?? `Navigate to ${n.pageUrl}`,
1230
- pageUrl: n.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 ? { naturalLanguage: { prompt: n.prompt, ...n.model ? { model: n.model } : {} } } : {},
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 = [...(live.tags ?? []).map((t) => t.name)].sort();
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 === "quarantined") {
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
- return expr.includes("\n") ? ["**If**", blockquote(expr)] : [`**If ${expr}**`];
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-B2VISN2V.js.map
2629
+ //# sourceMappingURL=chunk-7VMO2WOZ.js.map