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.
@@ -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
  }
@@ -466,6 +544,11 @@ function isDeviceCredentialPrincipal(context) {
466
544
  function hasDeviceCredentialType(value3) {
467
545
  return DeviceCredentialClaimSchema.safeParse(value3).success;
468
546
  }
547
+ function sessionAuthTime(context) {
548
+ if (!context || context.credential.type !== "firstPartySession") return void 0;
549
+ const authTime = context.authTime;
550
+ return typeof authTime === "number" && Number.isInteger(authTime) && authTime >= 0 && authTime <= SESSION_AUTH_TIME_MAX_S ? authTime : void 0;
551
+ }
469
552
  function isTypedApiKeyPrincipal(context) {
470
553
  return context?.subject.subjectType === "apiKey" && context.credential.type === "apiKey" && !context.compatibility;
471
554
  }
@@ -638,6 +721,39 @@ function scheduledWorkflowRunId(jobId, scheduledTime) {
638
721
  const key = typeof scheduledTime === "number" ? String(scheduledTime) : scheduledTimeKey(scheduledTime);
639
722
  return `${WORKFLOW_SCHEDULED_RUN_ID_PREFIX}${jobId}_${key}`;
640
723
  }
724
+ function renderWorkflowScheduleKeyTemplate(template3, ctx) {
725
+ if (!template3) return void 0;
726
+ const read = /* @__PURE__ */ __name2((path3) => path3.split(".").reduce((o, k) => o && typeof o === "object" ? o[k] : void 0, ctx.input), "read");
727
+ let unresolved = false;
728
+ const out = template3.replace(/\$\{\s*([a-zA-Z0-9_.]+)\s*\}/g, (_m, expr) => {
729
+ let v = "";
730
+ if (expr === "scheduledTime") v = ctx.scheduledTime ?? "";
731
+ else if (expr.startsWith("input.")) v = read(expr.slice("input.".length));
732
+ const s = v === void 0 || v === null ? "" : String(v);
733
+ if (s === "") unresolved = true;
734
+ return s;
735
+ });
736
+ if (unresolved) return void 0;
737
+ const key = out.slice(0, WORKFLOW_SCHEDULE_KEY_MAX);
738
+ return key && /^[A-Za-z0-9:_\-.\/]+$/.test(key) ? key : void 0;
739
+ }
740
+ function scheduledWorkflowIdempotencyKey(jobId, rendered) {
741
+ const head = `${WORKFLOW_SCHEDULE_IDEMPOTENCY_KEY_PREFIX}${jobId}:`;
742
+ if (head.length + rendered.length <= WORKFLOW_SCHEDULE_KEY_MAX) return `${head}${rendered}`;
743
+ const digest = stableKeyDigest(rendered);
744
+ const room = WORKFLOW_SCHEDULE_KEY_MAX - head.length - digest.length - 1;
745
+ return `${head}${rendered.slice(0, Math.max(0, room))}~${digest}`;
746
+ }
747
+ function stableKeyDigest(s) {
748
+ let a = 2166136261;
749
+ let b = 84696351;
750
+ for (let i = 0; i < s.length; i++) {
751
+ const c = s.charCodeAt(i);
752
+ a = Math.imul(a ^ c, 16777619);
753
+ b = Math.imul(b ^ c, 16777619) ^ b >>> 13;
754
+ }
755
+ return (a >>> 0).toString(16).padStart(8, "0") + (b >>> 0).toString(16).padStart(8, "0");
756
+ }
641
757
  function workflowOperationId(runId, stepId, billingEpoch) {
642
758
  return `${WORKFLOW_OPERATION_ID_PREFIX}${runId}:${stepId}:${billingEpoch}`;
643
759
  }
@@ -941,7 +1057,59 @@ function extractSingleJsonValue(text) {
941
1057
  };
942
1058
  }
943
1059
  }
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;
1060
+ function agentFeatureCatalogDefault(featureName) {
1061
+ return DEFAULT_ON_AGENT_FEATURES.includes(featureName);
1062
+ }
1063
+ function hasExplicitFeatureActive(row) {
1064
+ return typeof row?.active === "boolean";
1065
+ }
1066
+ function effectiveFeatureActive(row, catalogDefault) {
1067
+ return hasExplicitFeatureActive(row) ? row.active : catalogDefault;
1068
+ }
1069
+ function resolveEffectiveFeature(row, catalogDefault) {
1070
+ return hasExplicitFeatureActive(row) ? {
1071
+ active: row.active,
1072
+ source: "agent",
1073
+ default: catalogDefault
1074
+ } : {
1075
+ active: catalogDefault,
1076
+ source: "default",
1077
+ default: catalogDefault
1078
+ };
1079
+ }
1080
+ function isFeatureRow(value3) {
1081
+ return typeof value3 === "object" && value3 !== null;
1082
+ }
1083
+ function effectiveAgentFeatureRows(base, override) {
1084
+ const merged = /* @__PURE__ */ new Map();
1085
+ for (const [name, row] of Object.entries(base ?? {})) {
1086
+ if (isFeatureRow(row)) merged.set(name, {
1087
+ row,
1088
+ origin: "baseAgent"
1089
+ });
1090
+ }
1091
+ for (const [name, row] of Object.entries(override ?? {})) {
1092
+ if (isFeatureRow(row)) merged.set(name, {
1093
+ row,
1094
+ origin: "subAgent"
1095
+ });
1096
+ }
1097
+ return {
1098
+ rows: Object.fromEntries([
1099
+ ...merged
1100
+ ].map(([name, e]) => [
1101
+ name,
1102
+ e.row
1103
+ ])),
1104
+ origins: Object.fromEntries([
1105
+ ...merged
1106
+ ].map(([name, e]) => [
1107
+ name,
1108
+ e.origin
1109
+ ]))
1110
+ };
1111
+ }
1112
+ 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, SESSION_AUTH_TIME_MAX_S, 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_SCHEDULE_KEY_MAX, WORKFLOW_SCHEDULE_IDEMPOTENCY_KEY_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, DEFAULT_ON_AGENT_FEATURES;
945
1113
  var init_dist = __esm({
946
1114
  "../shared-types/dist/index.mjs"() {
947
1115
  "use strict";
@@ -1258,6 +1426,16 @@ var init_dist = __esm({
1258
1426
  __name2(isDesktopFileCommandName, "isDesktopFileCommandName");
1259
1427
  __name(isDesktopFileSessionId, "isDesktopFileSessionId");
1260
1428
  __name2(isDesktopFileSessionId, "isDesktopFileSessionId");
1429
+ MODEL_ID_BYOK_PROVIDERS = [
1430
+ "azure",
1431
+ "bedrock"
1432
+ ];
1433
+ __name(isModelIdSentinel, "isModelIdSentinel");
1434
+ __name2(isModelIdSentinel, "isModelIdSentinel");
1435
+ __name(normalizeModelId, "normalizeModelId");
1436
+ __name2(normalizeModelId, "normalizeModelId");
1437
+ __name(modelUnresolvedMessage, "modelUnresolvedMessage");
1438
+ __name2(modelUnresolvedMessage, "modelUnresolvedMessage");
1261
1439
  REASONING_EFFORT_VALUES = [
1262
1440
  "off",
1263
1441
  "minimal",
@@ -1676,6 +1854,7 @@ This text is who you are for this person. As you learn them, their name, their w
1676
1854
  }
1677
1855
  });
1678
1856
  IdSchema = z2.string().min(1).max(256);
1857
+ SESSION_AUTH_TIME_MAX_S = 4102444800;
1679
1858
  PrincipalDescriptorSchema = z2.object({
1680
1859
  subjectType: SubjectTypeSchema,
1681
1860
  subjectId: IdSchema
@@ -1724,7 +1903,8 @@ This text is who you are for this person. As you learn them, their name, their w
1724
1903
  owner: PrincipalOwnerSchema.optional(),
1725
1904
  compatibility: z2.object({
1726
1905
  mode: z2.literal("legacy-owner-delegation")
1727
- }).strict().optional()
1906
+ }).strict().optional(),
1907
+ authTime: z2.number().int().nonnegative().max(SESSION_AUTH_TIME_MAX_S).optional()
1728
1908
  }).strict();
1729
1909
  DeviceCredentialPrincipalContextSchema = z2.object({
1730
1910
  version: z2.literal(1),
@@ -1780,6 +1960,8 @@ This text is who you are for this person. As you learn them, their name, their w
1780
1960
  }).passthrough();
1781
1961
  __name(hasDeviceCredentialType, "hasDeviceCredentialType");
1782
1962
  __name2(hasDeviceCredentialType, "hasDeviceCredentialType");
1963
+ __name(sessionAuthTime, "sessionAuthTime");
1964
+ __name2(sessionAuthTime, "sessionAuthTime");
1783
1965
  __name(isTypedApiKeyPrincipal, "isTypedApiKeyPrincipal");
1784
1966
  __name2(isTypedApiKeyPrincipal, "isTypedApiKeyPrincipal");
1785
1967
  __name(typedApiKeyPrincipalId, "typedApiKeyPrincipalId");
@@ -2011,6 +2193,14 @@ This text is who you are for this person. As you learn them, their name, their w
2011
2193
  __name2(isScheduledWorkflowRunId, "isScheduledWorkflowRunId");
2012
2194
  __name(scheduledWorkflowRunId, "scheduledWorkflowRunId");
2013
2195
  __name2(scheduledWorkflowRunId, "scheduledWorkflowRunId");
2196
+ WORKFLOW_SCHEDULE_KEY_MAX = 128;
2197
+ __name(renderWorkflowScheduleKeyTemplate, "renderWorkflowScheduleKeyTemplate");
2198
+ __name2(renderWorkflowScheduleKeyTemplate, "renderWorkflowScheduleKeyTemplate");
2199
+ WORKFLOW_SCHEDULE_IDEMPOTENCY_KEY_PREFIX = "sched:";
2200
+ __name(scheduledWorkflowIdempotencyKey, "scheduledWorkflowIdempotencyKey");
2201
+ __name2(scheduledWorkflowIdempotencyKey, "scheduledWorkflowIdempotencyKey");
2202
+ __name(stableKeyDigest, "stableKeyDigest");
2203
+ __name2(stableKeyDigest, "stableKeyDigest");
2014
2204
  WORKFLOW_OPERATION_ID_PREFIX = "wf:";
2015
2205
  __name(workflowOperationId, "workflowOperationId");
2016
2206
  __name2(workflowOperationId, "workflowOperationId");
@@ -2456,6 +2646,23 @@ listed here; never invent a target.`;
2456
2646
  JSON_FENCE_RE = /```(?:json)?[ \t]*\r?\n([\s\S]*?)\r?\n?```/g;
2457
2647
  __name(extractSingleJsonValue, "extractSingleJsonValue");
2458
2648
  __name2(extractSingleJsonValue, "extractSingleJsonValue");
2649
+ DEFAULT_ON_AGENT_FEATURES = [
2650
+ "workflows",
2651
+ "workflowCompose",
2652
+ "observationalMemory"
2653
+ ];
2654
+ __name(agentFeatureCatalogDefault, "agentFeatureCatalogDefault");
2655
+ __name2(agentFeatureCatalogDefault, "agentFeatureCatalogDefault");
2656
+ __name(hasExplicitFeatureActive, "hasExplicitFeatureActive");
2657
+ __name2(hasExplicitFeatureActive, "hasExplicitFeatureActive");
2658
+ __name(effectiveFeatureActive, "effectiveFeatureActive");
2659
+ __name2(effectiveFeatureActive, "effectiveFeatureActive");
2660
+ __name(resolveEffectiveFeature, "resolveEffectiveFeature");
2661
+ __name2(resolveEffectiveFeature, "resolveEffectiveFeature");
2662
+ __name(isFeatureRow, "isFeatureRow");
2663
+ __name2(isFeatureRow, "isFeatureRow");
2664
+ __name(effectiveAgentFeatureRows, "effectiveAgentFeatureRows");
2665
+ __name2(effectiveAgentFeatureRows, "effectiveAgentFeatureRows");
2459
2666
  }
2460
2667
  });
2461
2668
 
@@ -2666,6 +2873,129 @@ function resolveMapping(cfg, ctx) {
2666
2873
  value: result
2667
2874
  };
2668
2875
  }
2876
+ function describeApproverSpecRefusal(spec) {
2877
+ const raw = spec === void 0 ? "undefined" : JSON.stringify(spec) ?? String(spec);
2878
+ const written = raw.length > APPROVER_WRITTEN_MAX ? `${raw.slice(0, APPROVER_WRITTEN_MAX - 1)}\u2026` : raw;
2879
+ const users = typeof spec === "object" && spec !== null ? spec.users : void 0;
2880
+ const approver = typeof users === "string" && USER_ID_SHAPED_RE.test(users) ? {
2881
+ users: [
2882
+ users
2883
+ ]
2884
+ } : "creator";
2885
+ 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)}`);
2886
+ return {
2887
+ approver,
2888
+ written,
2889
+ message
2890
+ };
2891
+ }
2892
+ function bindingRootsOk(template22) {
2893
+ const refs = [
2894
+ ...template22.matchAll(/\$\{\s*([A-Za-z_$][\w$]*)/g)
2895
+ ].map((m) => m[1]);
2896
+ return refs.length > 0 && refs.every((r) => BINDING_ROOTS.includes(r));
2897
+ }
2898
+ function isTemplateBinding(v) {
2899
+ return typeof v === "object" && v !== null && typeof v.template === "string";
2900
+ }
2901
+ function approvalEditable(node) {
2902
+ if (node.editable === true) return true;
2903
+ if (node.editable === false) return false;
2904
+ return Array.isArray(node.editablePaths) && node.editablePaths.length > 0;
2905
+ }
2906
+ function validateApproverBlock(node, opts = {
2907
+ path: "approval"
2908
+ }) {
2909
+ const issues = [];
2910
+ const push = /* @__PURE__ */ __name3((code, path3, message, severity = "error") => issues.push({
2911
+ code,
2912
+ path: path3,
2913
+ severity,
2914
+ message
2915
+ }), "push");
2916
+ const checkSpec = /* @__PURE__ */ __name3((spec, path3) => {
2917
+ const r = ApproverSpecSchema.safeParse(spec);
2918
+ if (!r.success) {
2919
+ const users = spec?.users;
2920
+ if (Array.isArray(users) && users.length > APPROVER_SPEC_MAX_USERS) push("cap-exceeded", path3, `at most ${APPROVER_SPEC_MAX_USERS} users`);
2921
+ else {
2922
+ const refusal = describeApproverSpecRefusal(spec);
2923
+ issues.push({
2924
+ code: "approver-invalid",
2925
+ path: path3,
2926
+ severity: "error",
2927
+ message: refusal.message,
2928
+ repair: {
2929
+ approver: refusal.approver,
2930
+ written: refusal.written
2931
+ }
2932
+ });
2933
+ }
2934
+ return;
2935
+ }
2936
+ const s = r.data;
2937
+ if (typeof s === "object") {
2938
+ if ("governance" in s && !opts.governanceEnabled) push("approver-governance-unavailable", path3, "governance reviewer routing is not enabled for this deployment");
2939
+ 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");
2940
+ const binding = "users" in s ? s.users : "role" in s ? s.role : "group" in s ? s.group : void 0;
2941
+ if (isTemplateBinding(binding)) {
2942
+ if (!bindingRootsOk(binding.template)) push("approver-binding-invalid", `${path3}.template`, "binding root must be initData / stepResults / requestContext / state");
2943
+ if ("users" in s && opts.customerReachable) push("approver-binding-customer-reachable", `${path3}.users`, "a customer-reachable workflow may not bind its approver list");
2944
+ }
2945
+ }
2946
+ }, "checkSpec");
2947
+ if (node.approver !== void 0) checkSpec(node.approver, `${opts.path}.approver`);
2948
+ if (node.fourEyes !== void 0) {
2949
+ const r = FourEyesSchema.safeParse(node.fourEyes);
2950
+ if (!r.success) push("approver-invalid", `${opts.path}.fourEyes`, "fourEyes needs { edit, approve } approver specs");
2951
+ else {
2952
+ checkSpec(r.data.edit, `${opts.path}.fourEyes.edit`);
2953
+ checkSpec(r.data.approve, `${opts.path}.fourEyes.approve`);
2954
+ }
2955
+ if (!approvalEditable(node)) push("four-eyes-requires-editable", `${opts.path}.fourEyes`, "fourEyes requires editable:true");
2956
+ if (node.approver !== void 0) push("four-eyes-overrides-approver", `${opts.path}.approver`, "fourEyes replaces approver", "warning");
2957
+ if (node.itemsPath) push("four-eyes-items-unsupported", `${opts.path}.fourEyes`, "fourEyes cannot combine with itemsPath");
2958
+ }
2959
+ 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");
2960
+ if (Array.isArray(node.onTimeout)) {
2961
+ const chain = node.onTimeout;
2962
+ const hops = chain.filter((m) => typeof m === "object" && m !== null && "escalateTo" in m);
2963
+ if (hops.length > ESCALATION_MAX_HOPS) push("escalation-chain-too-long", `${opts.path}.onTimeout`, `at most ${ESCALATION_MAX_HOPS} hops`);
2964
+ const last = chain[chain.length - 1];
2965
+ if (typeof last === "object" && last !== null) push("escalation-chain-not-terminal", `${opts.path}.onTimeout`, "a chain must end in deny | cancel-run | fail");
2966
+ hops.forEach((h, i) => checkSpec(h.escalateTo, `${opts.path}.onTimeout[${i}].escalateTo`));
2967
+ } else if (typeof node.onTimeout === "object" && node.onTimeout !== null) {
2968
+ checkSpec(node.onTimeout.escalateTo, `${opts.path}.onTimeout.escalateTo`);
2969
+ }
2970
+ return issues;
2971
+ }
2972
+ function liftRenderedApprover(row, rendered) {
2973
+ const text = (rendered ?? "").trim();
2974
+ if (!text) return null;
2975
+ if (row === "users") {
2976
+ let members = null;
2977
+ if (text.startsWith("[")) {
2978
+ try {
2979
+ members = JSON.parse(text);
2980
+ } catch {
2981
+ return null;
2982
+ }
2983
+ } else members = text.split(",").map((s) => s.trim());
2984
+ if (!Array.isArray(members) || members.length === 0 || members.length > APPROVER_SPEC_MAX_USERS) return null;
2985
+ if (!members.every((m) => typeof m === "string" && m.length > 0 && m.length <= 128)) return null;
2986
+ return {
2987
+ users: [
2988
+ ...new Set(members)
2989
+ ].sort()
2990
+ };
2991
+ }
2992
+ if (text.length > 128 || text.startsWith("[") || text.startsWith("{")) return null;
2993
+ return row === "role" ? {
2994
+ role: text
2995
+ } : {
2996
+ group: text
2997
+ };
2998
+ }
2669
2999
  function workspaceTemplatePath(template22) {
2670
3000
  const key = template22.trim();
2671
3001
  const expr = WORKSPACE_TEMPLATE_EXPR_RE.exec(key);
@@ -2682,6 +3012,9 @@ function retryBackoffs() {
2682
3012
  function sleepUntilUnsupportedMessage(id) {
2683
3013
  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
3014
  }
3015
+ function armSubrunUnsupportedMessage(id, workflowId) {
3016
+ 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)`;
3017
+ }
2685
3018
  function fillPolicy(node, defaultTimeout) {
2686
3019
  if (node.tier === void 0 && node.workspace !== void 0 && node.workspace !== "inherit") node.tier = "job";
2687
3020
  if (node.timeoutSeconds === void 0) node.timeoutSeconds = node.tier === "job" ? WORKFLOW_JOB_DEFAULT_TIMEOUT_SECONDS : defaultTimeout;
@@ -2707,7 +3040,6 @@ function fillSingle(node) {
2707
3040
  fillPolicy(node, WORKFLOW_STEP_DEFAULT_TIMEOUT_SECONDS);
2708
3041
  return;
2709
3042
  case "workflow":
2710
- if (node.workflowId === WORKFLOW_ARM_SUBRUN_ID && Array.isArray(node.graph) && node.graph[1]) fillSingle(node.graph[1]);
2711
3043
  return;
2712
3044
  }
2713
3045
  }
@@ -2839,8 +3171,14 @@ function nodeStepRefs(entry) {
2839
3171
  case "agent": {
2840
3172
  const a = entry;
2841
3173
  const p = a.promptTemplate;
2842
- return typeof p === "string" ? templateStepRefs(p) : p && "template" in p ? templateStepRefs(p.template) : [];
3174
+ const prompt = typeof p === "string" ? templateStepRefs(p) : p && "template" in p ? templateStepRefs(p.template) : [];
3175
+ return [
3176
+ ...prompt,
3177
+ ...mapConfigStepRefs(a.input)
3178
+ ];
2843
3179
  }
3180
+ case "step":
3181
+ return mapConfigStepRefs(entry.input);
2844
3182
  case "tool":
2845
3183
  return mapConfigStepRefs(entry.input);
2846
3184
  case "workflow":
@@ -2957,7 +3295,7 @@ function validateLuaExtensions(g, caps = WORKFLOW_CAPS_DEFAULT, opts = {
2957
3295
  const id = singleId(node);
2958
3296
  const unknown = unknownWorkflowRetryMembers(r);
2959
3297
  if (unknown.length) err("invalid-envelope", workflowRetryUnknownMembersMessage(unknown), `${path3}.retry`, id);
2960
- if (r.maxAttempts !== void 0 && !isWithinWorkflowRetryAttempts(r.maxAttempts)) {
3298
+ if (!isWithinWorkflowRetryAttempts(r.maxAttempts)) {
2961
3299
  const over = typeof r.maxAttempts === "number" && r.maxAttempts > WORKFLOW_RETRY_MAX_ATTEMPTS;
2962
3300
  err(over ? "cap-exceeded" : "invalid-envelope", workflowRetryMaxAttemptsMessage(r.maxAttempts), `${path3}.retry.maxAttempts`, id);
2963
3301
  }
@@ -3057,6 +3395,21 @@ function validateLuaExtensions(g, caps = WORKFLOW_CAPS_DEFAULT, opts = {
3057
3395
  err("job-tier-provider-unsupported", `model provider '${provider}' is outside LUA_WF_JOB_PROVIDERS [${opts.policy.jobProviders.join(", ")}]`, `${path3}.model`, id);
3058
3396
  }
3059
3397
  }, "checkTier");
3398
+ const checkModel = /* @__PURE__ */ __name3((node, path3) => {
3399
+ if (node.type !== "agent" || typeof node.model !== "string") return;
3400
+ const registry = opts.approvedModels;
3401
+ if (registry === void 0) return;
3402
+ const id = singleId(node);
3403
+ if (registry === "unavailable") {
3404
+ const pin = node.model.trim();
3405
+ if (pin && !normalizeModelId(pin, []).ok) {
3406
+ 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);
3407
+ }
3408
+ return;
3409
+ }
3410
+ const resolved = normalizeModelId(node.model, registry);
3411
+ if (!resolved.ok) err("model-unresolved", modelUnresolvedMessage(resolved), `${path3}.model`, id);
3412
+ }, "checkModel");
3060
3413
  const checkWorkspace = /* @__PURE__ */ __name3((node, path3) => {
3061
3414
  const id = singleId(node);
3062
3415
  const ws = workspaceOf(node);
@@ -3109,38 +3462,29 @@ function validateLuaExtensions(g, caps = WORKFLOW_CAPS_DEFAULT, opts = {
3109
3462
  }
3110
3463
  }, "checkMapMembers");
3111
3464
  const checkInputShape = /* @__PURE__ */ __name3((node, path3) => {
3112
- if (node.type !== "tool" && node.type !== "workflow") return;
3113
3465
  const input = node.input;
3114
3466
  if (input === void 0) return;
3467
+ const id = singleId(node);
3115
3468
  if (input !== null && typeof input === "object" && !Array.isArray(input)) {
3116
- checkMapMembers(input, `${path3}.input`, node.id);
3469
+ checkMapMembers(input, `${path3}.input`, id);
3117
3470
  return;
3118
3471
  }
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);
3472
+ 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
3473
  }, "checkInputShape");
3474
+ const checkBodyInput = /* @__PURE__ */ __name3((body, path3, container) => {
3475
+ if (body.type === "workflow" || body.input === void 0) return;
3476
+ 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));
3477
+ }, "checkBodyInput");
3121
3478
  const checkSingle = /* @__PURE__ */ __name3((node, path3, depth) => {
3122
3479
  recordOutputSchema(node);
3123
- if (node.type === "workflow" && node.workflowId === WORKFLOW_ARM_SUBRUN_ID) {
3480
+ if (node.type === "workflow" && (typeof node.workflowId !== "string" || node.workflowId.length === 0)) {
3124
3481
  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]));
3482
+ err("invalid-envelope", `\`workflowId\` must be a non-empty string naming the workflow to start (got ${JSON.stringify(node.workflowId)})`, `${path3}.workflowId`, node.id);
3483
+ return;
3484
+ }
3485
+ if (node.type === "workflow" && (node.workflowId.startsWith("$") || Array.isArray(node.graph))) {
3486
+ checkId(node.id, path3);
3487
+ err("node-type-unsupported-by-engine", armSubrunUnsupportedMessage(node.id, node.workflowId), path3, node.id);
3144
3488
  return;
3145
3489
  }
3146
3490
  checkId(singleId(node), path3);
@@ -3148,6 +3492,7 @@ function validateLuaExtensions(g, caps = WORKFLOW_CAPS_DEFAULT, opts = {
3148
3492
  checkInputShape(node, path3);
3149
3493
  checkTimeout(node, path3);
3150
3494
  checkTier(node, path3);
3495
+ checkModel(node, path3);
3151
3496
  checkRetry(node, path3);
3152
3497
  checkWorkspace(node, path3);
3153
3498
  if (!opts.static) {
@@ -3170,7 +3515,7 @@ function validateLuaExtensions(g, caps = WORKFLOW_CAPS_DEFAULT, opts = {
3170
3515
  if (node.type === "workflow" && node.kind === "subrun" && depth > caps.maxNestingDepth) {
3171
3516
  err("cap-exceeded", `nesting depth ${depth} exceeds ${caps.maxNestingDepth}`, path3, node.id);
3172
3517
  }
3173
- if (node.type === "workflow" && node.workflowId !== WORKFLOW_ARM_SUBRUN_ID && typeof g.definition?.id === "string" && node.workflowId === g.definition.id) {
3518
+ if (node.type === "workflow" && typeof g.definition?.id === "string" && node.workflowId === g.definition.id) {
3174
3519
  err("subrun-cycle", `"${node.id}" starts "${node.workflowId}", which is this workflow itself`, path3, node.id);
3175
3520
  }
3176
3521
  for (const ref of nodeStepRefs(node)) {
@@ -3191,11 +3536,14 @@ function validateLuaExtensions(g, caps = WORKFLOW_CAPS_DEFAULT, opts = {
3191
3536
  if (a.approver === "creator" && a.excludeInitiator === true) {
3192
3537
  err("approver-excludes-only-candidate", "approver:'creator' with excludeInitiator:true always excludes the only candidate", path3, a.id);
3193
3538
  }
3194
- if (a.fourEyes !== void 0 && a.editable !== true) {
3539
+ const editable = approvalEditable(a);
3540
+ if (a.fourEyes !== void 0 && !editable) {
3195
3541
  err("four-eyes-requires-editable", "`fourEyes` requires editable:true", `${path3}.fourEyes`, a.id);
3196
3542
  }
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);
3543
+ if (a.editable === false && Array.isArray(a.editablePaths) && a.editablePaths.length > 0) {
3544
+ err("editable-path-invalid", "`editablePaths` beside editable:false is contradictory \u2014 drop the paths or set editable:true", `${path3}.editablePaths`, a.id);
3545
+ } else if ((a.editablePaths !== void 0 || a.editedPayloadSchema !== void 0) && !editable) {
3546
+ err("editable-path-invalid", "`editablePaths` / `editedPayloadSchema` require editable:true (a non-empty editablePaths implies it)", `${path3}.editablePaths`, a.id);
3199
3547
  }
3200
3548
  for (const p of a.editablePaths ?? []) {
3201
3549
  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 +3724,7 @@ function validateLuaExtensions(g, caps = WORKFLOW_CAPS_DEFAULT, opts = {
3376
3724
  } else checkHitlArm(f.step, `${path3}.step`, "foreach");
3377
3725
  declared.push(f.step.id);
3378
3726
  } else {
3727
+ checkBodyInput(f.step, `${path3}.step`, "foreach");
3379
3728
  checkSingle(f.step, `${path3}.step`, o.chunk ? 2 : 1);
3380
3729
  declared.push(singleId(f.step));
3381
3730
  }
@@ -3396,6 +3745,7 @@ function validateLuaExtensions(g, caps = WORKFLOW_CAPS_DEFAULT, opts = {
3396
3745
  checkHitlArm(l.step, `${path3}.step`, "loop");
3397
3746
  declared.push(l.step.id);
3398
3747
  } else {
3748
+ checkBodyInput(l.step, `${path3}.step`, "loop");
3399
3749
  checkSingle(l.step, `${path3}.step`, 1);
3400
3750
  declared.push(singleId(l.step));
3401
3751
  }
@@ -3869,17 +4219,10 @@ function isContinuedFailureValue(v) {
3869
4219
  const err = o.error;
3870
4220
  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
4221
  }
3872
- function lowerContainerArm(mapping, step22) {
3873
- const stepId = nodeIdOf(step22);
4222
+ function inlineContainerArm(mapping, step22) {
3874
4223
  return {
3875
- type: "workflow",
3876
- id: `${stepId}_arm`,
3877
- workflowId: WORKFLOW_ARM_SUBRUN_ID,
3878
- kind: "subrun",
3879
- graph: [
3880
- mapping,
3881
- step22
3882
- ]
4224
+ ...step22,
4225
+ input: parseMapConfig(mapping.mapConfig, mapping.id)
3883
4226
  };
3884
4227
  }
3885
4228
  function entryIds(entry) {
@@ -3949,6 +4292,27 @@ function resolvePlacements(calls) {
3949
4292
  break;
3950
4293
  }
3951
4294
  });
4295
+ const armMapPlacementIssue = /* @__PURE__ */ __name3((node, ref, i, container) => {
4296
+ if (!ref.armMap || node.type === "mapping" || isHitlNode2(node)) return void 0;
4297
+ const id = nodeIdOf(node);
4298
+ if ((container === "foreach" || container === "loop") && node.type !== "workflow") {
4299
+ return {
4300
+ code: "mapping-placement",
4301
+ 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`,
4302
+ callIndex: i,
4303
+ stepId: id
4304
+ };
4305
+ }
4306
+ if (node.input !== void 0) {
4307
+ return {
4308
+ code: "mapping-placement",
4309
+ 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)`,
4310
+ callIndex: i,
4311
+ stepId: id
4312
+ };
4313
+ }
4314
+ return void 0;
4315
+ }, "armMapPlacementIssue");
3952
4316
  const hitlPlacementIssue = /* @__PURE__ */ __name3((node, ref, i, container) => {
3953
4317
  if (!isHitlNode2(node)) return void 0;
3954
4318
  const id = node.id;
@@ -3975,7 +4339,7 @@ function resolvePlacements(calls) {
3975
4339
  if (ref.node.type === "mapping" && !allowMapping) {
3976
4340
  issues.push({
3977
4341
  code: "mapping-placement",
3978
- message: `mapping "${ref.node.id}" cannot be a container arm \u2014 chain it as [map, step]`,
4342
+ 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
4343
  callIndex: i,
3980
4344
  stepId: ref.node.id
3981
4345
  });
@@ -3996,7 +4360,7 @@ function resolvePlacements(calls) {
3996
4360
  if (d.node.type === "mapping" && !allowMapping) {
3997
4361
  issues.push({
3998
4362
  code: "mapping-placement",
3999
- message: `map "${ref.ref}" cannot be a parallel/foreach/loop arm \u2014 chain it as [map, step]`,
4363
+ 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
4364
  callIndex: i,
4001
4365
  stepId: ref.ref
4002
4366
  });
@@ -4007,6 +4371,11 @@ function resolvePlacements(calls) {
4007
4371
  issues.push(hitl);
4008
4372
  return void 0;
4009
4373
  }
4374
+ const mapped = armMapPlacementIssue(d.node, ref, i, container);
4375
+ if (mapped) {
4376
+ issues.push(mapped);
4377
+ return void 0;
4378
+ }
4010
4379
  const prior = placedBy.get(ref.ref);
4011
4380
  if (prior !== void 0 && prior !== i) {
4012
4381
  issues.push({
@@ -4027,6 +4396,10 @@ function resolvePlacements(calls) {
4027
4396
  }
4028
4397
  const hitl = hitlPlacementIssue(ref.node, ref, i, container);
4029
4398
  if (hitl) issues.push(hitl);
4399
+ else {
4400
+ const mapped = armMapPlacementIssue(ref.node, ref, i, container);
4401
+ if (mapped) issues.push(mapped);
4402
+ }
4030
4403
  }, "claim");
4031
4404
  calls.forEach((call, i) => {
4032
4405
  switch (call.kind) {
@@ -4054,7 +4427,7 @@ function resolvePlacements(calls) {
4054
4427
  const lookup = /* @__PURE__ */ __name3((ref) => {
4055
4428
  const n2 = "node" in ref ? ref.node : declared.get(ref.ref)?.node;
4056
4429
  if (!n2 || !ref.armMap || n2.type === "mapping" || isHitlNode2(n2)) return n2;
4057
- return lowerContainerArm(ref.armMap, n2);
4430
+ return inlineContainerArm(ref.armMap, n2);
4058
4431
  }, "lookup");
4059
4432
  calls.forEach((call, i) => {
4060
4433
  switch (call.kind) {
@@ -4439,9 +4812,31 @@ function isTerminalRunStatus(status) {
4439
4812
  function pruneUndefined(o) {
4440
4813
  return Object.fromEntries(Object.entries(o).filter(([, v]) => v !== void 0));
4441
4814
  }
4815
+ function runOrigin(run) {
4816
+ if (run.goalId) return "goal";
4817
+ if (run.jobId || run.trigger === "schedule") return "schedule";
4818
+ if (run.dynamic === true) return run.tags?.includes(WORKFLOW_INLINE_RUN_TAG) ? "inline" : "compose";
4819
+ return "definition";
4820
+ }
4821
+ function runErrorIssues(issues) {
4822
+ if (!Array.isArray(issues)) return void 0;
4823
+ const out = [];
4824
+ for (const raw of issues.slice(0, RUN_ERROR_ISSUES_MAX)) {
4825
+ if (!raw || typeof raw !== "object") continue;
4826
+ const o = raw;
4827
+ if (typeof o.code !== "string" || !o.code) continue;
4828
+ out.push(pruneUndefined({
4829
+ code: o.code,
4830
+ path: typeof o.path === "string" ? o.path : void 0,
4831
+ message: typeof o.message === "string" ? o.message : void 0
4832
+ }));
4833
+ }
4834
+ return out.length ? out : void 0;
4835
+ }
4442
4836
  function runNextAction(run) {
4443
4837
  if (isTerminalRunStatus(run.status)) return "none";
4444
4838
  if (run.status === "suspended" && run.gate?.kind === "budget") return "raise_budget";
4839
+ if (run.status === "suspended" && run.gate?.kind === "billing") return "top_up";
4445
4840
  if (!run.cancel?.requestedAt) return "none";
4446
4841
  const forceAt = run.cancel.forceAfter ?? run.cancel.requestedAt + FORCE_CANCEL_STALE_MS;
4447
4842
  return Date.now() >= forceAt ? "force" : "cancel_again";
@@ -4469,6 +4864,12 @@ function runCountsFromStepStatuses(statuses) {
4469
4864
  for (const s of statuses) tally[s] = (tally[s] ?? 0) + 1;
4470
4865
  return runCountsFromStatusTally(tally);
4471
4866
  }
4867
+ function isBillingHeldStep(row) {
4868
+ return row.status === "ready" && row.billingHold === true;
4869
+ }
4870
+ function stepEffectiveStatus(row) {
4871
+ return isBillingHeldStep(row) ? "suspended" : row.status;
4872
+ }
4472
4873
  function runCounts(counts) {
4473
4874
  const c = counts ?? {};
4474
4875
  const rawInFlight = c.dispatched !== void 0 || c.claimed !== void 0 || c.running !== void 0 || c.cancellation_requested !== void 0;
@@ -4608,6 +5009,7 @@ function toWorkflowRunSummary(run) {
4608
5009
  repairOf: run.repairOf,
4609
5010
  repairRunIds: run.repairRunIds,
4610
5011
  trigger: run.trigger ?? "api",
5012
+ origin: runOrigin(run),
4611
5013
  createdBy: {
4612
5014
  subjectType: principal?.subjectType ?? "system",
4613
5015
  subjectId: principal?.subjectId ?? run.userId ?? ""
@@ -4625,11 +5027,13 @@ function toWorkflowRunSummary(run) {
4625
5027
  usage: runUsage(run),
4626
5028
  // LUA-697: a row persisted before the write seams (#2406 / #2465 / the script tier) leaves scrubbed here too —
4627
5029
  // idempotent on a scrubbed message, bounded input; an empty message falls back to the code.
4628
- error: run.error ? {
5030
+ error: run.error ? pruneUndefined({
4629
5031
  code: run.error.code ?? "error",
4630
5032
  message: scrubStepErrorMessage(run.error.message) ?? run.error.code ?? "error",
4631
- stepId: run.error.stepId
4632
- } : void 0,
5033
+ stepId: run.error.stepId,
5034
+ // LUA-784 (item 3): the unattended pre-start failure's refusal rows (`input_schema_invalid` and kin).
5035
+ issues: runErrorIssues(run.error.issues)
5036
+ }) : void 0,
4633
5037
  kind: "run",
4634
5038
  aclHash: run.aclHash,
4635
5039
  migration: run.migration,
@@ -5129,147 +5533,29 @@ function applyJsonPatch(doc, ops) {
5129
5533
  ok: false,
5130
5534
  code: "PATCH_INVALID",
5131
5535
  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()
5536
+ path: op.path,
5537
+ message: "path not allowed"
5538
+ };
5539
+ if (op.op === "add") obj[key] = structuredClone(op.value);
5540
+ else if (!(key in obj)) return {
5541
+ ok: false,
5542
+ code: "PATH_NOT_FOUND",
5543
+ index: i,
5544
+ path: op.path,
5545
+ message: "path not found"
5264
5546
  };
5547
+ else if (op.op === "replace") obj[key] = structuredClone(op.value);
5548
+ else delete obj[key];
5265
5549
  }
5266
- if (text.length > 128 || text.startsWith("[") || text.startsWith("{")) return null;
5267
- return row === "role" ? {
5268
- role: text
5269
- } : {
5270
- group: text
5550
+ return {
5551
+ ok: true,
5552
+ value: value22
5271
5553
  };
5272
5554
  }
5555
+ function rebaseItemPointer(pointer, itemsPath, index) {
5556
+ const base = `/${itemsPath.split(".").map(escapePointer).join("/")}/${index}`;
5557
+ return pointer === "/" || pointer === "" ? base : `${base}${pointer}`;
5558
+ }
5273
5559
  function collectEnvTemplateKeys(value22) {
5274
5560
  const keys = /* @__PURE__ */ new Set();
5275
5561
  const walk22 = /* @__PURE__ */ __name3((v) => {
@@ -5518,7 +5804,6 @@ function* singleStepsOf(entry) {
5518
5804
  return;
5519
5805
  case "workflow":
5520
5806
  yield entry;
5521
- if (Array.isArray(entry.graph)) yield* singleStepsOf(entry.graph[1]);
5522
5807
  return;
5523
5808
  case "parallel":
5524
5809
  case "conditional":
@@ -5560,7 +5845,7 @@ function needsInheritedWorkspace(graph) {
5560
5845
  }
5561
5846
  return false;
5562
5847
  }
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;
5848
+ 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
5849
  var init_dist2 = __esm({
5565
5850
  "../workflow-graph/dist/index.mjs"() {
5566
5851
  "use strict";
@@ -5663,7 +5948,88 @@ var init_dist2 = __esm({
5663
5948
  }), "fromKnowledge");
5664
5949
  SideEffectsSchema = z4.enum(WORKFLOW_SIDE_EFFECTS);
5665
5950
  JobResourcesSchema = z4.enum(WORKFLOW_JOB_RESOURCES);
5666
- WORKFLOW_ARM_SUBRUN_ID = "$arm";
5951
+ APPROVER_SPEC_MAX_USERS = 20;
5952
+ ESCALATION_MAX_HOPS = 3;
5953
+ TemplateBindingSchema = z22.object({
5954
+ template: z22.string().min(1).max(2048)
5955
+ }).strict();
5956
+ ApproverSpecSchema = z22.union([
5957
+ z22.literal("creator"),
5958
+ z22.literal("org-admins"),
5959
+ z22.object({
5960
+ users: z22.union([
5961
+ z22.array(z22.string().min(1).max(128)).min(1).max(APPROVER_SPEC_MAX_USERS),
5962
+ TemplateBindingSchema
5963
+ ])
5964
+ }).strict(),
5965
+ z22.object({
5966
+ role: z22.union([
5967
+ z22.string().min(1).max(128),
5968
+ TemplateBindingSchema
5969
+ ])
5970
+ }).strict(),
5971
+ z22.object({
5972
+ group: z22.union([
5973
+ z22.string().min(1).max(128),
5974
+ TemplateBindingSchema
5975
+ ])
5976
+ }).strict(),
5977
+ z22.object({
5978
+ governance: z22.object({
5979
+ policyId: z22.string().min(1).max(128)
5980
+ }).strict()
5981
+ }).strict()
5982
+ ]);
5983
+ FourEyesSchema = z22.object({
5984
+ edit: ApproverSpecSchema,
5985
+ approve: ApproverSpecSchema
5986
+ }).strict();
5987
+ EscalationHopSchema = z22.object({
5988
+ escalateTo: ApproverSpecSchema,
5989
+ timeoutHours: z22.number().finite().min(1).max(720)
5990
+ }).strict();
5991
+ TerminalOutcomeSchema = z22.enum([
5992
+ "deny",
5993
+ "cancel-run",
5994
+ "fail",
5995
+ "continue"
5996
+ ]);
5997
+ ApprovalOnTimeoutSchema = z22.union([
5998
+ TerminalOutcomeSchema,
5999
+ EscalationHopSchema,
6000
+ z22.array(z22.union([
6001
+ TerminalOutcomeSchema,
6002
+ EscalationHopSchema
6003
+ ])).min(1).max(ESCALATION_MAX_HOPS + 1)
6004
+ ]);
6005
+ APPROVER_SPEC_SHAPES = [
6006
+ "'creator'",
6007
+ "'org-admins'",
6008
+ "{users:[userId, \u2026]}",
6009
+ "{role:roleName}",
6010
+ "{group:groupName}",
6011
+ "{governance:{policyId}}"
6012
+ ];
6013
+ APPROVER_WRITTEN_MAX = 120;
6014
+ USER_ID_SHAPED_RE = /^[^\s@]{1,128}$/;
6015
+ __name(describeApproverSpecRefusal, "describeApproverSpecRefusal");
6016
+ __name3(describeApproverSpecRefusal, "describeApproverSpecRefusal");
6017
+ BINDING_ROOTS = [
6018
+ "initData",
6019
+ "stepResults",
6020
+ "requestContext",
6021
+ "state"
6022
+ ];
6023
+ __name(bindingRootsOk, "bindingRootsOk");
6024
+ __name3(bindingRootsOk, "bindingRootsOk");
6025
+ __name(isTemplateBinding, "isTemplateBinding");
6026
+ __name3(isTemplateBinding, "isTemplateBinding");
6027
+ __name(approvalEditable, "approvalEditable");
6028
+ __name3(approvalEditable, "approvalEditable");
6029
+ __name(validateApproverBlock, "validateApproverBlock");
6030
+ __name3(validateApproverBlock, "validateApproverBlock");
6031
+ __name(liftRenderedApprover, "liftRenderedApprover");
6032
+ __name3(liftRenderedApprover, "liftRenderedApprover");
5667
6033
  WORKSPACE_TEMPLATE_EXPR_RE = /^\$\{\s*(?:initData|input)\.([^}]+?)\s*\}$/;
5668
6034
  __name(workspaceTemplatePath, "workspaceTemplatePath");
5669
6035
  __name3(workspaceTemplatePath, "workspaceTemplatePath");
@@ -5675,6 +6041,8 @@ var init_dist2 = __esm({
5675
6041
  });
5676
6042
  __name(sleepUntilUnsupportedMessage, "sleepUntilUnsupportedMessage");
5677
6043
  __name3(sleepUntilUnsupportedMessage, "sleepUntilUnsupportedMessage");
6044
+ __name(armSubrunUnsupportedMessage, "armSubrunUnsupportedMessage");
6045
+ __name3(armSubrunUnsupportedMessage, "armSubrunUnsupportedMessage");
5678
6046
  WORKFLOW_CAPS_DEFAULT = Object.freeze({
5679
6047
  maxParallelArms: 16,
5680
6048
  maxForeachConcurrency: 16,
@@ -5956,8 +6324,8 @@ var init_dist2 = __esm({
5956
6324
  __name(isContinuedFailureValue, "isContinuedFailureValue");
5957
6325
  __name3(isContinuedFailureValue, "isContinuedFailureValue");
5958
6326
  isHitlNode2 = /* @__PURE__ */ __name3((n2) => isWorkflowHitlEntryType(n2.type), "isHitlNode");
5959
- __name(lowerContainerArm, "lowerContainerArm");
5960
- __name3(lowerContainerArm, "lowerContainerArm");
6327
+ __name(inlineContainerArm, "inlineContainerArm");
6328
+ __name3(inlineContainerArm, "inlineContainerArm");
5961
6329
  nodeIdOf = /* @__PURE__ */ __name3((n2) => n2.type === "step" ? n2.step.id : n2.id, "nodeIdOf");
5962
6330
  __name(entryIds, "entryIds");
5963
6331
  __name3(entryIds, "entryIds");
@@ -6017,6 +6385,12 @@ var init_dist2 = __esm({
6017
6385
  __name3(isTerminalRunStatus, "isTerminalRunStatus");
6018
6386
  __name(pruneUndefined, "pruneUndefined");
6019
6387
  __name3(pruneUndefined, "pruneUndefined");
6388
+ WORKFLOW_INLINE_RUN_TAG = "inline";
6389
+ __name(runOrigin, "runOrigin");
6390
+ __name3(runOrigin, "runOrigin");
6391
+ RUN_ERROR_ISSUES_MAX = 20;
6392
+ __name(runErrorIssues, "runErrorIssues");
6393
+ __name3(runErrorIssues, "runErrorIssues");
6020
6394
  __name(runNextAction, "runNextAction");
6021
6395
  __name3(runNextAction, "runNextAction");
6022
6396
  IN_FLIGHT = new Set(WORKFLOW_STEP_IN_FLIGHT);
@@ -6026,6 +6400,10 @@ var init_dist2 = __esm({
6026
6400
  __name3(runCountsFromStatusTally, "runCountsFromStatusTally");
6027
6401
  __name(runCountsFromStepStatuses, "runCountsFromStepStatuses");
6028
6402
  __name3(runCountsFromStepStatuses, "runCountsFromStepStatuses");
6403
+ __name(isBillingHeldStep, "isBillingHeldStep");
6404
+ __name3(isBillingHeldStep, "isBillingHeldStep");
6405
+ __name(stepEffectiveStatus, "stepEffectiveStatus");
6406
+ __name3(stepEffectiveStatus, "stepEffectiveStatus");
6029
6407
  n = /* @__PURE__ */ __name3((v) => typeof v === "number" && Number.isFinite(v) ? v : 0, "n");
6030
6408
  __name(runCounts, "runCounts");
6031
6409
  __name3(runCounts, "runCounts");
@@ -6177,86 +6555,6 @@ var init_dist2 = __esm({
6177
6555
  __name3(applyJsonPatch, "applyJsonPatch");
6178
6556
  __name(rebaseItemPointer, "rebaseItemPointer");
6179
6557
  __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
6558
  WORKFLOW_ENV_OVERLAY_MAX_KEYS = 64;
6261
6559
  WORKFLOW_ENV_OVERLAY_MAX_VALUE_BYTES = 4096;
6262
6560
  WORKFLOW_ENV_TEMPLATE_SECRET_KEY_RE = /(SECRET|TOKEN|KEY|PASSWORD)$/;
@@ -6359,14 +6657,13 @@ function stepNodeOf(s) {
6359
6657
  }
6360
6658
  function materializeEntry(entry, steps) {
6361
6659
  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
- };
6660
+ if (n2.type === "step" && steps[n2.step.id]) {
6661
+ const node = stepNodeOf(steps[n2.step.id]);
6662
+ return n2.input !== void 0 ? {
6663
+ ...node,
6664
+ input: n2.input
6665
+ } : node;
6666
+ }
6370
6667
  return n2;
6371
6668
  }, "single");
6372
6669
  switch (entry.type) {
@@ -6524,7 +6821,10 @@ var init_workflow = __esm({
6524
6821
  }, "assertPredicate");
6525
6822
  assertRetry = /* @__PURE__ */ __name((r, id) => {
6526
6823
  if (!r) return;
6527
- if (typeof r.maxAttempts === "number" && r.maxAttempts > WORKFLOW_RETRY_MAX_ATTEMPTS) throw new LuaWorkflowBuildError("cap-exceeded", `"${id}": ${workflowRetryMaxAttemptsMessage(r.maxAttempts)}`);
6824
+ if (!isWithinWorkflowRetryAttempts(r.maxAttempts)) {
6825
+ const over = typeof r.maxAttempts === "number" && r.maxAttempts > WORKFLOW_RETRY_MAX_ATTEMPTS;
6826
+ throw new LuaWorkflowBuildError(over ? "cap-exceeded" : "invalid-envelope", `"${id}": ${workflowRetryMaxAttemptsMessage(r.maxAttempts)}`);
6827
+ }
6528
6828
  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
6829
  if (r.maxBackoffSeconds !== void 0) {
6530
6830
  if (r.backoff !== "exponential") throw new LuaWorkflowBuildError("backoff-invalid", `"${id}": retry.maxBackoffSeconds is only meaningful with backoff:'exponential'`);
@@ -7299,7 +7599,102 @@ function isAccessDeniedError(error) {
7299
7599
  if (CliError.isCliError(error)) return error.statusCode === 403;
7300
7600
  return error instanceof Error && error.message.startsWith("Access denied (403)");
7301
7601
  }
7302
- var CLI_EXIT, CliError;
7602
+ function authHint(error) {
7603
+ if (error.suppressDefaultRemediation) return void 0;
7604
+ if (error.reason === "no_agent_access") {
7605
+ return [
7606
+ "Your API key is valid, but it does not have access to the agentId in lua.skill.yaml \u2014 the agent belongs",
7607
+ "to another account or organization, was deleted or transferred, or the yaml was copied from another project.",
7608
+ "Check the configured agent and switch if needed:",
7609
+ " lua agents (list agents you have access to)",
7610
+ " lua init (re-select the agent for this project)"
7611
+ ].join("\n");
7612
+ }
7613
+ return "Re-authenticate or check your API key: lua auth configure \xB7 https://admin.heylua.ai";
7614
+ }
7615
+ function numericStatus(error) {
7616
+ const candidate = error.statusCode ?? error.status;
7617
+ return typeof candidate === "number" && Number.isFinite(candidate) ? candidate : void 0;
7618
+ }
7619
+ function classifyCliError(error) {
7620
+ if (CliError.isCliError(error)) {
7621
+ return {
7622
+ code: error.code,
7623
+ exitCode: error.exitCode,
7624
+ message: error.message,
7625
+ hint: error.hint,
7626
+ statusCode: error.statusCode,
7627
+ serverCode: error.serverCode,
7628
+ issues: error.issues
7629
+ };
7630
+ }
7631
+ if (AuthenticationError.isAuthenticationError(error)) {
7632
+ return {
7633
+ code: "auth",
7634
+ exitCode: CLI_EXIT.AUTH,
7635
+ message: error.message,
7636
+ hint: authHint(error)
7637
+ };
7638
+ }
7639
+ const e = typeof error === "object" && error !== null ? error : {};
7640
+ const message = typeof e.message === "string" && e.message.length > 0 ? e.message : error instanceof Error ? error.name : String(error ?? "Unknown error");
7641
+ if (e.name === "WorkflowLocalUsageError" || typeof e.code === "string" && e.code.startsWith("commander.")) {
7642
+ return {
7643
+ code: "usage",
7644
+ exitCode: CLI_EXIT.USAGE,
7645
+ message
7646
+ };
7647
+ }
7648
+ const status = numericStatus(e);
7649
+ if (status !== void 0) {
7650
+ const statusCode = status;
7651
+ if (status === 401) return {
7652
+ code: "auth",
7653
+ exitCode: CLI_EXIT.AUTH,
7654
+ message,
7655
+ statusCode
7656
+ };
7657
+ if (status === 403) return {
7658
+ code: "forbidden",
7659
+ exitCode: CLI_EXIT.FORBIDDEN,
7660
+ message,
7661
+ statusCode
7662
+ };
7663
+ if (status === 404) return {
7664
+ code: "not_found",
7665
+ exitCode: CLI_EXIT.NOT_FOUND,
7666
+ message,
7667
+ statusCode
7668
+ };
7669
+ if (status >= 400 && status < 500) return {
7670
+ code: `http_${status}`,
7671
+ exitCode: CLI_EXIT.FORBIDDEN,
7672
+ message,
7673
+ statusCode
7674
+ };
7675
+ if (status >= 500 || status === 0) return {
7676
+ code: "unavailable",
7677
+ exitCode: CLI_EXIT.UNAVAILABLE,
7678
+ message,
7679
+ statusCode
7680
+ };
7681
+ }
7682
+ const causeCode = e.cause?.code;
7683
+ 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)) {
7684
+ return {
7685
+ code: "unavailable",
7686
+ exitCode: CLI_EXIT.UNAVAILABLE,
7687
+ message,
7688
+ hint: UNAVAILABLE_HINT
7689
+ };
7690
+ }
7691
+ return {
7692
+ code: "error",
7693
+ exitCode: CLI_EXIT.ERROR,
7694
+ message
7695
+ };
7696
+ }
7697
+ var CLI_EXIT, CliError, NETWORK_ERRNO, NETWORK_MESSAGE, UNAVAILABLE_HINT;
7303
7698
  var init_cli_error = __esm({
7304
7699
  "src/errors/cli.error.ts"() {
7305
7700
  "use strict";
@@ -7322,6 +7717,8 @@ var init_cli_error = __esm({
7322
7717
  exitCode;
7323
7718
  hint;
7324
7719
  statusCode;
7720
+ serverCode;
7721
+ issues;
7325
7722
  constructor(code, message, options = {}) {
7326
7723
  super(message);
7327
7724
  this.name = "CliError";
@@ -7329,6 +7726,8 @@ var init_cli_error = __esm({
7329
7726
  this.exitCode = options.exitCode ?? CLI_EXIT.ERROR;
7330
7727
  this.hint = options.hint;
7331
7728
  this.statusCode = options.statusCode;
7729
+ this.serverCode = options.serverCode;
7730
+ this.issues = options.issues?.length ? options.issues : void 0;
7332
7731
  if (Error.captureStackTrace) Error.captureStackTrace(this, _CliError);
7333
7732
  }
7334
7733
  /** Bad arguments, an unknown action, no project — exit 2. */
@@ -7354,11 +7753,50 @@ var init_cli_error = __esm({
7354
7753
  statusCode: 403
7355
7754
  });
7356
7755
  }
7756
+ /**
7757
+ * An API refusal the site already holds the status of (LUA-766) — classified by the same table the top-level
7758
+ * classifier applies to an untyped error: 401 auth · 403 forbidden · 404 not_found · other 4xx `http_<status>`
7759
+ * (10) · 5xx / 0 unavailable (11, with the network hint unless the site gives its own) · no status `error` (1).
7760
+ * A command that reads `response.error.statusCode` throws through here, so `lua logs` on a 503 exits 11 like
7761
+ * every other verb instead of printing the message itself and then throwing an exit-1 `Error`.
7762
+ */
7763
+ static fromStatus(statusCode, message, hint, detail = {}) {
7764
+ const reported = classifyCliError(Object.assign(new Error(message), {
7765
+ statusCode
7766
+ }));
7767
+ const classHint = reported.exitCode === CLI_EXIT.UNAVAILABLE ? UNAVAILABLE_HINT : reported.hint;
7768
+ return new _CliError(reported.code, message, {
7769
+ exitCode: reported.exitCode,
7770
+ hint: hint ?? classHint,
7771
+ statusCode,
7772
+ serverCode: detail.serverCode,
7773
+ issues: detail.issues
7774
+ });
7775
+ }
7357
7776
  static isCliError(error) {
7358
7777
  return error instanceof _CliError || typeof error === "object" && error !== null && error.isCliError === true;
7359
7778
  }
7360
7779
  };
7361
7780
  __name(isAccessDeniedError, "isAccessDeniedError");
7781
+ NETWORK_ERRNO = /* @__PURE__ */ new Set([
7782
+ "ECONNREFUSED",
7783
+ "ECONNRESET",
7784
+ "ENOTFOUND",
7785
+ "ETIMEDOUT",
7786
+ "EAI_AGAIN",
7787
+ "EPIPE",
7788
+ "EHOSTUNREACH",
7789
+ "ENETUNREACH",
7790
+ "UND_ERR_CONNECT_TIMEOUT",
7791
+ "UND_ERR_HEADERS_TIMEOUT",
7792
+ "UND_ERR_BODY_TIMEOUT",
7793
+ "UND_ERR_SOCKET"
7794
+ ]);
7795
+ NETWORK_MESSAGE = /fetch failed|socket hang up|network request failed|request timeout|ECONNREFUSED|ENOTFOUND/i;
7796
+ UNAVAILABLE_HINT = "The Lua API could not be reached \u2014 check your network and https://status.heylua.ai, then retry.";
7797
+ __name(authHint, "authHint");
7798
+ __name(numericStatus, "numericStatus");
7799
+ __name(classifyCliError, "classifyCliError");
7362
7800
  }
7363
7801
  });
7364
7802
 
@@ -7833,6 +8271,52 @@ var init_request_credential = __esm({
7833
8271
 
7834
8272
  // src/api/http.client.ts
7835
8273
  import { randomUUID as randomUUID2 } from "crypto";
8274
+ async function classifyErrorResponse(response) {
8275
+ let errorData;
8276
+ try {
8277
+ errorData = await response.json();
8278
+ } catch (jsonError) {
8279
+ errorData = {};
8280
+ }
8281
+ if (response.status === 401) {
8282
+ const serverMessage = typeof errorData.message === "string" ? errorData.message : void 0;
8283
+ if (serverMessage && /not an admin/i.test(serverMessage)) {
8284
+ throw new AuthenticationError(`Access denied for this agent: ${serverMessage}`, "no_agent_access", serverMessage);
8285
+ }
8286
+ const isExplicitCredential = !!serverMessage && /(invalid|expired|missing|no)\s+(api[\s_-]?key|token|credential)/i.test(serverMessage);
8287
+ const isBareAuthRejection = !serverMessage || /^unauthorized$/i.test(serverMessage);
8288
+ if (isExplicitCredential || isBareAuthRejection) {
8289
+ throw new AuthenticationError("Authentication failed. Your Lua credential may be invalid or expired.", "invalid_credentials", serverMessage);
8290
+ }
8291
+ throw new AuthenticationError(`Authentication failed: ${serverMessage}`, "unknown", serverMessage);
8292
+ }
8293
+ if (response.status === 403) {
8294
+ const detail = errorData.message || "You do not have permission to access this resource.";
8295
+ const serverCode = serverCodeOf(errorData.code, errorData.error);
8296
+ throw new CliError("forbidden", `Access denied (403): ${detail}${serverCode ? ` (${serverCode})` : ""}`, {
8297
+ exitCode: CLI_EXIT.FORBIDDEN,
8298
+ statusCode: 403,
8299
+ serverCode,
8300
+ issues: Array.isArray(errorData.issues) ? errorData.issues : void 0,
8301
+ hint: "Check that your Lua login has access to this agent or organization."
8302
+ });
8303
+ }
8304
+ return {
8305
+ success: false,
8306
+ error: {
8307
+ message: errorData.message || `HTTP ${response.status}: ${response.statusText}`,
8308
+ statusCode: response.status,
8309
+ error: errorData.error,
8310
+ retryAfterSeconds: parseRetryAfter(response.headers.get("retry-after")),
8311
+ ...errorData
8312
+ }
8313
+ };
8314
+ }
8315
+ function serverCodeOf(code, error) {
8316
+ if (typeof code === "string" && code.length > 0) return code;
8317
+ if (typeof error === "string" && /^[A-Z0-9][A-Z0-9_]*$/.test(error)) return error;
8318
+ return void 0;
8319
+ }
7836
8320
  async function* parseSseStream(body, signal) {
7837
8321
  const reader = body.getReader();
7838
8322
  const decoder = new TextDecoder();
@@ -8013,42 +8497,7 @@ var init_http_client = __esm({
8013
8497
  * @private
8014
8498
  */
8015
8499
  async classifyErrorResponse(response) {
8016
- let errorData;
8017
- try {
8018
- errorData = await response.json();
8019
- } catch (jsonError) {
8020
- errorData = {};
8021
- }
8022
- if (response.status === 401) {
8023
- const serverMessage = typeof errorData.message === "string" ? errorData.message : void 0;
8024
- if (serverMessage && /not an admin/i.test(serverMessage)) {
8025
- throw new AuthenticationError(`Access denied for this agent: ${serverMessage}`, "no_agent_access", serverMessage);
8026
- }
8027
- const isExplicitCredential = !!serverMessage && /(invalid|expired|missing|no)\s+(api[\s_-]?key|token|credential)/i.test(serverMessage);
8028
- const isBareAuthRejection = !serverMessage || /^unauthorized$/i.test(serverMessage);
8029
- if (isExplicitCredential || isBareAuthRejection) {
8030
- throw new AuthenticationError("Authentication failed. Your Lua credential may be invalid or expired.", "invalid_credentials", serverMessage);
8031
- }
8032
- throw new AuthenticationError(`Authentication failed: ${serverMessage}`, "unknown", serverMessage);
8033
- }
8034
- if (response.status === 403) {
8035
- const detail = errorData.message || "You do not have permission to access this resource.";
8036
- throw new CliError("forbidden", `Access denied (403): ${detail}`, {
8037
- exitCode: CLI_EXIT.FORBIDDEN,
8038
- statusCode: 403,
8039
- hint: "Check that your Lua login has access to this agent or organization."
8040
- });
8041
- }
8042
- return {
8043
- success: false,
8044
- error: {
8045
- message: errorData.message || `HTTP ${response.status}: ${response.statusText}`,
8046
- statusCode: response.status,
8047
- error: errorData.error,
8048
- retryAfterSeconds: parseRetryAfter(response.headers.get("retry-after")),
8049
- ...errorData
8050
- }
8051
- };
8500
+ return classifyErrorResponse(response);
8052
8501
  }
8053
8502
  /**
8054
8503
  * Checks if an HTTP status code is retryable
@@ -8256,6 +8705,8 @@ var init_http_client = __esm({
8256
8705
  };
8257
8706
  }
8258
8707
  };
8708
+ __name(classifyErrorResponse, "classifyErrorResponse");
8709
+ __name(serverCodeOf, "serverCodeOf");
8259
8710
  __name(parseSseStream, "parseSseStream");
8260
8711
  __name(parseRetryAfter, "parseRetryAfter");
8261
8712
  __name(isCoreDrainApiError, "isCoreDrainApiError");
@@ -12314,6 +12765,7 @@ var init_job_api_service = __esm({
12314
12765
  "src/api/job.api.service.ts"() {
12315
12766
  "use strict";
12316
12767
  init_http_client();
12768
+ init_cli_error();
12317
12769
  init_job_instance();
12318
12770
  JobApi = class extends HttpClient {
12319
12771
  static {
@@ -12370,7 +12822,7 @@ var init_job_api_service = __esm({
12370
12822
  if (response.success && response.data) {
12371
12823
  return new JobInstance(this, response.data);
12372
12824
  }
12373
- throw new Error(response.error?.message || "Failed to get job");
12825
+ throw CliError.fromStatus(response.error?.statusCode, response.error?.message || "Failed to get job");
12374
12826
  }
12375
12827
  /**
12376
12828
  * Creates a new job for the agent.
@@ -13440,6 +13892,14 @@ var init_workflow_api_service = __esm({
13440
13892
  async getVersionEnvOverlay(workflowId, version) {
13441
13893
  return this.httpGet(`${this.base}/${workflowId}/versions/${encodeURIComponent(version)}/env-overlay`, await this.auth());
13442
13894
  }
13895
+ /**
13896
+ * WF-403 (13 §13.14; LUA-752) — `GET …/:workflowId/export?version=`: the active (or named) version as pushable
13897
+ * files (`{ form, version, files:[{ path, contents }], warnings }`). `lua workflows export` writes them to disk.
13898
+ */
13899
+ async exportWorkflowFiles(workflowId, version) {
13900
+ const qs = version ? `?version=${encodeURIComponent(version)}` : "";
13901
+ return this.httpGet(`${this.base}/${workflowId}/export${qs}`, await this.auth());
13902
+ }
13443
13903
  async getWorkflowVersions(workflowId) {
13444
13904
  return this.httpGet(`${this.base}/${workflowId}/versions`, await this.auth());
13445
13905
  }
@@ -13536,6 +13996,34 @@ var init_workflow_api_service = __esm({
13536
13996
  async retryStep(runId, stepId, data = {}) {
13537
13997
  return this.httpPost(`${this.runs}/${runId}/steps/${pathId(stepId)}/retry`, data, await this.auth());
13538
13998
  }
13999
+ /**
14000
+ * R37 (LUA-752) — a human decides a parked step: `skip` it, `complete` it with the output it would have produced,
14001
+ * or `fail` it (the step's onError policy applies). 400 `VALIDATION_FAILED{output-required}` / `RESOLVE_OUTPUT_INVALID`,
14002
+ * 403 `APPROVAL_REQUIRES_HUMAN` / `NOT_RUN_CREATOR`, 404 `RUN_NOT_FOUND` / `STEP_NOT_FOUND`, 409 `STEP_NOT_PARKED` /
14003
+ * `RUN_TERMINAL`, 413 `OUTPUT_TOO_LARGE`; the CAS loser is a 200 `{ resolved:false, reason, recorded }`.
14004
+ */
14005
+ async resolveStep(runId, stepId, data) {
14006
+ return this.httpPost(`${this.runs}/${runId}/steps/${pathId(stepId)}/resolve`, data, await this.auth());
14007
+ }
14008
+ /**
14009
+ * R45 (LUA-752) — raise a parked run's budget (`maxCredits` / `maxSteps` / `maxJobSeconds` / `maxDurationSeconds`;
14010
+ * increases only). 400 `VALIDATION_FAILED` / `CAP_EXCEEDED`, 403 `NOT_RUN_CREATOR`, 409 `BUDGET_NOT_RAISABLE`.
14011
+ */
14012
+ async raiseBudget(runId, data) {
14013
+ return this.httpPost(`${this.runs}/${runId}/budget`, data, await this.auth());
14014
+ }
14015
+ /**
14016
+ * R39 (LUA-752) — the current approval payload with its `payloadFingerprint` / `editRevision` (what
14017
+ * `approve --edit --fingerprint` echoes). `path` pages one array of a large payload.
14018
+ */
14019
+ async getApprovalPayload(runId, approvalId, query = {}) {
14020
+ const q = new URLSearchParams();
14021
+ if (query.path) q.append("path", query.path);
14022
+ if (query.cursor) q.append("cursor", query.cursor);
14023
+ if (query.limit !== void 0) q.append("limit", String(query.limit));
14024
+ const qs = q.toString();
14025
+ return this.httpGet(`${this.runs}/${runId}/approvals/${pathId(approvalId)}/payload${qs ? `?${qs}` : ""}`, await this.auth());
14026
+ }
13539
14027
  /** R13 — resolve an approval (human; `expectedFingerprint` guards against an edited payload — 409 `PAYLOAD_MISMATCH`). */
13540
14028
  async resolveApproval(runId, approvalId, data) {
13541
14029
  return this.httpPost(`${this.runs}/${runId}/approvals/${pathId(approvalId)}/resolve`, data, await this.auth());
@@ -13620,6 +14108,14 @@ var init_workflow_api_service = __esm({
13620
14108
  async getSchedule(jobId) {
13621
14109
  return this.httpGet(`${this.schedules}/${encodeURIComponent(jobId)}`, await this.auth());
13622
14110
  }
14111
+ /** 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`). */
14112
+ async createSchedule(data) {
14113
+ return this.httpPost(this.schedules, data, await this.auth());
14114
+ }
14115
+ /** R56 (LUA-752) — pause / resume a schedule, persist `backfillOnEnable`, one-shot `backfillNow` (404 `SCHEDULE_NOT_FOUND`, 400 `VALIDATION_FAILED{issues}`). */
14116
+ async updateSchedule(jobId, data) {
14117
+ return this.httpPatch(`${this.schedules}/${encodeURIComponent(jobId)}`, data, await this.auth());
14118
+ }
13623
14119
  /** 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
14120
  async deleteSchedule(jobId) {
13625
14121
  return this.httpDelete(`${this.schedules}/${encodeURIComponent(jobId)}`, await this.auth());