lua-cli 3.32.6 → 3.34.0

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.
@@ -83,6 +83,9 @@ function aiGenerateInputFromSimplified(prompt, content) {
83
83
  function isAllowedReviewableExecuteTool(tool) {
84
84
  return REVIEWABLE_ACTION_EXECUTE_TOOL_ALLOWLIST.includes(tool);
85
85
  }
86
+ function isReviewableStandingStartTool(tool) {
87
+ return REVIEWABLE_STANDING_START_TOOLS.includes(tool);
88
+ }
86
89
  function isReviewableMcpSendTool(tool) {
87
90
  return tool.length > REVIEWABLE_MCP_SEND_TOOL_SUFFIX.length && tool.endsWith(REVIEWABLE_MCP_SEND_TOOL_SUFFIX);
88
91
  }
@@ -112,7 +115,7 @@ function mcpSendSiblingForDraftTool(tool, availableToolIds) {
112
115
  return candidates[0]?.id;
113
116
  }
114
117
  function isReviewableExecuteTool(tool) {
115
- return isAllowedReviewableExecuteTool(tool) || isReviewableMcpSendTool(tool);
118
+ return isAllowedReviewableExecuteTool(tool) || isReviewableMcpSendTool(tool) || isReviewableStandingStartTool(tool);
116
119
  }
117
120
  function isInteractiveChannel(channel) {
118
121
  if (!channel) return true;
@@ -258,7 +261,10 @@ function transformChatHistoryContentParts(parts) {
258
261
  content.push({
259
262
  type: "file",
260
263
  data: part.data,
261
- mediaType
264
+ mediaType,
265
+ ...part.filename && {
266
+ filename: part.filename
267
+ }
262
268
  });
263
269
  }
264
270
  }
@@ -537,6 +543,55 @@ function normalizeLuaJobExecutionTimeoutSeconds(timeout) {
537
543
  }
538
544
  return Math.min(Math.max(timeout, LUA_JOB_MIN_TIMEOUT_SECONDS), LUA_JOB_MAX_TIMEOUT_SECONDS);
539
545
  }
546
+ function isId(value3) {
547
+ return typeof value3 === "string" && value3.length > 0 && value3.length <= MAX_ID_LENGTH;
548
+ }
549
+ function parseScheduledJobFire(raw) {
550
+ if (new TextEncoder().encode(raw).byteLength > MAX_BODY_BYTES) {
551
+ throw new Error("Invalid scheduled job fire: body is too large");
552
+ }
553
+ let value3;
554
+ try {
555
+ value3 = JSON.parse(raw);
556
+ } catch {
557
+ throw new Error("Invalid scheduled job fire: body is not JSON");
558
+ }
559
+ if (!value3 || typeof value3 !== "object" || Array.isArray(value3)) {
560
+ throw new Error("Invalid scheduled job fire: body must be an object");
561
+ }
562
+ const record = value3;
563
+ if (Object.keys(record).some((key) => !KEYS.has(key))) {
564
+ throw new Error("Invalid scheduled job fire: unknown field");
565
+ }
566
+ if (record.v !== 1 || record.kind !== "scheduled-job-fire") {
567
+ throw new Error("Invalid scheduled job fire: unsupported contract");
568
+ }
569
+ if (!isId(record.agentId)) {
570
+ throw new Error("Invalid scheduled job fire: agentId is required");
571
+ }
572
+ if (!isId(record.jobId)) {
573
+ throw new Error("Invalid scheduled job fire: jobId is required");
574
+ }
575
+ if (typeof record.scheduledTime !== "string" || !UTC_ISO.test(record.scheduledTime) || !Number.isFinite(Date.parse(record.scheduledTime)) || ![
576
+ new Date(record.scheduledTime).toISOString(),
577
+ new Date(record.scheduledTime).toISOString().replace(".000Z", "Z")
578
+ ].includes(record.scheduledTime)) {
579
+ throw new Error("Invalid scheduled job fire: scheduledTime must be ISO 8601");
580
+ }
581
+ if (record.triggerId !== void 0 && !isId(record.triggerId)) {
582
+ throw new Error("Invalid scheduled job fire: triggerId must be a non-empty string");
583
+ }
584
+ return {
585
+ v: 1,
586
+ kind: "scheduled-job-fire",
587
+ agentId: record.agentId,
588
+ jobId: record.jobId,
589
+ scheduledTime: record.scheduledTime,
590
+ ...typeof record.triggerId === "string" ? {
591
+ triggerId: record.triggerId
592
+ } : {}
593
+ };
594
+ }
540
595
  function triggerUrlEnvKey(triggerKey) {
541
596
  const upper = triggerKey.trim().replace(/[^A-Za-z0-9]+/g, "_").replace(/^_+|_+$/g, "").toUpperCase();
542
597
  return `${TEMPLATE_TRIGGER_URL_ENV_PREFIX}${upper}`;
@@ -711,6 +766,9 @@ function creatorUserId(identity) {
711
766
  function actingUserId(identity) {
712
767
  return creatorUserId(identity);
713
768
  }
769
+ function isWorkflowSignalEventSite(value3) {
770
+ return typeof value3 === "string" && WORKFLOW_SIGNAL_EVENT_SITES.includes(value3);
771
+ }
714
772
  function shouldSkipArchive(run, manifestSha256, sinkSha256) {
715
773
  if (!run.completedAt || !run.exportedAt || run.exportedAt < run.completedAt) return false;
716
774
  return !!manifestSha256 && manifestSha256 === sinkSha256;
@@ -850,6 +908,23 @@ function workflowHitlArmUnsupportedMessage(type, id, container) {
850
908
  function workflowHitlArmShapeMessage(type, id, shape) {
851
909
  return shape === "mapped-arm" ? `\`${type}\` arm "${id}" takes the previous output as its payload \u2014 it cannot head a [mapping, step] chain; map before the container instead` : `a chunked foreach hands each child a slice of items, not one \u2014 \`${type}\` body "${id}" takes one item; drop \`chunk\``;
852
910
  }
911
+ function workflowGoalJudgeKind(judge) {
912
+ return judge && typeof judge === "object" && judge.predicate !== void 0 ? "predicate" : "agent";
913
+ }
914
+ function isWorkflowGoalJudgeComplete(judge) {
915
+ if (workflowGoalJudgeKind(judge) === "predicate") return true;
916
+ return typeof judge.agentId === "string" && judge.agentId.length > 0 && !!judge.schema && typeof judge.schema === "object" && !Array.isArray(judge.schema);
917
+ }
918
+ function normalizeWorkflowGoalJudge(judge) {
919
+ if (workflowGoalJudgeKind(judge) === "agent") return judge;
920
+ return {
921
+ agentId: judge.agentId ?? WORKFLOW_GOAL_JUDGE_SELF,
922
+ predicate: judge.predicate,
923
+ ...judge.schema ? {
924
+ schema: judge.schema
925
+ } : {}
926
+ };
927
+ }
853
928
  function groupCount(re) {
854
929
  let n2 = GROUP_COUNT.get(re);
855
930
  if (n2 === void 0) {
@@ -1089,19 +1164,27 @@ function resolveEffectiveFeature(row, catalogDefault) {
1089
1164
  default: catalogDefault
1090
1165
  };
1091
1166
  }
1092
- function isFeatureRow(value3) {
1093
- return typeof value3 === "object" && value3 !== null;
1167
+ function asFeatureRow(value3) {
1168
+ if (value3 === false) return {
1169
+ active: false
1170
+ };
1171
+ return typeof value3 === "object" && value3 !== null && !Array.isArray(value3) ? value3 : void 0;
1172
+ }
1173
+ function agentFeatureBagCarries(bag, name) {
1174
+ return bag != null && Object.prototype.hasOwnProperty.call(bag, name) && asFeatureRow(bag[name]) !== void 0;
1094
1175
  }
1095
1176
  function effectiveAgentFeatureRows(base, override) {
1096
1177
  const merged = /* @__PURE__ */ new Map();
1097
- for (const [name, row] of Object.entries(base ?? {})) {
1098
- if (isFeatureRow(row)) merged.set(name, {
1178
+ for (const [name, value3] of Object.entries(base ?? {})) {
1179
+ const row = asFeatureRow(value3);
1180
+ if (row) merged.set(name, {
1099
1181
  row,
1100
1182
  origin: "baseAgent"
1101
1183
  });
1102
1184
  }
1103
- for (const [name, row] of Object.entries(override ?? {})) {
1104
- if (isFeatureRow(row)) merged.set(name, {
1185
+ for (const [name, value3] of Object.entries(override ?? {})) {
1186
+ const row = asFeatureRow(value3);
1187
+ if (row) merged.set(name, {
1105
1188
  row,
1106
1189
  origin: "subAgent"
1107
1190
  });
@@ -1121,7 +1204,15 @@ function effectiveAgentFeatureRows(base, override) {
1121
1204
  ]))
1122
1205
  };
1123
1206
  }
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;
1207
+ function agentFeatureMergeRuleFromEnv(env2) {
1208
+ const raw = env2[SUBAGENT_PER_KEY_FLAG_ENV];
1209
+ return typeof raw === "string" && PER_KEY_FLAG_VALUES.has(raw.trim().toLowerCase()) ? "per-key" : "wholesale";
1210
+ }
1211
+ function effectiveAgentFeatures(base, override, rule) {
1212
+ if (rule === "wholesale") return override || base || void 0;
1213
+ return effectiveAgentFeatureRows(base, override).rows;
1214
+ }
1215
+ var __defProp2, __name2, CHANNEL_SEND_CHANNELS, REVIEWABLE_ACTION_EXECUTE_TOOL_ALLOWLIST, REVIEWABLE_STANDING_START_TOOLS, 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, KEYS, MAX_BODY_BYTES, MAX_ID_LENGTH, UTC_ISO, TEMPLATE_TRIGGER_URL_ENV_PREFIX, TEMPLATE_INSTALL_POLICY_PER_WORKSPACE_VALUES, 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, LUA_SESSION_ID_CLAIM, SESSION_REVOKED_CODE, 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_RUN_GATE_KINDS, WORKFLOW_STEP_STATUSES, WORKFLOW_STEP_IN_FLIGHT, WORKFLOW_SIGNAL_EVENT_SITES, 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_SUSPEND_KINDS, WORKFLOW_RUN_NOTIFICATION_SUSPENDED_KINDS, 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, WORKFLOW_GOAL_JUDGE_SELF, 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, SUBAGENT_PER_KEY_FLAG_ENV, PER_KEY_FLAG_VALUES;
1125
1216
  var init_dist = __esm({
1126
1217
  "../shared-types/dist/index.mjs"() {
1127
1218
  "use strict";
@@ -1161,6 +1252,11 @@ var init_dist = __esm({
1161
1252
  ];
1162
1253
  __name(isAllowedReviewableExecuteTool, "isAllowedReviewableExecuteTool");
1163
1254
  __name2(isAllowedReviewableExecuteTool, "isAllowedReviewableExecuteTool");
1255
+ REVIEWABLE_STANDING_START_TOOLS = [
1256
+ "scheduleWorkflow"
1257
+ ];
1258
+ __name(isReviewableStandingStartTool, "isReviewableStandingStartTool");
1259
+ __name2(isReviewableStandingStartTool, "isReviewableStandingStartTool");
1164
1260
  REVIEWABLE_MCP_SEND_TOOL_SUFFIX = "_create_messaging_message";
1165
1261
  __name(isReviewableMcpSendTool, "isReviewableMcpSendTool");
1166
1262
  __name2(isReviewableMcpSendTool, "isReviewableMcpSendTool");
@@ -1821,9 +1917,28 @@ This text is who you are for this person. As you learn them, their name, their w
1821
1917
  __name2(resolveLuaJobTimeoutSeconds, "resolveLuaJobTimeoutSeconds");
1822
1918
  __name(normalizeLuaJobExecutionTimeoutSeconds, "normalizeLuaJobExecutionTimeoutSeconds");
1823
1919
  __name2(normalizeLuaJobExecutionTimeoutSeconds, "normalizeLuaJobExecutionTimeoutSeconds");
1920
+ KEYS = /* @__PURE__ */ new Set([
1921
+ "v",
1922
+ "kind",
1923
+ "agentId",
1924
+ "jobId",
1925
+ "scheduledTime",
1926
+ "triggerId"
1927
+ ]);
1928
+ MAX_BODY_BYTES = 4096;
1929
+ MAX_ID_LENGTH = 512;
1930
+ UTC_ISO = /^\d{4}-\d{2}-\d{2}T\d{2}:\d{2}:\d{2}(?:\.\d{3})?Z$/;
1931
+ __name(isId, "isId");
1932
+ __name2(isId, "isId");
1933
+ __name(parseScheduledJobFire, "parseScheduledJobFire");
1934
+ __name2(parseScheduledJobFire, "parseScheduledJobFire");
1824
1935
  TEMPLATE_TRIGGER_URL_ENV_PREFIX = "LUA_TRIGGER_URL__";
1825
1936
  __name(triggerUrlEnvKey, "triggerUrlEnvKey");
1826
1937
  __name2(triggerUrlEnvKey, "triggerUrlEnvKey");
1938
+ TEMPLATE_INSTALL_POLICY_PER_WORKSPACE_VALUES = Object.freeze([
1939
+ "single",
1940
+ "multiple"
1941
+ ]);
1827
1942
  SUBJECT_TYPES = [
1828
1943
  "user",
1829
1944
  "apiKey",
@@ -2008,6 +2123,8 @@ This text is who you are for this person. As you learn them, their name, their w
2008
2123
  __name2(formatLuaClientHeader, "formatLuaClientHeader");
2009
2124
  __name(luaClientMetricLabels, "luaClientMetricLabels");
2010
2125
  __name2(luaClientMetricLabels, "luaClientMetricLabels");
2126
+ LUA_SESSION_ID_CLAIM = "luaSessionId";
2127
+ SESSION_REVOKED_CODE = "SESSION_REVOKED";
2011
2128
  AUTHZ_PROJECTION_VERSION = 1;
2012
2129
  ProjectedScopeSchema = z3.string().min(1).max(128);
2013
2130
  DisplayRoleSchema = z3.object({
@@ -2084,7 +2201,20 @@ This text is who you are for this person. As you learn them, their name, their w
2084
2201
  "platform-allowlist"
2085
2202
  ]),
2086
2203
  /** Product data only. A roster row confers nothing. */
2087
- rostered: z3.boolean()
2204
+ rostered: z3.boolean(),
2205
+ /**
2206
+ * Ownership, product data only (PRO-1754). `createdBy` is the creating
2207
+ * user's id straight off the sub-agent document; `owner` is that id
2208
+ * resolved to a display identity after the list is decided. Both are
2209
+ * absent when the document records no creator or the lookup fails —
2210
+ * they never influence which resources are listed.
2211
+ */
2212
+ createdBy: z3.string().min(1).max(256).optional(),
2213
+ owner: z3.object({
2214
+ id: z3.string().min(1).max(256),
2215
+ name: z3.string().optional(),
2216
+ email: z3.string().optional()
2217
+ }).optional()
2088
2218
  }).passthrough();
2089
2219
  CapabilityProfilesSchema = z3.record(z3.string().min(1).max(64), z3.array(ProjectedScopeSchema));
2090
2220
  RoleCatalogSchema = z3.record(z3.string().min(1).max(128), z3.object({
@@ -2167,6 +2297,15 @@ This text is who you are for this person. As you learn them, their name, their w
2167
2297
  ...WORKFLOW_RUN_IDLE,
2168
2298
  ...WORKFLOW_RUN_TERMINAL
2169
2299
  ];
2300
+ WORKFLOW_RUN_GATE_KINDS = [
2301
+ "start-consent",
2302
+ "quota",
2303
+ "billing",
2304
+ "org_archived",
2305
+ "disabled",
2306
+ "exception",
2307
+ "budget"
2308
+ ];
2170
2309
  WORKFLOW_STEP_STATUSES = [
2171
2310
  "pending",
2172
2311
  "ready",
@@ -2188,6 +2327,13 @@ This text is who you are for this person. As you learn them, their name, their w
2188
2327
  "running",
2189
2328
  "cancellation_requested"
2190
2329
  ];
2330
+ WORKFLOW_SIGNAL_EVENT_SITES = [
2331
+ "webhook",
2332
+ "trigger",
2333
+ "device-trigger"
2334
+ ];
2335
+ __name(isWorkflowSignalEventSite, "isWorkflowSignalEventSite");
2336
+ __name2(isWorkflowSignalEventSite, "isWorkflowSignalEventSite");
2191
2337
  ARCHIVE_WINDOW_MARGIN_DAYS = 7;
2192
2338
  __name(shouldSkipArchive, "shouldSkipArchive");
2193
2339
  __name2(shouldSkipArchive, "shouldSkipArchive");
@@ -2230,6 +2376,16 @@ This text is who you are for this person. As you learn them, their name, their w
2230
2376
  __name2(scheduledTimeKey, "scheduledTimeKey");
2231
2377
  __name(scheduledWorkflowRunIdForTime, "scheduledWorkflowRunIdForTime");
2232
2378
  __name2(scheduledWorkflowRunIdForTime, "scheduledWorkflowRunIdForTime");
2379
+ WORKFLOW_SUSPEND_KINDS = [
2380
+ "input",
2381
+ "approval",
2382
+ "signal",
2383
+ "gate"
2384
+ ];
2385
+ WORKFLOW_RUN_NOTIFICATION_SUSPENDED_KINDS = [
2386
+ ...WORKFLOW_SUSPEND_KINDS,
2387
+ ...WORKFLOW_RUN_GATE_KINDS
2388
+ ];
2233
2389
  WORKFLOW_SIGNAL_PAYLOAD_MAX_BYTES = 64 * 1024;
2234
2390
  WORKFLOW_RESOLVE_OUTPUT_MAX_BYTES = 256 * 1024;
2235
2391
  WORKFLOW_RETRY_BACKOFFS = [
@@ -2352,6 +2508,13 @@ This text is who you are for this person. As you learn them, their name, their w
2352
2508
  min: 60,
2353
2509
  max: 2592e3
2354
2510
  });
2511
+ WORKFLOW_GOAL_JUDGE_SELF = "$self";
2512
+ __name(workflowGoalJudgeKind, "workflowGoalJudgeKind");
2513
+ __name2(workflowGoalJudgeKind, "workflowGoalJudgeKind");
2514
+ __name(isWorkflowGoalJudgeComplete, "isWorkflowGoalJudgeComplete");
2515
+ __name2(isWorkflowGoalJudgeComplete, "isWorkflowGoalJudgeComplete");
2516
+ __name(normalizeWorkflowGoalJudge, "normalizeWorkflowGoalJudge");
2517
+ __name2(normalizeWorkflowGoalJudge, "normalizeWorkflowGoalJudge");
2355
2518
  REDACTED_PLACEHOLDER = "[REDACTED]";
2356
2519
  PROVIDER_MESSAGE_MAX_CHARS = 300;
2357
2520
  ERROR_MESSAGE_MAX_CHARS = 2e3;
@@ -2676,10 +2839,71 @@ listed here; never invent a target.`;
2676
2839
  __name2(effectiveFeatureActive, "effectiveFeatureActive");
2677
2840
  __name(resolveEffectiveFeature, "resolveEffectiveFeature");
2678
2841
  __name2(resolveEffectiveFeature, "resolveEffectiveFeature");
2679
- __name(isFeatureRow, "isFeatureRow");
2680
- __name2(isFeatureRow, "isFeatureRow");
2842
+ __name(asFeatureRow, "asFeatureRow");
2843
+ __name2(asFeatureRow, "asFeatureRow");
2844
+ __name(agentFeatureBagCarries, "agentFeatureBagCarries");
2845
+ __name2(agentFeatureBagCarries, "agentFeatureBagCarries");
2681
2846
  __name(effectiveAgentFeatureRows, "effectiveAgentFeatureRows");
2682
2847
  __name2(effectiveAgentFeatureRows, "effectiveAgentFeatureRows");
2848
+ SUBAGENT_PER_KEY_FLAG_ENV = "LUA_SUBAGENT_FEATURES_PER_KEY";
2849
+ PER_KEY_FLAG_VALUES = /* @__PURE__ */ new Set([
2850
+ "1",
2851
+ "true",
2852
+ "on",
2853
+ "yes"
2854
+ ]);
2855
+ __name(agentFeatureMergeRuleFromEnv, "agentFeatureMergeRuleFromEnv");
2856
+ __name2(agentFeatureMergeRuleFromEnv, "agentFeatureMergeRuleFromEnv");
2857
+ __name(effectiveAgentFeatures, "effectiveAgentFeatures");
2858
+ __name2(effectiveAgentFeatures, "effectiveAgentFeatures");
2859
+ }
2860
+ });
2861
+
2862
+ // ../shared-types/dist/workflow-job-tools.mjs
2863
+ function effectiveJobTools(jobTools, readOnly) {
2864
+ const base = jobTools?.length ? jobTools : WORKFLOW_JOB_DEFAULT_TOOLS;
2865
+ const out = [];
2866
+ for (const id of base) {
2867
+ if (readOnly && WORKFLOW_JOB_READ_ONLY_DROPPED.includes(id)) continue;
2868
+ if (!out.includes(id)) out.push(id);
2869
+ }
2870
+ return out;
2871
+ }
2872
+ var __defProp3, __name3, WORKFLOW_JOB_TOOLS, WORKFLOW_JOB_READ_ONLY_DROPPED, WORKFLOW_JOB_DEFAULT_TOOLS;
2873
+ var init_workflow_job_tools = __esm({
2874
+ "../shared-types/dist/workflow-job-tools.mjs"() {
2875
+ "use strict";
2876
+ __defProp3 = Object.defineProperty;
2877
+ __name3 = /* @__PURE__ */ __name((target, value3) => __defProp3(target, "name", { value: value3, configurable: true }), "__name");
2878
+ WORKFLOW_JOB_TOOLS = [
2879
+ "shell",
2880
+ "read",
2881
+ "write",
2882
+ "edit",
2883
+ "glob",
2884
+ "grep",
2885
+ "git",
2886
+ "gh",
2887
+ "fetch",
2888
+ "ripwire"
2889
+ ];
2890
+ WORKFLOW_JOB_READ_ONLY_DROPPED = [
2891
+ "write",
2892
+ "edit",
2893
+ "git",
2894
+ "shell"
2895
+ ];
2896
+ WORKFLOW_JOB_DEFAULT_TOOLS = [
2897
+ "shell",
2898
+ "read",
2899
+ "write",
2900
+ "edit",
2901
+ "glob",
2902
+ "grep",
2903
+ "git"
2904
+ ];
2905
+ __name(effectiveJobTools, "effectiveJobTools");
2906
+ __name3(effectiveJobTools, "effectiveJobTools");
2683
2907
  }
2684
2908
  });
2685
2909
 
@@ -2787,7 +3011,7 @@ function isMapDescriptor(v) {
2787
3011
  if (v === null || typeof v !== "object" || Array.isArray(v)) return false;
2788
3012
  const d = v;
2789
3013
  const keys = Object.keys(d);
2790
- const only = /* @__PURE__ */ __name3((...allowed) => keys.every((k) => allowed.includes(k)), "only");
3014
+ const only = /* @__PURE__ */ __name4((...allowed) => keys.every((k) => allowed.includes(k)), "only");
2791
3015
  if ("value" in d) return keys.length === 1;
2792
3016
  if ("template" in d) return keys.length === 1 && typeof d.template === "string";
2793
3017
  if ("requestContextPath" in d) return keys.length === 1 && typeof d.requestContextPath === "string";
@@ -2890,6 +3114,148 @@ function resolveMapping(cfg, ctx) {
2890
3114
  value: result
2891
3115
  };
2892
3116
  }
3117
+ function looksLikeModelTemplate(model) {
3118
+ return typeof model === "string" && model.includes("${");
3119
+ }
3120
+ function parseModelTemplate(model) {
3121
+ if (!looksLikeModelTemplate(model)) return {
3122
+ kind: "static"
3123
+ };
3124
+ const trimmed = model.trim();
3125
+ const m = WORKFLOW_MODEL_TEMPLATE_RE.exec(trimmed);
3126
+ if (!m) {
3127
+ const inner = /^\$\{([^}]*)\}$/.exec(trimmed)?.[1];
3128
+ const root = inner?.split(/[.|]/, 1)[0];
3129
+ const why = inner !== void 0 && root !== void 0 && root !== WORKFLOW_MODEL_TEMPLATE_ROOT ? `only the \`${WORKFLOW_MODEL_TEMPLATE_ROOT}\` root is allowed (got \`${root || "(empty)"}\`)` : inner !== void 0 && (inner === WORKFLOW_MODEL_TEMPLATE_ROOT || inner.startsWith(`${WORKFLOW_MODEL_TEMPLATE_ROOT}.`)) ? "the path after `initData.` is empty" : "the whole value must be exactly one placeholder \u2014 no prefix, suffix or second placeholder";
3130
+ return {
3131
+ kind: "invalid",
3132
+ message: modelTemplateInvalidMessage(model, why)
3133
+ };
3134
+ }
3135
+ const path3 = m[1];
3136
+ if (!path3.split(".").every((seg) => PATH_SEGMENT_RE.test(seg))) {
3137
+ return {
3138
+ kind: "invalid",
3139
+ message: modelTemplateInvalidMessage(model, `the path \`${path3}\` is not a dotted path of names and canonical [n] indexes`)
3140
+ };
3141
+ }
3142
+ if (m[2] !== void 0) {
3143
+ const dflt = m[2].trim();
3144
+ if (!dflt) return {
3145
+ kind: "invalid",
3146
+ message: modelTemplateInvalidMessage(model, "the default after `|` is empty")
3147
+ };
3148
+ if (dflt.includes("|")) {
3149
+ return {
3150
+ kind: "invalid",
3151
+ message: modelTemplateInvalidMessage(model, "a placeholder names ONE default \u2014 a second `|` is not a fallback chain")
3152
+ };
3153
+ }
3154
+ return {
3155
+ kind: "template",
3156
+ template: {
3157
+ placeholder: trimmed,
3158
+ path: path3,
3159
+ default: dflt
3160
+ }
3161
+ };
3162
+ }
3163
+ return {
3164
+ kind: "template",
3165
+ template: {
3166
+ placeholder: trimmed,
3167
+ path: path3
3168
+ }
3169
+ };
3170
+ }
3171
+ function modelTemplateInvalidMessage(model, why) {
3172
+ return `model "${model.trim()}" is not a valid run-input-bound model placeholder \u2014 ${why}; the forms are \${initData.<path>} and \${initData.<path>|<provider/model default>}`;
3173
+ }
3174
+ function modelTemplateDefaultRequiredMessage(model) {
3175
+ return `model "${model}" runs on the Job tier, so its placeholder needs a default \u2014 the harness / provider gates (harness:'claude-code' needs an Anthropic model) classify it at push; write ${model.replace(/\}$/, "|<provider/model>}")}`;
3176
+ }
3177
+ function staticModelPin(model) {
3178
+ if (typeof model !== "string") return void 0;
3179
+ const parsed = parseModelTemplate(model);
3180
+ if (parsed.kind === "static") return model;
3181
+ if (parsed.kind === "template") return parsed.template.default;
3182
+ return void 0;
3183
+ }
3184
+ function readPath(root, path3) {
3185
+ let cur = root;
3186
+ for (const seg of path3.split(".")) {
3187
+ const name = seg.replace(/\[(?:0|[1-9]\d*)\]/g, "");
3188
+ const indexes = [
3189
+ ...seg.matchAll(/\[(0|[1-9]\d*)\]/g)
3190
+ ].map((x) => Number(x[1]));
3191
+ if (cur === null || typeof cur !== "object") return void 0;
3192
+ cur = cur[name];
3193
+ for (const i of indexes) {
3194
+ if (!Array.isArray(cur)) return void 0;
3195
+ cur = cur[i];
3196
+ }
3197
+ }
3198
+ return cur;
3199
+ }
3200
+ function renderModelTemplate(model, initData) {
3201
+ if (model === void 0 || !looksLikeModelTemplate(model)) return {
3202
+ ok: true,
3203
+ model,
3204
+ source: "static"
3205
+ };
3206
+ const parsed = parseModelTemplate(model);
3207
+ if (parsed.kind === "invalid") {
3208
+ return {
3209
+ ok: false,
3210
+ placeholder: model.trim(),
3211
+ path: "",
3212
+ reason: "invalid",
3213
+ message: parsed.message
3214
+ };
3215
+ }
3216
+ if (parsed.kind === "static") return {
3217
+ ok: true,
3218
+ model,
3219
+ source: "static"
3220
+ };
3221
+ const { placeholder, path: path3 } = parsed.template;
3222
+ if (initData !== void 0 && initData !== null && (typeof initData !== "object" || Array.isArray(initData))) {
3223
+ return {
3224
+ ok: false,
3225
+ placeholder,
3226
+ path: path3,
3227
+ reason: "input-not-object",
3228
+ message: modelTemplateInputNotObjectMessage(placeholder, initData)
3229
+ };
3230
+ }
3231
+ const value22 = readPath(initData, path3);
3232
+ const reason = value22 === void 0 || value22 === null ? "unbound" : typeof value22 !== "string" ? "not-a-string" : value22.trim() ? null : "empty";
3233
+ if (reason === null) return {
3234
+ ok: true,
3235
+ model: value22.trim(),
3236
+ source: "initData"
3237
+ };
3238
+ if (parsed.template.default !== void 0) return {
3239
+ ok: true,
3240
+ model: parsed.template.default,
3241
+ source: "default"
3242
+ };
3243
+ return {
3244
+ ok: false,
3245
+ placeholder,
3246
+ path: path3,
3247
+ reason,
3248
+ message: modelTemplateUnboundMessage(placeholder, path3, reason)
3249
+ };
3250
+ }
3251
+ function modelTemplateUnboundMessage(placeholder, path3, reason) {
3252
+ const what = reason === "unbound" ? `the run input has no ${WORKFLOW_MODEL_TEMPLATE_ROOT}.${path3}` : reason === "empty" ? `${WORKFLOW_MODEL_TEMPLATE_ROOT}.${path3} is empty on the run input` : `${WORKFLOW_MODEL_TEMPLATE_ROOT}.${path3} on the run input is not a string`;
3253
+ return `model placeholder "${placeholder}" is unbound \u2014 ${what} and the placeholder declares no default; pass one in the run input or write \${${WORKFLOW_MODEL_TEMPLATE_ROOT}.${path3}|<provider/model>}`;
3254
+ }
3255
+ function modelTemplateInputNotObjectMessage(placeholder, initData) {
3256
+ const type = Array.isArray(initData) ? "an array" : `a ${typeof initData}`;
3257
+ return `model placeholder "${placeholder}" cannot be rendered \u2014 the run input is ${type}, not an object; start the run with an object input (a JSON string must be parsed before it is passed)`;
3258
+ }
2893
3259
  function describeApproverSpecRefusal(spec) {
2894
3260
  const raw = spec === void 0 ? "undefined" : JSON.stringify(spec) ?? String(spec);
2895
3261
  const written = raw.length > APPROVER_WRITTEN_MAX ? `${raw.slice(0, APPROVER_WRITTEN_MAX - 1)}\u2026` : raw;
@@ -2924,13 +3290,13 @@ function validateApproverBlock(node, opts = {
2924
3290
  path: "approval"
2925
3291
  }) {
2926
3292
  const issues = [];
2927
- const push = /* @__PURE__ */ __name3((code, path3, message, severity = "error") => issues.push({
3293
+ const push = /* @__PURE__ */ __name4((code, path3, message, severity = "error") => issues.push({
2928
3294
  code,
2929
3295
  path: path3,
2930
3296
  severity,
2931
3297
  message
2932
3298
  }), "push");
2933
- const checkSpec = /* @__PURE__ */ __name3((spec, path3) => {
3299
+ const checkSpec = /* @__PURE__ */ __name4((spec, path3) => {
2934
3300
  const r = ApproverSpecSchema.safeParse(spec);
2935
3301
  if (!r.success) {
2936
3302
  const users = spec?.users;
@@ -3214,7 +3580,7 @@ function validateLuaExtensions(g, caps = WORKFLOW_CAPS_DEFAULT, opts = {
3214
3580
  static: true
3215
3581
  }) {
3216
3582
  const issues = [];
3217
- const err = /* @__PURE__ */ __name3((code, message, path3, stepId) => {
3583
+ const err = /* @__PURE__ */ __name4((code, message, path3, stepId) => {
3218
3584
  issues.push({
3219
3585
  code,
3220
3586
  message,
@@ -3223,7 +3589,7 @@ function validateLuaExtensions(g, caps = WORKFLOW_CAPS_DEFAULT, opts = {
3223
3589
  stepId
3224
3590
  });
3225
3591
  }, "err");
3226
- const warn = /* @__PURE__ */ __name3((code, message, path3, stepId) => {
3592
+ const warn = /* @__PURE__ */ __name4((code, message, path3, stepId) => {
3227
3593
  issues.push({
3228
3594
  code,
3229
3595
  message,
@@ -3259,6 +3625,7 @@ function validateLuaExtensions(g, caps = WORKFLOW_CAPS_DEFAULT, opts = {
3259
3625
  }
3260
3626
  }
3261
3627
  const declaredKeys = new Set(opts.connectionKeys ?? []);
3628
+ const ownKeys = /* @__PURE__ */ new Set();
3262
3629
  if (g.connections !== void 0 && !Array.isArray(g.connections)) {
3263
3630
  err("connection-declaration-invalid", "`connections` must be an array of { key, integrationType }", "connections");
3264
3631
  }
@@ -3270,7 +3637,7 @@ function validateLuaExtensions(g, caps = WORKFLOW_CAPS_DEFAULT, opts = {
3270
3637
  err("connection-declaration-invalid", `connections[${i}].key must match ${WORKFLOW_CONNECTION_KEY_RE}`, `${path3}.key`);
3271
3638
  return;
3272
3639
  }
3273
- if (declaredKeys.has(key)) {
3640
+ if (ownKeys.has(key)) {
3274
3641
  err("connection-declaration-invalid", `connections[${i}].key "${key}" is declared twice`, `${path3}.key`);
3275
3642
  return;
3276
3643
  }
@@ -3278,9 +3645,10 @@ function validateLuaExtensions(g, caps = WORKFLOW_CAPS_DEFAULT, opts = {
3278
3645
  err("connection-declaration-invalid", `connections[${i}] ("${key}") needs an integrationType (the catalog slug, e.g. 'github')`, `${path3}.integrationType`);
3279
3646
  return;
3280
3647
  }
3648
+ ownKeys.add(key);
3281
3649
  declaredKeys.add(key);
3282
3650
  });
3283
- const undeclaredKey = /* @__PURE__ */ __name3((ref) => typeof ref === "string" && !declaredKeys.has(ref) && isConnectionKeyShaped(ref) && opts.connectionIds?.has(ref) !== true, "undeclaredKey");
3651
+ const undeclaredKey = /* @__PURE__ */ __name4((ref) => typeof ref === "string" && !declaredKeys.has(ref) && isConnectionKeyShaped(ref) && opts.connectionIds?.has(ref) !== true, "undeclaredKey");
3284
3652
  const credentialsRef = envelopeWorkspace?.credentialsRef;
3285
3653
  if (undeclaredKey(credentialsRef)) {
3286
3654
  err("connection-key-undeclared", connectionKeyUndeclaredMessage("workspace.credentialsRef", credentialsRef), "workspace.credentialsRef");
@@ -3288,7 +3656,7 @@ function validateLuaExtensions(g, caps = WORKFLOW_CAPS_DEFAULT, opts = {
3288
3656
  const seen = /* @__PURE__ */ new Map();
3289
3657
  let nodeCount = 0;
3290
3658
  const upstream = /* @__PURE__ */ new Set();
3291
- const checkId = /* @__PURE__ */ __name3((id, path3) => {
3659
+ const checkId = /* @__PURE__ */ __name4((id, path3) => {
3292
3660
  nodeCount += 1;
3293
3661
  if (seen.has(id)) {
3294
3662
  err("duplicate-step-id", `step id "${id}" is declared twice (first at ${seen.get(id)})`, path3, id);
@@ -3296,9 +3664,9 @@ function validateLuaExtensions(g, caps = WORKFLOW_CAPS_DEFAULT, opts = {
3296
3664
  seen.set(id, path3);
3297
3665
  }
3298
3666
  }, "checkId");
3299
- const checkPolicyEnums = /* @__PURE__ */ __name3((node, path3) => {
3667
+ const checkPolicyEnums = /* @__PURE__ */ __name4((node, path3) => {
3300
3668
  const id = singleId(node);
3301
- const check = /* @__PURE__ */ __name3((member, allowed) => {
3669
+ const check = /* @__PURE__ */ __name4((member, allowed) => {
3302
3670
  const value22 = node[member];
3303
3671
  if (value22 === void 0 || typeof value22 === "string" && allowed.includes(value22)) return;
3304
3672
  err("invalid-envelope", `\`${member}\` must be ${allowed.map((a) => `'${a}'`).join(" | ")} (got ${JSON.stringify(value22)})`, `${path3}.${member}`, id);
@@ -3306,7 +3674,7 @@ function validateLuaExtensions(g, caps = WORKFLOW_CAPS_DEFAULT, opts = {
3306
3674
  check("sideEffects", WORKFLOW_SIDE_EFFECTS);
3307
3675
  check("jobResources", WORKFLOW_JOB_RESOURCES);
3308
3676
  }, "checkPolicyEnums");
3309
- const checkRetry = /* @__PURE__ */ __name3((node, path3) => {
3677
+ const checkRetry = /* @__PURE__ */ __name4((node, path3) => {
3310
3678
  const r = node.retry;
3311
3679
  if (!r) return;
3312
3680
  const id = singleId(node);
@@ -3332,7 +3700,7 @@ function validateLuaExtensions(g, caps = WORKFLOW_CAPS_DEFAULT, opts = {
3332
3700
  }
3333
3701
  }
3334
3702
  }, "checkRetry");
3335
- const checkTimeout = /* @__PURE__ */ __name3((node, path3) => {
3703
+ const checkTimeout = /* @__PURE__ */ __name4((node, path3) => {
3336
3704
  const t = node.timeoutSeconds;
3337
3705
  if (t === void 0) return;
3338
3706
  const id = singleId(node);
@@ -3351,7 +3719,7 @@ function validateLuaExtensions(g, caps = WORKFLOW_CAPS_DEFAULT, opts = {
3351
3719
  err("timeout-exceeds-tier", `timeoutSeconds ${t} exceeds the worker tier's ${caps.maxWorkerTimeoutSeconds} s \u2014 steps longer than 10 min run on the Job tier: add tier:'job' (up to ${caps.maxJobSegmentSeconds} s)`, `${path3}.timeoutSeconds`, id);
3352
3720
  }
3353
3721
  }, "checkTimeout");
3354
- const checkSpecialistRole = /* @__PURE__ */ __name3((node, path3) => {
3722
+ const checkSpecialistRole = /* @__PURE__ */ __name4((node, path3) => {
3355
3723
  const role = node.role;
3356
3724
  const hasRef = typeof role.ref === "string";
3357
3725
  const hasInline = role.name !== void 0 || role.instructions !== void 0 || Array.isArray(role.tools) && role.tools.length > 0;
@@ -3383,7 +3751,7 @@ function validateLuaExtensions(g, caps = WORKFLOW_CAPS_DEFAULT, opts = {
3383
3751
  }
3384
3752
  }
3385
3753
  }, "checkSpecialistRole");
3386
- const checkRequiredConnections = /* @__PURE__ */ __name3((node, path3) => {
3754
+ const checkRequiredConnections = /* @__PURE__ */ __name4((node, path3) => {
3387
3755
  const required = node.requiredConnections;
3388
3756
  if (!Array.isArray(required)) return;
3389
3757
  const undeclared = required.filter(undeclaredKey);
@@ -3396,7 +3764,7 @@ function validateLuaExtensions(g, caps = WORKFLOW_CAPS_DEFAULT, opts = {
3396
3764
  err("required-connection-unknown", `requiredConnections ${JSON.stringify(unknown)} are neither declared connections[].key values nor connections the owner can mount`, `${path3}.requiredConnections`, singleId(node));
3397
3765
  }
3398
3766
  }, "checkRequiredConnections");
3399
- const checkTier = /* @__PURE__ */ __name3((node, path3) => {
3767
+ const checkTier = /* @__PURE__ */ __name4((node, path3) => {
3400
3768
  const id = singleId(node);
3401
3769
  if (node.workspace && node.workspace !== "inherit" && node.tier !== void 0 && node.tier !== "job") {
3402
3770
  err("workspace-requires-job-tier", "a step mounting a workspace must be tier:'job'", `${path3}.workspace`, id);
@@ -3404,7 +3772,7 @@ function validateLuaExtensions(g, caps = WORKFLOW_CAPS_DEFAULT, opts = {
3404
3772
  if (node.harness !== void 0 && node.tier !== "job") {
3405
3773
  err("harness-requires-job-tier", "`harness` is only legal on a tier:'job' agent step", `${path3}.harness`, id);
3406
3774
  }
3407
- const provider = node.type === "agent" ? classifyModelProvider(node.model) : null;
3775
+ const provider = node.type === "agent" ? classifyModelProvider(staticModelPin(node.model)) : null;
3408
3776
  if (node.harness === "claude-code" && provider !== null && provider !== "anthropic") {
3409
3777
  err("harness-provider-mismatch", `harness:'claude-code' needs an Anthropic model (model "${node.type === "agent" ? node.model : ""}" is ${provider})`, `${path3}.harness`, id);
3410
3778
  }
@@ -3412,22 +3780,36 @@ function validateLuaExtensions(g, caps = WORKFLOW_CAPS_DEFAULT, opts = {
3412
3780
  err("job-tier-provider-unsupported", `model provider '${provider}' is outside LUA_WF_JOB_PROVIDERS [${opts.policy.jobProviders.join(", ")}]`, `${path3}.model`, id);
3413
3781
  }
3414
3782
  }, "checkTier");
3415
- const checkModel = /* @__PURE__ */ __name3((node, path3) => {
3783
+ const checkModel = /* @__PURE__ */ __name4((node, path3) => {
3416
3784
  if (node.type !== "agent" || typeof node.model !== "string") return;
3785
+ const id = singleId(node);
3786
+ const parsed = parseModelTemplate(node.model);
3787
+ if (parsed.kind === "invalid") {
3788
+ err("model-template-invalid", parsed.message, `${path3}.model`, id);
3789
+ return;
3790
+ }
3791
+ if (parsed.kind === "template" && parsed.template.default === void 0) {
3792
+ if (isJobTier(node)) {
3793
+ err("model-template-default-required", modelTemplateDefaultRequiredMessage(node.model), `${path3}.model`, id);
3794
+ }
3795
+ return;
3796
+ }
3797
+ const pin = parsed.kind === "template" ? parsed.template.default : node.model;
3798
+ if (pin === void 0) return;
3799
+ const inContext = /* @__PURE__ */ __name4((message) => parsed.kind === "template" ? `${message} (the default of ${parsed.template.placeholder})` : message, "inContext");
3417
3800
  const registry = opts.approvedModels;
3418
3801
  if (registry === void 0) return;
3419
- const id = singleId(node);
3420
3802
  if (registry === "unavailable") {
3421
- const pin = node.model.trim();
3422
- if (pin && !normalizeModelId(pin, []).ok) {
3423
- 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);
3803
+ const trimmed = pin.trim();
3804
+ if (trimmed && !normalizeModelId(trimmed, []).ok) {
3805
+ warn("model-unresolved", inContext(`model "${trimmed}" 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);
3424
3806
  }
3425
3807
  return;
3426
3808
  }
3427
- const resolved = normalizeModelId(node.model, registry);
3428
- if (!resolved.ok) err("model-unresolved", modelUnresolvedMessage(resolved), `${path3}.model`, id);
3809
+ const resolved = normalizeModelId(pin, registry);
3810
+ if (!resolved.ok) err("model-unresolved", inContext(modelUnresolvedMessage(resolved)), `${path3}.model`, id);
3429
3811
  }, "checkModel");
3430
- const checkWorkspace = /* @__PURE__ */ __name3((node, path3) => {
3812
+ const checkWorkspace = /* @__PURE__ */ __name4((node, path3) => {
3431
3813
  const id = singleId(node);
3432
3814
  const ws = workspaceOf(node);
3433
3815
  if (isJobTier(node) && opts.policy && opts.policy.jobTier !== true) {
@@ -3450,6 +3832,9 @@ function validateLuaExtensions(g, caps = WORKFLOW_CAPS_DEFAULT, opts = {
3450
3832
  warn("gh-on-coding-turn", `"${id}" grants the gh tool on a coding turn \u2014 the pod can open/merge PRs on the workspace repo (purpose:'gh' token, pull_requests:write + contents:write)`, `${path3}.jobTools`, id);
3451
3833
  }
3452
3834
  }
3835
+ if (node.type === "agent" && ws && ws !== "inherit" && ws.mount === "ro" && Array.isArray(tools) && effectiveJobTools(tools, true).length === 0) {
3836
+ warn("ro-step-has-no-tools", `"${id}" mounts the workspace read-only and every jobTool it declares (${JSON.stringify(tools)}) is one the ro mount drops [${WORKFLOW_JOB_READ_ONLY_DROPPED.join(", ")}] \u2014 the coding turn would run with no tools at all; keep a read-only tool (read/glob/grep, gh) or mount rw`, `${path3}.jobTools`, id);
3837
+ }
3453
3838
  if (ws && ws !== "inherit") {
3454
3839
  if (!envelopeWorkspace && !opts.mayInherit) {
3455
3840
  err("workspace-not-declared", `"${id}" mounts a workspace but the workflow declares none \u2014 add workspace:{kind, \u2026} on createWorkflow`, `${path3}.workspace`, id);
@@ -3469,16 +3854,16 @@ function validateLuaExtensions(g, caps = WORKFLOW_CAPS_DEFAULT, opts = {
3469
3854
  }
3470
3855
  }, "checkWorkspace");
3471
3856
  const outputSchemas = /* @__PURE__ */ new Map();
3472
- const recordOutputSchema = /* @__PURE__ */ __name3((node) => {
3857
+ const recordOutputSchema = /* @__PURE__ */ __name4((node) => {
3473
3858
  const schema = node.type === "step" ? node.step.outputSchema : node.type === "agent" ? node.outputSchema : void 0;
3474
3859
  if (schema !== void 0) outputSchemas.set(singleId(node), schema);
3475
3860
  }, "recordOutputSchema");
3476
- const checkMapMembers = /* @__PURE__ */ __name3((cfg, basePath, id) => {
3861
+ const checkMapMembers = /* @__PURE__ */ __name4((cfg, basePath, id) => {
3477
3862
  for (const m of malformedMapMembers(cfg)) {
3478
3863
  warn(MAP_MEMBER_MALFORMED_CODE, mapMemberMalformedMessage(id, m), `${basePath}.${m.member}`, id);
3479
3864
  }
3480
3865
  }, "checkMapMembers");
3481
- const checkInputShape = /* @__PURE__ */ __name3((node, path3) => {
3866
+ const checkInputShape = /* @__PURE__ */ __name4((node, path3) => {
3482
3867
  const input = node.input;
3483
3868
  if (input === void 0) return;
3484
3869
  const id = singleId(node);
@@ -3488,11 +3873,11 @@ function validateLuaExtensions(g, caps = WORKFLOW_CAPS_DEFAULT, opts = {
3488
3873
  }
3489
3874
  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);
3490
3875
  }, "checkInputShape");
3491
- const checkBodyInput = /* @__PURE__ */ __name3((body, path3, container) => {
3876
+ const checkBodyInput = /* @__PURE__ */ __name4((body, path3, container) => {
3492
3877
  if (body.type === "workflow" || body.input === void 0) return;
3493
3878
  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));
3494
3879
  }, "checkBodyInput");
3495
- const checkSingle = /* @__PURE__ */ __name3((node, path3, depth) => {
3880
+ const checkSingle = /* @__PURE__ */ __name4((node, path3, depth) => {
3496
3881
  recordOutputSchema(node);
3497
3882
  if (node.type === "workflow" && (typeof node.workflowId !== "string" || node.workflowId.length === 0)) {
3498
3883
  checkId(node.id, path3);
@@ -3541,7 +3926,7 @@ function validateLuaExtensions(g, caps = WORKFLOW_CAPS_DEFAULT, opts = {
3541
3926
  }
3542
3927
  }
3543
3928
  }, "checkSingle");
3544
- const checkHitl = /* @__PURE__ */ __name3((node, path3) => {
3929
+ const checkHitl = /* @__PURE__ */ __name4((node, path3) => {
3545
3930
  if (node.type === "waitForSignal") {
3546
3931
  const w = node;
3547
3932
  checkId(w.id, path3);
@@ -3580,7 +3965,7 @@ function validateLuaExtensions(g, caps = WORKFLOW_CAPS_DEFAULT, opts = {
3580
3965
  }
3581
3966
  }
3582
3967
  }, "checkHitl");
3583
- const checkHitlArm = /* @__PURE__ */ __name3((node, path3, container) => {
3968
+ const checkHitlArm = /* @__PURE__ */ __name4((node, path3, container) => {
3584
3969
  if (!workflowContainerRunsHitlArm(container)) {
3585
3970
  checkId(node.id, path3);
3586
3971
  err("node-type-unsupported-in-container", workflowHitlArmUnsupportedMessage(node.type, node.id, container), path3, node.id);
@@ -3588,7 +3973,7 @@ function validateLuaExtensions(g, caps = WORKFLOW_CAPS_DEFAULT, opts = {
3588
3973
  }
3589
3974
  checkHitl(node, path3);
3590
3975
  }, "checkHitlArm");
3591
- const checkArm = /* @__PURE__ */ __name3((arm, path3, depth, container) => {
3976
+ const checkArm = /* @__PURE__ */ __name4((arm, path3, depth, container) => {
3592
3977
  if (arm.type === "mapping") {
3593
3978
  checkId(arm.id, path3);
3594
3979
  checkMapMembers(readMapConfig(arm.mapConfig), `${path3}.mapConfig`, arm.id);
@@ -3824,7 +4209,7 @@ function isWellFormedPredicate(p) {
3824
4209
  }
3825
4210
  function canonicalJson(value22) {
3826
4211
  const seen = /* @__PURE__ */ new WeakSet();
3827
- const encode = /* @__PURE__ */ __name3((v) => {
4212
+ const encode = /* @__PURE__ */ __name4((v) => {
3828
4213
  if (v === null || typeof v === "number" || typeof v === "boolean") return JSON.stringify(v);
3829
4214
  if (typeof v === "string") return JSON.stringify(v);
3830
4215
  if (typeof v === "bigint") return JSON.stringify(`${v}n`);
@@ -3851,7 +4236,7 @@ function hashGraph(g) {
3851
4236
  function compilePlan(g) {
3852
4237
  const steps = {};
3853
4238
  const order = [];
3854
- const addNode = /* @__PURE__ */ __name3((id, node) => {
4239
+ const addNode = /* @__PURE__ */ __name4((id, node) => {
3855
4240
  if (id in steps) {
3856
4241
  throw new WorkflowPlanError("duplicate-step-id", `Duplicate step id "${id}" in definition.graph`);
3857
4242
  }
@@ -4181,7 +4566,7 @@ function renderRef(ref) {
4181
4566
  function step(s) {
4182
4567
  const id = stepIdOf(s);
4183
4568
  return {
4184
- path: /* @__PURE__ */ __name3((p) => ({
4569
+ path: /* @__PURE__ */ __name4((p) => ({
4185
4570
  path: p === "" ? `stepResults.${id}` : `stepResults.${id}.${p}`
4186
4571
  }), "path")
4187
4572
  };
@@ -4269,7 +4654,7 @@ function resolvePlacements(calls) {
4269
4654
  const declared = /* @__PURE__ */ new Map();
4270
4655
  const placedBy = /* @__PURE__ */ new Map();
4271
4656
  const allIds = /* @__PURE__ */ new Map();
4272
- const claimId = /* @__PURE__ */ __name3((id, callIndex) => {
4657
+ const claimId = /* @__PURE__ */ __name4((id, callIndex) => {
4273
4658
  const first = allIds.get(id);
4274
4659
  if (first !== void 0 && first !== callIndex) {
4275
4660
  issues.push({
@@ -4309,7 +4694,7 @@ function resolvePlacements(calls) {
4309
4694
  break;
4310
4695
  }
4311
4696
  });
4312
- const armMapPlacementIssue = /* @__PURE__ */ __name3((node, ref, i, container) => {
4697
+ const armMapPlacementIssue = /* @__PURE__ */ __name4((node, ref, i, container) => {
4313
4698
  if (!ref.armMap || node.type === "mapping" || isHitlNode2(node)) return void 0;
4314
4699
  const id = nodeIdOf(node);
4315
4700
  if ((container === "foreach" || container === "loop") && node.type !== "workflow") {
@@ -4330,7 +4715,7 @@ function resolvePlacements(calls) {
4330
4715
  }
4331
4716
  return void 0;
4332
4717
  }, "armMapPlacementIssue");
4333
- const hitlPlacementIssue = /* @__PURE__ */ __name3((node, ref, i, container) => {
4718
+ const hitlPlacementIssue = /* @__PURE__ */ __name4((node, ref, i, container) => {
4334
4719
  if (!isHitlNode2(node)) return void 0;
4335
4720
  const id = node.id;
4336
4721
  if (ref.armMap) {
@@ -4351,7 +4736,7 @@ function resolvePlacements(calls) {
4351
4736
  }
4352
4737
  return void 0;
4353
4738
  }, "hitlPlacementIssue");
4354
- const resolve3 = /* @__PURE__ */ __name3((ref, i, allowMapping, container) => {
4739
+ const resolve3 = /* @__PURE__ */ __name4((ref, i, allowMapping, container) => {
4355
4740
  if ("node" in ref) {
4356
4741
  if (ref.node.type === "mapping" && !allowMapping) {
4357
4742
  issues.push({
@@ -4406,7 +4791,7 @@ function resolvePlacements(calls) {
4406
4791
  placedBy.set(ref.ref, i);
4407
4792
  return d.node;
4408
4793
  }, "resolve");
4409
- const claim = /* @__PURE__ */ __name3((ref, i, allowMapping, container) => {
4794
+ const claim = /* @__PURE__ */ __name4((ref, i, allowMapping, container) => {
4410
4795
  if ("ref" in ref) {
4411
4796
  resolve3(ref, i, allowMapping, container);
4412
4797
  return;
@@ -4441,7 +4826,7 @@ function resolvePlacements(calls) {
4441
4826
  }
4442
4827
  });
4443
4828
  const graph = [];
4444
- const lookup = /* @__PURE__ */ __name3((ref) => {
4829
+ const lookup = /* @__PURE__ */ __name4((ref) => {
4445
4830
  const n2 = "node" in ref ? ref.node : declared.get(ref.ref)?.node;
4446
4831
  if (!n2 || !ref.armMap || n2.type === "mapping" || isHitlNode2(n2)) return n2;
4447
4832
  return inlineContainerArm(ref.armMap, n2);
@@ -4584,11 +4969,11 @@ function seedLedgerFromRun(run, steps, targetPlan, opts = {}) {
4584
4969
  const seeded = [];
4585
4970
  const unseeded = [];
4586
4971
  const known = new Set(Object.keys(targetPlan.steps));
4587
- const parentOf = /* @__PURE__ */ __name3((id) => {
4972
+ const parentOf = /* @__PURE__ */ __name4((id) => {
4588
4973
  const m = /^(.*)(\[\d+\]|#\d+)$/.exec(id);
4589
4974
  return m ? m[1] : void 0;
4590
4975
  }, "parentOf");
4591
- const dependsOf = /* @__PURE__ */ __name3((id) => {
4976
+ const dependsOf = /* @__PURE__ */ __name4((id) => {
4592
4977
  const node = targetPlan.steps[id];
4593
4978
  if (node) return node.dependsOn;
4594
4979
  const parent = parentOf(id);
@@ -4675,7 +5060,7 @@ function replayLedger(g, ledger) {
4675
5060
  startedAt: 0,
4676
5061
  ...ledger.requestContext
4677
5062
  };
4678
- const ctxFor = /* @__PURE__ */ __name3((id) => ({
5063
+ const ctxFor = /* @__PURE__ */ __name4((id) => ({
4679
5064
  initData: ledger.initData,
4680
5065
  stepResults: ancestorResults(plan, id, rows22),
4681
5066
  state: ledger.state ?? {},
@@ -4757,7 +5142,7 @@ function ancestorResults(plan, id, rows22) {
4757
5142
  const out = {};
4758
5143
  const joinAliased = /* @__PURE__ */ new Set();
4759
5144
  const seen = /* @__PURE__ */ new Set();
4760
- const take = /* @__PURE__ */ __name3((rowId) => {
5145
+ const take = /* @__PURE__ */ __name4((rowId) => {
4761
5146
  const hit = replayResultOf(rows22.get(rowId), plan.steps[rowId]);
4762
5147
  if (!hit) return void 0;
4763
5148
  if (!joinAliased.has(rowId)) out[rowId] = hit.value;
@@ -4774,7 +5159,7 @@ function ancestorResults(plan, id, rows22) {
4774
5159
  }
4775
5160
  return hit;
4776
5161
  }, "take");
4777
- const walk22 = /* @__PURE__ */ __name3((ids) => {
5162
+ const walk22 = /* @__PURE__ */ __name4((ids) => {
4778
5163
  for (const dep of ids) {
4779
5164
  if (seen.has(dep)) continue;
4780
5165
  seen.add(dep);
@@ -5128,7 +5513,7 @@ function timeZoneSupported(tz) {
5128
5513
  }
5129
5514
  function validateBusinessHours(cal, path3 = "businessHours") {
5130
5515
  const issues = [];
5131
- const issue = /* @__PURE__ */ __name3((p, message) => issues.push({
5516
+ const issue = /* @__PURE__ */ __name4((p, message) => issues.push({
5132
5517
  code: "business-hours-invalid",
5133
5518
  path: p,
5134
5519
  message
@@ -5197,7 +5582,7 @@ function formatter(tz) {
5197
5582
  }
5198
5583
  function localParts(ms, tz) {
5199
5584
  const parts = formatter(tz).formatToParts(new Date(ms));
5200
- const get = /* @__PURE__ */ __name3((t) => parts.find((p) => p.type === t)?.value ?? "", "get");
5585
+ const get = /* @__PURE__ */ __name4((t) => parts.find((p) => p.type === t)?.value ?? "", "get");
5201
5586
  const hour = Number(get("hour")) % 24;
5202
5587
  return {
5203
5588
  year: Number(get("year")),
@@ -5367,7 +5752,7 @@ function matchesEditablePath(pointer, editablePaths, op = "replace") {
5367
5752
  }
5368
5753
  function changedPointers(before, after, base = "") {
5369
5754
  if (before === after) return [];
5370
- const isObj = /* @__PURE__ */ __name3((v) => typeof v === "object" && v !== null && !Array.isArray(v), "isObj");
5755
+ const isObj = /* @__PURE__ */ __name4((v) => typeof v === "object" && v !== null && !Array.isArray(v), "isObj");
5371
5756
  if (Array.isArray(before) && Array.isArray(after)) {
5372
5757
  if (before.length !== after.length) return [
5373
5758
  base || "/"
@@ -5575,7 +5960,7 @@ function rebaseItemPointer(pointer, itemsPath, index) {
5575
5960
  }
5576
5961
  function validateWorkflowSchedule(schedule, path3 = "/schedule") {
5577
5962
  if (schedule === void 0 || schedule === null) return [];
5578
- const issue = /* @__PURE__ */ __name3((at, detail) => [
5963
+ const issue = /* @__PURE__ */ __name4((at, detail) => [
5579
5964
  {
5580
5965
  code: WORKFLOW_SCHEDULE_SHAPE_ISSUE,
5581
5966
  severity: "error",
@@ -5595,6 +5980,9 @@ function validateWorkflowSchedule(schedule, path3 = "/schedule") {
5595
5980
  if (typeof type !== "string" || !WORKFLOW_SCHEDULE_TYPES.includes(type)) {
5596
5981
  return issue(path3, `\`schedule.type\` ${JSON.stringify(type)} is not one of ${WORKFLOW_SCHEDULE_TYPES.map((t) => `'${t}'`).join(" | ")}`);
5597
5982
  }
5983
+ if (schedule.runAs !== void 0 && !WORKFLOW_SCHEDULE_RUN_AS.includes(schedule.runAs)) {
5984
+ return issue(`${path3}/runAs`, `\`schedule.runAs\` ${JSON.stringify(schedule.runAs)} is not one of ${WORKFLOW_SCHEDULE_RUN_AS.map((v) => `'${v}'`).join(" | ")}`);
5985
+ }
5598
5986
  switch (type) {
5599
5987
  case "cron": {
5600
5988
  if (typeof schedule.expression !== "string" || schedule.expression.trim().length === 0) {
@@ -5622,7 +6010,7 @@ function validateWorkflowSchedule(schedule, path3 = "/schedule") {
5622
6010
  }
5623
6011
  function collectEnvTemplateKeys(value22) {
5624
6012
  const keys = /* @__PURE__ */ new Set();
5625
- const walk22 = /* @__PURE__ */ __name3((v) => {
6013
+ const walk22 = /* @__PURE__ */ __name4((v) => {
5626
6014
  if (isEnvRef(v)) {
5627
6015
  keys.add(v.__envRef);
5628
6016
  return;
@@ -5649,7 +6037,7 @@ function collectEnvTemplateKeys(value22) {
5649
6037
  }
5650
6038
  function substituteEnvRefs(value22, overlay) {
5651
6039
  const missing = /* @__PURE__ */ new Set();
5652
- const walk22 = /* @__PURE__ */ __name3((v, slot = false) => {
6040
+ const walk22 = /* @__PURE__ */ __name4((v, slot = false) => {
5653
6041
  if (isEnvRef(v)) {
5654
6042
  if (Object.prototype.hasOwnProperty.call(overlay, v.__envRef)) {
5655
6043
  const s = overlay[v.__envRef];
@@ -5909,25 +6297,57 @@ function needsInheritedWorkspace(graph) {
5909
6297
  }
5910
6298
  return false;
5911
6299
  }
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;
6300
+ function armEntry2(arm) {
6301
+ return Array.isArray(arm) ? arm[arm.length - 1] : arm;
6302
+ }
6303
+ function entryHasJobTier(entry) {
6304
+ const n2 = armEntry2(entry);
6305
+ if (!n2 || typeof n2 !== "object") return false;
6306
+ const node = n2;
6307
+ if (node.tier === "job") return true;
6308
+ const ws = node.workspace;
6309
+ if (ws !== void 0 && ws !== "inherit") return true;
6310
+ switch (node.type) {
6311
+ case "parallel":
6312
+ return Array.isArray(node.steps) && node.steps.some(entryHasJobTier);
6313
+ case "conditional":
6314
+ return Array.isArray(node.steps) && node.steps.some(entryHasJobTier) || node.otherwise !== void 0 && entryHasJobTier(node.otherwise);
6315
+ case "foreach":
6316
+ case "loop":
6317
+ return entryHasJobTier(node.step);
6318
+ default:
6319
+ return false;
6320
+ }
6321
+ }
6322
+ function graphHasJobTierStep(envelopeOrGraph) {
6323
+ if (!envelopeOrGraph || typeof envelopeOrGraph !== "object") return false;
6324
+ const env2 = envelopeOrGraph;
6325
+ const envWorkspace = env2.workspace;
6326
+ if (envWorkspace !== void 0 && envWorkspace !== "inherit") return true;
6327
+ const graph = Array.isArray(envelopeOrGraph) ? envelopeOrGraph : env2.definition?.graph ?? [];
6328
+ return Array.isArray(graph) && graph.some(entryHasJobTier);
6329
+ }
6330
+ var __defProp4, __name4, WorkflowTemplateError, TEMPLATE_PLACEHOLDER, TEMPLATE_NAMESPACES, MAP_DESCRIPTOR_KEYS, MAP_MEMBER_MALFORMED_CODE, fromInit, fromStep, value, template, fromRequest, rows, fromKnowledge, SideEffectsSchema, JobResourcesSchema, WORKFLOW_MODEL_TEMPLATE_ROOT, WORKFLOW_MODEL_TEMPLATE_RE, PATH_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, 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_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, WORKFLOW_SCHEDULE_RUN_AS, isObject, WORKFLOW_ENV_OVERLAY_MAX_KEYS, WORKFLOW_ENV_OVERLAY_MAX_VALUE_BYTES, WORKFLOW_ENV_TEMPLATE_SECRET_KEY_RE, isEnvRef, looksLikeEmbeddedJson, ZERO, isRecord2;
5913
6331
  var init_dist2 = __esm({
5914
6332
  "../workflow-graph/dist/index.mjs"() {
5915
6333
  "use strict";
5916
6334
  init_dist();
5917
6335
  init_dist();
5918
6336
  init_dist();
6337
+ init_workflow_job_tools();
6338
+ init_workflow_job_tools();
5919
6339
  init_dist();
5920
6340
  init_dist();
5921
6341
  init_dist();
5922
6342
  init_dist();
5923
- __defProp3 = Object.defineProperty;
5924
- __name3 = /* @__PURE__ */ __name((target, value22) => __defProp3(target, "name", { value: value22, configurable: true }), "__name");
6343
+ __defProp4 = Object.defineProperty;
6344
+ __name4 = /* @__PURE__ */ __name((target, value22) => __defProp4(target, "name", { value: value22, configurable: true }), "__name");
5925
6345
  WorkflowTemplateError = class extends Error {
5926
6346
  static {
5927
6347
  __name(this, "WorkflowTemplateError");
5928
6348
  }
5929
6349
  static {
5930
- __name3(this, "WorkflowTemplateError");
6350
+ __name4(this, "WorkflowTemplateError");
5931
6351
  }
5932
6352
  placeholder;
5933
6353
  constructor(message, placeholder) {
@@ -5936,11 +6356,11 @@ var init_dist2 = __esm({
5936
6356
  }
5937
6357
  };
5938
6358
  __name(isMapConfigObject, "isMapConfigObject");
5939
- __name3(isMapConfigObject, "isMapConfigObject");
6359
+ __name4(isMapConfigObject, "isMapConfigObject");
5940
6360
  __name(parseMapConfig, "parseMapConfig");
5941
- __name3(parseMapConfig, "parseMapConfig");
6361
+ __name4(parseMapConfig, "parseMapConfig");
5942
6362
  __name(mapConfigWire, "mapConfigWire");
5943
- __name3(mapConfigWire, "mapConfigWire");
6363
+ __name4(mapConfigWire, "mapConfigWire");
5944
6364
  TEMPLATE_PLACEHOLDER = /\$\{([^}]*)\}/g;
5945
6365
  TEMPLATE_NAMESPACES = [
5946
6366
  "initData",
@@ -5949,21 +6369,21 @@ var init_dist2 = __esm({
5949
6369
  "stepResults"
5950
6370
  ];
5951
6371
  __name(describeBadPlaceholder, "describeBadPlaceholder");
5952
- __name3(describeBadPlaceholder, "describeBadPlaceholder");
6372
+ __name4(describeBadPlaceholder, "describeBadPlaceholder");
5953
6373
  __name(parseTemplatePlaceholder, "parseTemplatePlaceholder");
5954
- __name3(parseTemplatePlaceholder, "parseTemplatePlaceholder");
6374
+ __name4(parseTemplatePlaceholder, "parseTemplatePlaceholder");
5955
6375
  __name(traverseMappingPath, "traverseMappingPath");
5956
- __name3(traverseMappingPath, "traverseMappingPath");
6376
+ __name4(traverseMappingPath, "traverseMappingPath");
5957
6377
  __name(stringifyTemplateValue, "stringifyTemplateValue");
5958
- __name3(stringifyTemplateValue, "stringifyTemplateValue");
6378
+ __name4(stringifyTemplateValue, "stringifyTemplateValue");
5959
6379
  __name(escapeFence, "escapeFence");
5960
- __name3(escapeFence, "escapeFence");
6380
+ __name4(escapeFence, "escapeFence");
5961
6381
  __name(fenceBlock, "fenceBlock");
5962
- __name3(fenceBlock, "fenceBlock");
6382
+ __name4(fenceBlock, "fenceBlock");
5963
6383
  __name(renderTemplate, "renderTemplate");
5964
- __name3(renderTemplate, "renderTemplate");
6384
+ __name4(renderTemplate, "renderTemplate");
5965
6385
  __name(isMapDescriptor, "isMapDescriptor");
5966
- __name3(isMapDescriptor, "isMapDescriptor");
6386
+ __name4(isMapDescriptor, "isMapDescriptor");
5967
6387
  MAP_DESCRIPTOR_KEYS = [
5968
6388
  "step",
5969
6389
  "path",
@@ -5975,43 +6395,64 @@ var init_dist2 = __esm({
5975
6395
  ];
5976
6396
  MAP_MEMBER_MALFORMED_CODE = "map-member-malformed";
5977
6397
  __name(malformedMapMembers, "malformedMapMembers");
5978
- __name3(malformedMapMembers, "malformedMapMembers");
6398
+ __name4(malformedMapMembers, "malformedMapMembers");
5979
6399
  __name(mapMemberMalformedMessage, "mapMemberMalformedMessage");
5980
- __name3(mapMemberMalformedMessage, "mapMemberMalformedMessage");
6400
+ __name4(mapMemberMalformedMessage, "mapMemberMalformedMessage");
5981
6401
  __name(resolveDescriptor, "resolveDescriptor");
5982
- __name3(resolveDescriptor, "resolveDescriptor");
6402
+ __name4(resolveDescriptor, "resolveDescriptor");
5983
6403
  __name(resolveMapping, "resolveMapping");
5984
- __name3(resolveMapping, "resolveMapping");
5985
- fromInit = /* @__PURE__ */ __name3((path3) => ({
6404
+ __name4(resolveMapping, "resolveMapping");
6405
+ fromInit = /* @__PURE__ */ __name4((path3) => ({
5986
6406
  initData: true,
5987
6407
  path: path3
5988
6408
  }), "fromInit");
5989
- fromStep = /* @__PURE__ */ __name3((s, path3 = "") => {
5990
- const idOf = /* @__PURE__ */ __name3((x) => typeof x === "string" ? x : x.id, "idOf");
6409
+ fromStep = /* @__PURE__ */ __name4((s, path3 = "") => {
6410
+ const idOf = /* @__PURE__ */ __name4((x) => typeof x === "string" ? x : x.id, "idOf");
5991
6411
  return {
5992
6412
  step: Array.isArray(s) ? s.map(idOf) : idOf(s),
5993
6413
  path: path3
5994
6414
  };
5995
6415
  }, "fromStep");
5996
- value = /* @__PURE__ */ __name3((v) => ({
6416
+ value = /* @__PURE__ */ __name4((v) => ({
5997
6417
  value: v
5998
6418
  }), "value");
5999
- template = /* @__PURE__ */ __name3((s) => ({
6419
+ template = /* @__PURE__ */ __name4((s) => ({
6000
6420
  template: s
6001
6421
  }), "template");
6002
- fromRequest = /* @__PURE__ */ __name3((path3) => ({
6422
+ fromRequest = /* @__PURE__ */ __name4((path3) => ({
6003
6423
  requestContextPath: path3
6004
6424
  }), "fromRequest");
6005
- rows = /* @__PURE__ */ __name3((s, path3, page) => ({
6425
+ rows = /* @__PURE__ */ __name4((s, path3, page) => ({
6006
6426
  step: typeof s === "string" ? s : s.id,
6007
6427
  path: path3,
6008
6428
  rows: page
6009
6429
  }), "rows");
6010
- fromKnowledge = /* @__PURE__ */ __name3((k) => ({
6430
+ fromKnowledge = /* @__PURE__ */ __name4((k) => ({
6011
6431
  knowledge: k
6012
6432
  }), "fromKnowledge");
6013
6433
  SideEffectsSchema = z4.enum(WORKFLOW_SIDE_EFFECTS);
6014
6434
  JobResourcesSchema = z4.enum(WORKFLOW_JOB_RESOURCES);
6435
+ WORKFLOW_MODEL_TEMPLATE_ROOT = "initData";
6436
+ WORKFLOW_MODEL_TEMPLATE_RE = /^\$\{\s*initData\.([A-Za-z0-9_.\-[\]]+)\s*(?:\|([^}]*))?\}$/;
6437
+ PATH_SEGMENT_RE = /^[A-Za-z0-9_-]+(?:\[(?:0|[1-9]\d*)\])*$/;
6438
+ __name(looksLikeModelTemplate, "looksLikeModelTemplate");
6439
+ __name4(looksLikeModelTemplate, "looksLikeModelTemplate");
6440
+ __name(parseModelTemplate, "parseModelTemplate");
6441
+ __name4(parseModelTemplate, "parseModelTemplate");
6442
+ __name(modelTemplateInvalidMessage, "modelTemplateInvalidMessage");
6443
+ __name4(modelTemplateInvalidMessage, "modelTemplateInvalidMessage");
6444
+ __name(modelTemplateDefaultRequiredMessage, "modelTemplateDefaultRequiredMessage");
6445
+ __name4(modelTemplateDefaultRequiredMessage, "modelTemplateDefaultRequiredMessage");
6446
+ __name(staticModelPin, "staticModelPin");
6447
+ __name4(staticModelPin, "staticModelPin");
6448
+ __name(readPath, "readPath");
6449
+ __name4(readPath, "readPath");
6450
+ __name(renderModelTemplate, "renderModelTemplate");
6451
+ __name4(renderModelTemplate, "renderModelTemplate");
6452
+ __name(modelTemplateUnboundMessage, "modelTemplateUnboundMessage");
6453
+ __name4(modelTemplateUnboundMessage, "modelTemplateUnboundMessage");
6454
+ __name(modelTemplateInputNotObjectMessage, "modelTemplateInputNotObjectMessage");
6455
+ __name4(modelTemplateInputNotObjectMessage, "modelTemplateInputNotObjectMessage");
6015
6456
  APPROVER_SPEC_MAX_USERS = 20;
6016
6457
  ESCALATION_MAX_HOPS = 3;
6017
6458
  TemplateBindingSchema = z22.object({
@@ -6077,7 +6518,7 @@ var init_dist2 = __esm({
6077
6518
  APPROVER_WRITTEN_MAX = 120;
6078
6519
  USER_ID_SHAPED_RE = /^[^\s@]{1,128}$/;
6079
6520
  __name(describeApproverSpecRefusal, "describeApproverSpecRefusal");
6080
- __name3(describeApproverSpecRefusal, "describeApproverSpecRefusal");
6521
+ __name4(describeApproverSpecRefusal, "describeApproverSpecRefusal");
6081
6522
  BINDING_ROOTS = [
6082
6523
  "initData",
6083
6524
  "stepResults",
@@ -6085,28 +6526,28 @@ var init_dist2 = __esm({
6085
6526
  "state"
6086
6527
  ];
6087
6528
  __name(bindingRootsOk, "bindingRootsOk");
6088
- __name3(bindingRootsOk, "bindingRootsOk");
6529
+ __name4(bindingRootsOk, "bindingRootsOk");
6089
6530
  __name(isTemplateBinding, "isTemplateBinding");
6090
- __name3(isTemplateBinding, "isTemplateBinding");
6531
+ __name4(isTemplateBinding, "isTemplateBinding");
6091
6532
  __name(approvalEditable, "approvalEditable");
6092
- __name3(approvalEditable, "approvalEditable");
6533
+ __name4(approvalEditable, "approvalEditable");
6093
6534
  __name(validateApproverBlock, "validateApproverBlock");
6094
- __name3(validateApproverBlock, "validateApproverBlock");
6535
+ __name4(validateApproverBlock, "validateApproverBlock");
6095
6536
  __name(liftRenderedApprover, "liftRenderedApprover");
6096
- __name3(liftRenderedApprover, "liftRenderedApprover");
6537
+ __name4(liftRenderedApprover, "liftRenderedApprover");
6097
6538
  WORKSPACE_TEMPLATE_EXPR_RE = /^\$\{\s*(?:initData|input)\.([^}]+?)\s*\}$/;
6098
6539
  __name(workspaceTemplatePath, "workspaceTemplatePath");
6099
- __name3(workspaceTemplatePath, "workspaceTemplatePath");
6540
+ __name4(workspaceTemplatePath, "workspaceTemplatePath");
6100
6541
  __name(retryBackoffs, "retryBackoffs");
6101
- __name3(retryBackoffs, "retryBackoffs");
6542
+ __name4(retryBackoffs, "retryBackoffs");
6102
6543
  SLEEP_UNTIL_REPLACEMENT = Object.freeze({
6103
6544
  type: "sleep",
6104
6545
  duration: 6e4
6105
6546
  });
6106
6547
  __name(sleepUntilUnsupportedMessage, "sleepUntilUnsupportedMessage");
6107
- __name3(sleepUntilUnsupportedMessage, "sleepUntilUnsupportedMessage");
6548
+ __name4(sleepUntilUnsupportedMessage, "sleepUntilUnsupportedMessage");
6108
6549
  __name(armSubrunUnsupportedMessage, "armSubrunUnsupportedMessage");
6109
- __name3(armSubrunUnsupportedMessage, "armSubrunUnsupportedMessage");
6550
+ __name4(armSubrunUnsupportedMessage, "armSubrunUnsupportedMessage");
6110
6551
  WORKFLOW_CAPS_DEFAULT = Object.freeze({
6111
6552
  maxParallelArms: 16,
6112
6553
  maxForeachConcurrency: 16,
@@ -6131,71 +6572,60 @@ var init_dist2 = __esm({
6131
6572
  "api",
6132
6573
  "user"
6133
6574
  ];
6134
- clone = /* @__PURE__ */ __name3((v) => JSON.parse(JSON.stringify(v)), "clone");
6575
+ clone = /* @__PURE__ */ __name4((v) => JSON.parse(JSON.stringify(v)), "clone");
6135
6576
  __name(fillPolicy, "fillPolicy");
6136
- __name3(fillPolicy, "fillPolicy");
6577
+ __name4(fillPolicy, "fillPolicy");
6137
6578
  __name(fillSingle, "fillSingle");
6138
- __name3(fillSingle, "fillSingle");
6579
+ __name4(fillSingle, "fillSingle");
6139
6580
  __name(fillHitl, "fillHitl");
6140
- __name3(fillHitl, "fillHitl");
6581
+ __name4(fillHitl, "fillHitl");
6141
6582
  __name(fillArm, "fillArm");
6142
- __name3(fillArm, "fillArm");
6583
+ __name4(fillArm, "fillArm");
6143
6584
  __name(fillEntry, "fillEntry");
6144
- __name3(fillEntry, "fillEntry");
6585
+ __name4(fillEntry, "fillEntry");
6145
6586
  __name(withDefaultsFilled, "withDefaultsFilled");
6146
- __name3(withDefaultsFilled, "withDefaultsFilled");
6587
+ __name4(withDefaultsFilled, "withDefaultsFilled");
6147
6588
  CONNECTION_ID_HEX_RE = /^[0-9a-f]{24}$/;
6148
6589
  __name(isConnectionKeyShaped, "isConnectionKeyShaped");
6149
- __name3(isConnectionKeyShaped, "isConnectionKeyShaped");
6590
+ __name4(isConnectionKeyShaped, "isConnectionKeyShaped");
6150
6591
  __name(connectionKeyUndeclaredMessage, "connectionKeyUndeclaredMessage");
6151
- __name3(connectionKeyUndeclaredMessage, "connectionKeyUndeclaredMessage");
6152
- WORKFLOW_JOB_TOOLS = [
6153
- "shell",
6154
- "read",
6155
- "write",
6156
- "edit",
6157
- "glob",
6158
- "grep",
6159
- "git",
6160
- "gh",
6161
- "fetch"
6162
- ];
6592
+ __name4(connectionKeyUndeclaredMessage, "connectionKeyUndeclaredMessage");
6163
6593
  WORKFLOW_JOB_MAX_WORKTREE_ARMS = 8;
6164
6594
  __name(classifyModelProvider, "classifyModelProvider");
6165
- __name3(classifyModelProvider, "classifyModelProvider");
6166
- workspaceOf = /* @__PURE__ */ __name3((node) => node.workspace, "workspaceOf");
6167
- mountsWorkspace = /* @__PURE__ */ __name3((node) => {
6595
+ __name4(classifyModelProvider, "classifyModelProvider");
6596
+ workspaceOf = /* @__PURE__ */ __name4((node) => node.workspace, "workspaceOf");
6597
+ mountsWorkspace = /* @__PURE__ */ __name4((node) => {
6168
6598
  const w = workspaceOf(node);
6169
6599
  return w !== void 0 && w !== "inherit";
6170
6600
  }, "mountsWorkspace");
6171
- isJobTier = /* @__PURE__ */ __name3((node) => node.tier === "job" || mountsWorkspace(node), "isJobTier");
6172
- jobToolsOf = /* @__PURE__ */ __name3((node) => {
6601
+ isJobTier = /* @__PURE__ */ __name4((node) => node.tier === "job" || mountsWorkspace(node), "isJobTier");
6602
+ jobToolsOf = /* @__PURE__ */ __name4((node) => {
6173
6603
  if (node.type === "agent") return node.toolScope?.jobTools;
6174
6604
  return node.jobTools;
6175
6605
  }, "jobToolsOf");
6176
6606
  __name(schemaAtPath, "schemaAtPath");
6177
- __name3(schemaAtPath, "schemaAtPath");
6178
- schemaIsArray = /* @__PURE__ */ __name3((schema) => {
6607
+ __name4(schemaAtPath, "schemaAtPath");
6608
+ schemaIsArray = /* @__PURE__ */ __name4((schema) => {
6179
6609
  if (!schema) return void 0;
6180
6610
  const t = schema.type;
6181
6611
  if (t === void 0) return void 0;
6182
6612
  return Array.isArray(t) ? t.includes("array") : t === "array";
6183
6613
  }, "schemaIsArray");
6184
- isHitlNode = /* @__PURE__ */ __name3((n2) => isWorkflowHitlEntryType(n2.type), "isHitlNode");
6185
- isSingleStep = /* @__PURE__ */ __name3((n2) => !isHitlNode(n2), "isSingleStep");
6186
- singleId = /* @__PURE__ */ __name3((s) => s.type === "step" ? s.step.id : s.id, "singleId");
6187
- armId = /* @__PURE__ */ __name3((a) => a.type === "mapping" ? a.id : singleId(a), "armId");
6614
+ isHitlNode = /* @__PURE__ */ __name4((n2) => isWorkflowHitlEntryType(n2.type), "isHitlNode");
6615
+ isSingleStep = /* @__PURE__ */ __name4((n2) => !isHitlNode(n2), "isSingleStep");
6616
+ singleId = /* @__PURE__ */ __name4((s) => s.type === "step" ? s.step.id : s.id, "singleId");
6617
+ armId = /* @__PURE__ */ __name4((a) => a.type === "mapping" ? a.id : singleId(a), "armId");
6188
6618
  TEMPLATE_STEP_REF = /\$\{\s*stepResults\.([A-Za-z0-9_\-]+)/g;
6189
6619
  __name(templateStepRefs, "templateStepRefs");
6190
- __name3(templateStepRefs, "templateStepRefs");
6620
+ __name4(templateStepRefs, "templateStepRefs");
6191
6621
  __name(readMapConfig, "readMapConfig");
6192
- __name3(readMapConfig, "readMapConfig");
6622
+ __name4(readMapConfig, "readMapConfig");
6193
6623
  __name(mapConfigStepRefs, "mapConfigStepRefs");
6194
- __name3(mapConfigStepRefs, "mapConfigStepRefs");
6624
+ __name4(mapConfigStepRefs, "mapConfigStepRefs");
6195
6625
  __name(nodeStepRefs, "nodeStepRefs");
6196
- __name3(nodeStepRefs, "nodeStepRefs");
6626
+ __name4(nodeStepRefs, "nodeStepRefs");
6197
6627
  __name(validateLuaExtensions, "validateLuaExtensions");
6198
- __name3(validateLuaExtensions, "validateLuaExtensions");
6628
+ __name4(validateLuaExtensions, "validateLuaExtensions");
6199
6629
  EDITABLE_PATH_RE = /^[A-Za-z_][A-Za-z0-9_]*(\[(\*|\d+)\])?(\.[A-Za-z_][A-Za-z0-9_]*(\[(\*|\d+)\])?)*$/;
6200
6630
  PREDICATE_OPS = /* @__PURE__ */ new Set([
6201
6631
  "eq",
@@ -6215,23 +6645,23 @@ var init_dist2 = __esm({
6215
6645
  "not"
6216
6646
  ]);
6217
6647
  __name(isPredicate, "isPredicate");
6218
- __name3(isPredicate, "isPredicate");
6219
- isPredicateScalar = /* @__PURE__ */ __name3((v) => v === null || typeof v === "string" || typeof v === "number" || typeof v === "boolean", "isPredicateScalar");
6648
+ __name4(isPredicate, "isPredicate");
6649
+ isPredicateScalar = /* @__PURE__ */ __name4((v) => v === null || typeof v === "string" || typeof v === "number" || typeof v === "boolean", "isPredicateScalar");
6220
6650
  __name(isPathOrLiteral, "isPathOrLiteral");
6221
- __name3(isPathOrLiteral, "isPathOrLiteral");
6651
+ __name4(isPathOrLiteral, "isPathOrLiteral");
6222
6652
  __name(isWellFormedPredicate, "isWellFormedPredicate");
6223
- __name3(isWellFormedPredicate, "isWellFormedPredicate");
6653
+ __name4(isWellFormedPredicate, "isWellFormedPredicate");
6224
6654
  GRAPH_HASH_PREFIX = "sha256-cj1:";
6225
6655
  __name(canonicalJson, "canonicalJson");
6226
- __name3(canonicalJson, "canonicalJson");
6656
+ __name4(canonicalJson, "canonicalJson");
6227
6657
  __name(hashGraph, "hashGraph");
6228
- __name3(hashGraph, "hashGraph");
6658
+ __name4(hashGraph, "hashGraph");
6229
6659
  WorkflowPlanError = class extends Error {
6230
6660
  static {
6231
6661
  __name(this, "WorkflowPlanError");
6232
6662
  }
6233
6663
  static {
6234
- __name3(this, "WorkflowPlanError");
6664
+ __name4(this, "WorkflowPlanError");
6235
6665
  }
6236
6666
  code;
6237
6667
  constructor(code, message) {
@@ -6239,47 +6669,47 @@ var init_dist2 = __esm({
6239
6669
  this.name = "WorkflowPlanError";
6240
6670
  }
6241
6671
  };
6242
- isArmStep = /* @__PURE__ */ __name3((e) => isWorkflowArmEntryType(e.type), "isArmStep");
6243
- armStepId = /* @__PURE__ */ __name3((e) => e.type === "step" ? e.step.id : e.id, "armStepId");
6244
- armStepKind = /* @__PURE__ */ __name3((e) => WORKFLOW_ARM_ENTRY_STEP_KINDS[e.type], "armStepKind");
6245
- joinIdOf = /* @__PURE__ */ __name3((entryId) => `${entryId}.join`, "joinIdOf");
6246
- containerIdOf = /* @__PURE__ */ __name3((type, entryIndex) => `${type}@${entryIndex}`, "containerIdOf");
6672
+ isArmStep = /* @__PURE__ */ __name4((e) => isWorkflowArmEntryType(e.type), "isArmStep");
6673
+ armStepId = /* @__PURE__ */ __name4((e) => e.type === "step" ? e.step.id : e.id, "armStepId");
6674
+ armStepKind = /* @__PURE__ */ __name4((e) => WORKFLOW_ARM_ENTRY_STEP_KINDS[e.type], "armStepKind");
6675
+ joinIdOf = /* @__PURE__ */ __name4((entryId) => `${entryId}.join`, "joinIdOf");
6676
+ containerIdOf = /* @__PURE__ */ __name4((type, entryIndex) => `${type}@${entryIndex}`, "containerIdOf");
6247
6677
  __name(compilePlan, "compilePlan");
6248
- __name3(compilePlan, "compilePlan");
6678
+ __name4(compilePlan, "compilePlan");
6249
6679
  PATH_PLACEHOLDER = /^\$\{([^}]+)\}$/;
6250
6680
  MISSING = /* @__PURE__ */ Symbol("predicate.missing");
6251
6681
  __name(resolvePath, "resolvePath");
6252
- __name3(resolvePath, "resolvePath");
6682
+ __name4(resolvePath, "resolvePath");
6253
6683
  __name(walk, "walk");
6254
- __name3(walk, "walk");
6684
+ __name4(walk, "walk");
6255
6685
  __name(resolveValue, "resolveValue");
6256
- __name3(resolveValue, "resolveValue");
6686
+ __name4(resolveValue, "resolveValue");
6257
6687
  __name(evaluatePredicate, "evaluatePredicate");
6258
- __name3(evaluatePredicate, "evaluatePredicate");
6688
+ __name4(evaluatePredicate, "evaluatePredicate");
6259
6689
  __name(compare, "compare");
6260
- __name3(compare, "compare");
6690
+ __name4(compare, "compare");
6261
6691
  __name(derivePredicateLabel, "derivePredicateLabel");
6262
- __name3(derivePredicateLabel, "derivePredicateLabel");
6692
+ __name4(derivePredicateLabel, "derivePredicateLabel");
6263
6693
  __name(renderPredicate, "renderPredicate");
6264
- __name3(renderPredicate, "renderPredicate");
6694
+ __name4(renderPredicate, "renderPredicate");
6265
6695
  __name(wrapLabel, "wrapLabel");
6266
- __name3(wrapLabel, "wrapLabel");
6696
+ __name4(wrapLabel, "wrapLabel");
6267
6697
  __name(renderRef, "renderRef");
6268
- __name3(renderRef, "renderRef");
6269
- stepIdOf = /* @__PURE__ */ __name3((s) => typeof s === "string" ? s : s.id, "stepIdOf");
6698
+ __name4(renderRef, "renderRef");
6699
+ stepIdOf = /* @__PURE__ */ __name4((s) => typeof s === "string" ? s : s.id, "stepIdOf");
6270
6700
  __name(step, "step");
6271
- __name3(step, "step");
6701
+ __name4(step, "step");
6272
6702
  __name(stepOf, "stepOf");
6273
- __name3(stepOf, "stepOf");
6703
+ __name4(stepOf, "stepOf");
6274
6704
  __name(init, "init");
6275
- __name3(init, "init");
6705
+ __name4(init, "init");
6276
6706
  __name(state, "state");
6277
- __name3(state, "state");
6707
+ __name4(state, "state");
6278
6708
  __name(lit, "lit");
6279
- __name3(lit, "lit");
6709
+ __name4(lit, "lit");
6280
6710
  __name(toPathOrLiteral, "toPathOrLiteral");
6281
- __name3(toPathOrLiteral, "toPathOrLiteral");
6282
- cmp = /* @__PURE__ */ __name3((op) => (l, r) => ({
6711
+ __name4(toPathOrLiteral, "toPathOrLiteral");
6712
+ cmp = /* @__PURE__ */ __name4((op) => (l, r) => ({
6283
6713
  op,
6284
6714
  left: toPathOrLiteral(l),
6285
6715
  right: toPathOrLiteral(r)
@@ -6290,49 +6720,49 @@ var init_dist2 = __esm({
6290
6720
  gte = cmp("gte");
6291
6721
  lt = cmp("lt");
6292
6722
  lte = cmp("lte");
6293
- inSet = /* @__PURE__ */ __name3((v, set) => ({
6723
+ inSet = /* @__PURE__ */ __name4((v, set) => ({
6294
6724
  op: "in",
6295
6725
  value: {
6296
6726
  path: v.path
6297
6727
  },
6298
6728
  set
6299
6729
  }), "inSet");
6300
- notIn = /* @__PURE__ */ __name3((v, set) => ({
6730
+ notIn = /* @__PURE__ */ __name4((v, set) => ({
6301
6731
  op: "notIn",
6302
6732
  value: {
6303
6733
  path: v.path
6304
6734
  },
6305
6735
  set
6306
6736
  }), "notIn");
6307
- exists = /* @__PURE__ */ __name3((ref) => ({
6737
+ exists = /* @__PURE__ */ __name4((ref) => ({
6308
6738
  op: "exists",
6309
6739
  path: ref.path
6310
6740
  }), "exists");
6311
- notExists = /* @__PURE__ */ __name3((ref) => ({
6741
+ notExists = /* @__PURE__ */ __name4((ref) => ({
6312
6742
  op: "notExists",
6313
6743
  path: ref.path
6314
6744
  }), "notExists");
6315
- truthy = /* @__PURE__ */ __name3((ref) => ({
6745
+ truthy = /* @__PURE__ */ __name4((ref) => ({
6316
6746
  op: "truthy",
6317
6747
  value: {
6318
6748
  path: ref.path
6319
6749
  }
6320
6750
  }), "truthy");
6321
- falsy = /* @__PURE__ */ __name3((ref) => ({
6751
+ falsy = /* @__PURE__ */ __name4((ref) => ({
6322
6752
  op: "falsy",
6323
6753
  value: {
6324
6754
  path: ref.path
6325
6755
  }
6326
6756
  }), "falsy");
6327
- and = /* @__PURE__ */ __name3((...args) => ({
6757
+ and = /* @__PURE__ */ __name4((...args) => ({
6328
6758
  op: "and",
6329
6759
  args
6330
6760
  }), "and");
6331
- or = /* @__PURE__ */ __name3((...args) => ({
6761
+ or = /* @__PURE__ */ __name4((...args) => ({
6332
6762
  op: "or",
6333
6763
  args
6334
6764
  }), "or");
6335
- not = /* @__PURE__ */ __name3((arg) => ({
6765
+ not = /* @__PURE__ */ __name4((arg) => ({
6336
6766
  op: "not",
6337
6767
  arg
6338
6768
  }), "not");
@@ -6384,17 +6814,17 @@ var init_dist2 = __esm({
6384
6814
  "text"
6385
6815
  ]);
6386
6816
  __name(continuedFailureValue, "continuedFailureValue");
6387
- __name3(continuedFailureValue, "continuedFailureValue");
6817
+ __name4(continuedFailureValue, "continuedFailureValue");
6388
6818
  __name(isContinuedFailureValue, "isContinuedFailureValue");
6389
- __name3(isContinuedFailureValue, "isContinuedFailureValue");
6390
- isHitlNode2 = /* @__PURE__ */ __name3((n2) => isWorkflowHitlEntryType(n2.type), "isHitlNode");
6819
+ __name4(isContinuedFailureValue, "isContinuedFailureValue");
6820
+ isHitlNode2 = /* @__PURE__ */ __name4((n2) => isWorkflowHitlEntryType(n2.type), "isHitlNode");
6391
6821
  __name(inlineContainerArm, "inlineContainerArm");
6392
- __name3(inlineContainerArm, "inlineContainerArm");
6393
- nodeIdOf = /* @__PURE__ */ __name3((n2) => n2.type === "step" ? n2.step.id : n2.id, "nodeIdOf");
6822
+ __name4(inlineContainerArm, "inlineContainerArm");
6823
+ nodeIdOf = /* @__PURE__ */ __name4((n2) => n2.type === "step" ? n2.step.id : n2.id, "nodeIdOf");
6394
6824
  __name(entryIds, "entryIds");
6395
- __name3(entryIds, "entryIds");
6825
+ __name4(entryIds, "entryIds");
6396
6826
  __name(resolvePlacements, "resolvePlacements");
6397
- __name3(resolvePlacements, "resolvePlacements");
6827
+ __name4(resolvePlacements, "resolvePlacements");
6398
6828
  GOAL_JUDGE_STEP_ID = "__goal_judge";
6399
6829
  NON_LEAF_KINDS = /* @__PURE__ */ new Set([
6400
6830
  "foreach",
@@ -6402,26 +6832,26 @@ var init_dist2 = __esm({
6402
6832
  ]);
6403
6833
  CONDITIONAL_JOIN_ID = /^conditional@\d+\.join$/;
6404
6834
  __name(isConditionalJoinId, "isConditionalJoinId");
6405
- __name3(isConditionalJoinId, "isConditionalJoinId");
6835
+ __name4(isConditionalJoinId, "isConditionalJoinId");
6406
6836
  __name(isPlainObject, "isPlainObject");
6407
- __name3(isPlainObject, "isPlainObject");
6837
+ __name4(isPlainObject, "isPlainObject");
6408
6838
  __name(leafValue, "leafValue");
6409
- __name3(leafValue, "leafValue");
6839
+ __name4(leafValue, "leafValue");
6410
6840
  __name(runOutputLeaves, "runOutputLeaves");
6411
- __name3(runOutputLeaves, "runOutputLeaves");
6841
+ __name4(runOutputLeaves, "runOutputLeaves");
6412
6842
  __name(deriveRunOutput, "deriveRunOutput");
6413
- __name3(deriveRunOutput, "deriveRunOutput");
6843
+ __name4(deriveRunOutput, "deriveRunOutput");
6414
6844
  __name(subrunSettledOutput, "subrunSettledOutput");
6415
- __name3(subrunSettledOutput, "subrunSettledOutput");
6845
+ __name4(subrunSettledOutput, "subrunSettledOutput");
6416
6846
  __name(seedLedgerFromRun, "seedLedgerFromRun");
6417
- __name3(seedLedgerFromRun, "seedLedgerFromRun");
6418
- branchArmId = /* @__PURE__ */ __name3((arm) => arm.type === "step" ? arm.step.id : arm.id, "branchArmId");
6847
+ __name4(seedLedgerFromRun, "seedLedgerFromRun");
6848
+ branchArmId = /* @__PURE__ */ __name4((arm) => arm.type === "step" ? arm.step.id : arm.id, "branchArmId");
6419
6849
  __name(branchSpecFromConditional, "branchSpecFromConditional");
6420
- __name3(branchSpecFromConditional, "branchSpecFromConditional");
6850
+ __name4(branchSpecFromConditional, "branchSpecFromConditional");
6421
6851
  __name(selectBranchArms, "selectBranchArms");
6422
- __name3(selectBranchArms, "selectBranchArms");
6423
- canonical = /* @__PURE__ */ __name3((v) => JSON.stringify(sortKeys(v)), "canonical");
6424
- sortKeys = /* @__PURE__ */ __name3((v) => {
6852
+ __name4(selectBranchArms, "selectBranchArms");
6853
+ canonical = /* @__PURE__ */ __name4((v) => JSON.stringify(sortKeys(v)), "canonical");
6854
+ sortKeys = /* @__PURE__ */ __name4((v) => {
6425
6855
  if (Array.isArray(v)) return v.map(sortKeys);
6426
6856
  if (v && typeof v === "object") {
6427
6857
  return Object.fromEntries(Object.keys(v).sort().map((k) => [
@@ -6432,65 +6862,65 @@ var init_dist2 = __esm({
6432
6862
  return v;
6433
6863
  }, "sortKeys");
6434
6864
  __name(replayLedger, "replayLedger");
6435
- __name3(replayLedger, "replayLedger");
6865
+ __name4(replayLedger, "replayLedger");
6436
6866
  JOIN = ".join";
6437
- entryOfJoin = /* @__PURE__ */ __name3((id) => id.endsWith(JOIN) ? id.slice(0, -JOIN.length) : void 0, "entryOfJoin");
6867
+ entryOfJoin = /* @__PURE__ */ __name4((id) => id.endsWith(JOIN) ? id.slice(0, -JOIN.length) : void 0, "entryOfJoin");
6438
6868
  __name(replayResultOf, "replayResultOf");
6439
- __name3(replayResultOf, "replayResultOf");
6869
+ __name4(replayResultOf, "replayResultOf");
6440
6870
  __name(ancestorResults, "ancestorResults");
6441
- __name3(ancestorResults, "ancestorResults");
6871
+ __name4(ancestorResults, "ancestorResults");
6442
6872
  __name(inferTaken, "inferTaken");
6443
- __name3(inferTaken, "inferTaken");
6873
+ __name4(inferTaken, "inferTaken");
6444
6874
  __name(countChildren, "countChildren");
6445
- __name3(countChildren, "countChildren");
6875
+ __name4(countChildren, "countChildren");
6446
6876
  FORCE_CANCEL_STALE_MS = 10 * 60 * 1e3;
6447
6877
  TERMINAL = new Set(WORKFLOW_RUN_TERMINAL);
6448
6878
  __name(isTerminalRunStatus, "isTerminalRunStatus");
6449
- __name3(isTerminalRunStatus, "isTerminalRunStatus");
6879
+ __name4(isTerminalRunStatus, "isTerminalRunStatus");
6450
6880
  __name(pruneUndefined, "pruneUndefined");
6451
- __name3(pruneUndefined, "pruneUndefined");
6881
+ __name4(pruneUndefined, "pruneUndefined");
6452
6882
  WORKFLOW_INLINE_RUN_TAG = "inline";
6453
6883
  __name(runOrigin, "runOrigin");
6454
- __name3(runOrigin, "runOrigin");
6884
+ __name4(runOrigin, "runOrigin");
6455
6885
  RUN_ERROR_ISSUES_MAX = 20;
6456
6886
  __name(runErrorIssues, "runErrorIssues");
6457
- __name3(runErrorIssues, "runErrorIssues");
6887
+ __name4(runErrorIssues, "runErrorIssues");
6458
6888
  __name(runNextAction, "runNextAction");
6459
- __name3(runNextAction, "runNextAction");
6889
+ __name4(runNextAction, "runNextAction");
6460
6890
  IN_FLIGHT = new Set(WORKFLOW_STEP_IN_FLIGHT);
6461
6891
  __name(emptyRunCounts, "emptyRunCounts");
6462
- __name3(emptyRunCounts, "emptyRunCounts");
6892
+ __name4(emptyRunCounts, "emptyRunCounts");
6463
6893
  __name(runCountsFromStatusTally, "runCountsFromStatusTally");
6464
- __name3(runCountsFromStatusTally, "runCountsFromStatusTally");
6894
+ __name4(runCountsFromStatusTally, "runCountsFromStatusTally");
6465
6895
  __name(runCountsFromStepStatuses, "runCountsFromStepStatuses");
6466
- __name3(runCountsFromStepStatuses, "runCountsFromStepStatuses");
6896
+ __name4(runCountsFromStepStatuses, "runCountsFromStepStatuses");
6467
6897
  __name(isBillingHeldStep, "isBillingHeldStep");
6468
- __name3(isBillingHeldStep, "isBillingHeldStep");
6898
+ __name4(isBillingHeldStep, "isBillingHeldStep");
6469
6899
  __name(stepEffectiveStatus, "stepEffectiveStatus");
6470
- __name3(stepEffectiveStatus, "stepEffectiveStatus");
6471
- n = /* @__PURE__ */ __name3((v) => typeof v === "number" && Number.isFinite(v) ? v : 0, "n");
6900
+ __name4(stepEffectiveStatus, "stepEffectiveStatus");
6901
+ n = /* @__PURE__ */ __name4((v) => typeof v === "number" && Number.isFinite(v) ? v : 0, "n");
6472
6902
  __name(runCounts, "runCounts");
6473
- __name3(runCounts, "runCounts");
6903
+ __name4(runCounts, "runCounts");
6474
6904
  __name(isPricedStepReceipt, "isPricedStepReceipt");
6475
- __name3(isPricedStepReceipt, "isPricedStepReceipt");
6905
+ __name4(isPricedStepReceipt, "isPricedStepReceipt");
6476
6906
  __name(receiptEngine, "receiptEngine");
6477
- __name3(receiptEngine, "receiptEngine");
6907
+ __name4(receiptEngine, "receiptEngine");
6478
6908
  __name(receiptTier, "receiptTier");
6479
- __name3(receiptTier, "receiptTier");
6909
+ __name4(receiptTier, "receiptTier");
6480
6910
  __name(stepBillingView, "stepBillingView");
6481
- __name3(stepBillingView, "stepBillingView");
6911
+ __name4(stepBillingView, "stepBillingView");
6482
6912
  __name(runUsage, "runUsage");
6483
- __name3(runUsage, "runUsage");
6913
+ __name4(runUsage, "runUsage");
6484
6914
  __name(runBudgetCap, "runBudgetCap");
6485
- __name3(runBudgetCap, "runBudgetCap");
6915
+ __name4(runBudgetCap, "runBudgetCap");
6486
6916
  __name(runBudgetRemaining, "runBudgetRemaining");
6487
- __name3(runBudgetRemaining, "runBudgetRemaining");
6917
+ __name4(runBudgetRemaining, "runBudgetRemaining");
6488
6918
  __name(runCancelView, "runCancelView");
6489
- __name3(runCancelView, "runCancelView");
6919
+ __name4(runCancelView, "runCancelView");
6490
6920
  __name(runWorkspaceView, "runWorkspaceView");
6491
- __name3(runWorkspaceView, "runWorkspaceView");
6921
+ __name4(runWorkspaceView, "runWorkspaceView");
6492
6922
  __name(toWorkflowRunSummary, "toWorkflowRunSummary");
6493
- __name3(toWorkflowRunSummary, "toWorkflowRunSummary");
6923
+ __name4(toWorkflowRunSummary, "toWorkflowRunSummary");
6494
6924
  STEP_ERROR_DETAIL_KEYS = [
6495
6925
  "reason",
6496
6926
  "key",
@@ -6519,15 +6949,34 @@ var init_dist2 = __esm({
6519
6949
  "workflowId",
6520
6950
  // LUA-696 (review 2): the `ctx.once` key of an `effect_in_doubt` park — the step site stamps it here (scrubbed)
6521
6951
  // beside `park.effectKey`; a key is user text and leaves scrubbed like every other string leaf.
6522
- "effectKey"
6952
+ "effectKey",
6953
+ // LUA-833: the Job tier's `job_auth_rejected{reason}` evidence — the pod that exited and its code, the Secret the
6954
+ // row named (a k8s object NAME, `wfs-<hash12>-a<n>`, never a value), the execution the pod was spawned for, the
6955
+ // one its credential was minted for, and whether that credential had expired. The LUA-716 / LUA-748 spawn
6956
+ // refusals name `secretName` too.
6957
+ "podName",
6958
+ "exitCode",
6959
+ "secretName",
6960
+ "executionId",
6961
+ "credentialsExecutionId",
6962
+ "expired",
6963
+ // Run-input-bound model pins (the Principal Engineer stage models): the Job tier's `MODEL_ERROR` refusals name the
6964
+ // pin they judged (`requested`), the declared harness, the provider the classifier read and the precedence leg the
6965
+ // pin came from (`source`: initData / default / node / env / org / stamp), and `provider_unsupported`'s fleet
6966
+ // (`allowed`, the LUA_WF_JOB_PROVIDERS list) — the members the PR body promises.
6967
+ "requested",
6968
+ "harness",
6969
+ "provider",
6970
+ "source",
6971
+ "allowed"
6523
6972
  ];
6524
6973
  STEP_ERROR_DETAIL_MAX_BYTES = 8 * 1024;
6525
6974
  DETAIL_MAX_DEPTH = 4;
6526
6975
  DETAIL_MAX_ITEMS = 100;
6527
6976
  __name(scrubDetailValue, "scrubDetailValue");
6528
- __name3(scrubDetailValue, "scrubDetailValue");
6977
+ __name4(scrubDetailValue, "scrubDetailValue");
6529
6978
  __name(stepErrorDetail, "stepErrorDetail");
6530
- __name3(stepErrorDetail, "stepErrorDetail");
6979
+ __name4(stepErrorDetail, "stepErrorDetail");
6531
6980
  MAX_HOLIDAYS = 366;
6532
6981
  MAX_WALK_DAYS = 400;
6533
6982
  HHMM = /^([01]\d|2[0-3]):([0-5]\d)$/;
@@ -6547,18 +6996,18 @@ var init_dist2 = __esm({
6547
6996
  };
6548
6997
  supportedTz = null;
6549
6998
  __name(timeZoneSupported, "timeZoneSupported");
6550
- __name3(timeZoneSupported, "timeZoneSupported");
6999
+ __name4(timeZoneSupported, "timeZoneSupported");
6551
7000
  __name(validateBusinessHours, "validateBusinessHours");
6552
- __name3(validateBusinessHours, "validateBusinessHours");
7001
+ __name4(validateBusinessHours, "validateBusinessHours");
6553
7002
  __name(toMinutes, "toMinutes");
6554
- __name3(toMinutes, "toMinutes");
7003
+ __name4(toMinutes, "toMinutes");
6555
7004
  __name(resolveCalendar, "resolveCalendar");
6556
- __name3(resolveCalendar, "resolveCalendar");
7005
+ __name4(resolveCalendar, "resolveCalendar");
6557
7006
  __name(assertValid, "assertValid");
6558
- __name3(assertValid, "assertValid");
7007
+ __name4(assertValid, "assertValid");
6559
7008
  fmtCache = /* @__PURE__ */ new Map();
6560
7009
  __name(formatter, "formatter");
6561
- __name3(formatter, "formatter");
7010
+ __name4(formatter, "formatter");
6562
7011
  WEEKDAYS = {
6563
7012
  Sun: 0,
6564
7013
  Mon: 1,
@@ -6569,25 +7018,25 @@ var init_dist2 = __esm({
6569
7018
  Sat: 6
6570
7019
  };
6571
7020
  __name(localParts, "localParts");
6572
- __name3(localParts, "localParts");
7021
+ __name4(localParts, "localParts");
6573
7022
  __name(offsetAt, "offsetAt");
6574
- __name3(offsetAt, "offsetAt");
7023
+ __name4(offsetAt, "offsetAt");
6575
7024
  __name(localToUtc, "localToUtc");
6576
- __name3(localToUtc, "localToUtc");
7025
+ __name4(localToUtc, "localToUtc");
6577
7026
  __name(sameWall, "sameWall");
6578
- __name3(sameWall, "sameWall");
7027
+ __name4(sameWall, "sameWall");
6579
7028
  __name(ymd, "ymd");
6580
- __name3(ymd, "ymd");
7029
+ __name4(ymd, "ymd");
6581
7030
  __name(windowOf, "windowOf");
6582
- __name3(windowOf, "windowOf");
7031
+ __name4(windowOf, "windowOf");
6583
7032
  __name(nextDayAnchor, "nextDayAnchor");
6584
- __name3(nextDayAnchor, "nextDayAnchor");
7033
+ __name4(nextDayAnchor, "nextDayAnchor");
6585
7034
  __name(addBusinessTime, "addBusinessTime");
6586
- __name3(addBusinessTime, "addBusinessTime");
7035
+ __name4(addBusinessTime, "addBusinessTime");
6587
7036
  __name(roundToBusinessTime, "roundToBusinessTime");
6588
- __name3(roundToBusinessTime, "roundToBusinessTime");
7037
+ __name4(roundToBusinessTime, "roundToBusinessTime");
6589
7038
  __name(isBusinessTime, "isBusinessTime");
6590
- __name3(isBusinessTime, "isBusinessTime");
7039
+ __name4(isBusinessTime, "isBusinessTime");
6591
7040
  JSON_PATCH_OPS = [
6592
7041
  "replace",
6593
7042
  "add",
@@ -6598,27 +7047,27 @@ var init_dist2 = __esm({
6598
7047
  JSON_PATCH_MAX_TOTAL_BYTES = 1024 * 1024;
6599
7048
  SEGMENT_RE = /^([A-Za-z_$][\w$-]*)((?:\[(?:\*|\d+)\])*)$/;
6600
7049
  __name(parseEditablePath, "parseEditablePath");
6601
- __name3(parseEditablePath, "parseEditablePath");
7050
+ __name4(parseEditablePath, "parseEditablePath");
6602
7051
  __name(isEditablePathEntry, "isEditablePathEntry");
6603
- __name3(isEditablePathEntry, "isEditablePathEntry");
7052
+ __name4(isEditablePathEntry, "isEditablePathEntry");
6604
7053
  __name(pointerToSegments, "pointerToSegments");
6605
- __name3(pointerToSegments, "pointerToSegments");
7054
+ __name4(pointerToSegments, "pointerToSegments");
6606
7055
  __name(pointerToDotPath, "pointerToDotPath");
6607
- __name3(pointerToDotPath, "pointerToDotPath");
7056
+ __name4(pointerToDotPath, "pointerToDotPath");
6608
7057
  __name(coveredBy, "coveredBy");
6609
- __name3(coveredBy, "coveredBy");
7058
+ __name4(coveredBy, "coveredBy");
6610
7059
  __name(matchesEditablePath, "matchesEditablePath");
6611
- __name3(matchesEditablePath, "matchesEditablePath");
7060
+ __name4(matchesEditablePath, "matchesEditablePath");
6612
7061
  __name(changedPointers, "changedPointers");
6613
- __name3(changedPointers, "changedPointers");
7062
+ __name4(changedPointers, "changedPointers");
6614
7063
  __name(escapePointer, "escapePointer");
6615
- __name3(escapePointer, "escapePointer");
7064
+ __name4(escapePointer, "escapePointer");
6616
7065
  __name(validateJsonPatch, "validateJsonPatch");
6617
- __name3(validateJsonPatch, "validateJsonPatch");
7066
+ __name4(validateJsonPatch, "validateJsonPatch");
6618
7067
  __name(applyJsonPatch, "applyJsonPatch");
6619
- __name3(applyJsonPatch, "applyJsonPatch");
7068
+ __name4(applyJsonPatch, "applyJsonPatch");
6620
7069
  __name(rebaseItemPointer, "rebaseItemPointer");
6621
- __name3(rebaseItemPointer, "rebaseItemPointer");
7070
+ __name4(rebaseItemPointer, "rebaseItemPointer");
6622
7071
  WORKFLOW_SCHEDULE_TYPES = [
6623
7072
  "cron",
6624
7073
  "interval",
@@ -6626,22 +7075,26 @@ var init_dist2 = __esm({
6626
7075
  ];
6627
7076
  WORKFLOW_SCHEDULE_SHAPE_ISSUE = "schedule-shape-invalid";
6628
7077
  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");
7078
+ WORKFLOW_SCHEDULE_RUN_AS = [
7079
+ "installer",
7080
+ "system"
7081
+ ];
7082
+ isObject = /* @__PURE__ */ __name4((v) => typeof v === "object" && v !== null && !Array.isArray(v), "isObject");
6630
7083
  __name(validateWorkflowSchedule, "validateWorkflowSchedule");
6631
- __name3(validateWorkflowSchedule, "validateWorkflowSchedule");
7084
+ __name4(validateWorkflowSchedule, "validateWorkflowSchedule");
6632
7085
  WORKFLOW_ENV_OVERLAY_MAX_KEYS = 64;
6633
7086
  WORKFLOW_ENV_OVERLAY_MAX_VALUE_BYTES = 4096;
6634
7087
  WORKFLOW_ENV_TEMPLATE_SECRET_KEY_RE = /(SECRET|TOKEN|KEY|PASSWORD)$/;
6635
- isEnvRef = /* @__PURE__ */ __name3((v) => typeof v === "object" && v !== null && !Array.isArray(v) && typeof v.__envRef === "string" && Object.keys(v).length === 1, "isEnvRef");
6636
- looksLikeEmbeddedJson = /* @__PURE__ */ __name3((s) => s.length > 1 && s[0] === "{" && s.includes("__envRef"), "looksLikeEmbeddedJson");
7088
+ isEnvRef = /* @__PURE__ */ __name4((v) => typeof v === "object" && v !== null && !Array.isArray(v) && typeof v.__envRef === "string" && Object.keys(v).length === 1, "isEnvRef");
7089
+ looksLikeEmbeddedJson = /* @__PURE__ */ __name4((s) => s.length > 1 && s[0] === "{" && s.includes("__envRef"), "looksLikeEmbeddedJson");
6637
7090
  __name(collectEnvTemplateKeys, "collectEnvTemplateKeys");
6638
- __name3(collectEnvTemplateKeys, "collectEnvTemplateKeys");
7091
+ __name4(collectEnvTemplateKeys, "collectEnvTemplateKeys");
6639
7092
  __name(substituteEnvRefs, "substituteEnvRefs");
6640
- __name3(substituteEnvRefs, "substituteEnvRefs");
7093
+ __name4(substituteEnvRefs, "substituteEnvRefs");
6641
7094
  __name(hashEnvOverlay, "hashEnvOverlay");
6642
- __name3(hashEnvOverlay, "hashEnvOverlay");
7095
+ __name4(hashEnvOverlay, "hashEnvOverlay");
6643
7096
  __name(validateEnvOverlay, "validateEnvOverlay");
6644
- __name3(validateEnvOverlay, "validateEnvOverlay");
7097
+ __name4(validateEnvOverlay, "validateEnvOverlay");
6645
7098
  ZERO = {
6646
7099
  steps: {
6647
7100
  min: 0,
@@ -6654,24 +7107,30 @@ var init_dist2 = __esm({
6654
7107
  agentCalls: 0
6655
7108
  };
6656
7109
  __name(add, "add");
6657
- __name3(add, "add");
7110
+ __name4(add, "add");
6658
7111
  __name(scale, "scale");
6659
- __name3(scale, "scale");
7112
+ __name4(scale, "scale");
6660
7113
  __name(armEntry, "armEntry");
6661
- __name3(armEntry, "armEntry");
7114
+ __name4(armEntry, "armEntry");
6662
7115
  __name(ofEntry, "ofEntry");
6663
- __name3(ofEntry, "ofEntry");
7116
+ __name4(ofEntry, "ofEntry");
6664
7117
  __name(estimateGraph, "estimateGraph");
6665
- __name3(estimateGraph, "estimateGraph");
6666
- isRecord2 = /* @__PURE__ */ __name3((v) => !!v && typeof v === "object" && !Array.isArray(v), "isRecord");
7118
+ __name4(estimateGraph, "estimateGraph");
7119
+ isRecord2 = /* @__PURE__ */ __name4((v) => !!v && typeof v === "object" && !Array.isArray(v), "isRecord");
6667
7120
  __name(singleStepsOf, "singleStepsOf");
6668
- __name3(singleStepsOf, "singleStepsOf");
7121
+ __name4(singleStepsOf, "singleStepsOf");
6669
7122
  __name(entriesOf, "entriesOf");
6670
- __name3(entriesOf, "entriesOf");
7123
+ __name4(entriesOf, "entriesOf");
6671
7124
  __name(inheritTargets, "inheritTargets");
6672
- __name3(inheritTargets, "inheritTargets");
7125
+ __name4(inheritTargets, "inheritTargets");
6673
7126
  __name(needsInheritedWorkspace, "needsInheritedWorkspace");
6674
- __name3(needsInheritedWorkspace, "needsInheritedWorkspace");
7127
+ __name4(needsInheritedWorkspace, "needsInheritedWorkspace");
7128
+ __name(armEntry2, "armEntry2");
7129
+ __name4(armEntry2, "armEntry");
7130
+ __name(entryHasJobTier, "entryHasJobTier");
7131
+ __name4(entryHasJobTier, "entryHasJobTier");
7132
+ __name(graphHasJobTierStep, "graphHasJobTierStep");
7133
+ __name4(graphHasJobTierStep, "graphHasJobTierStep");
6675
7134
  }
6676
7135
  });
6677
7136
 
@@ -6808,7 +7267,7 @@ function defineWorkflow(cfg, build) {
6808
7267
  if (!(wf instanceof LuaWorkflow)) throw new LuaWorkflowBuildError("invalid-envelope", "defineWorkflow: the build callback must return `wf\u2026.commit()`");
6809
7268
  return wf;
6810
7269
  }
6811
- var init2, state2, lit2, eq2, ne2, gt2, gte2, lt2, lte2, inSet2, notIn2, exists2, notExists2, truthy2, falsy2, and2, or2, not2, fromInit2, fromStep2, value2, template2, fromRequest2, rows2, fromKnowledge2, LuaWorkflowBuildError, STEP_ID_RE, WORKFLOW_NAME_RE, WORKFLOW_MAX_PARALLEL_ARMS, WORKFLOW_MAX_FOREACH_CONCURRENCY, WORKFLOW_MAX_FOREACH_ITEMS, WORKFLOW_WORKER_MAX_TIMEOUT_SECONDS, WORKFLOW_JOB_SEGMENT_MAX_SECONDS, WORKFLOW_JOB_MAX_TIMEOUT_SECONDS, WORKFLOW_LOOP_INTERVAL_MAX_SECONDS, WORKFLOW_FOREACH_RATE_MAX_PER_SECOND, WORKFLOW_SPECIALIST_ROLE_MAX_INSTRUCTIONS, WORKFLOW_DEFAULT_MAX_DURATION_SECONDS, WORKFLOW_HITL_MAX_DURATION_SECONDS, SECRET_KEY_RE, isZod, defined, templateText, assertNoClosure, assertPredicate, assertRetry, assertTimeout, envRefKeys, refToDescriptor, __workflowCommitHook, LuaWorkflow, isHitlEntry, WorkflowBuilderImpl, EDITABLE_PATH_RE2;
7270
+ var init2, state2, lit2, eq2, ne2, gt2, gte2, lt2, lte2, inSet2, notIn2, exists2, notExists2, truthy2, falsy2, and2, or2, not2, fromInit2, fromStep2, value2, template2, fromRequest2, rows2, fromKnowledge2, LuaWorkflowBuildError, STEP_ID_RE, WORKFLOW_NAME_RE, WORKFLOW_MAX_PARALLEL_ARMS, WORKFLOW_MAX_FOREACH_CONCURRENCY, WORKFLOW_MAX_FOREACH_ITEMS, WORKFLOW_WORKER_MAX_TIMEOUT_SECONDS, WORKFLOW_JOB_SEGMENT_MAX_SECONDS, WORKFLOW_JOB_MAX_TIMEOUT_SECONDS, WORKFLOW_LOOP_INTERVAL_MAX_SECONDS, WORKFLOW_FOREACH_RATE_MAX_PER_SECOND, WORKFLOW_SPECIALIST_ROLE_MAX_INSTRUCTIONS, WORKFLOW_DEFAULT_MAX_DURATION_SECONDS, WORKFLOW_HITL_MAX_DURATION_SECONDS, SECRET_KEY_RE, isZod, defined, templateText, assertNoClosure, assertPredicate, assertRetry, assertTimeout, envRefKeys, foreachItemsNotLowered, refToDescriptor, __workflowCommitHook, LuaWorkflow, isHitlEntry, WorkflowBuilderImpl, EDITABLE_PATH_RE2;
6812
7271
  var init_workflow = __esm({
6813
7272
  "src/types/workflow.ts"() {
6814
7273
  "use strict";
@@ -6927,6 +7386,7 @@ var init_workflow = __esm({
6927
7386
  }
6928
7387
  for (const inner of Object.values(v)) envRefKeys(inner, into);
6929
7388
  }, "envRefKeys");
7389
+ foreachItemsNotLowered = /* @__PURE__ */ __name((what) => new LuaWorkflowBuildError("invalid-envelope", `foreach.items takes fromInit(path) / fromStep(step, path) or an initData.* / stepResults.* ref \u2014 ${what} is not a foreach source; .map({ '': \u2026 }, { id }) before the foreach instead`), "foreachItemsNotLowered");
6930
7390
  refToDescriptor = /* @__PURE__ */ __name((items) => {
6931
7391
  if (!items) throw new LuaWorkflowBuildError("invalid-envelope", "foreach.items needs a ref");
6932
7392
  if ("initData" in items && items.initData === true) {
@@ -6936,11 +7396,14 @@ var init_workflow = __esm({
6936
7396
  };
6937
7397
  }
6938
7398
  if ("step" in items && typeof items.step === "string" && !("path" in items && items.path.startsWith("stepResults"))) {
7399
+ if ("rows" in items) throw foreachItemsNotLowered("rows(\u2026) (a paged dataset)");
6939
7400
  return {
6940
7401
  step: items.step,
6941
7402
  path: items.path
6942
7403
  };
6943
7404
  }
7405
+ if ("step" in items && Array.isArray(items.step)) throw foreachItemsNotLowered("a fan-in fromStep([\u2026])");
7406
+ if (typeof items.path !== "string") throw foreachItemsNotLowered("value(\u2026) / template(\u2026) / fromRequest(\u2026) / fromKnowledge(\u2026)");
6944
7407
  const path3 = items.path;
6945
7408
  if (path3.startsWith("initData")) return {
6946
7409
  initData: true,
@@ -7671,307 +8134,69 @@ var init_auth_error = __esm({
7671
8134
  }
7672
8135
  });
7673
8136
 
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
8137
+ // src/utils/package-root.ts
8138
+ import { readFileSync, existsSync } from "fs";
8139
+ import { fileURLToPath, pathToFileURL } from "url";
8140
+ import { dirname, join as join2 } from "path";
8141
+ function locate() {
8142
+ if (cachedRoot && cachedPkg) return {
8143
+ root: cachedRoot,
8144
+ pkg: cachedPkg
7683
8145
  };
8146
+ let dir = dirname(fileURLToPath(import.meta.url));
8147
+ while (true) {
8148
+ const candidate = join2(dir, "package.json");
8149
+ if (existsSync(candidate)) {
8150
+ try {
8151
+ const parsed = JSON.parse(readFileSync(candidate, "utf8"));
8152
+ if (parsed?.name === "lua-cli") {
8153
+ cachedRoot = dir;
8154
+ cachedPkg = parsed;
8155
+ return {
8156
+ root: dir,
8157
+ pkg: parsed
8158
+ };
8159
+ }
8160
+ } catch {
8161
+ }
8162
+ }
8163
+ const parent = dirname(dir);
8164
+ if (parent === dir) break;
8165
+ dir = parent;
8166
+ }
8167
+ throw new Error("Could not locate lua-cli package root from " + fileURLToPath(import.meta.url));
7684
8168
  }
7685
- function isAccessDeniedError(error) {
7686
- if (CliError.isCliError(error)) return error.statusCode === 403;
7687
- return error instanceof Error && error.message.startsWith("Access denied (403)");
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}`;
8169
+ function getCliVersion() {
8170
+ try {
8171
+ return locate().pkg.version;
8172
+ } catch {
8173
+ return "0.0.0";
8174
+ }
7699
8175
  }
7700
- function authHint(error) {
7701
- if (error.suppressDefaultRemediation) return void 0;
7702
- if (error.reason === "no_agent_access") {
7703
- return [
7704
- "Your API key is valid, but it does not have access to the agentId in lua.skill.yaml \u2014 the agent belongs",
7705
- "to another account or organization, was deleted or transferred, or the yaml was copied from another project.",
7706
- "Check the configured agent and switch if needed:",
7707
- " lua agents (list agents you have access to)",
7708
- " lua init (re-select the agent for this project)"
7709
- ].join("\n");
8176
+ var cachedRoot, cachedPkg;
8177
+ var init_package_root = __esm({
8178
+ "src/utils/package-root.ts"() {
8179
+ "use strict";
8180
+ cachedRoot = null;
8181
+ cachedPkg = null;
8182
+ __name(locate, "locate");
8183
+ __name(getCliVersion, "getCliVersion");
7710
8184
  }
7711
- return "Re-authenticate or check your API key: lua auth configure \xB7 https://admin.heylua.ai";
8185
+ });
8186
+
8187
+ // src/utils/lua-fetch.ts
8188
+ function luaClientHeaderValue() {
8189
+ return formatLuaClientHeader("cli", getCliVersion());
7712
8190
  }
7713
- function numericStatus(error) {
7714
- const candidate = error.statusCode ?? error.status;
7715
- return typeof candidate === "number" && Number.isFinite(candidate) ? candidate : void 0;
7716
- }
7717
- function classifyCliError(error) {
7718
- if (CliError.isCliError(error)) {
7719
- return {
7720
- code: error.code,
7721
- exitCode: error.exitCode,
7722
- message: error.message,
7723
- hint: error.hint,
7724
- statusCode: error.statusCode,
7725
- serverCode: error.serverCode,
7726
- issues: error.issues
7727
- };
7728
- }
7729
- if (AuthenticationError.isAuthenticationError(error)) {
7730
- return {
7731
- code: "auth",
7732
- exitCode: CLI_EXIT.AUTH,
7733
- message: error.message,
7734
- hint: authHint(error)
7735
- };
7736
- }
7737
- const e = typeof error === "object" && error !== null ? error : {};
7738
- const message = typeof e.message === "string" && e.message.length > 0 ? e.message : error instanceof Error ? error.name : String(error ?? "Unknown error");
7739
- if (e.name === "WorkflowLocalUsageError" || typeof e.code === "string" && e.code.startsWith("commander.")) {
7740
- return {
7741
- code: "usage",
7742
- exitCode: CLI_EXIT.USAGE,
7743
- message
7744
- };
7745
- }
7746
- const status = numericStatus(e);
7747
- if (status !== void 0) {
7748
- const statusCode = status;
7749
- if (status === 401) return {
7750
- code: "auth",
7751
- exitCode: CLI_EXIT.AUTH,
7752
- message,
7753
- statusCode
7754
- };
7755
- if (status === 403) return {
7756
- code: "forbidden",
7757
- exitCode: CLI_EXIT.FORBIDDEN,
7758
- message,
7759
- statusCode
7760
- };
7761
- if (status === 404) return {
7762
- code: "not_found",
7763
- exitCode: CLI_EXIT.NOT_FOUND,
7764
- message,
7765
- statusCode
7766
- };
7767
- if (status >= 400 && status < 500) return {
7768
- code: `http_${status}`,
7769
- exitCode: CLI_EXIT.FORBIDDEN,
7770
- message,
7771
- statusCode
7772
- };
7773
- if (status >= 500 || status === 0) return {
7774
- code: "unavailable",
7775
- exitCode: CLI_EXIT.UNAVAILABLE,
7776
- message,
7777
- statusCode
7778
- };
7779
- }
7780
- const causeCode = e.cause?.code;
7781
- 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)) {
7782
- return {
7783
- code: "unavailable",
7784
- exitCode: CLI_EXIT.UNAVAILABLE,
7785
- message,
7786
- hint: UNAVAILABLE_HINT
7787
- };
7788
- }
7789
- return {
7790
- code: "error",
7791
- exitCode: CLI_EXIT.ERROR,
7792
- message
7793
- };
7794
- }
7795
- var CLI_EXIT, CliError, NETWORK_ERRNO, NETWORK_MESSAGE, UNAVAILABLE_HINT, VENDOR_LABELS;
7796
- var init_cli_error = __esm({
7797
- "src/errors/cli.error.ts"() {
7798
- "use strict";
7799
- init_auth_error();
7800
- CLI_EXIT = {
7801
- OK: 0,
7802
- ERROR: 1,
7803
- USAGE: 2,
7804
- NOT_FOUND: 3,
7805
- AUTH: 9,
7806
- FORBIDDEN: 10,
7807
- UNAVAILABLE: 11
7808
- };
7809
- __name(apiErrorDetail, "apiErrorDetail");
7810
- CliError = class _CliError extends Error {
7811
- static {
7812
- __name(this, "CliError");
7813
- }
7814
- isCliError = true;
7815
- code;
7816
- exitCode;
7817
- hint;
7818
- statusCode;
7819
- serverCode;
7820
- issues;
7821
- constructor(code, message, options = {}) {
7822
- super(message);
7823
- this.name = "CliError";
7824
- this.code = code;
7825
- this.exitCode = options.exitCode ?? CLI_EXIT.ERROR;
7826
- this.hint = options.hint;
7827
- this.statusCode = options.statusCode;
7828
- this.serverCode = options.serverCode;
7829
- this.issues = options.issues?.length ? options.issues : void 0;
7830
- if (Error.captureStackTrace) Error.captureStackTrace(this, _CliError);
7831
- }
7832
- /** Bad arguments, an unknown action, no project — exit 2. */
7833
- static usage(message, hint) {
7834
- return new _CliError("usage", message, {
7835
- exitCode: CLI_EXIT.USAGE,
7836
- hint
7837
- });
7838
- }
7839
- /** The named thing does not exist — exit 3. */
7840
- static notFound(message, hint) {
7841
- return new _CliError("not_found", message, {
7842
- exitCode: CLI_EXIT.NOT_FOUND,
7843
- hint,
7844
- statusCode: 404
7845
- });
7846
- }
7847
- /** The credential may not do this — exit 10. */
7848
- static forbidden(message, hint) {
7849
- return new _CliError("forbidden", message, {
7850
- exitCode: CLI_EXIT.FORBIDDEN,
7851
- hint,
7852
- statusCode: 403
7853
- });
7854
- }
7855
- /**
7856
- * An API refusal the site already holds the status of (LUA-766) — classified by the same table the top-level
7857
- * classifier applies to an untyped error: 401 auth · 403 forbidden · 404 not_found · other 4xx `http_<status>`
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).
7860
- * A command that reads `response.error.statusCode` throws through here, so `lua logs` on a 503 exits 11 like
7861
- * every other verb instead of printing the message itself and then throwing an exit-1 `Error`.
7862
- */
7863
- static fromStatus(statusCode, message, hint, detail = {}) {
7864
- const reported = classifyCliError(Object.assign(new Error(message), {
7865
- statusCode
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;
7868
- const classHint = reported.exitCode === CLI_EXIT.UNAVAILABLE ? UNAVAILABLE_HINT : reported.hint;
7869
- return new _CliError(reported.code, message, {
7870
- exitCode: reported.exitCode,
7871
- hint: hint ?? codeHint ?? classHint,
7872
- statusCode,
7873
- serverCode: detail.serverCode,
7874
- issues: detail.issues
7875
- });
7876
- }
7877
- static isCliError(error) {
7878
- return error instanceof _CliError || typeof error === "object" && error !== null && error.isCliError === true;
7879
- }
7880
- };
7881
- __name(isAccessDeniedError, "isAccessDeniedError");
7882
- NETWORK_ERRNO = /* @__PURE__ */ new Set([
7883
- "ECONNREFUSED",
7884
- "ECONNRESET",
7885
- "ENOTFOUND",
7886
- "ETIMEDOUT",
7887
- "EAI_AGAIN",
7888
- "EPIPE",
7889
- "EHOSTUNREACH",
7890
- "ENETUNREACH",
7891
- "UND_ERR_CONNECT_TIMEOUT",
7892
- "UND_ERR_HEADERS_TIMEOUT",
7893
- "UND_ERR_BODY_TIMEOUT",
7894
- "UND_ERR_SOCKET"
7895
- ]);
7896
- NETWORK_MESSAGE = /fetch failed|socket hang up|network request failed|request timeout|ECONNREFUSED|ENOTFOUND/i;
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");
7906
- __name(authHint, "authHint");
7907
- __name(numericStatus, "numericStatus");
7908
- __name(classifyCliError, "classifyCliError");
7909
- }
7910
- });
7911
-
7912
- // src/utils/package-root.ts
7913
- import { readFileSync, existsSync } from "fs";
7914
- import { fileURLToPath, pathToFileURL } from "url";
7915
- import { dirname, join as join2 } from "path";
7916
- function locate() {
7917
- if (cachedRoot && cachedPkg) return {
7918
- root: cachedRoot,
7919
- pkg: cachedPkg
7920
- };
7921
- let dir = dirname(fileURLToPath(import.meta.url));
7922
- while (true) {
7923
- const candidate = join2(dir, "package.json");
7924
- if (existsSync(candidate)) {
7925
- try {
7926
- const parsed = JSON.parse(readFileSync(candidate, "utf8"));
7927
- if (parsed?.name === "lua-cli") {
7928
- cachedRoot = dir;
7929
- cachedPkg = parsed;
7930
- return {
7931
- root: dir,
7932
- pkg: parsed
7933
- };
7934
- }
7935
- } catch {
7936
- }
7937
- }
7938
- const parent = dirname(dir);
7939
- if (parent === dir) break;
7940
- dir = parent;
7941
- }
7942
- throw new Error("Could not locate lua-cli package root from " + fileURLToPath(import.meta.url));
7943
- }
7944
- function getCliVersion() {
7945
- try {
7946
- return locate().pkg.version;
7947
- } catch {
7948
- return "0.0.0";
7949
- }
7950
- }
7951
- var cachedRoot, cachedPkg;
7952
- var init_package_root = __esm({
7953
- "src/utils/package-root.ts"() {
7954
- "use strict";
7955
- cachedRoot = null;
7956
- cachedPkg = null;
7957
- __name(locate, "locate");
7958
- __name(getCliVersion, "getCliVersion");
7959
- }
7960
- });
7961
-
7962
- // src/utils/lua-fetch.ts
7963
- function luaClientHeaderValue() {
7964
- return formatLuaClientHeader("cli", getCliVersion());
7965
- }
7966
- function headerRecord(headers) {
7967
- if (!headers) return {};
7968
- if (headers instanceof Headers) return Object.fromEntries(headers.entries());
7969
- if (Array.isArray(headers)) return Object.fromEntries(headers);
7970
- const record = {};
7971
- for (const [name, value3] of Object.entries(headers)) {
7972
- if (typeof value3 === "string") record[name] = value3;
7973
- }
7974
- return record;
8191
+ function headerRecord(headers) {
8192
+ if (!headers) return {};
8193
+ if (headers instanceof Headers) return Object.fromEntries(headers.entries());
8194
+ if (Array.isArray(headers)) return Object.fromEntries(headers);
8195
+ const record = {};
8196
+ for (const [name, value3] of Object.entries(headers)) {
8197
+ if (typeof value3 === "string") record[name] = value3;
8198
+ }
8199
+ return record;
7975
8200
  }
7976
8201
  function luaFetch(input, init3 = {}) {
7977
8202
  const headers = headerRecord(init3.headers);
@@ -7997,21 +8222,29 @@ var init_lua_fetch = __esm({
7997
8222
 
7998
8223
  // src/services/firebase-session.ts
7999
8224
  import { z as z5 } from "zod";
8225
+ function rejectedRefreshReason(message) {
8226
+ const normalised = message.toUpperCase();
8227
+ return REJECTED_REFRESH_REASONS.find((reason) => normalised.includes(reason));
8228
+ }
8000
8229
  function requireFirebaseWebApiKey() {
8001
8230
  if (!FIREBASE_WEB_API_KEY) {
8002
8231
  throw new Error("Firebase sign-in is not configured for this CLI build.");
8003
8232
  }
8004
8233
  return FIREBASE_WEB_API_KEY;
8005
8234
  }
8006
- function uidFromFirebaseIdToken(idToken) {
8235
+ function claimsOfFirebaseIdToken(idToken) {
8007
8236
  const segments = idToken.split(".");
8008
8237
  if (segments.length !== 3 || !segments[1]) throw new Error(INVALID_FIREBASE_SESSION);
8009
- let payload;
8010
8238
  try {
8011
- payload = JSON.parse(Buffer.from(segments[1], "base64url").toString("utf8"));
8239
+ const payload = JSON.parse(Buffer.from(segments[1], "base64url").toString("utf8"));
8240
+ if (typeof payload !== "object" || payload === null) throw new Error(INVALID_FIREBASE_SESSION);
8241
+ return payload;
8012
8242
  } catch {
8013
8243
  throw new Error(INVALID_FIREBASE_SESSION);
8014
8244
  }
8245
+ }
8246
+ function uidFromFirebaseIdToken(idToken) {
8247
+ const payload = claimsOfFirebaseIdToken(idToken);
8015
8248
  const parsed = firebaseIdTokenPayloadSchema.safeParse(payload);
8016
8249
  if (parsed.success) return parsed.data.sub;
8017
8250
  throw new Error(INVALID_FIREBASE_SESSION);
@@ -8067,6 +8300,23 @@ async function fetchFirebase(url, init3, timeoutMessage) {
8067
8300
  if (timeoutId !== void 0) clearTimeout(timeoutId);
8068
8301
  }
8069
8302
  }
8303
+ async function exchangeFirebaseCustomToken(signInToken) {
8304
+ const key = requireFirebaseWebApiKey();
8305
+ const response = await fetchFirebase(`${FIREBASE_CUSTOM_TOKEN_URL}?key=${encodeURIComponent(key)}`, {
8306
+ method: "POST",
8307
+ headers: {
8308
+ "Content-Type": "application/json"
8309
+ },
8310
+ body: JSON.stringify({
8311
+ token: signInToken,
8312
+ returnSecureToken: true
8313
+ })
8314
+ }, "Firebase sign-in timed out after 15 seconds.");
8315
+ if (!response.ok) {
8316
+ throw new Error(`Firebase sign-in failed: ${await parseFirebaseError(response)}`);
8317
+ }
8318
+ return parseFirebaseSession(await response.json());
8319
+ }
8070
8320
  async function refreshFirebaseSession(session) {
8071
8321
  const key = requireFirebaseWebApiKey();
8072
8322
  const response = await fetchFirebase(`${FIREBASE_REFRESH_URL}?key=${encodeURIComponent(key)}`, {
@@ -8080,20 +8330,43 @@ async function refreshFirebaseSession(session) {
8080
8330
  }).toString()
8081
8331
  }, "Firebase session refresh timed out after 15 seconds.");
8082
8332
  if (!response.ok) {
8083
- throw new Error(`Firebase session refresh failed: ${await parseFirebaseError(response)}`);
8333
+ const reason = await parseFirebaseError(response);
8334
+ const rejected = response.status < 500 ? rejectedRefreshReason(reason) : void 0;
8335
+ if (rejected) throw new FirebaseSessionRejectedError(rejected);
8336
+ throw new Error(`Firebase session refresh failed: ${reason}`);
8084
8337
  }
8085
8338
  const refreshed = parseFirebaseSession(await response.json());
8086
8339
  if (refreshed.uid !== session.uid) throw new Error("Firebase session refresh returned a different identity.");
8087
8340
  return refreshed;
8088
8341
  }
8089
- var FIREBASE_REFRESH_URL, FIREBASE_REQUEST_TIMEOUT_MS, INVALID_FIREBASE_SESSION, customTokenResponseSchema, refreshResponseSchema, firebaseIdTokenPayloadSchema;
8342
+ var FIREBASE_CUSTOM_TOKEN_URL, FIREBASE_REFRESH_URL, FIREBASE_REQUEST_TIMEOUT_MS, INVALID_FIREBASE_SESSION, REJECTED_REFRESH_REASONS, FirebaseSessionRejectedError, customTokenResponseSchema, refreshResponseSchema, firebaseIdTokenPayloadSchema;
8090
8343
  var init_firebase_session = __esm({
8091
8344
  "src/services/firebase-session.ts"() {
8092
8345
  "use strict";
8093
8346
  init_constants();
8347
+ FIREBASE_CUSTOM_TOKEN_URL = "https://identitytoolkit.googleapis.com/v1/accounts:signInWithCustomToken";
8094
8348
  FIREBASE_REFRESH_URL = "https://securetoken.googleapis.com/v1/token";
8095
8349
  FIREBASE_REQUEST_TIMEOUT_MS = 15e3;
8096
8350
  INVALID_FIREBASE_SESSION = "Sign-in failed because Firebase returned an invalid session.";
8351
+ REJECTED_REFRESH_REASONS = [
8352
+ "TOKEN_EXPIRED",
8353
+ "USER_DISABLED",
8354
+ "USER_NOT_FOUND",
8355
+ "INVALID_REFRESH_TOKEN",
8356
+ "INVALID_GRANT_TYPE",
8357
+ "MISSING_REFRESH_TOKEN"
8358
+ ];
8359
+ __name(rejectedRefreshReason, "rejectedRefreshReason");
8360
+ FirebaseSessionRejectedError = class extends Error {
8361
+ static {
8362
+ __name(this, "FirebaseSessionRejectedError");
8363
+ }
8364
+ reason;
8365
+ constructor(reason) {
8366
+ super(`Firebase session refresh rejected: ${reason}`), this.reason = reason;
8367
+ this.name = "FirebaseSessionRejectedError";
8368
+ }
8369
+ };
8097
8370
  customTokenResponseSchema = z5.object({
8098
8371
  idToken: z5.string().min(1),
8099
8372
  refreshToken: z5.string().min(1),
@@ -8110,17 +8383,19 @@ var init_firebase_session = __esm({
8110
8383
  sub: z5.string().min(1)
8111
8384
  });
8112
8385
  __name(requireFirebaseWebApiKey, "requireFirebaseWebApiKey");
8386
+ __name(claimsOfFirebaseIdToken, "claimsOfFirebaseIdToken");
8113
8387
  __name(uidFromFirebaseIdToken, "uidFromFirebaseIdToken");
8114
8388
  __name(parseFirebaseSession, "parseFirebaseSession");
8115
8389
  __name(parseFirebaseError, "parseFirebaseError");
8116
8390
  __name(fetchFirebase, "fetchFirebase");
8391
+ __name(exchangeFirebaseCustomToken, "exchangeFirebaseCustomToken");
8117
8392
  __name(refreshFirebaseSession, "refreshFirebaseSession");
8118
8393
  }
8119
8394
  });
8120
8395
 
8121
8396
  // src/services/firebase-session-store.ts
8122
8397
  import { createHash as createHash3, randomUUID } from "crypto";
8123
- import { mkdir, open, readFile, rename, unlink } from "fs/promises";
8398
+ import { mkdir, open, readFile, rename, rm, stat, unlink, writeFile } from "fs/promises";
8124
8399
  import { join as join3 } from "path";
8125
8400
  import { z as z6 } from "zod";
8126
8401
  function environmentKey(environment) {
@@ -8131,7 +8406,10 @@ ${environment.firebaseWebApiKey}`).digest("hex").slice(0, 16);
8131
8406
  function isMissing(error) {
8132
8407
  return typeof error === "object" && error !== null && "code" in error && error.code === "ENOENT";
8133
8408
  }
8134
- var storedFirebaseSessionSchema, currentFirebaseSessionEnvironment, wait, FirebaseSessionStore;
8409
+ function errorCode(error) {
8410
+ return typeof error === "object" && error !== null && "code" in error ? String(error.code) : void 0;
8411
+ }
8412
+ var storedFirebaseSessionSchema, currentFirebaseSessionEnvironment, wait, LOCK_STALE_MS, LOCK_TIMEOUT_MS, FirebaseSessionStore;
8135
8413
  var init_firebase_session_store = __esm({
8136
8414
  "src/services/firebase-session-store.ts"() {
8137
8415
  "use strict";
@@ -8154,6 +8432,9 @@ var init_firebase_session_store = __esm({
8154
8432
  __name(environmentKey, "environmentKey");
8155
8433
  __name(isMissing, "isMissing");
8156
8434
  wait = /* @__PURE__ */ __name((milliseconds) => new Promise((resolve3) => setTimeout(resolve3, milliseconds)), "wait");
8435
+ LOCK_STALE_MS = 3e4;
8436
+ LOCK_TIMEOUT_MS = LOCK_STALE_MS + 5e3;
8437
+ __name(errorCode, "errorCode");
8157
8438
  FirebaseSessionStore = class {
8158
8439
  static {
8159
8440
  __name(this, "FirebaseSessionStore");
@@ -8235,27 +8516,39 @@ var init_firebase_session_store = __esm({
8235
8516
  if (!isMissing(error)) throw error;
8236
8517
  }
8237
8518
  }
8519
+ /**
8520
+ * A lock DIRECTORY, not a file: `mkdir` is atomic on every platform Node runs on, where an exclusive `open`
8521
+ * answered EPERM on Windows. The owner id inside lets a process release only its own lock, and a lock older
8522
+ * than any operation could take is treated as left behind by a crashed process and removed.
8523
+ */
8238
8524
  async withLock(operation) {
8239
8525
  await mkdir(this.directory, {
8240
8526
  recursive: true,
8241
8527
  mode: 448
8242
8528
  });
8243
8529
  const lockPath = `${this.path()}.lock`;
8530
+ const ownerPath = join3(lockPath, "owner");
8244
8531
  const lockOwner = randomUUID();
8245
- const deadline = Date.now() + 2e4;
8532
+ const deadline = Date.now() + LOCK_TIMEOUT_MS;
8246
8533
  while (true) {
8247
8534
  try {
8248
- const handle = await open(lockPath, "wx", 384);
8249
- try {
8250
- await handle.writeFile(lockOwner, "utf8");
8251
- await handle.sync();
8252
- } finally {
8253
- await handle.close();
8254
- }
8255
- break;
8535
+ await mkdir(lockPath, {
8536
+ mode: 448
8537
+ });
8538
+ await writeFile(ownerPath, lockOwner, {
8539
+ encoding: "utf8",
8540
+ mode: 384
8541
+ });
8542
+ if (await readFile(ownerPath, "utf8") === lockOwner) break;
8256
8543
  } catch (error) {
8257
- const code = typeof error === "object" && error !== null && "code" in error ? error.code : void 0;
8258
- if (code !== "EEXIST") throw error;
8544
+ if (errorCode(error) !== "EEXIST") throw error;
8545
+ if (await this.isStaleLock(lockPath)) {
8546
+ await rm(lockPath, {
8547
+ recursive: true,
8548
+ force: true
8549
+ });
8550
+ continue;
8551
+ }
8259
8552
  if (Date.now() >= deadline) {
8260
8553
  throw new Error("Timed out waiting for another Lua CLI process to finish updating the session.");
8261
8554
  }
@@ -8266,115 +8559,480 @@ var init_firebase_session_store = __esm({
8266
8559
  return await operation();
8267
8560
  } finally {
8268
8561
  try {
8269
- if (await readFile(lockPath, "utf8") === lockOwner) await unlink(lockPath);
8562
+ if (await readFile(ownerPath, "utf8") === lockOwner) await rm(lockPath, {
8563
+ recursive: true,
8564
+ force: true
8565
+ });
8270
8566
  } catch (error) {
8271
8567
  if (!isMissing(error)) throw error;
8272
8568
  }
8273
8569
  }
8274
8570
  }
8571
+ async isStaleLock(lockPath) {
8572
+ try {
8573
+ return Date.now() - (await stat(lockPath)).mtimeMs > LOCK_STALE_MS;
8574
+ } catch (error) {
8575
+ return isMissing(error);
8576
+ }
8577
+ }
8578
+ };
8579
+ }
8580
+ });
8581
+
8582
+ // src/services/request-credential.ts
8583
+ import "dotenv/config";
8584
+ import { readFileSync as readFileSync2, unlinkSync } from "fs";
8585
+ function sessionSignedOutError() {
8586
+ return new AuthenticationError("Your Lua CLI session was signed out.\n\n Signing out of the Lua dashboard, desktop or mobile app also ends CLI sessions.\n Run `lua auth configure` to sign in again.", "invalid_credentials", void 0, true);
8587
+ }
8588
+ function loadStoredApiKey() {
8589
+ try {
8590
+ return readFileSync2(CREDENTIALS_FILE, "utf8").trim() || null;
8591
+ } catch {
8592
+ return null;
8593
+ }
8594
+ }
8595
+ function isRequestCredential(value3) {
8596
+ return typeof value3 !== "string";
8597
+ }
8598
+ async function bearerFor(credential) {
8599
+ return isRequestCredential(credential) ? credential.bearer() : credential;
8600
+ }
8601
+ async function registerSessionIfNeeded(live, authUrl) {
8602
+ try {
8603
+ if (typeof claimsOfFirebaseIdToken(live.idToken)[LUA_SESSION_ID_CLAIM] === "string") return void 0;
8604
+ const response = await luaFetch(`${authUrl}/auth/sessions/register`, {
8605
+ method: "POST",
8606
+ headers: {
8607
+ Authorization: `Bearer ${live.idToken}`
8608
+ }
8609
+ });
8610
+ if (!response.ok) return void 0;
8611
+ const registered = await response.json().catch(() => null);
8612
+ if (typeof registered?.token !== "string") return void 0;
8613
+ const exchanged = await exchangeFirebaseCustomToken(registered.token);
8614
+ return exchanged.uid === live.uid ? exchanged : void 0;
8615
+ } catch {
8616
+ return void 0;
8617
+ }
8618
+ }
8619
+ async function resolveRequestCredential() {
8620
+ if (process.env.LUA_API_KEY) return new StaticRequestCredential(process.env.LUA_API_KEY, "environment");
8621
+ const store = new FirebaseSessionStore();
8622
+ const session = await store.read();
8623
+ if (session) return new FirebaseRequestCredential(store, session);
8624
+ const storedApiKey = loadStoredApiKey();
8625
+ if (storedApiKey) return new StaticRequestCredential(storedApiKey, "stored");
8626
+ throw new AuthenticationError("No Lua CLI authentication found. Run `lua auth configure` or set LUA_API_KEY.", "invalid_credentials", void 0, true);
8627
+ }
8628
+ async function clearStoredFirebaseSession() {
8629
+ const store = new FirebaseSessionStore();
8630
+ const session = await store.read();
8631
+ return session ? store.clearIfGeneration(session.generation) : false;
8632
+ }
8633
+ var StaticRequestCredential, FirebaseRequestCredential;
8634
+ var init_request_credential = __esm({
8635
+ "src/services/request-credential.ts"() {
8636
+ "use strict";
8637
+ init_dist();
8638
+ init_constants();
8639
+ init_auth_error();
8640
+ init_lua_fetch();
8641
+ init_firebase_session();
8642
+ init_firebase_session_store();
8643
+ __name(sessionSignedOutError, "sessionSignedOutError");
8644
+ __name(loadStoredApiKey, "loadStoredApiKey");
8645
+ __name(isRequestCredential, "isRequestCredential");
8646
+ __name(bearerFor, "bearerFor");
8647
+ StaticRequestCredential = class StaticRequestCredential2 {
8648
+ static {
8649
+ __name(this, "StaticRequestCredential");
8650
+ }
8651
+ apiKey;
8652
+ descriptor;
8653
+ constructor(apiKey, source) {
8654
+ this.apiKey = apiKey;
8655
+ this.descriptor = {
8656
+ kind: "api-key",
8657
+ source
8658
+ };
8659
+ }
8660
+ async bearer() {
8661
+ return this.apiKey;
8662
+ }
8663
+ };
8664
+ FirebaseRequestCredential = class FirebaseRequestCredential2 {
8665
+ static {
8666
+ __name(this, "FirebaseRequestCredential");
8667
+ }
8668
+ store;
8669
+ descriptor;
8670
+ liveSession;
8671
+ refresh;
8672
+ constructor(store, stored) {
8673
+ this.store = store;
8674
+ this.descriptor = {
8675
+ kind: "first-party-session",
8676
+ source: "stored",
8677
+ uid: stored.firebaseUid
8678
+ };
8679
+ }
8680
+ async bearer() {
8681
+ if (this.liveSession && this.liveSession.expiresAt - Date.now() > 6e4) return this.liveSession.idToken;
8682
+ if (!this.refresh) this.refresh = this.refreshBearer().finally(() => this.refresh = void 0);
8683
+ return this.refresh;
8684
+ }
8685
+ async refreshBearer() {
8686
+ let live;
8687
+ let rejected = false;
8688
+ await this.store.update(async (stored) => {
8689
+ if (!stored) throw sessionSignedOutError();
8690
+ try {
8691
+ live = await refreshFirebaseSession({
8692
+ idToken: "",
8693
+ refreshToken: stored.refreshToken,
8694
+ expiresAt: 0,
8695
+ uid: stored.firebaseUid
8696
+ });
8697
+ } catch (error) {
8698
+ if (!(error instanceof FirebaseSessionRejectedError)) throw error;
8699
+ rejected = true;
8700
+ return null;
8701
+ }
8702
+ live = await registerSessionIfNeeded(live, stored.authUrl) ?? live;
8703
+ return {
8704
+ ...stored,
8705
+ refreshToken: live.refreshToken,
8706
+ firebaseUid: live.uid
8707
+ };
8708
+ });
8709
+ if (rejected) throw sessionSignedOutError();
8710
+ if (!live) throw new Error("Firebase session refresh did not return a session.");
8711
+ this.liveSession = live;
8712
+ return live.idToken;
8713
+ }
8714
+ };
8715
+ __name(registerSessionIfNeeded, "registerSessionIfNeeded");
8716
+ __name(resolveRequestCredential, "resolveRequestCredential");
8717
+ __name(clearStoredFirebaseSession, "clearStoredFirebaseSession");
8718
+ }
8719
+ });
8720
+
8721
+ // src/errors/cli.error.ts
8722
+ function apiErrorDetail(error) {
8723
+ return {
8724
+ serverCode: error?.code,
8725
+ issues: error?.issues,
8726
+ upstream: error?.upstream,
8727
+ requestId: error?.requestId,
8728
+ vendor: error?.vendor,
8729
+ retryAfterSeconds: error?.retryAfterSeconds,
8730
+ reason: error?.reason,
8731
+ providerStatus: error?.providerStatus,
8732
+ keyOwner: error?.keyOwner
8733
+ };
8734
+ }
8735
+ function isAccessDeniedError(error) {
8736
+ if (CliError.isCliError(error)) return error.statusCode === 403;
8737
+ return error instanceof Error && error.message.startsWith("Access denied (403)");
8738
+ }
8739
+ function upstreamUnavailableHint(upstream, requestId) {
8740
+ const service = typeof upstream === "string" && upstream ? `its ${upstream} service` : "a service behind it";
8741
+ const ref = typeof requestId === "string" && requestId ? ` If it persists, quote request ${requestId}.` : "";
8742
+ return `The Lua API is up, but ${service} is temporarily unavailable (503 UPSTREAM_UNAVAILABLE) \u2014 retry in a moment.${ref}`;
8743
+ }
8744
+ function vendorUnavailableHint(vendor, requestId, retryAfterSeconds) {
8745
+ const name = typeof vendor === "string" && vendor ? VENDOR_LABELS[vendor] ?? vendor : "a vendor it depends on";
8746
+ const ref = typeof requestId === "string" && requestId ? ` If it persists, quote request ${requestId}.` : "";
8747
+ const retry = typeof retryAfterSeconds === "number" ? retryAfterSeconds > VENDOR_RETRY_SOON_SECONDS ? `retry in about ${Math.ceil(retryAfterSeconds)} s` : "retry in a moment" : "the request may have applied at the vendor \u2014 check before retrying";
8748
+ return `The Lua API is up, but ${name} is temporarily unavailable (503 VENDOR_UNAVAILABLE) \u2014 ${retry}.${ref}`;
8749
+ }
8750
+ function providerRejectionReasonOf(reason) {
8751
+ return typeof reason === "string" && PROVIDER_REJECTION_REASONS.has(reason) ? reason : void 0;
8752
+ }
8753
+ function providerKeyOwnerOf(keyOwner) {
8754
+ return keyOwner === "byok" || keyOwner === "platform" ? keyOwner : void 0;
8755
+ }
8756
+ function providerStatusOf(status) {
8757
+ return typeof status === "number" && Number.isInteger(status) && status >= 100 && status <= 599 ? status : void 0;
8758
+ }
8759
+ function providerRejectedHint(reason, providerStatus, keyOwner) {
8760
+ const owner = providerKeyOwnerOf(keyOwner);
8761
+ const status = providerStatusOf(providerStatus);
8762
+ const at = status !== void 0 ? ` (the provider answered HTTP ${status})` : "";
8763
+ switch (providerRejectionReasonOf(reason)) {
8764
+ case "invalid_api_key":
8765
+ if (owner === "platform") return `The provider refused Lua's platform key${at} \u2014 ${PROVIDER_REJECTED_LUA_SIDE}.`;
8766
+ return `The provider refused ${owner === "byok" ? "your organization's own API key" : "the API key behind this agent"}${at} \u2014 check the provider key in the agent's model settings at ${MODEL_SETTINGS_URL}. ${PROVIDER_REJECTED_NO_RETRY}`;
8767
+ case "forbidden":
8768
+ if (owner === "platform") return `Lua's platform key is not permitted to use this model${at} \u2014 ${PROVIDER_REJECTED_LUA_SIDE}.`;
8769
+ return `${owner === "byok" ? "Your organization's provider key" : "The provider key behind this agent"} is not permitted to use this model${at} \u2014 check the key's access with the provider, or change the agent's model. ${PROVIDER_REJECTED_NO_RETRY}`;
8770
+ case "model_not_found":
8771
+ if (owner === "platform") return `The provider does not know the model id Lua configured${at} \u2014 ${PROVIDER_REJECTED_LUA_SIDE}.`;
8772
+ return `The provider does not know this model id${at} \u2014 change the agent's model in its settings at ${MODEL_SETTINGS_URL} to one the provider serves. ${PROVIDER_REJECTED_NO_RETRY}`;
8773
+ case "quota_exhausted":
8774
+ if (owner === "platform") return `Lua's quota or billing allowance with this provider is exhausted${at} \u2014 ${PROVIDER_REJECTED_LUA_SIDE}.`;
8775
+ return `The provider's quota or billing allowance for ${owner === "byok" ? "your organization's key" : "this key"} is exhausted${at} \u2014 top up or raise the limit with the provider. ${PROVIDER_REJECTED_NO_RETRY}`;
8776
+ case "content_refused":
8777
+ return `The provider's content policy declined this request as written${at} \u2014 adjust the request and send it again.`;
8778
+ case "bad_request":
8779
+ return `The provider could not accept the request as sent${at} \u2014 adjust the request (shorter input, fewer or smaller attachments, a supported format) and send it again.`;
8780
+ default:
8781
+ return `The model provider behind this agent refused the request${at} \u2014 ${owner === "platform" ? PROVIDER_REJECTED_LUA_SIDE : owner === "byok" ? `check the agent's model settings and the provider key at ${MODEL_SETTINGS_URL}` : `check the agent's model settings, or contact Lua support if the agent uses Lua's platform key`}. ${PROVIDER_REJECTED_NO_RETRY}`;
8782
+ }
8783
+ }
8784
+ function authHint(error) {
8785
+ if (error.suppressDefaultRemediation) return void 0;
8786
+ if (error.reason === "no_agent_access") {
8787
+ return [
8788
+ "Your API key is valid, but it does not have access to the agentId in lua.skill.yaml \u2014 the agent belongs",
8789
+ "to another account or organization, was deleted or transferred, or the yaml was copied from another project.",
8790
+ "Check the configured agent and switch if needed:",
8791
+ " lua agents (list agents you have access to)",
8792
+ " lua init (re-select the agent for this project)"
8793
+ ].join("\n");
8794
+ }
8795
+ return "Re-authenticate or check your API key: lua auth configure \xB7 https://admin.heylua.ai";
8796
+ }
8797
+ function numericStatus(error) {
8798
+ const candidate = error.statusCode ?? error.status;
8799
+ return typeof candidate === "number" && Number.isFinite(candidate) ? candidate : void 0;
8800
+ }
8801
+ function classifyCliError(error) {
8802
+ if (CliError.isCliError(error)) {
8803
+ return {
8804
+ code: error.code,
8805
+ exitCode: error.exitCode,
8806
+ message: error.message,
8807
+ hint: error.hint,
8808
+ statusCode: error.statusCode,
8809
+ serverCode: error.serverCode,
8810
+ issues: error.issues
8811
+ };
8812
+ }
8813
+ if (AuthenticationError.isAuthenticationError(error)) {
8814
+ return {
8815
+ code: "auth",
8816
+ exitCode: CLI_EXIT.AUTH,
8817
+ message: error.message,
8818
+ hint: authHint(error)
8275
8819
  };
8276
8820
  }
8277
- });
8278
-
8279
- // src/services/request-credential.ts
8280
- import "dotenv/config";
8281
- import { readFileSync as readFileSync2, unlinkSync } from "fs";
8282
- function loadStoredApiKey() {
8283
- try {
8284
- return readFileSync2(CREDENTIALS_FILE, "utf8").trim() || null;
8285
- } catch {
8286
- return null;
8821
+ const e = typeof error === "object" && error !== null ? error : {};
8822
+ const message = typeof e.message === "string" && e.message.length > 0 ? e.message : error instanceof Error ? error.name : String(error ?? "Unknown error");
8823
+ if (e.name === "WorkflowLocalUsageError" || typeof e.code === "string" && e.code.startsWith("commander.")) {
8824
+ return {
8825
+ code: "usage",
8826
+ exitCode: CLI_EXIT.USAGE,
8827
+ message
8828
+ };
8287
8829
  }
8830
+ const status = numericStatus(e);
8831
+ if (status !== void 0) {
8832
+ const statusCode = status;
8833
+ if (status === 401) return {
8834
+ code: "auth",
8835
+ exitCode: CLI_EXIT.AUTH,
8836
+ message,
8837
+ statusCode
8838
+ };
8839
+ if (status === 403) return {
8840
+ code: "forbidden",
8841
+ exitCode: CLI_EXIT.FORBIDDEN,
8842
+ message,
8843
+ statusCode
8844
+ };
8845
+ if (status === 404) return {
8846
+ code: "not_found",
8847
+ exitCode: CLI_EXIT.NOT_FOUND,
8848
+ message,
8849
+ statusCode
8850
+ };
8851
+ if (status >= 400 && status < 500) return {
8852
+ code: `http_${status}`,
8853
+ exitCode: CLI_EXIT.FORBIDDEN,
8854
+ message,
8855
+ statusCode
8856
+ };
8857
+ if (status >= 500 || status === 0) return {
8858
+ code: "unavailable",
8859
+ exitCode: CLI_EXIT.UNAVAILABLE,
8860
+ message,
8861
+ statusCode
8862
+ };
8863
+ }
8864
+ const causeCode = e.cause?.code;
8865
+ 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)) {
8866
+ return {
8867
+ code: "unavailable",
8868
+ exitCode: CLI_EXIT.UNAVAILABLE,
8869
+ message,
8870
+ hint: UNAVAILABLE_HINT
8871
+ };
8872
+ }
8873
+ return {
8874
+ code: "error",
8875
+ exitCode: CLI_EXIT.ERROR,
8876
+ message
8877
+ };
8288
8878
  }
8289
- function isRequestCredential(value3) {
8290
- return typeof value3 !== "string";
8291
- }
8292
- async function bearerFor(credential) {
8293
- return isRequestCredential(credential) ? credential.bearer() : credential;
8294
- }
8295
- async function resolveRequestCredential() {
8296
- if (process.env.LUA_API_KEY) return new StaticRequestCredential(process.env.LUA_API_KEY, "environment");
8297
- const store = new FirebaseSessionStore();
8298
- const session = await store.read();
8299
- if (session) return new FirebaseRequestCredential(store, session);
8300
- const storedApiKey = loadStoredApiKey();
8301
- if (storedApiKey) return new StaticRequestCredential(storedApiKey, "stored");
8302
- throw new AuthenticationError("No Lua CLI authentication found. Run `lua auth configure` or set LUA_API_KEY.", "invalid_credentials", void 0, true);
8303
- }
8304
- var StaticRequestCredential, FirebaseRequestCredential;
8305
- var init_request_credential = __esm({
8306
- "src/services/request-credential.ts"() {
8879
+ var CLI_EXIT, CliError, NETWORK_ERRNO, NETWORK_MESSAGE, UNAVAILABLE_HINT, VENDOR_RETRY_SOON_SECONDS, VENDOR_LABELS, PROVIDER_REJECTED_SERVER_CODE, PROVIDER_REJECTED_HTTP_STATUS, PROVIDER_REJECTION_REASONS, PROVIDER_REJECTED_NO_RETRY, PROVIDER_REJECTED_LUA_SIDE, MODEL_SETTINGS_URL;
8880
+ var init_cli_error = __esm({
8881
+ "src/errors/cli.error.ts"() {
8307
8882
  "use strict";
8308
- init_constants();
8309
8883
  init_auth_error();
8310
- init_lua_fetch();
8311
- init_firebase_session();
8312
- init_firebase_session_store();
8313
- __name(loadStoredApiKey, "loadStoredApiKey");
8314
- __name(isRequestCredential, "isRequestCredential");
8315
- __name(bearerFor, "bearerFor");
8316
- StaticRequestCredential = class StaticRequestCredential2 {
8884
+ CLI_EXIT = {
8885
+ OK: 0,
8886
+ ERROR: 1,
8887
+ USAGE: 2,
8888
+ NOT_FOUND: 3,
8889
+ AUTH: 9,
8890
+ FORBIDDEN: 10,
8891
+ UNAVAILABLE: 11,
8892
+ PROVIDER_REJECTED: 12
8893
+ };
8894
+ __name(apiErrorDetail, "apiErrorDetail");
8895
+ CliError = class _CliError extends Error {
8317
8896
  static {
8318
- __name(this, "StaticRequestCredential");
8897
+ __name(this, "CliError");
8319
8898
  }
8320
- apiKey;
8321
- descriptor;
8322
- constructor(apiKey, source) {
8323
- this.apiKey = apiKey;
8324
- this.descriptor = {
8325
- kind: "api-key",
8326
- source
8327
- };
8899
+ isCliError = true;
8900
+ code;
8901
+ exitCode;
8902
+ hint;
8903
+ statusCode;
8904
+ serverCode;
8905
+ issues;
8906
+ constructor(code, message, options = {}) {
8907
+ super(message);
8908
+ this.name = "CliError";
8909
+ this.code = code;
8910
+ this.exitCode = options.exitCode ?? CLI_EXIT.ERROR;
8911
+ this.hint = options.hint;
8912
+ this.statusCode = options.statusCode;
8913
+ this.serverCode = options.serverCode;
8914
+ this.issues = options.issues?.length ? options.issues : void 0;
8915
+ if (Error.captureStackTrace) Error.captureStackTrace(this, _CliError);
8328
8916
  }
8329
- async bearer() {
8330
- return this.apiKey;
8917
+ /** Bad arguments, an unknown action, no project — exit 2. */
8918
+ static usage(message, hint) {
8919
+ return new _CliError("usage", message, {
8920
+ exitCode: CLI_EXIT.USAGE,
8921
+ hint
8922
+ });
8331
8923
  }
8332
- };
8333
- FirebaseRequestCredential = class FirebaseRequestCredential2 {
8334
- static {
8335
- __name(this, "FirebaseRequestCredential");
8924
+ /** The named thing does not exist — exit 3. */
8925
+ static notFound(message, hint) {
8926
+ return new _CliError("not_found", message, {
8927
+ exitCode: CLI_EXIT.NOT_FOUND,
8928
+ hint,
8929
+ statusCode: 404
8930
+ });
8336
8931
  }
8337
- store;
8338
- descriptor;
8339
- liveSession;
8340
- refresh;
8341
- constructor(store, stored) {
8342
- this.store = store;
8343
- this.descriptor = {
8344
- kind: "first-party-session",
8345
- source: "stored",
8346
- uid: stored.firebaseUid
8347
- };
8932
+ /** The credential may not do this — exit 10. */
8933
+ static forbidden(message, hint) {
8934
+ return new _CliError("forbidden", message, {
8935
+ exitCode: CLI_EXIT.FORBIDDEN,
8936
+ hint,
8937
+ statusCode: 403
8938
+ });
8348
8939
  }
8349
- async bearer() {
8350
- if (this.liveSession && this.liveSession.expiresAt - Date.now() > 6e4) return this.liveSession.idToken;
8351
- if (!this.refresh) this.refresh = this.refreshBearer().finally(() => this.refresh = void 0);
8352
- return this.refresh;
8940
+ /**
8941
+ * The model provider behind the agent refused the request (LUA-820) a 424 `PROVIDER_REJECTED` body, or a chat
8942
+ * stream `error` chunk carrying that code `provider_rejected`, exit 12, the hint picked by `reason` / `keyOwner`
8943
+ * (`providerRejectedHint`). The message is the server's typed line ("Your model provider rejected the request
8944
+ * (401 invalid_api_key): …"). Never a re-login or a network hint: the Lua session and the network are fine — the
8945
+ * provider ANSWERED and said no, and the same request fails identically on a retry.
8946
+ */
8947
+ static providerRejected(message, detail = {}, options = {}) {
8948
+ return new _CliError("provider_rejected", message, {
8949
+ exitCode: CLI_EXIT.PROVIDER_REJECTED,
8950
+ hint: options.hint ?? providerRejectedHint(detail.reason, detail.providerStatus, detail.keyOwner),
8951
+ statusCode: options.statusCode ?? PROVIDER_REJECTED_HTTP_STATUS,
8952
+ serverCode: PROVIDER_REJECTED_SERVER_CODE,
8953
+ issues: detail.issues
8954
+ });
8353
8955
  }
8354
- async refreshBearer() {
8355
- let live;
8356
- await this.store.update(async (stored) => {
8357
- if (!stored) {
8358
- throw new AuthenticationError("Your Lua CLI session has expired. Run `lua auth configure`.", "invalid_credentials");
8359
- }
8360
- live = await refreshFirebaseSession({
8361
- idToken: "",
8362
- refreshToken: stored.refreshToken,
8363
- expiresAt: 0,
8364
- uid: stored.firebaseUid
8956
+ /**
8957
+ * An API refusal the site already holds the status of (LUA-766) — classified by the same table the top-level
8958
+ * classifier applies to an untyped error: 401 auth · 403 forbidden · 404 not_found · other 4xx `http_<status>`
8959
+ * (10) · 5xx / 0 unavailable (11, with the network hint unless the site gives its own — or the body's code
8960
+ * picks one: a 503 UPSTREAM_UNAVAILABLE names the Lua service behind the API, LUA-810) · no status `error` (1).
8961
+ * The body's code can also pick the CLASS: a 424 `PROVIDER_REJECTED` is `provider_rejected` (12) with the
8962
+ * per-reason hint (LUA-820) — a 424 WITHOUT the code stays the opaque `http_424`. A command that reads
8963
+ * `response.error.statusCode` throws through here, so `lua logs` on a 503 exits 11 like every other verb instead
8964
+ * of printing the message itself and then throwing an exit-1 `Error`.
8965
+ */
8966
+ static fromStatus(statusCode, message, hint, detail = {}) {
8967
+ if (detail.serverCode === PROVIDER_REJECTED_SERVER_CODE) {
8968
+ return _CliError.providerRejected(message, detail, {
8969
+ hint,
8970
+ statusCode
8365
8971
  });
8366
- return {
8367
- ...stored,
8368
- refreshToken: live.refreshToken,
8369
- firebaseUid: live.uid
8370
- };
8972
+ }
8973
+ const reported = classifyCliError(Object.assign(new Error(message), {
8974
+ statusCode
8975
+ }));
8976
+ const codeHint = detail.serverCode === "UPSTREAM_UNAVAILABLE" ? upstreamUnavailableHint(detail.upstream, detail.requestId) : detail.serverCode === "VENDOR_UNAVAILABLE" ? vendorUnavailableHint(detail.vendor, detail.requestId, detail.retryAfterSeconds) : void 0;
8977
+ const classHint = reported.exitCode === CLI_EXIT.UNAVAILABLE ? UNAVAILABLE_HINT : reported.hint;
8978
+ return new _CliError(reported.code, message, {
8979
+ exitCode: reported.exitCode,
8980
+ hint: hint ?? codeHint ?? classHint,
8981
+ statusCode,
8982
+ serverCode: detail.serverCode,
8983
+ issues: detail.issues
8371
8984
  });
8372
- if (!live) throw new Error("Firebase session refresh did not return a session.");
8373
- this.liveSession = live;
8374
- return live.idToken;
8985
+ }
8986
+ static isCliError(error) {
8987
+ return error instanceof _CliError || typeof error === "object" && error !== null && error.isCliError === true;
8375
8988
  }
8376
8989
  };
8377
- __name(resolveRequestCredential, "resolveRequestCredential");
8990
+ __name(isAccessDeniedError, "isAccessDeniedError");
8991
+ NETWORK_ERRNO = /* @__PURE__ */ new Set([
8992
+ "ECONNREFUSED",
8993
+ "ECONNRESET",
8994
+ "ENOTFOUND",
8995
+ "ETIMEDOUT",
8996
+ "EAI_AGAIN",
8997
+ "EPIPE",
8998
+ "EHOSTUNREACH",
8999
+ "ENETUNREACH",
9000
+ "UND_ERR_CONNECT_TIMEOUT",
9001
+ "UND_ERR_HEADERS_TIMEOUT",
9002
+ "UND_ERR_BODY_TIMEOUT",
9003
+ "UND_ERR_SOCKET"
9004
+ ]);
9005
+ NETWORK_MESSAGE = /fetch failed|socket hang up|network request failed|request timeout|ECONNREFUSED|ENOTFOUND/i;
9006
+ UNAVAILABLE_HINT = "The Lua API could not be reached \u2014 check your network and https://status.heylua.ai, then retry.";
9007
+ __name(upstreamUnavailableHint, "upstreamUnavailableHint");
9008
+ VENDOR_RETRY_SOON_SECONDS = 5;
9009
+ VENDOR_LABELS = {
9010
+ unified: "Unified.to",
9011
+ github: "GitHub",
9012
+ pusher: "Pusher",
9013
+ google: "Google"
9014
+ };
9015
+ __name(vendorUnavailableHint, "vendorUnavailableHint");
9016
+ PROVIDER_REJECTED_SERVER_CODE = "PROVIDER_REJECTED";
9017
+ PROVIDER_REJECTED_HTTP_STATUS = 424;
9018
+ PROVIDER_REJECTION_REASONS = /* @__PURE__ */ new Set([
9019
+ "invalid_api_key",
9020
+ "forbidden",
9021
+ "model_not_found",
9022
+ "content_refused",
9023
+ "quota_exhausted",
9024
+ "bad_request"
9025
+ ]);
9026
+ __name(providerRejectionReasonOf, "providerRejectionReasonOf");
9027
+ __name(providerKeyOwnerOf, "providerKeyOwnerOf");
9028
+ __name(providerStatusOf, "providerStatusOf");
9029
+ PROVIDER_REJECTED_NO_RETRY = "Retrying the same request will fail identically.";
9030
+ PROVIDER_REJECTED_LUA_SIDE = "a Lua-side model configuration problem, not your request or settings \u2014 contact Lua support if it persists";
9031
+ MODEL_SETTINGS_URL = "https://admin.heylua.ai";
9032
+ __name(providerRejectedHint, "providerRejectedHint");
9033
+ __name(authHint, "authHint");
9034
+ __name(numericStatus, "numericStatus");
9035
+ __name(classifyCliError, "classifyCliError");
8378
9036
  }
8379
9037
  });
8380
9038
 
@@ -8388,6 +9046,10 @@ async function classifyErrorResponse(response) {
8388
9046
  errorData = {};
8389
9047
  }
8390
9048
  if (response.status === 401) {
9049
+ if (serverCodeOf(errorData.code, errorData.error) === SESSION_REVOKED_CODE) {
9050
+ await clearStoredFirebaseSession().catch(() => false);
9051
+ throw sessionSignedOutError();
9052
+ }
8391
9053
  const serverMessage = typeof errorData.message === "string" ? errorData.message : void 0;
8392
9054
  if (serverMessage && /not an admin/i.test(serverMessage)) {
8393
9055
  throw new AuthenticationError(`Access denied for this agent: ${serverMessage}`, "no_agent_access", serverMessage);
@@ -8513,6 +9175,7 @@ var init_http_client = __esm({
8513
9175
  "src/api/http.client.ts"() {
8514
9176
  "use strict";
8515
9177
  init_dist();
9178
+ init_dist();
8516
9179
  init_auth_error();
8517
9180
  init_cli_error();
8518
9181
  init_lua_fetch();
@@ -8837,23 +9500,25 @@ var init_http_client = __esm({
8837
9500
  }
8838
9501
  });
8839
9502
 
8840
- // src/api/auth.api.service.ts
8841
- var init_auth_api_service = __esm({
8842
- "src/api/auth.api.service.ts"() {
9503
+ // src/api/cli-credentials.api.service.ts
9504
+ var init_cli_credentials_api_service = __esm({
9505
+ "src/api/cli-credentials.api.service.ts"() {
8843
9506
  "use strict";
8844
9507
  init_http_client();
9508
+ init_dist();
8845
9509
  }
8846
9510
  });
8847
9511
 
8848
- // src/services/auth.ts
8849
- import "dotenv/config";
8850
- var init_auth = __esm({
8851
- "src/services/auth.ts"() {
9512
+ // src/services/credential-operational-context.ts
9513
+ var init_credential_operational_context = __esm({
9514
+ "src/services/credential-operational-context.ts"() {
8852
9515
  "use strict";
8853
- init_auth_api_service();
9516
+ init_dist();
9517
+ init_cli_credentials_api_service();
8854
9518
  init_constants();
8855
9519
  init_auth_error();
8856
9520
  init_cli_error();
9521
+ init_request_credential();
8857
9522
  }
8858
9523
  });
8859
9524
 
@@ -9152,7 +9817,7 @@ function walkWorkspace(rootDir, opts = {}) {
9152
9817
  const refs = [];
9153
9818
  const contentByHash = /* @__PURE__ */ new Map();
9154
9819
  let totalSize = 0;
9155
- const visit = /* @__PURE__ */ __name4((relPrefix) => {
9820
+ const visit = /* @__PURE__ */ __name5((relPrefix) => {
9156
9821
  const absDir = relPrefix ? join4(rootDir, relPrefix) : rootDir;
9157
9822
  let entries;
9158
9823
  try {
@@ -9446,21 +10111,21 @@ function walk2(root, prefix, out) {
9446
10111
  }
9447
10112
  }
9448
10113
  }
9449
- var __defProp4, __name4, FILE_HASH_LENGTH, SKIP_DIRECTORIES, ARCHIVE_ONLY_SKIP_DIRECTORIES, DEFAULT_MAX_FILE_BYTES, KIND_BY_EXT, CHECK_BLOBS_MAX_HASHES, BackupHttpError, BackupHttpClient, DEFAULT_CONCURRENCY, CREDENTIAL_PATHS, WINDOWS_ABSOLUTE_PATH, ARCHIVE_SCHEMA_VERSION;
10114
+ var __defProp5, __name5, FILE_HASH_LENGTH, SKIP_DIRECTORIES, ARCHIVE_ONLY_SKIP_DIRECTORIES, DEFAULT_MAX_FILE_BYTES, KIND_BY_EXT, CHECK_BLOBS_MAX_HASHES, BackupHttpError, BackupHttpClient, DEFAULT_CONCURRENCY, CREDENTIAL_PATHS, WINDOWS_ABSOLUTE_PATH, ARCHIVE_SCHEMA_VERSION;
9450
10115
  var init_dist3 = __esm({
9451
10116
  "../shared-source-sync/dist/index.mjs"() {
9452
10117
  "use strict";
9453
- __defProp4 = Object.defineProperty;
9454
- __name4 = /* @__PURE__ */ __name((target, value3) => __defProp4(target, "name", { value: value3, configurable: true }), "__name");
10118
+ __defProp5 = Object.defineProperty;
10119
+ __name5 = /* @__PURE__ */ __name((target, value3) => __defProp5(target, "name", { value: value3, configurable: true }), "__name");
9455
10120
  FILE_HASH_LENGTH = 16;
9456
10121
  __name(hashContentTruncated, "hashContentTruncated");
9457
- __name4(hashContentTruncated, "hashContentTruncated");
10122
+ __name5(hashContentTruncated, "hashContentTruncated");
9458
10123
  __name(sha256Hex, "sha256Hex");
9459
- __name4(sha256Hex, "sha256Hex");
10124
+ __name5(sha256Hex, "sha256Hex");
9460
10125
  __name(matchesFileHash, "matchesFileHash");
9461
- __name4(matchesFileHash, "matchesFileHash");
10126
+ __name5(matchesFileHash, "matchesFileHash");
9462
10127
  __name(combineFileHashes, "combineFileHashes");
9463
- __name4(combineFileHashes, "combineFileHashes");
10128
+ __name5(combineFileHashes, "combineFileHashes");
9464
10129
  SKIP_DIRECTORIES = /* @__PURE__ */ new Set([
9465
10130
  "node_modules",
9466
10131
  "dist",
@@ -9477,9 +10142,9 @@ var init_dist3 = __esm({
9477
10142
  ]);
9478
10143
  DEFAULT_MAX_FILE_BYTES = 256 * 1024;
9479
10144
  __name(shouldSkipDirectory, "shouldSkipDirectory");
9480
- __name4(shouldSkipDirectory, "shouldSkipDirectory");
10145
+ __name5(shouldSkipDirectory, "shouldSkipDirectory");
9481
10146
  __name(shouldSkipFile, "shouldSkipFile");
9482
- __name4(shouldSkipFile, "shouldSkipFile");
10147
+ __name5(shouldSkipFile, "shouldSkipFile");
9483
10148
  KIND_BY_EXT = {
9484
10149
  ".ts": "source",
9485
10150
  ".tsx": "source",
@@ -9491,16 +10156,16 @@ var init_dist3 = __esm({
9491
10156
  ".toml": "config"
9492
10157
  };
9493
10158
  __name(classifyFile, "classifyFile");
9494
- __name4(classifyFile, "classifyFile");
10159
+ __name5(classifyFile, "classifyFile");
9495
10160
  __name(walkWorkspace, "walkWorkspace");
9496
- __name4(walkWorkspace, "walkWorkspace");
10161
+ __name5(walkWorkspace, "walkWorkspace");
9497
10162
  CHECK_BLOBS_MAX_HASHES = 500;
9498
10163
  BackupHttpError = class extends Error {
9499
10164
  static {
9500
10165
  __name(this, "BackupHttpError");
9501
10166
  }
9502
10167
  static {
9503
- __name4(this, "BackupHttpError");
10168
+ __name5(this, "BackupHttpError");
9504
10169
  }
9505
10170
  status;
9506
10171
  endpoint;
@@ -9515,7 +10180,7 @@ var init_dist3 = __esm({
9515
10180
  __name(this, "BackupHttpClient");
9516
10181
  }
9517
10182
  static {
9518
- __name4(this, "BackupHttpClient");
10183
+ __name5(this, "BackupHttpClient");
9519
10184
  }
9520
10185
  options;
9521
10186
  fetchFn;
@@ -9620,17 +10285,17 @@ var init_dist3 = __esm({
9620
10285
  };
9621
10286
  DEFAULT_CONCURRENCY = 10;
9622
10287
  __name(uploadBlobs, "uploadBlobs");
9623
- __name4(uploadBlobs, "uploadBlobs");
10288
+ __name5(uploadBlobs, "uploadBlobs");
9624
10289
  __name(decodeBlob, "decodeBlob");
9625
- __name4(decodeBlob, "decodeBlob");
10290
+ __name5(decodeBlob, "decodeBlob");
9626
10291
  __name(verifyDownloaded, "verifyDownloaded");
9627
- __name4(verifyDownloaded, "verifyDownloaded");
10292
+ __name5(verifyDownloaded, "verifyDownloaded");
9628
10293
  __name(downloadBlobs, "downloadBlobs");
9629
- __name4(downloadBlobs, "downloadBlobs");
10294
+ __name5(downloadBlobs, "downloadBlobs");
9630
10295
  __name(resolveBackupFileTarget, "resolveBackupFileTarget");
9631
- __name4(resolveBackupFileTarget, "resolveBackupFileTarget");
10296
+ __name5(resolveBackupFileTarget, "resolveBackupFileTarget");
9632
10297
  __name(restoreFromBlobs, "restoreFromBlobs");
9633
- __name4(restoreFromBlobs, "restoreFromBlobs");
10298
+ __name5(restoreFromBlobs, "restoreFromBlobs");
9634
10299
  CREDENTIAL_PATHS = /* @__PURE__ */ new Set([
9635
10300
  ".env",
9636
10301
  ".lua/config.json",
@@ -9638,22 +10303,22 @@ var init_dist3 = __esm({
9638
10303
  ]);
9639
10304
  WINDOWS_ABSOLUTE_PATH = /^[a-z]:\//i;
9640
10305
  __name(normalizeWorkspaceRelativePath, "normalizeWorkspaceRelativePath");
9641
- __name4(normalizeWorkspaceRelativePath, "normalizeWorkspaceRelativePath");
10306
+ __name5(normalizeWorkspaceRelativePath, "normalizeWorkspaceRelativePath");
9642
10307
  __name(isCredentialPersistencePath, "isCredentialPersistencePath");
9643
- __name4(isCredentialPersistencePath, "isCredentialPersistencePath");
10308
+ __name5(isCredentialPersistencePath, "isCredentialPersistencePath");
9644
10309
  __name(pushAgentBackup, "pushAgentBackup");
9645
- __name4(pushAgentBackup, "pushAgentBackup");
10310
+ __name5(pushAgentBackup, "pushAgentBackup");
9646
10311
  __name(pullAgentBackup, "pullAgentBackup");
9647
- __name4(pullAgentBackup, "pullAgentBackup");
10312
+ __name5(pullAgentBackup, "pullAgentBackup");
9648
10313
  ARCHIVE_SCHEMA_VERSION = 1;
9649
10314
  __name(encodeWorkspaceArchive, "encodeWorkspaceArchive");
9650
- __name4(encodeWorkspaceArchive, "encodeWorkspaceArchive");
10315
+ __name5(encodeWorkspaceArchive, "encodeWorkspaceArchive");
9651
10316
  __name(decodeWorkspaceArchive, "decodeWorkspaceArchive");
9652
- __name4(decodeWorkspaceArchive, "decodeWorkspaceArchive");
10317
+ __name5(decodeWorkspaceArchive, "decodeWorkspaceArchive");
9653
10318
  __name(writeArchiveToWorkspace, "writeArchiveToWorkspace");
9654
- __name4(writeArchiveToWorkspace, "writeArchiveToWorkspace");
10319
+ __name5(writeArchiveToWorkspace, "writeArchiveToWorkspace");
9655
10320
  __name(walk2, "walk");
9656
- __name4(walk2, "walk");
10321
+ __name5(walk2, "walk");
9657
10322
  }
9658
10323
  });
9659
10324
 
@@ -10538,8 +11203,8 @@ async function requireAuth() {
10538
11203
  var init_command_utils = __esm({
10539
11204
  "src/utils/command-utils.ts"() {
10540
11205
  "use strict";
10541
- init_auth();
10542
11206
  init_request_credential();
11207
+ init_credential_operational_context();
10543
11208
  init_files();
10544
11209
  init_cli();
10545
11210
  init_cli_error();
@@ -13137,11 +13802,48 @@ var init_ai_api_service = __esm({
13137
13802
  });
13138
13803
 
13139
13804
  // src/api/integrations.api.service.ts
13140
- var IntegrationsApiService;
13805
+ function integrationPassthroughErrorFields(error) {
13806
+ const fields = {};
13807
+ if (!error) return fields;
13808
+ const strings = [
13809
+ "code",
13810
+ "legacyCode",
13811
+ "legacyMessage",
13812
+ "vendor",
13813
+ "requestId"
13814
+ ];
13815
+ for (const key of strings) {
13816
+ const value3 = error[key];
13817
+ if (typeof value3 === "string" && value3.length > 0) fields[key] = value3;
13818
+ }
13819
+ const numbers = [
13820
+ "statusCode",
13821
+ "retryAfterSeconds",
13822
+ "vendorStatus"
13823
+ ];
13824
+ for (const key of numbers) {
13825
+ const value3 = error[key];
13826
+ if (typeof value3 === "number" && Number.isFinite(value3)) fields[key] = value3;
13827
+ }
13828
+ if (fields.statusCode !== void 0) fields.status = fields.statusCode;
13829
+ return fields;
13830
+ }
13831
+ var IntegrationPassthroughError, IntegrationsApiService;
13141
13832
  var init_integrations_api_service = __esm({
13142
13833
  "src/api/integrations.api.service.ts"() {
13143
13834
  "use strict";
13144
13835
  init_http_client();
13836
+ IntegrationPassthroughError = class extends Error {
13837
+ static {
13838
+ __name(this, "IntegrationPassthroughError");
13839
+ }
13840
+ constructor(message, fields = {}) {
13841
+ super(message);
13842
+ this.name = "IntegrationPassthroughError";
13843
+ Object.assign(this, fields);
13844
+ }
13845
+ };
13846
+ __name(integrationPassthroughErrorFields, "integrationPassthroughErrorFields");
13145
13847
  IntegrationsApiService = class extends HttpClient {
13146
13848
  static {
13147
13849
  __name(this, "IntegrationsApiService");
@@ -13157,12 +13859,14 @@ var init_integrations_api_service = __esm({
13157
13859
  * Sandbox-facing wrapper: returns the raw provider envelope
13158
13860
  * `{ status, headers, data }` (provider error statuses relayed faithfully in
13159
13861
  * `status`), and throws only on route-level failures (no connection,
13160
- * passthrough disabled, rate limited, transport error).
13862
+ * passthrough disabled, rate limited, transport error) — as an
13863
+ * `IntegrationPassthroughError` carrying the server's typed fields (LUA-860);
13864
+ * `message` is the server's line, unchanged from the bare `Error` it used to be.
13161
13865
  */
13162
13866
  async passthroughForSandbox(integrationType, request) {
13163
13867
  const result = await this.passthrough(integrationType, request);
13164
13868
  if (!result.success || !result.data) {
13165
- throw new Error(result.error?.message || `Integration passthrough failed for '${integrationType}'`);
13869
+ throw new IntegrationPassthroughError(result.error?.message || `Integration passthrough failed for '${integrationType}'`, integrationPassthroughErrorFields(result.error));
13166
13870
  }
13167
13871
  return result.data;
13168
13872
  }