lua-cli 3.32.4 → 3.32.6

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.
@@ -431,6 +431,18 @@ function modelUnresolvedMessage(r) {
431
431
  }
432
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
433
  }
434
+ function providerModelId(code) {
435
+ const requested = typeof code === "string" ? code.trim() : "";
436
+ if (!requested || isModelIdSentinel(requested)) return requested;
437
+ const slash = requested.indexOf("/");
438
+ if (slash <= 0) return requested;
439
+ const provider = requested.slice(0, slash).toLowerCase();
440
+ if (MODEL_ID_BYOK_PROVIDERS.includes(provider)) return requested;
441
+ return requested.slice(slash + 1);
442
+ }
443
+ function providerModelFamily(code) {
444
+ return providerModelId(code).toLowerCase().replace(MODEL_SNAPSHOT_SUFFIX, "");
445
+ }
434
446
  function isImplicitModelSelectionSource(source) {
435
447
  return source !== void 0 && IMPLICIT_MODEL_SELECTION_SOURCES.includes(source);
436
448
  }
@@ -544,6 +556,11 @@ function isDeviceCredentialPrincipal(context) {
544
556
  function hasDeviceCredentialType(value3) {
545
557
  return DeviceCredentialClaimSchema.safeParse(value3).success;
546
558
  }
559
+ function sessionAuthTime(context) {
560
+ if (!context || context.credential.type !== "firstPartySession") return void 0;
561
+ const authTime = context.authTime;
562
+ return typeof authTime === "number" && Number.isInteger(authTime) && authTime >= 0 && authTime <= SESSION_AUTH_TIME_MAX_S ? authTime : void 0;
563
+ }
547
564
  function isTypedApiKeyPrincipal(context) {
548
565
  return context?.subject.subjectType === "apiKey" && context.credential.type === "apiKey" && !context.compatibility;
549
566
  }
@@ -716,6 +733,39 @@ function scheduledWorkflowRunId(jobId, scheduledTime) {
716
733
  const key = typeof scheduledTime === "number" ? String(scheduledTime) : scheduledTimeKey(scheduledTime);
717
734
  return `${WORKFLOW_SCHEDULED_RUN_ID_PREFIX}${jobId}_${key}`;
718
735
  }
736
+ function renderWorkflowScheduleKeyTemplate(template3, ctx) {
737
+ if (!template3) return void 0;
738
+ const read = /* @__PURE__ */ __name2((path3) => path3.split(".").reduce((o, k) => o && typeof o === "object" ? o[k] : void 0, ctx.input), "read");
739
+ let unresolved = false;
740
+ const out = template3.replace(/\$\{\s*([a-zA-Z0-9_.]+)\s*\}/g, (_m, expr) => {
741
+ let v = "";
742
+ if (expr === "scheduledTime") v = ctx.scheduledTime ?? "";
743
+ else if (expr.startsWith("input.")) v = read(expr.slice("input.".length));
744
+ const s = v === void 0 || v === null ? "" : String(v);
745
+ if (s === "") unresolved = true;
746
+ return s;
747
+ });
748
+ if (unresolved) return void 0;
749
+ const key = out.slice(0, WORKFLOW_SCHEDULE_KEY_MAX);
750
+ return key && /^[A-Za-z0-9:_\-.\/]+$/.test(key) ? key : void 0;
751
+ }
752
+ function scheduledWorkflowIdempotencyKey(jobId, rendered) {
753
+ const head = `${WORKFLOW_SCHEDULE_IDEMPOTENCY_KEY_PREFIX}${jobId}:`;
754
+ if (head.length + rendered.length <= WORKFLOW_SCHEDULE_KEY_MAX) return `${head}${rendered}`;
755
+ const digest = stableKeyDigest(rendered);
756
+ const room = WORKFLOW_SCHEDULE_KEY_MAX - head.length - digest.length - 1;
757
+ return `${head}${rendered.slice(0, Math.max(0, room))}~${digest}`;
758
+ }
759
+ function stableKeyDigest(s) {
760
+ let a = 2166136261;
761
+ let b = 84696351;
762
+ for (let i = 0; i < s.length; i++) {
763
+ const c = s.charCodeAt(i);
764
+ a = Math.imul(a ^ c, 16777619);
765
+ b = Math.imul(b ^ c, 16777619) ^ b >>> 13;
766
+ }
767
+ return (a >>> 0).toString(16).padStart(8, "0") + (b >>> 0).toString(16).padStart(8, "0");
768
+ }
719
769
  function workflowOperationId(runId, stepId, billingEpoch) {
720
770
  return `${WORKFLOW_OPERATION_ID_PREFIX}${runId}:${stepId}:${billingEpoch}`;
721
771
  }
@@ -1019,7 +1069,59 @@ function extractSingleJsonValue(text) {
1019
1069
  };
1020
1070
  }
1021
1071
  }
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;
1072
+ function agentFeatureCatalogDefault(featureName) {
1073
+ return DEFAULT_ON_AGENT_FEATURES.includes(featureName);
1074
+ }
1075
+ function hasExplicitFeatureActive(row) {
1076
+ return typeof row?.active === "boolean";
1077
+ }
1078
+ function effectiveFeatureActive(row, catalogDefault) {
1079
+ return hasExplicitFeatureActive(row) ? row.active : catalogDefault;
1080
+ }
1081
+ function resolveEffectiveFeature(row, catalogDefault) {
1082
+ return hasExplicitFeatureActive(row) ? {
1083
+ active: row.active,
1084
+ source: "agent",
1085
+ default: catalogDefault
1086
+ } : {
1087
+ active: catalogDefault,
1088
+ source: "default",
1089
+ default: catalogDefault
1090
+ };
1091
+ }
1092
+ function isFeatureRow(value3) {
1093
+ return typeof value3 === "object" && value3 !== null;
1094
+ }
1095
+ function effectiveAgentFeatureRows(base, override) {
1096
+ const merged = /* @__PURE__ */ new Map();
1097
+ for (const [name, row] of Object.entries(base ?? {})) {
1098
+ if (isFeatureRow(row)) merged.set(name, {
1099
+ row,
1100
+ origin: "baseAgent"
1101
+ });
1102
+ }
1103
+ for (const [name, row] of Object.entries(override ?? {})) {
1104
+ if (isFeatureRow(row)) merged.set(name, {
1105
+ row,
1106
+ origin: "subAgent"
1107
+ });
1108
+ }
1109
+ return {
1110
+ rows: Object.fromEntries([
1111
+ ...merged
1112
+ ].map(([name, e]) => [
1113
+ name,
1114
+ e.row
1115
+ ])),
1116
+ origins: Object.fromEntries([
1117
+ ...merged
1118
+ ].map(([name, e]) => [
1119
+ name,
1120
+ e.origin
1121
+ ]))
1122
+ };
1123
+ }
1124
+ 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, MODEL_SNAPSHOT_SUFFIX, 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;
1023
1125
  var init_dist = __esm({
1024
1126
  "../shared-types/dist/index.mjs"() {
1025
1127
  "use strict";
@@ -1346,6 +1448,11 @@ var init_dist = __esm({
1346
1448
  __name2(normalizeModelId, "normalizeModelId");
1347
1449
  __name(modelUnresolvedMessage, "modelUnresolvedMessage");
1348
1450
  __name2(modelUnresolvedMessage, "modelUnresolvedMessage");
1451
+ __name(providerModelId, "providerModelId");
1452
+ __name2(providerModelId, "providerModelId");
1453
+ MODEL_SNAPSHOT_SUFFIX = /(?:[-@](?:19|20)\d{2}(?:0[1-9]|1[0-2])(?:0[1-9]|[12]\d|3[01])|-(?:19|20)\d{2}-(?:0[1-9]|1[0-2])-(?:0[1-9]|[12]\d|3[01]))$/;
1454
+ __name(providerModelFamily, "providerModelFamily");
1455
+ __name2(providerModelFamily, "providerModelFamily");
1349
1456
  REASONING_EFFORT_VALUES = [
1350
1457
  "off",
1351
1458
  "minimal",
@@ -1764,6 +1871,7 @@ This text is who you are for this person. As you learn them, their name, their w
1764
1871
  }
1765
1872
  });
1766
1873
  IdSchema = z2.string().min(1).max(256);
1874
+ SESSION_AUTH_TIME_MAX_S = 4102444800;
1767
1875
  PrincipalDescriptorSchema = z2.object({
1768
1876
  subjectType: SubjectTypeSchema,
1769
1877
  subjectId: IdSchema
@@ -1812,7 +1920,8 @@ This text is who you are for this person. As you learn them, their name, their w
1812
1920
  owner: PrincipalOwnerSchema.optional(),
1813
1921
  compatibility: z2.object({
1814
1922
  mode: z2.literal("legacy-owner-delegation")
1815
- }).strict().optional()
1923
+ }).strict().optional(),
1924
+ authTime: z2.number().int().nonnegative().max(SESSION_AUTH_TIME_MAX_S).optional()
1816
1925
  }).strict();
1817
1926
  DeviceCredentialPrincipalContextSchema = z2.object({
1818
1927
  version: z2.literal(1),
@@ -1868,6 +1977,8 @@ This text is who you are for this person. As you learn them, their name, their w
1868
1977
  }).passthrough();
1869
1978
  __name(hasDeviceCredentialType, "hasDeviceCredentialType");
1870
1979
  __name2(hasDeviceCredentialType, "hasDeviceCredentialType");
1980
+ __name(sessionAuthTime, "sessionAuthTime");
1981
+ __name2(sessionAuthTime, "sessionAuthTime");
1871
1982
  __name(isTypedApiKeyPrincipal, "isTypedApiKeyPrincipal");
1872
1983
  __name2(isTypedApiKeyPrincipal, "isTypedApiKeyPrincipal");
1873
1984
  __name(typedApiKeyPrincipalId, "typedApiKeyPrincipalId");
@@ -2099,6 +2210,14 @@ This text is who you are for this person. As you learn them, their name, their w
2099
2210
  __name2(isScheduledWorkflowRunId, "isScheduledWorkflowRunId");
2100
2211
  __name(scheduledWorkflowRunId, "scheduledWorkflowRunId");
2101
2212
  __name2(scheduledWorkflowRunId, "scheduledWorkflowRunId");
2213
+ WORKFLOW_SCHEDULE_KEY_MAX = 128;
2214
+ __name(renderWorkflowScheduleKeyTemplate, "renderWorkflowScheduleKeyTemplate");
2215
+ __name2(renderWorkflowScheduleKeyTemplate, "renderWorkflowScheduleKeyTemplate");
2216
+ WORKFLOW_SCHEDULE_IDEMPOTENCY_KEY_PREFIX = "sched:";
2217
+ __name(scheduledWorkflowIdempotencyKey, "scheduledWorkflowIdempotencyKey");
2218
+ __name2(scheduledWorkflowIdempotencyKey, "scheduledWorkflowIdempotencyKey");
2219
+ __name(stableKeyDigest, "stableKeyDigest");
2220
+ __name2(stableKeyDigest, "stableKeyDigest");
2102
2221
  WORKFLOW_OPERATION_ID_PREFIX = "wf:";
2103
2222
  __name(workflowOperationId, "workflowOperationId");
2104
2223
  __name2(workflowOperationId, "workflowOperationId");
@@ -2544,6 +2663,23 @@ listed here; never invent a target.`;
2544
2663
  JSON_FENCE_RE = /```(?:json)?[ \t]*\r?\n([\s\S]*?)\r?\n?```/g;
2545
2664
  __name(extractSingleJsonValue, "extractSingleJsonValue");
2546
2665
  __name2(extractSingleJsonValue, "extractSingleJsonValue");
2666
+ DEFAULT_ON_AGENT_FEATURES = [
2667
+ "workflows",
2668
+ "workflowCompose",
2669
+ "observationalMemory"
2670
+ ];
2671
+ __name(agentFeatureCatalogDefault, "agentFeatureCatalogDefault");
2672
+ __name2(agentFeatureCatalogDefault, "agentFeatureCatalogDefault");
2673
+ __name(hasExplicitFeatureActive, "hasExplicitFeatureActive");
2674
+ __name2(hasExplicitFeatureActive, "hasExplicitFeatureActive");
2675
+ __name(effectiveFeatureActive, "effectiveFeatureActive");
2676
+ __name2(effectiveFeatureActive, "effectiveFeatureActive");
2677
+ __name(resolveEffectiveFeature, "resolveEffectiveFeature");
2678
+ __name2(resolveEffectiveFeature, "resolveEffectiveFeature");
2679
+ __name(isFeatureRow, "isFeatureRow");
2680
+ __name2(isFeatureRow, "isFeatureRow");
2681
+ __name(effectiveAgentFeatureRows, "effectiveAgentFeatureRows");
2682
+ __name2(effectiveAgentFeatureRows, "effectiveAgentFeatureRows");
2547
2683
  }
2548
2684
  });
2549
2685
 
@@ -2932,7 +3068,7 @@ function fillHitl(node) {
2932
3068
  if (a.onTimeout === void 0) a.onTimeout = "deny";
2933
3069
  if (a.onDeny === void 0) a.onDeny = "continue";
2934
3070
  if (a.excludeInitiator === void 0) a.excludeInitiator = false;
2935
- if (a.editable === void 0) a.editable = false;
3071
+ if (a.editable === void 0) a.editable = approvalEditable(a);
2936
3072
  return;
2937
3073
  }
2938
3074
  const w = node;
@@ -3176,7 +3312,7 @@ function validateLuaExtensions(g, caps = WORKFLOW_CAPS_DEFAULT, opts = {
3176
3312
  const id = singleId(node);
3177
3313
  const unknown = unknownWorkflowRetryMembers(r);
3178
3314
  if (unknown.length) err("invalid-envelope", workflowRetryUnknownMembersMessage(unknown), `${path3}.retry`, id);
3179
- if (r.maxAttempts !== void 0 && !isWithinWorkflowRetryAttempts(r.maxAttempts)) {
3315
+ if (!isWithinWorkflowRetryAttempts(r.maxAttempts)) {
3180
3316
  const over = typeof r.maxAttempts === "number" && r.maxAttempts > WORKFLOW_RETRY_MAX_ATTEMPTS;
3181
3317
  err(over ? "cap-exceeded" : "invalid-envelope", workflowRetryMaxAttemptsMessage(r.maxAttempts), `${path3}.retry.maxAttempts`, id);
3182
3318
  }
@@ -3414,7 +3550,7 @@ function validateLuaExtensions(g, caps = WORKFLOW_CAPS_DEFAULT, opts = {
3414
3550
  }
3415
3551
  const a = node;
3416
3552
  checkId(a.id, path3);
3417
- if (a.approver === "creator" && a.excludeInitiator === true) {
3553
+ if ((a.approver ?? "creator") === "creator" && a.excludeInitiator === true) {
3418
3554
  err("approver-excludes-only-candidate", "approver:'creator' with excludeInitiator:true always excludes the only candidate", path3, a.id);
3419
3555
  }
3420
3556
  const editable = approvalEditable(a);
@@ -4717,6 +4853,7 @@ function runErrorIssues(issues) {
4717
4853
  function runNextAction(run) {
4718
4854
  if (isTerminalRunStatus(run.status)) return "none";
4719
4855
  if (run.status === "suspended" && run.gate?.kind === "budget") return "raise_budget";
4856
+ if (run.status === "suspended" && run.gate?.kind === "billing") return "top_up";
4720
4857
  if (!run.cancel?.requestedAt) return "none";
4721
4858
  const forceAt = run.cancel.forceAfter ?? run.cancel.requestedAt + FORCE_CANCEL_STALE_MS;
4722
4859
  return Date.now() >= forceAt ? "force" : "cancel_again";
@@ -4744,6 +4881,12 @@ function runCountsFromStepStatuses(statuses) {
4744
4881
  for (const s of statuses) tally[s] = (tally[s] ?? 0) + 1;
4745
4882
  return runCountsFromStatusTally(tally);
4746
4883
  }
4884
+ function isBillingHeldStep(row) {
4885
+ return row.status === "ready" && row.billingHold === true;
4886
+ }
4887
+ function stepEffectiveStatus(row) {
4888
+ return isBillingHeldStep(row) ? "suspended" : row.status;
4889
+ }
4747
4890
  function runCounts(counts) {
4748
4891
  const c = counts ?? {};
4749
4892
  const rawInFlight = c.dispatched !== void 0 || c.claimed !== void 0 || c.running !== void 0 || c.cancellation_requested !== void 0;
@@ -5430,6 +5573,53 @@ function rebaseItemPointer(pointer, itemsPath, index) {
5430
5573
  const base = `/${itemsPath.split(".").map(escapePointer).join("/")}/${index}`;
5431
5574
  return pointer === "/" || pointer === "" ? base : `${base}${pointer}`;
5432
5575
  }
5576
+ function validateWorkflowSchedule(schedule, path3 = "/schedule") {
5577
+ if (schedule === void 0 || schedule === null) return [];
5578
+ const issue = /* @__PURE__ */ __name3((at, detail) => [
5579
+ {
5580
+ code: WORKFLOW_SCHEDULE_SHAPE_ISSUE,
5581
+ severity: "error",
5582
+ path: at,
5583
+ message: `${detail} \u2014 ${WORKFLOW_SCHEDULE_SHAPES_HINT}`
5584
+ }
5585
+ ], "issue");
5586
+ if (!isObject(schedule)) {
5587
+ return issue(path3, `\`schedule\` is ${Array.isArray(schedule) ? "an array" : `a ${typeof schedule}`}, not a typed schedule object`);
5588
+ }
5589
+ const type = schedule.type;
5590
+ if (type === void 0) {
5591
+ const keys = Object.keys(schedule);
5592
+ const seen = keys.length ? ` (got { ${keys.join(", ")} })` : " (got {})";
5593
+ return issue(path3, `\`schedule\` carries no \`type\` discriminator${seen}`);
5594
+ }
5595
+ if (typeof type !== "string" || !WORKFLOW_SCHEDULE_TYPES.includes(type)) {
5596
+ return issue(path3, `\`schedule.type\` ${JSON.stringify(type)} is not one of ${WORKFLOW_SCHEDULE_TYPES.map((t) => `'${t}'`).join(" | ")}`);
5597
+ }
5598
+ switch (type) {
5599
+ case "cron": {
5600
+ if (typeof schedule.expression !== "string" || schedule.expression.trim().length === 0) {
5601
+ return issue(`${path3}/expression`, "a { type: 'cron' } schedule needs a non-empty string `expression`");
5602
+ }
5603
+ if (schedule.timezone !== void 0 && (typeof schedule.timezone !== "string" || schedule.timezone.length === 0)) {
5604
+ return issue(`${path3}/timezone`, "a { type: 'cron' } schedule's `timezone`, when given, is a non-empty IANA string");
5605
+ }
5606
+ return [];
5607
+ }
5608
+ case "interval": {
5609
+ const s = schedule.seconds;
5610
+ if (typeof s !== "number" || !Number.isFinite(s) || s <= 0) {
5611
+ return issue(`${path3}/seconds`, "a { type: 'interval' } schedule needs a positive number `seconds`");
5612
+ }
5613
+ return [];
5614
+ }
5615
+ case "once": {
5616
+ if (typeof schedule.executeAt !== "string" || Number.isNaN(Date.parse(schedule.executeAt))) {
5617
+ return issue(`${path3}/executeAt`, "a { type: 'once' } schedule needs an ISO-8601 string `executeAt`");
5618
+ }
5619
+ return [];
5620
+ }
5621
+ }
5622
+ }
5433
5623
  function collectEnvTemplateKeys(value22) {
5434
5624
  const keys = /* @__PURE__ */ new Set();
5435
5625
  const walk22 = /* @__PURE__ */ __name3((v) => {
@@ -5719,7 +5909,7 @@ function needsInheritedWorkspace(graph) {
5719
5909
  }
5720
5910
  return false;
5721
5911
  }
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;
5912
+ 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_SCHEDULE_TYPES, WORKFLOW_SCHEDULE_SHAPE_ISSUE, WORKFLOW_SCHEDULE_SHAPES_HINT, isObject, WORKFLOW_ENV_OVERLAY_MAX_KEYS, WORKFLOW_ENV_OVERLAY_MAX_VALUE_BYTES, WORKFLOW_ENV_TEMPLATE_SECRET_KEY_RE, isEnvRef, looksLikeEmbeddedJson, ZERO, isRecord2;
5723
5913
  var init_dist2 = __esm({
5724
5914
  "../workflow-graph/dist/index.mjs"() {
5725
5915
  "use strict";
@@ -6274,6 +6464,10 @@ var init_dist2 = __esm({
6274
6464
  __name3(runCountsFromStatusTally, "runCountsFromStatusTally");
6275
6465
  __name(runCountsFromStepStatuses, "runCountsFromStepStatuses");
6276
6466
  __name3(runCountsFromStepStatuses, "runCountsFromStepStatuses");
6467
+ __name(isBillingHeldStep, "isBillingHeldStep");
6468
+ __name3(isBillingHeldStep, "isBillingHeldStep");
6469
+ __name(stepEffectiveStatus, "stepEffectiveStatus");
6470
+ __name3(stepEffectiveStatus, "stepEffectiveStatus");
6277
6471
  n = /* @__PURE__ */ __name3((v) => typeof v === "number" && Number.isFinite(v) ? v : 0, "n");
6278
6472
  __name(runCounts, "runCounts");
6279
6473
  __name3(runCounts, "runCounts");
@@ -6425,6 +6619,16 @@ var init_dist2 = __esm({
6425
6619
  __name3(applyJsonPatch, "applyJsonPatch");
6426
6620
  __name(rebaseItemPointer, "rebaseItemPointer");
6427
6621
  __name3(rebaseItemPointer, "rebaseItemPointer");
6622
+ WORKFLOW_SCHEDULE_TYPES = [
6623
+ "cron",
6624
+ "interval",
6625
+ "once"
6626
+ ];
6627
+ WORKFLOW_SCHEDULE_SHAPE_ISSUE = "schedule-shape-invalid";
6628
+ WORKFLOW_SCHEDULE_SHAPES_HINT = "`schedule` must be one of { type: 'cron', expression: '<5-field cron>', timezone?: '<IANA tz>' } | { type: 'interval', seconds: <n> } | { type: 'once', executeAt: '<ISO-8601>' }";
6629
+ isObject = /* @__PURE__ */ __name3((v) => typeof v === "object" && v !== null && !Array.isArray(v), "isObject");
6630
+ __name(validateWorkflowSchedule, "validateWorkflowSchedule");
6631
+ __name3(validateWorkflowSchedule, "validateWorkflowSchedule");
6428
6632
  WORKFLOW_ENV_OVERLAY_MAX_KEYS = 64;
6429
6633
  WORKFLOW_ENV_OVERLAY_MAX_VALUE_BYTES = 4096;
6430
6634
  WORKFLOW_ENV_TEMPLATE_SECRET_KEY_RE = /(SECRET|TOKEN|KEY|PASSWORD)$/;
@@ -6691,7 +6895,7 @@ var init_workflow = __esm({
6691
6895
  }, "assertPredicate");
6692
6896
  assertRetry = /* @__PURE__ */ __name((r, id) => {
6693
6897
  if (!r) return;
6694
- if (r.maxAttempts !== void 0 && !isWithinWorkflowRetryAttempts(r.maxAttempts)) {
6898
+ if (!isWithinWorkflowRetryAttempts(r.maxAttempts)) {
6695
6899
  const over = typeof r.maxAttempts === "number" && r.maxAttempts > WORKFLOW_RETRY_MAX_ATTEMPTS;
6696
6900
  throw new LuaWorkflowBuildError(over ? "cap-exceeded" : "invalid-envelope", `"${id}": ${workflowRetryMaxAttemptsMessage(r.maxAttempts)}`);
6697
6901
  }
@@ -7212,9 +7416,12 @@ var init_workflow = __esm({
7212
7416
  if (opts.approver === "creator" && opts.excludeInitiator === true) {
7213
7417
  throw new LuaWorkflowBuildError("approver-excludes-only-candidate", `"${id}": approver:'creator' with excludeInitiator:true always excludes the only candidate`);
7214
7418
  }
7215
- if (opts.fourEyes !== void 0 && opts.editable !== true) throw new LuaWorkflowBuildError("four-eyes-requires-editable", `"${id}": fourEyes requires editable:true`);
7216
- if ((opts.editablePaths !== void 0 || opts.editedPayloadSchema !== void 0) && opts.editable !== true) {
7217
- throw new LuaWorkflowBuildError("editable-path-invalid", `"${id}": editablePaths / editedPayloadSchema require editable:true`);
7419
+ const editable = approvalEditable(opts);
7420
+ if (opts.fourEyes !== void 0 && !editable) throw new LuaWorkflowBuildError("four-eyes-requires-editable", `"${id}": \`fourEyes\` requires editable:true`);
7421
+ if (opts.editable === false && Array.isArray(opts.editablePaths) && opts.editablePaths.length > 0) {
7422
+ throw new LuaWorkflowBuildError("editable-path-invalid", `"${id}": \`editablePaths\` beside editable:false is contradictory \u2014 drop the paths or set editable:true`);
7423
+ } else if ((opts.editablePaths !== void 0 || opts.editedPayloadSchema !== void 0) && !editable) {
7424
+ throw new LuaWorkflowBuildError("editable-path-invalid", `"${id}": \`editablePaths\` / \`editedPayloadSchema\` require editable:true (a non-empty editablePaths implies it)`);
7218
7425
  }
7219
7426
  for (const p of opts.editablePaths ?? []) {
7220
7427
  if (!EDITABLE_PATH_RE2.test(p)) throw new LuaWorkflowBuildError("editable-path-invalid", `"${id}": editablePaths entry "${p}" is outside the grammar seg(.seg)* with [*]/[n] selectors`);
@@ -7465,10 +7672,31 @@ var init_auth_error = __esm({
7465
7672
  });
7466
7673
 
7467
7674
  // src/errors/cli.error.ts
7675
+ function apiErrorDetail(error) {
7676
+ return {
7677
+ serverCode: error?.code,
7678
+ issues: error?.issues,
7679
+ upstream: error?.upstream,
7680
+ requestId: error?.requestId,
7681
+ vendor: error?.vendor,
7682
+ retryAfterSeconds: error?.retryAfterSeconds
7683
+ };
7684
+ }
7468
7685
  function isAccessDeniedError(error) {
7469
7686
  if (CliError.isCliError(error)) return error.statusCode === 403;
7470
7687
  return error instanceof Error && error.message.startsWith("Access denied (403)");
7471
7688
  }
7689
+ function upstreamUnavailableHint(upstream, requestId) {
7690
+ const service = typeof upstream === "string" && upstream ? `its ${upstream} service` : "a service behind it";
7691
+ const ref = typeof requestId === "string" && requestId ? ` If it persists, quote request ${requestId}.` : "";
7692
+ return `The Lua API is up, but ${service} is temporarily unavailable (503 UPSTREAM_UNAVAILABLE) \u2014 retry in a moment.${ref}`;
7693
+ }
7694
+ function vendorUnavailableHint(vendor, requestId, retryAfterSeconds) {
7695
+ const name = typeof vendor === "string" && vendor ? VENDOR_LABELS[vendor] ?? vendor : "a vendor it depends on";
7696
+ const ref = typeof requestId === "string" && requestId ? ` If it persists, quote request ${requestId}.` : "";
7697
+ const retry = typeof retryAfterSeconds === "number" ? "retry in a moment" : "the request may have applied at the vendor \u2014 check before retrying";
7698
+ return `The Lua API is up, but ${name} is temporarily unavailable (503 VENDOR_UNAVAILABLE) \u2014 ${retry}.${ref}`;
7699
+ }
7472
7700
  function authHint(error) {
7473
7701
  if (error.suppressDefaultRemediation) return void 0;
7474
7702
  if (error.reason === "no_agent_access") {
@@ -7492,7 +7720,10 @@ function classifyCliError(error) {
7492
7720
  code: error.code,
7493
7721
  exitCode: error.exitCode,
7494
7722
  message: error.message,
7495
- hint: error.hint
7723
+ hint: error.hint,
7724
+ statusCode: error.statusCode,
7725
+ serverCode: error.serverCode,
7726
+ issues: error.issues
7496
7727
  };
7497
7728
  }
7498
7729
  if (AuthenticationError.isAuthenticationError(error)) {
@@ -7514,30 +7745,36 @@ function classifyCliError(error) {
7514
7745
  }
7515
7746
  const status = numericStatus(e);
7516
7747
  if (status !== void 0) {
7748
+ const statusCode = status;
7517
7749
  if (status === 401) return {
7518
7750
  code: "auth",
7519
7751
  exitCode: CLI_EXIT.AUTH,
7520
- message
7752
+ message,
7753
+ statusCode
7521
7754
  };
7522
7755
  if (status === 403) return {
7523
7756
  code: "forbidden",
7524
7757
  exitCode: CLI_EXIT.FORBIDDEN,
7525
- message
7758
+ message,
7759
+ statusCode
7526
7760
  };
7527
7761
  if (status === 404) return {
7528
7762
  code: "not_found",
7529
7763
  exitCode: CLI_EXIT.NOT_FOUND,
7530
- message
7764
+ message,
7765
+ statusCode
7531
7766
  };
7532
7767
  if (status >= 400 && status < 500) return {
7533
7768
  code: `http_${status}`,
7534
7769
  exitCode: CLI_EXIT.FORBIDDEN,
7535
- message
7770
+ message,
7771
+ statusCode
7536
7772
  };
7537
7773
  if (status >= 500 || status === 0) return {
7538
7774
  code: "unavailable",
7539
7775
  exitCode: CLI_EXIT.UNAVAILABLE,
7540
- message
7776
+ message,
7777
+ statusCode
7541
7778
  };
7542
7779
  }
7543
7780
  const causeCode = e.cause?.code;
@@ -7555,7 +7792,7 @@ function classifyCliError(error) {
7555
7792
  message
7556
7793
  };
7557
7794
  }
7558
- var CLI_EXIT, CliError, NETWORK_ERRNO, NETWORK_MESSAGE, UNAVAILABLE_HINT;
7795
+ var CLI_EXIT, CliError, NETWORK_ERRNO, NETWORK_MESSAGE, UNAVAILABLE_HINT, VENDOR_LABELS;
7559
7796
  var init_cli_error = __esm({
7560
7797
  "src/errors/cli.error.ts"() {
7561
7798
  "use strict";
@@ -7569,6 +7806,7 @@ var init_cli_error = __esm({
7569
7806
  FORBIDDEN: 10,
7570
7807
  UNAVAILABLE: 11
7571
7808
  };
7809
+ __name(apiErrorDetail, "apiErrorDetail");
7572
7810
  CliError = class _CliError extends Error {
7573
7811
  static {
7574
7812
  __name(this, "CliError");
@@ -7578,6 +7816,8 @@ var init_cli_error = __esm({
7578
7816
  exitCode;
7579
7817
  hint;
7580
7818
  statusCode;
7819
+ serverCode;
7820
+ issues;
7581
7821
  constructor(code, message, options = {}) {
7582
7822
  super(message);
7583
7823
  this.name = "CliError";
@@ -7585,6 +7825,8 @@ var init_cli_error = __esm({
7585
7825
  this.exitCode = options.exitCode ?? CLI_EXIT.ERROR;
7586
7826
  this.hint = options.hint;
7587
7827
  this.statusCode = options.statusCode;
7828
+ this.serverCode = options.serverCode;
7829
+ this.issues = options.issues?.length ? options.issues : void 0;
7588
7830
  if (Error.captureStackTrace) Error.captureStackTrace(this, _CliError);
7589
7831
  }
7590
7832
  /** Bad arguments, an unknown action, no project — exit 2. */
@@ -7613,19 +7855,23 @@ var init_cli_error = __esm({
7613
7855
  /**
7614
7856
  * An API refusal the site already holds the status of (LUA-766) — classified by the same table the top-level
7615
7857
  * 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).
7858
+ * (10) · 5xx / 0 unavailable (11, with the network hint unless the site gives its own or the body's code
7859
+ * picks one: a 503 UPSTREAM_UNAVAILABLE names the Lua service behind the API, LUA-810) · no status `error` (1).
7617
7860
  * A command that reads `response.error.statusCode` throws through here, so `lua logs` on a 503 exits 11 like
7618
7861
  * every other verb instead of printing the message itself and then throwing an exit-1 `Error`.
7619
7862
  */
7620
- static fromStatus(statusCode, message, hint) {
7863
+ static fromStatus(statusCode, message, hint, detail = {}) {
7621
7864
  const reported = classifyCliError(Object.assign(new Error(message), {
7622
7865
  statusCode
7623
7866
  }));
7867
+ const codeHint = detail.serverCode === "UPSTREAM_UNAVAILABLE" ? upstreamUnavailableHint(detail.upstream, detail.requestId) : detail.serverCode === "VENDOR_UNAVAILABLE" ? vendorUnavailableHint(detail.vendor, detail.requestId, detail.retryAfterSeconds) : void 0;
7624
7868
  const classHint = reported.exitCode === CLI_EXIT.UNAVAILABLE ? UNAVAILABLE_HINT : reported.hint;
7625
7869
  return new _CliError(reported.code, message, {
7626
7870
  exitCode: reported.exitCode,
7627
- hint: hint ?? classHint,
7628
- statusCode
7871
+ hint: hint ?? codeHint ?? classHint,
7872
+ statusCode,
7873
+ serverCode: detail.serverCode,
7874
+ issues: detail.issues
7629
7875
  });
7630
7876
  }
7631
7877
  static isCliError(error) {
@@ -7649,6 +7895,14 @@ var init_cli_error = __esm({
7649
7895
  ]);
7650
7896
  NETWORK_MESSAGE = /fetch failed|socket hang up|network request failed|request timeout|ECONNREFUSED|ENOTFOUND/i;
7651
7897
  UNAVAILABLE_HINT = "The Lua API could not be reached \u2014 check your network and https://status.heylua.ai, then retry.";
7898
+ __name(upstreamUnavailableHint, "upstreamUnavailableHint");
7899
+ VENDOR_LABELS = {
7900
+ unified: "Unified.to",
7901
+ github: "GitHub",
7902
+ pusher: "Pusher",
7903
+ google: "Google"
7904
+ };
7905
+ __name(vendorUnavailableHint, "vendorUnavailableHint");
7652
7906
  __name(authHint, "authHint");
7653
7907
  __name(numericStatus, "numericStatus");
7654
7908
  __name(classifyCliError, "classifyCliError");
@@ -8126,6 +8380,52 @@ var init_request_credential = __esm({
8126
8380
 
8127
8381
  // src/api/http.client.ts
8128
8382
  import { randomUUID as randomUUID2 } from "crypto";
8383
+ async function classifyErrorResponse(response) {
8384
+ let errorData;
8385
+ try {
8386
+ errorData = await response.json();
8387
+ } catch (jsonError) {
8388
+ errorData = {};
8389
+ }
8390
+ if (response.status === 401) {
8391
+ const serverMessage = typeof errorData.message === "string" ? errorData.message : void 0;
8392
+ if (serverMessage && /not an admin/i.test(serverMessage)) {
8393
+ throw new AuthenticationError(`Access denied for this agent: ${serverMessage}`, "no_agent_access", serverMessage);
8394
+ }
8395
+ const isExplicitCredential = !!serverMessage && /(invalid|expired|missing|no)\s+(api[\s_-]?key|token|credential)/i.test(serverMessage);
8396
+ const isBareAuthRejection = !serverMessage || /^unauthorized$/i.test(serverMessage);
8397
+ if (isExplicitCredential || isBareAuthRejection) {
8398
+ throw new AuthenticationError("Authentication failed. Your Lua credential may be invalid or expired.", "invalid_credentials", serverMessage);
8399
+ }
8400
+ throw new AuthenticationError(`Authentication failed: ${serverMessage}`, "unknown", serverMessage);
8401
+ }
8402
+ if (response.status === 403) {
8403
+ const detail = errorData.message || "You do not have permission to access this resource.";
8404
+ const serverCode = serverCodeOf(errorData.code, errorData.error);
8405
+ throw new CliError("forbidden", `Access denied (403): ${detail}${serverCode ? ` (${serverCode})` : ""}`, {
8406
+ exitCode: CLI_EXIT.FORBIDDEN,
8407
+ statusCode: 403,
8408
+ serverCode,
8409
+ issues: Array.isArray(errorData.issues) ? errorData.issues : void 0,
8410
+ hint: "Check that your Lua login has access to this agent or organization."
8411
+ });
8412
+ }
8413
+ return {
8414
+ success: false,
8415
+ error: {
8416
+ message: errorData.message || `HTTP ${response.status}: ${response.statusText}`,
8417
+ statusCode: response.status,
8418
+ error: errorData.error,
8419
+ retryAfterSeconds: parseRetryAfter(response.headers.get("retry-after")),
8420
+ ...errorData
8421
+ }
8422
+ };
8423
+ }
8424
+ function serverCodeOf(code, error) {
8425
+ if (typeof code === "string" && code.length > 0) return code;
8426
+ if (typeof error === "string" && /^[A-Z0-9][A-Z0-9_]*$/.test(error)) return error;
8427
+ return void 0;
8428
+ }
8129
8429
  async function* parseSseStream(body, signal) {
8130
8430
  const reader = body.getReader();
8131
8431
  const decoder = new TextDecoder();
@@ -8306,42 +8606,7 @@ var init_http_client = __esm({
8306
8606
  * @private
8307
8607
  */
8308
8608
  async classifyErrorResponse(response) {
8309
- let errorData;
8310
- try {
8311
- errorData = await response.json();
8312
- } catch (jsonError) {
8313
- errorData = {};
8314
- }
8315
- if (response.status === 401) {
8316
- const serverMessage = typeof errorData.message === "string" ? errorData.message : void 0;
8317
- if (serverMessage && /not an admin/i.test(serverMessage)) {
8318
- throw new AuthenticationError(`Access denied for this agent: ${serverMessage}`, "no_agent_access", serverMessage);
8319
- }
8320
- const isExplicitCredential = !!serverMessage && /(invalid|expired|missing|no)\s+(api[\s_-]?key|token|credential)/i.test(serverMessage);
8321
- const isBareAuthRejection = !serverMessage || /^unauthorized$/i.test(serverMessage);
8322
- if (isExplicitCredential || isBareAuthRejection) {
8323
- throw new AuthenticationError("Authentication failed. Your Lua credential may be invalid or expired.", "invalid_credentials", serverMessage);
8324
- }
8325
- throw new AuthenticationError(`Authentication failed: ${serverMessage}`, "unknown", serverMessage);
8326
- }
8327
- if (response.status === 403) {
8328
- const detail = errorData.message || "You do not have permission to access this resource.";
8329
- throw new CliError("forbidden", `Access denied (403): ${detail}`, {
8330
- exitCode: CLI_EXIT.FORBIDDEN,
8331
- statusCode: 403,
8332
- hint: "Check that your Lua login has access to this agent or organization."
8333
- });
8334
- }
8335
- return {
8336
- success: false,
8337
- error: {
8338
- message: errorData.message || `HTTP ${response.status}: ${response.statusText}`,
8339
- statusCode: response.status,
8340
- error: errorData.error,
8341
- retryAfterSeconds: parseRetryAfter(response.headers.get("retry-after")),
8342
- ...errorData
8343
- }
8344
- };
8609
+ return classifyErrorResponse(response);
8345
8610
  }
8346
8611
  /**
8347
8612
  * Checks if an HTTP status code is retryable
@@ -8365,6 +8630,21 @@ var init_http_client = __esm({
8365
8630
  return Math.max(100, Math.random() * exponential);
8366
8631
  }
8367
8632
  /**
8633
+ * The wait before the next attempt: the client's jittered exponential backoff, floored by the server's
8634
+ * `retryAfterSeconds` on a 429 (the limiter's word is final) and on an idempotent read (GET / HEAD). LUA-810: a
8635
+ * POST / PUT / PATCH / DELETE that met a 5xx keeps the client's own backoff — every 503 body carries
8636
+ * `retryAfterSeconds: 5` (`CONTROL_UNAVAILABLE`, `UPSTREAM_UNAVAILABLE`), which floored all three waits at 5 s:
8637
+ * a ≥15 s stall on a write that may already have landed, and retrying an ambiguous write harder does not make
8638
+ * it less ambiguous. The client's own schedule is ≤1 s + ≤2 s + ≤4 s.
8639
+ */
8640
+ retryDelayMs(attempt, error, method) {
8641
+ const own = this.calculateBackoff(attempt);
8642
+ const advised = Number(error?.retryAfterSeconds ?? 0) * 1e3;
8643
+ const verb = (method ?? "GET").toUpperCase();
8644
+ const honourAdvice = error?.statusCode === 429 || verb === "GET" || verb === "HEAD";
8645
+ return honourAdvice ? Math.max(own, advised) : own;
8646
+ }
8647
+ /**
8368
8648
  * Wraps request with retry logic for transient failures
8369
8649
  * @param url - The full URL to request
8370
8650
  * @param options - Fetch API request options
@@ -8398,8 +8678,7 @@ var init_http_client = __esm({
8398
8678
  throw error;
8399
8679
  }
8400
8680
  if (attempt < maxRetries) {
8401
- const serverDelay = Number(lastResult?.error?.retryAfterSeconds ?? 0) * 1e3;
8402
- const backoff = Math.max(this.calculateBackoff(attempt), serverDelay);
8681
+ const backoff = this.retryDelayMs(attempt, lastResult?.error, options.method);
8403
8682
  await new Promise((resolve3) => setTimeout(resolve3, backoff));
8404
8683
  }
8405
8684
  }
@@ -8549,6 +8828,8 @@ var init_http_client = __esm({
8549
8828
  };
8550
8829
  }
8551
8830
  };
8831
+ __name(classifyErrorResponse, "classifyErrorResponse");
8832
+ __name(serverCodeOf, "serverCodeOf");
8552
8833
  __name(parseSseStream, "parseSseStream");
8553
8834
  __name(parseRetryAfter, "parseRetryAfter");
8554
8835
  __name(isCoreDrainApiError, "isCoreDrainApiError");
@@ -12607,6 +12888,7 @@ var init_job_api_service = __esm({
12607
12888
  "src/api/job.api.service.ts"() {
12608
12889
  "use strict";
12609
12890
  init_http_client();
12891
+ init_cli_error();
12610
12892
  init_job_instance();
12611
12893
  JobApi = class extends HttpClient {
12612
12894
  static {
@@ -12663,7 +12945,7 @@ var init_job_api_service = __esm({
12663
12945
  if (response.success && response.data) {
12664
12946
  return new JobInstance(this, response.data);
12665
12947
  }
12666
- throw new Error(response.error?.message || "Failed to get job");
12948
+ throw CliError.fromStatus(response.error?.statusCode, response.error?.message || "Failed to get job", void 0, apiErrorDetail(response.error));
12667
12949
  }
12668
12950
  /**
12669
12951
  * Creates a new job for the agent.