lua-cli 3.32.3 → 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.
@@ -353,6 +353,84 @@ function isDesktopFileCommandName(value3) {
353
353
  function isDesktopFileSessionId(value3) {
354
354
  return typeof value3 === "string" && /^[0-9a-f]{8}-[0-9a-f]{4}-[1-5][0-9a-f]{3}-[89ab][0-9a-f]{3}-[0-9a-f]{12}$/i.test(value3);
355
355
  }
356
+ function isModelIdSentinel(input) {
357
+ const lower = (input ?? "").trim().toLowerCase();
358
+ return lower === "auto" || lower.startsWith("auto/");
359
+ }
360
+ function normalizeModelId(input, registry) {
361
+ const requested = typeof input === "string" ? input.trim() : "";
362
+ if (!requested) return {
363
+ ok: false,
364
+ reason: "empty",
365
+ requested,
366
+ candidates: []
367
+ };
368
+ const lower = requested.toLowerCase();
369
+ if (isModelIdSentinel(lower)) return {
370
+ ok: true,
371
+ id: lower,
372
+ form: "sentinel"
373
+ };
374
+ const slash = requested.indexOf("/");
375
+ const malformed = slash === 0;
376
+ const provider = slash > 0 ? lower.slice(0, slash) : void 0;
377
+ if (provider && MODEL_ID_BYOK_PROVIDERS.includes(provider)) {
378
+ return {
379
+ ok: true,
380
+ id: requested,
381
+ form: "byok"
382
+ };
383
+ }
384
+ const bareId = slash >= 0 ? lower.slice(slash + 1) : lower;
385
+ const lastSegment = bareId.slice(bareId.lastIndexOf("/") + 1);
386
+ const exact = /* @__PURE__ */ new Set();
387
+ const hints = /* @__PURE__ */ new Set();
388
+ for (const code of registry) {
389
+ if (typeof code !== "string" || !code) continue;
390
+ const codeLower = code.toLowerCase();
391
+ if (!malformed && codeLower === lower) return {
392
+ ok: true,
393
+ id: code,
394
+ form: provider ? "canonical" : "bare"
395
+ };
396
+ const i = codeLower.indexOf("/");
397
+ if (i < 0) continue;
398
+ const codeBare = codeLower.slice(i + 1);
399
+ if (bareId && codeBare === bareId) exact.add(code);
400
+ else if (lastSegment && codeBare.slice(codeBare.lastIndexOf("/") + 1) === lastSegment) hints.add(code);
401
+ }
402
+ const sorted = [
403
+ ...exact
404
+ ].sort();
405
+ if (!provider && !malformed && sorted.length === 1) return {
406
+ ok: true,
407
+ id: sorted[0],
408
+ form: "bare"
409
+ };
410
+ if (!provider && !malformed && sorted.length > 1) {
411
+ return {
412
+ ok: false,
413
+ reason: "ambiguous",
414
+ requested,
415
+ candidates: sorted
416
+ };
417
+ }
418
+ return {
419
+ ok: false,
420
+ reason: "unknown",
421
+ requested,
422
+ candidates: sorted.length ? sorted : [
423
+ ...hints
424
+ ].sort()
425
+ };
426
+ }
427
+ function modelUnresolvedMessage(r) {
428
+ if (r.reason === "empty") return "model pin is empty \u2014 pin an approved model (provider/model) or omit `model`";
429
+ if (r.reason === "ambiguous") {
430
+ return `model "${r.requested}" does not resolve to one approved model \u2014 it names ${r.candidates.length}; pin one of: ${r.candidates.join(", ")}`;
431
+ }
432
+ 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`;
433
+ }
356
434
  function isImplicitModelSelectionSource(source) {
357
435
  return source !== void 0 && IMPLICIT_MODEL_SELECTION_SOURCES.includes(source);
358
436
  }
@@ -941,7 +1019,7 @@ function extractSingleJsonValue(text) {
941
1019
  };
942
1020
  }
943
1021
  }
944
- var __defProp2, __name2, CHANNEL_SEND_CHANNELS, REVIEWABLE_ACTION_EXECUTE_TOOL_ALLOWLIST, REVIEWABLE_MCP_SEND_TOOL_SUFFIX, MCP_TOOL_READ_VERB_RE, MCP_DRAFT_CREATE_VERBS, NON_INTERACTIVE_CHANNELS, RICH_PARTS_MESSAGE_ID_PREFIX, SCREENSHOT_MESSAGE_ID_PREFIX, BROWSER_COMMANDS, BROWSER_COMMAND_NAMES, DESKTOP_FILE_COMMANDS, DESKTOP_FILE_COMMAND_SET, REASONING_EFFORT_VALUES, IMPLICIT_MODEL_SELECTION_SOURCES, PLATFORM_FALLBACK_MODEL_SOURCE, AGENT_NAME_TOKEN, DEFAULT_PERSONA_GUIDE, PERSONAL_SPACE_STARTING_PERSONA, CORE_DRAINING_CODE, CORE_DRAINING_DEFAULT_RETRY_MS, CORE_DRAINING_MAX_RETRY_MS, VoiceNameSchema, PluginProviderSchema, RealtimeProviderSchema, PluginClassSchema, ModelDescriptorSchema, InferenceModelSchema, PluginModelSchema, RealtimeModelSchema, LuaVoiceModelSchema, TurnDetectionSchema, InterruptionSchema, BuiltinAudioClipSchema, AudioConfigSchema, BackgroundAudioEntrySchema, BackgroundAudioSchema, LuaVoiceConfigInnerSchema, LuaVoiceConfigSchema, LuaVoiceRefSchema, LUA_JOB_DEFAULT_TIMEOUT_SECONDS, LUA_JOB_MIN_TIMEOUT_SECONDS, LUA_JOB_MAX_TIMEOUT_SECONDS, TEMPLATE_TRIGGER_URL_ENV_PREFIX, SUBJECT_TYPES, SubjectTypeSchema, CREDENTIAL_TYPES, CredentialTypeSchema, DEVICE_OPERATIONS, DeviceOperationSchema, DEVICE_SCOPE_BY_OPERATION, DeviceBindingSchema, IdSchema, PrincipalDescriptorSchema, ActorDescriptorSchema, PrincipalOwnerSchema, CredentialLifecycleSchema, GeneralCredentialDescriptorSchema, DeviceCredentialDescriptorSchema, GeneralPrincipalContextSchema, DeviceCredentialPrincipalContextSchema, RawPrincipalContextSchema, PrincipalContextSchema, DeviceCredentialClaimSchema, LUA_CLIENT_HEADER, LUA_CLIENT_APPS, SEMVER_PATTERN, WEB_RELEASE_PATTERN, CLIENT_HEADER_PATTERN, AUTHZ_PROJECTION_VERSION, ProjectedScopeSchema, DisplayRoleSchema, AuthorizationPrincipalSchema, CredentialContextSchema, ProjectionAnomalySchema, ProjectedOrgSchema, ProjectedResourceSchema, CapabilityProfilesSchema, RoleCatalogSchema, EffectiveAuthorizationSchema, ResourcePageSchema, SYSTEM_USER_PREFIX, WORKFLOW_RUN_IN_FLIGHT, WORKFLOW_RUN_IDLE, WORKFLOW_RUN_TERMINAL, WORKFLOW_RUN_STATUSES, WORKFLOW_STEP_STATUSES, WORKFLOW_STEP_IN_FLIGHT, ARCHIVE_WINDOW_MARGIN_DAYS, WORKFLOW_ORG_PURGING_TTL_S, WORKFLOW_ORG_PURGE_FORCE_AFTER_MS, IDEMPOTENCY_HOLDING_STATUSES, WORKFLOW_SCHEDULED_RUN_ID_PREFIX, CLOUD_TASK_RUN_ID_PREFIX, WORKFLOW_OPERATION_ID_PREFIX, WORKFLOW_CONNECTION_KEY_RE, WORKFLOW_SIGNAL_PAYLOAD_MAX_BYTES, WORKFLOW_RESOLVE_OUTPUT_MAX_BYTES, WORKFLOW_RETRY_BACKOFFS, WORKFLOW_RETRY_MIN_ATTEMPTS, WORKFLOW_RETRY_POLICY_KEYS, WORKFLOW_RETRY_MAX_ATTEMPTS, WORKFLOW_RETRY_ENGINE_KEYS, WORKFLOW_JOB_RESOURCES, WORKFLOW_SIDE_EFFECTS, WORKFLOW_JOB_RANGES, WORKFLOW_JOB_RANGE_MEMBERS, WORKFLOW_SINGLE_STEP_TYPES, WORKFLOW_HITL_ENTRY_TYPES, WORKFLOW_ARM_ENTRY_TYPES, WORKFLOW_HITL_ARM_CONTAINERS, WORKFLOW_GRAPH_ENTRY_STEP_KINDS, WORKFLOW_ARM_ENTRY_STEP_KINDS, WORKFLOW_BUDGET_MAX_DURATION_SECONDS, REDACTED_PLACEHOLDER, PROVIDER_MESSAGE_MAX_CHARS, ERROR_MESSAGE_MAX_CHARS, SECRET_LITERAL_PATTERNS, SECRET_NAME, SECRET_PAIR_PATTERNS, GROUP_COUNT, WORKFLOW_SECRET_KEY_RE, WORKFLOW_RESERVED_SECRET_KEYS, SCRUB_INPUT_MAX_CHARS, SCRUB_CUT_BACKOFF_CHARS, WORKFLOW_AUDIT_EVENTS, WORKFLOW_AUDIT_METADATA_MAX_BYTES, INDENT, WRAP_WIDTH, NOUNS, GET_TOOL_NAMES, PREAMBLE, WORKFLOW_APPROVAL_OUTPUT_DECISIONS, WORKFLOW_APPROVAL_OUTPUT_SCHEMA, JSON_FENCE_RE;
1022
+ var __defProp2, __name2, CHANNEL_SEND_CHANNELS, REVIEWABLE_ACTION_EXECUTE_TOOL_ALLOWLIST, REVIEWABLE_MCP_SEND_TOOL_SUFFIX, MCP_TOOL_READ_VERB_RE, MCP_DRAFT_CREATE_VERBS, NON_INTERACTIVE_CHANNELS, RICH_PARTS_MESSAGE_ID_PREFIX, SCREENSHOT_MESSAGE_ID_PREFIX, BROWSER_COMMANDS, BROWSER_COMMAND_NAMES, DESKTOP_FILE_COMMANDS, DESKTOP_FILE_COMMAND_SET, MODEL_ID_BYOK_PROVIDERS, REASONING_EFFORT_VALUES, IMPLICIT_MODEL_SELECTION_SOURCES, PLATFORM_FALLBACK_MODEL_SOURCE, AGENT_NAME_TOKEN, DEFAULT_PERSONA_GUIDE, PERSONAL_SPACE_STARTING_PERSONA, CORE_DRAINING_CODE, CORE_DRAINING_DEFAULT_RETRY_MS, CORE_DRAINING_MAX_RETRY_MS, VoiceNameSchema, PluginProviderSchema, RealtimeProviderSchema, PluginClassSchema, ModelDescriptorSchema, InferenceModelSchema, PluginModelSchema, RealtimeModelSchema, LuaVoiceModelSchema, TurnDetectionSchema, InterruptionSchema, BuiltinAudioClipSchema, AudioConfigSchema, BackgroundAudioEntrySchema, BackgroundAudioSchema, LuaVoiceConfigInnerSchema, LuaVoiceConfigSchema, LuaVoiceRefSchema, LUA_JOB_DEFAULT_TIMEOUT_SECONDS, LUA_JOB_MIN_TIMEOUT_SECONDS, LUA_JOB_MAX_TIMEOUT_SECONDS, TEMPLATE_TRIGGER_URL_ENV_PREFIX, SUBJECT_TYPES, SubjectTypeSchema, CREDENTIAL_TYPES, CredentialTypeSchema, DEVICE_OPERATIONS, DeviceOperationSchema, DEVICE_SCOPE_BY_OPERATION, DeviceBindingSchema, IdSchema, PrincipalDescriptorSchema, ActorDescriptorSchema, PrincipalOwnerSchema, CredentialLifecycleSchema, GeneralCredentialDescriptorSchema, DeviceCredentialDescriptorSchema, GeneralPrincipalContextSchema, DeviceCredentialPrincipalContextSchema, RawPrincipalContextSchema, PrincipalContextSchema, DeviceCredentialClaimSchema, LUA_CLIENT_HEADER, LUA_CLIENT_APPS, SEMVER_PATTERN, WEB_RELEASE_PATTERN, CLIENT_HEADER_PATTERN, AUTHZ_PROJECTION_VERSION, ProjectedScopeSchema, DisplayRoleSchema, AuthorizationPrincipalSchema, CredentialContextSchema, ProjectionAnomalySchema, ProjectedOrgSchema, ProjectedResourceSchema, CapabilityProfilesSchema, RoleCatalogSchema, EffectiveAuthorizationSchema, ResourcePageSchema, SYSTEM_USER_PREFIX, WORKFLOW_RUN_IN_FLIGHT, WORKFLOW_RUN_IDLE, WORKFLOW_RUN_TERMINAL, WORKFLOW_RUN_STATUSES, WORKFLOW_STEP_STATUSES, WORKFLOW_STEP_IN_FLIGHT, ARCHIVE_WINDOW_MARGIN_DAYS, WORKFLOW_ORG_PURGING_TTL_S, WORKFLOW_ORG_PURGE_FORCE_AFTER_MS, IDEMPOTENCY_HOLDING_STATUSES, WORKFLOW_SCHEDULED_RUN_ID_PREFIX, CLOUD_TASK_RUN_ID_PREFIX, WORKFLOW_OPERATION_ID_PREFIX, WORKFLOW_CONNECTION_KEY_RE, WORKFLOW_SIGNAL_PAYLOAD_MAX_BYTES, WORKFLOW_RESOLVE_OUTPUT_MAX_BYTES, WORKFLOW_RETRY_BACKOFFS, WORKFLOW_RETRY_MIN_ATTEMPTS, WORKFLOW_RETRY_POLICY_KEYS, WORKFLOW_RETRY_MAX_ATTEMPTS, WORKFLOW_RETRY_ENGINE_KEYS, WORKFLOW_JOB_RESOURCES, WORKFLOW_SIDE_EFFECTS, WORKFLOW_JOB_RANGES, WORKFLOW_JOB_RANGE_MEMBERS, WORKFLOW_SINGLE_STEP_TYPES, WORKFLOW_HITL_ENTRY_TYPES, WORKFLOW_ARM_ENTRY_TYPES, WORKFLOW_HITL_ARM_CONTAINERS, WORKFLOW_GRAPH_ENTRY_STEP_KINDS, WORKFLOW_ARM_ENTRY_STEP_KINDS, WORKFLOW_BUDGET_MAX_DURATION_SECONDS, REDACTED_PLACEHOLDER, PROVIDER_MESSAGE_MAX_CHARS, ERROR_MESSAGE_MAX_CHARS, SECRET_LITERAL_PATTERNS, SECRET_NAME, SECRET_PAIR_PATTERNS, GROUP_COUNT, WORKFLOW_SECRET_KEY_RE, WORKFLOW_RESERVED_SECRET_KEYS, SCRUB_INPUT_MAX_CHARS, SCRUB_CUT_BACKOFF_CHARS, WORKFLOW_AUDIT_EVENTS, WORKFLOW_AUDIT_METADATA_MAX_BYTES, INDENT, WRAP_WIDTH, NOUNS, GET_TOOL_NAMES, PREAMBLE, WORKFLOW_APPROVAL_OUTPUT_DECISIONS, WORKFLOW_APPROVAL_OUTPUT_SCHEMA, JSON_FENCE_RE;
945
1023
  var init_dist = __esm({
946
1024
  "../shared-types/dist/index.mjs"() {
947
1025
  "use strict";
@@ -1258,6 +1336,16 @@ var init_dist = __esm({
1258
1336
  __name2(isDesktopFileCommandName, "isDesktopFileCommandName");
1259
1337
  __name(isDesktopFileSessionId, "isDesktopFileSessionId");
1260
1338
  __name2(isDesktopFileSessionId, "isDesktopFileSessionId");
1339
+ MODEL_ID_BYOK_PROVIDERS = [
1340
+ "azure",
1341
+ "bedrock"
1342
+ ];
1343
+ __name(isModelIdSentinel, "isModelIdSentinel");
1344
+ __name2(isModelIdSentinel, "isModelIdSentinel");
1345
+ __name(normalizeModelId, "normalizeModelId");
1346
+ __name2(normalizeModelId, "normalizeModelId");
1347
+ __name(modelUnresolvedMessage, "modelUnresolvedMessage");
1348
+ __name2(modelUnresolvedMessage, "modelUnresolvedMessage");
1261
1349
  REASONING_EFFORT_VALUES = [
1262
1350
  "off",
1263
1351
  "minimal",
@@ -2666,6 +2754,129 @@ function resolveMapping(cfg, ctx) {
2666
2754
  value: result
2667
2755
  };
2668
2756
  }
2757
+ function describeApproverSpecRefusal(spec) {
2758
+ const raw = spec === void 0 ? "undefined" : JSON.stringify(spec) ?? String(spec);
2759
+ const written = raw.length > APPROVER_WRITTEN_MAX ? `${raw.slice(0, APPROVER_WRITTEN_MAX - 1)}\u2026` : raw;
2760
+ const users = typeof spec === "object" && spec !== null ? spec.users : void 0;
2761
+ const approver = typeof users === "string" && USER_ID_SHAPED_RE.test(users) ? {
2762
+ users: [
2763
+ users
2764
+ ]
2765
+ } : "creator";
2766
+ 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)}`);
2767
+ return {
2768
+ approver,
2769
+ written,
2770
+ message
2771
+ };
2772
+ }
2773
+ function bindingRootsOk(template22) {
2774
+ const refs = [
2775
+ ...template22.matchAll(/\$\{\s*([A-Za-z_$][\w$]*)/g)
2776
+ ].map((m) => m[1]);
2777
+ return refs.length > 0 && refs.every((r) => BINDING_ROOTS.includes(r));
2778
+ }
2779
+ function isTemplateBinding(v) {
2780
+ return typeof v === "object" && v !== null && typeof v.template === "string";
2781
+ }
2782
+ function approvalEditable(node) {
2783
+ if (node.editable === true) return true;
2784
+ if (node.editable === false) return false;
2785
+ return Array.isArray(node.editablePaths) && node.editablePaths.length > 0;
2786
+ }
2787
+ function validateApproverBlock(node, opts = {
2788
+ path: "approval"
2789
+ }) {
2790
+ const issues = [];
2791
+ const push = /* @__PURE__ */ __name3((code, path3, message, severity = "error") => issues.push({
2792
+ code,
2793
+ path: path3,
2794
+ severity,
2795
+ message
2796
+ }), "push");
2797
+ const checkSpec = /* @__PURE__ */ __name3((spec, path3) => {
2798
+ const r = ApproverSpecSchema.safeParse(spec);
2799
+ if (!r.success) {
2800
+ const users = spec?.users;
2801
+ if (Array.isArray(users) && users.length > APPROVER_SPEC_MAX_USERS) push("cap-exceeded", path3, `at most ${APPROVER_SPEC_MAX_USERS} users`);
2802
+ else {
2803
+ const refusal = describeApproverSpecRefusal(spec);
2804
+ issues.push({
2805
+ code: "approver-invalid",
2806
+ path: path3,
2807
+ severity: "error",
2808
+ message: refusal.message,
2809
+ repair: {
2810
+ approver: refusal.approver,
2811
+ written: refusal.written
2812
+ }
2813
+ });
2814
+ }
2815
+ return;
2816
+ }
2817
+ const s = r.data;
2818
+ if (typeof s === "object") {
2819
+ if ("governance" in s && !opts.governanceEnabled) push("approver-governance-unavailable", path3, "governance reviewer routing is not enabled for this deployment");
2820
+ if ("group" in s && typeof s.group === "string" && !opts.scimEnabled && opts.idpGroups?.includes(s.group)) push("approver-idp-group-unavailable", path3, "IdP-group approvers are not enabled for this deployment");
2821
+ const binding = "users" in s ? s.users : "role" in s ? s.role : "group" in s ? s.group : void 0;
2822
+ if (isTemplateBinding(binding)) {
2823
+ if (!bindingRootsOk(binding.template)) push("approver-binding-invalid", `${path3}.template`, "binding root must be initData / stepResults / requestContext / state");
2824
+ if ("users" in s && opts.customerReachable) push("approver-binding-customer-reachable", `${path3}.users`, "a customer-reachable workflow may not bind its approver list");
2825
+ }
2826
+ }
2827
+ }, "checkSpec");
2828
+ if (node.approver !== void 0) checkSpec(node.approver, `${opts.path}.approver`);
2829
+ if (node.fourEyes !== void 0) {
2830
+ const r = FourEyesSchema.safeParse(node.fourEyes);
2831
+ if (!r.success) push("approver-invalid", `${opts.path}.fourEyes`, "fourEyes needs { edit, approve } approver specs");
2832
+ else {
2833
+ checkSpec(r.data.edit, `${opts.path}.fourEyes.edit`);
2834
+ checkSpec(r.data.approve, `${opts.path}.fourEyes.approve`);
2835
+ }
2836
+ if (!approvalEditable(node)) push("four-eyes-requires-editable", `${opts.path}.fourEyes`, "fourEyes requires editable:true");
2837
+ if (node.approver !== void 0) push("four-eyes-overrides-approver", `${opts.path}.approver`, "fourEyes replaces approver", "warning");
2838
+ if (node.itemsPath) push("four-eyes-items-unsupported", `${opts.path}.fourEyes`, "fourEyes cannot combine with itemsPath");
2839
+ }
2840
+ 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");
2841
+ if (Array.isArray(node.onTimeout)) {
2842
+ const chain = node.onTimeout;
2843
+ const hops = chain.filter((m) => typeof m === "object" && m !== null && "escalateTo" in m);
2844
+ if (hops.length > ESCALATION_MAX_HOPS) push("escalation-chain-too-long", `${opts.path}.onTimeout`, `at most ${ESCALATION_MAX_HOPS} hops`);
2845
+ const last = chain[chain.length - 1];
2846
+ if (typeof last === "object" && last !== null) push("escalation-chain-not-terminal", `${opts.path}.onTimeout`, "a chain must end in deny | cancel-run | fail");
2847
+ hops.forEach((h, i) => checkSpec(h.escalateTo, `${opts.path}.onTimeout[${i}].escalateTo`));
2848
+ } else if (typeof node.onTimeout === "object" && node.onTimeout !== null) {
2849
+ checkSpec(node.onTimeout.escalateTo, `${opts.path}.onTimeout.escalateTo`);
2850
+ }
2851
+ return issues;
2852
+ }
2853
+ function liftRenderedApprover(row, rendered) {
2854
+ const text = (rendered ?? "").trim();
2855
+ if (!text) return null;
2856
+ if (row === "users") {
2857
+ let members = null;
2858
+ if (text.startsWith("[")) {
2859
+ try {
2860
+ members = JSON.parse(text);
2861
+ } catch {
2862
+ return null;
2863
+ }
2864
+ } else members = text.split(",").map((s) => s.trim());
2865
+ if (!Array.isArray(members) || members.length === 0 || members.length > APPROVER_SPEC_MAX_USERS) return null;
2866
+ if (!members.every((m) => typeof m === "string" && m.length > 0 && m.length <= 128)) return null;
2867
+ return {
2868
+ users: [
2869
+ ...new Set(members)
2870
+ ].sort()
2871
+ };
2872
+ }
2873
+ if (text.length > 128 || text.startsWith("[") || text.startsWith("{")) return null;
2874
+ return row === "role" ? {
2875
+ role: text
2876
+ } : {
2877
+ group: text
2878
+ };
2879
+ }
2669
2880
  function workspaceTemplatePath(template22) {
2670
2881
  const key = template22.trim();
2671
2882
  const expr = WORKSPACE_TEMPLATE_EXPR_RE.exec(key);
@@ -2682,6 +2893,9 @@ function retryBackoffs() {
2682
2893
  function sleepUntilUnsupportedMessage(id) {
2683
2894
  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} }`;
2684
2895
  }
2896
+ function armSubrunUnsupportedMessage(id, workflowId) {
2897
+ 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)`;
2898
+ }
2685
2899
  function fillPolicy(node, defaultTimeout) {
2686
2900
  if (node.tier === void 0 && node.workspace !== void 0 && node.workspace !== "inherit") node.tier = "job";
2687
2901
  if (node.timeoutSeconds === void 0) node.timeoutSeconds = node.tier === "job" ? WORKFLOW_JOB_DEFAULT_TIMEOUT_SECONDS : defaultTimeout;
@@ -2707,7 +2921,6 @@ function fillSingle(node) {
2707
2921
  fillPolicy(node, WORKFLOW_STEP_DEFAULT_TIMEOUT_SECONDS);
2708
2922
  return;
2709
2923
  case "workflow":
2710
- if (node.workflowId === WORKFLOW_ARM_SUBRUN_ID && Array.isArray(node.graph) && node.graph[1]) fillSingle(node.graph[1]);
2711
2924
  return;
2712
2925
  }
2713
2926
  }
@@ -2839,8 +3052,14 @@ function nodeStepRefs(entry) {
2839
3052
  case "agent": {
2840
3053
  const a = entry;
2841
3054
  const p = a.promptTemplate;
2842
- return typeof p === "string" ? templateStepRefs(p) : p && "template" in p ? templateStepRefs(p.template) : [];
3055
+ const prompt = typeof p === "string" ? templateStepRefs(p) : p && "template" in p ? templateStepRefs(p.template) : [];
3056
+ return [
3057
+ ...prompt,
3058
+ ...mapConfigStepRefs(a.input)
3059
+ ];
2843
3060
  }
3061
+ case "step":
3062
+ return mapConfigStepRefs(entry.input);
2844
3063
  case "tool":
2845
3064
  return mapConfigStepRefs(entry.input);
2846
3065
  case "workflow":
@@ -3057,6 +3276,21 @@ function validateLuaExtensions(g, caps = WORKFLOW_CAPS_DEFAULT, opts = {
3057
3276
  err("job-tier-provider-unsupported", `model provider '${provider}' is outside LUA_WF_JOB_PROVIDERS [${opts.policy.jobProviders.join(", ")}]`, `${path3}.model`, id);
3058
3277
  }
3059
3278
  }, "checkTier");
3279
+ const checkModel = /* @__PURE__ */ __name3((node, path3) => {
3280
+ if (node.type !== "agent" || typeof node.model !== "string") return;
3281
+ const registry = opts.approvedModels;
3282
+ if (registry === void 0) return;
3283
+ const id = singleId(node);
3284
+ if (registry === "unavailable") {
3285
+ const pin = node.model.trim();
3286
+ if (pin && !normalizeModelId(pin, []).ok) {
3287
+ 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)`, `${path3}.model`, id);
3288
+ }
3289
+ return;
3290
+ }
3291
+ const resolved = normalizeModelId(node.model, registry);
3292
+ if (!resolved.ok) err("model-unresolved", modelUnresolvedMessage(resolved), `${path3}.model`, id);
3293
+ }, "checkModel");
3060
3294
  const checkWorkspace = /* @__PURE__ */ __name3((node, path3) => {
3061
3295
  const id = singleId(node);
3062
3296
  const ws = workspaceOf(node);
@@ -3109,38 +3343,29 @@ function validateLuaExtensions(g, caps = WORKFLOW_CAPS_DEFAULT, opts = {
3109
3343
  }
3110
3344
  }, "checkMapMembers");
3111
3345
  const checkInputShape = /* @__PURE__ */ __name3((node, path3) => {
3112
- if (node.type !== "tool" && node.type !== "workflow") return;
3113
3346
  const input = node.input;
3114
3347
  if (input === void 0) return;
3348
+ const id = singleId(node);
3115
3349
  if (input !== null && typeof input === "object" && !Array.isArray(input)) {
3116
- checkMapMembers(input, `${path3}.input`, node.id);
3350
+ checkMapMembers(input, `${path3}.input`, id);
3117
3351
  return;
3118
3352
  }
3119
- 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)})`, `${path3}.input`, node.id);
3353
+ 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)})`, `${path3}.input`, id);
3120
3354
  }, "checkInputShape");
3355
+ const checkBodyInput = /* @__PURE__ */ __name3((body, path3, container) => {
3356
+ if (body.type === "workflow" || body.input === void 0) return;
3357
+ 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`, `${path3}.input`, singleId(body));
3358
+ }, "checkBodyInput");
3121
3359
  const checkSingle = /* @__PURE__ */ __name3((node, path3, depth) => {
3122
3360
  recordOutputSchema(node);
3123
- if (node.type === "workflow" && node.workflowId === WORKFLOW_ARM_SUBRUN_ID) {
3361
+ if (node.type === "workflow" && (typeof node.workflowId !== "string" || node.workflowId.length === 0)) {
3124
3362
  checkId(node.id, path3);
3125
- const body = node.graph;
3126
- if (!Array.isArray(body) || body.length !== 2 || body[0]?.type !== "mapping" || !body[1]) {
3127
- err("container-arm-empty", "an implicit arm subrun needs a [mapping, step] body", `${path3}.graph`, node.id);
3128
- return;
3129
- }
3130
- if (body[1].type === "mapping") {
3131
- err("container-arm-empty", "a bare mapping arm has nothing to run", `${path3}.graph.1`, node.id);
3132
- return;
3133
- }
3134
- const inner = body[1];
3135
- if (isHitlNode(inner)) {
3136
- err("node-type-unsupported-in-container", workflowHitlArmShapeMessage(inner.type, inner.id, "mapped-arm"), `${path3}.graph.1`, inner.id);
3137
- return;
3138
- }
3139
- upstream.add(singleId(body[1]));
3140
- checkArm(body[0], `${path3}.graph.0`, depth, "parallel");
3141
- checkSingle(body[1], `${path3}.graph.1`, depth);
3142
- upstream.add(body[0].id);
3143
- upstream.add(singleId(body[1]));
3363
+ err("invalid-envelope", `\`workflowId\` must be a non-empty string naming the workflow to start (got ${JSON.stringify(node.workflowId)})`, `${path3}.workflowId`, node.id);
3364
+ return;
3365
+ }
3366
+ if (node.type === "workflow" && (node.workflowId.startsWith("$") || Array.isArray(node.graph))) {
3367
+ checkId(node.id, path3);
3368
+ err("node-type-unsupported-by-engine", armSubrunUnsupportedMessage(node.id, node.workflowId), path3, node.id);
3144
3369
  return;
3145
3370
  }
3146
3371
  checkId(singleId(node), path3);
@@ -3148,6 +3373,7 @@ function validateLuaExtensions(g, caps = WORKFLOW_CAPS_DEFAULT, opts = {
3148
3373
  checkInputShape(node, path3);
3149
3374
  checkTimeout(node, path3);
3150
3375
  checkTier(node, path3);
3376
+ checkModel(node, path3);
3151
3377
  checkRetry(node, path3);
3152
3378
  checkWorkspace(node, path3);
3153
3379
  if (!opts.static) {
@@ -3170,7 +3396,7 @@ function validateLuaExtensions(g, caps = WORKFLOW_CAPS_DEFAULT, opts = {
3170
3396
  if (node.type === "workflow" && node.kind === "subrun" && depth > caps.maxNestingDepth) {
3171
3397
  err("cap-exceeded", `nesting depth ${depth} exceeds ${caps.maxNestingDepth}`, path3, node.id);
3172
3398
  }
3173
- if (node.type === "workflow" && node.workflowId !== WORKFLOW_ARM_SUBRUN_ID && typeof g.definition?.id === "string" && node.workflowId === g.definition.id) {
3399
+ if (node.type === "workflow" && typeof g.definition?.id === "string" && node.workflowId === g.definition.id) {
3174
3400
  err("subrun-cycle", `"${node.id}" starts "${node.workflowId}", which is this workflow itself`, path3, node.id);
3175
3401
  }
3176
3402
  for (const ref of nodeStepRefs(node)) {
@@ -3191,11 +3417,14 @@ function validateLuaExtensions(g, caps = WORKFLOW_CAPS_DEFAULT, opts = {
3191
3417
  if (a.approver === "creator" && a.excludeInitiator === true) {
3192
3418
  err("approver-excludes-only-candidate", "approver:'creator' with excludeInitiator:true always excludes the only candidate", path3, a.id);
3193
3419
  }
3194
- if (a.fourEyes !== void 0 && a.editable !== true) {
3420
+ const editable = approvalEditable(a);
3421
+ if (a.fourEyes !== void 0 && !editable) {
3195
3422
  err("four-eyes-requires-editable", "`fourEyes` requires editable:true", `${path3}.fourEyes`, a.id);
3196
3423
  }
3197
- if ((a.editablePaths !== void 0 || a.editedPayloadSchema !== void 0) && a.editable !== true) {
3198
- err("editable-path-invalid", "`editablePaths` / `editedPayloadSchema` require editable:true", `${path3}.editablePaths`, a.id);
3424
+ if (a.editable === false && Array.isArray(a.editablePaths) && a.editablePaths.length > 0) {
3425
+ err("editable-path-invalid", "`editablePaths` beside editable:false is contradictory \u2014 drop the paths or set editable:true", `${path3}.editablePaths`, a.id);
3426
+ } else if ((a.editablePaths !== void 0 || a.editedPayloadSchema !== void 0) && !editable) {
3427
+ err("editable-path-invalid", "`editablePaths` / `editedPayloadSchema` require editable:true (a non-empty editablePaths implies it)", `${path3}.editablePaths`, a.id);
3199
3428
  }
3200
3429
  for (const p of a.editablePaths ?? []) {
3201
3430
  if (!EDITABLE_PATH_RE.test(p)) err("editable-path-invalid", `editablePaths entry "${p}" is outside the seg(.seg)*[*]/[n] grammar`, `${path3}.editablePaths`, a.id);
@@ -3376,6 +3605,7 @@ function validateLuaExtensions(g, caps = WORKFLOW_CAPS_DEFAULT, opts = {
3376
3605
  } else checkHitlArm(f.step, `${path3}.step`, "foreach");
3377
3606
  declared.push(f.step.id);
3378
3607
  } else {
3608
+ checkBodyInput(f.step, `${path3}.step`, "foreach");
3379
3609
  checkSingle(f.step, `${path3}.step`, o.chunk ? 2 : 1);
3380
3610
  declared.push(singleId(f.step));
3381
3611
  }
@@ -3396,6 +3626,7 @@ function validateLuaExtensions(g, caps = WORKFLOW_CAPS_DEFAULT, opts = {
3396
3626
  checkHitlArm(l.step, `${path3}.step`, "loop");
3397
3627
  declared.push(l.step.id);
3398
3628
  } else {
3629
+ checkBodyInput(l.step, `${path3}.step`, "loop");
3399
3630
  checkSingle(l.step, `${path3}.step`, 1);
3400
3631
  declared.push(singleId(l.step));
3401
3632
  }
@@ -3869,17 +4100,10 @@ function isContinuedFailureValue(v) {
3869
4100
  const err = o.error;
3870
4101
  return o.__lua_workflow === CONTINUED_FAILURE_TAG && o.failed === true && o.text === "" && err !== null && typeof err === "object" && typeof err.code === "string" && typeof err.message === "string";
3871
4102
  }
3872
- function lowerContainerArm(mapping, step22) {
3873
- const stepId = nodeIdOf(step22);
4103
+ function inlineContainerArm(mapping, step22) {
3874
4104
  return {
3875
- type: "workflow",
3876
- id: `${stepId}_arm`,
3877
- workflowId: WORKFLOW_ARM_SUBRUN_ID,
3878
- kind: "subrun",
3879
- graph: [
3880
- mapping,
3881
- step22
3882
- ]
4105
+ ...step22,
4106
+ input: parseMapConfig(mapping.mapConfig, mapping.id)
3883
4107
  };
3884
4108
  }
3885
4109
  function entryIds(entry) {
@@ -3949,6 +4173,27 @@ function resolvePlacements(calls) {
3949
4173
  break;
3950
4174
  }
3951
4175
  });
4176
+ const armMapPlacementIssue = /* @__PURE__ */ __name3((node, ref, i, container) => {
4177
+ if (!ref.armMap || node.type === "mapping" || isHitlNode2(node)) return void 0;
4178
+ const id = nodeIdOf(node);
4179
+ if ((container === "foreach" || container === "loop") && node.type !== "workflow") {
4180
+ return {
4181
+ code: "mapping-placement",
4182
+ 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`,
4183
+ callIndex: i,
4184
+ stepId: id
4185
+ };
4186
+ }
4187
+ if (node.input !== void 0) {
4188
+ return {
4189
+ code: "mapping-placement",
4190
+ 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)`,
4191
+ callIndex: i,
4192
+ stepId: id
4193
+ };
4194
+ }
4195
+ return void 0;
4196
+ }, "armMapPlacementIssue");
3952
4197
  const hitlPlacementIssue = /* @__PURE__ */ __name3((node, ref, i, container) => {
3953
4198
  if (!isHitlNode2(node)) return void 0;
3954
4199
  const id = node.id;
@@ -3975,7 +4220,7 @@ function resolvePlacements(calls) {
3975
4220
  if (ref.node.type === "mapping" && !allowMapping) {
3976
4221
  issues.push({
3977
4222
  code: "mapping-placement",
3978
- message: `mapping "${ref.node.id}" cannot be a container arm \u2014 chain it as [map, step]`,
4223
+ 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`,
3979
4224
  callIndex: i,
3980
4225
  stepId: ref.node.id
3981
4226
  });
@@ -3996,7 +4241,7 @@ function resolvePlacements(calls) {
3996
4241
  if (d.node.type === "mapping" && !allowMapping) {
3997
4242
  issues.push({
3998
4243
  code: "mapping-placement",
3999
- message: `map "${ref.ref}" cannot be a parallel/foreach/loop arm \u2014 chain it as [map, step]`,
4244
+ 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`,
4000
4245
  callIndex: i,
4001
4246
  stepId: ref.ref
4002
4247
  });
@@ -4007,6 +4252,11 @@ function resolvePlacements(calls) {
4007
4252
  issues.push(hitl);
4008
4253
  return void 0;
4009
4254
  }
4255
+ const mapped = armMapPlacementIssue(d.node, ref, i, container);
4256
+ if (mapped) {
4257
+ issues.push(mapped);
4258
+ return void 0;
4259
+ }
4010
4260
  const prior = placedBy.get(ref.ref);
4011
4261
  if (prior !== void 0 && prior !== i) {
4012
4262
  issues.push({
@@ -4027,6 +4277,10 @@ function resolvePlacements(calls) {
4027
4277
  }
4028
4278
  const hitl = hitlPlacementIssue(ref.node, ref, i, container);
4029
4279
  if (hitl) issues.push(hitl);
4280
+ else {
4281
+ const mapped = armMapPlacementIssue(ref.node, ref, i, container);
4282
+ if (mapped) issues.push(mapped);
4283
+ }
4030
4284
  }, "claim");
4031
4285
  calls.forEach((call, i) => {
4032
4286
  switch (call.kind) {
@@ -4054,7 +4308,7 @@ function resolvePlacements(calls) {
4054
4308
  const lookup = /* @__PURE__ */ __name3((ref) => {
4055
4309
  const n2 = "node" in ref ? ref.node : declared.get(ref.ref)?.node;
4056
4310
  if (!n2 || !ref.armMap || n2.type === "mapping" || isHitlNode2(n2)) return n2;
4057
- return lowerContainerArm(ref.armMap, n2);
4311
+ return inlineContainerArm(ref.armMap, n2);
4058
4312
  }, "lookup");
4059
4313
  calls.forEach((call, i) => {
4060
4314
  switch (call.kind) {
@@ -4439,6 +4693,27 @@ function isTerminalRunStatus(status) {
4439
4693
  function pruneUndefined(o) {
4440
4694
  return Object.fromEntries(Object.entries(o).filter(([, v]) => v !== void 0));
4441
4695
  }
4696
+ function runOrigin(run) {
4697
+ if (run.goalId) return "goal";
4698
+ if (run.jobId || run.trigger === "schedule") return "schedule";
4699
+ if (run.dynamic === true) return run.tags?.includes(WORKFLOW_INLINE_RUN_TAG) ? "inline" : "compose";
4700
+ return "definition";
4701
+ }
4702
+ function runErrorIssues(issues) {
4703
+ if (!Array.isArray(issues)) return void 0;
4704
+ const out = [];
4705
+ for (const raw of issues.slice(0, RUN_ERROR_ISSUES_MAX)) {
4706
+ if (!raw || typeof raw !== "object") continue;
4707
+ const o = raw;
4708
+ if (typeof o.code !== "string" || !o.code) continue;
4709
+ out.push(pruneUndefined({
4710
+ code: o.code,
4711
+ path: typeof o.path === "string" ? o.path : void 0,
4712
+ message: typeof o.message === "string" ? o.message : void 0
4713
+ }));
4714
+ }
4715
+ return out.length ? out : void 0;
4716
+ }
4442
4717
  function runNextAction(run) {
4443
4718
  if (isTerminalRunStatus(run.status)) return "none";
4444
4719
  if (run.status === "suspended" && run.gate?.kind === "budget") return "raise_budget";
@@ -4608,6 +4883,7 @@ function toWorkflowRunSummary(run) {
4608
4883
  repairOf: run.repairOf,
4609
4884
  repairRunIds: run.repairRunIds,
4610
4885
  trigger: run.trigger ?? "api",
4886
+ origin: runOrigin(run),
4611
4887
  createdBy: {
4612
4888
  subjectType: principal?.subjectType ?? "system",
4613
4889
  subjectId: principal?.subjectId ?? run.userId ?? ""
@@ -4625,11 +4901,13 @@ function toWorkflowRunSummary(run) {
4625
4901
  usage: runUsage(run),
4626
4902
  // LUA-697: a row persisted before the write seams (#2406 / #2465 / the script tier) leaves scrubbed here too —
4627
4903
  // idempotent on a scrubbed message, bounded input; an empty message falls back to the code.
4628
- error: run.error ? {
4904
+ error: run.error ? pruneUndefined({
4629
4905
  code: run.error.code ?? "error",
4630
4906
  message: scrubStepErrorMessage(run.error.message) ?? run.error.code ?? "error",
4631
- stepId: run.error.stepId
4632
- } : void 0,
4907
+ stepId: run.error.stepId,
4908
+ // LUA-784 (item 3): the unattended pre-start failure's refusal rows (`input_schema_invalid` and kin).
4909
+ issues: runErrorIssues(run.error.issues)
4910
+ }) : void 0,
4633
4911
  kind: "run",
4634
4912
  aclHash: run.aclHash,
4635
4913
  migration: run.migration,
@@ -5110,166 +5388,48 @@ function applyJsonPatch(doc, ops) {
5110
5388
  code: "PATH_NOT_FOUND",
5111
5389
  index: i,
5112
5390
  path: op.path,
5113
- message: "index out of range"
5114
- };
5115
- } else if (op.op === "replace") parent[last] = structuredClone(op.value);
5116
- else parent.splice(last, 1);
5117
- continue;
5118
- }
5119
- if (typeof parent !== "object" || parent === null || typeof last !== "string" && typeof last !== "number") return {
5120
- ok: false,
5121
- code: "PATH_NOT_FOUND",
5122
- index: i,
5123
- path: op.path,
5124
- message: "path not found"
5125
- };
5126
- const obj = parent;
5127
- const key = String(last);
5128
- if (key === "__proto__" || key === "constructor" || key === "prototype") return {
5129
- ok: false,
5130
- code: "PATCH_INVALID",
5131
- index: i,
5132
- path: op.path,
5133
- message: "path not allowed"
5134
- };
5135
- if (op.op === "add") obj[key] = structuredClone(op.value);
5136
- else if (!(key in obj)) return {
5137
- ok: false,
5138
- code: "PATH_NOT_FOUND",
5139
- index: i,
5140
- path: op.path,
5141
- message: "path not found"
5142
- };
5143
- else if (op.op === "replace") obj[key] = structuredClone(op.value);
5144
- else delete obj[key];
5145
- }
5146
- return {
5147
- ok: true,
5148
- value: value22
5149
- };
5150
- }
5151
- function rebaseItemPointer(pointer, itemsPath, index) {
5152
- const base = `/${itemsPath.split(".").map(escapePointer).join("/")}/${index}`;
5153
- return pointer === "/" || pointer === "" ? base : `${base}${pointer}`;
5154
- }
5155
- function describeApproverSpecRefusal(spec) {
5156
- const raw = spec === void 0 ? "undefined" : JSON.stringify(spec) ?? String(spec);
5157
- const written = raw.length > APPROVER_WRITTEN_MAX ? `${raw.slice(0, APPROVER_WRITTEN_MAX - 1)}\u2026` : raw;
5158
- const users = typeof spec === "object" && spec !== null ? spec.users : void 0;
5159
- const approver = typeof users === "string" && USER_ID_SHAPED_RE.test(users) ? {
5160
- users: [
5161
- users
5162
- ]
5163
- } : "creator";
5164
- 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)}`);
5165
- return {
5166
- approver,
5167
- written,
5168
- message
5169
- };
5170
- }
5171
- function bindingRootsOk(template22) {
5172
- const refs = [
5173
- ...template22.matchAll(/\$\{\s*([A-Za-z_$][\w$]*)/g)
5174
- ].map((m) => m[1]);
5175
- return refs.length > 0 && refs.every((r) => BINDING_ROOTS.includes(r));
5176
- }
5177
- function isTemplateBinding(v) {
5178
- return typeof v === "object" && v !== null && typeof v.template === "string";
5179
- }
5180
- function validateApproverBlock(node, opts = {
5181
- path: "approval"
5182
- }) {
5183
- const issues = [];
5184
- const push = /* @__PURE__ */ __name3((code, path3, message, severity = "error") => issues.push({
5185
- code,
5186
- path: path3,
5187
- severity,
5188
- message
5189
- }), "push");
5190
- const checkSpec = /* @__PURE__ */ __name3((spec, path3) => {
5191
- const r = ApproverSpecSchema.safeParse(spec);
5192
- if (!r.success) {
5193
- const users = spec?.users;
5194
- if (Array.isArray(users) && users.length > APPROVER_SPEC_MAX_USERS) push("cap-exceeded", path3, `at most ${APPROVER_SPEC_MAX_USERS} users`);
5195
- else {
5196
- const refusal = describeApproverSpecRefusal(spec);
5197
- issues.push({
5198
- code: "approver-invalid",
5199
- path: path3,
5200
- severity: "error",
5201
- message: refusal.message,
5202
- repair: {
5203
- approver: refusal.approver,
5204
- written: refusal.written
5205
- }
5206
- });
5207
- }
5208
- return;
5209
- }
5210
- const s = r.data;
5211
- if (typeof s === "object") {
5212
- if ("governance" in s && !opts.governanceEnabled) push("approver-governance-unavailable", path3, "governance reviewer routing is not enabled for this deployment");
5213
- if ("group" in s && typeof s.group === "string" && !opts.scimEnabled && opts.idpGroups?.includes(s.group)) push("approver-idp-group-unavailable", path3, "IdP-group approvers are not enabled for this deployment");
5214
- const binding = "users" in s ? s.users : "role" in s ? s.role : "group" in s ? s.group : void 0;
5215
- if (isTemplateBinding(binding)) {
5216
- if (!bindingRootsOk(binding.template)) push("approver-binding-invalid", `${path3}.template`, "binding root must be initData / stepResults / requestContext / state");
5217
- if ("users" in s && opts.customerReachable) push("approver-binding-customer-reachable", `${path3}.users`, "a customer-reachable workflow may not bind its approver list");
5218
- }
5219
- }
5220
- }, "checkSpec");
5221
- if (node.approver !== void 0) checkSpec(node.approver, `${opts.path}.approver`);
5222
- if (node.fourEyes !== void 0) {
5223
- const r = FourEyesSchema.safeParse(node.fourEyes);
5224
- if (!r.success) push("approver-invalid", `${opts.path}.fourEyes`, "fourEyes needs { edit, approve } approver specs");
5225
- else {
5226
- checkSpec(r.data.edit, `${opts.path}.fourEyes.edit`);
5227
- checkSpec(r.data.approve, `${opts.path}.fourEyes.approve`);
5228
- }
5229
- if (!node.editable) push("four-eyes-requires-editable", `${opts.path}.fourEyes`, "fourEyes requires editable:true");
5230
- if (node.approver !== void 0) push("four-eyes-overrides-approver", `${opts.path}.approver`, "fourEyes replaces approver", "warning");
5231
- if (node.itemsPath) push("four-eyes-items-unsupported", `${opts.path}.fourEyes`, "fourEyes cannot combine with itemsPath");
5232
- }
5233
- 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");
5234
- if (Array.isArray(node.onTimeout)) {
5235
- const chain = node.onTimeout;
5236
- const hops = chain.filter((m) => typeof m === "object" && m !== null && "escalateTo" in m);
5237
- if (hops.length > ESCALATION_MAX_HOPS) push("escalation-chain-too-long", `${opts.path}.onTimeout`, `at most ${ESCALATION_MAX_HOPS} hops`);
5238
- const last = chain[chain.length - 1];
5239
- if (typeof last === "object" && last !== null) push("escalation-chain-not-terminal", `${opts.path}.onTimeout`, "a chain must end in deny | cancel-run | fail");
5240
- hops.forEach((h, i) => checkSpec(h.escalateTo, `${opts.path}.onTimeout[${i}].escalateTo`));
5241
- } else if (typeof node.onTimeout === "object" && node.onTimeout !== null) {
5242
- checkSpec(node.onTimeout.escalateTo, `${opts.path}.onTimeout.escalateTo`);
5243
- }
5244
- return issues;
5245
- }
5246
- function liftRenderedApprover(row, rendered) {
5247
- const text = (rendered ?? "").trim();
5248
- if (!text) return null;
5249
- if (row === "users") {
5250
- let members = null;
5251
- if (text.startsWith("[")) {
5252
- try {
5253
- members = JSON.parse(text);
5254
- } catch {
5255
- return null;
5256
- }
5257
- } else members = text.split(",").map((s) => s.trim());
5258
- if (!Array.isArray(members) || members.length === 0 || members.length > APPROVER_SPEC_MAX_USERS) return null;
5259
- if (!members.every((m) => typeof m === "string" && m.length > 0 && m.length <= 128)) return null;
5260
- return {
5261
- users: [
5262
- ...new Set(members)
5263
- ].sort()
5391
+ message: "index out of range"
5392
+ };
5393
+ } else if (op.op === "replace") parent[last] = structuredClone(op.value);
5394
+ else parent.splice(last, 1);
5395
+ continue;
5396
+ }
5397
+ if (typeof parent !== "object" || parent === null || typeof last !== "string" && typeof last !== "number") return {
5398
+ ok: false,
5399
+ code: "PATH_NOT_FOUND",
5400
+ index: i,
5401
+ path: op.path,
5402
+ message: "path not found"
5403
+ };
5404
+ const obj = parent;
5405
+ const key = String(last);
5406
+ if (key === "__proto__" || key === "constructor" || key === "prototype") return {
5407
+ ok: false,
5408
+ code: "PATCH_INVALID",
5409
+ index: i,
5410
+ path: op.path,
5411
+ message: "path not allowed"
5412
+ };
5413
+ if (op.op === "add") obj[key] = structuredClone(op.value);
5414
+ else if (!(key in obj)) return {
5415
+ ok: false,
5416
+ code: "PATH_NOT_FOUND",
5417
+ index: i,
5418
+ path: op.path,
5419
+ message: "path not found"
5264
5420
  };
5421
+ else if (op.op === "replace") obj[key] = structuredClone(op.value);
5422
+ else delete obj[key];
5265
5423
  }
5266
- if (text.length > 128 || text.startsWith("[") || text.startsWith("{")) return null;
5267
- return row === "role" ? {
5268
- role: text
5269
- } : {
5270
- group: text
5424
+ return {
5425
+ ok: true,
5426
+ value: value22
5271
5427
  };
5272
5428
  }
5429
+ function rebaseItemPointer(pointer, itemsPath, index) {
5430
+ const base = `/${itemsPath.split(".").map(escapePointer).join("/")}/${index}`;
5431
+ return pointer === "/" || pointer === "" ? base : `${base}${pointer}`;
5432
+ }
5273
5433
  function collectEnvTemplateKeys(value22) {
5274
5434
  const keys = /* @__PURE__ */ new Set();
5275
5435
  const walk22 = /* @__PURE__ */ __name3((v) => {
@@ -5518,7 +5678,6 @@ function* singleStepsOf(entry) {
5518
5678
  return;
5519
5679
  case "workflow":
5520
5680
  yield entry;
5521
- if (Array.isArray(entry.graph)) yield* singleStepsOf(entry.graph[1]);
5522
5681
  return;
5523
5682
  case "parallel":
5524
5683
  case "conditional":
@@ -5560,7 +5719,7 @@ function needsInheritedWorkspace(graph) {
5560
5719
  }
5561
5720
  return false;
5562
5721
  }
5563
- var __defProp3, __name3, WorkflowTemplateError, TEMPLATE_PLACEHOLDER, TEMPLATE_NAMESPACES, MAP_DESCRIPTOR_KEYS, MAP_MEMBER_MALFORMED_CODE, fromInit, fromStep, value, template, fromRequest, rows, fromKnowledge, SideEffectsSchema, JobResourcesSchema, WORKFLOW_ARM_SUBRUN_ID, WORKSPACE_TEMPLATE_EXPR_RE, SLEEP_UNTIL_REPLACEMENT, WORKFLOW_CAPS_DEFAULT, WORKFLOW_STEP_DEFAULT_TIMEOUT_SECONDS, WORKFLOW_AGENT_DEFAULT_TIMEOUT_SECONDS, WORKFLOW_JOB_DEFAULT_TIMEOUT_SECONDS, WORKFLOW_FOREACH_DEFAULT_CONCURRENCY, WORKFLOW_FOREACH_DEFAULT_MAX_ITEMS, WORKFLOW_LOOP_DEFAULT_MAX_ITERATIONS, WORKFLOW_SUSPEND_DEFAULT_TIMEOUT_HOURS, WORKFLOW_SIGNAL_DEFAULT_SOURCES, clone, CONNECTION_ID_HEX_RE, WORKFLOW_JOB_TOOLS, WORKFLOW_JOB_MAX_WORKTREE_ARMS, workspaceOf, mountsWorkspace, isJobTier, jobToolsOf, schemaIsArray, isHitlNode, isSingleStep, singleId, armId, TEMPLATE_STEP_REF, EDITABLE_PATH_RE, PREDICATE_OPS, isPredicateScalar, GRAPH_HASH_PREFIX, WorkflowPlanError, isArmStep, armStepId, armStepKind, joinIdOf, containerIdOf, PATH_PLACEHOLDER, MISSING, stepIdOf, cmp, eq, ne, gt, gte, lt, lte, inSet, notIn, exists, notExists, truthy, falsy, and, or, not, CONTINUED_FAILURE_TAG, CONTINUED_FAILURE_DEFAULT_CODE, CONTINUED_FAILURE_OUTPUT_SCHEMA, CONTINUED_FAILURE_LEAF_PATHS, isHitlNode2, nodeIdOf, GOAL_JUDGE_STEP_ID, NON_LEAF_KINDS, CONDITIONAL_JOIN_ID, branchArmId, canonical, sortKeys, JOIN, entryOfJoin, FORCE_CANCEL_STALE_MS, TERMINAL, IN_FLIGHT, n, STEP_ERROR_DETAIL_KEYS, STEP_ERROR_DETAIL_MAX_BYTES, DETAIL_MAX_DEPTH, DETAIL_MAX_ITEMS, MAX_HOLIDAYS, MAX_WALK_DAYS, HHMM, YMD, MS_PER_MIN, MS_PER_DAY, MON_FRI, supportedTz, fmtCache, WEEKDAYS, JSON_PATCH_OPS, JSON_PATCH_MAX_OPS, JSON_PATCH_MAX_VALUE_BYTES, JSON_PATCH_MAX_TOTAL_BYTES, SEGMENT_RE, APPROVER_SPEC_MAX_USERS, ESCALATION_MAX_HOPS, TemplateBindingSchema, ApproverSpecSchema, FourEyesSchema, EscalationHopSchema, TerminalOutcomeSchema, ApprovalOnTimeoutSchema, APPROVER_SPEC_SHAPES, APPROVER_WRITTEN_MAX, USER_ID_SHAPED_RE, BINDING_ROOTS, WORKFLOW_ENV_OVERLAY_MAX_KEYS, WORKFLOW_ENV_OVERLAY_MAX_VALUE_BYTES, WORKFLOW_ENV_TEMPLATE_SECRET_KEY_RE, isEnvRef, looksLikeEmbeddedJson, ZERO, isRecord2;
5722
+ var __defProp3, __name3, WorkflowTemplateError, TEMPLATE_PLACEHOLDER, TEMPLATE_NAMESPACES, MAP_DESCRIPTOR_KEYS, MAP_MEMBER_MALFORMED_CODE, fromInit, fromStep, value, template, fromRequest, rows, fromKnowledge, SideEffectsSchema, JobResourcesSchema, APPROVER_SPEC_MAX_USERS, ESCALATION_MAX_HOPS, TemplateBindingSchema, ApproverSpecSchema, FourEyesSchema, EscalationHopSchema, TerminalOutcomeSchema, ApprovalOnTimeoutSchema, APPROVER_SPEC_SHAPES, APPROVER_WRITTEN_MAX, USER_ID_SHAPED_RE, BINDING_ROOTS, WORKSPACE_TEMPLATE_EXPR_RE, SLEEP_UNTIL_REPLACEMENT, WORKFLOW_CAPS_DEFAULT, WORKFLOW_STEP_DEFAULT_TIMEOUT_SECONDS, WORKFLOW_AGENT_DEFAULT_TIMEOUT_SECONDS, WORKFLOW_JOB_DEFAULT_TIMEOUT_SECONDS, WORKFLOW_FOREACH_DEFAULT_CONCURRENCY, WORKFLOW_FOREACH_DEFAULT_MAX_ITEMS, WORKFLOW_LOOP_DEFAULT_MAX_ITERATIONS, WORKFLOW_SUSPEND_DEFAULT_TIMEOUT_HOURS, WORKFLOW_SIGNAL_DEFAULT_SOURCES, clone, CONNECTION_ID_HEX_RE, WORKFLOW_JOB_TOOLS, WORKFLOW_JOB_MAX_WORKTREE_ARMS, workspaceOf, mountsWorkspace, isJobTier, jobToolsOf, schemaIsArray, isHitlNode, isSingleStep, singleId, armId, TEMPLATE_STEP_REF, EDITABLE_PATH_RE, PREDICATE_OPS, isPredicateScalar, GRAPH_HASH_PREFIX, WorkflowPlanError, isArmStep, armStepId, armStepKind, joinIdOf, containerIdOf, PATH_PLACEHOLDER, MISSING, stepIdOf, cmp, eq, ne, gt, gte, lt, lte, inSet, notIn, exists, notExists, truthy, falsy, and, or, not, CONTINUED_FAILURE_TAG, CONTINUED_FAILURE_DEFAULT_CODE, CONTINUED_FAILURE_OUTPUT_SCHEMA, CONTINUED_FAILURE_LEAF_PATHS, isHitlNode2, nodeIdOf, GOAL_JUDGE_STEP_ID, NON_LEAF_KINDS, CONDITIONAL_JOIN_ID, branchArmId, canonical, sortKeys, JOIN, entryOfJoin, FORCE_CANCEL_STALE_MS, TERMINAL, WORKFLOW_INLINE_RUN_TAG, RUN_ERROR_ISSUES_MAX, IN_FLIGHT, n, STEP_ERROR_DETAIL_KEYS, STEP_ERROR_DETAIL_MAX_BYTES, DETAIL_MAX_DEPTH, DETAIL_MAX_ITEMS, MAX_HOLIDAYS, MAX_WALK_DAYS, HHMM, YMD, MS_PER_MIN, MS_PER_DAY, MON_FRI, supportedTz, fmtCache, WEEKDAYS, JSON_PATCH_OPS, JSON_PATCH_MAX_OPS, JSON_PATCH_MAX_VALUE_BYTES, JSON_PATCH_MAX_TOTAL_BYTES, SEGMENT_RE, WORKFLOW_ENV_OVERLAY_MAX_KEYS, WORKFLOW_ENV_OVERLAY_MAX_VALUE_BYTES, WORKFLOW_ENV_TEMPLATE_SECRET_KEY_RE, isEnvRef, looksLikeEmbeddedJson, ZERO, isRecord2;
5564
5723
  var init_dist2 = __esm({
5565
5724
  "../workflow-graph/dist/index.mjs"() {
5566
5725
  "use strict";
@@ -5663,7 +5822,88 @@ var init_dist2 = __esm({
5663
5822
  }), "fromKnowledge");
5664
5823
  SideEffectsSchema = z4.enum(WORKFLOW_SIDE_EFFECTS);
5665
5824
  JobResourcesSchema = z4.enum(WORKFLOW_JOB_RESOURCES);
5666
- WORKFLOW_ARM_SUBRUN_ID = "$arm";
5825
+ APPROVER_SPEC_MAX_USERS = 20;
5826
+ ESCALATION_MAX_HOPS = 3;
5827
+ TemplateBindingSchema = z22.object({
5828
+ template: z22.string().min(1).max(2048)
5829
+ }).strict();
5830
+ ApproverSpecSchema = z22.union([
5831
+ z22.literal("creator"),
5832
+ z22.literal("org-admins"),
5833
+ z22.object({
5834
+ users: z22.union([
5835
+ z22.array(z22.string().min(1).max(128)).min(1).max(APPROVER_SPEC_MAX_USERS),
5836
+ TemplateBindingSchema
5837
+ ])
5838
+ }).strict(),
5839
+ z22.object({
5840
+ role: z22.union([
5841
+ z22.string().min(1).max(128),
5842
+ TemplateBindingSchema
5843
+ ])
5844
+ }).strict(),
5845
+ z22.object({
5846
+ group: z22.union([
5847
+ z22.string().min(1).max(128),
5848
+ TemplateBindingSchema
5849
+ ])
5850
+ }).strict(),
5851
+ z22.object({
5852
+ governance: z22.object({
5853
+ policyId: z22.string().min(1).max(128)
5854
+ }).strict()
5855
+ }).strict()
5856
+ ]);
5857
+ FourEyesSchema = z22.object({
5858
+ edit: ApproverSpecSchema,
5859
+ approve: ApproverSpecSchema
5860
+ }).strict();
5861
+ EscalationHopSchema = z22.object({
5862
+ escalateTo: ApproverSpecSchema,
5863
+ timeoutHours: z22.number().finite().min(1).max(720)
5864
+ }).strict();
5865
+ TerminalOutcomeSchema = z22.enum([
5866
+ "deny",
5867
+ "cancel-run",
5868
+ "fail",
5869
+ "continue"
5870
+ ]);
5871
+ ApprovalOnTimeoutSchema = z22.union([
5872
+ TerminalOutcomeSchema,
5873
+ EscalationHopSchema,
5874
+ z22.array(z22.union([
5875
+ TerminalOutcomeSchema,
5876
+ EscalationHopSchema
5877
+ ])).min(1).max(ESCALATION_MAX_HOPS + 1)
5878
+ ]);
5879
+ APPROVER_SPEC_SHAPES = [
5880
+ "'creator'",
5881
+ "'org-admins'",
5882
+ "{users:[userId, \u2026]}",
5883
+ "{role:roleName}",
5884
+ "{group:groupName}",
5885
+ "{governance:{policyId}}"
5886
+ ];
5887
+ APPROVER_WRITTEN_MAX = 120;
5888
+ USER_ID_SHAPED_RE = /^[^\s@]{1,128}$/;
5889
+ __name(describeApproverSpecRefusal, "describeApproverSpecRefusal");
5890
+ __name3(describeApproverSpecRefusal, "describeApproverSpecRefusal");
5891
+ BINDING_ROOTS = [
5892
+ "initData",
5893
+ "stepResults",
5894
+ "requestContext",
5895
+ "state"
5896
+ ];
5897
+ __name(bindingRootsOk, "bindingRootsOk");
5898
+ __name3(bindingRootsOk, "bindingRootsOk");
5899
+ __name(isTemplateBinding, "isTemplateBinding");
5900
+ __name3(isTemplateBinding, "isTemplateBinding");
5901
+ __name(approvalEditable, "approvalEditable");
5902
+ __name3(approvalEditable, "approvalEditable");
5903
+ __name(validateApproverBlock, "validateApproverBlock");
5904
+ __name3(validateApproverBlock, "validateApproverBlock");
5905
+ __name(liftRenderedApprover, "liftRenderedApprover");
5906
+ __name3(liftRenderedApprover, "liftRenderedApprover");
5667
5907
  WORKSPACE_TEMPLATE_EXPR_RE = /^\$\{\s*(?:initData|input)\.([^}]+?)\s*\}$/;
5668
5908
  __name(workspaceTemplatePath, "workspaceTemplatePath");
5669
5909
  __name3(workspaceTemplatePath, "workspaceTemplatePath");
@@ -5675,6 +5915,8 @@ var init_dist2 = __esm({
5675
5915
  });
5676
5916
  __name(sleepUntilUnsupportedMessage, "sleepUntilUnsupportedMessage");
5677
5917
  __name3(sleepUntilUnsupportedMessage, "sleepUntilUnsupportedMessage");
5918
+ __name(armSubrunUnsupportedMessage, "armSubrunUnsupportedMessage");
5919
+ __name3(armSubrunUnsupportedMessage, "armSubrunUnsupportedMessage");
5678
5920
  WORKFLOW_CAPS_DEFAULT = Object.freeze({
5679
5921
  maxParallelArms: 16,
5680
5922
  maxForeachConcurrency: 16,
@@ -5956,8 +6198,8 @@ var init_dist2 = __esm({
5956
6198
  __name(isContinuedFailureValue, "isContinuedFailureValue");
5957
6199
  __name3(isContinuedFailureValue, "isContinuedFailureValue");
5958
6200
  isHitlNode2 = /* @__PURE__ */ __name3((n2) => isWorkflowHitlEntryType(n2.type), "isHitlNode");
5959
- __name(lowerContainerArm, "lowerContainerArm");
5960
- __name3(lowerContainerArm, "lowerContainerArm");
6201
+ __name(inlineContainerArm, "inlineContainerArm");
6202
+ __name3(inlineContainerArm, "inlineContainerArm");
5961
6203
  nodeIdOf = /* @__PURE__ */ __name3((n2) => n2.type === "step" ? n2.step.id : n2.id, "nodeIdOf");
5962
6204
  __name(entryIds, "entryIds");
5963
6205
  __name3(entryIds, "entryIds");
@@ -6017,6 +6259,12 @@ var init_dist2 = __esm({
6017
6259
  __name3(isTerminalRunStatus, "isTerminalRunStatus");
6018
6260
  __name(pruneUndefined, "pruneUndefined");
6019
6261
  __name3(pruneUndefined, "pruneUndefined");
6262
+ WORKFLOW_INLINE_RUN_TAG = "inline";
6263
+ __name(runOrigin, "runOrigin");
6264
+ __name3(runOrigin, "runOrigin");
6265
+ RUN_ERROR_ISSUES_MAX = 20;
6266
+ __name(runErrorIssues, "runErrorIssues");
6267
+ __name3(runErrorIssues, "runErrorIssues");
6020
6268
  __name(runNextAction, "runNextAction");
6021
6269
  __name3(runNextAction, "runNextAction");
6022
6270
  IN_FLIGHT = new Set(WORKFLOW_STEP_IN_FLIGHT);
@@ -6177,86 +6425,6 @@ var init_dist2 = __esm({
6177
6425
  __name3(applyJsonPatch, "applyJsonPatch");
6178
6426
  __name(rebaseItemPointer, "rebaseItemPointer");
6179
6427
  __name3(rebaseItemPointer, "rebaseItemPointer");
6180
- APPROVER_SPEC_MAX_USERS = 20;
6181
- ESCALATION_MAX_HOPS = 3;
6182
- TemplateBindingSchema = z22.object({
6183
- template: z22.string().min(1).max(2048)
6184
- }).strict();
6185
- ApproverSpecSchema = z22.union([
6186
- z22.literal("creator"),
6187
- z22.literal("org-admins"),
6188
- z22.object({
6189
- users: z22.union([
6190
- z22.array(z22.string().min(1).max(128)).min(1).max(APPROVER_SPEC_MAX_USERS),
6191
- TemplateBindingSchema
6192
- ])
6193
- }).strict(),
6194
- z22.object({
6195
- role: z22.union([
6196
- z22.string().min(1).max(128),
6197
- TemplateBindingSchema
6198
- ])
6199
- }).strict(),
6200
- z22.object({
6201
- group: z22.union([
6202
- z22.string().min(1).max(128),
6203
- TemplateBindingSchema
6204
- ])
6205
- }).strict(),
6206
- z22.object({
6207
- governance: z22.object({
6208
- policyId: z22.string().min(1).max(128)
6209
- }).strict()
6210
- }).strict()
6211
- ]);
6212
- FourEyesSchema = z22.object({
6213
- edit: ApproverSpecSchema,
6214
- approve: ApproverSpecSchema
6215
- }).strict();
6216
- EscalationHopSchema = z22.object({
6217
- escalateTo: ApproverSpecSchema,
6218
- timeoutHours: z22.number().finite().min(1).max(720)
6219
- }).strict();
6220
- TerminalOutcomeSchema = z22.enum([
6221
- "deny",
6222
- "cancel-run",
6223
- "fail",
6224
- "continue"
6225
- ]);
6226
- ApprovalOnTimeoutSchema = z22.union([
6227
- TerminalOutcomeSchema,
6228
- EscalationHopSchema,
6229
- z22.array(z22.union([
6230
- TerminalOutcomeSchema,
6231
- EscalationHopSchema
6232
- ])).min(1).max(ESCALATION_MAX_HOPS + 1)
6233
- ]);
6234
- APPROVER_SPEC_SHAPES = [
6235
- "'creator'",
6236
- "'org-admins'",
6237
- "{users:[userId, \u2026]}",
6238
- "{role:roleName}",
6239
- "{group:groupName}",
6240
- "{governance:{policyId}}"
6241
- ];
6242
- APPROVER_WRITTEN_MAX = 120;
6243
- USER_ID_SHAPED_RE = /^[^\s@]{1,128}$/;
6244
- __name(describeApproverSpecRefusal, "describeApproverSpecRefusal");
6245
- __name3(describeApproverSpecRefusal, "describeApproverSpecRefusal");
6246
- BINDING_ROOTS = [
6247
- "initData",
6248
- "stepResults",
6249
- "requestContext",
6250
- "state"
6251
- ];
6252
- __name(bindingRootsOk, "bindingRootsOk");
6253
- __name3(bindingRootsOk, "bindingRootsOk");
6254
- __name(isTemplateBinding, "isTemplateBinding");
6255
- __name3(isTemplateBinding, "isTemplateBinding");
6256
- __name(validateApproverBlock, "validateApproverBlock");
6257
- __name3(validateApproverBlock, "validateApproverBlock");
6258
- __name(liftRenderedApprover, "liftRenderedApprover");
6259
- __name3(liftRenderedApprover, "liftRenderedApprover");
6260
6428
  WORKFLOW_ENV_OVERLAY_MAX_KEYS = 64;
6261
6429
  WORKFLOW_ENV_OVERLAY_MAX_VALUE_BYTES = 4096;
6262
6430
  WORKFLOW_ENV_TEMPLATE_SECRET_KEY_RE = /(SECRET|TOKEN|KEY|PASSWORD)$/;
@@ -6359,14 +6527,13 @@ function stepNodeOf(s) {
6359
6527
  }
6360
6528
  function materializeEntry(entry, steps) {
6361
6529
  const single = /* @__PURE__ */ __name((n2) => {
6362
- if (n2.type === "step" && steps[n2.step.id]) return stepNodeOf(steps[n2.step.id]);
6363
- if (n2.type === "workflow" && n2.workflowId === WORKFLOW_ARM_SUBRUN_ID && n2.graph) return {
6364
- ...n2,
6365
- graph: [
6366
- n2.graph[0],
6367
- single(n2.graph[1])
6368
- ]
6369
- };
6530
+ if (n2.type === "step" && steps[n2.step.id]) {
6531
+ const node = stepNodeOf(steps[n2.step.id]);
6532
+ return n2.input !== void 0 ? {
6533
+ ...node,
6534
+ input: n2.input
6535
+ } : node;
6536
+ }
6370
6537
  return n2;
6371
6538
  }, "single");
6372
6539
  switch (entry.type) {
@@ -6524,7 +6691,10 @@ var init_workflow = __esm({
6524
6691
  }, "assertPredicate");
6525
6692
  assertRetry = /* @__PURE__ */ __name((r, id) => {
6526
6693
  if (!r) return;
6527
- if (typeof r.maxAttempts === "number" && r.maxAttempts > WORKFLOW_RETRY_MAX_ATTEMPTS) throw new LuaWorkflowBuildError("cap-exceeded", `"${id}": ${workflowRetryMaxAttemptsMessage(r.maxAttempts)}`);
6694
+ if (r.maxAttempts !== void 0 && !isWithinWorkflowRetryAttempts(r.maxAttempts)) {
6695
+ const over = typeof r.maxAttempts === "number" && r.maxAttempts > WORKFLOW_RETRY_MAX_ATTEMPTS;
6696
+ throw new LuaWorkflowBuildError(over ? "cap-exceeded" : "invalid-envelope", `"${id}": ${workflowRetryMaxAttemptsMessage(r.maxAttempts)}`);
6697
+ }
6528
6698
  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(" | ")}`);
6529
6699
  if (r.maxBackoffSeconds !== void 0) {
6530
6700
  if (r.backoff !== "exponential") throw new LuaWorkflowBuildError("backoff-invalid", `"${id}": retry.maxBackoffSeconds is only meaningful with backoff:'exponential'`);
@@ -7299,7 +7469,93 @@ function isAccessDeniedError(error) {
7299
7469
  if (CliError.isCliError(error)) return error.statusCode === 403;
7300
7470
  return error instanceof Error && error.message.startsWith("Access denied (403)");
7301
7471
  }
7302
- var CLI_EXIT, CliError;
7472
+ function authHint(error) {
7473
+ if (error.suppressDefaultRemediation) return void 0;
7474
+ if (error.reason === "no_agent_access") {
7475
+ return [
7476
+ "Your API key is valid, but it does not have access to the agentId in lua.skill.yaml \u2014 the agent belongs",
7477
+ "to another account or organization, was deleted or transferred, or the yaml was copied from another project.",
7478
+ "Check the configured agent and switch if needed:",
7479
+ " lua agents (list agents you have access to)",
7480
+ " lua init (re-select the agent for this project)"
7481
+ ].join("\n");
7482
+ }
7483
+ return "Re-authenticate or check your API key: lua auth configure \xB7 https://admin.heylua.ai";
7484
+ }
7485
+ function numericStatus(error) {
7486
+ const candidate = error.statusCode ?? error.status;
7487
+ return typeof candidate === "number" && Number.isFinite(candidate) ? candidate : void 0;
7488
+ }
7489
+ function classifyCliError(error) {
7490
+ if (CliError.isCliError(error)) {
7491
+ return {
7492
+ code: error.code,
7493
+ exitCode: error.exitCode,
7494
+ message: error.message,
7495
+ hint: error.hint
7496
+ };
7497
+ }
7498
+ if (AuthenticationError.isAuthenticationError(error)) {
7499
+ return {
7500
+ code: "auth",
7501
+ exitCode: CLI_EXIT.AUTH,
7502
+ message: error.message,
7503
+ hint: authHint(error)
7504
+ };
7505
+ }
7506
+ const e = typeof error === "object" && error !== null ? error : {};
7507
+ const message = typeof e.message === "string" && e.message.length > 0 ? e.message : error instanceof Error ? error.name : String(error ?? "Unknown error");
7508
+ if (e.name === "WorkflowLocalUsageError" || typeof e.code === "string" && e.code.startsWith("commander.")) {
7509
+ return {
7510
+ code: "usage",
7511
+ exitCode: CLI_EXIT.USAGE,
7512
+ message
7513
+ };
7514
+ }
7515
+ const status = numericStatus(e);
7516
+ if (status !== void 0) {
7517
+ if (status === 401) return {
7518
+ code: "auth",
7519
+ exitCode: CLI_EXIT.AUTH,
7520
+ message
7521
+ };
7522
+ if (status === 403) return {
7523
+ code: "forbidden",
7524
+ exitCode: CLI_EXIT.FORBIDDEN,
7525
+ message
7526
+ };
7527
+ if (status === 404) return {
7528
+ code: "not_found",
7529
+ exitCode: CLI_EXIT.NOT_FOUND,
7530
+ message
7531
+ };
7532
+ if (status >= 400 && status < 500) return {
7533
+ code: `http_${status}`,
7534
+ exitCode: CLI_EXIT.FORBIDDEN,
7535
+ message
7536
+ };
7537
+ if (status >= 500 || status === 0) return {
7538
+ code: "unavailable",
7539
+ exitCode: CLI_EXIT.UNAVAILABLE,
7540
+ message
7541
+ };
7542
+ }
7543
+ const causeCode = e.cause?.code;
7544
+ if (typeof e.code === "string" && NETWORK_ERRNO.has(e.code) || typeof causeCode === "string" && NETWORK_ERRNO.has(causeCode) || e.name === "AbortError" || e.name === "TimeoutError" || NETWORK_MESSAGE.test(message)) {
7545
+ return {
7546
+ code: "unavailable",
7547
+ exitCode: CLI_EXIT.UNAVAILABLE,
7548
+ message,
7549
+ hint: UNAVAILABLE_HINT
7550
+ };
7551
+ }
7552
+ return {
7553
+ code: "error",
7554
+ exitCode: CLI_EXIT.ERROR,
7555
+ message
7556
+ };
7557
+ }
7558
+ var CLI_EXIT, CliError, NETWORK_ERRNO, NETWORK_MESSAGE, UNAVAILABLE_HINT;
7303
7559
  var init_cli_error = __esm({
7304
7560
  "src/errors/cli.error.ts"() {
7305
7561
  "use strict";
@@ -7354,11 +7610,48 @@ var init_cli_error = __esm({
7354
7610
  statusCode: 403
7355
7611
  });
7356
7612
  }
7613
+ /**
7614
+ * An API refusal the site already holds the status of (LUA-766) — classified by the same table the top-level
7615
+ * classifier applies to an untyped error: 401 auth · 403 forbidden · 404 not_found · other 4xx `http_<status>`
7616
+ * (10) · 5xx / 0 unavailable (11, with the network hint unless the site gives its own) · no status `error` (1).
7617
+ * A command that reads `response.error.statusCode` throws through here, so `lua logs` on a 503 exits 11 like
7618
+ * every other verb instead of printing the message itself and then throwing an exit-1 `Error`.
7619
+ */
7620
+ static fromStatus(statusCode, message, hint) {
7621
+ const reported = classifyCliError(Object.assign(new Error(message), {
7622
+ statusCode
7623
+ }));
7624
+ const classHint = reported.exitCode === CLI_EXIT.UNAVAILABLE ? UNAVAILABLE_HINT : reported.hint;
7625
+ return new _CliError(reported.code, message, {
7626
+ exitCode: reported.exitCode,
7627
+ hint: hint ?? classHint,
7628
+ statusCode
7629
+ });
7630
+ }
7357
7631
  static isCliError(error) {
7358
7632
  return error instanceof _CliError || typeof error === "object" && error !== null && error.isCliError === true;
7359
7633
  }
7360
7634
  };
7361
7635
  __name(isAccessDeniedError, "isAccessDeniedError");
7636
+ NETWORK_ERRNO = /* @__PURE__ */ new Set([
7637
+ "ECONNREFUSED",
7638
+ "ECONNRESET",
7639
+ "ENOTFOUND",
7640
+ "ETIMEDOUT",
7641
+ "EAI_AGAIN",
7642
+ "EPIPE",
7643
+ "EHOSTUNREACH",
7644
+ "ENETUNREACH",
7645
+ "UND_ERR_CONNECT_TIMEOUT",
7646
+ "UND_ERR_HEADERS_TIMEOUT",
7647
+ "UND_ERR_BODY_TIMEOUT",
7648
+ "UND_ERR_SOCKET"
7649
+ ]);
7650
+ NETWORK_MESSAGE = /fetch failed|socket hang up|network request failed|request timeout|ECONNREFUSED|ENOTFOUND/i;
7651
+ UNAVAILABLE_HINT = "The Lua API could not be reached \u2014 check your network and https://status.heylua.ai, then retry.";
7652
+ __name(authHint, "authHint");
7653
+ __name(numericStatus, "numericStatus");
7654
+ __name(classifyCliError, "classifyCliError");
7362
7655
  }
7363
7656
  });
7364
7657
 
@@ -13440,6 +13733,14 @@ var init_workflow_api_service = __esm({
13440
13733
  async getVersionEnvOverlay(workflowId, version) {
13441
13734
  return this.httpGet(`${this.base}/${workflowId}/versions/${encodeURIComponent(version)}/env-overlay`, await this.auth());
13442
13735
  }
13736
+ /**
13737
+ * WF-403 (13 §13.14; LUA-752) — `GET …/:workflowId/export?version=`: the active (or named) version as pushable
13738
+ * files (`{ form, version, files:[{ path, contents }], warnings }`). `lua workflows export` writes them to disk.
13739
+ */
13740
+ async exportWorkflowFiles(workflowId, version) {
13741
+ const qs = version ? `?version=${encodeURIComponent(version)}` : "";
13742
+ return this.httpGet(`${this.base}/${workflowId}/export${qs}`, await this.auth());
13743
+ }
13443
13744
  async getWorkflowVersions(workflowId) {
13444
13745
  return this.httpGet(`${this.base}/${workflowId}/versions`, await this.auth());
13445
13746
  }
@@ -13536,6 +13837,34 @@ var init_workflow_api_service = __esm({
13536
13837
  async retryStep(runId, stepId, data = {}) {
13537
13838
  return this.httpPost(`${this.runs}/${runId}/steps/${pathId(stepId)}/retry`, data, await this.auth());
13538
13839
  }
13840
+ /**
13841
+ * R37 (LUA-752) — a human decides a parked step: `skip` it, `complete` it with the output it would have produced,
13842
+ * or `fail` it (the step's onError policy applies). 400 `VALIDATION_FAILED{output-required}` / `RESOLVE_OUTPUT_INVALID`,
13843
+ * 403 `APPROVAL_REQUIRES_HUMAN` / `NOT_RUN_CREATOR`, 404 `RUN_NOT_FOUND` / `STEP_NOT_FOUND`, 409 `STEP_NOT_PARKED` /
13844
+ * `RUN_TERMINAL`, 413 `OUTPUT_TOO_LARGE`; the CAS loser is a 200 `{ resolved:false, reason, recorded }`.
13845
+ */
13846
+ async resolveStep(runId, stepId, data) {
13847
+ return this.httpPost(`${this.runs}/${runId}/steps/${pathId(stepId)}/resolve`, data, await this.auth());
13848
+ }
13849
+ /**
13850
+ * R45 (LUA-752) — raise a parked run's budget (`maxCredits` / `maxSteps` / `maxJobSeconds` / `maxDurationSeconds`;
13851
+ * increases only). 400 `VALIDATION_FAILED` / `CAP_EXCEEDED`, 403 `NOT_RUN_CREATOR`, 409 `BUDGET_NOT_RAISABLE`.
13852
+ */
13853
+ async raiseBudget(runId, data) {
13854
+ return this.httpPost(`${this.runs}/${runId}/budget`, data, await this.auth());
13855
+ }
13856
+ /**
13857
+ * R39 (LUA-752) — the current approval payload with its `payloadFingerprint` / `editRevision` (what
13858
+ * `approve --edit --fingerprint` echoes). `path` pages one array of a large payload.
13859
+ */
13860
+ async getApprovalPayload(runId, approvalId, query = {}) {
13861
+ const q = new URLSearchParams();
13862
+ if (query.path) q.append("path", query.path);
13863
+ if (query.cursor) q.append("cursor", query.cursor);
13864
+ if (query.limit !== void 0) q.append("limit", String(query.limit));
13865
+ const qs = q.toString();
13866
+ return this.httpGet(`${this.runs}/${runId}/approvals/${pathId(approvalId)}/payload${qs ? `?${qs}` : ""}`, await this.auth());
13867
+ }
13539
13868
  /** R13 — resolve an approval (human; `expectedFingerprint` guards against an edited payload — 409 `PAYLOAD_MISMATCH`). */
13540
13869
  async resolveApproval(runId, approvalId, data) {
13541
13870
  return this.httpPost(`${this.runs}/${runId}/approvals/${pathId(approvalId)}/resolve`, data, await this.auth());
@@ -13620,6 +13949,14 @@ var init_workflow_api_service = __esm({
13620
13949
  async getSchedule(jobId) {
13621
13950
  return this.httpGet(`${this.schedules}/${encodeURIComponent(jobId)}`, await this.auth());
13622
13951
  }
13952
+ /** R27 (LUA-752) — create or replace the plain schedule Job of a workflow (201; 400 `VALIDATION_FAILED` / `WORKFLOW_NOT_ON_AGENT`, 404 `WORKFLOW_NOT_FOUND`, 409 `SCHEDULE_CAP`). */
13953
+ async createSchedule(data) {
13954
+ return this.httpPost(this.schedules, data, await this.auth());
13955
+ }
13956
+ /** R56 (LUA-752) — pause / resume a schedule, persist `backfillOnEnable`, one-shot `backfillNow` (404 `SCHEDULE_NOT_FOUND`, 400 `VALIDATION_FAILED{issues}`). */
13957
+ async updateSchedule(jobId, data) {
13958
+ return this.httpPatch(`${this.schedules}/${encodeURIComponent(jobId)}`, data, await this.auth());
13959
+ }
13623
13960
  /** R28 — delete a schedule Job (404 `SCHEDULE_NOT_FOUND`). The CLI refuses a LIVE goal's job BEFORE this call (`goal_schedule`); an ended goal's lingering Job is retired here (LUA-760). */
13624
13961
  async deleteSchedule(jobId) {
13625
13962
  return this.httpDelete(`${this.schedules}/${encodeURIComponent(jobId)}`, await this.auth());