lua-cli 3.32.3 → 3.32.5

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"
@@ -1160,6 +1248,7 @@ var DeviceBindingSchema = z2.object({
1160
1248
  }
1161
1249
  });
1162
1250
  var IdSchema = z2.string().min(1).max(256);
1251
+ var SESSION_AUTH_TIME_MAX_S = 4102444800;
1163
1252
  var PrincipalDescriptorSchema = z2.object({
1164
1253
  subjectType: SubjectTypeSchema,
1165
1254
  subjectId: IdSchema
@@ -1208,7 +1297,8 @@ var GeneralPrincipalContextSchema = z2.object({
1208
1297
  owner: PrincipalOwnerSchema.optional(),
1209
1298
  compatibility: z2.object({
1210
1299
  mode: z2.literal("legacy-owner-delegation")
1211
- }).strict().optional()
1300
+ }).strict().optional(),
1301
+ authTime: z2.number().int().nonnegative().max(SESSION_AUTH_TIME_MAX_S).optional()
1212
1302
  }).strict();
1213
1303
  var DeviceCredentialPrincipalContextSchema = z2.object({
1214
1304
  version: z2.literal(1),
@@ -1274,6 +1364,13 @@ function hasDeviceCredentialType(value3) {
1274
1364
  }
1275
1365
  __name(hasDeviceCredentialType, "hasDeviceCredentialType");
1276
1366
  __name2(hasDeviceCredentialType, "hasDeviceCredentialType");
1367
+ function sessionAuthTime(context) {
1368
+ if (!context || context.credential.type !== "firstPartySession") return void 0;
1369
+ const authTime = context.authTime;
1370
+ return typeof authTime === "number" && Number.isInteger(authTime) && authTime >= 0 && authTime <= SESSION_AUTH_TIME_MAX_S ? authTime : void 0;
1371
+ }
1372
+ __name(sessionAuthTime, "sessionAuthTime");
1373
+ __name2(sessionAuthTime, "sessionAuthTime");
1277
1374
  function isTypedApiKeyPrincipal(context) {
1278
1375
  return context?.subject.subjectType === "apiKey" && context.credential.type === "apiKey" && !context.compatibility;
1279
1376
  }
@@ -1676,6 +1773,47 @@ function scheduledWorkflowRunId(jobId, scheduledTime) {
1676
1773
  }
1677
1774
  __name(scheduledWorkflowRunId, "scheduledWorkflowRunId");
1678
1775
  __name2(scheduledWorkflowRunId, "scheduledWorkflowRunId");
1776
+ var WORKFLOW_SCHEDULE_KEY_MAX = 128;
1777
+ function renderWorkflowScheduleKeyTemplate(template3, ctx) {
1778
+ if (!template3) return void 0;
1779
+ const read = /* @__PURE__ */ __name2((path) => path.split(".").reduce((o, k) => o && typeof o === "object" ? o[k] : void 0, ctx.input), "read");
1780
+ let unresolved = false;
1781
+ const out = template3.replace(/\$\{\s*([a-zA-Z0-9_.]+)\s*\}/g, (_m, expr) => {
1782
+ let v = "";
1783
+ if (expr === "scheduledTime") v = ctx.scheduledTime ?? "";
1784
+ else if (expr.startsWith("input.")) v = read(expr.slice("input.".length));
1785
+ const s = v === void 0 || v === null ? "" : String(v);
1786
+ if (s === "") unresolved = true;
1787
+ return s;
1788
+ });
1789
+ if (unresolved) return void 0;
1790
+ const key = out.slice(0, WORKFLOW_SCHEDULE_KEY_MAX);
1791
+ return key && /^[A-Za-z0-9:_\-.\/]+$/.test(key) ? key : void 0;
1792
+ }
1793
+ __name(renderWorkflowScheduleKeyTemplate, "renderWorkflowScheduleKeyTemplate");
1794
+ __name2(renderWorkflowScheduleKeyTemplate, "renderWorkflowScheduleKeyTemplate");
1795
+ var WORKFLOW_SCHEDULE_IDEMPOTENCY_KEY_PREFIX = "sched:";
1796
+ function scheduledWorkflowIdempotencyKey(jobId, rendered) {
1797
+ const head = `${WORKFLOW_SCHEDULE_IDEMPOTENCY_KEY_PREFIX}${jobId}:`;
1798
+ if (head.length + rendered.length <= WORKFLOW_SCHEDULE_KEY_MAX) return `${head}${rendered}`;
1799
+ const digest = stableKeyDigest(rendered);
1800
+ const room = WORKFLOW_SCHEDULE_KEY_MAX - head.length - digest.length - 1;
1801
+ return `${head}${rendered.slice(0, Math.max(0, room))}~${digest}`;
1802
+ }
1803
+ __name(scheduledWorkflowIdempotencyKey, "scheduledWorkflowIdempotencyKey");
1804
+ __name2(scheduledWorkflowIdempotencyKey, "scheduledWorkflowIdempotencyKey");
1805
+ function stableKeyDigest(s) {
1806
+ let a = 2166136261;
1807
+ let b = 84696351;
1808
+ for (let i = 0; i < s.length; i++) {
1809
+ const c = s.charCodeAt(i);
1810
+ a = Math.imul(a ^ c, 16777619);
1811
+ b = Math.imul(b ^ c, 16777619) ^ b >>> 13;
1812
+ }
1813
+ return (a >>> 0).toString(16).padStart(8, "0") + (b >>> 0).toString(16).padStart(8, "0");
1814
+ }
1815
+ __name(stableKeyDigest, "stableKeyDigest");
1816
+ __name2(stableKeyDigest, "stableKeyDigest");
1679
1817
  var WORKFLOW_OPERATION_ID_PREFIX = "wf:";
1680
1818
  function workflowOperationId(runId, stepId, billingEpoch) {
1681
1819
  return `${WORKFLOW_OPERATION_ID_PREFIX}${runId}:${stepId}:${billingEpoch}`;
@@ -2424,6 +2562,75 @@ function extractSingleJsonValue(text) {
2424
2562
  }
2425
2563
  __name(extractSingleJsonValue, "extractSingleJsonValue");
2426
2564
  __name2(extractSingleJsonValue, "extractSingleJsonValue");
2565
+ var DEFAULT_ON_AGENT_FEATURES = [
2566
+ "workflows",
2567
+ "workflowCompose",
2568
+ "observationalMemory"
2569
+ ];
2570
+ function agentFeatureCatalogDefault(featureName) {
2571
+ return DEFAULT_ON_AGENT_FEATURES.includes(featureName);
2572
+ }
2573
+ __name(agentFeatureCatalogDefault, "agentFeatureCatalogDefault");
2574
+ __name2(agentFeatureCatalogDefault, "agentFeatureCatalogDefault");
2575
+ function hasExplicitFeatureActive(row) {
2576
+ return typeof row?.active === "boolean";
2577
+ }
2578
+ __name(hasExplicitFeatureActive, "hasExplicitFeatureActive");
2579
+ __name2(hasExplicitFeatureActive, "hasExplicitFeatureActive");
2580
+ function effectiveFeatureActive(row, catalogDefault) {
2581
+ return hasExplicitFeatureActive(row) ? row.active : catalogDefault;
2582
+ }
2583
+ __name(effectiveFeatureActive, "effectiveFeatureActive");
2584
+ __name2(effectiveFeatureActive, "effectiveFeatureActive");
2585
+ function resolveEffectiveFeature(row, catalogDefault) {
2586
+ return hasExplicitFeatureActive(row) ? {
2587
+ active: row.active,
2588
+ source: "agent",
2589
+ default: catalogDefault
2590
+ } : {
2591
+ active: catalogDefault,
2592
+ source: "default",
2593
+ default: catalogDefault
2594
+ };
2595
+ }
2596
+ __name(resolveEffectiveFeature, "resolveEffectiveFeature");
2597
+ __name2(resolveEffectiveFeature, "resolveEffectiveFeature");
2598
+ function isFeatureRow(value3) {
2599
+ return typeof value3 === "object" && value3 !== null;
2600
+ }
2601
+ __name(isFeatureRow, "isFeatureRow");
2602
+ __name2(isFeatureRow, "isFeatureRow");
2603
+ function effectiveAgentFeatureRows(base, override) {
2604
+ const merged = /* @__PURE__ */ new Map();
2605
+ for (const [name, row] of Object.entries(base ?? {})) {
2606
+ if (isFeatureRow(row)) merged.set(name, {
2607
+ row,
2608
+ origin: "baseAgent"
2609
+ });
2610
+ }
2611
+ for (const [name, row] of Object.entries(override ?? {})) {
2612
+ if (isFeatureRow(row)) merged.set(name, {
2613
+ row,
2614
+ origin: "subAgent"
2615
+ });
2616
+ }
2617
+ return {
2618
+ rows: Object.fromEntries([
2619
+ ...merged
2620
+ ].map(([name, e]) => [
2621
+ name,
2622
+ e.row
2623
+ ])),
2624
+ origins: Object.fromEntries([
2625
+ ...merged
2626
+ ].map(([name, e]) => [
2627
+ name,
2628
+ e.origin
2629
+ ]))
2630
+ };
2631
+ }
2632
+ __name(effectiveAgentFeatureRows, "effectiveAgentFeatureRows");
2633
+ __name2(effectiveAgentFeatureRows, "effectiveAgentFeatureRows");
2427
2634
 
2428
2635
  // ../workflow-graph/dist/index.mjs
2429
2636
  import { createHash } from "crypto";
@@ -2724,7 +2931,211 @@ var fromKnowledge = /* @__PURE__ */ __name3((k) => ({
2724
2931
  }), "fromKnowledge");
2725
2932
  var SideEffectsSchema = z4.enum(WORKFLOW_SIDE_EFFECTS);
2726
2933
  var JobResourcesSchema = z4.enum(WORKFLOW_JOB_RESOURCES);
2727
- var WORKFLOW_ARM_SUBRUN_ID = "$arm";
2934
+ var APPROVER_SPEC_MAX_USERS = 20;
2935
+ var ESCALATION_MAX_HOPS = 3;
2936
+ var TemplateBindingSchema = z22.object({
2937
+ template: z22.string().min(1).max(2048)
2938
+ }).strict();
2939
+ var ApproverSpecSchema = z22.union([
2940
+ z22.literal("creator"),
2941
+ z22.literal("org-admins"),
2942
+ z22.object({
2943
+ users: z22.union([
2944
+ z22.array(z22.string().min(1).max(128)).min(1).max(APPROVER_SPEC_MAX_USERS),
2945
+ TemplateBindingSchema
2946
+ ])
2947
+ }).strict(),
2948
+ z22.object({
2949
+ role: z22.union([
2950
+ z22.string().min(1).max(128),
2951
+ TemplateBindingSchema
2952
+ ])
2953
+ }).strict(),
2954
+ z22.object({
2955
+ group: z22.union([
2956
+ z22.string().min(1).max(128),
2957
+ TemplateBindingSchema
2958
+ ])
2959
+ }).strict(),
2960
+ z22.object({
2961
+ governance: z22.object({
2962
+ policyId: z22.string().min(1).max(128)
2963
+ }).strict()
2964
+ }).strict()
2965
+ ]);
2966
+ var FourEyesSchema = z22.object({
2967
+ edit: ApproverSpecSchema,
2968
+ approve: ApproverSpecSchema
2969
+ }).strict();
2970
+ var EscalationHopSchema = z22.object({
2971
+ escalateTo: ApproverSpecSchema,
2972
+ timeoutHours: z22.number().finite().min(1).max(720)
2973
+ }).strict();
2974
+ var TerminalOutcomeSchema = z22.enum([
2975
+ "deny",
2976
+ "cancel-run",
2977
+ "fail",
2978
+ "continue"
2979
+ ]);
2980
+ var ApprovalOnTimeoutSchema = z22.union([
2981
+ TerminalOutcomeSchema,
2982
+ EscalationHopSchema,
2983
+ z22.array(z22.union([
2984
+ TerminalOutcomeSchema,
2985
+ EscalationHopSchema
2986
+ ])).min(1).max(ESCALATION_MAX_HOPS + 1)
2987
+ ]);
2988
+ var APPROVER_SPEC_SHAPES = [
2989
+ "'creator'",
2990
+ "'org-admins'",
2991
+ "{users:[userId, \u2026]}",
2992
+ "{role:roleName}",
2993
+ "{group:groupName}",
2994
+ "{governance:{policyId}}"
2995
+ ];
2996
+ var APPROVER_WRITTEN_MAX = 120;
2997
+ var USER_ID_SHAPED_RE = /^[^\s@]{1,128}$/;
2998
+ function describeApproverSpecRefusal(spec) {
2999
+ const raw = spec === void 0 ? "undefined" : JSON.stringify(spec) ?? String(spec);
3000
+ const written = raw.length > APPROVER_WRITTEN_MAX ? `${raw.slice(0, APPROVER_WRITTEN_MAX - 1)}\u2026` : raw;
3001
+ const users = typeof spec === "object" && spec !== null ? spec.users : void 0;
3002
+ const approver = typeof users === "string" && USER_ID_SHAPED_RE.test(users) ? {
3003
+ users: [
3004
+ users
3005
+ ]
3006
+ } : "creator";
3007
+ 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)}`);
3008
+ return {
3009
+ approver,
3010
+ written,
3011
+ message
3012
+ };
3013
+ }
3014
+ __name(describeApproverSpecRefusal, "describeApproverSpecRefusal");
3015
+ __name3(describeApproverSpecRefusal, "describeApproverSpecRefusal");
3016
+ var BINDING_ROOTS = [
3017
+ "initData",
3018
+ "stepResults",
3019
+ "requestContext",
3020
+ "state"
3021
+ ];
3022
+ function bindingRootsOk(template22) {
3023
+ const refs = [
3024
+ ...template22.matchAll(/\$\{\s*([A-Za-z_$][\w$]*)/g)
3025
+ ].map((m) => m[1]);
3026
+ return refs.length > 0 && refs.every((r) => BINDING_ROOTS.includes(r));
3027
+ }
3028
+ __name(bindingRootsOk, "bindingRootsOk");
3029
+ __name3(bindingRootsOk, "bindingRootsOk");
3030
+ function isTemplateBinding(v) {
3031
+ return typeof v === "object" && v !== null && typeof v.template === "string";
3032
+ }
3033
+ __name(isTemplateBinding, "isTemplateBinding");
3034
+ __name3(isTemplateBinding, "isTemplateBinding");
3035
+ function approvalEditable(node) {
3036
+ if (node.editable === true) return true;
3037
+ if (node.editable === false) return false;
3038
+ return Array.isArray(node.editablePaths) && node.editablePaths.length > 0;
3039
+ }
3040
+ __name(approvalEditable, "approvalEditable");
3041
+ __name3(approvalEditable, "approvalEditable");
3042
+ function validateApproverBlock(node, opts = {
3043
+ path: "approval"
3044
+ }) {
3045
+ const issues = [];
3046
+ const push = /* @__PURE__ */ __name3((code, path, message, severity = "error") => issues.push({
3047
+ code,
3048
+ path,
3049
+ severity,
3050
+ message
3051
+ }), "push");
3052
+ const checkSpec = /* @__PURE__ */ __name3((spec, path) => {
3053
+ const r = ApproverSpecSchema.safeParse(spec);
3054
+ if (!r.success) {
3055
+ const users = spec?.users;
3056
+ if (Array.isArray(users) && users.length > APPROVER_SPEC_MAX_USERS) push("cap-exceeded", path, `at most ${APPROVER_SPEC_MAX_USERS} users`);
3057
+ else {
3058
+ const refusal = describeApproverSpecRefusal(spec);
3059
+ issues.push({
3060
+ code: "approver-invalid",
3061
+ path,
3062
+ severity: "error",
3063
+ message: refusal.message,
3064
+ repair: {
3065
+ approver: refusal.approver,
3066
+ written: refusal.written
3067
+ }
3068
+ });
3069
+ }
3070
+ return;
3071
+ }
3072
+ const s = r.data;
3073
+ if (typeof s === "object") {
3074
+ if ("governance" in s && !opts.governanceEnabled) push("approver-governance-unavailable", path, "governance reviewer routing is not enabled for this deployment");
3075
+ 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");
3076
+ const binding = "users" in s ? s.users : "role" in s ? s.role : "group" in s ? s.group : void 0;
3077
+ if (isTemplateBinding(binding)) {
3078
+ if (!bindingRootsOk(binding.template)) push("approver-binding-invalid", `${path}.template`, "binding root must be initData / stepResults / requestContext / state");
3079
+ if ("users" in s && opts.customerReachable) push("approver-binding-customer-reachable", `${path}.users`, "a customer-reachable workflow may not bind its approver list");
3080
+ }
3081
+ }
3082
+ }, "checkSpec");
3083
+ if (node.approver !== void 0) checkSpec(node.approver, `${opts.path}.approver`);
3084
+ if (node.fourEyes !== void 0) {
3085
+ const r = FourEyesSchema.safeParse(node.fourEyes);
3086
+ if (!r.success) push("approver-invalid", `${opts.path}.fourEyes`, "fourEyes needs { edit, approve } approver specs");
3087
+ else {
3088
+ checkSpec(r.data.edit, `${opts.path}.fourEyes.edit`);
3089
+ checkSpec(r.data.approve, `${opts.path}.fourEyes.approve`);
3090
+ }
3091
+ if (!approvalEditable(node)) push("four-eyes-requires-editable", `${opts.path}.fourEyes`, "fourEyes requires editable:true");
3092
+ if (node.approver !== void 0) push("four-eyes-overrides-approver", `${opts.path}.approver`, "fourEyes replaces approver", "warning");
3093
+ if (node.itemsPath) push("four-eyes-items-unsupported", `${opts.path}.fourEyes`, "fourEyes cannot combine with itemsPath");
3094
+ }
3095
+ 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");
3096
+ if (Array.isArray(node.onTimeout)) {
3097
+ const chain = node.onTimeout;
3098
+ const hops = chain.filter((m) => typeof m === "object" && m !== null && "escalateTo" in m);
3099
+ if (hops.length > ESCALATION_MAX_HOPS) push("escalation-chain-too-long", `${opts.path}.onTimeout`, `at most ${ESCALATION_MAX_HOPS} hops`);
3100
+ const last = chain[chain.length - 1];
3101
+ if (typeof last === "object" && last !== null) push("escalation-chain-not-terminal", `${opts.path}.onTimeout`, "a chain must end in deny | cancel-run | fail");
3102
+ hops.forEach((h, i) => checkSpec(h.escalateTo, `${opts.path}.onTimeout[${i}].escalateTo`));
3103
+ } else if (typeof node.onTimeout === "object" && node.onTimeout !== null) {
3104
+ checkSpec(node.onTimeout.escalateTo, `${opts.path}.onTimeout.escalateTo`);
3105
+ }
3106
+ return issues;
3107
+ }
3108
+ __name(validateApproverBlock, "validateApproverBlock");
3109
+ __name3(validateApproverBlock, "validateApproverBlock");
3110
+ function liftRenderedApprover(row, rendered) {
3111
+ const text = (rendered ?? "").trim();
3112
+ if (!text) return null;
3113
+ if (row === "users") {
3114
+ let members = null;
3115
+ if (text.startsWith("[")) {
3116
+ try {
3117
+ members = JSON.parse(text);
3118
+ } catch {
3119
+ return null;
3120
+ }
3121
+ } else members = text.split(",").map((s) => s.trim());
3122
+ if (!Array.isArray(members) || members.length === 0 || members.length > APPROVER_SPEC_MAX_USERS) return null;
3123
+ if (!members.every((m) => typeof m === "string" && m.length > 0 && m.length <= 128)) return null;
3124
+ return {
3125
+ users: [
3126
+ ...new Set(members)
3127
+ ].sort()
3128
+ };
3129
+ }
3130
+ if (text.length > 128 || text.startsWith("[") || text.startsWith("{")) return null;
3131
+ return row === "role" ? {
3132
+ role: text
3133
+ } : {
3134
+ group: text
3135
+ };
3136
+ }
3137
+ __name(liftRenderedApprover, "liftRenderedApprover");
3138
+ __name3(liftRenderedApprover, "liftRenderedApprover");
2728
3139
  var WORKSPACE_TEMPLATE_EXPR_RE = /^\$\{\s*(?:initData|input)\.([^}]+?)\s*\}$/;
2729
3140
  function workspaceTemplatePath(template22) {
2730
3141
  const key = template22.trim();
@@ -2752,6 +3163,11 @@ function sleepUntilUnsupportedMessage(id) {
2752
3163
  }
2753
3164
  __name(sleepUntilUnsupportedMessage, "sleepUntilUnsupportedMessage");
2754
3165
  __name3(sleepUntilUnsupportedMessage, "sleepUntilUnsupportedMessage");
3166
+ function armSubrunUnsupportedMessage(id, workflowId) {
3167
+ 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)`;
3168
+ }
3169
+ __name(armSubrunUnsupportedMessage, "armSubrunUnsupportedMessage");
3170
+ __name3(armSubrunUnsupportedMessage, "armSubrunUnsupportedMessage");
2755
3171
  var WORKFLOW_CAPS_DEFAULT = Object.freeze({
2756
3172
  maxParallelArms: 16,
2757
3173
  maxForeachConcurrency: 16,
@@ -2804,7 +3220,6 @@ function fillSingle(node) {
2804
3220
  fillPolicy(node, WORKFLOW_STEP_DEFAULT_TIMEOUT_SECONDS);
2805
3221
  return;
2806
3222
  case "workflow":
2807
- if (node.workflowId === WORKFLOW_ARM_SUBRUN_ID && Array.isArray(node.graph) && node.graph[1]) fillSingle(node.graph[1]);
2808
3223
  return;
2809
3224
  }
2810
3225
  }
@@ -2994,8 +3409,14 @@ function nodeStepRefs(entry) {
2994
3409
  case "agent": {
2995
3410
  const a = entry;
2996
3411
  const p = a.promptTemplate;
2997
- return typeof p === "string" ? templateStepRefs(p) : p && "template" in p ? templateStepRefs(p.template) : [];
3412
+ const prompt = typeof p === "string" ? templateStepRefs(p) : p && "template" in p ? templateStepRefs(p.template) : [];
3413
+ return [
3414
+ ...prompt,
3415
+ ...mapConfigStepRefs(a.input)
3416
+ ];
2998
3417
  }
3418
+ case "step":
3419
+ return mapConfigStepRefs(entry.input);
2999
3420
  case "tool":
3000
3421
  return mapConfigStepRefs(entry.input);
3001
3422
  case "workflow":
@@ -3114,7 +3535,7 @@ function validateLuaExtensions(g, caps = WORKFLOW_CAPS_DEFAULT, opts = {
3114
3535
  const id = singleId(node);
3115
3536
  const unknown = unknownWorkflowRetryMembers(r);
3116
3537
  if (unknown.length) err("invalid-envelope", workflowRetryUnknownMembersMessage(unknown), `${path}.retry`, id);
3117
- if (r.maxAttempts !== void 0 && !isWithinWorkflowRetryAttempts(r.maxAttempts)) {
3538
+ if (!isWithinWorkflowRetryAttempts(r.maxAttempts)) {
3118
3539
  const over = typeof r.maxAttempts === "number" && r.maxAttempts > WORKFLOW_RETRY_MAX_ATTEMPTS;
3119
3540
  err(over ? "cap-exceeded" : "invalid-envelope", workflowRetryMaxAttemptsMessage(r.maxAttempts), `${path}.retry.maxAttempts`, id);
3120
3541
  }
@@ -3214,6 +3635,21 @@ function validateLuaExtensions(g, caps = WORKFLOW_CAPS_DEFAULT, opts = {
3214
3635
  err("job-tier-provider-unsupported", `model provider '${provider}' is outside LUA_WF_JOB_PROVIDERS [${opts.policy.jobProviders.join(", ")}]`, `${path}.model`, id);
3215
3636
  }
3216
3637
  }, "checkTier");
3638
+ const checkModel = /* @__PURE__ */ __name3((node, path) => {
3639
+ if (node.type !== "agent" || typeof node.model !== "string") return;
3640
+ const registry = opts.approvedModels;
3641
+ if (registry === void 0) return;
3642
+ const id = singleId(node);
3643
+ if (registry === "unavailable") {
3644
+ const pin = node.model.trim();
3645
+ if (pin && !normalizeModelId(pin, []).ok) {
3646
+ 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);
3647
+ }
3648
+ return;
3649
+ }
3650
+ const resolved = normalizeModelId(node.model, registry);
3651
+ if (!resolved.ok) err("model-unresolved", modelUnresolvedMessage(resolved), `${path}.model`, id);
3652
+ }, "checkModel");
3217
3653
  const checkWorkspace = /* @__PURE__ */ __name3((node, path) => {
3218
3654
  const id = singleId(node);
3219
3655
  const ws = workspaceOf(node);
@@ -3266,38 +3702,29 @@ function validateLuaExtensions(g, caps = WORKFLOW_CAPS_DEFAULT, opts = {
3266
3702
  }
3267
3703
  }, "checkMapMembers");
3268
3704
  const checkInputShape = /* @__PURE__ */ __name3((node, path) => {
3269
- if (node.type !== "tool" && node.type !== "workflow") return;
3270
3705
  const input = node.input;
3271
3706
  if (input === void 0) return;
3707
+ const id = singleId(node);
3272
3708
  if (input !== null && typeof input === "object" && !Array.isArray(input)) {
3273
- checkMapMembers(input, `${path}.input`, node.id);
3709
+ checkMapMembers(input, `${path}.input`, id);
3274
3710
  return;
3275
3711
  }
3276
- err("invalid-envelope", `\`input\` must be an object map \u2014 each member a binding descriptor ({initData:true, path} | {step, path} | {value} | {template} | {requestContextPath}) or a JSON literal (got ${JSON.stringify(input)})`, `${path}.input`, node.id);
3712
+ 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);
3277
3713
  }, "checkInputShape");
3714
+ const checkBodyInput = /* @__PURE__ */ __name3((body, path, container) => {
3715
+ if (body.type === "workflow" || body.input === void 0) return;
3716
+ 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));
3717
+ }, "checkBodyInput");
3278
3718
  const checkSingle = /* @__PURE__ */ __name3((node, path, depth) => {
3279
3719
  recordOutputSchema(node);
3280
- if (node.type === "workflow" && node.workflowId === WORKFLOW_ARM_SUBRUN_ID) {
3720
+ if (node.type === "workflow" && (typeof node.workflowId !== "string" || node.workflowId.length === 0)) {
3281
3721
  checkId(node.id, path);
3282
- const body = node.graph;
3283
- if (!Array.isArray(body) || body.length !== 2 || body[0]?.type !== "mapping" || !body[1]) {
3284
- err("container-arm-empty", "an implicit arm subrun needs a [mapping, step] body", `${path}.graph`, node.id);
3285
- return;
3286
- }
3287
- if (body[1].type === "mapping") {
3288
- err("container-arm-empty", "a bare mapping arm has nothing to run", `${path}.graph.1`, node.id);
3289
- return;
3290
- }
3291
- const inner = body[1];
3292
- if (isHitlNode(inner)) {
3293
- err("node-type-unsupported-in-container", workflowHitlArmShapeMessage(inner.type, inner.id, "mapped-arm"), `${path}.graph.1`, inner.id);
3294
- return;
3295
- }
3296
- upstream.add(singleId(body[1]));
3297
- checkArm(body[0], `${path}.graph.0`, depth, "parallel");
3298
- checkSingle(body[1], `${path}.graph.1`, depth);
3299
- upstream.add(body[0].id);
3300
- upstream.add(singleId(body[1]));
3722
+ err("invalid-envelope", `\`workflowId\` must be a non-empty string naming the workflow to start (got ${JSON.stringify(node.workflowId)})`, `${path}.workflowId`, node.id);
3723
+ return;
3724
+ }
3725
+ if (node.type === "workflow" && (node.workflowId.startsWith("$") || Array.isArray(node.graph))) {
3726
+ checkId(node.id, path);
3727
+ err("node-type-unsupported-by-engine", armSubrunUnsupportedMessage(node.id, node.workflowId), path, node.id);
3301
3728
  return;
3302
3729
  }
3303
3730
  checkId(singleId(node), path);
@@ -3305,6 +3732,7 @@ function validateLuaExtensions(g, caps = WORKFLOW_CAPS_DEFAULT, opts = {
3305
3732
  checkInputShape(node, path);
3306
3733
  checkTimeout(node, path);
3307
3734
  checkTier(node, path);
3735
+ checkModel(node, path);
3308
3736
  checkRetry(node, path);
3309
3737
  checkWorkspace(node, path);
3310
3738
  if (!opts.static) {
@@ -3327,7 +3755,7 @@ function validateLuaExtensions(g, caps = WORKFLOW_CAPS_DEFAULT, opts = {
3327
3755
  if (node.type === "workflow" && node.kind === "subrun" && depth > caps.maxNestingDepth) {
3328
3756
  err("cap-exceeded", `nesting depth ${depth} exceeds ${caps.maxNestingDepth}`, path, node.id);
3329
3757
  }
3330
- if (node.type === "workflow" && node.workflowId !== WORKFLOW_ARM_SUBRUN_ID && typeof g.definition?.id === "string" && node.workflowId === g.definition.id) {
3758
+ if (node.type === "workflow" && typeof g.definition?.id === "string" && node.workflowId === g.definition.id) {
3331
3759
  err("subrun-cycle", `"${node.id}" starts "${node.workflowId}", which is this workflow itself`, path, node.id);
3332
3760
  }
3333
3761
  for (const ref of nodeStepRefs(node)) {
@@ -3348,11 +3776,14 @@ function validateLuaExtensions(g, caps = WORKFLOW_CAPS_DEFAULT, opts = {
3348
3776
  if (a.approver === "creator" && a.excludeInitiator === true) {
3349
3777
  err("approver-excludes-only-candidate", "approver:'creator' with excludeInitiator:true always excludes the only candidate", path, a.id);
3350
3778
  }
3351
- if (a.fourEyes !== void 0 && a.editable !== true) {
3779
+ const editable = approvalEditable(a);
3780
+ if (a.fourEyes !== void 0 && !editable) {
3352
3781
  err("four-eyes-requires-editable", "`fourEyes` requires editable:true", `${path}.fourEyes`, a.id);
3353
3782
  }
3354
- if ((a.editablePaths !== void 0 || a.editedPayloadSchema !== void 0) && a.editable !== true) {
3355
- err("editable-path-invalid", "`editablePaths` / `editedPayloadSchema` require editable:true", `${path}.editablePaths`, a.id);
3783
+ if (a.editable === false && Array.isArray(a.editablePaths) && a.editablePaths.length > 0) {
3784
+ err("editable-path-invalid", "`editablePaths` beside editable:false is contradictory \u2014 drop the paths or set editable:true", `${path}.editablePaths`, a.id);
3785
+ } else if ((a.editablePaths !== void 0 || a.editedPayloadSchema !== void 0) && !editable) {
3786
+ err("editable-path-invalid", "`editablePaths` / `editedPayloadSchema` require editable:true (a non-empty editablePaths implies it)", `${path}.editablePaths`, a.id);
3356
3787
  }
3357
3788
  for (const p of a.editablePaths ?? []) {
3358
3789
  if (!EDITABLE_PATH_RE.test(p)) err("editable-path-invalid", `editablePaths entry "${p}" is outside the seg(.seg)*[*]/[n] grammar`, `${path}.editablePaths`, a.id);
@@ -3533,6 +3964,7 @@ function validateLuaExtensions(g, caps = WORKFLOW_CAPS_DEFAULT, opts = {
3533
3964
  } else checkHitlArm(f.step, `${path}.step`, "foreach");
3534
3965
  declared.push(f.step.id);
3535
3966
  } else {
3967
+ checkBodyInput(f.step, `${path}.step`, "foreach");
3536
3968
  checkSingle(f.step, `${path}.step`, o.chunk ? 2 : 1);
3537
3969
  declared.push(singleId(f.step));
3538
3970
  }
@@ -3553,6 +3985,7 @@ function validateLuaExtensions(g, caps = WORKFLOW_CAPS_DEFAULT, opts = {
3553
3985
  checkHitlArm(l.step, `${path}.step`, "loop");
3554
3986
  declared.push(l.step.id);
3555
3987
  } else {
3988
+ checkBodyInput(l.step, `${path}.step`, "loop");
3556
3989
  checkSingle(l.step, `${path}.step`, 1);
3557
3990
  declared.push(singleId(l.step));
3558
3991
  }
@@ -4220,21 +4653,14 @@ function isContinuedFailureValue(v) {
4220
4653
  __name(isContinuedFailureValue, "isContinuedFailureValue");
4221
4654
  __name3(isContinuedFailureValue, "isContinuedFailureValue");
4222
4655
  var isHitlNode2 = /* @__PURE__ */ __name3((n2) => isWorkflowHitlEntryType(n2.type), "isHitlNode");
4223
- function lowerContainerArm(mapping, step22) {
4224
- const stepId = nodeIdOf(step22);
4656
+ function inlineContainerArm(mapping, step22) {
4225
4657
  return {
4226
- type: "workflow",
4227
- id: `${stepId}_arm`,
4228
- workflowId: WORKFLOW_ARM_SUBRUN_ID,
4229
- kind: "subrun",
4230
- graph: [
4231
- mapping,
4232
- step22
4233
- ]
4658
+ ...step22,
4659
+ input: parseMapConfig(mapping.mapConfig, mapping.id)
4234
4660
  };
4235
4661
  }
4236
- __name(lowerContainerArm, "lowerContainerArm");
4237
- __name3(lowerContainerArm, "lowerContainerArm");
4662
+ __name(inlineContainerArm, "inlineContainerArm");
4663
+ __name3(inlineContainerArm, "inlineContainerArm");
4238
4664
  var nodeIdOf = /* @__PURE__ */ __name3((n2) => n2.type === "step" ? n2.step.id : n2.id, "nodeIdOf");
4239
4665
  function entryIds(entry) {
4240
4666
  switch (entry.type) {
@@ -4305,6 +4731,27 @@ function resolvePlacements(calls) {
4305
4731
  break;
4306
4732
  }
4307
4733
  });
4734
+ const armMapPlacementIssue = /* @__PURE__ */ __name3((node, ref, i, container) => {
4735
+ if (!ref.armMap || node.type === "mapping" || isHitlNode2(node)) return void 0;
4736
+ const id = nodeIdOf(node);
4737
+ if ((container === "foreach" || container === "loop") && node.type !== "workflow") {
4738
+ return {
4739
+ code: "mapping-placement",
4740
+ 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`,
4741
+ callIndex: i,
4742
+ stepId: id
4743
+ };
4744
+ }
4745
+ if (node.input !== void 0) {
4746
+ return {
4747
+ code: "mapping-placement",
4748
+ 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)`,
4749
+ callIndex: i,
4750
+ stepId: id
4751
+ };
4752
+ }
4753
+ return void 0;
4754
+ }, "armMapPlacementIssue");
4308
4755
  const hitlPlacementIssue = /* @__PURE__ */ __name3((node, ref, i, container) => {
4309
4756
  if (!isHitlNode2(node)) return void 0;
4310
4757
  const id = node.id;
@@ -4331,7 +4778,7 @@ function resolvePlacements(calls) {
4331
4778
  if (ref.node.type === "mapping" && !allowMapping) {
4332
4779
  issues.push({
4333
4780
  code: "mapping-placement",
4334
- message: `mapping "${ref.node.id}" cannot be a container arm \u2014 chain it as [map, step]`,
4781
+ 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`,
4335
4782
  callIndex: i,
4336
4783
  stepId: ref.node.id
4337
4784
  });
@@ -4352,7 +4799,7 @@ function resolvePlacements(calls) {
4352
4799
  if (d.node.type === "mapping" && !allowMapping) {
4353
4800
  issues.push({
4354
4801
  code: "mapping-placement",
4355
- message: `map "${ref.ref}" cannot be a parallel/foreach/loop arm \u2014 chain it as [map, step]`,
4802
+ 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`,
4356
4803
  callIndex: i,
4357
4804
  stepId: ref.ref
4358
4805
  });
@@ -4363,6 +4810,11 @@ function resolvePlacements(calls) {
4363
4810
  issues.push(hitl);
4364
4811
  return void 0;
4365
4812
  }
4813
+ const mapped = armMapPlacementIssue(d.node, ref, i, container);
4814
+ if (mapped) {
4815
+ issues.push(mapped);
4816
+ return void 0;
4817
+ }
4366
4818
  const prior = placedBy.get(ref.ref);
4367
4819
  if (prior !== void 0 && prior !== i) {
4368
4820
  issues.push({
@@ -4383,6 +4835,10 @@ function resolvePlacements(calls) {
4383
4835
  }
4384
4836
  const hitl = hitlPlacementIssue(ref.node, ref, i, container);
4385
4837
  if (hitl) issues.push(hitl);
4838
+ else {
4839
+ const mapped = armMapPlacementIssue(ref.node, ref, i, container);
4840
+ if (mapped) issues.push(mapped);
4841
+ }
4386
4842
  }, "claim");
4387
4843
  calls.forEach((call, i) => {
4388
4844
  switch (call.kind) {
@@ -4410,7 +4866,7 @@ function resolvePlacements(calls) {
4410
4866
  const lookup = /* @__PURE__ */ __name3((ref) => {
4411
4867
  const n2 = "node" in ref ? ref.node : declared.get(ref.ref)?.node;
4412
4868
  if (!n2 || !ref.armMap || n2.type === "mapping" || isHitlNode2(n2)) return n2;
4413
- return lowerContainerArm(ref.armMap, n2);
4869
+ return inlineContainerArm(ref.armMap, n2);
4414
4870
  }, "lookup");
4415
4871
  calls.forEach((call, i) => {
4416
4872
  switch (call.kind) {
@@ -4851,9 +5307,37 @@ function pruneUndefined(o) {
4851
5307
  }
4852
5308
  __name(pruneUndefined, "pruneUndefined");
4853
5309
  __name3(pruneUndefined, "pruneUndefined");
5310
+ var WORKFLOW_INLINE_RUN_TAG = "inline";
5311
+ function runOrigin(run) {
5312
+ if (run.goalId) return "goal";
5313
+ if (run.jobId || run.trigger === "schedule") return "schedule";
5314
+ if (run.dynamic === true) return run.tags?.includes(WORKFLOW_INLINE_RUN_TAG) ? "inline" : "compose";
5315
+ return "definition";
5316
+ }
5317
+ __name(runOrigin, "runOrigin");
5318
+ __name3(runOrigin, "runOrigin");
5319
+ var RUN_ERROR_ISSUES_MAX = 20;
5320
+ function runErrorIssues(issues) {
5321
+ if (!Array.isArray(issues)) return void 0;
5322
+ const out = [];
5323
+ for (const raw of issues.slice(0, RUN_ERROR_ISSUES_MAX)) {
5324
+ if (!raw || typeof raw !== "object") continue;
5325
+ const o = raw;
5326
+ if (typeof o.code !== "string" || !o.code) continue;
5327
+ out.push(pruneUndefined({
5328
+ code: o.code,
5329
+ path: typeof o.path === "string" ? o.path : void 0,
5330
+ message: typeof o.message === "string" ? o.message : void 0
5331
+ }));
5332
+ }
5333
+ return out.length ? out : void 0;
5334
+ }
5335
+ __name(runErrorIssues, "runErrorIssues");
5336
+ __name3(runErrorIssues, "runErrorIssues");
4854
5337
  function runNextAction(run) {
4855
5338
  if (isTerminalRunStatus(run.status)) return "none";
4856
5339
  if (run.status === "suspended" && run.gate?.kind === "budget") return "raise_budget";
5340
+ if (run.status === "suspended" && run.gate?.kind === "billing") return "top_up";
4857
5341
  if (!run.cancel?.requestedAt) return "none";
4858
5342
  const forceAt = run.cancel.forceAfter ?? run.cancel.requestedAt + FORCE_CANCEL_STALE_MS;
4859
5343
  return Date.now() >= forceAt ? "force" : "cancel_again";
@@ -4890,6 +5374,16 @@ function runCountsFromStepStatuses(statuses) {
4890
5374
  }
4891
5375
  __name(runCountsFromStepStatuses, "runCountsFromStepStatuses");
4892
5376
  __name3(runCountsFromStepStatuses, "runCountsFromStepStatuses");
5377
+ function isBillingHeldStep(row) {
5378
+ return row.status === "ready" && row.billingHold === true;
5379
+ }
5380
+ __name(isBillingHeldStep, "isBillingHeldStep");
5381
+ __name3(isBillingHeldStep, "isBillingHeldStep");
5382
+ function stepEffectiveStatus(row) {
5383
+ return isBillingHeldStep(row) ? "suspended" : row.status;
5384
+ }
5385
+ __name(stepEffectiveStatus, "stepEffectiveStatus");
5386
+ __name3(stepEffectiveStatus, "stepEffectiveStatus");
4893
5387
  var n = /* @__PURE__ */ __name3((v) => typeof v === "number" && Number.isFinite(v) ? v : 0, "n");
4894
5388
  function runCounts(counts) {
4895
5389
  const c = counts ?? {};
@@ -5050,6 +5544,7 @@ function toWorkflowRunSummary(run) {
5050
5544
  repairOf: run.repairOf,
5051
5545
  repairRunIds: run.repairRunIds,
5052
5546
  trigger: run.trigger ?? "api",
5547
+ origin: runOrigin(run),
5053
5548
  createdBy: {
5054
5549
  subjectType: principal?.subjectType ?? "system",
5055
5550
  subjectId: principal?.subjectId ?? run.userId ?? ""
@@ -5067,11 +5562,13 @@ function toWorkflowRunSummary(run) {
5067
5562
  usage: runUsage(run),
5068
5563
  // LUA-697: a row persisted before the write seams (#2406 / #2465 / the script tier) leaves scrubbed here too —
5069
5564
  // idempotent on a scrubbed message, bounded input; an empty message falls back to the code.
5070
- error: run.error ? {
5565
+ error: run.error ? pruneUndefined({
5071
5566
  code: run.error.code ?? "error",
5072
5567
  message: scrubStepErrorMessage(run.error.message) ?? run.error.code ?? "error",
5073
- stepId: run.error.stepId
5074
- } : void 0,
5568
+ stepId: run.error.stepId,
5569
+ // LUA-784 (item 3): the unattended pre-start failure's refusal rows (`input_schema_invalid` and kin).
5570
+ issues: runErrorIssues(run.error.issues)
5571
+ }) : void 0,
5075
5572
  kind: "run",
5076
5573
  aclHash: run.aclHash,
5077
5574
  migration: run.migration,
@@ -5724,204 +6221,6 @@ function rebaseItemPointer(pointer, itemsPath, index) {
5724
6221
  }
5725
6222
  __name(rebaseItemPointer, "rebaseItemPointer");
5726
6223
  __name3(rebaseItemPointer, "rebaseItemPointer");
5727
- var APPROVER_SPEC_MAX_USERS = 20;
5728
- var ESCALATION_MAX_HOPS = 3;
5729
- var TemplateBindingSchema = z22.object({
5730
- template: z22.string().min(1).max(2048)
5731
- }).strict();
5732
- var ApproverSpecSchema = z22.union([
5733
- z22.literal("creator"),
5734
- z22.literal("org-admins"),
5735
- z22.object({
5736
- users: z22.union([
5737
- z22.array(z22.string().min(1).max(128)).min(1).max(APPROVER_SPEC_MAX_USERS),
5738
- TemplateBindingSchema
5739
- ])
5740
- }).strict(),
5741
- z22.object({
5742
- role: z22.union([
5743
- z22.string().min(1).max(128),
5744
- TemplateBindingSchema
5745
- ])
5746
- }).strict(),
5747
- z22.object({
5748
- group: z22.union([
5749
- z22.string().min(1).max(128),
5750
- TemplateBindingSchema
5751
- ])
5752
- }).strict(),
5753
- z22.object({
5754
- governance: z22.object({
5755
- policyId: z22.string().min(1).max(128)
5756
- }).strict()
5757
- }).strict()
5758
- ]);
5759
- var FourEyesSchema = z22.object({
5760
- edit: ApproverSpecSchema,
5761
- approve: ApproverSpecSchema
5762
- }).strict();
5763
- var EscalationHopSchema = z22.object({
5764
- escalateTo: ApproverSpecSchema,
5765
- timeoutHours: z22.number().finite().min(1).max(720)
5766
- }).strict();
5767
- var TerminalOutcomeSchema = z22.enum([
5768
- "deny",
5769
- "cancel-run",
5770
- "fail",
5771
- "continue"
5772
- ]);
5773
- var ApprovalOnTimeoutSchema = z22.union([
5774
- TerminalOutcomeSchema,
5775
- EscalationHopSchema,
5776
- z22.array(z22.union([
5777
- TerminalOutcomeSchema,
5778
- EscalationHopSchema
5779
- ])).min(1).max(ESCALATION_MAX_HOPS + 1)
5780
- ]);
5781
- var APPROVER_SPEC_SHAPES = [
5782
- "'creator'",
5783
- "'org-admins'",
5784
- "{users:[userId, \u2026]}",
5785
- "{role:roleName}",
5786
- "{group:groupName}",
5787
- "{governance:{policyId}}"
5788
- ];
5789
- var APPROVER_WRITTEN_MAX = 120;
5790
- var USER_ID_SHAPED_RE = /^[^\s@]{1,128}$/;
5791
- function describeApproverSpecRefusal(spec) {
5792
- const raw = spec === void 0 ? "undefined" : JSON.stringify(spec) ?? String(spec);
5793
- const written = raw.length > APPROVER_WRITTEN_MAX ? `${raw.slice(0, APPROVER_WRITTEN_MAX - 1)}\u2026` : raw;
5794
- const users = typeof spec === "object" && spec !== null ? spec.users : void 0;
5795
- const approver = typeof users === "string" && USER_ID_SHAPED_RE.test(users) ? {
5796
- users: [
5797
- users
5798
- ]
5799
- } : "creator";
5800
- 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)}`);
5801
- return {
5802
- approver,
5803
- written,
5804
- message
5805
- };
5806
- }
5807
- __name(describeApproverSpecRefusal, "describeApproverSpecRefusal");
5808
- __name3(describeApproverSpecRefusal, "describeApproverSpecRefusal");
5809
- var BINDING_ROOTS = [
5810
- "initData",
5811
- "stepResults",
5812
- "requestContext",
5813
- "state"
5814
- ];
5815
- function bindingRootsOk(template22) {
5816
- const refs = [
5817
- ...template22.matchAll(/\$\{\s*([A-Za-z_$][\w$]*)/g)
5818
- ].map((m) => m[1]);
5819
- return refs.length > 0 && refs.every((r) => BINDING_ROOTS.includes(r));
5820
- }
5821
- __name(bindingRootsOk, "bindingRootsOk");
5822
- __name3(bindingRootsOk, "bindingRootsOk");
5823
- function isTemplateBinding(v) {
5824
- return typeof v === "object" && v !== null && typeof v.template === "string";
5825
- }
5826
- __name(isTemplateBinding, "isTemplateBinding");
5827
- __name3(isTemplateBinding, "isTemplateBinding");
5828
- function validateApproverBlock(node, opts = {
5829
- path: "approval"
5830
- }) {
5831
- const issues = [];
5832
- const push = /* @__PURE__ */ __name3((code, path, message, severity = "error") => issues.push({
5833
- code,
5834
- path,
5835
- severity,
5836
- message
5837
- }), "push");
5838
- const checkSpec = /* @__PURE__ */ __name3((spec, path) => {
5839
- const r = ApproverSpecSchema.safeParse(spec);
5840
- if (!r.success) {
5841
- const users = spec?.users;
5842
- if (Array.isArray(users) && users.length > APPROVER_SPEC_MAX_USERS) push("cap-exceeded", path, `at most ${APPROVER_SPEC_MAX_USERS} users`);
5843
- else {
5844
- const refusal = describeApproverSpecRefusal(spec);
5845
- issues.push({
5846
- code: "approver-invalid",
5847
- path,
5848
- severity: "error",
5849
- message: refusal.message,
5850
- repair: {
5851
- approver: refusal.approver,
5852
- written: refusal.written
5853
- }
5854
- });
5855
- }
5856
- return;
5857
- }
5858
- const s = r.data;
5859
- if (typeof s === "object") {
5860
- if ("governance" in s && !opts.governanceEnabled) push("approver-governance-unavailable", path, "governance reviewer routing is not enabled for this deployment");
5861
- 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");
5862
- const binding = "users" in s ? s.users : "role" in s ? s.role : "group" in s ? s.group : void 0;
5863
- if (isTemplateBinding(binding)) {
5864
- if (!bindingRootsOk(binding.template)) push("approver-binding-invalid", `${path}.template`, "binding root must be initData / stepResults / requestContext / state");
5865
- if ("users" in s && opts.customerReachable) push("approver-binding-customer-reachable", `${path}.users`, "a customer-reachable workflow may not bind its approver list");
5866
- }
5867
- }
5868
- }, "checkSpec");
5869
- if (node.approver !== void 0) checkSpec(node.approver, `${opts.path}.approver`);
5870
- if (node.fourEyes !== void 0) {
5871
- const r = FourEyesSchema.safeParse(node.fourEyes);
5872
- if (!r.success) push("approver-invalid", `${opts.path}.fourEyes`, "fourEyes needs { edit, approve } approver specs");
5873
- else {
5874
- checkSpec(r.data.edit, `${opts.path}.fourEyes.edit`);
5875
- checkSpec(r.data.approve, `${opts.path}.fourEyes.approve`);
5876
- }
5877
- if (!node.editable) push("four-eyes-requires-editable", `${opts.path}.fourEyes`, "fourEyes requires editable:true");
5878
- if (node.approver !== void 0) push("four-eyes-overrides-approver", `${opts.path}.approver`, "fourEyes replaces approver", "warning");
5879
- if (node.itemsPath) push("four-eyes-items-unsupported", `${opts.path}.fourEyes`, "fourEyes cannot combine with itemsPath");
5880
- }
5881
- 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");
5882
- if (Array.isArray(node.onTimeout)) {
5883
- const chain = node.onTimeout;
5884
- const hops = chain.filter((m) => typeof m === "object" && m !== null && "escalateTo" in m);
5885
- if (hops.length > ESCALATION_MAX_HOPS) push("escalation-chain-too-long", `${opts.path}.onTimeout`, `at most ${ESCALATION_MAX_HOPS} hops`);
5886
- const last = chain[chain.length - 1];
5887
- if (typeof last === "object" && last !== null) push("escalation-chain-not-terminal", `${opts.path}.onTimeout`, "a chain must end in deny | cancel-run | fail");
5888
- hops.forEach((h, i) => checkSpec(h.escalateTo, `${opts.path}.onTimeout[${i}].escalateTo`));
5889
- } else if (typeof node.onTimeout === "object" && node.onTimeout !== null) {
5890
- checkSpec(node.onTimeout.escalateTo, `${opts.path}.onTimeout.escalateTo`);
5891
- }
5892
- return issues;
5893
- }
5894
- __name(validateApproverBlock, "validateApproverBlock");
5895
- __name3(validateApproverBlock, "validateApproverBlock");
5896
- function liftRenderedApprover(row, rendered) {
5897
- const text = (rendered ?? "").trim();
5898
- if (!text) return null;
5899
- if (row === "users") {
5900
- let members = null;
5901
- if (text.startsWith("[")) {
5902
- try {
5903
- members = JSON.parse(text);
5904
- } catch {
5905
- return null;
5906
- }
5907
- } else members = text.split(",").map((s) => s.trim());
5908
- if (!Array.isArray(members) || members.length === 0 || members.length > APPROVER_SPEC_MAX_USERS) return null;
5909
- if (!members.every((m) => typeof m === "string" && m.length > 0 && m.length <= 128)) return null;
5910
- return {
5911
- users: [
5912
- ...new Set(members)
5913
- ].sort()
5914
- };
5915
- }
5916
- if (text.length > 128 || text.startsWith("[") || text.startsWith("{")) return null;
5917
- return row === "role" ? {
5918
- role: text
5919
- } : {
5920
- group: text
5921
- };
5922
- }
5923
- __name(liftRenderedApprover, "liftRenderedApprover");
5924
- __name3(liftRenderedApprover, "liftRenderedApprover");
5925
6224
  var WORKFLOW_ENV_OVERLAY_MAX_KEYS = 64;
5926
6225
  var WORKFLOW_ENV_OVERLAY_MAX_VALUE_BYTES = 4096;
5927
6226
  var WORKFLOW_ENV_TEMPLATE_SECRET_KEY_RE = /(SECRET|TOKEN|KEY|PASSWORD)$/;
@@ -6205,7 +6504,6 @@ function* singleStepsOf(entry) {
6205
6504
  return;
6206
6505
  case "workflow":
6207
6506
  yield entry;
6208
- if (Array.isArray(entry.graph)) yield* singleStepsOf(entry.graph[1]);
6209
6507
  return;
6210
6508
  case "parallel":
6211
6509
  case "conditional":
@@ -6364,7 +6662,10 @@ var assertPredicate = /* @__PURE__ */ __name((p, where) => {
6364
6662
  }, "assertPredicate");
6365
6663
  var assertRetry = /* @__PURE__ */ __name((r, id) => {
6366
6664
  if (!r) return;
6367
- if (typeof r.maxAttempts === "number" && r.maxAttempts > WORKFLOW_RETRY_MAX_ATTEMPTS) throw new LuaWorkflowBuildError("cap-exceeded", `"${id}": ${workflowRetryMaxAttemptsMessage(r.maxAttempts)}`);
6665
+ if (!isWithinWorkflowRetryAttempts(r.maxAttempts)) {
6666
+ const over = typeof r.maxAttempts === "number" && r.maxAttempts > WORKFLOW_RETRY_MAX_ATTEMPTS;
6667
+ throw new LuaWorkflowBuildError(over ? "cap-exceeded" : "invalid-envelope", `"${id}": ${workflowRetryMaxAttemptsMessage(r.maxAttempts)}`);
6668
+ }
6368
6669
  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(" | ")}`);
6369
6670
  if (r.maxBackoffSeconds !== void 0) {
6370
6671
  if (r.backoff !== "exponential") throw new LuaWorkflowBuildError("backoff-invalid", `"${id}": retry.maxBackoffSeconds is only meaningful with backoff:'exponential'`);
@@ -6514,14 +6815,13 @@ function stepNodeOf(s) {
6514
6815
  __name(stepNodeOf, "stepNodeOf");
6515
6816
  function materializeEntry(entry, steps) {
6516
6817
  const single = /* @__PURE__ */ __name((n2) => {
6517
- if (n2.type === "step" && steps[n2.step.id]) return stepNodeOf(steps[n2.step.id]);
6518
- if (n2.type === "workflow" && n2.workflowId === WORKFLOW_ARM_SUBRUN_ID && n2.graph) return {
6519
- ...n2,
6520
- graph: [
6521
- n2.graph[0],
6522
- single(n2.graph[1])
6523
- ]
6524
- };
6818
+ if (n2.type === "step" && steps[n2.step.id]) {
6819
+ const node = stepNodeOf(steps[n2.step.id]);
6820
+ return n2.input !== void 0 ? {
6821
+ ...node,
6822
+ input: n2.input
6823
+ } : node;
6824
+ }
6525
6825
  return n2;
6526
6826
  }, "single");
6527
6827
  switch (entry.type) {