lua-cli 3.32.5 → 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.
@@ -582,6 +582,13 @@ declare interface ApiResponse<T = any> {
582
582
  stepId?: string;
583
583
  /** the live step status on 409 NOT_SUSPENDED (LUA-644) */
584
584
  status?: string;
585
+ /** LUA-810 — 503 UPSTREAM_UNAVAILABLE: the internal Lua service behind the API that answered a fault or did
586
+ * not answer (`lua-agents`, `lua-core`, …), and the id on the server's matching error log line. */
587
+ upstream?: string;
588
+ requestId?: string;
589
+ /** LUA-812 — 503 VENDOR_UNAVAILABLE: the third-party vendor behind the API that failed (`unified` | `github` |
590
+ * `pusher` | `google`); `retryAfterSeconds` above is present only when a blind retry is safe. */
591
+ vendor?: string;
585
592
  };
586
593
  }
587
594
 
@@ -599,6 +606,11 @@ export declare interface ApprovalOptions {
599
606
  /** default 'continue' (denial is data unless 'fail') */
600
607
  onDeny?: WorkflowApprovalOnDeny;
601
608
  businessHours?: WorkflowBusinessHours;
609
+ /**
610
+ * Optional — inferred `true` from a non-empty `editablePaths` (LUA-808 / LUA-825: the validator's `approvalEditable`
611
+ * rule, applied by the builder too); an explicit `false` beside paths is refused as contradictory. Absent with no
612
+ * paths ⇒ `false` (the approver decides, never edits).
613
+ */
602
614
  editable?: boolean;
603
615
  /** grammar: `drafts`, `drafts[*]`, `drafts[*].body`, `drafts[3].body`, `summary.title` */
604
616
  editablePaths?: string[];
@@ -2229,6 +2241,15 @@ declare abstract class HttpClient {
2229
2241
  * @private
2230
2242
  */
2231
2243
  private calculateBackoff;
2244
+ /**
2245
+ * The wait before the next attempt: the client's jittered exponential backoff, floored by the server's
2246
+ * `retryAfterSeconds` on a 429 (the limiter's word is final) and on an idempotent read (GET / HEAD). LUA-810: a
2247
+ * POST / PUT / PATCH / DELETE that met a 5xx keeps the client's own backoff — every 503 body carries
2248
+ * `retryAfterSeconds: 5` (`CONTROL_UNAVAILABLE`, `UPSTREAM_UNAVAILABLE`), which floored all three waits at 5 s:
2249
+ * a ≥15 s stall on a write that may already have landed, and retrying an ambiguous write harder does not make
2250
+ * it less ambiguous. The client's own schedule is ≤1 s + ≤2 s + ≤4 s.
2251
+ */
2252
+ private retryDelayMs;
2232
2253
  /**
2233
2254
  * Wraps request with retry logic for transient failures
2234
2255
  * @param url - The full URL to request
@@ -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
  }
@@ -1109,7 +1121,7 @@ function effectiveAgentFeatureRows(base, override) {
1109
1121
  ]))
1110
1122
  };
1111
1123
  }
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;
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;
1113
1125
  var init_dist = __esm({
1114
1126
  "../shared-types/dist/index.mjs"() {
1115
1127
  "use strict";
@@ -1436,6 +1448,11 @@ var init_dist = __esm({
1436
1448
  __name2(normalizeModelId, "normalizeModelId");
1437
1449
  __name(modelUnresolvedMessage, "modelUnresolvedMessage");
1438
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");
1439
1456
  REASONING_EFFORT_VALUES = [
1440
1457
  "off",
1441
1458
  "minimal",
@@ -3051,7 +3068,7 @@ function fillHitl(node) {
3051
3068
  if (a.onTimeout === void 0) a.onTimeout = "deny";
3052
3069
  if (a.onDeny === void 0) a.onDeny = "continue";
3053
3070
  if (a.excludeInitiator === void 0) a.excludeInitiator = false;
3054
- if (a.editable === void 0) a.editable = false;
3071
+ if (a.editable === void 0) a.editable = approvalEditable(a);
3055
3072
  return;
3056
3073
  }
3057
3074
  const w = node;
@@ -3533,7 +3550,7 @@ function validateLuaExtensions(g, caps = WORKFLOW_CAPS_DEFAULT, opts = {
3533
3550
  }
3534
3551
  const a = node;
3535
3552
  checkId(a.id, path3);
3536
- if (a.approver === "creator" && a.excludeInitiator === true) {
3553
+ if ((a.approver ?? "creator") === "creator" && a.excludeInitiator === true) {
3537
3554
  err("approver-excludes-only-candidate", "approver:'creator' with excludeInitiator:true always excludes the only candidate", path3, a.id);
3538
3555
  }
3539
3556
  const editable = approvalEditable(a);
@@ -5556,6 +5573,53 @@ function rebaseItemPointer(pointer, itemsPath, index) {
5556
5573
  const base = `/${itemsPath.split(".").map(escapePointer).join("/")}/${index}`;
5557
5574
  return pointer === "/" || pointer === "" ? base : `${base}${pointer}`;
5558
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
+ }
5559
5623
  function collectEnvTemplateKeys(value22) {
5560
5624
  const keys = /* @__PURE__ */ new Set();
5561
5625
  const walk22 = /* @__PURE__ */ __name3((v) => {
@@ -5845,7 +5909,7 @@ function needsInheritedWorkspace(graph) {
5845
5909
  }
5846
5910
  return false;
5847
5911
  }
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;
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;
5849
5913
  var init_dist2 = __esm({
5850
5914
  "../workflow-graph/dist/index.mjs"() {
5851
5915
  "use strict";
@@ -6555,6 +6619,16 @@ var init_dist2 = __esm({
6555
6619
  __name3(applyJsonPatch, "applyJsonPatch");
6556
6620
  __name(rebaseItemPointer, "rebaseItemPointer");
6557
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");
6558
6632
  WORKFLOW_ENV_OVERLAY_MAX_KEYS = 64;
6559
6633
  WORKFLOW_ENV_OVERLAY_MAX_VALUE_BYTES = 4096;
6560
6634
  WORKFLOW_ENV_TEMPLATE_SECRET_KEY_RE = /(SECRET|TOKEN|KEY|PASSWORD)$/;
@@ -7342,9 +7416,12 @@ var init_workflow = __esm({
7342
7416
  if (opts.approver === "creator" && opts.excludeInitiator === true) {
7343
7417
  throw new LuaWorkflowBuildError("approver-excludes-only-candidate", `"${id}": approver:'creator' with excludeInitiator:true always excludes the only candidate`);
7344
7418
  }
7345
- if (opts.fourEyes !== void 0 && opts.editable !== true) throw new LuaWorkflowBuildError("four-eyes-requires-editable", `"${id}": fourEyes requires editable:true`);
7346
- if ((opts.editablePaths !== void 0 || opts.editedPayloadSchema !== void 0) && opts.editable !== true) {
7347
- 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)`);
7348
7425
  }
7349
7426
  for (const p of opts.editablePaths ?? []) {
7350
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`);
@@ -7595,10 +7672,31 @@ var init_auth_error = __esm({
7595
7672
  });
7596
7673
 
7597
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
+ }
7598
7685
  function isAccessDeniedError(error) {
7599
7686
  if (CliError.isCliError(error)) return error.statusCode === 403;
7600
7687
  return error instanceof Error && error.message.startsWith("Access denied (403)");
7601
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
+ }
7602
7700
  function authHint(error) {
7603
7701
  if (error.suppressDefaultRemediation) return void 0;
7604
7702
  if (error.reason === "no_agent_access") {
@@ -7694,7 +7792,7 @@ function classifyCliError(error) {
7694
7792
  message
7695
7793
  };
7696
7794
  }
7697
- var CLI_EXIT, CliError, NETWORK_ERRNO, NETWORK_MESSAGE, UNAVAILABLE_HINT;
7795
+ var CLI_EXIT, CliError, NETWORK_ERRNO, NETWORK_MESSAGE, UNAVAILABLE_HINT, VENDOR_LABELS;
7698
7796
  var init_cli_error = __esm({
7699
7797
  "src/errors/cli.error.ts"() {
7700
7798
  "use strict";
@@ -7708,6 +7806,7 @@ var init_cli_error = __esm({
7708
7806
  FORBIDDEN: 10,
7709
7807
  UNAVAILABLE: 11
7710
7808
  };
7809
+ __name(apiErrorDetail, "apiErrorDetail");
7711
7810
  CliError = class _CliError extends Error {
7712
7811
  static {
7713
7812
  __name(this, "CliError");
@@ -7756,7 +7855,8 @@ var init_cli_error = __esm({
7756
7855
  /**
7757
7856
  * An API refusal the site already holds the status of (LUA-766) — classified by the same table the top-level
7758
7857
  * 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).
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).
7760
7860
  * A command that reads `response.error.statusCode` throws through here, so `lua logs` on a 503 exits 11 like
7761
7861
  * every other verb instead of printing the message itself and then throwing an exit-1 `Error`.
7762
7862
  */
@@ -7764,10 +7864,11 @@ var init_cli_error = __esm({
7764
7864
  const reported = classifyCliError(Object.assign(new Error(message), {
7765
7865
  statusCode
7766
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;
7767
7868
  const classHint = reported.exitCode === CLI_EXIT.UNAVAILABLE ? UNAVAILABLE_HINT : reported.hint;
7768
7869
  return new _CliError(reported.code, message, {
7769
7870
  exitCode: reported.exitCode,
7770
- hint: hint ?? classHint,
7871
+ hint: hint ?? codeHint ?? classHint,
7771
7872
  statusCode,
7772
7873
  serverCode: detail.serverCode,
7773
7874
  issues: detail.issues
@@ -7794,6 +7895,14 @@ var init_cli_error = __esm({
7794
7895
  ]);
7795
7896
  NETWORK_MESSAGE = /fetch failed|socket hang up|network request failed|request timeout|ECONNREFUSED|ENOTFOUND/i;
7796
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");
7797
7906
  __name(authHint, "authHint");
7798
7907
  __name(numericStatus, "numericStatus");
7799
7908
  __name(classifyCliError, "classifyCliError");
@@ -8521,6 +8630,21 @@ var init_http_client = __esm({
8521
8630
  return Math.max(100, Math.random() * exponential);
8522
8631
  }
8523
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
+ /**
8524
8648
  * Wraps request with retry logic for transient failures
8525
8649
  * @param url - The full URL to request
8526
8650
  * @param options - Fetch API request options
@@ -8554,8 +8678,7 @@ var init_http_client = __esm({
8554
8678
  throw error;
8555
8679
  }
8556
8680
  if (attempt < maxRetries) {
8557
- const serverDelay = Number(lastResult?.error?.retryAfterSeconds ?? 0) * 1e3;
8558
- const backoff = Math.max(this.calculateBackoff(attempt), serverDelay);
8681
+ const backoff = this.retryDelayMs(attempt, lastResult?.error, options.method);
8559
8682
  await new Promise((resolve3) => setTimeout(resolve3, backoff));
8560
8683
  }
8561
8684
  }
@@ -12822,7 +12945,7 @@ var init_job_api_service = __esm({
12822
12945
  if (response.success && response.data) {
12823
12946
  return new JobInstance(this, response.data);
12824
12947
  }
12825
- throw CliError.fromStatus(response.error?.statusCode, 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));
12826
12949
  }
12827
12950
  /**
12828
12951
  * Creates a new job for the agent.