lua-cli 3.32.2 → 3.32.4

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.
@@ -647,6 +647,94 @@ function isDesktopFileSessionId(value3) {
647
647
  }
648
648
  __name(isDesktopFileSessionId, "isDesktopFileSessionId");
649
649
  __name2(isDesktopFileSessionId, "isDesktopFileSessionId");
650
+ var MODEL_ID_BYOK_PROVIDERS = [
651
+ "azure",
652
+ "bedrock"
653
+ ];
654
+ function isModelIdSentinel(input) {
655
+ const lower = (input ?? "").trim().toLowerCase();
656
+ return lower === "auto" || lower.startsWith("auto/");
657
+ }
658
+ __name(isModelIdSentinel, "isModelIdSentinel");
659
+ __name2(isModelIdSentinel, "isModelIdSentinel");
660
+ function normalizeModelId(input, registry) {
661
+ const requested = typeof input === "string" ? input.trim() : "";
662
+ if (!requested) return {
663
+ ok: false,
664
+ reason: "empty",
665
+ requested,
666
+ candidates: []
667
+ };
668
+ const lower = requested.toLowerCase();
669
+ if (isModelIdSentinel(lower)) return {
670
+ ok: true,
671
+ id: lower,
672
+ form: "sentinel"
673
+ };
674
+ const slash = requested.indexOf("/");
675
+ const malformed = slash === 0;
676
+ const provider = slash > 0 ? lower.slice(0, slash) : void 0;
677
+ if (provider && MODEL_ID_BYOK_PROVIDERS.includes(provider)) {
678
+ return {
679
+ ok: true,
680
+ id: requested,
681
+ form: "byok"
682
+ };
683
+ }
684
+ const bareId = slash >= 0 ? lower.slice(slash + 1) : lower;
685
+ const lastSegment = bareId.slice(bareId.lastIndexOf("/") + 1);
686
+ const exact = /* @__PURE__ */ new Set();
687
+ const hints = /* @__PURE__ */ new Set();
688
+ for (const code of registry) {
689
+ if (typeof code !== "string" || !code) continue;
690
+ const codeLower = code.toLowerCase();
691
+ if (!malformed && codeLower === lower) return {
692
+ ok: true,
693
+ id: code,
694
+ form: provider ? "canonical" : "bare"
695
+ };
696
+ const i = codeLower.indexOf("/");
697
+ if (i < 0) continue;
698
+ const codeBare = codeLower.slice(i + 1);
699
+ if (bareId && codeBare === bareId) exact.add(code);
700
+ else if (lastSegment && codeBare.slice(codeBare.lastIndexOf("/") + 1) === lastSegment) hints.add(code);
701
+ }
702
+ const sorted = [
703
+ ...exact
704
+ ].sort();
705
+ if (!provider && !malformed && sorted.length === 1) return {
706
+ ok: true,
707
+ id: sorted[0],
708
+ form: "bare"
709
+ };
710
+ if (!provider && !malformed && sorted.length > 1) {
711
+ return {
712
+ ok: false,
713
+ reason: "ambiguous",
714
+ requested,
715
+ candidates: sorted
716
+ };
717
+ }
718
+ return {
719
+ ok: false,
720
+ reason: "unknown",
721
+ requested,
722
+ candidates: sorted.length ? sorted : [
723
+ ...hints
724
+ ].sort()
725
+ };
726
+ }
727
+ __name(normalizeModelId, "normalizeModelId");
728
+ __name2(normalizeModelId, "normalizeModelId");
729
+ function modelUnresolvedMessage(r) {
730
+ if (r.reason === "empty") return "model pin is empty \u2014 pin an approved model (provider/model) or omit `model`";
731
+ if (r.reason === "ambiguous") {
732
+ return `model "${r.requested}" does not resolve to one approved model \u2014 it names ${r.candidates.length}; pin one of: ${r.candidates.join(", ")}`;
733
+ }
734
+ return r.candidates.length ? `model "${r.requested}" does not resolve to an approved model \u2014 accepted forms: ${r.candidates.join(", ")}` : `model "${r.requested}" does not resolve to an approved model \u2014 accepted forms are the registry's provider-prefixed ids (provider/model) or a bare id that names exactly one of them`;
735
+ }
736
+ __name(modelUnresolvedMessage, "modelUnresolvedMessage");
737
+ __name2(modelUnresolvedMessage, "modelUnresolvedMessage");
650
738
  var IMPLICIT_MODEL_SELECTION_SOURCES = [
651
739
  "workspace-default",
652
740
  "platform-default"
@@ -1709,6 +1797,79 @@ var WORKFLOW_RETRY_BACKOFFS = [
1709
1797
  "fixed",
1710
1798
  "exponential"
1711
1799
  ];
1800
+ var WORKFLOW_RETRY_MIN_ATTEMPTS = 1;
1801
+ var WORKFLOW_RETRY_POLICY_KEYS = [
1802
+ "maxAttempts",
1803
+ "backoffSeconds",
1804
+ "backoff",
1805
+ "maxBackoffSeconds"
1806
+ ];
1807
+ var WORKFLOW_RETRY_MAX_ATTEMPTS = 20;
1808
+ function workflowRetryMaxAttemptsMessage(got) {
1809
+ const tail = got === void 0 ? "" : ` (got ${JSON.stringify(got)})`;
1810
+ return `\`retry.maxAttempts\` must be an integer ${WORKFLOW_RETRY_MIN_ATTEMPTS}..${WORKFLOW_RETRY_MAX_ATTEMPTS}${tail}`;
1811
+ }
1812
+ __name(workflowRetryMaxAttemptsMessage, "workflowRetryMaxAttemptsMessage");
1813
+ __name2(workflowRetryMaxAttemptsMessage, "workflowRetryMaxAttemptsMessage");
1814
+ function isWithinWorkflowRetryAttempts(value3) {
1815
+ return typeof value3 === "number" && Number.isInteger(value3) && value3 >= WORKFLOW_RETRY_MIN_ATTEMPTS && value3 <= WORKFLOW_RETRY_MAX_ATTEMPTS;
1816
+ }
1817
+ __name(isWithinWorkflowRetryAttempts, "isWithinWorkflowRetryAttempts");
1818
+ __name2(isWithinWorkflowRetryAttempts, "isWithinWorkflowRetryAttempts");
1819
+ var WORKFLOW_RETRY_ENGINE_KEYS = [
1820
+ "budgetBaseAttempt"
1821
+ ];
1822
+ function workflowRetryUnknownMembersMessage(keys) {
1823
+ const named = keys.map((k) => {
1824
+ const engine = WORKFLOW_RETRY_ENGINE_KEYS.includes(k);
1825
+ return `\`${k}\`${engine ? " (engine-owned \u2014 stamped by resetAttempts, never authored)" : ""}`;
1826
+ });
1827
+ return `\`retry\` has no member ${named.join(", ")}; members: ${WORKFLOW_RETRY_POLICY_KEYS.join(", ")}`;
1828
+ }
1829
+ __name(workflowRetryUnknownMembersMessage, "workflowRetryUnknownMembersMessage");
1830
+ __name2(workflowRetryUnknownMembersMessage, "workflowRetryUnknownMembersMessage");
1831
+ function unknownWorkflowRetryMembers(retry) {
1832
+ if (!retry || typeof retry !== "object" || Array.isArray(retry)) return [];
1833
+ return Object.keys(retry).filter((k) => !WORKFLOW_RETRY_POLICY_KEYS.includes(k));
1834
+ }
1835
+ __name(unknownWorkflowRetryMembers, "unknownWorkflowRetryMembers");
1836
+ __name2(unknownWorkflowRetryMembers, "unknownWorkflowRetryMembers");
1837
+ function authoredRetryPolicy(retry) {
1838
+ if (!retry || typeof retry !== "object" || Array.isArray(retry)) return void 0;
1839
+ const src = retry;
1840
+ const out = {};
1841
+ for (const k of WORKFLOW_RETRY_POLICY_KEYS) if (src[k] !== void 0) out[k] = src[k];
1842
+ return Object.keys(out).length ? out : void 0;
1843
+ }
1844
+ __name(authoredRetryPolicy, "authoredRetryPolicy");
1845
+ __name2(authoredRetryPolicy, "authoredRetryPolicy");
1846
+ function retryBudgetBaseAttempt(row) {
1847
+ const base = row.retry?.budgetBaseAttempt;
1848
+ return typeof base === "number" && Number.isSafeInteger(base) && base > 0 ? base : 0;
1849
+ }
1850
+ __name(retryBudgetBaseAttempt, "retryBudgetBaseAttempt");
1851
+ __name2(retryBudgetBaseAttempt, "retryBudgetBaseAttempt");
1852
+ function retryBudgetAttempt(row) {
1853
+ return Math.max(0, row.attempt - retryBudgetBaseAttempt(row));
1854
+ }
1855
+ __name(retryBudgetAttempt, "retryBudgetAttempt");
1856
+ __name2(retryBudgetAttempt, "retryBudgetAttempt");
1857
+ function retryBudgetMaxAttempts(row) {
1858
+ const max = row.retry?.maxAttempts;
1859
+ return typeof max === "number" && Number.isFinite(max) && max >= 1 ? max : 1;
1860
+ }
1861
+ __name(retryBudgetMaxAttempts, "retryBudgetMaxAttempts");
1862
+ __name2(retryBudgetMaxAttempts, "retryBudgetMaxAttempts");
1863
+ function retryBudgetRemaining(row) {
1864
+ return retryBudgetAttempt(row) < retryBudgetMaxAttempts(row);
1865
+ }
1866
+ __name(retryBudgetRemaining, "retryBudgetRemaining");
1867
+ __name2(retryBudgetRemaining, "retryBudgetRemaining");
1868
+ function retriesRemaining(row) {
1869
+ return Math.max(0, retryBudgetMaxAttempts(row) - retryBudgetAttempt(row));
1870
+ }
1871
+ __name(retriesRemaining, "retriesRemaining");
1872
+ __name2(retriesRemaining, "retriesRemaining");
1712
1873
  var WORKFLOW_JOB_RESOURCES = [
1713
1874
  "small",
1714
1875
  "medium",
@@ -2074,6 +2235,8 @@ var WORKFLOW_AUDIT_EVENTS = [
2074
2235
  "workflow.goal.resumed",
2075
2236
  "workflow.goal.done",
2076
2237
  "workflow.goal.closed",
2238
+ // LUA-760: an ended goal's cadence Job retired (deleted) — inline on done / closed, by R21 / R28, or by sweep #30
2239
+ "workflow.goal.job_retired",
2077
2240
  // --- org policy (02 §2.10 / 09 R23) ---
2078
2241
  "workflow.policy.retention_changed",
2079
2242
  "workflow.policy.pacing_changed",
@@ -2217,6 +2380,138 @@ ${items.join("\n\n")}`;
2217
2380
  }
2218
2381
  __name(renderTargetsBlock, "renderTargetsBlock");
2219
2382
  __name2(renderTargetsBlock, "renderTargetsBlock");
2383
+ var WORKFLOW_APPROVAL_OUTPUT_DECISIONS = [
2384
+ "approved",
2385
+ "denied",
2386
+ "timed_out"
2387
+ ];
2388
+ var WORKFLOW_APPROVAL_OUTPUT_SCHEMA = {
2389
+ type: "object",
2390
+ properties: {
2391
+ approved: {
2392
+ type: "boolean"
2393
+ },
2394
+ decision: {
2395
+ type: "string",
2396
+ enum: [
2397
+ ...WORKFLOW_APPROVAL_OUTPUT_DECISIONS
2398
+ ]
2399
+ },
2400
+ /** the approver's note when given, else the decision word — what `${stepResults.<id>.text}` reads */
2401
+ text: {
2402
+ type: "string"
2403
+ },
2404
+ note: {
2405
+ type: "string"
2406
+ },
2407
+ editedPayload: {},
2408
+ editRevision: {
2409
+ type: "integer"
2410
+ },
2411
+ decidedBy: {
2412
+ type: "object",
2413
+ properties: {
2414
+ id: {
2415
+ type: "string"
2416
+ },
2417
+ kind: {
2418
+ type: "string"
2419
+ }
2420
+ }
2421
+ },
2422
+ timedOut: {
2423
+ type: "boolean"
2424
+ },
2425
+ escalations: {
2426
+ type: "integer"
2427
+ },
2428
+ evidence: {
2429
+ type: "array",
2430
+ items: {
2431
+ type: "string"
2432
+ }
2433
+ },
2434
+ items: {
2435
+ type: "array",
2436
+ items: {
2437
+ type: "object"
2438
+ }
2439
+ }
2440
+ },
2441
+ required: [
2442
+ "approved",
2443
+ "decision",
2444
+ "text"
2445
+ ]
2446
+ };
2447
+ function workflowApprovalDecisionOf(resumeData) {
2448
+ if (resumeData.timedOut === true) return "timed_out";
2449
+ return resumeData.approved === true ? "approved" : "denied";
2450
+ }
2451
+ __name(workflowApprovalDecisionOf, "workflowApprovalDecisionOf");
2452
+ __name2(workflowApprovalDecisionOf, "workflowApprovalDecisionOf");
2453
+ function workflowApprovalOutput(resumeData) {
2454
+ const decision = typeof resumeData.decision === "string" ? resumeData.decision : workflowApprovalDecisionOf(resumeData);
2455
+ const note = typeof resumeData.note === "string" && resumeData.note.trim() !== "" ? resumeData.note : void 0;
2456
+ const text = typeof resumeData.text === "string" ? resumeData.text : note ?? decision;
2457
+ return {
2458
+ ...resumeData,
2459
+ decision,
2460
+ text
2461
+ };
2462
+ }
2463
+ __name(workflowApprovalOutput, "workflowApprovalOutput");
2464
+ __name2(workflowApprovalOutput, "workflowApprovalOutput");
2465
+ function isWorkflowApprovalOutput(value3) {
2466
+ if (typeof value3 !== "object" || value3 === null || Array.isArray(value3)) return false;
2467
+ const v = value3;
2468
+ return typeof v.approved === "boolean" && WORKFLOW_APPROVAL_OUTPUT_DECISIONS.includes(v.decision) && typeof v.text === "string";
2469
+ }
2470
+ __name(isWorkflowApprovalOutput, "isWorkflowApprovalOutput");
2471
+ __name2(isWorkflowApprovalOutput, "isWorkflowApprovalOutput");
2472
+ var JSON_FENCE_RE = /```(?:json)?[ \t]*\r?\n([\s\S]*?)\r?\n?```/g;
2473
+ function extractSingleJsonValue(text) {
2474
+ const trimmed = (text ?? "").trim();
2475
+ if (!trimmed) return {
2476
+ reason: "reply is empty"
2477
+ };
2478
+ const fenced = [
2479
+ ...trimmed.matchAll(JSON_FENCE_RE)
2480
+ ];
2481
+ if (fenced.length > 1) return {
2482
+ reason: "reply carries more than one fenced block"
2483
+ };
2484
+ const candidate = fenced.length === 1 ? fenced[0][1].trim() : trimmed;
2485
+ try {
2486
+ return {
2487
+ value: JSON.parse(candidate)
2488
+ };
2489
+ } catch {
2490
+ if (fenced.length === 1) return {
2491
+ reason: "fenced block is not valid JSON"
2492
+ };
2493
+ }
2494
+ const opens = [
2495
+ trimmed.indexOf("{"),
2496
+ trimmed.indexOf("[")
2497
+ ].filter((i) => i !== -1);
2498
+ const start = opens.length ? Math.min(...opens) : -1;
2499
+ const end = Math.max(trimmed.lastIndexOf("}"), trimmed.lastIndexOf("]"));
2500
+ if (start === -1 || end <= start) return {
2501
+ reason: "reply is not JSON"
2502
+ };
2503
+ try {
2504
+ return {
2505
+ value: JSON.parse(trimmed.slice(start, end + 1))
2506
+ };
2507
+ } catch {
2508
+ return {
2509
+ reason: "reply does not contain a single JSON value"
2510
+ };
2511
+ }
2512
+ }
2513
+ __name(extractSingleJsonValue, "extractSingleJsonValue");
2514
+ __name2(extractSingleJsonValue, "extractSingleJsonValue");
2220
2515
 
2221
2516
  // ../workflow-graph/dist/index.mjs
2222
2517
  import { createHash } from "crypto";
@@ -2225,122 +2520,620 @@ import { z as z22 } from "zod";
2225
2520
  import { createHash as createHash2 } from "crypto";
2226
2521
  var __defProp3 = Object.defineProperty;
2227
2522
  var __name3 = /* @__PURE__ */ __name((target, value22) => __defProp3(target, "name", { value: value22, configurable: true }), "__name");
2228
- var SideEffectsSchema = z4.enum(WORKFLOW_SIDE_EFFECTS);
2229
- var JobResourcesSchema = z4.enum(WORKFLOW_JOB_RESOURCES);
2230
- var WORKFLOW_ARM_SUBRUN_ID = "$arm";
2231
- var WORKSPACE_TEMPLATE_EXPR_RE = /^\$\{\s*(?:initData|input)\.([^}]+?)\s*\}$/;
2232
- function workspaceTemplatePath(template22) {
2233
- const key = template22.trim();
2234
- const expr = WORKSPACE_TEMPLATE_EXPR_RE.exec(key);
2235
- if (expr) return expr[1].split(".");
2236
- if (key.includes("${")) return void 0;
2237
- return key.replace(/^(?:input|initData)\./, "").split(".");
2523
+ var WorkflowTemplateError = class extends Error {
2524
+ static {
2525
+ __name(this, "WorkflowTemplateError");
2526
+ }
2527
+ static {
2528
+ __name3(this, "WorkflowTemplateError");
2529
+ }
2530
+ placeholder;
2531
+ constructor(message, placeholder) {
2532
+ super(message), this.placeholder = placeholder;
2533
+ this.name = "WorkflowTemplateError";
2534
+ }
2535
+ };
2536
+ function isMapConfigObject(v) {
2537
+ return typeof v === "object" && v !== null && !Array.isArray(v);
2238
2538
  }
2239
- __name(workspaceTemplatePath, "workspaceTemplatePath");
2240
- __name3(workspaceTemplatePath, "workspaceTemplatePath");
2241
- function retryBackoffs() {
2242
- if (!Array.isArray(WORKFLOW_RETRY_BACKOFFS)) {
2243
- throw new Error("@lua/shared-types.WORKFLOW_RETRY_BACKOFFS is not a tuple \u2014 a jest.mock('@lua/shared-types') must spread jest.requireActual('@lua/shared-types')");
2539
+ __name(isMapConfigObject, "isMapConfigObject");
2540
+ __name3(isMapConfigObject, "isMapConfigObject");
2541
+ function parseMapConfig(raw, stepId) {
2542
+ if (isMapConfigObject(raw)) return raw;
2543
+ if (typeof raw !== "string") {
2544
+ throw new Error(`Stored mapping step "${stepId}" has a mapConfig that is neither a JSON string nor an object.`);
2545
+ }
2546
+ try {
2547
+ return JSON.parse(raw);
2548
+ } catch (e) {
2549
+ throw new Error(`Stored mapping step "${stepId}" has invalid JSON mapConfig: ${e.message}`);
2244
2550
  }
2245
- return WORKFLOW_RETRY_BACKOFFS;
2246
2551
  }
2247
- __name(retryBackoffs, "retryBackoffs");
2248
- __name3(retryBackoffs, "retryBackoffs");
2249
- var SLEEP_UNTIL_REPLACEMENT = Object.freeze({
2250
- type: "sleep",
2251
- duration: 6e4
2252
- });
2253
- function sleepUntilUnsupportedMessage(id) {
2254
- return `the engine does not execute \`sleepUntil\` yet (node "${id}") \u2014 replace it with a \`sleep\` node with a \`duration\` in ms, e.g. { type: 'sleep', id: '${id}', duration: ${SLEEP_UNTIL_REPLACEMENT.duration} }`;
2552
+ __name(parseMapConfig, "parseMapConfig");
2553
+ __name3(parseMapConfig, "parseMapConfig");
2554
+ function mapConfigWire(raw) {
2555
+ if (typeof raw === "string") return raw;
2556
+ if (isMapConfigObject(raw)) return canonicalJson(raw);
2557
+ return void 0;
2255
2558
  }
2256
- __name(sleepUntilUnsupportedMessage, "sleepUntilUnsupportedMessage");
2257
- __name3(sleepUntilUnsupportedMessage, "sleepUntilUnsupportedMessage");
2258
- var WORKFLOW_CAPS_DEFAULT = Object.freeze({
2259
- maxParallelArms: 16,
2260
- maxForeachConcurrency: 16,
2261
- maxForeachItems: 2e4,
2262
- maxNodes: 200,
2263
- maxNestingDepth: 3,
2264
- maxForeachRatePerSecond: 50,
2265
- maxLoopIntervalSeconds: 86400,
2266
- maxWorkerTimeoutSeconds: 600,
2267
- maxJobTimeoutSeconds: 86400,
2268
- maxJobSegmentSeconds: 14400
2269
- });
2270
- var WORKFLOW_STEP_DEFAULT_TIMEOUT_SECONDS = 300;
2271
- var WORKFLOW_AGENT_DEFAULT_TIMEOUT_SECONDS = 600;
2272
- var WORKFLOW_JOB_DEFAULT_TIMEOUT_SECONDS = 3600;
2273
- var WORKFLOW_FOREACH_DEFAULT_CONCURRENCY = 4;
2274
- var WORKFLOW_FOREACH_DEFAULT_MAX_ITEMS = 256;
2275
- var WORKFLOW_LOOP_DEFAULT_MAX_ITERATIONS = 100;
2276
- var WORKFLOW_SUSPEND_DEFAULT_TIMEOUT_HOURS = 168;
2277
- var WORKFLOW_SIGNAL_DEFAULT_SOURCES = [
2278
- "webhook",
2279
- "api",
2280
- "user"
2559
+ __name(mapConfigWire, "mapConfigWire");
2560
+ __name3(mapConfigWire, "mapConfigWire");
2561
+ var TEMPLATE_PLACEHOLDER = /\$\{([^}]*)\}/g;
2562
+ var TEMPLATE_NAMESPACES = [
2563
+ "initData",
2564
+ "state",
2565
+ "requestContext",
2566
+ "stepResults"
2281
2567
  ];
2282
- var clone = /* @__PURE__ */ __name3((v) => JSON.parse(JSON.stringify(v)), "clone");
2283
- function fillPolicy(node, defaultTimeout) {
2284
- if (node.tier === void 0 && node.workspace !== void 0 && node.workspace !== "inherit") node.tier = "job";
2285
- if (node.timeoutSeconds === void 0) node.timeoutSeconds = node.tier === "job" ? WORKFLOW_JOB_DEFAULT_TIMEOUT_SECONDS : defaultTimeout;
2286
- if (node.retry === void 0) node.retry = {
2287
- maxAttempts: 1
2568
+ function describeBadPlaceholder(template22, idx, rawExpr) {
2569
+ return `Template placeholder #${idx} (\${${rawExpr}}) in '${template22}'`;
2570
+ }
2571
+ __name(describeBadPlaceholder, "describeBadPlaceholder");
2572
+ __name3(describeBadPlaceholder, "describeBadPlaceholder");
2573
+ function parseTemplatePlaceholder(rawExpr) {
2574
+ const dot = rawExpr.indexOf(".");
2575
+ return {
2576
+ scope: dot === -1 ? rawExpr : rawExpr.slice(0, dot),
2577
+ rest: dot === -1 ? "" : rawExpr.slice(dot + 1)
2288
2578
  };
2289
- if (node.onError === void 0) node.onError = "fail";
2290
- if ((node.type === "step" || node.type === "tool") && node.sideEffects === void 0) node.sideEffects = "none";
2291
2579
  }
2292
- __name(fillPolicy, "fillPolicy");
2293
- __name3(fillPolicy, "fillPolicy");
2294
- function fillSingle(node) {
2295
- switch (node.type) {
2296
- case "step": {
2297
- fillPolicy(node, WORKFLOW_STEP_DEFAULT_TIMEOUT_SECONDS);
2298
- const s = node;
2299
- if (s.resumeTimeoutHours === void 0) s.resumeTimeoutHours = WORKFLOW_SUSPEND_DEFAULT_TIMEOUT_HOURS;
2300
- if (s.onSuspendTimeout === void 0) s.onSuspendTimeout = "fail";
2301
- return;
2302
- }
2303
- case "agent":
2304
- fillPolicy(node, WORKFLOW_AGENT_DEFAULT_TIMEOUT_SECONDS);
2305
- return;
2306
- case "tool":
2307
- fillPolicy(node, WORKFLOW_STEP_DEFAULT_TIMEOUT_SECONDS);
2308
- return;
2309
- case "workflow":
2310
- if (node.workflowId === WORKFLOW_ARM_SUBRUN_ID && Array.isArray(node.graph) && node.graph[1]) fillSingle(node.graph[1]);
2311
- return;
2580
+ __name(parseTemplatePlaceholder, "parseTemplatePlaceholder");
2581
+ __name3(parseTemplatePlaceholder, "parseTemplatePlaceholder");
2582
+ function traverseMappingPath(root, path, errorLabel) {
2583
+ if (path === "" || path === ".") return root;
2584
+ const parts = path.split(".");
2585
+ let value22 = root;
2586
+ for (const part of parts) {
2587
+ if (typeof value22 === "object" && value22 !== null) value22 = value22[part];
2588
+ else throw new WorkflowTemplateError(`Invalid path ${path} in ${errorLabel}`, path);
2312
2589
  }
2590
+ return value22;
2313
2591
  }
2314
- __name(fillSingle, "fillSingle");
2315
- __name3(fillSingle, "fillSingle");
2316
- function fillHitl(node) {
2317
- if (node.type === "approval") {
2318
- const a = node;
2319
- if (a.approver === void 0) a.approver = "creator";
2320
- if (a.timeoutHours === void 0) a.timeoutHours = WORKFLOW_SUSPEND_DEFAULT_TIMEOUT_HOURS;
2321
- if (a.onTimeout === void 0) a.onTimeout = "deny";
2322
- if (a.onDeny === void 0) a.onDeny = "continue";
2323
- if (a.excludeInitiator === void 0) a.excludeInitiator = false;
2324
- if (a.editable === void 0) a.editable = false;
2325
- return;
2592
+ __name(traverseMappingPath, "traverseMappingPath");
2593
+ __name3(traverseMappingPath, "traverseMappingPath");
2594
+ function stringifyTemplateValue(v, template22, idx, rawExpr) {
2595
+ if (v === null || v === void 0) return "";
2596
+ if (typeof v === "object") {
2597
+ try {
2598
+ return JSON.stringify(v);
2599
+ } catch (err) {
2600
+ throw new WorkflowTemplateError(`${describeBadPlaceholder(template22, idx, rawExpr)} resolved to a value that could not be JSON-stringified (${err.message}).`, rawExpr);
2601
+ }
2326
2602
  }
2327
- const w = node;
2328
- if (w.timeoutHours === void 0) w.timeoutHours = WORKFLOW_SUSPEND_DEFAULT_TIMEOUT_HOURS;
2329
- if (w.onTimeout === void 0) w.onTimeout = "fail";
2330
- if (w.acceptedSources === void 0) w.acceptedSources = [
2331
- ...WORKFLOW_SIGNAL_DEFAULT_SOURCES
2332
- ];
2603
+ return String(v);
2333
2604
  }
2334
- __name(fillHitl, "fillHitl");
2335
- __name3(fillHitl, "fillHitl");
2336
- function fillArm(arm) {
2337
- if (arm.type === "mapping") return;
2338
- if (isHitlNode(arm)) fillHitl(arm);
2339
- else fillSingle(arm);
2605
+ __name(stringifyTemplateValue, "stringifyTemplateValue");
2606
+ __name3(stringifyTemplateValue, "stringifyTemplateValue");
2607
+ function escapeFence(content) {
2608
+ return content.replace(/<\/lua-data/g, "<\\/lua-data");
2340
2609
  }
2341
- __name(fillArm, "fillArm");
2342
- __name3(fillArm, "fillArm");
2343
- function fillEntry(entry) {
2610
+ __name(escapeFence, "escapeFence");
2611
+ __name3(escapeFence, "escapeFence");
2612
+ function fenceBlock(name, source, content) {
2613
+ return `<lua-data name="${name}" source="${source}" untrusted="true">${escapeFence(content)}</lua-data>`;
2614
+ }
2615
+ __name(fenceBlock, "fenceBlock");
2616
+ __name3(fenceBlock, "fenceBlock");
2617
+ function renderTemplate(template22, ctx, opts) {
2618
+ let idx = 0;
2619
+ return template22.replace(TEMPLATE_PLACEHOLDER, (_match, rawExpr) => {
2620
+ idx += 1;
2621
+ const { scope, rest } = parseTemplatePlaceholder(rawExpr);
2622
+ const label = describeBadPlaceholder(template22, idx, rawExpr);
2623
+ let rendered;
2624
+ let source;
2625
+ switch (scope) {
2626
+ case "initData":
2627
+ rendered = stringifyTemplateValue(traverseMappingPath(ctx.initData, rest, label), template22, idx, rawExpr);
2628
+ source = "initData";
2629
+ break;
2630
+ case "state":
2631
+ rendered = stringifyTemplateValue(traverseMappingPath(ctx.state, rest, label), template22, idx, rawExpr);
2632
+ source = "state";
2633
+ break;
2634
+ case "requestContext":
2635
+ rendered = stringifyTemplateValue(traverseMappingPath(ctx.requestContext, rest, label), template22, idx, rawExpr);
2636
+ source = "requestContext";
2637
+ break;
2638
+ case "stepResults": {
2639
+ const innerDot = rest.indexOf(".");
2640
+ const stepId = innerDot === -1 ? rest : rest.slice(0, innerDot);
2641
+ const subPath = innerDot === -1 ? "" : rest.slice(innerDot + 1);
2642
+ if (!stepId) throw new WorkflowTemplateError(`${label} must name a step: \${stepResults.<stepId>.<path>}.`, rawExpr);
2643
+ if (!(stepId in ctx.stepResults) || ctx.stepResults[stepId] == null) {
2644
+ 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);
2645
+ }
2646
+ rendered = stringifyTemplateValue(traverseMappingPath(ctx.stepResults[stepId], subPath, label), template22, idx, rawExpr);
2647
+ source = `step:${stepId}`;
2648
+ break;
2649
+ }
2650
+ default:
2651
+ throw new WorkflowTemplateError(`${label} references unknown namespace "${scope}". Use one of: ${TEMPLATE_NAMESPACES.join(", ")}.`, rawExpr);
2652
+ }
2653
+ return opts.fenced ? fenceBlock(rawExpr, source, rendered) : rendered;
2654
+ });
2655
+ }
2656
+ __name(renderTemplate, "renderTemplate");
2657
+ __name3(renderTemplate, "renderTemplate");
2658
+ function isMapDescriptor(v) {
2659
+ if (v === null || typeof v !== "object" || Array.isArray(v)) return false;
2660
+ const d = v;
2661
+ const keys = Object.keys(d);
2662
+ const only = /* @__PURE__ */ __name3((...allowed) => keys.every((k) => allowed.includes(k)), "only");
2663
+ if ("value" in d) return keys.length === 1;
2664
+ if ("template" in d) return keys.length === 1 && typeof d.template === "string";
2665
+ if ("requestContextPath" in d) return keys.length === 1 && typeof d.requestContextPath === "string";
2666
+ if ("knowledge" in d) return keys.length === 1 && typeof d.knowledge === "object" && d.knowledge !== null;
2667
+ if ("initData" in d) return d.initData === true && typeof d.path === "string" && only("initData", "path");
2668
+ if ("step" in d) {
2669
+ const stepOk = typeof d.step === "string" || Array.isArray(d.step) && d.step.every((x) => typeof x === "string");
2670
+ return stepOk && typeof d.path === "string" && only("step", "path", "rows");
2671
+ }
2672
+ return false;
2673
+ }
2674
+ __name(isMapDescriptor, "isMapDescriptor");
2675
+ __name3(isMapDescriptor, "isMapDescriptor");
2676
+ var MAP_DESCRIPTOR_KEYS = [
2677
+ "step",
2678
+ "path",
2679
+ "initData",
2680
+ "value",
2681
+ "template",
2682
+ "requestContextPath",
2683
+ "knowledge"
2684
+ ];
2685
+ var MAP_MEMBER_MALFORMED_CODE = "map-member-malformed";
2686
+ function malformedMapMembers(cfg) {
2687
+ if (!cfg || typeof cfg !== "object" || Array.isArray(cfg)) return [];
2688
+ const out = [];
2689
+ for (const [member, v] of Object.entries(cfg)) {
2690
+ if (!v || typeof v !== "object" || Array.isArray(v) || isMapDescriptor(v)) continue;
2691
+ const keys = Object.keys(v).filter((k) => MAP_DESCRIPTOR_KEYS.includes(k));
2692
+ if (keys.length > 0) out.push({
2693
+ member,
2694
+ keys
2695
+ });
2696
+ }
2697
+ return out;
2698
+ }
2699
+ __name(malformedMapMembers, "malformedMapMembers");
2700
+ __name3(malformedMapMembers, "malformedMapMembers");
2701
+ function mapMemberMalformedMessage(id, m) {
2702
+ const keys = m.keys.map((k) => `\`${k}\``).join(", ");
2703
+ 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`;
2704
+ }
2705
+ __name(mapMemberMalformedMessage, "mapMemberMalformedMessage");
2706
+ __name3(mapMemberMalformedMessage, "mapMemberMalformedMessage");
2707
+ function resolveDescriptor(key, m, ctx) {
2708
+ if (!isMapDescriptor(m)) return {
2709
+ value: m
2710
+ };
2711
+ try {
2712
+ if ("value" in m) return {
2713
+ value: m.value
2714
+ };
2715
+ if ("template" in m && typeof m.template === "string") {
2716
+ return {
2717
+ value: renderTemplate(m.template, ctx, {
2718
+ fenced: false
2719
+ })
2720
+ };
2721
+ }
2722
+ if ("knowledge" in m || "rows" in m && m.rows !== void 0) {
2723
+ return {
2724
+ error: "binding_unresolved",
2725
+ key
2726
+ };
2727
+ }
2728
+ if ("requestContextPath" in m) {
2729
+ const label = `requestContext path for key "${key}"`;
2730
+ return {
2731
+ value: traverseMappingPath(ctx.requestContext, m.requestContextPath, label)
2732
+ };
2733
+ }
2734
+ if ("path" in m) {
2735
+ const source = "initData" in m && m.initData ? "initData" : "step";
2736
+ if (source === "initData") {
2737
+ return {
2738
+ value: traverseMappingPath(ctx.initData, m.path, `initData for key "${key}"`)
2739
+ };
2740
+ }
2741
+ const stepRef = m.step;
2742
+ const candidates = Array.isArray(stepRef) ? stepRef : [
2743
+ stepRef
2744
+ ];
2745
+ const stepId = candidates.find((s) => ctx.stepResults[s] !== void 0 && ctx.stepResults[s] !== null);
2746
+ if (stepId === void 0) return {
2747
+ error: "binding_unresolved",
2748
+ key
2749
+ };
2750
+ return {
2751
+ value: traverseMappingPath(ctx.stepResults[stepId], m.path, `step ${candidates.join("|")} for key "${key}"`)
2752
+ };
2753
+ }
2754
+ return {
2755
+ error: "binding_unresolved",
2756
+ key
2757
+ };
2758
+ } catch (err) {
2759
+ if (err instanceof WorkflowTemplateError) return {
2760
+ error: "binding_unresolved",
2761
+ key
2762
+ };
2763
+ throw err;
2764
+ }
2765
+ }
2766
+ __name(resolveDescriptor, "resolveDescriptor");
2767
+ __name3(resolveDescriptor, "resolveDescriptor");
2768
+ function resolveMapping(cfg, ctx) {
2769
+ const keys = Object.keys(cfg);
2770
+ if (keys.length === 1 && keys[0] === "") {
2771
+ return resolveDescriptor("", cfg[""], ctx);
2772
+ }
2773
+ const result = {};
2774
+ for (const key of keys) {
2775
+ const resolved = resolveDescriptor(key, cfg[key], ctx);
2776
+ if ("error" in resolved) return resolved;
2777
+ result[key] = resolved.value;
2778
+ }
2779
+ return {
2780
+ value: result
2781
+ };
2782
+ }
2783
+ __name(resolveMapping, "resolveMapping");
2784
+ __name3(resolveMapping, "resolveMapping");
2785
+ var fromInit = /* @__PURE__ */ __name3((path) => ({
2786
+ initData: true,
2787
+ path
2788
+ }), "fromInit");
2789
+ var fromStep = /* @__PURE__ */ __name3((s, path = "") => {
2790
+ const idOf = /* @__PURE__ */ __name3((x) => typeof x === "string" ? x : x.id, "idOf");
2791
+ return {
2792
+ step: Array.isArray(s) ? s.map(idOf) : idOf(s),
2793
+ path
2794
+ };
2795
+ }, "fromStep");
2796
+ var value = /* @__PURE__ */ __name3((v) => ({
2797
+ value: v
2798
+ }), "value");
2799
+ var template = /* @__PURE__ */ __name3((s) => ({
2800
+ template: s
2801
+ }), "template");
2802
+ var fromRequest = /* @__PURE__ */ __name3((path) => ({
2803
+ requestContextPath: path
2804
+ }), "fromRequest");
2805
+ var rows = /* @__PURE__ */ __name3((s, path, page) => ({
2806
+ step: typeof s === "string" ? s : s.id,
2807
+ path,
2808
+ rows: page
2809
+ }), "rows");
2810
+ var fromKnowledge = /* @__PURE__ */ __name3((k) => ({
2811
+ knowledge: k
2812
+ }), "fromKnowledge");
2813
+ var SideEffectsSchema = z4.enum(WORKFLOW_SIDE_EFFECTS);
2814
+ var JobResourcesSchema = z4.enum(WORKFLOW_JOB_RESOURCES);
2815
+ var APPROVER_SPEC_MAX_USERS = 20;
2816
+ var ESCALATION_MAX_HOPS = 3;
2817
+ var TemplateBindingSchema = z22.object({
2818
+ template: z22.string().min(1).max(2048)
2819
+ }).strict();
2820
+ var ApproverSpecSchema = z22.union([
2821
+ z22.literal("creator"),
2822
+ z22.literal("org-admins"),
2823
+ z22.object({
2824
+ users: z22.union([
2825
+ z22.array(z22.string().min(1).max(128)).min(1).max(APPROVER_SPEC_MAX_USERS),
2826
+ TemplateBindingSchema
2827
+ ])
2828
+ }).strict(),
2829
+ z22.object({
2830
+ role: z22.union([
2831
+ z22.string().min(1).max(128),
2832
+ TemplateBindingSchema
2833
+ ])
2834
+ }).strict(),
2835
+ z22.object({
2836
+ group: z22.union([
2837
+ z22.string().min(1).max(128),
2838
+ TemplateBindingSchema
2839
+ ])
2840
+ }).strict(),
2841
+ z22.object({
2842
+ governance: z22.object({
2843
+ policyId: z22.string().min(1).max(128)
2844
+ }).strict()
2845
+ }).strict()
2846
+ ]);
2847
+ var FourEyesSchema = z22.object({
2848
+ edit: ApproverSpecSchema,
2849
+ approve: ApproverSpecSchema
2850
+ }).strict();
2851
+ var EscalationHopSchema = z22.object({
2852
+ escalateTo: ApproverSpecSchema,
2853
+ timeoutHours: z22.number().finite().min(1).max(720)
2854
+ }).strict();
2855
+ var TerminalOutcomeSchema = z22.enum([
2856
+ "deny",
2857
+ "cancel-run",
2858
+ "fail",
2859
+ "continue"
2860
+ ]);
2861
+ var ApprovalOnTimeoutSchema = z22.union([
2862
+ TerminalOutcomeSchema,
2863
+ EscalationHopSchema,
2864
+ z22.array(z22.union([
2865
+ TerminalOutcomeSchema,
2866
+ EscalationHopSchema
2867
+ ])).min(1).max(ESCALATION_MAX_HOPS + 1)
2868
+ ]);
2869
+ var APPROVER_SPEC_SHAPES = [
2870
+ "'creator'",
2871
+ "'org-admins'",
2872
+ "{users:[userId, \u2026]}",
2873
+ "{role:roleName}",
2874
+ "{group:groupName}",
2875
+ "{governance:{policyId}}"
2876
+ ];
2877
+ var APPROVER_WRITTEN_MAX = 120;
2878
+ var USER_ID_SHAPED_RE = /^[^\s@]{1,128}$/;
2879
+ function describeApproverSpecRefusal(spec) {
2880
+ const raw = spec === void 0 ? "undefined" : JSON.stringify(spec) ?? String(spec);
2881
+ const written = raw.length > APPROVER_WRITTEN_MAX ? `${raw.slice(0, APPROVER_WRITTEN_MAX - 1)}\u2026` : raw;
2882
+ const users = typeof spec === "object" && spec !== null ? spec.users : void 0;
2883
+ const approver = typeof users === "string" && USER_ID_SHAPED_RE.test(users) ? {
2884
+ users: [
2885
+ users
2886
+ ]
2887
+ } : "creator";
2888
+ const message = `approver ${written} is not an approver \u2014 legal: ${APPROVER_SPEC_SHAPES.join(" | ")}. 'creator' is the person who started the run: write approver:'creator' for "ask me" / "I approve"; {users:[\u2026]} takes user ids, never emails, names or {type:'user'}` + (approver === "creator" ? "" : `; here: approver:${JSON.stringify(approver)}`);
2889
+ return {
2890
+ approver,
2891
+ written,
2892
+ message
2893
+ };
2894
+ }
2895
+ __name(describeApproverSpecRefusal, "describeApproverSpecRefusal");
2896
+ __name3(describeApproverSpecRefusal, "describeApproverSpecRefusal");
2897
+ var BINDING_ROOTS = [
2898
+ "initData",
2899
+ "stepResults",
2900
+ "requestContext",
2901
+ "state"
2902
+ ];
2903
+ function bindingRootsOk(template22) {
2904
+ const refs = [
2905
+ ...template22.matchAll(/\$\{\s*([A-Za-z_$][\w$]*)/g)
2906
+ ].map((m) => m[1]);
2907
+ return refs.length > 0 && refs.every((r) => BINDING_ROOTS.includes(r));
2908
+ }
2909
+ __name(bindingRootsOk, "bindingRootsOk");
2910
+ __name3(bindingRootsOk, "bindingRootsOk");
2911
+ function isTemplateBinding(v) {
2912
+ return typeof v === "object" && v !== null && typeof v.template === "string";
2913
+ }
2914
+ __name(isTemplateBinding, "isTemplateBinding");
2915
+ __name3(isTemplateBinding, "isTemplateBinding");
2916
+ function approvalEditable(node) {
2917
+ if (node.editable === true) return true;
2918
+ if (node.editable === false) return false;
2919
+ return Array.isArray(node.editablePaths) && node.editablePaths.length > 0;
2920
+ }
2921
+ __name(approvalEditable, "approvalEditable");
2922
+ __name3(approvalEditable, "approvalEditable");
2923
+ function validateApproverBlock(node, opts = {
2924
+ path: "approval"
2925
+ }) {
2926
+ const issues = [];
2927
+ const push = /* @__PURE__ */ __name3((code, path, message, severity = "error") => issues.push({
2928
+ code,
2929
+ path,
2930
+ severity,
2931
+ message
2932
+ }), "push");
2933
+ const checkSpec = /* @__PURE__ */ __name3((spec, path) => {
2934
+ const r = ApproverSpecSchema.safeParse(spec);
2935
+ if (!r.success) {
2936
+ const users = spec?.users;
2937
+ if (Array.isArray(users) && users.length > APPROVER_SPEC_MAX_USERS) push("cap-exceeded", path, `at most ${APPROVER_SPEC_MAX_USERS} users`);
2938
+ else {
2939
+ const refusal = describeApproverSpecRefusal(spec);
2940
+ issues.push({
2941
+ code: "approver-invalid",
2942
+ path,
2943
+ severity: "error",
2944
+ message: refusal.message,
2945
+ repair: {
2946
+ approver: refusal.approver,
2947
+ written: refusal.written
2948
+ }
2949
+ });
2950
+ }
2951
+ return;
2952
+ }
2953
+ const s = r.data;
2954
+ if (typeof s === "object") {
2955
+ if ("governance" in s && !opts.governanceEnabled) push("approver-governance-unavailable", path, "governance reviewer routing is not enabled for this deployment");
2956
+ if ("group" in s && typeof s.group === "string" && !opts.scimEnabled && opts.idpGroups?.includes(s.group)) push("approver-idp-group-unavailable", path, "IdP-group approvers are not enabled for this deployment");
2957
+ const binding = "users" in s ? s.users : "role" in s ? s.role : "group" in s ? s.group : void 0;
2958
+ if (isTemplateBinding(binding)) {
2959
+ if (!bindingRootsOk(binding.template)) push("approver-binding-invalid", `${path}.template`, "binding root must be initData / stepResults / requestContext / state");
2960
+ if ("users" in s && opts.customerReachable) push("approver-binding-customer-reachable", `${path}.users`, "a customer-reachable workflow may not bind its approver list");
2961
+ }
2962
+ }
2963
+ }, "checkSpec");
2964
+ if (node.approver !== void 0) checkSpec(node.approver, `${opts.path}.approver`);
2965
+ if (node.fourEyes !== void 0) {
2966
+ const r = FourEyesSchema.safeParse(node.fourEyes);
2967
+ if (!r.success) push("approver-invalid", `${opts.path}.fourEyes`, "fourEyes needs { edit, approve } approver specs");
2968
+ else {
2969
+ checkSpec(r.data.edit, `${opts.path}.fourEyes.edit`);
2970
+ checkSpec(r.data.approve, `${opts.path}.fourEyes.approve`);
2971
+ }
2972
+ if (!approvalEditable(node)) push("four-eyes-requires-editable", `${opts.path}.fourEyes`, "fourEyes requires editable:true");
2973
+ if (node.approver !== void 0) push("four-eyes-overrides-approver", `${opts.path}.approver`, "fourEyes replaces approver", "warning");
2974
+ if (node.itemsPath) push("four-eyes-items-unsupported", `${opts.path}.fourEyes`, "fourEyes cannot combine with itemsPath");
2975
+ }
2976
+ if (node.excludeInitiator && (node.approver === void 0 || node.approver === "creator") && !node.fourEyes) push("approver-excludes-only-candidate", `${opts.path}.excludeInitiator`, "'creator' with excludeInitiator leaves no approver");
2977
+ if (Array.isArray(node.onTimeout)) {
2978
+ const chain = node.onTimeout;
2979
+ const hops = chain.filter((m) => typeof m === "object" && m !== null && "escalateTo" in m);
2980
+ if (hops.length > ESCALATION_MAX_HOPS) push("escalation-chain-too-long", `${opts.path}.onTimeout`, `at most ${ESCALATION_MAX_HOPS} hops`);
2981
+ const last = chain[chain.length - 1];
2982
+ if (typeof last === "object" && last !== null) push("escalation-chain-not-terminal", `${opts.path}.onTimeout`, "a chain must end in deny | cancel-run | fail");
2983
+ hops.forEach((h, i) => checkSpec(h.escalateTo, `${opts.path}.onTimeout[${i}].escalateTo`));
2984
+ } else if (typeof node.onTimeout === "object" && node.onTimeout !== null) {
2985
+ checkSpec(node.onTimeout.escalateTo, `${opts.path}.onTimeout.escalateTo`);
2986
+ }
2987
+ return issues;
2988
+ }
2989
+ __name(validateApproverBlock, "validateApproverBlock");
2990
+ __name3(validateApproverBlock, "validateApproverBlock");
2991
+ function liftRenderedApprover(row, rendered) {
2992
+ const text = (rendered ?? "").trim();
2993
+ if (!text) return null;
2994
+ if (row === "users") {
2995
+ let members = null;
2996
+ if (text.startsWith("[")) {
2997
+ try {
2998
+ members = JSON.parse(text);
2999
+ } catch {
3000
+ return null;
3001
+ }
3002
+ } else members = text.split(",").map((s) => s.trim());
3003
+ if (!Array.isArray(members) || members.length === 0 || members.length > APPROVER_SPEC_MAX_USERS) return null;
3004
+ if (!members.every((m) => typeof m === "string" && m.length > 0 && m.length <= 128)) return null;
3005
+ return {
3006
+ users: [
3007
+ ...new Set(members)
3008
+ ].sort()
3009
+ };
3010
+ }
3011
+ if (text.length > 128 || text.startsWith("[") || text.startsWith("{")) return null;
3012
+ return row === "role" ? {
3013
+ role: text
3014
+ } : {
3015
+ group: text
3016
+ };
3017
+ }
3018
+ __name(liftRenderedApprover, "liftRenderedApprover");
3019
+ __name3(liftRenderedApprover, "liftRenderedApprover");
3020
+ var WORKSPACE_TEMPLATE_EXPR_RE = /^\$\{\s*(?:initData|input)\.([^}]+?)\s*\}$/;
3021
+ function workspaceTemplatePath(template22) {
3022
+ const key = template22.trim();
3023
+ const expr = WORKSPACE_TEMPLATE_EXPR_RE.exec(key);
3024
+ if (expr) return expr[1].split(".");
3025
+ if (key.includes("${")) return void 0;
3026
+ return key.replace(/^(?:input|initData)\./, "").split(".");
3027
+ }
3028
+ __name(workspaceTemplatePath, "workspaceTemplatePath");
3029
+ __name3(workspaceTemplatePath, "workspaceTemplatePath");
3030
+ function retryBackoffs() {
3031
+ if (!Array.isArray(WORKFLOW_RETRY_BACKOFFS)) {
3032
+ throw new Error("@lua/shared-types.WORKFLOW_RETRY_BACKOFFS is not a tuple \u2014 a jest.mock('@lua/shared-types') must spread jest.requireActual('@lua/shared-types')");
3033
+ }
3034
+ return WORKFLOW_RETRY_BACKOFFS;
3035
+ }
3036
+ __name(retryBackoffs, "retryBackoffs");
3037
+ __name3(retryBackoffs, "retryBackoffs");
3038
+ var SLEEP_UNTIL_REPLACEMENT = Object.freeze({
3039
+ type: "sleep",
3040
+ duration: 6e4
3041
+ });
3042
+ function sleepUntilUnsupportedMessage(id) {
3043
+ return `the engine does not execute \`sleepUntil\` yet (node "${id}") \u2014 replace it with a \`sleep\` node with a \`duration\` in ms, e.g. { type: 'sleep', id: '${id}', duration: ${SLEEP_UNTIL_REPLACEMENT.duration} }`;
3044
+ }
3045
+ __name(sleepUntilUnsupportedMessage, "sleepUntilUnsupportedMessage");
3046
+ __name3(sleepUntilUnsupportedMessage, "sleepUntilUnsupportedMessage");
3047
+ function armSubrunUnsupportedMessage(id, workflowId) {
3048
+ return `the engine does not execute the implicit \`${workflowId}\` arm subrun (node "${id}") \u2014 a [map, step] container arm is the step itself with the map as its \`input\` since lua-cli 3.32.4; re-run \`lua compile\` with the current CLI (a hand-written artifact: put the map on the arm node's \`input\` and drop the \`workflow\` wrapper)`;
3049
+ }
3050
+ __name(armSubrunUnsupportedMessage, "armSubrunUnsupportedMessage");
3051
+ __name3(armSubrunUnsupportedMessage, "armSubrunUnsupportedMessage");
3052
+ var WORKFLOW_CAPS_DEFAULT = Object.freeze({
3053
+ maxParallelArms: 16,
3054
+ maxForeachConcurrency: 16,
3055
+ maxForeachItems: 2e4,
3056
+ maxNodes: 200,
3057
+ maxNestingDepth: 3,
3058
+ maxForeachRatePerSecond: 50,
3059
+ maxLoopIntervalSeconds: 86400,
3060
+ maxWorkerTimeoutSeconds: 600,
3061
+ maxJobTimeoutSeconds: 86400,
3062
+ maxJobSegmentSeconds: 14400
3063
+ });
3064
+ var WORKFLOW_STEP_DEFAULT_TIMEOUT_SECONDS = 300;
3065
+ var WORKFLOW_AGENT_DEFAULT_TIMEOUT_SECONDS = 600;
3066
+ var WORKFLOW_JOB_DEFAULT_TIMEOUT_SECONDS = 3600;
3067
+ var WORKFLOW_FOREACH_DEFAULT_CONCURRENCY = 4;
3068
+ var WORKFLOW_FOREACH_DEFAULT_MAX_ITEMS = 256;
3069
+ var WORKFLOW_LOOP_DEFAULT_MAX_ITERATIONS = 100;
3070
+ var WORKFLOW_SUSPEND_DEFAULT_TIMEOUT_HOURS = 168;
3071
+ var WORKFLOW_SIGNAL_DEFAULT_SOURCES = [
3072
+ "webhook",
3073
+ "api",
3074
+ "user"
3075
+ ];
3076
+ var clone = /* @__PURE__ */ __name3((v) => JSON.parse(JSON.stringify(v)), "clone");
3077
+ function fillPolicy(node, defaultTimeout) {
3078
+ if (node.tier === void 0 && node.workspace !== void 0 && node.workspace !== "inherit") node.tier = "job";
3079
+ if (node.timeoutSeconds === void 0) node.timeoutSeconds = node.tier === "job" ? WORKFLOW_JOB_DEFAULT_TIMEOUT_SECONDS : defaultTimeout;
3080
+ if (node.retry === void 0) node.retry = {
3081
+ maxAttempts: 1
3082
+ };
3083
+ if (node.onError === void 0) node.onError = "fail";
3084
+ if ((node.type === "step" || node.type === "tool") && node.sideEffects === void 0) node.sideEffects = "none";
3085
+ }
3086
+ __name(fillPolicy, "fillPolicy");
3087
+ __name3(fillPolicy, "fillPolicy");
3088
+ function fillSingle(node) {
3089
+ switch (node.type) {
3090
+ case "step": {
3091
+ fillPolicy(node, WORKFLOW_STEP_DEFAULT_TIMEOUT_SECONDS);
3092
+ const s = node;
3093
+ if (s.resumeTimeoutHours === void 0) s.resumeTimeoutHours = WORKFLOW_SUSPEND_DEFAULT_TIMEOUT_HOURS;
3094
+ if (s.onSuspendTimeout === void 0) s.onSuspendTimeout = "fail";
3095
+ return;
3096
+ }
3097
+ case "agent":
3098
+ fillPolicy(node, WORKFLOW_AGENT_DEFAULT_TIMEOUT_SECONDS);
3099
+ return;
3100
+ case "tool":
3101
+ fillPolicy(node, WORKFLOW_STEP_DEFAULT_TIMEOUT_SECONDS);
3102
+ return;
3103
+ case "workflow":
3104
+ return;
3105
+ }
3106
+ }
3107
+ __name(fillSingle, "fillSingle");
3108
+ __name3(fillSingle, "fillSingle");
3109
+ function fillHitl(node) {
3110
+ if (node.type === "approval") {
3111
+ const a = node;
3112
+ if (a.approver === void 0) a.approver = "creator";
3113
+ if (a.timeoutHours === void 0) a.timeoutHours = WORKFLOW_SUSPEND_DEFAULT_TIMEOUT_HOURS;
3114
+ if (a.onTimeout === void 0) a.onTimeout = "deny";
3115
+ if (a.onDeny === void 0) a.onDeny = "continue";
3116
+ if (a.excludeInitiator === void 0) a.excludeInitiator = false;
3117
+ if (a.editable === void 0) a.editable = false;
3118
+ return;
3119
+ }
3120
+ const w = node;
3121
+ if (w.timeoutHours === void 0) w.timeoutHours = WORKFLOW_SUSPEND_DEFAULT_TIMEOUT_HOURS;
3122
+ if (w.onTimeout === void 0) w.onTimeout = "fail";
3123
+ if (w.acceptedSources === void 0) w.acceptedSources = [
3124
+ ...WORKFLOW_SIGNAL_DEFAULT_SOURCES
3125
+ ];
3126
+ }
3127
+ __name(fillHitl, "fillHitl");
3128
+ __name3(fillHitl, "fillHitl");
3129
+ function fillArm(arm) {
3130
+ if (arm.type === "mapping") return;
3131
+ if (isHitlNode(arm)) fillHitl(arm);
3132
+ else fillSingle(arm);
3133
+ }
3134
+ __name(fillArm, "fillArm");
3135
+ __name3(fillArm, "fillArm");
3136
+ function fillEntry(entry) {
2344
3137
  switch (entry.type) {
2345
3138
  case "step":
2346
3139
  case "agent":
@@ -2482,12 +3275,11 @@ function mapConfigStepRefs(raw) {
2482
3275
  if (!cfg) return [];
2483
3276
  const ids = [];
2484
3277
  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
3278
+ if (!isMapDescriptor(d)) continue;
3279
+ if ("step" in d) ids.push(...Array.isArray(d.step) ? d.step : [
3280
+ d.step
2489
3281
  ]);
2490
- if (typeof desc.template === "string") ids.push(...templateStepRefs(desc.template));
3282
+ if ("template" in d) ids.push(...templateStepRefs(d.template));
2491
3283
  }
2492
3284
  return ids;
2493
3285
  }
@@ -2498,8 +3290,14 @@ function nodeStepRefs(entry) {
2498
3290
  case "agent": {
2499
3291
  const a = entry;
2500
3292
  const p = a.promptTemplate;
2501
- return typeof p === "string" ? templateStepRefs(p) : p && "template" in p ? templateStepRefs(p.template) : [];
3293
+ const prompt = typeof p === "string" ? templateStepRefs(p) : p && "template" in p ? templateStepRefs(p.template) : [];
3294
+ return [
3295
+ ...prompt,
3296
+ ...mapConfigStepRefs(a.input)
3297
+ ];
2502
3298
  }
3299
+ case "step":
3300
+ return mapConfigStepRefs(entry.input);
2503
3301
  case "tool":
2504
3302
  return mapConfigStepRefs(entry.input);
2505
3303
  case "workflow":
@@ -2616,6 +3414,12 @@ function validateLuaExtensions(g, caps = WORKFLOW_CAPS_DEFAULT, opts = {
2616
3414
  const r = node.retry;
2617
3415
  if (!r) return;
2618
3416
  const id = singleId(node);
3417
+ const unknown = unknownWorkflowRetryMembers(r);
3418
+ if (unknown.length) err("invalid-envelope", workflowRetryUnknownMembersMessage(unknown), `${path}.retry`, id);
3419
+ if (r.maxAttempts !== void 0 && !isWithinWorkflowRetryAttempts(r.maxAttempts)) {
3420
+ const over = typeof r.maxAttempts === "number" && r.maxAttempts > WORKFLOW_RETRY_MAX_ATTEMPTS;
3421
+ err(over ? "cap-exceeded" : "invalid-envelope", workflowRetryMaxAttemptsMessage(r.maxAttempts), `${path}.retry.maxAttempts`, id);
3422
+ }
2619
3423
  const backoffs = retryBackoffs();
2620
3424
  if (r.backoff !== void 0 && !backoffs.includes(r.backoff)) {
2621
3425
  const list = backoffs.map((b) => `'${b}'`).join(" | ");
@@ -2712,6 +3516,21 @@ function validateLuaExtensions(g, caps = WORKFLOW_CAPS_DEFAULT, opts = {
2712
3516
  err("job-tier-provider-unsupported", `model provider '${provider}' is outside LUA_WF_JOB_PROVIDERS [${opts.policy.jobProviders.join(", ")}]`, `${path}.model`, id);
2713
3517
  }
2714
3518
  }, "checkTier");
3519
+ const checkModel = /* @__PURE__ */ __name3((node, path) => {
3520
+ if (node.type !== "agent" || typeof node.model !== "string") return;
3521
+ const registry = opts.approvedModels;
3522
+ if (registry === void 0) return;
3523
+ const id = singleId(node);
3524
+ if (registry === "unavailable") {
3525
+ const pin = node.model.trim();
3526
+ if (pin && !normalizeModelId(pin, []).ok) {
3527
+ warn("model-unresolved", `model "${pin}" could not be checked against the approved-model registry (unavailable at push) \u2014 it dispatches only if it resolves there (a provider/model registry code, or a bare id exactly one approved model carries)`, `${path}.model`, id);
3528
+ }
3529
+ return;
3530
+ }
3531
+ const resolved = normalizeModelId(node.model, registry);
3532
+ if (!resolved.ok) err("model-unresolved", modelUnresolvedMessage(resolved), `${path}.model`, id);
3533
+ }, "checkModel");
2715
3534
  const checkWorkspace = /* @__PURE__ */ __name3((node, path) => {
2716
3535
  const id = singleId(node);
2717
3536
  const ws = workspaceOf(node);
@@ -2758,35 +3577,43 @@ function validateLuaExtensions(g, caps = WORKFLOW_CAPS_DEFAULT, opts = {
2758
3577
  const schema = node.type === "step" ? node.step.outputSchema : node.type === "agent" ? node.outputSchema : void 0;
2759
3578
  if (schema !== void 0) outputSchemas.set(singleId(node), schema);
2760
3579
  }, "recordOutputSchema");
3580
+ const checkMapMembers = /* @__PURE__ */ __name3((cfg, basePath, id) => {
3581
+ for (const m of malformedMapMembers(cfg)) {
3582
+ warn(MAP_MEMBER_MALFORMED_CODE, mapMemberMalformedMessage(id, m), `${basePath}.${m.member}`, id);
3583
+ }
3584
+ }, "checkMapMembers");
3585
+ const checkInputShape = /* @__PURE__ */ __name3((node, path) => {
3586
+ const input = node.input;
3587
+ if (input === void 0) return;
3588
+ const id = singleId(node);
3589
+ if (input !== null && typeof input === "object" && !Array.isArray(input)) {
3590
+ checkMapMembers(input, `${path}.input`, id);
3591
+ return;
3592
+ }
3593
+ 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`, id);
3594
+ }, "checkInputShape");
3595
+ const checkBodyInput = /* @__PURE__ */ __name3((body, path, container) => {
3596
+ if (body.type === "workflow" || body.input === void 0) return;
3597
+ err("arm-input-unsupported", container === "foreach" ? `a foreach body receives each item as its input \u2014 drop \`input\` on "${singleId(body)}" and map the items before the foreach instead` : `a loop body receives the previous output as its input \u2014 drop \`input\` on "${singleId(body)}" and put the map before the loop instead`, `${path}.input`, singleId(body));
3598
+ }, "checkBodyInput");
2761
3599
  const checkSingle = /* @__PURE__ */ __name3((node, path, depth) => {
2762
3600
  recordOutputSchema(node);
2763
- if (node.type === "workflow" && node.workflowId === WORKFLOW_ARM_SUBRUN_ID) {
3601
+ if (node.type === "workflow" && (typeof node.workflowId !== "string" || node.workflowId.length === 0)) {
2764
3602
  checkId(node.id, path);
2765
- const body = node.graph;
2766
- if (!Array.isArray(body) || body.length !== 2 || body[0]?.type !== "mapping" || !body[1]) {
2767
- err("container-arm-empty", "an implicit arm subrun needs a [mapping, step] body", `${path}.graph`, node.id);
2768
- return;
2769
- }
2770
- if (body[1].type === "mapping") {
2771
- err("container-arm-empty", "a bare mapping arm has nothing to run", `${path}.graph.1`, node.id);
2772
- return;
2773
- }
2774
- const inner = body[1];
2775
- if (isHitlNode(inner)) {
2776
- err("node-type-unsupported-in-container", workflowHitlArmShapeMessage(inner.type, inner.id, "mapped-arm"), `${path}.graph.1`, inner.id);
2777
- return;
2778
- }
2779
- upstream.add(singleId(body[1]));
2780
- checkArm(body[0], `${path}.graph.0`, depth, "parallel");
2781
- checkSingle(body[1], `${path}.graph.1`, depth);
2782
- upstream.add(body[0].id);
2783
- upstream.add(singleId(body[1]));
3603
+ err("invalid-envelope", `\`workflowId\` must be a non-empty string naming the workflow to start (got ${JSON.stringify(node.workflowId)})`, `${path}.workflowId`, node.id);
3604
+ return;
3605
+ }
3606
+ if (node.type === "workflow" && (node.workflowId.startsWith("$") || Array.isArray(node.graph))) {
3607
+ checkId(node.id, path);
3608
+ err("node-type-unsupported-by-engine", armSubrunUnsupportedMessage(node.id, node.workflowId), path, node.id);
2784
3609
  return;
2785
3610
  }
2786
3611
  checkId(singleId(node), path);
2787
3612
  checkPolicyEnums(node, path);
3613
+ checkInputShape(node, path);
2788
3614
  checkTimeout(node, path);
2789
3615
  checkTier(node, path);
3616
+ checkModel(node, path);
2790
3617
  checkRetry(node, path);
2791
3618
  checkWorkspace(node, path);
2792
3619
  if (!opts.static) {
@@ -2809,7 +3636,7 @@ function validateLuaExtensions(g, caps = WORKFLOW_CAPS_DEFAULT, opts = {
2809
3636
  if (node.type === "workflow" && node.kind === "subrun" && depth > caps.maxNestingDepth) {
2810
3637
  err("cap-exceeded", `nesting depth ${depth} exceeds ${caps.maxNestingDepth}`, path, node.id);
2811
3638
  }
2812
- if (node.type === "workflow" && node.workflowId !== WORKFLOW_ARM_SUBRUN_ID && typeof g.definition?.id === "string" && node.workflowId === g.definition.id) {
3639
+ if (node.type === "workflow" && typeof g.definition?.id === "string" && node.workflowId === g.definition.id) {
2813
3640
  err("subrun-cycle", `"${node.id}" starts "${node.workflowId}", which is this workflow itself`, path, node.id);
2814
3641
  }
2815
3642
  for (const ref of nodeStepRefs(node)) {
@@ -2830,11 +3657,14 @@ function validateLuaExtensions(g, caps = WORKFLOW_CAPS_DEFAULT, opts = {
2830
3657
  if (a.approver === "creator" && a.excludeInitiator === true) {
2831
3658
  err("approver-excludes-only-candidate", "approver:'creator' with excludeInitiator:true always excludes the only candidate", path, a.id);
2832
3659
  }
2833
- if (a.fourEyes !== void 0 && a.editable !== true) {
3660
+ const editable = approvalEditable(a);
3661
+ if (a.fourEyes !== void 0 && !editable) {
2834
3662
  err("four-eyes-requires-editable", "`fourEyes` requires editable:true", `${path}.fourEyes`, a.id);
2835
3663
  }
2836
- if ((a.editablePaths !== void 0 || a.editedPayloadSchema !== void 0) && a.editable !== true) {
2837
- err("editable-path-invalid", "`editablePaths` / `editedPayloadSchema` require editable:true", `${path}.editablePaths`, a.id);
3664
+ if (a.editable === false && Array.isArray(a.editablePaths) && a.editablePaths.length > 0) {
3665
+ err("editable-path-invalid", "`editablePaths` beside editable:false is contradictory \u2014 drop the paths or set editable:true", `${path}.editablePaths`, a.id);
3666
+ } else if ((a.editablePaths !== void 0 || a.editedPayloadSchema !== void 0) && !editable) {
3667
+ err("editable-path-invalid", "`editablePaths` / `editedPayloadSchema` require editable:true (a non-empty editablePaths implies it)", `${path}.editablePaths`, a.id);
2838
3668
  }
2839
3669
  for (const p of a.editablePaths ?? []) {
2840
3670
  if (!EDITABLE_PATH_RE.test(p)) err("editable-path-invalid", `editablePaths entry "${p}" is outside the seg(.seg)*[*]/[n] grammar`, `${path}.editablePaths`, a.id);
@@ -2865,6 +3695,7 @@ function validateLuaExtensions(g, caps = WORKFLOW_CAPS_DEFAULT, opts = {
2865
3695
  const checkArm = /* @__PURE__ */ __name3((arm, path, depth, container) => {
2866
3696
  if (arm.type === "mapping") {
2867
3697
  checkId(arm.id, path);
3698
+ checkMapMembers(readMapConfig(arm.mapConfig), `${path}.mapConfig`, arm.id);
2868
3699
  for (const ref of nodeStepRefs(arm)) {
2869
3700
  if (!upstream.has(ref)) err("template-reference-unresolved", `"${arm.id}" references stepResults.${ref}, which is not upstream`, path, arm.id);
2870
3701
  }
@@ -2889,6 +3720,7 @@ function validateLuaExtensions(g, caps = WORKFLOW_CAPS_DEFAULT, opts = {
2889
3720
  break;
2890
3721
  case "mapping":
2891
3722
  checkId(entry.id, path);
3723
+ checkMapMembers(readMapConfig(entry.mapConfig), `${path}.mapConfig`, entry.id);
2892
3724
  for (const ref of nodeStepRefs(entry)) {
2893
3725
  if (!upstream.has(ref)) err("template-reference-unresolved", `"${entry.id}" references stepResults.${ref}, which is not upstream`, path, entry.id);
2894
3726
  }
@@ -3013,6 +3845,7 @@ function validateLuaExtensions(g, caps = WORKFLOW_CAPS_DEFAULT, opts = {
3013
3845
  } else checkHitlArm(f.step, `${path}.step`, "foreach");
3014
3846
  declared.push(f.step.id);
3015
3847
  } else {
3848
+ checkBodyInput(f.step, `${path}.step`, "foreach");
3016
3849
  checkSingle(f.step, `${path}.step`, o.chunk ? 2 : 1);
3017
3850
  declared.push(singleId(f.step));
3018
3851
  }
@@ -3033,6 +3866,7 @@ function validateLuaExtensions(g, caps = WORKFLOW_CAPS_DEFAULT, opts = {
3033
3866
  checkHitlArm(l.step, `${path}.step`, "loop");
3034
3867
  declared.push(l.step.id);
3035
3868
  } else {
3869
+ checkBodyInput(l.step, `${path}.step`, "loop");
3036
3870
  checkSingle(l.step, `${path}.step`, 1);
3037
3871
  declared.push(singleId(l.step));
3038
3872
  }
@@ -3512,361 +4346,123 @@ __name3(renderPredicate, "renderPredicate");
3512
4346
  function wrapLabel(child, rendered) {
3513
4347
  return child.op === "and" || child.op === "or" || child.op === "not" ? `(${rendered})` : rendered;
3514
4348
  }
3515
- __name(wrapLabel, "wrapLabel");
3516
- __name3(wrapLabel, "wrapLabel");
3517
- function renderRef(ref) {
3518
- if ("literal" in ref) return JSON.stringify(ref.literal);
3519
- return ref.path;
3520
- }
3521
- __name(renderRef, "renderRef");
3522
- __name3(renderRef, "renderRef");
3523
- var stepIdOf = /* @__PURE__ */ __name3((s) => typeof s === "string" ? s : s.id, "stepIdOf");
3524
- function step(s) {
3525
- const id = stepIdOf(s);
3526
- return {
3527
- path: /* @__PURE__ */ __name3((p) => ({
3528
- path: p === "" ? `stepResults.${id}` : `stepResults.${id}.${p}`
3529
- }), "path")
3530
- };
3531
- }
3532
- __name(step, "step");
3533
- __name3(step, "step");
3534
- function stepOf(id) {
3535
- return step(id);
3536
- }
3537
- __name(stepOf, "stepOf");
3538
- __name3(stepOf, "stepOf");
3539
- function init(path) {
3540
- return {
3541
- path: path === "" ? "initData" : `initData.${path}`
3542
- };
3543
- }
3544
- __name(init, "init");
3545
- __name3(init, "init");
3546
- function state(path) {
3547
- return {
3548
- path: path === "" ? "state" : `state.${path}`
3549
- };
3550
- }
3551
- __name(state, "state");
3552
- __name3(state, "state");
3553
- function lit(v) {
3554
- return {
3555
- literal: v
3556
- };
3557
- }
3558
- __name(lit, "lit");
3559
- __name3(lit, "lit");
3560
- function toPathOrLiteral(v) {
3561
- if (typeof v === "object" && v !== null) {
3562
- if ("path" in v) return {
3563
- path: v.path
3564
- };
3565
- if ("literal" in v) return {
3566
- literal: v.literal
3567
- };
3568
- }
3569
- return {
3570
- literal: v
3571
- };
3572
- }
3573
- __name(toPathOrLiteral, "toPathOrLiteral");
3574
- __name3(toPathOrLiteral, "toPathOrLiteral");
3575
- var cmp = /* @__PURE__ */ __name3((op) => (l, r) => ({
3576
- op,
3577
- left: toPathOrLiteral(l),
3578
- right: toPathOrLiteral(r)
3579
- }), "cmp");
3580
- var eq = cmp("eq");
3581
- var ne = cmp("ne");
3582
- var gt = cmp("gt");
3583
- var gte = cmp("gte");
3584
- var lt = cmp("lt");
3585
- var lte = cmp("lte");
3586
- var inSet = /* @__PURE__ */ __name3((v, set) => ({
3587
- op: "in",
3588
- value: {
3589
- path: v.path
3590
- },
3591
- set
3592
- }), "inSet");
3593
- var notIn = /* @__PURE__ */ __name3((v, set) => ({
3594
- op: "notIn",
3595
- value: {
3596
- path: v.path
3597
- },
3598
- set
3599
- }), "notIn");
3600
- var exists = /* @__PURE__ */ __name3((ref) => ({
3601
- op: "exists",
3602
- path: ref.path
3603
- }), "exists");
3604
- var notExists = /* @__PURE__ */ __name3((ref) => ({
3605
- op: "notExists",
3606
- path: ref.path
3607
- }), "notExists");
3608
- var truthy = /* @__PURE__ */ __name3((ref) => ({
3609
- op: "truthy",
3610
- value: {
3611
- path: ref.path
3612
- }
3613
- }), "truthy");
3614
- var falsy = /* @__PURE__ */ __name3((ref) => ({
3615
- op: "falsy",
3616
- value: {
3617
- path: ref.path
3618
- }
3619
- }), "falsy");
3620
- var and = /* @__PURE__ */ __name3((...args) => ({
3621
- op: "and",
3622
- args
3623
- }), "and");
3624
- var or = /* @__PURE__ */ __name3((...args) => ({
3625
- op: "or",
3626
- args
3627
- }), "or");
3628
- var not = /* @__PURE__ */ __name3((arg) => ({
3629
- op: "not",
3630
- arg
3631
- }), "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(".");
4349
+ __name(wrapLabel, "wrapLabel");
4350
+ __name3(wrapLabel, "wrapLabel");
4351
+ function renderRef(ref) {
4352
+ if ("literal" in ref) return JSON.stringify(ref.literal);
4353
+ return ref.path;
4354
+ }
4355
+ __name(renderRef, "renderRef");
4356
+ __name3(renderRef, "renderRef");
4357
+ var stepIdOf = /* @__PURE__ */ __name3((s) => typeof s === "string" ? s : s.id, "stepIdOf");
4358
+ function step(s) {
4359
+ const id = stepIdOf(s);
3684
4360
  return {
3685
- scope: dot === -1 ? rawExpr : rawExpr.slice(0, dot),
3686
- rest: dot === -1 ? "" : rawExpr.slice(dot + 1)
4361
+ path: /* @__PURE__ */ __name3((p) => ({
4362
+ path: p === "" ? `stepResults.${id}` : `stepResults.${id}.${p}`
4363
+ }), "path")
3687
4364
  };
3688
4365
  }
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);
4366
+ __name(step, "step");
4367
+ __name3(step, "step");
4368
+ function stepOf(id) {
4369
+ return step(id);
3713
4370
  }
3714
- __name(stringifyTemplateValue, "stringifyTemplateValue");
3715
- __name3(stringifyTemplateValue, "stringifyTemplateValue");
3716
- function escapeFence(content) {
3717
- return content.replace(/<\/lua-data/g, "<\\/lua-data");
4371
+ __name(stepOf, "stepOf");
4372
+ __name3(stepOf, "stepOf");
4373
+ function init(path) {
4374
+ return {
4375
+ path: path === "" ? "initData" : `initData.${path}`
4376
+ };
3718
4377
  }
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>`;
4378
+ __name(init, "init");
4379
+ __name3(init, "init");
4380
+ function state(path) {
4381
+ return {
4382
+ path: path === "" ? "state" : `state.${path}`
4383
+ };
3723
4384
  }
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
- });
4385
+ __name(state, "state");
4386
+ __name3(state, "state");
4387
+ function lit(v) {
4388
+ return {
4389
+ literal: v
4390
+ };
3764
4391
  }
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
4392
+ __name(lit, "lit");
4393
+ __name3(lit, "lit");
4394
+ function toPathOrLiteral(v) {
4395
+ if (typeof v === "object" && v !== null) {
4396
+ if ("path" in v) return {
4397
+ path: v.path
3814
4398
  };
3815
- } catch (err) {
3816
- if (err instanceof WorkflowTemplateError) return {
3817
- error: "binding_unresolved",
3818
- key
4399
+ if ("literal" in v) return {
4400
+ literal: v.literal
3819
4401
  };
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
4402
  }
3836
4403
  return {
3837
- value: result
4404
+ literal: v
3838
4405
  };
3839
4406
  }
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");
4407
+ __name(toPathOrLiteral, "toPathOrLiteral");
4408
+ __name3(toPathOrLiteral, "toPathOrLiteral");
4409
+ var cmp = /* @__PURE__ */ __name3((op) => (l, r) => ({
4410
+ op,
4411
+ left: toPathOrLiteral(l),
4412
+ right: toPathOrLiteral(r)
4413
+ }), "cmp");
4414
+ var eq = cmp("eq");
4415
+ var ne = cmp("ne");
4416
+ var gt = cmp("gt");
4417
+ var gte = cmp("gte");
4418
+ var lt = cmp("lt");
4419
+ var lte = cmp("lte");
4420
+ var inSet = /* @__PURE__ */ __name3((v, set) => ({
4421
+ op: "in",
4422
+ value: {
4423
+ path: v.path
4424
+ },
4425
+ set
4426
+ }), "inSet");
4427
+ var notIn = /* @__PURE__ */ __name3((v, set) => ({
4428
+ op: "notIn",
4429
+ value: {
4430
+ path: v.path
4431
+ },
4432
+ set
4433
+ }), "notIn");
4434
+ var exists = /* @__PURE__ */ __name3((ref) => ({
4435
+ op: "exists",
4436
+ path: ref.path
4437
+ }), "exists");
4438
+ var notExists = /* @__PURE__ */ __name3((ref) => ({
4439
+ op: "notExists",
4440
+ path: ref.path
4441
+ }), "notExists");
4442
+ var truthy = /* @__PURE__ */ __name3((ref) => ({
4443
+ op: "truthy",
4444
+ value: {
4445
+ path: ref.path
4446
+ }
4447
+ }), "truthy");
4448
+ var falsy = /* @__PURE__ */ __name3((ref) => ({
4449
+ op: "falsy",
4450
+ value: {
4451
+ path: ref.path
4452
+ }
4453
+ }), "falsy");
4454
+ var and = /* @__PURE__ */ __name3((...args) => ({
4455
+ op: "and",
4456
+ args
4457
+ }), "and");
4458
+ var or = /* @__PURE__ */ __name3((...args) => ({
4459
+ op: "or",
4460
+ args
4461
+ }), "or");
4462
+ var not = /* @__PURE__ */ __name3((arg) => ({
4463
+ op: "not",
4464
+ arg
4465
+ }), "not");
3870
4466
  var CONTINUED_FAILURE_TAG = "continued_failure";
3871
4467
  var CONTINUED_FAILURE_DEFAULT_CODE = "step_failed";
3872
4468
  var CONTINUED_FAILURE_OUTPUT_SCHEMA = Object.freeze({
@@ -3938,21 +4534,14 @@ function isContinuedFailureValue(v) {
3938
4534
  __name(isContinuedFailureValue, "isContinuedFailureValue");
3939
4535
  __name3(isContinuedFailureValue, "isContinuedFailureValue");
3940
4536
  var isHitlNode2 = /* @__PURE__ */ __name3((n2) => isWorkflowHitlEntryType(n2.type), "isHitlNode");
3941
- function lowerContainerArm(mapping, step22) {
3942
- const stepId = nodeIdOf(step22);
4537
+ function inlineContainerArm(mapping, step22) {
3943
4538
  return {
3944
- type: "workflow",
3945
- id: `${stepId}_arm`,
3946
- workflowId: WORKFLOW_ARM_SUBRUN_ID,
3947
- kind: "subrun",
3948
- graph: [
3949
- mapping,
3950
- step22
3951
- ]
4539
+ ...step22,
4540
+ input: parseMapConfig(mapping.mapConfig, mapping.id)
3952
4541
  };
3953
4542
  }
3954
- __name(lowerContainerArm, "lowerContainerArm");
3955
- __name3(lowerContainerArm, "lowerContainerArm");
4543
+ __name(inlineContainerArm, "inlineContainerArm");
4544
+ __name3(inlineContainerArm, "inlineContainerArm");
3956
4545
  var nodeIdOf = /* @__PURE__ */ __name3((n2) => n2.type === "step" ? n2.step.id : n2.id, "nodeIdOf");
3957
4546
  function entryIds(entry) {
3958
4547
  switch (entry.type) {
@@ -4023,6 +4612,27 @@ function resolvePlacements(calls) {
4023
4612
  break;
4024
4613
  }
4025
4614
  });
4615
+ const armMapPlacementIssue = /* @__PURE__ */ __name3((node, ref, i, container) => {
4616
+ if (!ref.armMap || node.type === "mapping" || isHitlNode2(node)) return void 0;
4617
+ const id = nodeIdOf(node);
4618
+ if ((container === "foreach" || container === "loop") && node.type !== "workflow") {
4619
+ return {
4620
+ code: "mapping-placement",
4621
+ message: container === "foreach" ? `foreach body "${id}": a [map, step] body is not supported \u2014 the body receives each item as its input; map the items before the foreach instead (foreach(step, { items: \u2026 }) or a .map() before it)` : `loop body "${id}": a [map, step] body is not supported \u2014 the body receives the previous output as its input; put the .map() before the loop instead`,
4622
+ callIndex: i,
4623
+ stepId: id
4624
+ };
4625
+ }
4626
+ if (node.input !== void 0) {
4627
+ return {
4628
+ code: "mapping-placement",
4629
+ message: `"${id}": the [map, step] arm mapping and the node's own input map would both bind its input \u2014 keep one (drop the arm map, or the \`input\` on the declaration)`,
4630
+ callIndex: i,
4631
+ stepId: id
4632
+ };
4633
+ }
4634
+ return void 0;
4635
+ }, "armMapPlacementIssue");
4026
4636
  const hitlPlacementIssue = /* @__PURE__ */ __name3((node, ref, i, container) => {
4027
4637
  if (!isHitlNode2(node)) return void 0;
4028
4638
  const id = node.id;
@@ -4049,7 +4659,7 @@ function resolvePlacements(calls) {
4049
4659
  if (ref.node.type === "mapping" && !allowMapping) {
4050
4660
  issues.push({
4051
4661
  code: "mapping-placement",
4052
- message: `mapping "${ref.node.id}" cannot be a container arm \u2014 chain it as [map, step]`,
4662
+ message: `mapping "${ref.node.id}" cannot be a container arm \u2014 chain it as [map, step] in a parallel / conditional arm, or place the .map() before the container`,
4053
4663
  callIndex: i,
4054
4664
  stepId: ref.node.id
4055
4665
  });
@@ -4070,7 +4680,7 @@ function resolvePlacements(calls) {
4070
4680
  if (d.node.type === "mapping" && !allowMapping) {
4071
4681
  issues.push({
4072
4682
  code: "mapping-placement",
4073
- message: `map "${ref.ref}" cannot be a parallel/foreach/loop arm \u2014 chain it as [map, step]`,
4683
+ message: `map "${ref.ref}" cannot be a parallel/foreach/loop arm \u2014 chain it as [map, step] in a parallel arm, or place the .map() before the container`,
4074
4684
  callIndex: i,
4075
4685
  stepId: ref.ref
4076
4686
  });
@@ -4081,6 +4691,11 @@ function resolvePlacements(calls) {
4081
4691
  issues.push(hitl);
4082
4692
  return void 0;
4083
4693
  }
4694
+ const mapped = armMapPlacementIssue(d.node, ref, i, container);
4695
+ if (mapped) {
4696
+ issues.push(mapped);
4697
+ return void 0;
4698
+ }
4084
4699
  const prior = placedBy.get(ref.ref);
4085
4700
  if (prior !== void 0 && prior !== i) {
4086
4701
  issues.push({
@@ -4101,6 +4716,10 @@ function resolvePlacements(calls) {
4101
4716
  }
4102
4717
  const hitl = hitlPlacementIssue(ref.node, ref, i, container);
4103
4718
  if (hitl) issues.push(hitl);
4719
+ else {
4720
+ const mapped = armMapPlacementIssue(ref.node, ref, i, container);
4721
+ if (mapped) issues.push(mapped);
4722
+ }
4104
4723
  }, "claim");
4105
4724
  calls.forEach((call, i) => {
4106
4725
  switch (call.kind) {
@@ -4128,7 +4747,7 @@ function resolvePlacements(calls) {
4128
4747
  const lookup = /* @__PURE__ */ __name3((ref) => {
4129
4748
  const n2 = "node" in ref ? ref.node : declared.get(ref.ref)?.node;
4130
4749
  if (!n2 || !ref.armMap || n2.type === "mapping" || isHitlNode2(n2)) return n2;
4131
- return lowerContainerArm(ref.armMap, n2);
4750
+ return inlineContainerArm(ref.armMap, n2);
4132
4751
  }, "lookup");
4133
4752
  calls.forEach((call, i) => {
4134
4753
  switch (call.kind) {
@@ -4569,6 +5188,33 @@ function pruneUndefined(o) {
4569
5188
  }
4570
5189
  __name(pruneUndefined, "pruneUndefined");
4571
5190
  __name3(pruneUndefined, "pruneUndefined");
5191
+ var WORKFLOW_INLINE_RUN_TAG = "inline";
5192
+ function runOrigin(run) {
5193
+ if (run.goalId) return "goal";
5194
+ if (run.jobId || run.trigger === "schedule") return "schedule";
5195
+ if (run.dynamic === true) return run.tags?.includes(WORKFLOW_INLINE_RUN_TAG) ? "inline" : "compose";
5196
+ return "definition";
5197
+ }
5198
+ __name(runOrigin, "runOrigin");
5199
+ __name3(runOrigin, "runOrigin");
5200
+ var RUN_ERROR_ISSUES_MAX = 20;
5201
+ function runErrorIssues(issues) {
5202
+ if (!Array.isArray(issues)) return void 0;
5203
+ const out = [];
5204
+ for (const raw of issues.slice(0, RUN_ERROR_ISSUES_MAX)) {
5205
+ if (!raw || typeof raw !== "object") continue;
5206
+ const o = raw;
5207
+ if (typeof o.code !== "string" || !o.code) continue;
5208
+ out.push(pruneUndefined({
5209
+ code: o.code,
5210
+ path: typeof o.path === "string" ? o.path : void 0,
5211
+ message: typeof o.message === "string" ? o.message : void 0
5212
+ }));
5213
+ }
5214
+ return out.length ? out : void 0;
5215
+ }
5216
+ __name(runErrorIssues, "runErrorIssues");
5217
+ __name3(runErrorIssues, "runErrorIssues");
4572
5218
  function runNextAction(run) {
4573
5219
  if (isTerminalRunStatus(run.status)) return "none";
4574
5220
  if (run.status === "suspended" && run.gate?.kind === "budget") return "raise_budget";
@@ -4626,10 +5272,57 @@ function runCounts(counts) {
4626
5272
  }
4627
5273
  __name(runCounts, "runCounts");
4628
5274
  __name3(runCounts, "runCounts");
4629
- function runUsage(run) {
5275
+ function isPricedStepReceipt(receipt) {
5276
+ return typeof receipt?.multiplier === "number" && Number.isFinite(receipt.multiplier);
5277
+ }
5278
+ __name(isPricedStepReceipt, "isPricedStepReceipt");
5279
+ __name3(isPricedStepReceipt, "isPricedStepReceipt");
5280
+ function receiptEngine(engine) {
5281
+ if (engine === "actions") return "seat";
5282
+ if (engine === "credits") return "legacy";
5283
+ return void 0;
5284
+ }
5285
+ __name(receiptEngine, "receiptEngine");
5286
+ __name3(receiptEngine, "receiptEngine");
5287
+ function receiptTier(tier) {
5288
+ return tier === "light" || tier === "standard" || tier === "heavy" ? tier : void 0;
5289
+ }
5290
+ __name(receiptTier, "receiptTier");
5291
+ __name3(receiptTier, "receiptTier");
5292
+ function stepBillingView(receipt) {
5293
+ const engine = receiptEngine(receipt?.engine);
5294
+ if (!receipt || engine === void 0) return void 0;
5295
+ return pruneUndefined({
5296
+ engine,
5297
+ attempt: typeof receipt.attempt === "number" ? receipt.attempt : void 0,
5298
+ credits: typeof receipt.credits === "number" ? receipt.credits : void 0,
5299
+ actions: typeof receipt.actionsEstimate === "number" ? receipt.actionsEstimate : void 0,
5300
+ model: typeof receipt.model === "string" ? receipt.model : void 0,
5301
+ tier: receiptTier(receipt.tier),
5302
+ multiplier: typeof receipt.multiplier === "number" ? receipt.multiplier : void 0,
5303
+ byok: typeof receipt.byok === "boolean" ? receipt.byok : void 0,
5304
+ calibrated: typeof receipt.calibrated === "boolean" ? receipt.calibrated : void 0
5305
+ });
5306
+ }
5307
+ __name(stepBillingView, "stepBillingView");
5308
+ __name3(stepBillingView, "stepBillingView");
5309
+ function runUsage(run, receipts) {
5310
+ const actions = n(run.budget?.spent?.actionsEstimate);
5311
+ const stamped = run.budget?.engine;
5312
+ const priced = (receipts ?? []).filter(isPricedStepReceipt);
5313
+ 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;
5314
+ const seat = engine === "seat";
5315
+ const metering = engine ? "priced" : "flat";
4630
5316
  return {
4631
5317
  creditsUsed: run.budget?.spent?.credits ?? 0,
4632
5318
  actionsEstimate: run.budget?.spent?.actionsEstimate ?? 0,
5319
+ ...seat ? {
5320
+ actionsUsed: actions
5321
+ } : {},
5322
+ metering,
5323
+ ...engine ? {
5324
+ engine
5325
+ } : {},
4633
5326
  steps: run.budget?.spent?.steps ?? 0,
4634
5327
  inputTokens: run.usage?.inputTokens ?? 0,
4635
5328
  outputTokens: run.usage?.outputTokens ?? 0
@@ -4637,6 +5330,20 @@ function runUsage(run) {
4637
5330
  }
4638
5331
  __name(runUsage, "runUsage");
4639
5332
  __name3(runUsage, "runUsage");
5333
+ function runBudgetCap(budget) {
5334
+ const cap = budget?.maxCredits;
5335
+ return typeof cap === "number" && Number.isFinite(cap) && cap > 0 ? cap : void 0;
5336
+ }
5337
+ __name(runBudgetCap, "runBudgetCap");
5338
+ __name3(runBudgetCap, "runBudgetCap");
5339
+ function runBudgetRemaining(budget) {
5340
+ const cap = runBudgetCap(budget);
5341
+ if (cap === void 0) return void 0;
5342
+ const spent = budget?.spent;
5343
+ return Math.max(0, cap - n(spent?.credits) - n(spent?.actionsEstimate) - n(budget?.reserved));
5344
+ }
5345
+ __name(runBudgetRemaining, "runBudgetRemaining");
5346
+ __name3(runBudgetRemaining, "runBudgetRemaining");
4640
5347
  function runCancelView(cancel) {
4641
5348
  if (!cancel) return void 0;
4642
5349
  return {
@@ -4707,6 +5414,7 @@ function toWorkflowRunSummary(run) {
4707
5414
  repairOf: run.repairOf,
4708
5415
  repairRunIds: run.repairRunIds,
4709
5416
  trigger: run.trigger ?? "api",
5417
+ origin: runOrigin(run),
4710
5418
  createdBy: {
4711
5419
  subjectType: principal?.subjectType ?? "system",
4712
5420
  subjectId: principal?.subjectId ?? run.userId ?? ""
@@ -4724,11 +5432,13 @@ function toWorkflowRunSummary(run) {
4724
5432
  usage: runUsage(run),
4725
5433
  // LUA-697: a row persisted before the write seams (#2406 / #2465 / the script tier) leaves scrubbed here too —
4726
5434
  // idempotent on a scrubbed message, bounded input; an empty message falls back to the code.
4727
- error: run.error ? {
5435
+ error: run.error ? pruneUndefined({
4728
5436
  code: run.error.code ?? "error",
4729
5437
  message: scrubStepErrorMessage(run.error.message) ?? run.error.code ?? "error",
4730
- stepId: run.error.stepId
4731
- } : void 0,
5438
+ stepId: run.error.stepId,
5439
+ // LUA-784 (item 3): the unattended pre-start failure's refusal rows (`input_schema_invalid` and kin).
5440
+ issues: runErrorIssues(run.error.issues)
5441
+ }) : void 0,
4732
5442
  kind: "run",
4733
5443
  aclHash: run.aclHash,
4734
5444
  migration: run.migration,
@@ -5381,204 +6091,6 @@ function rebaseItemPointer(pointer, itemsPath, index) {
5381
6091
  }
5382
6092
  __name(rebaseItemPointer, "rebaseItemPointer");
5383
6093
  __name3(rebaseItemPointer, "rebaseItemPointer");
5384
- var APPROVER_SPEC_MAX_USERS = 20;
5385
- var ESCALATION_MAX_HOPS = 3;
5386
- var TemplateBindingSchema = z22.object({
5387
- template: z22.string().min(1).max(2048)
5388
- }).strict();
5389
- var ApproverSpecSchema = z22.union([
5390
- z22.literal("creator"),
5391
- z22.literal("org-admins"),
5392
- z22.object({
5393
- users: z22.union([
5394
- z22.array(z22.string().min(1).max(128)).min(1).max(APPROVER_SPEC_MAX_USERS),
5395
- TemplateBindingSchema
5396
- ])
5397
- }).strict(),
5398
- z22.object({
5399
- role: z22.union([
5400
- z22.string().min(1).max(128),
5401
- TemplateBindingSchema
5402
- ])
5403
- }).strict(),
5404
- z22.object({
5405
- group: z22.union([
5406
- z22.string().min(1).max(128),
5407
- TemplateBindingSchema
5408
- ])
5409
- }).strict(),
5410
- z22.object({
5411
- governance: z22.object({
5412
- policyId: z22.string().min(1).max(128)
5413
- }).strict()
5414
- }).strict()
5415
- ]);
5416
- var FourEyesSchema = z22.object({
5417
- edit: ApproverSpecSchema,
5418
- approve: ApproverSpecSchema
5419
- }).strict();
5420
- var EscalationHopSchema = z22.object({
5421
- escalateTo: ApproverSpecSchema,
5422
- timeoutHours: z22.number().finite().min(1).max(720)
5423
- }).strict();
5424
- var TerminalOutcomeSchema = z22.enum([
5425
- "deny",
5426
- "cancel-run",
5427
- "fail",
5428
- "continue"
5429
- ]);
5430
- var ApprovalOnTimeoutSchema = z22.union([
5431
- TerminalOutcomeSchema,
5432
- EscalationHopSchema,
5433
- z22.array(z22.union([
5434
- TerminalOutcomeSchema,
5435
- EscalationHopSchema
5436
- ])).min(1).max(ESCALATION_MAX_HOPS + 1)
5437
- ]);
5438
- var APPROVER_SPEC_SHAPES = [
5439
- "'creator'",
5440
- "'org-admins'",
5441
- "{users:[userId, \u2026]}",
5442
- "{role:roleName}",
5443
- "{group:groupName}",
5444
- "{governance:{policyId}}"
5445
- ];
5446
- var APPROVER_WRITTEN_MAX = 120;
5447
- var USER_ID_SHAPED_RE = /^[^\s@]{1,128}$/;
5448
- function describeApproverSpecRefusal(spec) {
5449
- const raw = spec === void 0 ? "undefined" : JSON.stringify(spec) ?? String(spec);
5450
- const written = raw.length > APPROVER_WRITTEN_MAX ? `${raw.slice(0, APPROVER_WRITTEN_MAX - 1)}\u2026` : raw;
5451
- const users = typeof spec === "object" && spec !== null ? spec.users : void 0;
5452
- const approver = typeof users === "string" && USER_ID_SHAPED_RE.test(users) ? {
5453
- users: [
5454
- users
5455
- ]
5456
- } : "creator";
5457
- const message = `approver ${written} is not an approver \u2014 legal: ${APPROVER_SPEC_SHAPES.join(" | ")}. 'creator' is the person who started the run: write approver:'creator' for "ask me" / "I approve"; {users:[\u2026]} takes user ids, never emails, names or {type:'user'}` + (approver === "creator" ? "" : `; here: approver:${JSON.stringify(approver)}`);
5458
- return {
5459
- approver,
5460
- written,
5461
- message
5462
- };
5463
- }
5464
- __name(describeApproverSpecRefusal, "describeApproverSpecRefusal");
5465
- __name3(describeApproverSpecRefusal, "describeApproverSpecRefusal");
5466
- var BINDING_ROOTS = [
5467
- "initData",
5468
- "stepResults",
5469
- "requestContext",
5470
- "state"
5471
- ];
5472
- function bindingRootsOk(template22) {
5473
- const refs = [
5474
- ...template22.matchAll(/\$\{\s*([A-Za-z_$][\w$]*)/g)
5475
- ].map((m) => m[1]);
5476
- return refs.length > 0 && refs.every((r) => BINDING_ROOTS.includes(r));
5477
- }
5478
- __name(bindingRootsOk, "bindingRootsOk");
5479
- __name3(bindingRootsOk, "bindingRootsOk");
5480
- function isTemplateBinding(v) {
5481
- return typeof v === "object" && v !== null && typeof v.template === "string";
5482
- }
5483
- __name(isTemplateBinding, "isTemplateBinding");
5484
- __name3(isTemplateBinding, "isTemplateBinding");
5485
- function validateApproverBlock(node, opts = {
5486
- path: "approval"
5487
- }) {
5488
- const issues = [];
5489
- const push = /* @__PURE__ */ __name3((code, path, message, severity = "error") => issues.push({
5490
- code,
5491
- path,
5492
- severity,
5493
- message
5494
- }), "push");
5495
- const checkSpec = /* @__PURE__ */ __name3((spec, path) => {
5496
- const r = ApproverSpecSchema.safeParse(spec);
5497
- if (!r.success) {
5498
- const users = spec?.users;
5499
- if (Array.isArray(users) && users.length > APPROVER_SPEC_MAX_USERS) push("cap-exceeded", path, `at most ${APPROVER_SPEC_MAX_USERS} users`);
5500
- else {
5501
- const refusal = describeApproverSpecRefusal(spec);
5502
- issues.push({
5503
- code: "approver-invalid",
5504
- path,
5505
- severity: "error",
5506
- message: refusal.message,
5507
- repair: {
5508
- approver: refusal.approver,
5509
- written: refusal.written
5510
- }
5511
- });
5512
- }
5513
- return;
5514
- }
5515
- const s = r.data;
5516
- if (typeof s === "object") {
5517
- if ("governance" in s && !opts.governanceEnabled) push("approver-governance-unavailable", path, "governance reviewer routing is not enabled for this deployment");
5518
- if ("group" in s && typeof s.group === "string" && !opts.scimEnabled && opts.idpGroups?.includes(s.group)) push("approver-idp-group-unavailable", path, "IdP-group approvers are not enabled for this deployment");
5519
- const binding = "users" in s ? s.users : "role" in s ? s.role : "group" in s ? s.group : void 0;
5520
- if (isTemplateBinding(binding)) {
5521
- if (!bindingRootsOk(binding.template)) push("approver-binding-invalid", `${path}.template`, "binding root must be initData / stepResults / requestContext / state");
5522
- if ("users" in s && opts.customerReachable) push("approver-binding-customer-reachable", `${path}.users`, "a customer-reachable workflow may not bind its approver list");
5523
- }
5524
- }
5525
- }, "checkSpec");
5526
- if (node.approver !== void 0) checkSpec(node.approver, `${opts.path}.approver`);
5527
- if (node.fourEyes !== void 0) {
5528
- const r = FourEyesSchema.safeParse(node.fourEyes);
5529
- if (!r.success) push("approver-invalid", `${opts.path}.fourEyes`, "fourEyes needs { edit, approve } approver specs");
5530
- else {
5531
- checkSpec(r.data.edit, `${opts.path}.fourEyes.edit`);
5532
- checkSpec(r.data.approve, `${opts.path}.fourEyes.approve`);
5533
- }
5534
- if (!node.editable) push("four-eyes-requires-editable", `${opts.path}.fourEyes`, "fourEyes requires editable:true");
5535
- if (node.approver !== void 0) push("four-eyes-overrides-approver", `${opts.path}.approver`, "fourEyes replaces approver", "warning");
5536
- if (node.itemsPath) push("four-eyes-items-unsupported", `${opts.path}.fourEyes`, "fourEyes cannot combine with itemsPath");
5537
- }
5538
- if (node.excludeInitiator && (node.approver === void 0 || node.approver === "creator") && !node.fourEyes) push("approver-excludes-only-candidate", `${opts.path}.excludeInitiator`, "'creator' with excludeInitiator leaves no approver");
5539
- if (Array.isArray(node.onTimeout)) {
5540
- const chain = node.onTimeout;
5541
- const hops = chain.filter((m) => typeof m === "object" && m !== null && "escalateTo" in m);
5542
- if (hops.length > ESCALATION_MAX_HOPS) push("escalation-chain-too-long", `${opts.path}.onTimeout`, `at most ${ESCALATION_MAX_HOPS} hops`);
5543
- const last = chain[chain.length - 1];
5544
- if (typeof last === "object" && last !== null) push("escalation-chain-not-terminal", `${opts.path}.onTimeout`, "a chain must end in deny | cancel-run | fail");
5545
- hops.forEach((h, i) => checkSpec(h.escalateTo, `${opts.path}.onTimeout[${i}].escalateTo`));
5546
- } else if (typeof node.onTimeout === "object" && node.onTimeout !== null) {
5547
- checkSpec(node.onTimeout.escalateTo, `${opts.path}.onTimeout.escalateTo`);
5548
- }
5549
- return issues;
5550
- }
5551
- __name(validateApproverBlock, "validateApproverBlock");
5552
- __name3(validateApproverBlock, "validateApproverBlock");
5553
- function liftRenderedApprover(row, rendered) {
5554
- const text = (rendered ?? "").trim();
5555
- if (!text) return null;
5556
- if (row === "users") {
5557
- let members = null;
5558
- if (text.startsWith("[")) {
5559
- try {
5560
- members = JSON.parse(text);
5561
- } catch {
5562
- return null;
5563
- }
5564
- } else members = text.split(",").map((s) => s.trim());
5565
- if (!Array.isArray(members) || members.length === 0 || members.length > APPROVER_SPEC_MAX_USERS) return null;
5566
- if (!members.every((m) => typeof m === "string" && m.length > 0 && m.length <= 128)) return null;
5567
- return {
5568
- users: [
5569
- ...new Set(members)
5570
- ].sort()
5571
- };
5572
- }
5573
- if (text.length > 128 || text.startsWith("[") || text.startsWith("{")) return null;
5574
- return row === "role" ? {
5575
- role: text
5576
- } : {
5577
- group: text
5578
- };
5579
- }
5580
- __name(liftRenderedApprover, "liftRenderedApprover");
5581
- __name3(liftRenderedApprover, "liftRenderedApprover");
5582
6094
  var WORKFLOW_ENV_OVERLAY_MAX_KEYS = 64;
5583
6095
  var WORKFLOW_ENV_OVERLAY_MAX_VALUE_BYTES = 4096;
5584
6096
  var WORKFLOW_ENV_TEMPLATE_SECRET_KEY_RE = /(SECRET|TOKEN|KEY|PASSWORD)$/;
@@ -5862,7 +6374,6 @@ function* singleStepsOf(entry) {
5862
6374
  return;
5863
6375
  case "workflow":
5864
6376
  yield entry;
5865
- if (Array.isArray(entry.graph)) yield* singleStepsOf(entry.graph[1]);
5866
6377
  return;
5867
6378
  case "parallel":
5868
6379
  case "conditional":
@@ -6021,6 +6532,10 @@ var assertPredicate = /* @__PURE__ */ __name((p, where) => {
6021
6532
  }, "assertPredicate");
6022
6533
  var assertRetry = /* @__PURE__ */ __name((r, id) => {
6023
6534
  if (!r) return;
6535
+ if (r.maxAttempts !== void 0 && !isWithinWorkflowRetryAttempts(r.maxAttempts)) {
6536
+ const over = typeof r.maxAttempts === "number" && r.maxAttempts > WORKFLOW_RETRY_MAX_ATTEMPTS;
6537
+ throw new LuaWorkflowBuildError(over ? "cap-exceeded" : "invalid-envelope", `"${id}": ${workflowRetryMaxAttemptsMessage(r.maxAttempts)}`);
6538
+ }
6024
6539
  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
6540
  if (r.maxBackoffSeconds !== void 0) {
6026
6541
  if (r.backoff !== "exponential") throw new LuaWorkflowBuildError("backoff-invalid", `"${id}": retry.maxBackoffSeconds is only meaningful with backoff:'exponential'`);
@@ -6170,14 +6685,13 @@ function stepNodeOf(s) {
6170
6685
  __name(stepNodeOf, "stepNodeOf");
6171
6686
  function materializeEntry(entry, steps) {
6172
6687
  const single = /* @__PURE__ */ __name((n2) => {
6173
- if (n2.type === "step" && steps[n2.step.id]) return stepNodeOf(steps[n2.step.id]);
6174
- if (n2.type === "workflow" && n2.workflowId === WORKFLOW_ARM_SUBRUN_ID && n2.graph) return {
6175
- ...n2,
6176
- graph: [
6177
- n2.graph[0],
6178
- single(n2.graph[1])
6179
- ]
6180
- };
6688
+ if (n2.type === "step" && steps[n2.step.id]) {
6689
+ const node = stepNodeOf(steps[n2.step.id]);
6690
+ return n2.input !== void 0 ? {
6691
+ ...node,
6692
+ input: n2.input
6693
+ } : node;
6694
+ }
6181
6695
  return n2;
6182
6696
  }, "single");
6183
6697
  switch (entry.type) {