lua-cli 3.32.2 → 3.32.3

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.
@@ -1709,6 +1709,79 @@ var WORKFLOW_RETRY_BACKOFFS = [
1709
1709
  "fixed",
1710
1710
  "exponential"
1711
1711
  ];
1712
+ var WORKFLOW_RETRY_MIN_ATTEMPTS = 1;
1713
+ var WORKFLOW_RETRY_POLICY_KEYS = [
1714
+ "maxAttempts",
1715
+ "backoffSeconds",
1716
+ "backoff",
1717
+ "maxBackoffSeconds"
1718
+ ];
1719
+ var WORKFLOW_RETRY_MAX_ATTEMPTS = 20;
1720
+ function workflowRetryMaxAttemptsMessage(got) {
1721
+ const tail = got === void 0 ? "" : ` (got ${JSON.stringify(got)})`;
1722
+ return `\`retry.maxAttempts\` must be an integer ${WORKFLOW_RETRY_MIN_ATTEMPTS}..${WORKFLOW_RETRY_MAX_ATTEMPTS}${tail}`;
1723
+ }
1724
+ __name(workflowRetryMaxAttemptsMessage, "workflowRetryMaxAttemptsMessage");
1725
+ __name2(workflowRetryMaxAttemptsMessage, "workflowRetryMaxAttemptsMessage");
1726
+ function isWithinWorkflowRetryAttempts(value3) {
1727
+ return typeof value3 === "number" && Number.isInteger(value3) && value3 >= WORKFLOW_RETRY_MIN_ATTEMPTS && value3 <= WORKFLOW_RETRY_MAX_ATTEMPTS;
1728
+ }
1729
+ __name(isWithinWorkflowRetryAttempts, "isWithinWorkflowRetryAttempts");
1730
+ __name2(isWithinWorkflowRetryAttempts, "isWithinWorkflowRetryAttempts");
1731
+ var WORKFLOW_RETRY_ENGINE_KEYS = [
1732
+ "budgetBaseAttempt"
1733
+ ];
1734
+ function workflowRetryUnknownMembersMessage(keys) {
1735
+ const named = keys.map((k) => {
1736
+ const engine = WORKFLOW_RETRY_ENGINE_KEYS.includes(k);
1737
+ return `\`${k}\`${engine ? " (engine-owned \u2014 stamped by resetAttempts, never authored)" : ""}`;
1738
+ });
1739
+ return `\`retry\` has no member ${named.join(", ")}; members: ${WORKFLOW_RETRY_POLICY_KEYS.join(", ")}`;
1740
+ }
1741
+ __name(workflowRetryUnknownMembersMessage, "workflowRetryUnknownMembersMessage");
1742
+ __name2(workflowRetryUnknownMembersMessage, "workflowRetryUnknownMembersMessage");
1743
+ function unknownWorkflowRetryMembers(retry) {
1744
+ if (!retry || typeof retry !== "object" || Array.isArray(retry)) return [];
1745
+ return Object.keys(retry).filter((k) => !WORKFLOW_RETRY_POLICY_KEYS.includes(k));
1746
+ }
1747
+ __name(unknownWorkflowRetryMembers, "unknownWorkflowRetryMembers");
1748
+ __name2(unknownWorkflowRetryMembers, "unknownWorkflowRetryMembers");
1749
+ function authoredRetryPolicy(retry) {
1750
+ if (!retry || typeof retry !== "object" || Array.isArray(retry)) return void 0;
1751
+ const src = retry;
1752
+ const out = {};
1753
+ for (const k of WORKFLOW_RETRY_POLICY_KEYS) if (src[k] !== void 0) out[k] = src[k];
1754
+ return Object.keys(out).length ? out : void 0;
1755
+ }
1756
+ __name(authoredRetryPolicy, "authoredRetryPolicy");
1757
+ __name2(authoredRetryPolicy, "authoredRetryPolicy");
1758
+ function retryBudgetBaseAttempt(row) {
1759
+ const base = row.retry?.budgetBaseAttempt;
1760
+ return typeof base === "number" && Number.isSafeInteger(base) && base > 0 ? base : 0;
1761
+ }
1762
+ __name(retryBudgetBaseAttempt, "retryBudgetBaseAttempt");
1763
+ __name2(retryBudgetBaseAttempt, "retryBudgetBaseAttempt");
1764
+ function retryBudgetAttempt(row) {
1765
+ return Math.max(0, row.attempt - retryBudgetBaseAttempt(row));
1766
+ }
1767
+ __name(retryBudgetAttempt, "retryBudgetAttempt");
1768
+ __name2(retryBudgetAttempt, "retryBudgetAttempt");
1769
+ function retryBudgetMaxAttempts(row) {
1770
+ const max = row.retry?.maxAttempts;
1771
+ return typeof max === "number" && Number.isFinite(max) && max >= 1 ? max : 1;
1772
+ }
1773
+ __name(retryBudgetMaxAttempts, "retryBudgetMaxAttempts");
1774
+ __name2(retryBudgetMaxAttempts, "retryBudgetMaxAttempts");
1775
+ function retryBudgetRemaining(row) {
1776
+ return retryBudgetAttempt(row) < retryBudgetMaxAttempts(row);
1777
+ }
1778
+ __name(retryBudgetRemaining, "retryBudgetRemaining");
1779
+ __name2(retryBudgetRemaining, "retryBudgetRemaining");
1780
+ function retriesRemaining(row) {
1781
+ return Math.max(0, retryBudgetMaxAttempts(row) - retryBudgetAttempt(row));
1782
+ }
1783
+ __name(retriesRemaining, "retriesRemaining");
1784
+ __name2(retriesRemaining, "retriesRemaining");
1712
1785
  var WORKFLOW_JOB_RESOURCES = [
1713
1786
  "small",
1714
1787
  "medium",
@@ -2074,6 +2147,8 @@ var WORKFLOW_AUDIT_EVENTS = [
2074
2147
  "workflow.goal.resumed",
2075
2148
  "workflow.goal.done",
2076
2149
  "workflow.goal.closed",
2150
+ // LUA-760: an ended goal's cadence Job retired (deleted) — inline on done / closed, by R21 / R28, or by sweep #30
2151
+ "workflow.goal.job_retired",
2077
2152
  // --- org policy (02 §2.10 / 09 R23) ---
2078
2153
  "workflow.policy.retention_changed",
2079
2154
  "workflow.policy.pacing_changed",
@@ -2217,6 +2292,138 @@ ${items.join("\n\n")}`;
2217
2292
  }
2218
2293
  __name(renderTargetsBlock, "renderTargetsBlock");
2219
2294
  __name2(renderTargetsBlock, "renderTargetsBlock");
2295
+ var WORKFLOW_APPROVAL_OUTPUT_DECISIONS = [
2296
+ "approved",
2297
+ "denied",
2298
+ "timed_out"
2299
+ ];
2300
+ var WORKFLOW_APPROVAL_OUTPUT_SCHEMA = {
2301
+ type: "object",
2302
+ properties: {
2303
+ approved: {
2304
+ type: "boolean"
2305
+ },
2306
+ decision: {
2307
+ type: "string",
2308
+ enum: [
2309
+ ...WORKFLOW_APPROVAL_OUTPUT_DECISIONS
2310
+ ]
2311
+ },
2312
+ /** the approver's note when given, else the decision word — what `${stepResults.<id>.text}` reads */
2313
+ text: {
2314
+ type: "string"
2315
+ },
2316
+ note: {
2317
+ type: "string"
2318
+ },
2319
+ editedPayload: {},
2320
+ editRevision: {
2321
+ type: "integer"
2322
+ },
2323
+ decidedBy: {
2324
+ type: "object",
2325
+ properties: {
2326
+ id: {
2327
+ type: "string"
2328
+ },
2329
+ kind: {
2330
+ type: "string"
2331
+ }
2332
+ }
2333
+ },
2334
+ timedOut: {
2335
+ type: "boolean"
2336
+ },
2337
+ escalations: {
2338
+ type: "integer"
2339
+ },
2340
+ evidence: {
2341
+ type: "array",
2342
+ items: {
2343
+ type: "string"
2344
+ }
2345
+ },
2346
+ items: {
2347
+ type: "array",
2348
+ items: {
2349
+ type: "object"
2350
+ }
2351
+ }
2352
+ },
2353
+ required: [
2354
+ "approved",
2355
+ "decision",
2356
+ "text"
2357
+ ]
2358
+ };
2359
+ function workflowApprovalDecisionOf(resumeData) {
2360
+ if (resumeData.timedOut === true) return "timed_out";
2361
+ return resumeData.approved === true ? "approved" : "denied";
2362
+ }
2363
+ __name(workflowApprovalDecisionOf, "workflowApprovalDecisionOf");
2364
+ __name2(workflowApprovalDecisionOf, "workflowApprovalDecisionOf");
2365
+ function workflowApprovalOutput(resumeData) {
2366
+ const decision = typeof resumeData.decision === "string" ? resumeData.decision : workflowApprovalDecisionOf(resumeData);
2367
+ const note = typeof resumeData.note === "string" && resumeData.note.trim() !== "" ? resumeData.note : void 0;
2368
+ const text = typeof resumeData.text === "string" ? resumeData.text : note ?? decision;
2369
+ return {
2370
+ ...resumeData,
2371
+ decision,
2372
+ text
2373
+ };
2374
+ }
2375
+ __name(workflowApprovalOutput, "workflowApprovalOutput");
2376
+ __name2(workflowApprovalOutput, "workflowApprovalOutput");
2377
+ function isWorkflowApprovalOutput(value3) {
2378
+ if (typeof value3 !== "object" || value3 === null || Array.isArray(value3)) return false;
2379
+ const v = value3;
2380
+ return typeof v.approved === "boolean" && WORKFLOW_APPROVAL_OUTPUT_DECISIONS.includes(v.decision) && typeof v.text === "string";
2381
+ }
2382
+ __name(isWorkflowApprovalOutput, "isWorkflowApprovalOutput");
2383
+ __name2(isWorkflowApprovalOutput, "isWorkflowApprovalOutput");
2384
+ var JSON_FENCE_RE = /```(?:json)?[ \t]*\r?\n([\s\S]*?)\r?\n?```/g;
2385
+ function extractSingleJsonValue(text) {
2386
+ const trimmed = (text ?? "").trim();
2387
+ if (!trimmed) return {
2388
+ reason: "reply is empty"
2389
+ };
2390
+ const fenced = [
2391
+ ...trimmed.matchAll(JSON_FENCE_RE)
2392
+ ];
2393
+ if (fenced.length > 1) return {
2394
+ reason: "reply carries more than one fenced block"
2395
+ };
2396
+ const candidate = fenced.length === 1 ? fenced[0][1].trim() : trimmed;
2397
+ try {
2398
+ return {
2399
+ value: JSON.parse(candidate)
2400
+ };
2401
+ } catch {
2402
+ if (fenced.length === 1) return {
2403
+ reason: "fenced block is not valid JSON"
2404
+ };
2405
+ }
2406
+ const opens = [
2407
+ trimmed.indexOf("{"),
2408
+ trimmed.indexOf("[")
2409
+ ].filter((i) => i !== -1);
2410
+ const start = opens.length ? Math.min(...opens) : -1;
2411
+ const end = Math.max(trimmed.lastIndexOf("}"), trimmed.lastIndexOf("]"));
2412
+ if (start === -1 || end <= start) return {
2413
+ reason: "reply is not JSON"
2414
+ };
2415
+ try {
2416
+ return {
2417
+ value: JSON.parse(trimmed.slice(start, end + 1))
2418
+ };
2419
+ } catch {
2420
+ return {
2421
+ reason: "reply does not contain a single JSON value"
2422
+ };
2423
+ }
2424
+ }
2425
+ __name(extractSingleJsonValue, "extractSingleJsonValue");
2426
+ __name2(extractSingleJsonValue, "extractSingleJsonValue");
2220
2427
 
2221
2428
  // ../workflow-graph/dist/index.mjs
2222
2429
  import { createHash } from "crypto";
@@ -2225,6 +2432,296 @@ import { z as z22 } from "zod";
2225
2432
  import { createHash as createHash2 } from "crypto";
2226
2433
  var __defProp3 = Object.defineProperty;
2227
2434
  var __name3 = /* @__PURE__ */ __name((target, value22) => __defProp3(target, "name", { value: value22, configurable: true }), "__name");
2435
+ var WorkflowTemplateError = class extends Error {
2436
+ static {
2437
+ __name(this, "WorkflowTemplateError");
2438
+ }
2439
+ static {
2440
+ __name3(this, "WorkflowTemplateError");
2441
+ }
2442
+ placeholder;
2443
+ constructor(message, placeholder) {
2444
+ super(message), this.placeholder = placeholder;
2445
+ this.name = "WorkflowTemplateError";
2446
+ }
2447
+ };
2448
+ function isMapConfigObject(v) {
2449
+ return typeof v === "object" && v !== null && !Array.isArray(v);
2450
+ }
2451
+ __name(isMapConfigObject, "isMapConfigObject");
2452
+ __name3(isMapConfigObject, "isMapConfigObject");
2453
+ function parseMapConfig(raw, stepId) {
2454
+ if (isMapConfigObject(raw)) return raw;
2455
+ if (typeof raw !== "string") {
2456
+ throw new Error(`Stored mapping step "${stepId}" has a mapConfig that is neither a JSON string nor an object.`);
2457
+ }
2458
+ try {
2459
+ return JSON.parse(raw);
2460
+ } catch (e) {
2461
+ throw new Error(`Stored mapping step "${stepId}" has invalid JSON mapConfig: ${e.message}`);
2462
+ }
2463
+ }
2464
+ __name(parseMapConfig, "parseMapConfig");
2465
+ __name3(parseMapConfig, "parseMapConfig");
2466
+ function mapConfigWire(raw) {
2467
+ if (typeof raw === "string") return raw;
2468
+ if (isMapConfigObject(raw)) return canonicalJson(raw);
2469
+ return void 0;
2470
+ }
2471
+ __name(mapConfigWire, "mapConfigWire");
2472
+ __name3(mapConfigWire, "mapConfigWire");
2473
+ var TEMPLATE_PLACEHOLDER = /\$\{([^}]*)\}/g;
2474
+ var TEMPLATE_NAMESPACES = [
2475
+ "initData",
2476
+ "state",
2477
+ "requestContext",
2478
+ "stepResults"
2479
+ ];
2480
+ function describeBadPlaceholder(template22, idx, rawExpr) {
2481
+ return `Template placeholder #${idx} (\${${rawExpr}}) in '${template22}'`;
2482
+ }
2483
+ __name(describeBadPlaceholder, "describeBadPlaceholder");
2484
+ __name3(describeBadPlaceholder, "describeBadPlaceholder");
2485
+ function parseTemplatePlaceholder(rawExpr) {
2486
+ const dot = rawExpr.indexOf(".");
2487
+ return {
2488
+ scope: dot === -1 ? rawExpr : rawExpr.slice(0, dot),
2489
+ rest: dot === -1 ? "" : rawExpr.slice(dot + 1)
2490
+ };
2491
+ }
2492
+ __name(parseTemplatePlaceholder, "parseTemplatePlaceholder");
2493
+ __name3(parseTemplatePlaceholder, "parseTemplatePlaceholder");
2494
+ function traverseMappingPath(root, path, errorLabel) {
2495
+ if (path === "" || path === ".") return root;
2496
+ const parts = path.split(".");
2497
+ let value22 = root;
2498
+ for (const part of parts) {
2499
+ if (typeof value22 === "object" && value22 !== null) value22 = value22[part];
2500
+ else throw new WorkflowTemplateError(`Invalid path ${path} in ${errorLabel}`, path);
2501
+ }
2502
+ return value22;
2503
+ }
2504
+ __name(traverseMappingPath, "traverseMappingPath");
2505
+ __name3(traverseMappingPath, "traverseMappingPath");
2506
+ function stringifyTemplateValue(v, template22, idx, rawExpr) {
2507
+ if (v === null || v === void 0) return "";
2508
+ if (typeof v === "object") {
2509
+ try {
2510
+ return JSON.stringify(v);
2511
+ } catch (err) {
2512
+ throw new WorkflowTemplateError(`${describeBadPlaceholder(template22, idx, rawExpr)} resolved to a value that could not be JSON-stringified (${err.message}).`, rawExpr);
2513
+ }
2514
+ }
2515
+ return String(v);
2516
+ }
2517
+ __name(stringifyTemplateValue, "stringifyTemplateValue");
2518
+ __name3(stringifyTemplateValue, "stringifyTemplateValue");
2519
+ function escapeFence(content) {
2520
+ return content.replace(/<\/lua-data/g, "<\\/lua-data");
2521
+ }
2522
+ __name(escapeFence, "escapeFence");
2523
+ __name3(escapeFence, "escapeFence");
2524
+ function fenceBlock(name, source, content) {
2525
+ return `<lua-data name="${name}" source="${source}" untrusted="true">${escapeFence(content)}</lua-data>`;
2526
+ }
2527
+ __name(fenceBlock, "fenceBlock");
2528
+ __name3(fenceBlock, "fenceBlock");
2529
+ function renderTemplate(template22, ctx, opts) {
2530
+ let idx = 0;
2531
+ return template22.replace(TEMPLATE_PLACEHOLDER, (_match, rawExpr) => {
2532
+ idx += 1;
2533
+ const { scope, rest } = parseTemplatePlaceholder(rawExpr);
2534
+ const label = describeBadPlaceholder(template22, idx, rawExpr);
2535
+ let rendered;
2536
+ let source;
2537
+ switch (scope) {
2538
+ case "initData":
2539
+ rendered = stringifyTemplateValue(traverseMappingPath(ctx.initData, rest, label), template22, idx, rawExpr);
2540
+ source = "initData";
2541
+ break;
2542
+ case "state":
2543
+ rendered = stringifyTemplateValue(traverseMappingPath(ctx.state, rest, label), template22, idx, rawExpr);
2544
+ source = "state";
2545
+ break;
2546
+ case "requestContext":
2547
+ rendered = stringifyTemplateValue(traverseMappingPath(ctx.requestContext, rest, label), template22, idx, rawExpr);
2548
+ source = "requestContext";
2549
+ break;
2550
+ case "stepResults": {
2551
+ const innerDot = rest.indexOf(".");
2552
+ const stepId = innerDot === -1 ? rest : rest.slice(0, innerDot);
2553
+ const subPath = innerDot === -1 ? "" : rest.slice(innerDot + 1);
2554
+ if (!stepId) throw new WorkflowTemplateError(`${label} must name a step: \${stepResults.<stepId>.<path>}.`, rawExpr);
2555
+ if (!(stepId in ctx.stepResults) || ctx.stepResults[stepId] == null) {
2556
+ throw new WorkflowTemplateError(`${label} references stepResults.${stepId} but step "${stepId}" has no resolvable output (not an ancestor, not run, failed, or produced no output).`, rawExpr);
2557
+ }
2558
+ rendered = stringifyTemplateValue(traverseMappingPath(ctx.stepResults[stepId], subPath, label), template22, idx, rawExpr);
2559
+ source = `step:${stepId}`;
2560
+ break;
2561
+ }
2562
+ default:
2563
+ throw new WorkflowTemplateError(`${label} references unknown namespace "${scope}". Use one of: ${TEMPLATE_NAMESPACES.join(", ")}.`, rawExpr);
2564
+ }
2565
+ return opts.fenced ? fenceBlock(rawExpr, source, rendered) : rendered;
2566
+ });
2567
+ }
2568
+ __name(renderTemplate, "renderTemplate");
2569
+ __name3(renderTemplate, "renderTemplate");
2570
+ function isMapDescriptor(v) {
2571
+ if (v === null || typeof v !== "object" || Array.isArray(v)) return false;
2572
+ const d = v;
2573
+ const keys = Object.keys(d);
2574
+ const only = /* @__PURE__ */ __name3((...allowed) => keys.every((k) => allowed.includes(k)), "only");
2575
+ if ("value" in d) return keys.length === 1;
2576
+ if ("template" in d) return keys.length === 1 && typeof d.template === "string";
2577
+ if ("requestContextPath" in d) return keys.length === 1 && typeof d.requestContextPath === "string";
2578
+ if ("knowledge" in d) return keys.length === 1 && typeof d.knowledge === "object" && d.knowledge !== null;
2579
+ if ("initData" in d) return d.initData === true && typeof d.path === "string" && only("initData", "path");
2580
+ if ("step" in d) {
2581
+ const stepOk = typeof d.step === "string" || Array.isArray(d.step) && d.step.every((x) => typeof x === "string");
2582
+ return stepOk && typeof d.path === "string" && only("step", "path", "rows");
2583
+ }
2584
+ return false;
2585
+ }
2586
+ __name(isMapDescriptor, "isMapDescriptor");
2587
+ __name3(isMapDescriptor, "isMapDescriptor");
2588
+ var MAP_DESCRIPTOR_KEYS = [
2589
+ "step",
2590
+ "path",
2591
+ "initData",
2592
+ "value",
2593
+ "template",
2594
+ "requestContextPath",
2595
+ "knowledge"
2596
+ ];
2597
+ var MAP_MEMBER_MALFORMED_CODE = "map-member-malformed";
2598
+ function malformedMapMembers(cfg) {
2599
+ if (!cfg || typeof cfg !== "object" || Array.isArray(cfg)) return [];
2600
+ const out = [];
2601
+ for (const [member, v] of Object.entries(cfg)) {
2602
+ if (!v || typeof v !== "object" || Array.isArray(v) || isMapDescriptor(v)) continue;
2603
+ const keys = Object.keys(v).filter((k) => MAP_DESCRIPTOR_KEYS.includes(k));
2604
+ if (keys.length > 0) out.push({
2605
+ member,
2606
+ keys
2607
+ });
2608
+ }
2609
+ return out;
2610
+ }
2611
+ __name(malformedMapMembers, "malformedMapMembers");
2612
+ __name3(malformedMapMembers, "malformedMapMembers");
2613
+ function mapMemberMalformedMessage(id, m) {
2614
+ const keys = m.keys.map((k) => `\`${k}\``).join(", ");
2615
+ return `"${id}".${m.member} carries descriptor key${m.keys.length === 1 ? "" : "s"} ${keys} but is not an exact binding form ({initData:true, path} | {step, path[, rows]} | {value} | {template} | {requestContextPath} | {knowledge}) \u2014 it is passed to the step verbatim as a literal; fix the descriptor, or wrap it in {value: \u2026} if the literal is intended`;
2616
+ }
2617
+ __name(mapMemberMalformedMessage, "mapMemberMalformedMessage");
2618
+ __name3(mapMemberMalformedMessage, "mapMemberMalformedMessage");
2619
+ function resolveDescriptor(key, m, ctx) {
2620
+ if (!isMapDescriptor(m)) return {
2621
+ value: m
2622
+ };
2623
+ try {
2624
+ if ("value" in m) return {
2625
+ value: m.value
2626
+ };
2627
+ if ("template" in m && typeof m.template === "string") {
2628
+ return {
2629
+ value: renderTemplate(m.template, ctx, {
2630
+ fenced: false
2631
+ })
2632
+ };
2633
+ }
2634
+ if ("knowledge" in m || "rows" in m && m.rows !== void 0) {
2635
+ return {
2636
+ error: "binding_unresolved",
2637
+ key
2638
+ };
2639
+ }
2640
+ if ("requestContextPath" in m) {
2641
+ const label = `requestContext path for key "${key}"`;
2642
+ return {
2643
+ value: traverseMappingPath(ctx.requestContext, m.requestContextPath, label)
2644
+ };
2645
+ }
2646
+ if ("path" in m) {
2647
+ const source = "initData" in m && m.initData ? "initData" : "step";
2648
+ if (source === "initData") {
2649
+ return {
2650
+ value: traverseMappingPath(ctx.initData, m.path, `initData for key "${key}"`)
2651
+ };
2652
+ }
2653
+ const stepRef = m.step;
2654
+ const candidates = Array.isArray(stepRef) ? stepRef : [
2655
+ stepRef
2656
+ ];
2657
+ const stepId = candidates.find((s) => ctx.stepResults[s] !== void 0 && ctx.stepResults[s] !== null);
2658
+ if (stepId === void 0) return {
2659
+ error: "binding_unresolved",
2660
+ key
2661
+ };
2662
+ return {
2663
+ value: traverseMappingPath(ctx.stepResults[stepId], m.path, `step ${candidates.join("|")} for key "${key}"`)
2664
+ };
2665
+ }
2666
+ return {
2667
+ error: "binding_unresolved",
2668
+ key
2669
+ };
2670
+ } catch (err) {
2671
+ if (err instanceof WorkflowTemplateError) return {
2672
+ error: "binding_unresolved",
2673
+ key
2674
+ };
2675
+ throw err;
2676
+ }
2677
+ }
2678
+ __name(resolveDescriptor, "resolveDescriptor");
2679
+ __name3(resolveDescriptor, "resolveDescriptor");
2680
+ function resolveMapping(cfg, ctx) {
2681
+ const keys = Object.keys(cfg);
2682
+ if (keys.length === 1 && keys[0] === "") {
2683
+ return resolveDescriptor("", cfg[""], ctx);
2684
+ }
2685
+ const result = {};
2686
+ for (const key of keys) {
2687
+ const resolved = resolveDescriptor(key, cfg[key], ctx);
2688
+ if ("error" in resolved) return resolved;
2689
+ result[key] = resolved.value;
2690
+ }
2691
+ return {
2692
+ value: result
2693
+ };
2694
+ }
2695
+ __name(resolveMapping, "resolveMapping");
2696
+ __name3(resolveMapping, "resolveMapping");
2697
+ var fromInit = /* @__PURE__ */ __name3((path) => ({
2698
+ initData: true,
2699
+ path
2700
+ }), "fromInit");
2701
+ var fromStep = /* @__PURE__ */ __name3((s, path = "") => {
2702
+ const idOf = /* @__PURE__ */ __name3((x) => typeof x === "string" ? x : x.id, "idOf");
2703
+ return {
2704
+ step: Array.isArray(s) ? s.map(idOf) : idOf(s),
2705
+ path
2706
+ };
2707
+ }, "fromStep");
2708
+ var value = /* @__PURE__ */ __name3((v) => ({
2709
+ value: v
2710
+ }), "value");
2711
+ var template = /* @__PURE__ */ __name3((s) => ({
2712
+ template: s
2713
+ }), "template");
2714
+ var fromRequest = /* @__PURE__ */ __name3((path) => ({
2715
+ requestContextPath: path
2716
+ }), "fromRequest");
2717
+ var rows = /* @__PURE__ */ __name3((s, path, page) => ({
2718
+ step: typeof s === "string" ? s : s.id,
2719
+ path,
2720
+ rows: page
2721
+ }), "rows");
2722
+ var fromKnowledge = /* @__PURE__ */ __name3((k) => ({
2723
+ knowledge: k
2724
+ }), "fromKnowledge");
2228
2725
  var SideEffectsSchema = z4.enum(WORKFLOW_SIDE_EFFECTS);
2229
2726
  var JobResourcesSchema = z4.enum(WORKFLOW_JOB_RESOURCES);
2230
2727
  var WORKFLOW_ARM_SUBRUN_ID = "$arm";
@@ -2482,12 +2979,11 @@ function mapConfigStepRefs(raw) {
2482
2979
  if (!cfg) return [];
2483
2980
  const ids = [];
2484
2981
  for (const d of Object.values(cfg)) {
2485
- if (!d || typeof d !== "object") continue;
2486
- const desc = d;
2487
- if (desc.step !== void 0) ids.push(...Array.isArray(desc.step) ? desc.step : [
2488
- desc.step
2982
+ if (!isMapDescriptor(d)) continue;
2983
+ if ("step" in d) ids.push(...Array.isArray(d.step) ? d.step : [
2984
+ d.step
2489
2985
  ]);
2490
- if (typeof desc.template === "string") ids.push(...templateStepRefs(desc.template));
2986
+ if ("template" in d) ids.push(...templateStepRefs(d.template));
2491
2987
  }
2492
2988
  return ids;
2493
2989
  }
@@ -2616,6 +3112,12 @@ function validateLuaExtensions(g, caps = WORKFLOW_CAPS_DEFAULT, opts = {
2616
3112
  const r = node.retry;
2617
3113
  if (!r) return;
2618
3114
  const id = singleId(node);
3115
+ const unknown = unknownWorkflowRetryMembers(r);
3116
+ if (unknown.length) err("invalid-envelope", workflowRetryUnknownMembersMessage(unknown), `${path}.retry`, id);
3117
+ if (r.maxAttempts !== void 0 && !isWithinWorkflowRetryAttempts(r.maxAttempts)) {
3118
+ const over = typeof r.maxAttempts === "number" && r.maxAttempts > WORKFLOW_RETRY_MAX_ATTEMPTS;
3119
+ err(over ? "cap-exceeded" : "invalid-envelope", workflowRetryMaxAttemptsMessage(r.maxAttempts), `${path}.retry.maxAttempts`, id);
3120
+ }
2619
3121
  const backoffs = retryBackoffs();
2620
3122
  if (r.backoff !== void 0 && !backoffs.includes(r.backoff)) {
2621
3123
  const list = backoffs.map((b) => `'${b}'`).join(" | ");
@@ -2758,6 +3260,21 @@ function validateLuaExtensions(g, caps = WORKFLOW_CAPS_DEFAULT, opts = {
2758
3260
  const schema = node.type === "step" ? node.step.outputSchema : node.type === "agent" ? node.outputSchema : void 0;
2759
3261
  if (schema !== void 0) outputSchemas.set(singleId(node), schema);
2760
3262
  }, "recordOutputSchema");
3263
+ const checkMapMembers = /* @__PURE__ */ __name3((cfg, basePath, id) => {
3264
+ for (const m of malformedMapMembers(cfg)) {
3265
+ warn(MAP_MEMBER_MALFORMED_CODE, mapMemberMalformedMessage(id, m), `${basePath}.${m.member}`, id);
3266
+ }
3267
+ }, "checkMapMembers");
3268
+ const checkInputShape = /* @__PURE__ */ __name3((node, path) => {
3269
+ if (node.type !== "tool" && node.type !== "workflow") return;
3270
+ const input = node.input;
3271
+ if (input === void 0) return;
3272
+ if (input !== null && typeof input === "object" && !Array.isArray(input)) {
3273
+ checkMapMembers(input, `${path}.input`, node.id);
3274
+ return;
3275
+ }
3276
+ err("invalid-envelope", `\`input\` must be an object map \u2014 each member a binding descriptor ({initData:true, path} | {step, path} | {value} | {template} | {requestContextPath}) or a JSON literal (got ${JSON.stringify(input)})`, `${path}.input`, node.id);
3277
+ }, "checkInputShape");
2761
3278
  const checkSingle = /* @__PURE__ */ __name3((node, path, depth) => {
2762
3279
  recordOutputSchema(node);
2763
3280
  if (node.type === "workflow" && node.workflowId === WORKFLOW_ARM_SUBRUN_ID) {
@@ -2785,6 +3302,7 @@ function validateLuaExtensions(g, caps = WORKFLOW_CAPS_DEFAULT, opts = {
2785
3302
  }
2786
3303
  checkId(singleId(node), path);
2787
3304
  checkPolicyEnums(node, path);
3305
+ checkInputShape(node, path);
2788
3306
  checkTimeout(node, path);
2789
3307
  checkTier(node, path);
2790
3308
  checkRetry(node, path);
@@ -2865,6 +3383,7 @@ function validateLuaExtensions(g, caps = WORKFLOW_CAPS_DEFAULT, opts = {
2865
3383
  const checkArm = /* @__PURE__ */ __name3((arm, path, depth, container) => {
2866
3384
  if (arm.type === "mapping") {
2867
3385
  checkId(arm.id, path);
3386
+ checkMapMembers(readMapConfig(arm.mapConfig), `${path}.mapConfig`, arm.id);
2868
3387
  for (const ref of nodeStepRefs(arm)) {
2869
3388
  if (!upstream.has(ref)) err("template-reference-unresolved", `"${arm.id}" references stepResults.${ref}, which is not upstream`, path, arm.id);
2870
3389
  }
@@ -2889,6 +3408,7 @@ function validateLuaExtensions(g, caps = WORKFLOW_CAPS_DEFAULT, opts = {
2889
3408
  break;
2890
3409
  case "mapping":
2891
3410
  checkId(entry.id, path);
3411
+ checkMapMembers(readMapConfig(entry.mapConfig), `${path}.mapConfig`, entry.id);
2892
3412
  for (const ref of nodeStepRefs(entry)) {
2893
3413
  if (!upstream.has(ref)) err("template-reference-unresolved", `"${entry.id}" references stepResults.${ref}, which is not upstream`, path, entry.id);
2894
3414
  }
@@ -3629,244 +4149,6 @@ var not = /* @__PURE__ */ __name3((arg) => ({
3629
4149
  op: "not",
3630
4150
  arg
3631
4151
  }), "not");
3632
- var WorkflowTemplateError = class extends Error {
3633
- static {
3634
- __name(this, "WorkflowTemplateError");
3635
- }
3636
- static {
3637
- __name3(this, "WorkflowTemplateError");
3638
- }
3639
- placeholder;
3640
- constructor(message, placeholder) {
3641
- super(message), this.placeholder = placeholder;
3642
- this.name = "WorkflowTemplateError";
3643
- }
3644
- };
3645
- function isMapConfigObject(v) {
3646
- return typeof v === "object" && v !== null && !Array.isArray(v);
3647
- }
3648
- __name(isMapConfigObject, "isMapConfigObject");
3649
- __name3(isMapConfigObject, "isMapConfigObject");
3650
- function parseMapConfig(raw, stepId) {
3651
- if (isMapConfigObject(raw)) return raw;
3652
- if (typeof raw !== "string") {
3653
- throw new Error(`Stored mapping step "${stepId}" has a mapConfig that is neither a JSON string nor an object.`);
3654
- }
3655
- try {
3656
- return JSON.parse(raw);
3657
- } catch (e) {
3658
- throw new Error(`Stored mapping step "${stepId}" has invalid JSON mapConfig: ${e.message}`);
3659
- }
3660
- }
3661
- __name(parseMapConfig, "parseMapConfig");
3662
- __name3(parseMapConfig, "parseMapConfig");
3663
- function mapConfigWire(raw) {
3664
- if (typeof raw === "string") return raw;
3665
- if (isMapConfigObject(raw)) return canonicalJson(raw);
3666
- return void 0;
3667
- }
3668
- __name(mapConfigWire, "mapConfigWire");
3669
- __name3(mapConfigWire, "mapConfigWire");
3670
- var TEMPLATE_PLACEHOLDER = /\$\{([^}]*)\}/g;
3671
- var TEMPLATE_NAMESPACES = [
3672
- "initData",
3673
- "state",
3674
- "requestContext",
3675
- "stepResults"
3676
- ];
3677
- function describeBadPlaceholder(template22, idx, rawExpr) {
3678
- return `Template placeholder #${idx} (\${${rawExpr}}) in '${template22}'`;
3679
- }
3680
- __name(describeBadPlaceholder, "describeBadPlaceholder");
3681
- __name3(describeBadPlaceholder, "describeBadPlaceholder");
3682
- function parseTemplatePlaceholder(rawExpr) {
3683
- const dot = rawExpr.indexOf(".");
3684
- return {
3685
- scope: dot === -1 ? rawExpr : rawExpr.slice(0, dot),
3686
- rest: dot === -1 ? "" : rawExpr.slice(dot + 1)
3687
- };
3688
- }
3689
- __name(parseTemplatePlaceholder, "parseTemplatePlaceholder");
3690
- __name3(parseTemplatePlaceholder, "parseTemplatePlaceholder");
3691
- function traverseMappingPath(root, path, errorLabel) {
3692
- if (path === "" || path === ".") return root;
3693
- const parts = path.split(".");
3694
- let value22 = root;
3695
- for (const part of parts) {
3696
- if (typeof value22 === "object" && value22 !== null) value22 = value22[part];
3697
- else throw new WorkflowTemplateError(`Invalid path ${path} in ${errorLabel}`, path);
3698
- }
3699
- return value22;
3700
- }
3701
- __name(traverseMappingPath, "traverseMappingPath");
3702
- __name3(traverseMappingPath, "traverseMappingPath");
3703
- function stringifyTemplateValue(v, template22, idx, rawExpr) {
3704
- if (v === null || v === void 0) return "";
3705
- if (typeof v === "object") {
3706
- try {
3707
- return JSON.stringify(v);
3708
- } catch (err) {
3709
- throw new WorkflowTemplateError(`${describeBadPlaceholder(template22, idx, rawExpr)} resolved to a value that could not be JSON-stringified (${err.message}).`, rawExpr);
3710
- }
3711
- }
3712
- return String(v);
3713
- }
3714
- __name(stringifyTemplateValue, "stringifyTemplateValue");
3715
- __name3(stringifyTemplateValue, "stringifyTemplateValue");
3716
- function escapeFence(content) {
3717
- return content.replace(/<\/lua-data/g, "<\\/lua-data");
3718
- }
3719
- __name(escapeFence, "escapeFence");
3720
- __name3(escapeFence, "escapeFence");
3721
- function fenceBlock(name, source, content) {
3722
- return `<lua-data name="${name}" source="${source}" untrusted="true">${escapeFence(content)}</lua-data>`;
3723
- }
3724
- __name(fenceBlock, "fenceBlock");
3725
- __name3(fenceBlock, "fenceBlock");
3726
- function renderTemplate(template22, ctx, opts) {
3727
- let idx = 0;
3728
- return template22.replace(TEMPLATE_PLACEHOLDER, (_match, rawExpr) => {
3729
- idx += 1;
3730
- const { scope, rest } = parseTemplatePlaceholder(rawExpr);
3731
- const label = describeBadPlaceholder(template22, idx, rawExpr);
3732
- let rendered;
3733
- let source;
3734
- switch (scope) {
3735
- case "initData":
3736
- rendered = stringifyTemplateValue(traverseMappingPath(ctx.initData, rest, label), template22, idx, rawExpr);
3737
- source = "initData";
3738
- break;
3739
- case "state":
3740
- rendered = stringifyTemplateValue(traverseMappingPath(ctx.state, rest, label), template22, idx, rawExpr);
3741
- source = "state";
3742
- break;
3743
- case "requestContext":
3744
- rendered = stringifyTemplateValue(traverseMappingPath(ctx.requestContext, rest, label), template22, idx, rawExpr);
3745
- source = "requestContext";
3746
- break;
3747
- case "stepResults": {
3748
- const innerDot = rest.indexOf(".");
3749
- const stepId = innerDot === -1 ? rest : rest.slice(0, innerDot);
3750
- const subPath = innerDot === -1 ? "" : rest.slice(innerDot + 1);
3751
- if (!stepId) throw new WorkflowTemplateError(`${label} must name a step: \${stepResults.<stepId>.<path>}.`, rawExpr);
3752
- if (!(stepId in ctx.stepResults) || ctx.stepResults[stepId] == null) {
3753
- throw new WorkflowTemplateError(`${label} references stepResults.${stepId} but step "${stepId}" has no resolvable output (not an ancestor, not run, failed, or produced no output).`, rawExpr);
3754
- }
3755
- rendered = stringifyTemplateValue(traverseMappingPath(ctx.stepResults[stepId], subPath, label), template22, idx, rawExpr);
3756
- source = `step:${stepId}`;
3757
- break;
3758
- }
3759
- default:
3760
- throw new WorkflowTemplateError(`${label} references unknown namespace "${scope}". Use one of: ${TEMPLATE_NAMESPACES.join(", ")}.`, rawExpr);
3761
- }
3762
- return opts.fenced ? fenceBlock(rawExpr, source, rendered) : rendered;
3763
- });
3764
- }
3765
- __name(renderTemplate, "renderTemplate");
3766
- __name3(renderTemplate, "renderTemplate");
3767
- function resolveDescriptor(key, m, ctx) {
3768
- try {
3769
- if ("value" in m) return {
3770
- value: m.value
3771
- };
3772
- if ("template" in m && typeof m.template === "string") {
3773
- return {
3774
- value: renderTemplate(m.template, ctx, {
3775
- fenced: false
3776
- })
3777
- };
3778
- }
3779
- if ("knowledge" in m || "rows" in m && m.rows !== void 0) {
3780
- return {
3781
- error: "binding_unresolved",
3782
- key
3783
- };
3784
- }
3785
- if ("requestContextPath" in m) {
3786
- const label = `requestContext path for key "${key}"`;
3787
- return {
3788
- value: traverseMappingPath(ctx.requestContext, m.requestContextPath, label)
3789
- };
3790
- }
3791
- if ("path" in m) {
3792
- const source = "initData" in m && m.initData ? "initData" : "step";
3793
- if (source === "initData") {
3794
- return {
3795
- value: traverseMappingPath(ctx.initData, m.path, `initData for key "${key}"`)
3796
- };
3797
- }
3798
- const stepRef = m.step;
3799
- const candidates = Array.isArray(stepRef) ? stepRef : [
3800
- stepRef
3801
- ];
3802
- const stepId = candidates.find((s) => ctx.stepResults[s] !== void 0 && ctx.stepResults[s] !== null);
3803
- if (stepId === void 0) return {
3804
- error: "binding_unresolved",
3805
- key
3806
- };
3807
- return {
3808
- value: traverseMappingPath(ctx.stepResults[stepId], m.path, `step ${candidates.join("|")} for key "${key}"`)
3809
- };
3810
- }
3811
- return {
3812
- error: "binding_unresolved",
3813
- key
3814
- };
3815
- } catch (err) {
3816
- if (err instanceof WorkflowTemplateError) return {
3817
- error: "binding_unresolved",
3818
- key
3819
- };
3820
- throw err;
3821
- }
3822
- }
3823
- __name(resolveDescriptor, "resolveDescriptor");
3824
- __name3(resolveDescriptor, "resolveDescriptor");
3825
- function resolveMapping(cfg, ctx) {
3826
- const keys = Object.keys(cfg);
3827
- if (keys.length === 1 && keys[0] === "") {
3828
- return resolveDescriptor("", cfg[""], ctx);
3829
- }
3830
- const result = {};
3831
- for (const key of keys) {
3832
- const resolved = resolveDescriptor(key, cfg[key], ctx);
3833
- if ("error" in resolved) return resolved;
3834
- result[key] = resolved.value;
3835
- }
3836
- return {
3837
- value: result
3838
- };
3839
- }
3840
- __name(resolveMapping, "resolveMapping");
3841
- __name3(resolveMapping, "resolveMapping");
3842
- var fromInit = /* @__PURE__ */ __name3((path) => ({
3843
- initData: true,
3844
- path
3845
- }), "fromInit");
3846
- var fromStep = /* @__PURE__ */ __name3((s, path = "") => {
3847
- const idOf = /* @__PURE__ */ __name3((x) => typeof x === "string" ? x : x.id, "idOf");
3848
- return {
3849
- step: Array.isArray(s) ? s.map(idOf) : idOf(s),
3850
- path
3851
- };
3852
- }, "fromStep");
3853
- var value = /* @__PURE__ */ __name3((v) => ({
3854
- value: v
3855
- }), "value");
3856
- var template = /* @__PURE__ */ __name3((s) => ({
3857
- template: s
3858
- }), "template");
3859
- var fromRequest = /* @__PURE__ */ __name3((path) => ({
3860
- requestContextPath: path
3861
- }), "fromRequest");
3862
- var rows = /* @__PURE__ */ __name3((s, path, page) => ({
3863
- step: typeof s === "string" ? s : s.id,
3864
- path,
3865
- rows: page
3866
- }), "rows");
3867
- var fromKnowledge = /* @__PURE__ */ __name3((k) => ({
3868
- knowledge: k
3869
- }), "fromKnowledge");
3870
4152
  var CONTINUED_FAILURE_TAG = "continued_failure";
3871
4153
  var CONTINUED_FAILURE_DEFAULT_CODE = "step_failed";
3872
4154
  var CONTINUED_FAILURE_OUTPUT_SCHEMA = Object.freeze({
@@ -4626,10 +4908,57 @@ function runCounts(counts) {
4626
4908
  }
4627
4909
  __name(runCounts, "runCounts");
4628
4910
  __name3(runCounts, "runCounts");
4629
- function runUsage(run) {
4911
+ function isPricedStepReceipt(receipt) {
4912
+ return typeof receipt?.multiplier === "number" && Number.isFinite(receipt.multiplier);
4913
+ }
4914
+ __name(isPricedStepReceipt, "isPricedStepReceipt");
4915
+ __name3(isPricedStepReceipt, "isPricedStepReceipt");
4916
+ function receiptEngine(engine) {
4917
+ if (engine === "actions") return "seat";
4918
+ if (engine === "credits") return "legacy";
4919
+ return void 0;
4920
+ }
4921
+ __name(receiptEngine, "receiptEngine");
4922
+ __name3(receiptEngine, "receiptEngine");
4923
+ function receiptTier(tier) {
4924
+ return tier === "light" || tier === "standard" || tier === "heavy" ? tier : void 0;
4925
+ }
4926
+ __name(receiptTier, "receiptTier");
4927
+ __name3(receiptTier, "receiptTier");
4928
+ function stepBillingView(receipt) {
4929
+ const engine = receiptEngine(receipt?.engine);
4930
+ if (!receipt || engine === void 0) return void 0;
4931
+ return pruneUndefined({
4932
+ engine,
4933
+ attempt: typeof receipt.attempt === "number" ? receipt.attempt : void 0,
4934
+ credits: typeof receipt.credits === "number" ? receipt.credits : void 0,
4935
+ actions: typeof receipt.actionsEstimate === "number" ? receipt.actionsEstimate : void 0,
4936
+ model: typeof receipt.model === "string" ? receipt.model : void 0,
4937
+ tier: receiptTier(receipt.tier),
4938
+ multiplier: typeof receipt.multiplier === "number" ? receipt.multiplier : void 0,
4939
+ byok: typeof receipt.byok === "boolean" ? receipt.byok : void 0,
4940
+ calibrated: typeof receipt.calibrated === "boolean" ? receipt.calibrated : void 0
4941
+ });
4942
+ }
4943
+ __name(stepBillingView, "stepBillingView");
4944
+ __name3(stepBillingView, "stepBillingView");
4945
+ function runUsage(run, receipts) {
4946
+ const actions = n(run.budget?.spent?.actionsEstimate);
4947
+ const stamped = run.budget?.engine;
4948
+ const priced = (receipts ?? []).filter(isPricedStepReceipt);
4949
+ const engine = stamped === "seat" || stamped === "legacy" ? stamped : actions > 0 || priced.some((r) => r.engine === "actions") ? "seat" : priced.some((r) => r.engine === "credits") ? "legacy" : void 0;
4950
+ const seat = engine === "seat";
4951
+ const metering = engine ? "priced" : "flat";
4630
4952
  return {
4631
4953
  creditsUsed: run.budget?.spent?.credits ?? 0,
4632
4954
  actionsEstimate: run.budget?.spent?.actionsEstimate ?? 0,
4955
+ ...seat ? {
4956
+ actionsUsed: actions
4957
+ } : {},
4958
+ metering,
4959
+ ...engine ? {
4960
+ engine
4961
+ } : {},
4633
4962
  steps: run.budget?.spent?.steps ?? 0,
4634
4963
  inputTokens: run.usage?.inputTokens ?? 0,
4635
4964
  outputTokens: run.usage?.outputTokens ?? 0
@@ -4637,6 +4966,20 @@ function runUsage(run) {
4637
4966
  }
4638
4967
  __name(runUsage, "runUsage");
4639
4968
  __name3(runUsage, "runUsage");
4969
+ function runBudgetCap(budget) {
4970
+ const cap = budget?.maxCredits;
4971
+ return typeof cap === "number" && Number.isFinite(cap) && cap > 0 ? cap : void 0;
4972
+ }
4973
+ __name(runBudgetCap, "runBudgetCap");
4974
+ __name3(runBudgetCap, "runBudgetCap");
4975
+ function runBudgetRemaining(budget) {
4976
+ const cap = runBudgetCap(budget);
4977
+ if (cap === void 0) return void 0;
4978
+ const spent = budget?.spent;
4979
+ return Math.max(0, cap - n(spent?.credits) - n(spent?.actionsEstimate) - n(budget?.reserved));
4980
+ }
4981
+ __name(runBudgetRemaining, "runBudgetRemaining");
4982
+ __name3(runBudgetRemaining, "runBudgetRemaining");
4640
4983
  function runCancelView(cancel) {
4641
4984
  if (!cancel) return void 0;
4642
4985
  return {
@@ -6021,6 +6364,7 @@ var assertPredicate = /* @__PURE__ */ __name((p, where) => {
6021
6364
  }, "assertPredicate");
6022
6365
  var assertRetry = /* @__PURE__ */ __name((r, id) => {
6023
6366
  if (!r) return;
6367
+ if (typeof r.maxAttempts === "number" && r.maxAttempts > WORKFLOW_RETRY_MAX_ATTEMPTS) throw new LuaWorkflowBuildError("cap-exceeded", `"${id}": ${workflowRetryMaxAttemptsMessage(r.maxAttempts)}`);
6024
6368
  if (r.backoff !== void 0 && !WORKFLOW_RETRY_BACKOFFS.includes(r.backoff)) throw new LuaWorkflowBuildError("backoff-invalid", `"${id}": retry.backoff must be ${WORKFLOW_RETRY_BACKOFFS.map((b) => `'${b}'`).join(" | ")}`);
6025
6369
  if (r.maxBackoffSeconds !== void 0) {
6026
6370
  if (r.backoff !== "exponential") throw new LuaWorkflowBuildError("backoff-invalid", `"${id}": retry.maxBackoffSeconds is only meaningful with backoff:'exponential'`);