lua-cli 3.35.0 → 3.36.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.
package/dist/index.js CHANGED
@@ -1182,10 +1182,113 @@ function isDesktopFileCommandName(value3) {
1182
1182
  function isDesktopFileSessionId(value3) {
1183
1183
  return typeof value3 === "string" && /^[0-9a-f]{8}-[0-9a-f]{4}-[1-5][0-9a-f]{3}-[89ab][0-9a-f]{3}-[0-9a-f]{12}$/i.test(value3);
1184
1184
  }
1185
+ function workflowRetryMaxAttemptsMessage(got) {
1186
+ const tail = got === void 0 ? "" : ` (got ${JSON.stringify(got)})`;
1187
+ return `\`retry.maxAttempts\` must be an integer ${WORKFLOW_RETRY_MIN_ATTEMPTS}..${WORKFLOW_RETRY_MAX_ATTEMPTS}${tail}`;
1188
+ }
1189
+ function isWithinWorkflowRetryAttempts(value3) {
1190
+ return typeof value3 === "number" && Number.isInteger(value3) && value3 >= WORKFLOW_RETRY_MIN_ATTEMPTS && value3 <= WORKFLOW_RETRY_MAX_ATTEMPTS;
1191
+ }
1192
+ function workflowRetryUnknownMembersMessage(keys) {
1193
+ const named = keys.map((k) => {
1194
+ const engine = WORKFLOW_RETRY_ENGINE_KEYS.includes(k);
1195
+ return `\`${k}\`${engine ? " (engine-owned \u2014 stamped by resetAttempts, never authored)" : ""}`;
1196
+ });
1197
+ return `\`retry\` has no member ${named.join(", ")}; members: ${WORKFLOW_RETRY_POLICY_KEYS.join(", ")}`;
1198
+ }
1199
+ function unknownWorkflowRetryMembers(retry) {
1200
+ if (!retry || typeof retry !== "object" || Array.isArray(retry)) return [];
1201
+ return Object.keys(retry).filter((k) => !WORKFLOW_RETRY_POLICY_KEYS.includes(k));
1202
+ }
1203
+ function authoredRetryPolicy(retry) {
1204
+ if (!retry || typeof retry !== "object" || Array.isArray(retry)) return void 0;
1205
+ const src = retry;
1206
+ const out = {};
1207
+ for (const k of WORKFLOW_RETRY_POLICY_KEYS) if (src[k] !== void 0) out[k] = src[k];
1208
+ return Object.keys(out).length ? out : void 0;
1209
+ }
1210
+ function retryBudgetBaseAttempt(row2) {
1211
+ const base = row2.retry?.budgetBaseAttempt;
1212
+ return typeof base === "number" && Number.isSafeInteger(base) && base > 0 ? base : 0;
1213
+ }
1214
+ function retryBudgetAttempt(row2) {
1215
+ return Math.max(0, row2.attempt - retryBudgetBaseAttempt(row2));
1216
+ }
1217
+ function retryBudgetMaxAttempts(row2) {
1218
+ const max = row2.retry?.maxAttempts;
1219
+ return typeof max === "number" && Number.isFinite(max) && max >= 1 ? max : 1;
1220
+ }
1221
+ function retryBudgetRemaining(row2) {
1222
+ return retryBudgetAttempt(row2) < retryBudgetMaxAttempts(row2);
1223
+ }
1224
+ function retriesRemaining(row2) {
1225
+ return Math.max(0, retryBudgetMaxAttempts(row2) - retryBudgetAttempt(row2));
1226
+ }
1227
+ function workflowModelCostComparison(estimate, onAgentModel, agentModel) {
1228
+ if (agentModel === void 0 || onAgentModel === void 0 || !(onAgentModel > 0)) return void 0;
1229
+ const ratio = Math.round(estimate / onAgentModel * 10) / 10;
1230
+ return `\u2248 ${ratio}\xD7 the cost of running every step on ${agentModel}`;
1231
+ }
1232
+ function modelClassRank(modelClass) {
1233
+ return WORKFLOW_MODEL_CLASSES.indexOf(modelClass);
1234
+ }
1235
+ function modelClassesAtOrBelow(maxClass) {
1236
+ const ceiling = modelClassRank(maxClass);
1237
+ return WORKFLOW_MODEL_CLASSES.filter((c) => modelClassRank(c) <= ceiling);
1238
+ }
1239
+ function workflowAutonomyMaxRunsPerHourCeiling(env) {
1240
+ const raw = Number((env ?? process.env)[WORKFLOW_AUTONOMY_MAX_RUNS_PER_HOUR_ENV]);
1241
+ return Number.isFinite(raw) && raw > 0 ? raw : WORKFLOW_AUTONOMY_MAX_RUNS_PER_HOUR_CEILING;
1242
+ }
1243
+ function isWithinWorkflowAutonomyRange(value3, ceiling) {
1244
+ return typeof value3 === "number" && Number.isInteger(value3) && value3 >= WORKFLOW_AUTONOMY_MIN_VALUE && value3 <= ceiling;
1245
+ }
1246
+ function workflowAutonomyRangeMessage(key, ceiling) {
1247
+ return `\`${key}\` must be an integer ${WORKFLOW_AUTONOMY_MIN_VALUE}..${ceiling}`;
1248
+ }
1249
+ function isWithinWorkflowJobRange(member, value3) {
1250
+ const { min, max } = WORKFLOW_JOB_RANGES[member];
1251
+ return typeof value3 === "number" && Number.isInteger(value3) && value3 >= min && value3 <= max;
1252
+ }
1253
+ function workflowJobRangeMessage(member) {
1254
+ const { min, max } = WORKFLOW_JOB_RANGES[member];
1255
+ return `\`${member}\` must be an integer ${min}..${max}`;
1256
+ }
1257
+ function isWorkflowSingleStepType(type) {
1258
+ return typeof type === "string" && WORKFLOW_SINGLE_STEP_TYPES.includes(type);
1259
+ }
1260
+ function isWorkflowHitlEntryType(type) {
1261
+ return typeof type === "string" && WORKFLOW_HITL_ENTRY_TYPES.includes(type);
1262
+ }
1263
+ function isWorkflowArmEntryType(type) {
1264
+ return typeof type === "string" && WORKFLOW_ARM_ENTRY_TYPES.includes(type);
1265
+ }
1266
+ function workflowContainerRunsHitlArm(container) {
1267
+ return typeof container === "string" && WORKFLOW_HITL_ARM_CONTAINERS.includes(container);
1268
+ }
1269
+ function workflowHitlArmUnsupportedMessage(type, id, container) {
1270
+ const legal = WORKFLOW_HITL_ARM_CONTAINERS.map((c) => `\`${c}\``).join(" / ");
1271
+ return `the engine does not run \`${type}\` inside a \`${container}\` yet (node "${id}") \u2014 place it at the top level, as a ${legal} arm, or inside a child \`workflow\``;
1272
+ }
1273
+ function workflowHitlArmShapeMessage(type, id, shape) {
1274
+ 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\``;
1275
+ }
1185
1276
  function isModelIdSentinel(input) {
1186
1277
  const lower = (input ?? "").trim().toLowerCase();
1187
1278
  return lower === "auto" || lower.startsWith("auto/");
1188
1279
  }
1280
+ function isModelClassRef(input) {
1281
+ return modelClassOf(input) !== void 0;
1282
+ }
1283
+ function modelClassOf(input) {
1284
+ const lower = (input ?? "").trim().toLowerCase();
1285
+ if (!lower.startsWith(MODEL_CLASS_REF_PREFIX)) return void 0;
1286
+ const c = lower.slice(MODEL_CLASS_REF_PREFIX.length);
1287
+ return WORKFLOW_MODEL_CLASSES.includes(c) ? c : void 0;
1288
+ }
1289
+ function modelClassRef(modelClass) {
1290
+ return `${MODEL_CLASS_REF_PREFIX}${modelClass}`;
1291
+ }
1189
1292
  function normalizeModelId(input, registry) {
1190
1293
  const requested = typeof input === "string" ? input.trim() : "";
1191
1294
  if (!requested) return {
@@ -1200,6 +1303,11 @@ function normalizeModelId(input, registry) {
1200
1303
  id: lower,
1201
1304
  form: "sentinel"
1202
1305
  };
1306
+ if (modelClassOf(lower) !== void 0) return {
1307
+ ok: true,
1308
+ id: lower,
1309
+ form: "class"
1310
+ };
1203
1311
  const slash = requested.indexOf("/");
1204
1312
  const malformed = slash === 0;
1205
1313
  const provider = slash > 0 ? lower.slice(0, slash) : void 0;
@@ -1260,6 +1368,9 @@ function modelUnresolvedMessage(r) {
1260
1368
  }
1261
1369
  return r.candidates.length ? `model "${r.requested}" does not resolve to an approved model \u2014 accepted forms: ${r.candidates.join(", ")}` : `model "${r.requested}" does not resolve to an approved model \u2014 accepted forms are the registry's provider-prefixed ids (provider/model) or a bare id that names exactly one of them`;
1262
1370
  }
1371
+ function modelClassUnresolvedMessage(ref) {
1372
+ return `model "${ref.trim()}" is a model-class request that was not resolved before dispatch \u2014 a class is resolved to a concrete approved model by the class map at dispatch, and is never sent to a provider as written; this step refuses rather than run on a substituted model`;
1373
+ }
1263
1374
  function providerModelId(code) {
1264
1375
  const requested = typeof code === "string" ? code.trim() : "";
1265
1376
  if (!requested || isModelIdSentinel(requested)) return requested;
@@ -1662,75 +1773,6 @@ function scheduledTimeKey(scheduledTime) {
1662
1773
  function scheduledWorkflowRunIdForTime(jobId, scheduledTime) {
1663
1774
  return scheduledWorkflowRunId(jobId, scheduledTime);
1664
1775
  }
1665
- function workflowRetryMaxAttemptsMessage(got) {
1666
- const tail = got === void 0 ? "" : ` (got ${JSON.stringify(got)})`;
1667
- return `\`retry.maxAttempts\` must be an integer ${WORKFLOW_RETRY_MIN_ATTEMPTS}..${WORKFLOW_RETRY_MAX_ATTEMPTS}${tail}`;
1668
- }
1669
- function isWithinWorkflowRetryAttempts(value3) {
1670
- return typeof value3 === "number" && Number.isInteger(value3) && value3 >= WORKFLOW_RETRY_MIN_ATTEMPTS && value3 <= WORKFLOW_RETRY_MAX_ATTEMPTS;
1671
- }
1672
- function workflowRetryUnknownMembersMessage(keys) {
1673
- const named = keys.map((k) => {
1674
- const engine = WORKFLOW_RETRY_ENGINE_KEYS.includes(k);
1675
- return `\`${k}\`${engine ? " (engine-owned \u2014 stamped by resetAttempts, never authored)" : ""}`;
1676
- });
1677
- return `\`retry\` has no member ${named.join(", ")}; members: ${WORKFLOW_RETRY_POLICY_KEYS.join(", ")}`;
1678
- }
1679
- function unknownWorkflowRetryMembers(retry) {
1680
- if (!retry || typeof retry !== "object" || Array.isArray(retry)) return [];
1681
- return Object.keys(retry).filter((k) => !WORKFLOW_RETRY_POLICY_KEYS.includes(k));
1682
- }
1683
- function authoredRetryPolicy(retry) {
1684
- if (!retry || typeof retry !== "object" || Array.isArray(retry)) return void 0;
1685
- const src = retry;
1686
- const out = {};
1687
- for (const k of WORKFLOW_RETRY_POLICY_KEYS) if (src[k] !== void 0) out[k] = src[k];
1688
- return Object.keys(out).length ? out : void 0;
1689
- }
1690
- function retryBudgetBaseAttempt(row2) {
1691
- const base = row2.retry?.budgetBaseAttempt;
1692
- return typeof base === "number" && Number.isSafeInteger(base) && base > 0 ? base : 0;
1693
- }
1694
- function retryBudgetAttempt(row2) {
1695
- return Math.max(0, row2.attempt - retryBudgetBaseAttempt(row2));
1696
- }
1697
- function retryBudgetMaxAttempts(row2) {
1698
- const max = row2.retry?.maxAttempts;
1699
- return typeof max === "number" && Number.isFinite(max) && max >= 1 ? max : 1;
1700
- }
1701
- function retryBudgetRemaining(row2) {
1702
- return retryBudgetAttempt(row2) < retryBudgetMaxAttempts(row2);
1703
- }
1704
- function retriesRemaining(row2) {
1705
- return Math.max(0, retryBudgetMaxAttempts(row2) - retryBudgetAttempt(row2));
1706
- }
1707
- function isWithinWorkflowJobRange(member, value3) {
1708
- const { min, max } = WORKFLOW_JOB_RANGES[member];
1709
- return typeof value3 === "number" && Number.isInteger(value3) && value3 >= min && value3 <= max;
1710
- }
1711
- function workflowJobRangeMessage(member) {
1712
- const { min, max } = WORKFLOW_JOB_RANGES[member];
1713
- return `\`${member}\` must be an integer ${min}..${max}`;
1714
- }
1715
- function isWorkflowSingleStepType(type) {
1716
- return typeof type === "string" && WORKFLOW_SINGLE_STEP_TYPES.includes(type);
1717
- }
1718
- function isWorkflowHitlEntryType(type) {
1719
- return typeof type === "string" && WORKFLOW_HITL_ENTRY_TYPES.includes(type);
1720
- }
1721
- function isWorkflowArmEntryType(type) {
1722
- return typeof type === "string" && WORKFLOW_ARM_ENTRY_TYPES.includes(type);
1723
- }
1724
- function workflowContainerRunsHitlArm(container) {
1725
- return typeof container === "string" && WORKFLOW_HITL_ARM_CONTAINERS.includes(container);
1726
- }
1727
- function workflowHitlArmUnsupportedMessage(type, id, container) {
1728
- const legal = WORKFLOW_HITL_ARM_CONTAINERS.map((c) => `\`${c}\``).join(" / ");
1729
- return `the engine does not run \`${type}\` inside a \`${container}\` yet (node "${id}") \u2014 place it at the top level, as a ${legal} arm, or inside a child \`workflow\``;
1730
- }
1731
- function workflowHitlArmShapeMessage(type, id, shape) {
1732
- 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\``;
1733
- }
1734
1776
  function workflowGoalJudgeKind(judge) {
1735
1777
  return judge && typeof judge === "object" && judge.predicate !== void 0 ? "predicate" : "agent";
1736
1778
  }
@@ -2035,7 +2077,7 @@ function effectiveAgentFeatures(base, override, rule) {
2035
2077
  if (rule === "wholesale") return override || base || void 0;
2036
2078
  return effectiveAgentFeatureRows(base, override).rows;
2037
2079
  }
2038
- var __defProp2, __name2, 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, AGENT_LOG_SOURCES, 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, EventType, 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, TYPED_API_KEY, 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_JOURNAL_PROTOCOL_VERSION, 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;
2080
+ var __defProp2, __name2, 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, 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_AGENT_EFFORTS, WORKFLOW_MODEL_CLASSES, WORKFLOW_TASK_CLASSES, WORKFLOW_MODEL_TRAITS, WORKFLOW_MODEL_REASON_MAX_LENGTH, WORKFLOW_MODELS_COMPOSE_MODES, WORKFLOW_MODELS_PIN_MODES, WORKFLOW_MODELS_FALLBACK_MODES, WORKFLOW_MODELS_CONSENT_ACTIONS_MIN, WORKFLOW_DEFAULT_TASK_CLASS_MAP, WORKFLOW_MODELS_MAX_CLASS_DEFAULT, WORKFLOW_AUTONOMY_FORMS, WORKFLOW_AUTONOMY_NUMERIC_KEYS, WORKFLOW_AUTONOMY_ENVELOPE_KEYS, WORKFLOW_AUTONOMY_ENABLED_DEFAULT, WORKFLOW_AUTONOMY_DEFAULTS, WORKFLOW_AUTONOMY_CEILINGS, WORKFLOW_AUTONOMY_MAX_RUNS_PER_HOUR_ENV, WORKFLOW_AUTONOMY_MAX_RUNS_PER_HOUR_CEILING, WORKFLOW_AUTONOMY_FORMS_DEFAULT, WORKFLOW_AUTONOMY_MIN_VALUE, 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, MODEL_ID_BYOK_PROVIDERS, MODEL_CLASS_REF_PREFIX, MODEL_SNAPSHOT_SUFFIX, REASONING_EFFORT_VALUES, IMPLICIT_MODEL_SELECTION_SOURCES, PLATFORM_FALLBACK_MODEL_SOURCE, AGENT_NAME_TOKEN, DEFAULT_PERSONA_GUIDE, PERSONAL_SPACE_STARTING_PERSONA, AGENT_LOG_SOURCES, 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, EventType, 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, TYPED_API_KEY, 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_JOURNAL_PROTOCOL_VERSION, WORKFLOW_CONNECTION_KEY_RE, WORKFLOW_SUSPEND_KINDS, WORKFLOW_RUN_NOTIFICATION_SUSPENDED_KINDS, WORKFLOW_SIGNAL_PAYLOAD_MAX_BYTES, WORKFLOW_RESOLVE_OUTPUT_MAX_BYTES, 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;
2039
2081
  var init_dist = __esm({
2040
2082
  "../shared-types/dist/index.mjs"() {
2041
2083
  "use strict";
@@ -2348,16 +2390,243 @@ var init_dist = __esm({
2348
2390
  __name2(isDesktopFileCommandName, "isDesktopFileCommandName");
2349
2391
  __name(isDesktopFileSessionId, "isDesktopFileSessionId");
2350
2392
  __name2(isDesktopFileSessionId, "isDesktopFileSessionId");
2393
+ WORKFLOW_RETRY_BACKOFFS = [
2394
+ "fixed",
2395
+ "exponential"
2396
+ ];
2397
+ WORKFLOW_RETRY_MIN_ATTEMPTS = 1;
2398
+ WORKFLOW_RETRY_POLICY_KEYS = [
2399
+ "maxAttempts",
2400
+ "backoffSeconds",
2401
+ "backoff",
2402
+ "maxBackoffSeconds"
2403
+ ];
2404
+ WORKFLOW_RETRY_MAX_ATTEMPTS = 20;
2405
+ __name(workflowRetryMaxAttemptsMessage, "workflowRetryMaxAttemptsMessage");
2406
+ __name2(workflowRetryMaxAttemptsMessage, "workflowRetryMaxAttemptsMessage");
2407
+ __name(isWithinWorkflowRetryAttempts, "isWithinWorkflowRetryAttempts");
2408
+ __name2(isWithinWorkflowRetryAttempts, "isWithinWorkflowRetryAttempts");
2409
+ WORKFLOW_RETRY_ENGINE_KEYS = [
2410
+ "budgetBaseAttempt"
2411
+ ];
2412
+ __name(workflowRetryUnknownMembersMessage, "workflowRetryUnknownMembersMessage");
2413
+ __name2(workflowRetryUnknownMembersMessage, "workflowRetryUnknownMembersMessage");
2414
+ __name(unknownWorkflowRetryMembers, "unknownWorkflowRetryMembers");
2415
+ __name2(unknownWorkflowRetryMembers, "unknownWorkflowRetryMembers");
2416
+ __name(authoredRetryPolicy, "authoredRetryPolicy");
2417
+ __name2(authoredRetryPolicy, "authoredRetryPolicy");
2418
+ __name(retryBudgetBaseAttempt, "retryBudgetBaseAttempt");
2419
+ __name2(retryBudgetBaseAttempt, "retryBudgetBaseAttempt");
2420
+ __name(retryBudgetAttempt, "retryBudgetAttempt");
2421
+ __name2(retryBudgetAttempt, "retryBudgetAttempt");
2422
+ __name(retryBudgetMaxAttempts, "retryBudgetMaxAttempts");
2423
+ __name2(retryBudgetMaxAttempts, "retryBudgetMaxAttempts");
2424
+ __name(retryBudgetRemaining, "retryBudgetRemaining");
2425
+ __name2(retryBudgetRemaining, "retryBudgetRemaining");
2426
+ __name(retriesRemaining, "retriesRemaining");
2427
+ __name2(retriesRemaining, "retriesRemaining");
2428
+ WORKFLOW_JOB_RESOURCES = [
2429
+ "small",
2430
+ "medium",
2431
+ "large"
2432
+ ];
2433
+ WORKFLOW_SIDE_EFFECTS = [
2434
+ "none",
2435
+ "external"
2436
+ ];
2437
+ WORKFLOW_AGENT_EFFORTS = [
2438
+ "low",
2439
+ "medium",
2440
+ "high"
2441
+ ];
2442
+ WORKFLOW_MODEL_CLASSES = [
2443
+ "fast",
2444
+ "balanced",
2445
+ "strong"
2446
+ ];
2447
+ WORKFLOW_TASK_CLASSES = [
2448
+ "classify",
2449
+ "extract",
2450
+ "transform",
2451
+ "draft",
2452
+ "research",
2453
+ "reason",
2454
+ "code",
2455
+ "judge"
2456
+ ];
2457
+ WORKFLOW_MODEL_TRAITS = [
2458
+ "vision",
2459
+ "structured",
2460
+ "largeContext",
2461
+ "codeExecution"
2462
+ ];
2463
+ WORKFLOW_MODEL_REASON_MAX_LENGTH = 160;
2464
+ __name(workflowModelCostComparison, "workflowModelCostComparison");
2465
+ __name2(workflowModelCostComparison, "workflowModelCostComparison");
2466
+ WORKFLOW_MODELS_COMPOSE_MODES = [
2467
+ "off",
2468
+ "on"
2469
+ ];
2470
+ WORKFLOW_MODELS_PIN_MODES = [
2471
+ "class-only",
2472
+ "allowed"
2473
+ ];
2474
+ WORKFLOW_MODELS_FALLBACK_MODES = [
2475
+ "same-class",
2476
+ "same-provider"
2477
+ ];
2478
+ WORKFLOW_MODELS_CONSENT_ACTIONS_MIN = 1;
2479
+ WORKFLOW_DEFAULT_TASK_CLASS_MAP = Object.freeze({
2480
+ classify: "fast",
2481
+ extract: "fast",
2482
+ transform: "fast",
2483
+ draft: "balanced",
2484
+ research: "balanced",
2485
+ judge: "balanced",
2486
+ reason: "strong",
2487
+ code: "strong"
2488
+ });
2489
+ WORKFLOW_MODELS_MAX_CLASS_DEFAULT = WORKFLOW_MODEL_CLASSES[WORKFLOW_MODEL_CLASSES.length - 1];
2490
+ __name(modelClassRank, "modelClassRank");
2491
+ __name2(modelClassRank, "modelClassRank");
2492
+ __name(modelClassesAtOrBelow, "modelClassesAtOrBelow");
2493
+ __name2(modelClassesAtOrBelow, "modelClassesAtOrBelow");
2494
+ WORKFLOW_AUTONOMY_FORMS = [
2495
+ "graph",
2496
+ "script",
2497
+ "static"
2498
+ ];
2499
+ WORKFLOW_AUTONOMY_NUMERIC_KEYS = [
2500
+ "maxCredits",
2501
+ "maxSteps",
2502
+ "maxDurationSeconds",
2503
+ "maxActions",
2504
+ "maxRunsPerHour"
2505
+ ];
2506
+ WORKFLOW_AUTONOMY_ENVELOPE_KEYS = [
2507
+ "enabled",
2508
+ ...WORKFLOW_AUTONOMY_NUMERIC_KEYS,
2509
+ "forms"
2510
+ ];
2511
+ WORKFLOW_AUTONOMY_ENABLED_DEFAULT = false;
2512
+ WORKFLOW_AUTONOMY_DEFAULTS = Object.freeze({
2513
+ maxCredits: 20,
2514
+ maxSteps: 15,
2515
+ maxDurationSeconds: 86400,
2516
+ maxRunsPerHour: 20
2517
+ });
2518
+ WORKFLOW_AUTONOMY_CEILINGS = Object.freeze({
2519
+ maxSteps: 40,
2520
+ maxDurationSeconds: 604800
2521
+ });
2522
+ WORKFLOW_AUTONOMY_MAX_RUNS_PER_HOUR_ENV = "LUA_WF_AUTONOMY_MAX_RUNS_PER_HOUR";
2523
+ WORKFLOW_AUTONOMY_MAX_RUNS_PER_HOUR_CEILING = 200;
2524
+ __name(workflowAutonomyMaxRunsPerHourCeiling, "workflowAutonomyMaxRunsPerHourCeiling");
2525
+ __name2(workflowAutonomyMaxRunsPerHourCeiling, "workflowAutonomyMaxRunsPerHourCeiling");
2526
+ WORKFLOW_AUTONOMY_FORMS_DEFAULT = Object.freeze([
2527
+ "graph",
2528
+ "static"
2529
+ ]);
2530
+ WORKFLOW_AUTONOMY_MIN_VALUE = 1;
2531
+ __name(isWithinWorkflowAutonomyRange, "isWithinWorkflowAutonomyRange");
2532
+ __name2(isWithinWorkflowAutonomyRange, "isWithinWorkflowAutonomyRange");
2533
+ __name(workflowAutonomyRangeMessage, "workflowAutonomyRangeMessage");
2534
+ __name2(workflowAutonomyRangeMessage, "workflowAutonomyRangeMessage");
2535
+ WORKFLOW_JOB_RANGES = Object.freeze({
2536
+ /** Coding-turn cap (`claude -p --max-turns`); absent ⇒ the cluster default (LUA_WF_JOB_MAX_TURNS). */
2537
+ maxTurns: Object.freeze({
2538
+ min: 1,
2539
+ max: 500
2540
+ }),
2541
+ /** Harness messages per attempt (one per content block); absent ⇒ the cluster default (400). */
2542
+ maxMessages: Object.freeze({
2543
+ min: 1,
2544
+ max: 5e3
2545
+ }),
2546
+ /** Input-side tokens per attempt (prompt + cache); absent ⇒ the cluster default (4M — LUA-708, was 30M). */
2547
+ maxInputTokens: Object.freeze({
2548
+ min: 1e6,
2549
+ max: 5e8
2550
+ })
2551
+ });
2552
+ WORKFLOW_JOB_RANGE_MEMBERS = Object.keys(WORKFLOW_JOB_RANGES);
2553
+ __name(isWithinWorkflowJobRange, "isWithinWorkflowJobRange");
2554
+ __name2(isWithinWorkflowJobRange, "isWithinWorkflowJobRange");
2555
+ __name(workflowJobRangeMessage, "workflowJobRangeMessage");
2556
+ __name2(workflowJobRangeMessage, "workflowJobRangeMessage");
2557
+ WORKFLOW_SINGLE_STEP_TYPES = [
2558
+ "agent",
2559
+ "tool",
2560
+ "workflow",
2561
+ "step"
2562
+ ];
2563
+ WORKFLOW_HITL_ENTRY_TYPES = [
2564
+ "approval",
2565
+ "waitForSignal"
2566
+ ];
2567
+ WORKFLOW_ARM_ENTRY_TYPES = [
2568
+ ...WORKFLOW_SINGLE_STEP_TYPES,
2569
+ ...WORKFLOW_HITL_ENTRY_TYPES
2570
+ ];
2571
+ WORKFLOW_HITL_ARM_CONTAINERS = [
2572
+ "parallel",
2573
+ "conditional",
2574
+ "foreach"
2575
+ ];
2576
+ __name(isWorkflowSingleStepType, "isWorkflowSingleStepType");
2577
+ __name2(isWorkflowSingleStepType, "isWorkflowSingleStepType");
2578
+ __name(isWorkflowHitlEntryType, "isWorkflowHitlEntryType");
2579
+ __name2(isWorkflowHitlEntryType, "isWorkflowHitlEntryType");
2580
+ __name(isWorkflowArmEntryType, "isWorkflowArmEntryType");
2581
+ __name2(isWorkflowArmEntryType, "isWorkflowArmEntryType");
2582
+ __name(workflowContainerRunsHitlArm, "workflowContainerRunsHitlArm");
2583
+ __name2(workflowContainerRunsHitlArm, "workflowContainerRunsHitlArm");
2584
+ __name(workflowHitlArmUnsupportedMessage, "workflowHitlArmUnsupportedMessage");
2585
+ __name2(workflowHitlArmUnsupportedMessage, "workflowHitlArmUnsupportedMessage");
2586
+ __name(workflowHitlArmShapeMessage, "workflowHitlArmShapeMessage");
2587
+ __name2(workflowHitlArmShapeMessage, "workflowHitlArmShapeMessage");
2588
+ WORKFLOW_GRAPH_ENTRY_STEP_KINDS = Object.freeze({
2589
+ agent: "agent",
2590
+ tool: "tool",
2591
+ workflow: "subrun",
2592
+ step: "code",
2593
+ mapping: "map",
2594
+ sleep: "sleep",
2595
+ sleepUntil: "sleepUntil",
2596
+ parallel: null,
2597
+ conditional: "branch",
2598
+ foreach: "foreach",
2599
+ loop: "loop",
2600
+ approval: "approval",
2601
+ waitForSignal: "signal"
2602
+ });
2603
+ WORKFLOW_ARM_ENTRY_STEP_KINDS = Object.freeze(Object.fromEntries(WORKFLOW_ARM_ENTRY_TYPES.map((t) => [
2604
+ t,
2605
+ WORKFLOW_GRAPH_ENTRY_STEP_KINDS[t]
2606
+ ])));
2607
+ WORKFLOW_BUDGET_MAX_DURATION_SECONDS = Object.freeze({
2608
+ min: 60,
2609
+ max: 2592e3
2610
+ });
2351
2611
  MODEL_ID_BYOK_PROVIDERS = [
2352
2612
  "azure",
2353
2613
  "bedrock"
2354
2614
  ];
2355
2615
  __name(isModelIdSentinel, "isModelIdSentinel");
2356
2616
  __name2(isModelIdSentinel, "isModelIdSentinel");
2617
+ MODEL_CLASS_REF_PREFIX = "class/";
2618
+ __name(isModelClassRef, "isModelClassRef");
2619
+ __name2(isModelClassRef, "isModelClassRef");
2620
+ __name(modelClassOf, "modelClassOf");
2621
+ __name2(modelClassOf, "modelClassOf");
2622
+ __name(modelClassRef, "modelClassRef");
2623
+ __name2(modelClassRef, "modelClassRef");
2357
2624
  __name(normalizeModelId, "normalizeModelId");
2358
2625
  __name2(normalizeModelId, "normalizeModelId");
2359
2626
  __name(modelUnresolvedMessage, "modelUnresolvedMessage");
2360
2627
  __name2(modelUnresolvedMessage, "modelUnresolvedMessage");
2628
+ __name(modelClassUnresolvedMessage, "modelClassUnresolvedMessage");
2629
+ __name2(modelClassUnresolvedMessage, "modelClassUnresolvedMessage");
2361
2630
  __name(providerModelId, "providerModelId");
2362
2631
  __name2(providerModelId, "providerModelId");
2363
2632
  MODEL_SNAPSHOT_SUFFIX = /(?:[-@](?:19|20)\d{2}(?:0[1-9]|1[0-2])(?:0[1-9]|[12]\d|3[01])|-(?:19|20)\d{2}-(?:0[1-9]|1[0-2])-(?:0[1-9]|[12]\d|3[01]))$/;
@@ -3030,7 +3299,15 @@ This text is who you are for this person. As you learn them, their name, their w
3030
3299
  "org-grant",
3031
3300
  "agent-grant-only"
3032
3301
  ]).describe("For user and staff principals, grant provenance: org-grant means a stored org grant produced the row. For owner-ceiling API keys, effective provenance: org-grant means the credential-owner intersection has org-level capability; agent-grant-only means the intersection reaches only an exact agent inside the org."),
3033
- anomalies: z3.array(ProjectionAnomalySchema).optional()
3302
+ anomalies: z3.array(ProjectionAnomalySchema).optional(),
3303
+ /**
3304
+ * How many agents and Spaces in this org the caller can read — the size of
3305
+ * the org's resource page under the same discovery rule, without paging it.
3306
+ */
3307
+ resourceCounts: z3.object({
3308
+ agents: z3.number().int().nonnegative(),
3309
+ spaces: z3.number().int().nonnegative()
3310
+ }).optional()
3034
3311
  }).passthrough();
3035
3312
  ProjectedResourceSchema = z3.object({
3036
3313
  resourceType: z3.literal("agent"),
@@ -3069,7 +3346,21 @@ This text is who you are for this person. As you learn them, their name, their w
3069
3346
  id: z3.string().min(1).max(256),
3070
3347
  name: z3.string().optional(),
3071
3348
  email: z3.string().optional()
3072
- }).optional()
3349
+ }).optional(),
3350
+ /**
3351
+ * Presentation enrichment (PRO-1994), product data only — never influences
3352
+ * discovery. These moved off the O(orgs) `/context` roster onto the bounded
3353
+ * per-active-org resource page so Desktop stops paying an org-count-scaled
3354
+ * cost at sign-in. `persona`/`avatar` are loose (`PersonaText` / `AgentAvatar`
3355
+ * are structured-or-string), `platform` marks the org's Designer agent
3356
+ * (previously stamped only by `/context`; retires with PRO-1657).
3357
+ */
3358
+ persona: z3.unknown().optional(),
3359
+ description: z3.string().optional(),
3360
+ avatar: z3.unknown().nullish(),
3361
+ platform: z3.boolean().optional(),
3362
+ /** A Space's supervised agent ids (`kind: 'space'` rows only). */
3363
+ supervisedAgents: z3.array(z3.string()).optional()
3073
3364
  }).passthrough();
3074
3365
  CapabilityProfilesSchema = z3.record(z3.string().min(1).max(64), z3.array(ProjectedScopeSchema));
3075
3366
  RoleCatalogSchema = z3.record(z3.string().min(1).max(128), z3.object({
@@ -3159,7 +3450,8 @@ This text is who you are for this person. As you learn them, their name, their w
3159
3450
  "org_archived",
3160
3451
  "disabled",
3161
3452
  "exception",
3162
- "budget"
3453
+ "budget",
3454
+ "model_policy"
3163
3455
  ];
3164
3456
  WORKFLOW_STEP_STATUSES = [
3165
3457
  "pending",
@@ -3244,126 +3536,6 @@ This text is who you are for this person. As you learn them, their name, their w
3244
3536
  ];
3245
3537
  WORKFLOW_SIGNAL_PAYLOAD_MAX_BYTES = 64 * 1024;
3246
3538
  WORKFLOW_RESOLVE_OUTPUT_MAX_BYTES = 256 * 1024;
3247
- WORKFLOW_RETRY_BACKOFFS = [
3248
- "fixed",
3249
- "exponential"
3250
- ];
3251
- WORKFLOW_RETRY_MIN_ATTEMPTS = 1;
3252
- WORKFLOW_RETRY_POLICY_KEYS = [
3253
- "maxAttempts",
3254
- "backoffSeconds",
3255
- "backoff",
3256
- "maxBackoffSeconds"
3257
- ];
3258
- WORKFLOW_RETRY_MAX_ATTEMPTS = 20;
3259
- __name(workflowRetryMaxAttemptsMessage, "workflowRetryMaxAttemptsMessage");
3260
- __name2(workflowRetryMaxAttemptsMessage, "workflowRetryMaxAttemptsMessage");
3261
- __name(isWithinWorkflowRetryAttempts, "isWithinWorkflowRetryAttempts");
3262
- __name2(isWithinWorkflowRetryAttempts, "isWithinWorkflowRetryAttempts");
3263
- WORKFLOW_RETRY_ENGINE_KEYS = [
3264
- "budgetBaseAttempt"
3265
- ];
3266
- __name(workflowRetryUnknownMembersMessage, "workflowRetryUnknownMembersMessage");
3267
- __name2(workflowRetryUnknownMembersMessage, "workflowRetryUnknownMembersMessage");
3268
- __name(unknownWorkflowRetryMembers, "unknownWorkflowRetryMembers");
3269
- __name2(unknownWorkflowRetryMembers, "unknownWorkflowRetryMembers");
3270
- __name(authoredRetryPolicy, "authoredRetryPolicy");
3271
- __name2(authoredRetryPolicy, "authoredRetryPolicy");
3272
- __name(retryBudgetBaseAttempt, "retryBudgetBaseAttempt");
3273
- __name2(retryBudgetBaseAttempt, "retryBudgetBaseAttempt");
3274
- __name(retryBudgetAttempt, "retryBudgetAttempt");
3275
- __name2(retryBudgetAttempt, "retryBudgetAttempt");
3276
- __name(retryBudgetMaxAttempts, "retryBudgetMaxAttempts");
3277
- __name2(retryBudgetMaxAttempts, "retryBudgetMaxAttempts");
3278
- __name(retryBudgetRemaining, "retryBudgetRemaining");
3279
- __name2(retryBudgetRemaining, "retryBudgetRemaining");
3280
- __name(retriesRemaining, "retriesRemaining");
3281
- __name2(retriesRemaining, "retriesRemaining");
3282
- WORKFLOW_JOB_RESOURCES = [
3283
- "small",
3284
- "medium",
3285
- "large"
3286
- ];
3287
- WORKFLOW_SIDE_EFFECTS = [
3288
- "none",
3289
- "external"
3290
- ];
3291
- WORKFLOW_JOB_RANGES = Object.freeze({
3292
- /** Coding-turn cap (`claude -p --max-turns`); absent ⇒ the cluster default (LUA_WF_JOB_MAX_TURNS). */
3293
- maxTurns: Object.freeze({
3294
- min: 1,
3295
- max: 500
3296
- }),
3297
- /** Harness messages per attempt (one per content block); absent ⇒ the cluster default (400). */
3298
- maxMessages: Object.freeze({
3299
- min: 1,
3300
- max: 5e3
3301
- }),
3302
- /** Input-side tokens per attempt (prompt + cache); absent ⇒ the cluster default (4M — LUA-708, was 30M). */
3303
- maxInputTokens: Object.freeze({
3304
- min: 1e6,
3305
- max: 5e8
3306
- })
3307
- });
3308
- WORKFLOW_JOB_RANGE_MEMBERS = Object.keys(WORKFLOW_JOB_RANGES);
3309
- __name(isWithinWorkflowJobRange, "isWithinWorkflowJobRange");
3310
- __name2(isWithinWorkflowJobRange, "isWithinWorkflowJobRange");
3311
- __name(workflowJobRangeMessage, "workflowJobRangeMessage");
3312
- __name2(workflowJobRangeMessage, "workflowJobRangeMessage");
3313
- WORKFLOW_SINGLE_STEP_TYPES = [
3314
- "agent",
3315
- "tool",
3316
- "workflow",
3317
- "step"
3318
- ];
3319
- WORKFLOW_HITL_ENTRY_TYPES = [
3320
- "approval",
3321
- "waitForSignal"
3322
- ];
3323
- WORKFLOW_ARM_ENTRY_TYPES = [
3324
- ...WORKFLOW_SINGLE_STEP_TYPES,
3325
- ...WORKFLOW_HITL_ENTRY_TYPES
3326
- ];
3327
- WORKFLOW_HITL_ARM_CONTAINERS = [
3328
- "parallel",
3329
- "conditional",
3330
- "foreach"
3331
- ];
3332
- __name(isWorkflowSingleStepType, "isWorkflowSingleStepType");
3333
- __name2(isWorkflowSingleStepType, "isWorkflowSingleStepType");
3334
- __name(isWorkflowHitlEntryType, "isWorkflowHitlEntryType");
3335
- __name2(isWorkflowHitlEntryType, "isWorkflowHitlEntryType");
3336
- __name(isWorkflowArmEntryType, "isWorkflowArmEntryType");
3337
- __name2(isWorkflowArmEntryType, "isWorkflowArmEntryType");
3338
- __name(workflowContainerRunsHitlArm, "workflowContainerRunsHitlArm");
3339
- __name2(workflowContainerRunsHitlArm, "workflowContainerRunsHitlArm");
3340
- __name(workflowHitlArmUnsupportedMessage, "workflowHitlArmUnsupportedMessage");
3341
- __name2(workflowHitlArmUnsupportedMessage, "workflowHitlArmUnsupportedMessage");
3342
- __name(workflowHitlArmShapeMessage, "workflowHitlArmShapeMessage");
3343
- __name2(workflowHitlArmShapeMessage, "workflowHitlArmShapeMessage");
3344
- WORKFLOW_GRAPH_ENTRY_STEP_KINDS = Object.freeze({
3345
- agent: "agent",
3346
- tool: "tool",
3347
- workflow: "subrun",
3348
- step: "code",
3349
- mapping: "map",
3350
- sleep: "sleep",
3351
- sleepUntil: "sleepUntil",
3352
- parallel: null,
3353
- conditional: "branch",
3354
- foreach: "foreach",
3355
- loop: "loop",
3356
- approval: "approval",
3357
- waitForSignal: "signal"
3358
- });
3359
- WORKFLOW_ARM_ENTRY_STEP_KINDS = Object.freeze(Object.fromEntries(WORKFLOW_ARM_ENTRY_TYPES.map((t) => [
3360
- t,
3361
- WORKFLOW_GRAPH_ENTRY_STEP_KINDS[t]
3362
- ])));
3363
- WORKFLOW_BUDGET_MAX_DURATION_SECONDS = Object.freeze({
3364
- min: 60,
3365
- max: 2592e3
3366
- });
3367
3539
  WORKFLOW_GOAL_JUDGE_SELF = "$self";
3368
3540
  __name(workflowGoalJudgeKind, "workflowGoalJudgeKind");
3369
3541
  __name2(workflowGoalJudgeKind, "workflowGoalJudgeKind");
@@ -3568,7 +3740,20 @@ This text is who you are for this person. As you learn them, their name, their w
3568
3740
  "workflow.export.auto_pushed",
3569
3741
  "workflow.retention.restamped",
3570
3742
  "workflow.retention.reaped",
3571
- "workflow.run.schema_migrated"
3743
+ "workflow.run.schema_migrated",
3744
+ // --- per-step model selection (Workflow Model Selection plan 6.5 / Appendix C.4) ---
3745
+ /** A `PATCH /admin/orgs/:orgId/workflow-policy` that changed the `models` block (who, what moved). */
3746
+ "workflow.policy.models_changed",
3747
+ /** A step's invocation hopped to another leg of its class — `{from, to, reason}`, priced at the served model. */
3748
+ "workflow.step.model_fallback",
3749
+ // --- autonomy envelope (Workflow autonomy plan A1; research/consent-gates.md §H2) ---
3750
+ /**
3751
+ * A start the consent ladder would have PARKED was admitted by `workflowPolicy.autonomy` instead —
3752
+ * `WorkflowRunAutonomyAppliedPayload`. Deliberately NOT `workflow.run.gate_cleared`: nothing was
3753
+ * gated and nobody approved it, and conflating the two would make "who approved this run"
3754
+ * unanswerable for every run of either kind (§H2 "Audit").
3755
+ */
3756
+ "workflow.run.autonomy_applied"
3572
3757
  ];
3573
3758
  WORKFLOW_AUDIT_METADATA_MAX_BYTES = 4 * 1024;
3574
3759
  __name(isWorkflowAuditEvent, "isWorkflowAuditEvent");
@@ -4629,7 +4814,7 @@ function modelTemplateInvalidMessage(model, why) {
4629
4814
  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>}`;
4630
4815
  }
4631
4816
  function modelTemplateDefaultRequiredMessage(model) {
4632
- 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>}")}`;
4817
+ 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>}")} or a class reference (|class/fast, |class/balanced, |class/strong)`;
4633
4818
  }
4634
4819
  function staticModelPin(model) {
4635
4820
  if (typeof model !== "string") return void 0;
@@ -5221,6 +5406,21 @@ function validateLuaExtensions(g, caps = WORKFLOW_CAPS_DEFAULT, opts = {
5221
5406
  err("required-connection-unknown", `requiredConnections ${JSON.stringify(unknown)} are neither declared connections[].key values nor connections the owner can mount`, `${path26}.requiredConnections`, singleId(node));
5222
5407
  }
5223
5408
  }, "checkRequiredConnections");
5409
+ const jobClassifiablePin = /* @__PURE__ */ __name4((model) => {
5410
+ const pin = staticModelPin(model);
5411
+ const modelClass = modelClassOf(pin);
5412
+ if (modelClass === void 0) return pin;
5413
+ const codes = opts.classMap?.[modelClass];
5414
+ if (!codes) return void 0;
5415
+ const jobProviders = opts.policy?.jobProviders;
5416
+ for (const code of codes) {
5417
+ const p = classifyModelProvider(code);
5418
+ if (p === null) continue;
5419
+ if (jobProviders && !jobProviders.includes(p)) continue;
5420
+ return code;
5421
+ }
5422
+ return void 0;
5423
+ }, "jobClassifiablePin");
5224
5424
  const checkTier = /* @__PURE__ */ __name4((node, path26) => {
5225
5425
  const id = singleId(node);
5226
5426
  if (node.workspace && node.workspace !== "inherit" && node.tier !== void 0 && node.tier !== "job") {
@@ -5229,7 +5429,7 @@ function validateLuaExtensions(g, caps = WORKFLOW_CAPS_DEFAULT, opts = {
5229
5429
  if (node.harness !== void 0 && node.tier !== "job") {
5230
5430
  err("harness-requires-job-tier", "`harness` is only legal on a tier:'job' agent step", `${path26}.harness`, id);
5231
5431
  }
5232
- const provider = node.type === "agent" ? classifyModelProvider(staticModelPin(node.model)) : null;
5432
+ const provider = node.type === "agent" ? classifyModelProvider(jobClassifiablePin(node.model)) : null;
5233
5433
  if (node.harness === "claude-code" && provider !== null && provider !== "anthropic") {
5234
5434
  err("harness-provider-mismatch", `harness:'claude-code' needs an Anthropic model (model "${node.type === "agent" ? node.model : ""}" is ${provider})`, `${path26}.harness`, id);
5235
5435
  }
@@ -5253,6 +5453,7 @@ function validateLuaExtensions(g, caps = WORKFLOW_CAPS_DEFAULT, opts = {
5253
5453
  }
5254
5454
  const pin = parsed.kind === "template" ? parsed.template.default : node.model;
5255
5455
  if (pin === void 0) return;
5456
+ if (isModelClassRef(pin)) return;
5256
5457
  const inContext = /* @__PURE__ */ __name4((message) => parsed.kind === "template" ? `${message} (the default of ${parsed.template.placeholder})` : message, "inContext");
5257
5458
  const registry = opts.approvedModels;
5258
5459
  if (registry === void 0) return;
@@ -5266,6 +5467,12 @@ function validateLuaExtensions(g, caps = WORKFLOW_CAPS_DEFAULT, opts = {
5266
5467
  const resolved = normalizeModelId(pin, registry);
5267
5468
  if (!resolved.ok) err("model-unresolved", inContext(modelUnresolvedMessage(resolved)), `${path26}.model`, id);
5268
5469
  }, "checkModel");
5470
+ const checkTaskClass = /* @__PURE__ */ __name4((node, path26) => {
5471
+ if (node.type !== "agent" || node.taskClass === void 0) return;
5472
+ if (!opts.static) return;
5473
+ if (typeof node.model === "string" && node.model.trim()) return;
5474
+ err("task-class-without-model", `taskClass '${String(node.taskClass)}' needs a \`model\` on a pushed definition \u2014 write a class (model: 'class/fast' | 'class/balanced' | 'class/strong') or an approved provider/model code; nothing maps a task class to a model at dispatch, so a step with neither would run on the agent\u2019s own model`, `${path26}.taskClass`, singleId(node));
5475
+ }, "checkTaskClass");
5269
5476
  const checkWorkspace = /* @__PURE__ */ __name4((node, path26) => {
5270
5477
  const id = singleId(node);
5271
5478
  const ws = workspaceOf(node);
@@ -5352,6 +5559,7 @@ function validateLuaExtensions(g, caps = WORKFLOW_CAPS_DEFAULT, opts = {
5352
5559
  checkTimeout(node, path26);
5353
5560
  checkTier(node, path26);
5354
5561
  checkModel(node, path26);
5562
+ checkTaskClass(node, path26);
5355
5563
  checkRetry(node, path26);
5356
5564
  checkWorkspace(node, path26);
5357
5565
  if (!opts.static) {
@@ -8921,6 +9129,10 @@ var init_workflow = __esm({
8921
9129
  maxDurationSeconds: cfg.budget?.maxDurationSeconds ?? (hitl ? WORKFLOW_HITL_MAX_DURATION_SECONDS : WORKFLOW_DEFAULT_MAX_DURATION_SECONDS)
8922
9130
  });
8923
9131
  const envelope = {
9132
+ // A plain build/push is ALWAYS marker 1 (plan 6.4's compatibility row: "a CLI test that a plain push of
9133
+ // such a definition stays at 1"). Moving a definition to 2 — the effort marker — is an explicit act
9134
+ // (`lua push --apply-effort`, or a new compose while assignment is on), never a side effect of the SDK
9135
+ // gaining an `effort` member.
8924
9136
  luaWorkflow: 1,
8925
9137
  budget,
8926
9138
  definition: defined({
@@ -9241,6 +9453,10 @@ var init_workflow = __esm({
9241
9453
  promptTemplate: templateText(opts.prompt),
9242
9454
  outputSchema: schemaToJson(opts.outputSchema),
9243
9455
  model: opts.model,
9456
+ taskClass: opts.taskClass,
9457
+ requires: opts.requires,
9458
+ modelReason: opts.modelReason,
9459
+ effort: opts.effort,
9244
9460
  toolScope: opts.toolScope,
9245
9461
  systemPrompt: opts.systemPrompt,
9246
9462
  timeoutSeconds: opts.timeoutSeconds,
@@ -20340,6 +20556,8 @@ function sketchTopology(sourceFile, exportName, name, description) {
20340
20556
  }
20341
20557
  return {
20342
20558
  graph: {
20559
+ // 1 is and stays the serializer's marker: the effort marker (2) is opted into by
20560
+ // `lua push --apply-effort` or a new compose (plan 6.4), never by a plain compile.
20343
20561
  luaWorkflow: 1,
20344
20562
  definition: {
20345
20563
  id: name,
@@ -20465,7 +20683,7 @@ function computeDeferred(graph, opts = {}) {
20465
20683
  deferred.add("job-tier-provider-unsupported");
20466
20684
  }
20467
20685
  const modelPin = n2.type === "agent" ? staticModelPin(n2.model) : void 0;
20468
- if (modelPin !== void 0 && !isModelIdSentinel(modelPin)) deferred.add("model-unresolved");
20686
+ if (modelPin !== void 0 && !isModelIdSentinel(modelPin) && !isModelClassRef(modelPin)) deferred.add("model-unresolved");
20469
20687
  if (Array.isArray(n2.requiredConnections) && n2.requiredConnections.some(serverDecides)) deferred.add("required-connection-unknown");
20470
20688
  if (n2.type === "approval") {
20471
20689
  const a = n2.approver;
@@ -26430,6 +26648,68 @@ var init_workflow_api_service = __esm({
26430
26648
  const qs = query.toString();
26431
26649
  return this.httpGet(`${this.runs}/${runId}/steps/${pathId(stepId)}/job${qs ? `?${qs}` : ""}`, await this.auth());
26432
26650
  }
26651
+ // ─── [WMC-E7] Per-step model selection (§6.5, §6.7) ───
26652
+ /**
26653
+ * §6.5 — the organization's workflow policy, `models` block included. The route is the organization's, not
26654
+ * the agent's, so the orgId comes from the project config rather than from `this.agentId`.
26655
+ */
26656
+ async getWorkflowPolicy(orgId, opts = {}) {
26657
+ const qs = opts.effective ? "?effective=true" : "";
26658
+ return this.httpGet(`/admin/orgs/${encodeURIComponent(orgId)}/workflow-policy${qs}`, await this.auth());
26659
+ }
26660
+ /**
26661
+ * §6.5 — PATCH the `models` block. Only the members the caller named are sent, so a `set` of one field
26662
+ * never clears the rest; the server validates against the organization's effective model set and refuses
26663
+ * with a code the CLI prints verbatim (a class with no eligible row, a cap the raise would exceed).
26664
+ */
26665
+ async patchWorkflowPolicyModels(orgId, models) {
26666
+ return this.httpPatch(`/admin/orgs/${encodeURIComponent(orgId)}/workflow-policy`, {
26667
+ models
26668
+ }, await this.auth());
26669
+ }
26670
+ // ─── [WMC-A6] Autonomy — the pre-consented envelope (research §H3) ───
26671
+ /**
26672
+ * PATCH the `autonomy` block of the ORGANIZATION's policy — the same R23 route the `models` block uses, and
26673
+ * a sibling of it in the body, so one PATCH never has to carry two blocks it did not mean to touch.
26674
+ *
26675
+ * A member sent as `null` is CLEARED (`--clear`); a member omitted is left exactly as it was. That
26676
+ * distinction is the route's, not the CLI's — which is why the patch type carries `null` rather than the CLI
26677
+ * collapsing it to an absent key on the way out.
26678
+ *
26679
+ * Every ceiling is the server's: `caps.maxCreditsPerRun`, the organization's own `models.consentActions` and
26680
+ * the platform's runs-per-hour env are all figures this client has never seen, so a value above one comes
26681
+ * back as a typed 400 and is printed verbatim.
26682
+ */
26683
+ async patchWorkflowPolicyAutonomy(orgId, autonomy) {
26684
+ return this.httpPatch(`/admin/orgs/${encodeURIComponent(orgId)}/workflow-policy`, {
26685
+ autonomy
26686
+ }, await this.auth());
26687
+ }
26688
+ /*
26689
+ * There is deliberately NO per-agent writer here. `SubAgentWorkflowSettings.autonomy` is read by
26690
+ * `effectiveWorkflowAutonomy`, but no HTTP surface writes it: `UpdateSubAgentRequestDto` has no
26691
+ * `workflows` member, so a PATCH carrying one is accepted and DISCARDED. A client method that posted a
26692
+ * narrowing into that hole would return 200 and change nothing, and the CLI would print a success line
26693
+ * over it — on a consent surface, a false confirmation is worse than a missing feature. The read half
26694
+ * already works: `?effective=true` shows a per-agent narrowing when the projection carries one.
26695
+ */
26696
+ /**
26697
+ * §6.5 — clear a run gate by kind. `model_policy` is the kind a class request that could not be resolved
26698
+ * parks on; the sweep clears it on its own when the switch returns, and this is the by-hand path.
26699
+ */
26700
+ async clearRunGate(runId, kind) {
26701
+ return this.httpPost(`${this.runs}/${runId}/clear-gate`, {
26702
+ kind
26703
+ }, await this.auth());
26704
+ }
26705
+ /**
26706
+ * §6.4 (Q19) — the deterministic rewrite of a dynamic parent's stored task classes into `class/<c>`.
26707
+ * Not a fresh model composition: the server rewrites and publishes a NEW version on the immutable parent,
26708
+ * and answers with it, so the CLI only has to print the version it got back.
26709
+ */
26710
+ async recomposeWorkflow(workflowId) {
26711
+ return this.httpPost(`${this.base}/${workflowId}/recompose`, {}, await this.auth());
26712
+ }
26433
26713
  };
26434
26714
  }
26435
26715
  });
@@ -36063,6 +36343,117 @@ __name(describeEnvOverlay, "describeEnvOverlay");
36063
36343
 
36064
36344
  // src/primitives/workflow.handler.ts
36065
36345
  init_base_handler();
36346
+
36347
+ // src/interfaces/workflow-model-classes.ts
36348
+ init_dist();
36349
+ var has = /* @__PURE__ */ __name((tuple, v) => tuple.includes(v), "has");
36350
+ var isWorkflowModelClass = /* @__PURE__ */ __name((v) => has(WORKFLOW_MODEL_CLASSES, v), "isWorkflowModelClass");
36351
+ var isWorkflowTaskClass = /* @__PURE__ */ __name((v) => has(WORKFLOW_TASK_CLASSES, v), "isWorkflowTaskClass");
36352
+ var isWorkflowModelTrait = /* @__PURE__ */ __name((v) => has(WORKFLOW_MODEL_TRAITS, v), "isWorkflowModelTrait");
36353
+ var isWorkflowEffort = /* @__PURE__ */ __name((v) => has(WORKFLOW_AGENT_EFFORTS, v), "isWorkflowEffort");
36354
+ function isWrittenAsModelClassRef(model) {
36355
+ return (model ?? "").trim().toLowerCase().startsWith(MODEL_CLASS_REF_PREFIX);
36356
+ }
36357
+ __name(isWrittenAsModelClassRef, "isWrittenAsModelClassRef");
36358
+ var oneOf = /* @__PURE__ */ __name((tuple) => tuple.map((v) => `\`${v}\``).join(", "), "oneOf");
36359
+ function validateAgentNodeModelMembers(node, path26) {
36360
+ const issues = [];
36361
+ if (typeof node.model === "string" && isWrittenAsModelClassRef(node.model)) {
36362
+ if (!modelClassOf(node.model)) {
36363
+ issues.push({
36364
+ path: `${path26}.model`,
36365
+ code: "model-class-unknown",
36366
+ message: `"${node.model}" is not a model class \u2014 use one of ${oneOf(WORKFLOW_MODEL_CLASSES.map((c) => modelClassRef(c)))}, or pin an approved model code`
36367
+ });
36368
+ }
36369
+ }
36370
+ if (node.taskClass !== void 0) {
36371
+ if (typeof node.taskClass !== "string" || !isWorkflowTaskClass(node.taskClass)) {
36372
+ issues.push({
36373
+ path: `${path26}.taskClass`,
36374
+ code: "task-class-unknown",
36375
+ message: `"${String(node.taskClass)}" is not a task class \u2014 use one of ${oneOf(WORKFLOW_TASK_CLASSES)}`
36376
+ });
36377
+ }
36378
+ }
36379
+ if (node.requires !== void 0) {
36380
+ if (!Array.isArray(node.requires)) {
36381
+ issues.push({
36382
+ path: `${path26}.requires`,
36383
+ code: "requires-invalid",
36384
+ message: `\`requires\` must be an array of ${oneOf(WORKFLOW_MODEL_TRAITS)}`
36385
+ });
36386
+ } else {
36387
+ node.requires.forEach((trait, i) => {
36388
+ if (typeof trait !== "string" || !isWorkflowModelTrait(trait)) {
36389
+ issues.push({
36390
+ path: `${path26}.requires.${i}`,
36391
+ code: "model-trait-unknown",
36392
+ message: `"${String(trait)}" is not a model trait \u2014 use one of ${oneOf(WORKFLOW_MODEL_TRAITS)}`
36393
+ });
36394
+ }
36395
+ });
36396
+ }
36397
+ }
36398
+ if (node.effort !== void 0) {
36399
+ if (typeof node.effort !== "string" || !isWorkflowEffort(node.effort)) {
36400
+ issues.push({
36401
+ path: `${path26}.effort`,
36402
+ code: "effort-unknown",
36403
+ message: `"${String(node.effort)}" is not a workflow effort \u2014 use one of ${oneOf(WORKFLOW_AGENT_EFFORTS)}. (\`off\`, \`minimal\` and \`max\` are the agent-level \`modelSettings.reasoning.effort\` scale, not this one.)`
36404
+ });
36405
+ }
36406
+ }
36407
+ if (node.modelReason !== void 0) {
36408
+ if (typeof node.modelReason !== "string") {
36409
+ issues.push({
36410
+ path: `${path26}.modelReason`,
36411
+ code: "model-reason-invalid",
36412
+ message: "`modelReason` must be a string"
36413
+ });
36414
+ } else if (node.modelReason.length > WORKFLOW_MODEL_REASON_MAX_LENGTH) {
36415
+ issues.push({
36416
+ path: `${path26}.modelReason`,
36417
+ code: "model-reason-too-long",
36418
+ message: `\`modelReason\` is ${node.modelReason.length} characters \u2014 the cap is ${WORKFLOW_MODEL_REASON_MAX_LENGTH}`
36419
+ });
36420
+ }
36421
+ }
36422
+ return issues;
36423
+ }
36424
+ __name(validateAgentNodeModelMembers, "validateAgentNodeModelMembers");
36425
+ var WORKFLOW_MODEL_WALK_MAX_DEPTH = 64;
36426
+ var MEMBERS = [
36427
+ "model",
36428
+ "taskClass",
36429
+ "requires",
36430
+ "effort",
36431
+ "modelReason"
36432
+ ];
36433
+ function validateGraphModelMembers(graph) {
36434
+ const issues = [];
36435
+ const seen = /* @__PURE__ */ new Set();
36436
+ const walk3 = /* @__PURE__ */ __name((value3, path26, depth) => {
36437
+ if (depth > WORKFLOW_MODEL_WALK_MAX_DEPTH || value3 === null || typeof value3 !== "object") return;
36438
+ if (seen.has(value3)) return;
36439
+ seen.add(value3);
36440
+ if (Array.isArray(value3)) {
36441
+ value3.forEach((v, i) => walk3(v, `${path26}.${i}`, depth + 1));
36442
+ return;
36443
+ }
36444
+ const node = value3;
36445
+ if (MEMBERS.some((m) => node[m] !== void 0)) {
36446
+ const label2 = typeof node.id === "string" && node.id ? node.id : path26;
36447
+ issues.push(...validateAgentNodeModelMembers(node, label2));
36448
+ }
36449
+ for (const [k, v] of Object.entries(node)) walk3(v, path26 ? `${path26}.${k}` : k, depth + 1);
36450
+ }, "walk");
36451
+ walk3(graph, "", 0);
36452
+ return issues;
36453
+ }
36454
+ __name(validateGraphModelMembers, "validateGraphModelMembers");
36455
+
36456
+ // src/primitives/workflow.handler.ts
36066
36457
  var WorkflowHandler = class extends BaseVersionedHandler {
36067
36458
  static {
36068
36459
  __name(this, "WorkflowHandler");
@@ -36147,6 +36538,8 @@ var WorkflowHandler = class extends BaseVersionedHandler {
36147
36538
  const primitive = findPrimitive(manifest, name, this.kind);
36148
36539
  if (!primitive) return null;
36149
36540
  if (primitive.unplacedStepIds?.length) throw unplacedStepError(primitive.name, primitive.unplacedStepIds);
36541
+ const modelIssues = validateGraphModelMembers(primitive.form === "script" ? primitive.meta : primitive.graph);
36542
+ if (modelIssues.length) throw workflowModelMemberError(primitive.name, modelIssues);
36150
36543
  if (primitive.form === "script") return this.buildPushData(primitive, void 0);
36151
36544
  const data = super.prepareForPush(manifest, name, projectPath, bundleAccumulator);
36152
36545
  if (!data) return null;
@@ -36293,6 +36686,17 @@ function workflowNameTakenHint(name, error) {
36293
36686
  return `workflow name "${name}" is held by ${holder}${id} \u2014 ${see}. Push does not replace it: rename this workflow, or delete the other one first.`;
36294
36687
  }
36295
36688
  __name(workflowNameTakenHint, "workflowNameTakenHint");
36689
+ function workflowModelMemberError(workflowName, issues) {
36690
+ return new CliError("error", `workflow "${workflowName}" is not pushed: ${issues.length} model-selection ${issues.length === 1 ? "value is" : "values are"} not in the vocabulary`, {
36691
+ issues: issues.map((i) => ({
36692
+ path: i.path,
36693
+ code: i.code,
36694
+ message: i.message
36695
+ })),
36696
+ hint: "Fix the values above and push again. Model classes are `class/fast`, `class/balanced` and `class/strong`; a concrete model code is checked by the server against your organization\u2019s approved models."
36697
+ });
36698
+ }
36699
+ __name(workflowModelMemberError, "workflowModelMemberError");
36296
36700
 
36297
36701
  // src/primitives/index.ts
36298
36702
  init_skill_handler();
@@ -36950,10 +37354,20 @@ var ALIAS_MAP = {
36950
37354
  "jobs",
36951
37355
  "job-logs",
36952
37356
  "goals",
36953
- "schedules"
37357
+ "schedules",
37358
+ // [WMC-E7] per-step model selection (§6.5, §6.7): the org's model policy, the `model_policy` gate,
37359
+ // and the deterministic rewrite of a definition composed before class resolution existed.
37360
+ "policy",
37361
+ "clear-gate",
37362
+ "recompose"
36954
37363
  ],
36955
37364
  aliases: lowerKeys({
36956
37365
  goal: "goals",
37366
+ policies: "policy",
37367
+ cleargate: "clear-gate",
37368
+ "clear-gates": "clear-gate",
37369
+ ungate: "clear-gate",
37370
+ recompile: "recompose",
36957
37371
  schedule: "schedules",
36958
37372
  sched: "schedules",
36959
37373
  ws: "workspace",
@@ -37769,7 +38183,16 @@ var WORKFLOW_SCRIPT_REPLAY_SOURCE = String.raw`
37769
38183
  function resolveModel(opts) {
37770
38184
  if (opts && opts.model) return opts.model;
37771
38185
  var ph = (opts && opts.phase) || currentPhase; var phases = __input.meta && __input.meta.phases;
37772
- if (ph && Array.isArray(phases)) for (var i = 0; i < phases.length; i++) if (phases[i] && phases[i].title === ph && phases[i].model) return phases[i].model;
38186
+ var phase;
38187
+ if (ph && Array.isArray(phases)) for (var i = 0; i < phases.length; i++) if (phases[i] && phases[i].title === ph) { phase = phases[i]; break; }
38188
+ if (phase && phase.model) return phase.model;
38189
+ // WMC (plan 6.3 script-form parity): a task class on the call or on its phase resolves to the SAME
38190
+ // class/<c> sentinel the graph form writes, through the org's map on the tick input. No map (every run
38191
+ // before the feature, and every organisation with assignment off) => undefined, exactly as before.
38192
+ // NB: no backticks in this comment - the wrapper source is itself a template literal.
38193
+ var map = __input.modelClassMap;
38194
+ var tc = (opts && opts.taskClass) || (phase && phase.taskClass);
38195
+ if (tc && map && map[tc]) return 'class/' + map[tc];
37773
38196
  return undefined;
37774
38197
  }
37775
38198
  function resolveRole(role) {
@@ -37961,6 +38384,12 @@ function computeWorkflowProtocolShipWindow(input) {
37961
38384
  }
37962
38385
  __name(computeWorkflowProtocolShipWindow, "computeWorkflowProtocolShipWindow");
37963
38386
  __name8(computeWorkflowProtocolShipWindow, "computeWorkflowProtocolShipWindow");
38387
+ var WORKFLOW_SCRIPT_EFFORT_PROTOCOL_VERSION = 2;
38388
+ function scriptEffortForwardable(journalProtocolVersion) {
38389
+ return typeof journalProtocolVersion === "number" && journalProtocolVersion >= WORKFLOW_SCRIPT_EFFORT_PROTOCOL_VERSION;
38390
+ }
38391
+ __name(scriptEffortForwardable, "scriptEffortForwardable");
38392
+ __name8(scriptEffortForwardable, "scriptEffortForwardable");
37964
38393
  function workflowScriptReplaySource(journalProtocolVersion) {
37965
38394
  return WORKFLOW_SCRIPT_PROTOCOL_VERSIONS.includes(journalProtocolVersion) ? WORKFLOW_SCRIPT_REPLAY_SOURCES[journalProtocolVersion] : void 0;
37966
38395
  }
@@ -40398,15 +40827,30 @@ function formatPushFailureSummary(failedItems) {
40398
40827
  return lines.join("\n");
40399
40828
  }
40400
40829
  __name(formatPushFailureSummary, "formatPushFailureSummary");
40830
+ var MODEL_CLASS_RESOLUTION_OFF_CODES = [
40831
+ "model-class-resolution-off",
40832
+ "MODEL_CLASS_RESOLUTION_OFF"
40833
+ ];
40834
+ function isModelClassResolutionOffCode(code) {
40835
+ if (!code) return false;
40836
+ const normal = code.toLowerCase().replace(/[^a-z]+/g, "-");
40837
+ if (MODEL_CLASS_RESOLUTION_OFF_CODES.some((c) => c.toLowerCase() === code.toLowerCase())) return true;
40838
+ const namesModelClass = normal.includes("model-class") || normal.includes("class-resolution");
40839
+ const namesOff = /(^|-)(off|disabled|unavailable|not-enabled)(-|$)/.test(normal);
40840
+ return namesModelClass && namesOff;
40841
+ }
40842
+ __name(isModelClassResolutionOffCode, "isModelClassResolutionOffCode");
40843
+ var MODEL_CLASS_RESOLUTION_OFF_HINT = "Model classes are not enabled on this environment yet \u2014 remove the `class/\u2026` values (pin an approved model code, or drop `model` to run the step on the agent's own model), or ask your administrator to enable them.";
40401
40844
  function pushRefusalError(handler, name, result) {
40402
40845
  const reason = result.error || "Unknown error";
40403
40846
  const isVersionConflict = reason.toLowerCase().includes("already exists");
40847
+ const classResolutionOff = isModelClassResolutionOffCode(result.code) || !!result.issues?.some((i) => isModelClassResolutionOffCode(i.code));
40404
40848
  return new CliError("error", `${handler.displayName.toLowerCase()} "${name}" is not pushed: ${reason}`, {
40405
40849
  exitCode: CLI_EXIT.ERROR,
40406
40850
  statusCode: result.statusCode,
40407
40851
  serverCode: result.code,
40408
40852
  issues: result.issues,
40409
- hint: isVersionConflict ? `Version conflict \u2014 this version already exists on the server. Auto-bump: lua push ${handler.kind} --force \xB7 or push all: lua push all --force` : void 0
40853
+ hint: classResolutionOff ? MODEL_CLASS_RESOLUTION_OFF_HINT : isVersionConflict ? `Version conflict \u2014 this version already exists on the server. Auto-bump: lua push ${handler.kind} --force \xB7 or push all: lua push all --force` : void 0
40410
40854
  });
40411
40855
  }
40412
40856
  __name(pushRefusalError, "pushRefusalError");
@@ -40419,8 +40863,31 @@ function stalePushEntryError(handler, name, entityId, serverMessage) {
40419
40863
  });
40420
40864
  }
40421
40865
  __name(stalePushEntryError, "stalePushEntryError");
40866
+ var WORKFLOW_EFFORT_MARKER = 2;
40867
+ function applyEffortMarker(pushData, applyEffort) {
40868
+ if (!applyEffort) return pushData;
40869
+ const graph = pushData.graph;
40870
+ if (!graph || typeof graph !== "object") return pushData;
40871
+ return {
40872
+ ...pushData,
40873
+ graph: {
40874
+ ...graph,
40875
+ luaWorkflow: WORKFLOW_EFFORT_MARKER
40876
+ }
40877
+ };
40878
+ }
40879
+ __name(applyEffortMarker, "applyEffortMarker");
40880
+ function effortMarkerNotice(cliVersion2, name) {
40881
+ return `
40882
+ \u2699\uFE0F --apply-effort: "${name}" is pushed with per-step effort ENABLED (lua-cli ${cliVersion2}).
40883
+ From this version on, each agent step's \`effort\` is sent to the model instead of only counted in the estimate.
40884
+ Runs already in flight and every version pushed before this one are unaffected \u2014 they keep their own marker.
40885
+ Push without --apply-effort to go back to estimate-only.`;
40886
+ }
40887
+ __name(effortMarkerNotice, "effortMarkerNotice");
40422
40888
 
40423
40889
  // src/commands/push.ts
40890
+ init_package_root();
40424
40891
  function getDeployHint(type) {
40425
40892
  const deployableMap = {
40426
40893
  skill: "lua deploy skill",
@@ -40616,12 +41083,13 @@ async function pushVersionedPrimitive(handler, options = {}) {
40616
41083
  if (confirmedVersion !== selected.version) {
40617
41084
  handler.updateVersionInYaml(selected.name, confirmedVersion);
40618
41085
  }
41086
+ if (options.applyEffort && handler.kind === "workflow") console.log(effortMarkerNotice(getCliVersion(), selected.name));
40619
41087
  writeProgress(`
40620
41088
  \u{1F680} Pushing ${selected.name} v${confirmedVersion} to server...`);
40621
- const result = await handler.pushToServer(apiKey, agentId, entityId, {
41089
+ const result = await handler.pushToServer(apiKey, agentId, entityId, applyEffortMarker({
40622
41090
  ...pushData,
40623
41091
  version: confirmedVersion
40624
- });
41092
+ }, options.applyEffort));
40625
41093
  if (!result.success) {
40626
41094
  if (result.statusCode === 404) throw stalePushEntryError(handler, selected.name, entityId, result.error);
40627
41095
  throw pushRefusalError(handler, selected.name, result);
@@ -40704,7 +41172,10 @@ async function pushCommand(type, cmdObj) {
40704
41172
  // Reading with `!== false` makes the programmatic-default-true path
40705
41173
  // explicit: when cmdObj is undefined (rare; programmatic invocation)
40706
41174
  // we still default to attaching source.
40707
- includeSource: cmdObj?.includeSource !== false
41175
+ includeSource: cmdObj?.includeSource !== false,
41176
+ // [WMC-E7] §6.9: a PLAIN push must never set the effort marker, so this reads the flag and nothing else —
41177
+ // no env fallback, no inheritance from a previous push.
41178
+ applyEffort: cmdObj?.applyEffort === true
40708
41179
  };
40709
41180
  let agentOutcome;
40710
41181
  let selectedType;
@@ -41177,6 +41648,11 @@ async function pushAllCommand(options) {
41177
41648
  webhookHandler,
41178
41649
  triggerHandler,
41179
41650
  jobHandler,
41651
+ // BAC — workflows were absent here, so `lua push` / `lua push all` never uploaded a changed
41652
+ // workflow (only the deprecated `lua push workflow` did). A published template then froze the
41653
+ // OLD workflow graph while its jobs advanced — an undetectable jobs-vs-workflows version skew.
41654
+ // Workflows ride the same push here; the deploy step below always activates them (see there).
41655
+ workflowHandler,
41180
41656
  preprocessorHandler,
41181
41657
  postprocessorHandler,
41182
41658
  deviceHandler,
@@ -41208,6 +41684,9 @@ async function pushAllCommand(options) {
41208
41684
  const icon = kindIcons[handler.kind] || "\u{1F4E6}";
41209
41685
  writeProgress(`
41210
41686
  ${icon} Pushing ${items.length} ${handler.displayName}(s)...`);
41687
+ if (options.applyEffort && handler.kind === "workflow") {
41688
+ console.log(effortMarkerNotice(getCliVersion(), `${items.length} workflow(s)`));
41689
+ }
41211
41690
  const handlerVersions = versionLookup.get(handler);
41212
41691
  for (const item of items) {
41213
41692
  try {
@@ -41236,20 +41715,20 @@ ${icon} Pushing ${items.length} ${handler.displayName}(s)...`);
41236
41715
  const baseVersion = serverHighest ? maxSemver(item.version, serverHighest) : item.version;
41237
41716
  let newVersion = incrementPatchVersion(baseVersion);
41238
41717
  writeInfo(` \u{1F4DD} ${item.name}: ${item.version} \u2192 ${newVersion}`);
41239
- let result = await handler.pushToServer(apiKey, agentId, entityId, {
41718
+ let result = await handler.pushToServer(apiKey, agentId, entityId, applyEffortMarker({
41240
41719
  ...pushData,
41241
41720
  version: newVersion
41242
- });
41721
+ }, options.applyEffort));
41243
41722
  if (!result.success && result.error?.toLowerCase().includes("already exists")) {
41244
41723
  console.log(` \u26A0\uFE0F Version collision on ${item.name}, refetching server state and retrying...`);
41245
41724
  const freshHighest = await handler.getHighestServerVersion(apiKey, agentId, entityId);
41246
41725
  if (freshHighest) {
41247
41726
  const retryVersion = incrementPatchVersion(freshHighest);
41248
41727
  writeInfo(` \u{1F4DD} ${item.name}: re-bumped ${newVersion} \u2192 ${retryVersion} after collision`);
41249
- result = await handler.pushToServer(apiKey, agentId, entityId, {
41728
+ result = await handler.pushToServer(apiKey, agentId, entityId, applyEffortMarker({
41250
41729
  ...pushData,
41251
41730
  version: retryVersion
41252
- });
41731
+ }, options.applyEffort));
41253
41732
  if (result.success) {
41254
41733
  newVersion = retryVersion;
41255
41734
  }
@@ -41274,7 +41753,7 @@ ${icon} Pushing ${items.length} ${handler.displayName}(s)...`);
41274
41753
  entityId
41275
41754
  });
41276
41755
  writeSuccess(` \u2705 ${item.name} v${newVersion} pushed`);
41277
- if (options.autoDeploy) {
41756
+ if (options.autoDeploy || handler.kind === PrimitiveKind.WORKFLOW) {
41278
41757
  toDeploy.push({
41279
41758
  handler,
41280
41759
  name: item.name,
@@ -41328,8 +41807,9 @@ ${icon} Pushing ${items.length} ${handler.displayName}(s)...`);
41328
41807
  if (personaPushResult && !options.autoDeploy) {
41329
41808
  writePersonaServedHint(personaPushResult.version);
41330
41809
  }
41331
- if (options.autoDeploy && toDeploy.length > 0) {
41332
- writeProgress("\n\u{1F680} Deploying all pushed versions to production...");
41810
+ if (toDeploy.length > 0) {
41811
+ const workflowsOnly = !options.autoDeploy;
41812
+ writeProgress(workflowsOnly ? "\n\u{1F680} Activating workflow version(s) \u2014 workflows deploy on their own, not via `lua version promote`..." : "\n\u{1F680} Deploying all pushed versions to production...");
41333
41813
  writeInfo("\u23F1\uFE0F Waiting for server to process versions (5 seconds)...\n");
41334
41814
  await new Promise((resolve7) => setTimeout(resolve7, 5e3));
41335
41815
  for (const item of toDeploy) {
@@ -51771,6 +52251,30 @@ init_constants();
51771
52251
  init_command_utils();
51772
52252
  init_analytics();
51773
52253
  init_workflow_api_service();
52254
+
52255
+ // src/interfaces/workflow-autonomy.ts
52256
+ init_dist();
52257
+ var has2 = /* @__PURE__ */ __name((tuple, v) => tuple.includes(v), "has");
52258
+ var isWorkflowAutonomyForm = /* @__PURE__ */ __name((v) => has2(WORKFLOW_AUTONOMY_FORMS, v), "isWorkflowAutonomyForm");
52259
+ var kebab = /* @__PURE__ */ __name((key) => key.replace(/([a-z0-9])([A-Z])/g, "$1-$2").toLowerCase(), "kebab");
52260
+ var WORKFLOW_AUTONOMY_CLEAR_KEYS = WORKFLOW_AUTONOMY_ENVELOPE_KEYS.map((k) => kebab(k).replace(/-seconds$/, ""));
52261
+ var CLEAR_ALIASES = Object.freeze(Object.fromEntries(WORKFLOW_AUTONOMY_ENVELOPE_KEYS.flatMap((key) => {
52262
+ const flag = kebab(key).replace(/-seconds$/, "");
52263
+ return [
52264
+ flag,
52265
+ kebab(key),
52266
+ key.toLowerCase()
52267
+ ].map((alias) => [
52268
+ alias,
52269
+ key
52270
+ ]);
52271
+ })));
52272
+ function autonomyClearKey(raw) {
52273
+ return CLEAR_ALIASES[raw.trim().toLowerCase()];
52274
+ }
52275
+ __name(autonomyClearKey, "autonomyClearKey");
52276
+
52277
+ // src/commands/workflows.ts
51774
52278
  init_artifact_loader();
51775
52279
  init_types();
51776
52280
  init_dist2();
@@ -51914,6 +52418,7 @@ function exitCodeForRunStatus(status) {
51914
52418
  if (status === "completed") return WORKFLOW_EXIT.OK;
51915
52419
  if (TERMINAL_FAILED.has(status)) return WORKFLOW_EXIT.RUN_FAILED;
51916
52420
  if (TERMINAL_CANCELLED.has(status)) return WORKFLOW_EXIT.RUN_CANCELLED;
52421
+ if (status === "gated") return WORKFLOW_EXIT.RUN_GATED;
51917
52422
  return void 0;
51918
52423
  }
51919
52424
  __name(exitCodeForRunStatus, "exitCodeForRunStatus");
@@ -51965,11 +52470,12 @@ async function workflowsCommand(action, target, extra, cmdObj) {
51965
52470
  });
51966
52471
  return;
51967
52472
  }
51968
- const { agentId, apiKey } = await initializeCommand({
52473
+ const { agentId, orgId, apiKey } = await initializeCommand({
51969
52474
  showProgress: !json
51970
52475
  });
51971
52476
  const ctx = {
51972
52477
  agentId,
52478
+ orgId,
51973
52479
  apiKey,
51974
52480
  api: new WorkflowApi(BASE_URLS.API, apiKey, agentId),
51975
52481
  json
@@ -52084,6 +52590,15 @@ async function executeAction(ctx, action, target, extra, o) {
52084
52590
  // ── schedules <list|create|patch|pause|resume|delete> (LUA-627 reads + R28; LUA-752 R27 / R56; goal-owned rows refuse) ──
52085
52591
  case "schedules":
52086
52592
  return schedulesCore(ctx, target, extra, o);
52593
+ // ── policy models <get|set> ([WMC-E7] — §6.5; the org's `models` block) ──
52594
+ case "policy":
52595
+ return policyCore(ctx, target, extra, o);
52596
+ // ── clear-gate ([WMC-E7] — §6.5; `resume` stays the `kind:'input'` resume) ──
52597
+ case "clear-gate":
52598
+ return requireRun(runId, "clear-gate", () => clearGateCore(ctx, runId, o));
52599
+ // ── recompose ([WMC-E7] — §6.4 Q19; a deterministic rewrite, never a fresh composition) ──
52600
+ case "recompose":
52601
+ return requireName(name, "recompose", () => recomposeCore(ctx, name, o));
52087
52602
  case "run":
52088
52603
  return WORKFLOW_EXIT.OK;
52089
52604
  }
@@ -52267,6 +52782,8 @@ async function viewCore(ctx, name) {
52267
52782
  if (active?.envTemplateKeys?.length) {
52268
52783
  console.log(` Env overlay: ${active.envTemplateKeys.join(", ")}${active.envOverlayHash ? ` \xB7 ${active.envOverlayHash}` : ""}`);
52269
52784
  }
52785
+ const agentModels = agentModelsBlock(active?.agentModels);
52786
+ if (agentModels) console.log(agentModels);
52270
52787
  printViewSchedules(sched);
52271
52788
  printViewGoals(goals);
52272
52789
  printVersions(w.versions ?? [], w.activeVersionId);
@@ -52452,6 +52969,11 @@ async function startCore(ctx, name, o) {
52452
52969
  const { runId, status } = res.data;
52453
52970
  if (!ctx.json) {
52454
52971
  writeSuccess(startResultLine(res.data, wf.name));
52972
+ const card = consentCardLines(res.data.modelConsent);
52973
+ if (card.length) {
52974
+ console.log("");
52975
+ for (const line of card) console.log(line);
52976
+ }
52455
52977
  if (status === "gated" && !o.follow) {
52456
52978
  writeInfo("\u23F8\uFE0F The run is gated awaiting consent \u2014 approve it from the desktop or: lua workflows status " + runId);
52457
52979
  }
@@ -52605,6 +53127,131 @@ function budgetLine(run) {
52605
53127
  return `${parts.join(" \xB7 ")} (${budgetCopy(run)})`;
52606
53128
  }
52607
53129
  __name(budgetLine, "budgetLine");
53130
+ function autonomyDurationLabel(seconds) {
53131
+ if (!Number.isFinite(seconds) || seconds < 0) return `${seconds} s`;
53132
+ if (seconds >= 86400 && seconds % 86400 === 0) return `${fmtNum(seconds / 86400)} d`;
53133
+ if (seconds >= 3600 && seconds % 3600 === 0) return `${fmtNum(seconds / 3600)} h`;
53134
+ if (seconds >= 60 && seconds % 60 === 0) return `${fmtNum(seconds / 60)} m`;
53135
+ return `${fmtNum(seconds)} s`;
53136
+ }
53137
+ __name(autonomyDurationLabel, "autonomyDurationLabel");
53138
+ function autonomyEnvelopeSummary(envelope) {
53139
+ if (!envelope) return void 0;
53140
+ const parts = [
53141
+ envelope.maxCredits !== void 0 ? `${fmtNum(envelope.maxCredits)} credits` : void 0,
53142
+ envelope.maxSteps !== void 0 ? `${fmtNum(envelope.maxSteps)} steps` : void 0,
53143
+ envelope.maxDurationSeconds !== void 0 ? autonomyDurationLabel(envelope.maxDurationSeconds) : void 0
53144
+ ].filter((p) => !!p);
53145
+ return parts.length ? `\u2264 ${parts.join(" \xB7 ")}` : void 0;
53146
+ }
53147
+ __name(autonomyEnvelopeSummary, "autonomyEnvelopeSummary");
53148
+ var CONSENT_VIA_AUTONOMY = "autonomy";
53149
+ function consentLine(consent) {
53150
+ if (consent?.via !== CONSENT_VIA_AUTONOMY) return void 0;
53151
+ const envelope = autonomyEnvelopeSummary(consent.envelope);
53152
+ return `auto (policy)${envelope ? ` \u2014 ${envelope}` : ""}`;
53153
+ }
53154
+ __name(consentLine, "consentLine");
53155
+ var dash = /* @__PURE__ */ __name((v) => v === void 0 || v === null || v === "" ? "\u2014" : String(v), "dash");
53156
+ function agentModelRow(s) {
53157
+ const effort = s.effort === void 0 ? "\u2014" : s.effortApplied === false ? `${s.effort} (not applied)` : String(s.effort);
53158
+ const requested = s.requires?.length ? `${dash(s.modelRequested)} +${s.requires.join(",")}` : dash(s.modelRequested);
53159
+ return [
53160
+ s.stepId,
53161
+ dash(s.taskClass),
53162
+ requested,
53163
+ dash(s.modelResolved),
53164
+ effort,
53165
+ dash(s.modelReason)
53166
+ ];
53167
+ }
53168
+ __name(agentModelRow, "agentModelRow");
53169
+ function agentModelsBlock(steps) {
53170
+ if (!steps?.length) return void 0;
53171
+ const rows3 = steps.map(agentModelRow);
53172
+ const anyUnapplied = steps.some((s) => s.effort !== void 0 && s.effortApplied === false);
53173
+ const table = renderTable([
53174
+ "Step",
53175
+ "Task class",
53176
+ "Requested",
53177
+ "Resolves to today",
53178
+ "Effort",
53179
+ "Reason"
53180
+ ], rows3);
53181
+ const note = anyUnapplied ? '\n\u{1F4A1} An effort marked "(not applied)" is recorded and counted in the estimate but not sent to the model. `lua push --apply-effort` applies it from the next push.' : "";
53182
+ return `
53183
+ \u{1F916} Agent steps
53184
+ ${table}${note}`;
53185
+ }
53186
+ __name(agentModelsBlock, "agentModelsBlock");
53187
+ function modelRollupRows(run, steps) {
53188
+ const projected = run.usage?.byModel;
53189
+ if (projected?.length) return [
53190
+ ...projected
53191
+ ];
53192
+ const folded = /* @__PURE__ */ new Map();
53193
+ for (const s of steps ?? []) {
53194
+ const b = s.billing;
53195
+ if (!b?.model) continue;
53196
+ const row2 = folded.get(b.model) ?? {
53197
+ model: b.model,
53198
+ calls: 0
53199
+ };
53200
+ row2.calls = (row2.calls ?? 0) + 1;
53201
+ if (b.credits !== void 0) row2.credits = (row2.credits ?? 0) + b.credits;
53202
+ if (b.actions !== void 0) row2.actions = (row2.actions ?? 0) + b.actions;
53203
+ folded.set(b.model, row2);
53204
+ }
53205
+ return [
53206
+ ...folded.values()
53207
+ ].sort((a, b) => (b.actions ?? b.credits ?? 0) - (a.actions ?? a.credits ?? 0));
53208
+ }
53209
+ __name(modelRollupRows, "modelRollupRows");
53210
+ function modelRollupBlock(run, steps) {
53211
+ const rows3 = modelRollupRows(run, steps);
53212
+ if (!rows3.length) return void 0;
53213
+ const seat = run.usage?.engine === "seat" || rows3.some((r) => r.actions !== void 0);
53214
+ const unit = seat ? "Actions" : "Credits";
53215
+ const anyClass = rows3.some((r) => r.class !== void 0);
53216
+ const anyFallback = rows3.some((r) => r.fallbacks !== void 0);
53217
+ const head = [
53218
+ "Model",
53219
+ ...anyClass ? [
53220
+ "Class"
53221
+ ] : [],
53222
+ "Calls",
53223
+ unit,
53224
+ ...anyFallback ? [
53225
+ "Fallbacks"
53226
+ ] : []
53227
+ ];
53228
+ const body = rows3.map((r) => {
53229
+ const spend = seat ? r.actions : r.credits;
53230
+ return [
53231
+ r.model,
53232
+ ...anyClass ? [
53233
+ dash(r.class)
53234
+ ] : [],
53235
+ r.calls !== void 0 ? fmtNum(r.calls) : "\u2014",
53236
+ spend !== void 0 ? fmtNum(spend) : "\u2014",
53237
+ ...anyFallback ? [
53238
+ r.fallbacks !== void 0 ? fmtNum(r.fallbacks) : "\u2014"
53239
+ ] : []
53240
+ ];
53241
+ });
53242
+ const derived = !run.usage?.byModel?.length;
53243
+ const note = derived ? "\n (derived from the step receipts \u2014 the run has no roll-up of its own)" : "";
53244
+ return `
53245
+ \u{1F9E0} By model
53246
+ ${renderTable(head, body)}${note}`;
53247
+ }
53248
+ __name(modelRollupBlock, "modelRollupBlock");
53249
+ function consentCardLines(consent) {
53250
+ return consent?.card?.length ? [
53251
+ ...consent.card
53252
+ ] : [];
53253
+ }
53254
+ __name(consentCardLines, "consentCardLines");
52608
53255
  function printRun(run, withSteps) {
52609
53256
  const id = runIdOf(run);
52610
53257
  console.log(`
@@ -52614,6 +53261,8 @@ function printRun(run, withSteps) {
52614
53261
  console.log(` Created: ${when2(run.createdAt)}${run.startedAt ? ` \xB7 started ${when2(run.startedAt)}` : ""}${run.completedAt ? ` \xB7 completed ${when2(run.completedAt)}` : ""}`);
52615
53262
  if (run.lineageId && run.lineageId !== id) console.log(` Lineage: ${run.lineageId}`);
52616
53263
  if (run.parentRunId) console.log(` Parent: ${run.parentRunId} \u2014 lua workflows status ${run.parentRunId} --steps`);
53264
+ const consent = consentLine(run.consent);
53265
+ if (consent) console.log(` Consent: ${consent}`);
52617
53266
  const budget = budgetLine(run);
52618
53267
  if (budget) console.log(` Budget: ${budget}`);
52619
53268
  if (run.cancel) console.log(` Cancel: ${formatRunCancel(run.cancel)}`);
@@ -52629,6 +53278,11 @@ function printRun(run, withSteps) {
52629
53278
  console.log(` lua workflows raise-budget ${id} --credits <n>`);
52630
53279
  } else if (kind === "billing") {
52631
53280
  for (const line of billingParkLines(run)) console.log(line);
53281
+ } else if (kind === "model_policy") {
53282
+ console.log(`
53283
+ \u23F8\uFE0F Paused \u2014 a step's model request cannot be resolved under the current policy:`);
53284
+ if (run.gate?.code) console.log(` ${run.gate.code}${run.gate.stepId ? ` \xB7 step ${run.gate.stepId}` : ""}`);
53285
+ console.log(` lua workflows clear-gate ${id} --kind model_policy`);
52632
53286
  } else {
52633
53287
  console.log(` Gate: ${kind}${run.gate.reason ? ` (${run.gate.reason})` : ""}${run.gate.since ? ` since ${when2(run.gate.since)}` : ""}`);
52634
53288
  }
@@ -52677,6 +53331,8 @@ function printRun(run, withSteps) {
52677
53331
  for (const s of steps) for (const line of stepAttemptLines(s)) console.log(line);
52678
53332
  }
52679
53333
  }
53334
+ const rollup = modelRollupBlock(run, steps);
53335
+ if (rollup) console.log(rollup);
52680
53336
  }
52681
53337
  __name(printRun, "printRun");
52682
53338
  function billingParkLines(run) {
@@ -52706,6 +53362,8 @@ function stepAttemptLines(s) {
52706
53362
  if (billed) out.push(` $ ${s.stepId}: attempt ${s.billing?.attempt ?? s.attempt ?? 1} billed: ${billed}`);
52707
53363
  const fetchable = outputRefLine(s.outputRef);
52708
53364
  if (fetchable) out.push(` \u21E9 ${s.stepId}: ${fetchable}`);
53365
+ const escalated = approverFallbackLine(s);
53366
+ if (escalated) out.push(escalated);
52709
53367
  for (const a of s.attempts ?? []) {
52710
53368
  if (a.status === "completed") continue;
52711
53369
  const what = stepErrorCell(a.error) || a.killReason || "\u2014";
@@ -52715,6 +53373,13 @@ function stepAttemptLines(s) {
52715
53373
  return out;
52716
53374
  }
52717
53375
  __name(stepAttemptLines, "stepAttemptLines");
53376
+ function approverFallbackLine(s) {
53377
+ const f = s.suspend?.approverFallback;
53378
+ if (!f?.from || !f.to) return void 0;
53379
+ const why = f.reason === "initiator_excluded" ? "the initiator is excluded (maker-checker)" : f.reason;
53380
+ return ` \u21C5 ${s.stepId}: approver escalated ${f.from} \u2192 ${f.to}${why ? ` \u2014 ${why}` : ""}`;
53381
+ }
53382
+ __name(approverFallbackLine, "approverFallbackLine");
52718
53383
  function outputRefLine(ref) {
52719
53384
  if (!ref?.artefactId || !ref.url) return void 0;
52720
53385
  const gate = "needs workflows:read-outputs";
@@ -53681,6 +54346,26 @@ async function replayChildRun(ctx, childRunId) {
53681
54346
  };
53682
54347
  }
53683
54348
  __name(replayChildRun, "replayChildRun");
54349
+ var WORKFLOW_LOG_EVENT_PATTERN = /progress|log|started|completed|failed|skipped|model_resolved|model_policy_warning/;
54350
+ function modelEventDetail(type, data) {
54351
+ if (type !== "step.model_resolved" && type !== "step.model_policy_warning") return void 0;
54352
+ const d = data ?? {};
54353
+ const nested = d.detail ?? {};
54354
+ const str = /* @__PURE__ */ __name((...vals) => {
54355
+ for (const v of vals) if (typeof v === "string" && v) return v;
54356
+ return void 0;
54357
+ }, "str");
54358
+ const requested = str(d.requested, nested.requested, d.modelRequested, nested.modelRequested);
54359
+ const resolved = str(d.resolved, nested.resolved, d.model, nested.model);
54360
+ if (type === "step.model_resolved") {
54361
+ const cls = requested?.startsWith("class/") ? requested.slice("class/".length) : str(d.taskClass, nested.taskClass);
54362
+ return `model resolved \u2192 ${resolved ?? requested ?? "?"}${cls ? ` (${cls})` : ""}`;
54363
+ }
54364
+ const outcome = str(d.outcome, nested.outcome, d.code, nested.code) ?? "unknown";
54365
+ const detail = str(d.message, nested.message) ?? (requested && resolved && requested !== resolved ? `${requested} \u2192 ${resolved}` : requested ?? resolved);
54366
+ return `model policy warning: ${outcome}${detail ? ` ${detail}` : ""}`;
54367
+ }
54368
+ __name(modelEventDetail, "modelEventDetail");
53684
54369
  async function logsCore(ctx, runId, o) {
53685
54370
  if (o.follow) return watchCore(ctx, runId, o);
53686
54371
  const res = await ctx.api.getRunEvents(runId, {
@@ -53689,10 +54374,11 @@ async function logsCore(ctx, runId, o) {
53689
54374
  if (!res.success || !res.data) return apiFailure(ctx, res, "logs");
53690
54375
  emitJson(ctx, res);
53691
54376
  if (ctx.json) return WORKFLOW_EXIT.OK;
53692
- const events = (res.data.events ?? []).filter((e) => (!o.step || e.stepId === o.step) && /progress|log|started|completed|failed|skipped/.test(e.type));
54377
+ const events = (res.data.events ?? []).filter((e) => (!o.step || e.stepId === o.step) && WORKFLOW_LOG_EVENT_PATTERN.test(e.type));
53693
54378
  if (events.length === 0) console.log("(no log events yet)");
53694
54379
  for (const e of events) {
53695
- const msg = scrubEventData(e.data)?.message ?? subrunEventDetail(e);
54380
+ const data = scrubEventData(e.data);
54381
+ const msg = modelEventDetail(e.type, data) ?? data?.message ?? subrunEventDetail(e);
53696
54382
  console.log(`[${clockOf(e.ts)}] ${e.type}${e.stepId ? ` \xB7 ${e.stepId}` : ""}${msg ? ` \xB7 ${msg}` : ""}`);
53697
54383
  }
53698
54384
  return WORKFLOW_EXIT.OK;
@@ -55384,6 +56070,290 @@ async function schedulesPatchCore(ctx, jobId, verb, o) {
55384
56070
  return WORKFLOW_EXIT.OK;
55385
56071
  }
55386
56072
  __name(schedulesPatchCore, "schedulesPatchCore");
56073
+ function csvFlag(raw) {
56074
+ if (raw === void 0) return void 0;
56075
+ const parts = (Array.isArray(raw) ? raw : [
56076
+ raw
56077
+ ]).flatMap((v) => String(v).split(","));
56078
+ const out = parts.map((v) => v.trim()).filter((v) => v.length > 0);
56079
+ return out;
56080
+ }
56081
+ __name(csvFlag, "csvFlag");
56082
+ function badFlagValue(flag, value3, allowed) {
56083
+ return CliError.usage(`${flag}: "${value3}" is not a valid value`, `${flag} takes one of ${allowed.map((v) => `\`${v}\``).join(", ")}`);
56084
+ }
56085
+ __name(badFlagValue, "badFlagValue");
56086
+ function buildModelsPolicyPatch(o) {
56087
+ const patch = {};
56088
+ if (o.compose !== void 0) {
56089
+ const v = String(o.compose);
56090
+ if (!WORKFLOW_MODELS_COMPOSE_MODES.includes(v)) throw badFlagValue("--compose", v, WORKFLOW_MODELS_COMPOSE_MODES);
56091
+ patch.compose = v;
56092
+ }
56093
+ if (o.maxClass !== void 0) {
56094
+ const v = String(o.maxClass);
56095
+ if (!isWorkflowModelClass(v)) throw badFlagValue("--max-class", v, WORKFLOW_MODEL_CLASSES);
56096
+ patch.maxClass = v;
56097
+ }
56098
+ if (o.consentActions !== void 0) {
56099
+ const n2 = parseIntegerFlag(o.consentActions, "--consent-actions", {
56100
+ min: WORKFLOW_MODELS_CONSENT_ACTIONS_MIN
56101
+ });
56102
+ if (n2 !== void 0) patch.consentActions = n2;
56103
+ }
56104
+ if (o.pins !== void 0) {
56105
+ const v = String(o.pins);
56106
+ if (!WORKFLOW_MODELS_PIN_MODES.includes(v)) throw badFlagValue("--pins", v, WORKFLOW_MODELS_PIN_MODES);
56107
+ patch.pins = v;
56108
+ }
56109
+ if (o.fallback !== void 0) {
56110
+ const v = String(o.fallback);
56111
+ if (!WORKFLOW_MODELS_FALLBACK_MODES.includes(v)) throw badFlagValue("--fallback", v, WORKFLOW_MODELS_FALLBACK_MODES);
56112
+ patch.fallback = v;
56113
+ }
56114
+ const allow = csvFlag(o.allow);
56115
+ if (allow !== void 0) patch.allow = allow;
56116
+ const classes = {};
56117
+ const perClass = {
56118
+ fast: o.classFast,
56119
+ balanced: o.classBalanced,
56120
+ strong: o.classStrong
56121
+ };
56122
+ for (const c of WORKFLOW_MODEL_CLASSES) {
56123
+ const codes = csvFlag(perClass[c]);
56124
+ if (codes !== void 0) classes[c] = codes;
56125
+ }
56126
+ if (Object.keys(classes).length) patch.classes = classes;
56127
+ if (o.classMap !== void 0) {
56128
+ const map = {};
56129
+ for (const entry of csvFlag(o.classMap) ?? []) {
56130
+ const [task, cls] = entry.split("=").map((v) => v.trim());
56131
+ if (!task || !cls) throw CliError.usage(`--class-map: "${entry}" is not a mapping`, "--class-map takes `<taskClass>=<modelClass>` pairs, e.g. --class-map judge=strong,draft=balanced");
56132
+ if (!isWorkflowTaskClass(task)) throw badFlagValue("--class-map", task, WORKFLOW_TASK_CLASSES);
56133
+ if (!isWorkflowModelClass(cls)) throw badFlagValue("--class-map", cls, WORKFLOW_MODEL_CLASSES);
56134
+ map[task] = cls;
56135
+ }
56136
+ if (Object.keys(map).length) patch.classMap = map;
56137
+ }
56138
+ return patch;
56139
+ }
56140
+ __name(buildModelsPolicyPatch, "buildModelsPolicyPatch");
56141
+ function modelsPolicyLines(models) {
56142
+ const lines = [
56143
+ "\n\u{1F9E0} Workflow model policy"
56144
+ ];
56145
+ if (!models || Object.keys(models).length === 0) {
56146
+ lines.push(" (not set \u2014 the platform defaults apply: assignment off, no class ceiling, composed steps class-only)");
56147
+ return lines;
56148
+ }
56149
+ const show = /* @__PURE__ */ __name((label2, v, fallback) => {
56150
+ lines.push(` ${label2.padEnd(16)} ${v === void 0 || v === null ? `\u2014 (${fallback})` : String(v)}`);
56151
+ }, "show");
56152
+ show("compose", models.compose, "platform default");
56153
+ show("maxClass", models.maxClass, "no ceiling below `strong`");
56154
+ show("consentActions", models.consentActions, "platform default");
56155
+ show("pins", models.pins, "class-only on composed definitions");
56156
+ show("fallback", models.fallback, "same-class");
56157
+ lines.push(` ${"allow".padEnd(16)} ${models.allow?.length ? models.allow.join(", ") : "\u2014 (all approved, minus the organization\u2019s excluded models)"}`);
56158
+ if (models.classes && Object.keys(models.classes).length) {
56159
+ lines.push(" classes");
56160
+ for (const c of WORKFLOW_MODEL_CLASSES) {
56161
+ const codes = models.classes[c];
56162
+ if (codes?.length) lines.push(` ${c.padEnd(10)} ${codes.join(", ")}`);
56163
+ }
56164
+ }
56165
+ if (models.classMap && Object.keys(models.classMap).length) {
56166
+ lines.push(" classMap (overrides only)");
56167
+ for (const [task, cls] of Object.entries(models.classMap)) lines.push(` ${task.padEnd(10)} \u2192 ${cls}`);
56168
+ }
56169
+ return lines;
56170
+ }
56171
+ __name(modelsPolicyLines, "modelsPolicyLines");
56172
+ var WORKFLOW_AUTONOMY_ENABLED_WORDS = [
56173
+ "on",
56174
+ "off"
56175
+ ];
56176
+ var AUTONOMY_NUMERIC_FLAGS = {
56177
+ maxCredits: "--max-credits",
56178
+ maxSteps: "--max-steps",
56179
+ // `--max-duration` takes SECONDS and the wire key says so; `--max-duration-seconds` is `raise-budget`'s
56180
+ // own flag for a different thing (one run's wall), so the two deliberately do not share a spelling.
56181
+ maxDurationSeconds: "--max-duration",
56182
+ maxActions: "--max-actions",
56183
+ maxRunsPerHour: "--max-runs-per-hour"
56184
+ };
56185
+ function buildAutonomyPolicyPatch(o) {
56186
+ const patch = {};
56187
+ if (o.enabled !== void 0) {
56188
+ const v = String(o.enabled).trim().toLowerCase();
56189
+ if (!WORKFLOW_AUTONOMY_ENABLED_WORDS.includes(v)) throw badFlagValue("--enabled", String(o.enabled), WORKFLOW_AUTONOMY_ENABLED_WORDS);
56190
+ patch.enabled = v === "on";
56191
+ }
56192
+ const raw = {
56193
+ maxCredits: o.maxCredits,
56194
+ maxSteps: o.maxSteps,
56195
+ maxDurationSeconds: o.maxDuration,
56196
+ maxActions: o.maxActions,
56197
+ maxRunsPerHour: o.maxRunsPerHour
56198
+ };
56199
+ for (const key of WORKFLOW_AUTONOMY_NUMERIC_KEYS) {
56200
+ const n2 = parseIntegerFlag(raw[key], AUTONOMY_NUMERIC_FLAGS[key], {
56201
+ min: WORKFLOW_AUTONOMY_MIN_VALUE
56202
+ });
56203
+ if (n2 !== void 0) patch[key] = n2;
56204
+ }
56205
+ const forms = csvFlag(o.forms);
56206
+ if (forms !== void 0) {
56207
+ for (const f of forms) if (!isWorkflowAutonomyForm(f)) throw badFlagValue("--forms", f, WORKFLOW_AUTONOMY_FORMS);
56208
+ patch.forms = forms;
56209
+ }
56210
+ for (const token of csvFlag(o.clear) ?? []) {
56211
+ const key = autonomyClearKey(token);
56212
+ if (!key) throw badFlagValue("--clear", token, WORKFLOW_AUTONOMY_CLEAR_KEYS);
56213
+ if (patch[key] !== void 0) throw CliError.usage(`--clear: "${token}" is also being set by ${key === "enabled" ? "--enabled" : key === "forms" ? "--forms" : AUTONOMY_NUMERIC_FLAGS[key]}`, "Clear a member or set it, not both in one call \u2014 `--clear` sends `null` so the platform default applies again.");
56214
+ patch[key] = null;
56215
+ }
56216
+ return patch;
56217
+ }
56218
+ __name(buildAutonomyPolicyPatch, "buildAutonomyPolicyPatch");
56219
+ function autonomyPolicyLines(autonomy, effective, opts = {}) {
56220
+ const lines = [
56221
+ "\n\u{1F6E1}\uFE0F Workflow autonomy (the pre-consented envelope)"
56222
+ ];
56223
+ const show = /* @__PURE__ */ __name((target, label2, v, fallback) => {
56224
+ const rendered = v === void 0 || v === null ? `\u2014 (${fallback})` : label2 === "maxDurationSeconds" && typeof v === "number" ? `${fmtNum(v)} (${autonomyDurationLabel(v)})` : Array.isArray(v) ? v.join(", ") : String(v);
56225
+ target.push(` ${label2.padEnd(18)} ${rendered}`);
56226
+ }, "show");
56227
+ const block = /* @__PURE__ */ __name((target, e) => {
56228
+ show(target, "enabled", e.enabled, `${WORKFLOW_AUTONOMY_ENABLED_DEFAULT} \u2014 absent means the organization never opted in`);
56229
+ show(target, "maxCredits", e.maxCredits, `default ${WORKFLOW_AUTONOMY_DEFAULTS.maxCredits}, clamped to caps.maxCreditsPerRun`);
56230
+ show(target, "maxSteps", e.maxSteps, `default ${WORKFLOW_AUTONOMY_DEFAULTS.maxSteps}`);
56231
+ show(target, "maxDurationSeconds", e.maxDurationSeconds, `default ${fmtNum(WORKFLOW_AUTONOMY_DEFAULTS.maxDurationSeconds)} \u2014 ${autonomyDurationLabel(WORKFLOW_AUTONOMY_DEFAULTS.maxDurationSeconds)}`);
56232
+ show(target, "maxActions", e.maxActions, "the organization\u2019s own models.consentActions");
56233
+ show(target, "maxRunsPerHour", e.maxRunsPerHour, `default ${WORKFLOW_AUTONOMY_DEFAULTS.maxRunsPerHour}`);
56234
+ show(target, "forms", e.forms?.length ? e.forms : void 0, `${WORKFLOW_AUTONOMY_FORMS_DEFAULT.join(", ")} \u2014 script opts in`);
56235
+ }, "block");
56236
+ if (!autonomy || Object.keys(autonomy).length === 0) {
56237
+ lines.push(" (not set \u2014 autonomy is OFF for this organization: every start that would ask a person still asks,", " exactly as it does today)");
56238
+ } else {
56239
+ block(lines, autonomy);
56240
+ }
56241
+ if (effective) {
56242
+ lines.push("\n Effective envelope (the server\u2019s own resolution \u2014 org narrowed by agent, defaults applied)");
56243
+ block(lines, effective);
56244
+ if (effective.enabled !== true) lines.push(" (enabled is not true \u2014 nothing is pre-consented; every start that would ask still asks)");
56245
+ } else if (opts.effectiveAsked) {
56246
+ lines.push("\n Effective envelope \u2014 the server served no resolution for it (a server without the envelope, or a", " policy route that does not answer `?effective=true`). What is above is the STORED block only; what a", " start would actually be admitted under is not shown.");
56247
+ }
56248
+ return lines;
56249
+ }
56250
+ __name(autonomyPolicyLines, "autonomyPolicyLines");
56251
+ var POLICY_NOUNS = [
56252
+ "models",
56253
+ "autonomy"
56254
+ ];
56255
+ async function autonomyPolicyCore(ctx, verb, o) {
56256
+ const action = verb ?? "get";
56257
+ if (action !== "get" && action !== "set") throw CliError.usage(`policy autonomy: "${action}" is not an action`, "lua workflows policy autonomy get \xB7 lua workflows policy autonomy set \u2026");
56258
+ if (o.agent) throw CliError.usage("policy autonomy: --agent is not supported", "There is no route that WRITES a per-agent workflow setting: the sub-agent PATCH has no `workflows` member, so a narrowing sent that way is accepted and discarded. Set the organization\u2019s envelope instead (lua workflows policy autonomy set \u2026); `policy autonomy get` shows a per-agent narrowing when the effective projection carries one.");
56259
+ if (action === "get") {
56260
+ const res2 = await ctx.api.getWorkflowPolicy(ctx.orgId, {
56261
+ effective: true
56262
+ });
56263
+ if (!res2.success || !res2.data) return apiFailure(ctx, res2, "policy autonomy get");
56264
+ emitJson(ctx, res2);
56265
+ if (!ctx.json) for (const line of autonomyPolicyLines(res2.data.autonomy, res2.data.effective?.autonomy, {
56266
+ effectiveAsked: true
56267
+ })) console.log(line);
56268
+ return WORKFLOW_EXIT.OK;
56269
+ }
56270
+ const patch = parsedOrUsage(() => buildAutonomyPolicyPatch(o));
56271
+ if (Object.keys(patch).length === 0) throw CliError.usage("policy autonomy set: nothing to set", `Name at least one member: --enabled on|off \xB7 --max-credits <n> \xB7 --max-steps <n> \xB7 --max-duration <seconds> \xB7 --max-actions <n> \xB7 --max-runs-per-hour <n> \xB7 --forms ${WORKFLOW_AUTONOMY_FORMS.join(",")} \xB7 --clear <${WORKFLOW_AUTONOMY_CLEAR_KEYS.join("|")}>`);
56272
+ const named = Object.keys(patch).join(", ");
56273
+ const res = await ctx.api.patchWorkflowPolicyAutonomy(ctx.orgId, patch);
56274
+ if (!res.success || !res.data) return apiFailure(ctx, res, "policy autonomy set");
56275
+ emitJson(ctx, res);
56276
+ if (!ctx.json) {
56277
+ writeSuccess(`\u2705 Workflow autonomy policy updated (${named})`);
56278
+ for (const line of autonomyPolicyLines(res.data.autonomy, res.data.effective?.autonomy)) console.log(line);
56279
+ console.log("\n\u{1F4A1} A policy change reaches a starting agent within 30 seconds.");
56280
+ console.log(" The platform switch and `dynamic: false` still sit above it, and `askAboveThresholds: false`");
56281
+ console.log(" still refuses \u2014 autonomy turns an \u201Cask\u201D into an \u201Cauto\u201D, never a \u201Crefuse\u201D into either.");
56282
+ }
56283
+ return WORKFLOW_EXIT.OK;
56284
+ }
56285
+ __name(autonomyPolicyCore, "autonomyPolicyCore");
56286
+ async function policyCore(ctx, noun, verb, o) {
56287
+ if (noun === "autonomy") return autonomyPolicyCore(ctx, verb, o);
56288
+ if (noun !== "models") throw CliError.usage(`policy: "${noun ?? ""}" is not a policy noun`, `policy takes one of ${POLICY_NOUNS.map((n2) => `\`${n2}\``).join(", ")} \u2014 lua workflows policy models get \xB7 lua workflows policy autonomy get`);
56289
+ const action = verb ?? "get";
56290
+ if (action !== "get" && action !== "set") throw CliError.usage(`policy models: "${action}" is not an action`, "lua workflows policy models get \xB7 lua workflows policy models set \u2026");
56291
+ if (action === "get") {
56292
+ const res2 = await ctx.api.getWorkflowPolicy(ctx.orgId);
56293
+ if (!res2.success || !res2.data) return apiFailure(ctx, res2, "policy models get");
56294
+ emitJson(ctx, res2);
56295
+ if (!ctx.json) for (const line of modelsPolicyLines(res2.data.models)) console.log(line);
56296
+ return WORKFLOW_EXIT.OK;
56297
+ }
56298
+ const patch = buildModelsPolicyPatch(o);
56299
+ if (Object.keys(patch).length === 0) throw CliError.usage("policy models set: nothing to set", "Name at least one field: --compose on|off \xB7 --max-class fast|balanced|strong \xB7 --consent-actions <n> \xB7 --pins class-only|allowed \xB7 --fallback same-class|same-provider \xB7 --allow <codes> \xB7 --class-fast/--class-balanced/--class-strong <codes> \xB7 --class-map <task>=<class>");
56300
+ const res = await ctx.api.patchWorkflowPolicyModels(ctx.orgId, patch);
56301
+ if (!res.success || !res.data) return apiFailure(ctx, res, "policy models set");
56302
+ emitJson(ctx, res);
56303
+ if (!ctx.json) {
56304
+ writeSuccess(`\u2705 Workflow model policy updated (${Object.keys(patch).join(", ")})`);
56305
+ for (const line of modelsPolicyLines(res.data.models)) console.log(line);
56306
+ console.log("\n\u{1F4A1} A policy change reaches a composing agent within 30 seconds.");
56307
+ }
56308
+ return WORKFLOW_EXIT.OK;
56309
+ }
56310
+ __name(policyCore, "policyCore");
56311
+ async function clearGateCore(ctx, runId, o) {
56312
+ const kind = o.kind;
56313
+ if (!kind) throw CliError.usage("clear-gate: --kind is required", `lua workflows clear-gate ${runId} --kind model_policy`);
56314
+ const res = await ctx.api.clearRunGate(runId, String(kind));
56315
+ if (!res.success || !res.data) return apiFailure(ctx, res, "clear-gate");
56316
+ emitJson(ctx, res);
56317
+ if (ctx.json) return WORKFLOW_EXIT.OK;
56318
+ if (res.data.cleared) {
56319
+ writeSuccess(`\u2705 Cleared the ${res.data.kind ?? kind} gate on ${runId}${res.data.status ? ` \u2014 ${res.data.status}` : ""}`);
56320
+ console.log(` lua workflows watch ${runId}`);
56321
+ } else {
56322
+ writeInfo(`\u2139\uFE0F ${runId} is not parked on a ${kind} gate${res.data.reason ? ` \u2014 ${res.data.reason}` : ""}. Nothing to clear.`);
56323
+ }
56324
+ return WORKFLOW_EXIT.OK;
56325
+ }
56326
+ __name(clearGateCore, "clearGateCore");
56327
+ function recomposeNextSteps(wf, version) {
56328
+ const lines = [
56329
+ ` lua workflows view ${wf.name}`,
56330
+ ` lua workflows versions ${wf.name}`
56331
+ ];
56332
+ if (wf.dynamic === true) {
56333
+ lines.push(" (this workflow was composed by chat \u2014 `deploy` does not apply to it; the new version is published on the", " same definition, and `versions` shows which one is active)");
56334
+ } else {
56335
+ lines.push(` lua workflows deploy ${wf.name} -v ${version ?? "latest"}`);
56336
+ }
56337
+ return lines;
56338
+ }
56339
+ __name(recomposeNextSteps, "recomposeNextSteps");
56340
+ async function recomposeCore(ctx, name, _o) {
56341
+ const wf = await resolveWorkflow(ctx, name);
56342
+ if (!wf) return WORKFLOW_EXIT.NOT_FOUND;
56343
+ const res = await ctx.api.recomposeWorkflow(wf.id);
56344
+ if (!res.success || !res.data) return apiFailure(ctx, res, "recompose");
56345
+ emitJson(ctx, res);
56346
+ if (ctx.json) return WORKFLOW_EXIT.OK;
56347
+ const d = res.data;
56348
+ if (d.unchanged) {
56349
+ writeInfo(`\u2139\uFE0F ${wf.name} already asks for model classes everywhere it can \u2014 no new version was published.`);
56350
+ return WORKFLOW_EXIT.OK;
56351
+ }
56352
+ writeSuccess(`\u2705 ${wf.name} recomposed \u2192 version ${d.version ?? d.versionId ?? "(new)"}` + (d.rewritten !== void 0 ? ` \xB7 ${d.rewritten} agent step${d.rewritten === 1 ? "" : "s"} rewritten` : ""));
56353
+ for (const line of recomposeNextSteps(wf, d.version)) console.log(line);
56354
+ return WORKFLOW_EXIT.OK;
56355
+ }
56356
+ __name(recomposeCore, "recomposeCore");
55387
56357
 
55388
56358
  // src/commands/features.ts
55389
56359
  init_cli();
@@ -64118,6 +65088,69 @@ import chalk4 from "chalk";
64118
65088
  init_compiler2();
64119
65089
  init_artifact_loader();
64120
65090
  init_analytics();
65091
+
65092
+ // src/commands/models-workflow-view.ts
65093
+ function classOf(m) {
65094
+ const c = m.fitness?.class;
65095
+ return c && WORKFLOW_MODEL_CLASSES.includes(c) ? c : void 0;
65096
+ }
65097
+ __name(classOf, "classOf");
65098
+ function isAwaitingConfirmation(m) {
65099
+ return m.fitness !== void 0 && m.fitness.confirmed !== true;
65100
+ }
65101
+ __name(isAwaitingConfirmation, "isAwaitingConfirmation");
65102
+ function isPinOnly(m) {
65103
+ return classOf(m) === void 0 || m.calibrated === false || isAwaitingConfirmation(m);
65104
+ }
65105
+ __name(isPinOnly, "isPinOnly");
65106
+ function costCell(m) {
65107
+ if (m.actionMultiplier === void 0) return "\u2014";
65108
+ const rate = `${m.actionMultiplier}\xD7`;
65109
+ if (m.billing === "byok") return `${rate} (own key)`;
65110
+ if (m.calibrated === false) return `${rate} (estimate)`;
65111
+ return rate;
65112
+ }
65113
+ __name(costCell, "costCell");
65114
+ function notesCell(m) {
65115
+ const notes = [];
65116
+ if (isAwaitingConfirmation(m)) notes.push("awaiting confirmation");
65117
+ if (m.billing === "byok") notes.push("own key");
65118
+ if (m.calibrated === false) notes.push("rate not calibrated");
65119
+ if (isPinOnly(m)) notes.push("pin only");
65120
+ return notes.length ? notes.join(" \xB7 ") : "";
65121
+ }
65122
+ __name(notesCell, "notesCell");
65123
+ function workflowModelRows(models) {
65124
+ const order = /* @__PURE__ */ __name((m) => {
65125
+ const c = classOf(m);
65126
+ if (c === void 0) return WORKFLOW_MODEL_CLASSES.length;
65127
+ return WORKFLOW_MODEL_CLASSES.indexOf(c);
65128
+ }, "order");
65129
+ return [
65130
+ ...models
65131
+ ].sort((a, b) => order(a) - order(b) || (a.actionMultiplier ?? 0) - (b.actionMultiplier ?? 0) || a.code.localeCompare(b.code)).map((m) => ({
65132
+ class: classOf(m) ?? "\u2014",
65133
+ code: m.code,
65134
+ bestFor: m.fitness?.bestFor?.length ? m.fitness.bestFor.join(", ") : "\u2014",
65135
+ speed: m.fitness?.speed ?? "\u2014",
65136
+ cost: costCell(m),
65137
+ efforts: m.reasoning?.efforts?.length ? m.reasoning.efforts.join(", ") : "\u2014",
65138
+ notes: notesCell(m)
65139
+ }));
65140
+ }
65141
+ __name(workflowModelRows, "workflowModelRows");
65142
+ function workflowModelFootnotes(models) {
65143
+ const out = [];
65144
+ if (models.some(isAwaitingConfirmation)) out.push("\u2022 awaiting confirmation \u2014 new to the catalog. It can be pinned by code, but no model class resolves to it yet.");
65145
+ if (models.some((m) => m.billing === "byok")) out.push("\u2022 own key \u2014 served through your organization\u2019s own provider key, shown at that provider\u2019s relative rate because you pay them directly.");
65146
+ if (models.some((m) => m.calibrated === false)) out.push("\u2022 rate not calibrated \u2014 the cost shown is a conservative placeholder, not a measured rate.");
65147
+ if (models.some((m) => m.reasoning?.efforts?.length === 1 || m.reasoning?.supported === false)) out.push("\u2022 a model with no graded effort ladder ignores a step\u2019s `effort`; it is recorded but inert.");
65148
+ out.push("\u2022 cost is a multiple of a small call on the pricing baseline model \u2014 the unit your run budget counts.");
65149
+ return out;
65150
+ }
65151
+ __name(workflowModelFootnotes, "workflowModelFootnotes");
65152
+
65153
+ // src/commands/models.ts
64121
65154
  init_cli_error();
64122
65155
  function noAgentConfigured() {
64123
65156
  return CliError.usage("No agent configured.", "Run `lua init` first to set up a project.");
@@ -64184,6 +65217,44 @@ async function listModels(models, currentModel, opts) {
64184
65217
  console.log("");
64185
65218
  }
64186
65219
  __name(listModels, "listModels");
65220
+ async function listWorkflowModels(models, opts) {
65221
+ const rows3 = models;
65222
+ if (opts.json) {
65223
+ console.log(JSON.stringify({
65224
+ view: "workflows",
65225
+ models
65226
+ }, null, 2));
65227
+ return;
65228
+ }
65229
+ const table = workflowModelRows(rows3);
65230
+ console.log("");
65231
+ console.log(chalk4.bold("\u{1F9ED} Models for workflow steps"));
65232
+ console.log("");
65233
+ console.log(renderTable([
65234
+ "Class",
65235
+ "Model",
65236
+ "Best for",
65237
+ "Speed",
65238
+ "Cost",
65239
+ "Efforts",
65240
+ "Notes"
65241
+ ], table.map((r) => [
65242
+ r.class,
65243
+ r.code,
65244
+ r.bestFor,
65245
+ r.speed,
65246
+ r.cost,
65247
+ r.efforts,
65248
+ r.notes
65249
+ ])));
65250
+ console.log("");
65251
+ for (const note of workflowModelFootnotes(rows3)) console.log(` ${chalk4.gray(note)}`);
65252
+ console.log("");
65253
+ console.log(` \u{1F4A1} A step asks for a class with ${chalk4.cyan("model: 'class/balanced'")}, or names its work with ${chalk4.cyan("taskClass")}.`);
65254
+ console.log(` ${chalk4.cyan("lua workflows policy models get")} shows the classes and ceilings your organization has set.`);
65255
+ console.log("");
65256
+ }
65257
+ __name(listWorkflowModels, "listWorkflowModels");
64187
65258
  async function modelsCommand(action, opts) {
64188
65259
  return withErrorHandling(async () => {
64189
65260
  const resolvedAction = action ? validateOrSuggest("models.action", action) : "list";
@@ -64201,6 +65272,16 @@ async function modelsCommand(action, opts) {
64201
65272
  });
64202
65273
  return;
64203
65274
  }
65275
+ if (opts.workflows) {
65276
+ await listWorkflowModels(models, opts);
65277
+ trackEvent("cli_models_listed", {
65278
+ models_count: models.length,
65279
+ has_current_model: false,
65280
+ json_output: opts.json ?? false,
65281
+ workflows_view: true
65282
+ });
65283
+ return;
65284
+ }
64204
65285
  const currentModel = agentId ? await resolveCurrentModel(apiKey, agentId) : null;
64205
65286
  await listModels(models, currentModel, opts);
64206
65287
  trackEvent("cli_models_listed", {
@@ -64391,13 +65472,13 @@ function hasSox() {
64391
65472
  __name(hasSox, "hasSox");
64392
65473
  function detectSoxInstaller() {
64393
65474
  const os3 = platform3();
64394
- const has = /* @__PURE__ */ __name((bin) => spawnSync(bin, [
65475
+ const has3 = /* @__PURE__ */ __name((bin) => spawnSync(bin, [
64395
65476
  "--version"
64396
65477
  ], {
64397
65478
  stdio: "ignore"
64398
65479
  }).status === 0, "has");
64399
65480
  if (os3 === "darwin") {
64400
- if (has("brew")) return {
65481
+ if (has3("brew")) return {
64401
65482
  manager: "Homebrew",
64402
65483
  argv: [
64403
65484
  "brew",
@@ -64408,7 +65489,7 @@ function detectSoxInstaller() {
64408
65489
  return null;
64409
65490
  }
64410
65491
  if (os3 === "linux") {
64411
- if (has("apt-get")) return {
65492
+ if (has3("apt-get")) return {
64412
65493
  manager: "apt",
64413
65494
  argv: [
64414
65495
  "sudo",
@@ -64419,7 +65500,7 @@ function detectSoxInstaller() {
64419
65500
  ],
64420
65501
  note: "may prompt for sudo password"
64421
65502
  };
64422
- if (has("apt")) return {
65503
+ if (has3("apt")) return {
64423
65504
  manager: "apt",
64424
65505
  argv: [
64425
65506
  "sudo",
@@ -64430,7 +65511,7 @@ function detectSoxInstaller() {
64430
65511
  ],
64431
65512
  note: "may prompt for sudo password"
64432
65513
  };
64433
- if (has("dnf")) return {
65514
+ if (has3("dnf")) return {
64434
65515
  manager: "dnf",
64435
65516
  argv: [
64436
65517
  "sudo",
@@ -64441,7 +65522,7 @@ function detectSoxInstaller() {
64441
65522
  ],
64442
65523
  note: "may prompt for sudo password"
64443
65524
  };
64444
- if (has("yum")) return {
65525
+ if (has3("yum")) return {
64445
65526
  manager: "yum",
64446
65527
  argv: [
64447
65528
  "sudo",
@@ -64452,7 +65533,7 @@ function detectSoxInstaller() {
64452
65533
  ],
64453
65534
  note: "may prompt for sudo password"
64454
65535
  };
64455
- if (has("pacman")) return {
65536
+ if (has3("pacman")) return {
64456
65537
  manager: "pacman",
64457
65538
  argv: [
64458
65539
  "sudo",
@@ -64463,7 +65544,7 @@ function detectSoxInstaller() {
64463
65544
  ],
64464
65545
  note: "may prompt for sudo password"
64465
65546
  };
64466
- if (has("apk")) return {
65547
+ if (has3("apk")) return {
64467
65548
  manager: "apk",
64468
65549
  argv: [
64469
65550
  "sudo",
@@ -64476,7 +65557,7 @@ function detectSoxInstaller() {
64476
65557
  return null;
64477
65558
  }
64478
65559
  if (os3 === "win32") {
64479
- if (has("winget")) return {
65560
+ if (has3("winget")) return {
64480
65561
  manager: "winget",
64481
65562
  argv: [
64482
65563
  "winget",
@@ -64487,7 +65568,7 @@ function detectSoxInstaller() {
64487
65568
  "--silent"
64488
65569
  ]
64489
65570
  };
64490
- if (has("choco")) return {
65571
+ if (has3("choco")) return {
64491
65572
  manager: "Chocolatey",
64492
65573
  argv: [
64493
65574
  "choco",
@@ -64496,7 +65577,7 @@ function detectSoxInstaller() {
64496
65577
  "-y"
64497
65578
  ]
64498
65579
  };
64499
- if (has("scoop")) return {
65580
+ if (has3("scoop")) return {
64500
65581
  manager: "Scoop",
64501
65582
  argv: [
64502
65583
  "scoop",
@@ -66471,7 +67552,7 @@ Examples:
66471
67552
  $ lua test skill --name mySkill --json Output raw JSON for scripting
66472
67553
  $ lua test workflow --name outreach --input @leads.json --step-output draftEmail=@draft.json --approve reviewDrafts
66473
67554
  `).action(testCommand);
66474
- program2.command("push [type]").description("\u2601\uFE0F Push skill, agent, webhook, job, MCP server, or backup to server").option("--force", "Skip all confirmation prompts (auto-confirm)").option("--auto-deploy", "Automatically deploy to production after push").option("--name <name>", "Entity name to push").option("--set-version <version>", "Version to set (e.g., 1.0.5)").option("--fresh", "Build backup manifest from disk instead of compiled manifest.json (push backup only)").option("--no-include-source", "Skip the per-skill source attach after push (default: attach, so admin Builder UI sees CLI edits)").addHelpText("after", `
67555
+ program2.command("push [type]").description("\u2601\uFE0F Push skill, agent, webhook, job, MCP server, or backup to server").option("--force", "Skip all confirmation prompts (auto-confirm)").option("--auto-deploy", "Automatically deploy to production after push").option("--name <name>", "Entity name to push").option("--set-version <version>", "Version to set (e.g., 1.0.5)").option("--fresh", "Build backup manifest from disk instead of compiled manifest.json (push backup only)").option("--apply-effort", "push workflow: send each agent step's effort to the model from this version on (a plain push never does)").option("--no-include-source", "Skip the per-skill source attach after push (default: attach, so admin Builder UI sees CLI edits)").addHelpText("after", `
66475
67556
  Arguments:
66476
67557
  type Optional: 'skill', 'agent', 'persona', 'webhook', 'job', 'preprocessor', 'postprocessor', 'mcp', 'backup', or 'all' (prompts if not provided)
66477
67558
 
@@ -66727,7 +67808,7 @@ Examples:
66727
67808
  $ lua jobs versions -i myJob View job versions
66728
67809
  $ lua jobs history -i myJob View execution history
66729
67810
  `).action(jobsCommand);
66730
- program2.command("workflows [action] [target] [extra]").description("\u{1F9ED} Manage workflows and their runs (list, start, watch, cancel, resume, retry-step, resolve-step, raise-budget, approve, signal, replay, export, schedules)").option("-i, --workflow-name <name>", "Workflow name (or id)").option("-r, --run-id <id>", "Run id").option("-v, --workflow-version <ver>", "deploy/start/export/goals create/schedules create: a semver, 'latest' (newest push) or a version id").option("--json", "Print the raw {success,data} envelope").option("--all", "list: include dynamic workflows").option("--input <json|@file>", "start/run/goals create/schedules create: run input").option("--idempotency-key <key>", "start: idempotency key").option("--correlation-key <key>", "start/runs: correlation key").option("--tag <tag>", "start/runs/schedules create: tag (repeatable, \u2264 10)", collect, []).option("--budget-credits <n>", "start/schedules create: run budget (credits)").option("--wait <s>", "start: server long-poll \u2264 55 s").option("--follow", "start/logs: attach watch").option("--status <status>", "runs/goals list: filter by status").option("--workflow <name>", "runs: filter by workflow").option("--limit <n>", "runs/goals list/approval-payload --path: page size").option("--cursor <c>", "runs/goals list/approval-payload --path: page cursor").option("--sort <field>", "runs: -createdAt|createdAt|-durationMs|durationMs").option("--steps", "status: per-step table").option("--strict", "status: exit 4/5 by terminal status").option("--after <seq>", "watch: replay from seq").option("--timeout <s>", "watch / start --follow: give up after s seconds while the run is still live (exit 7)").option("--events", "watch: print raw frames").option("--wait-for-human", "watch / start --follow: keep following through a human boundary (approval, input, signal, park) instead of exiting 8").option("--reason <text>", "cancel: reason").option("--step <id>", "resume/retry-step/resolve-step/logs: step id").option("--outcome <skip|complete|fail>", "resolve-step: the decision on the parked step (--action is accepted too)").option("--action <skip|complete|fail>", "resolve-step: alias of --outcome").option("--output <json|@file>", "resolve-step: the output a completed step would have produced (required with --outcome complete)").option("--credits <n>", "raise-budget: the new credit cap of a budget-parked run (above the current one)").option("--max-steps <n>", "raise-budget: the new step cap").option("--max-job-seconds <n>", "raise-budget: the new Job-tier seconds cap").option("--max-duration-seconds <n>", "raise-budget: the new wall-clock cap").option("--data <json|@file>", "resume: resumeData").option("--approval <id>", "approve/approval-payload: approval id").option("--path <array.path>", "approval-payload: page one array of a large payload (--cursor / --limit inside it)").option("--decision <approve|deny>", "approve: decision (default approve)").option("--note <text>", "approve/retry-step/resolve-step/raise-budget/goals close: note").option("--edit <json|@file>", "approve: edited payload (small inline edits)").option("--fingerprint <f>", "approve: payloadFingerprint (mandatory with --edit)").option("--payload <json|@file>", "signal: payload").option("--dedupe-key <key>", "signal: dedupe key").option("--local", "replay: replay locally against the compiled artifact").option("--since <dur>", "logs: window").option("--yes", "delete/delete-run/schedules delete: skip confirmation").option("--force", "delete: cancel in-flight runs first \xB7 run: seed from a changed graph \xB7 export: overwrite files").option("--step-output <id=json>", "run: complete a step with this output (repeatable)", collect, []).option("--approve <id[=@payload]>", "run: pre-answer an approval (repeatable)", collect, []).option("--deny <id[=@reason]>", "run: pre-deny an approval (repeatable)", collect, []).option("--signal <name=json>", "run: pre-supply a waitForSignal payload (repeatable)", collect, []).option("--from-run <runId>", "run: seed completed steps from a real run").option("--record <dir>", "run: record agent/tool outputs as fixtures").option("--fixtures <dir>", "run: replay recorded fixtures").option("--step-wall <s>", "run: per-step wall in seconds (default 600)").option("--job-wall <s>", "run: virtual wall for tier:'job' steps \u2014 splits at 14400 s segments, > 86400 is exit 2").option("--ledger-out <file>", "run: write the in-memory ledger as JSON").option("--agents <fake|live>", "run: fake agent steps (default) or call the dev API").option("--now <iso>", "run: virtual clock start").option("--park <id>", "run: simulate a platform-fault park of this step (repeatable)", collect, []).option("--fast-retries", "run: collapse retry backoff waits to 0").option("--real-time", "run: actually wait on sleeps/backoffs instead of fast-forwarding").option("--artefacts-dir <dir>", "run: back ctx.artefacts.* on disk").option("--workspace <dir>", "run: the checkout Job-tier code steps run in (ctx.workspace + ctx.exec / ctx.$)").option("--env <KEY=value>", "run: local env.template() overlay (repeatable; missing key \u21D2 exit 2)", collect, []).option("--max-ticks <n>", "run (script form): tick cap before SCRIPT_TICK_LIMIT (default 64)").option("--until <iso>", "archive-runs: window end").option("--out <dir>", "archive-runs: destination dir (archive-index.ndjson + <runId>.zip) \xB7 export: target dir").option("--concurrency <n>", "archive-runs: parallel exports (default 2, max 5)").option("--no-inputs", "archive-runs: exclude run inputs from the bundle").option("--no-artefacts", "archive-runs: exclude artefacts from the bundle").option("--retention-days <n>", "archive-runs: org run retention (default 90) \u2014 --since must fit retention \u2212 7 d").option("--connection <id>", "archive-runs: org storage connection for s3:// / gs:// sinks").option("--release", "workspace: release the run workspace (R42)").option("--attempt <n>", "job-logs: attempt (default latest)").option("--tail <n>", "job-logs: log lines (1..2000, default 200)").option("--objective <text>", "goals create: the objective (\u2264 2000 chars)").option("--judge-predicate <spec>", "goals create: deterministic judge \u2014 '<path> <op> [value]' (e.g. 'output.done truthy'), JSON or @file").option("--judge-agent <agentId|'$self'>", "goals create: judge agent \u2014 write '$self' quoted (or self); it needs --judge-role").option("--judge-role <json|@file>", "goals create: D25 role {name,instructions,tools} for a '$self' judge").option("--schema <json|@file>", "goals create: judge output JsonSchema (must declare a boolean `done`)").option("--cadence <cron|json|@file>", "goals create/schedules create: cadence entry (repeatable, \u2264 5); goals: none \u21D2 immediate", collect, []).option("--timezone <tz>", "goals create/edit/schedules create: IANA timezone for bare cron cadences").option("--notify <emailApp|email|app|off>", "schedules create: where each fire notifies").option("--backfill-on-enable <n|none>", "schedules create/patch/resume: replay \u2264 n missed fires on re-enable (patch: none clears it)").option("--backfill-now", "schedules resume (or patch --paused false): one-shot backfill on THIS re-enable").option("--paused <true|false>", "schedules patch: pause (true) or re-enable (false) the schedule").option("--max-runs <n>", "goals create/edit/raise: iteration cap (1..100)").option("--max-total-credits <n>", "goals create: lineage-wide credit gate").option("--max-credits <n|none>", "goals edit/raise: lineage-wide credit gate (edit: none clears it)").option("--every <interval>", "goals edit/schedules create: interval cadence \u2014 900, 15m, 2h (whole minutes, \u2265 60s)").option("--if-match <updatedAt>", "goals edit/raise: refuse the write if the goal changed since this updatedAt").addHelpText("after", `
67811
+ program2.command("workflows [action] [target] [extra]").description("\u{1F9ED} Manage workflows and their runs (list, start, watch, cancel, resume, retry-step, resolve-step, raise-budget, approve, signal, replay, export, schedules)").option("-i, --workflow-name <name>", "Workflow name (or id)").option("-r, --run-id <id>", "Run id").option("-v, --workflow-version <ver>", "deploy/start/export/goals create/schedules create: a semver, 'latest' (newest push) or a version id").option("--json", "Print the raw {success,data} envelope").option("--all", "list: include dynamic workflows").option("--input <json|@file>", "start/run/goals create/schedules create: run input").option("--idempotency-key <key>", "start: idempotency key").option("--correlation-key <key>", "start/runs: correlation key").option("--tag <tag>", "start/runs/schedules create: tag (repeatable, \u2264 10)", collect, []).option("--budget-credits <n>", "start/schedules create: run budget (credits)").option("--wait <s>", "start: server long-poll \u2264 55 s").option("--follow", "start/logs: attach watch").option("--status <status>", "runs/goals list: filter by status").option("--workflow <name>", "runs: filter by workflow").option("--limit <n>", "runs/goals list/approval-payload --path: page size").option("--cursor <c>", "runs/goals list/approval-payload --path: page cursor").option("--sort <field>", "runs: -createdAt|createdAt|-durationMs|durationMs").option("--steps", "status: per-step table").option("--strict", "status: exit 4/5 by terminal status, 6 for a gated run").option("--compose <on|off>", "policy models set: may the composer be shown the model menu").option("--max-class <fast|balanced|strong>", "policy models set: ceiling for class requests and the class map").option("--consent-actions <n>", "policy models set: estimated actions above which a composed run shows the card").option("--allow <codes>", "policy models set: comma-separated approved codes to narrow the set to").option("--class-fast <codes>", "policy models set: ordered overrides of the fast class (comma-separated)").option("--class-balanced <codes>", "policy models set: ordered overrides of the balanced class (comma-separated)").option("--class-strong <codes>", "policy models set: ordered overrides of the strong class (comma-separated)").option("--class-map <pairs>", "policy models set: comma-separated <taskClass>=<modelClass> pairs").option("--pins <class-only|allowed>", "policy models set: may a composed definition pin a concrete code").option("--fallback <same-class|same-provider>", "policy models set: where a failed leg may hop to").option("--enabled <on|off>", "policy autonomy set: may a start inside the envelope skip the consent card").option("--max-duration <seconds>", "policy autonomy set: the envelope\u2019s duration bound, in seconds").option("--max-actions <n>", "policy autonomy set: the envelope\u2019s estimated-actions bound").option("--max-runs-per-hour <n>", "policy autonomy set: autonomous starts per hour, per agent").option("--forms <list>", "policy autonomy set: comma-separated forms the envelope admits (graph,script,static)").option("--clear <keys>", "policy autonomy set: comma-separated members to clear back to the platform default").option("--agent <agentId>", "policy autonomy: not supported \u2014 no route writes a per-agent envelope (see the refusal)").option("--kind <kind>", "clear-gate: the gate kind to clear (e.g. model_policy)").option("--after <seq>", "watch: replay from seq").option("--timeout <s>", "watch / start --follow: give up after s seconds while the run is still live (exit 7)").option("--events", "watch: print raw frames").option("--wait-for-human", "watch / start --follow: keep following through a human boundary (approval, input, signal, park) instead of exiting 8").option("--reason <text>", "cancel: reason").option("--step <id>", "resume/retry-step/resolve-step/logs: step id").option("--outcome <skip|complete|fail>", "resolve-step: the decision on the parked step (--action is accepted too)").option("--action <skip|complete|fail>", "resolve-step: alias of --outcome").option("--output <json|@file>", "resolve-step: the output a completed step would have produced (required with --outcome complete)").option("--credits <n>", "raise-budget: the new credit cap of a budget-parked run (above the current one)").option("--max-steps <n>", "raise-budget: the new step cap").option("--max-job-seconds <n>", "raise-budget: the new Job-tier seconds cap").option("--max-duration-seconds <n>", "raise-budget: the new wall-clock cap").option("--data <json|@file>", "resume: resumeData").option("--approval <id>", "approve/approval-payload: approval id").option("--path <array.path>", "approval-payload: page one array of a large payload (--cursor / --limit inside it)").option("--decision <approve|deny>", "approve: decision (default approve)").option("--note <text>", "approve/retry-step/resolve-step/raise-budget/goals close: note").option("--edit <json|@file>", "approve: edited payload (small inline edits)").option("--fingerprint <f>", "approve: payloadFingerprint (mandatory with --edit)").option("--payload <json|@file>", "signal: payload").option("--dedupe-key <key>", "signal: dedupe key").option("--local", "replay: replay locally against the compiled artifact").option("--since <dur>", "logs: window").option("--yes", "delete/delete-run/schedules delete: skip confirmation").option("--force", "delete: cancel in-flight runs first \xB7 run: seed from a changed graph \xB7 export: overwrite files").option("--step-output <id=json>", "run: complete a step with this output (repeatable)", collect, []).option("--approve <id[=@payload]>", "run: pre-answer an approval (repeatable)", collect, []).option("--deny <id[=@reason]>", "run: pre-deny an approval (repeatable)", collect, []).option("--signal <name=json>", "run: pre-supply a waitForSignal payload (repeatable)", collect, []).option("--from-run <runId>", "run: seed completed steps from a real run").option("--record <dir>", "run: record agent/tool outputs as fixtures").option("--fixtures <dir>", "run: replay recorded fixtures").option("--step-wall <s>", "run: per-step wall in seconds (default 600)").option("--job-wall <s>", "run: virtual wall for tier:'job' steps \u2014 splits at 14400 s segments, > 86400 is exit 2").option("--ledger-out <file>", "run: write the in-memory ledger as JSON").option("--agents <fake|live>", "run: fake agent steps (default) or call the dev API").option("--now <iso>", "run: virtual clock start").option("--park <id>", "run: simulate a platform-fault park of this step (repeatable)", collect, []).option("--fast-retries", "run: collapse retry backoff waits to 0").option("--real-time", "run: actually wait on sleeps/backoffs instead of fast-forwarding").option("--artefacts-dir <dir>", "run: back ctx.artefacts.* on disk").option("--workspace <dir>", "run: the checkout Job-tier code steps run in (ctx.workspace + ctx.exec / ctx.$)").option("--env <KEY=value>", "run: local env.template() overlay (repeatable; missing key \u21D2 exit 2)", collect, []).option("--max-ticks <n>", "run (script form): tick cap before SCRIPT_TICK_LIMIT (default 64)").option("--until <iso>", "archive-runs: window end").option("--out <dir>", "archive-runs: destination dir (archive-index.ndjson + <runId>.zip) \xB7 export: target dir").option("--concurrency <n>", "archive-runs: parallel exports (default 2, max 5)").option("--no-inputs", "archive-runs: exclude run inputs from the bundle").option("--no-artefacts", "archive-runs: exclude artefacts from the bundle").option("--retention-days <n>", "archive-runs: org run retention (default 90) \u2014 --since must fit retention \u2212 7 d").option("--connection <id>", "archive-runs: org storage connection for s3:// / gs:// sinks").option("--release", "workspace: release the run workspace (R42)").option("--attempt <n>", "job-logs: attempt (default latest)").option("--tail <n>", "job-logs: log lines (1..2000, default 200)").option("--objective <text>", "goals create: the objective (\u2264 2000 chars)").option("--judge-predicate <spec>", "goals create: deterministic judge \u2014 '<path> <op> [value]' (e.g. 'output.done truthy'), JSON or @file").option("--judge-agent <agentId|'$self'>", "goals create: judge agent \u2014 write '$self' quoted (or self); it needs --judge-role").option("--judge-role <json|@file>", "goals create: D25 role {name,instructions,tools} for a '$self' judge").option("--schema <json|@file>", "goals create: judge output JsonSchema (must declare a boolean `done`)").option("--cadence <cron|json|@file>", "goals create/schedules create: cadence entry (repeatable, \u2264 5); goals: none \u21D2 immediate", collect, []).option("--timezone <tz>", "goals create/edit/schedules create: IANA timezone for bare cron cadences").option("--notify <emailApp|email|app|off>", "schedules create: where each fire notifies").option("--backfill-on-enable <n|none>", "schedules create/patch/resume: replay \u2264 n missed fires on re-enable (patch: none clears it)").option("--backfill-now", "schedules resume (or patch --paused false): one-shot backfill on THIS re-enable").option("--paused <true|false>", "schedules patch: pause (true) or re-enable (false) the schedule").option("--max-runs <n>", "goals create/edit/raise: iteration cap (1..100)").option("--max-total-credits <n>", "goals create: lineage-wide credit gate").option("--max-credits <n|none>", "goals edit/raise: lineage-wide credit gate (edit: none clears it)").option("--every <interval>", "goals edit/schedules create: interval cadence \u2014 900, 15m, 2h (whole minutes, \u2265 60s)").option("--if-match <updatedAt>", "goals edit/raise: refuse the write if the goal changed since this updatedAt").addHelpText("after", `
66731
67812
  Arguments:
66732
67813
  action list \xB7 view \xB7 versions \xB7 deploy \xB7 activate \xB7 deactivate \xB7 start \xB7 run \xB7 runs \xB7 status \xB7
66733
67814
  watch \xB7 cancel \xB7 resume \xB7 retry-step \xB7 resolve-step \xB7 raise-budget \xB7 approve \xB7 approval-payload \xB7
@@ -66784,6 +67865,15 @@ Examples:
66784
67865
  $ lua workflows goals pause wfg_1234 \xB7 goals resume wfg_1234 \xB7 goals close wfg_1234 --note "shipped"
66785
67866
  $ lua workflows schedules list -i outreach
66786
67867
  $ lua workflows schedules delete <jobId> --yes (a goal's cadence is refused: goal_schedule)
67868
+ $ lua workflows policy models get
67869
+ $ lua workflows policy models set --compose on --max-class strong --consent-actions 60 --pins class-only
67870
+ $ lua workflows policy models set --class-map judge=strong,draft=balanced --class-fast alibaba/qwen3.8-flash
67871
+ $ lua workflows policy autonomy get (the stored envelope and the one a start is admitted under)
67872
+ $ lua workflows policy autonomy set --enabled on --max-credits 40 --max-steps 20 --max-duration 86400
67873
+ $ lua workflows policy autonomy set --forms graph,static --max-runs-per-hour 20
67874
+ $ lua workflows policy autonomy set --clear max-credits,forms (back to the platform defaults)
67875
+ $ lua workflows clear-gate <runId> --kind model_policy
67876
+ $ lua workflows recompose outreach (rewrites stored task classes into class/<c>; a new version)
66787
67877
  `).action(workflowsCommand);
66788
67878
  program2.command("features [action]").description("\u{1F3AF} Manage agent features (RAG, webSearch, inquiry, outboundChannels)").option("--feature-name <name>", "Feature name").option("--recipient-scope <scope>", "For configure: outboundChannels recipient scope (current_user | anyone)").addHelpText("after", `
66789
67879
  Arguments:
@@ -66967,18 +68057,20 @@ Examples:
66967
68057
  $ lua agents List all orgs and agents (formatted)
66968
68058
  $ lua agents --json Output as JSON for scripting
66969
68059
  `).action(agentsCommand);
66970
- program2.command("models [action]").description("\u{1F9E0} List and manage LLM models for your agent").option("--model <code>", "Model code for 'set' action (e.g. 'openai/gpt-4o')").option("--json", "Output as JSON").addHelpText("after", `
68060
+ program2.command("models [action]").description("\u{1F9E0} List and manage LLM models for your agent").option("--model <code>", "Model code for 'set' action (e.g. 'openai/gpt-4o')").option("--json", "Output as JSON").option("--workflows", "list: the catalog as a workflow step sees it \u2014 class, best for, speed, cost, efforts").addHelpText("after", `
66971
68061
  Arguments:
66972
68062
  action Optional: 'list', 'set', or 'unset' (default: list)
66973
68063
 
66974
68064
  Options:
66975
68065
  --model <code> Set model non-interactively (use with 'set' action)
66976
68066
  --json Output list as JSON (use with 'list' action)
68067
+ --workflows List for workflow steps: class, best for, speed, cost, efforts (use with 'list')
66977
68068
 
66978
68069
  Examples:
66979
68070
  $ lua models List available models (formatted)
66980
68071
  $ lua models list List available models (explicit)
66981
68072
  $ lua models list --json List as JSON for scripting
68073
+ $ lua models list --workflows Class, best for, speed, cost and efforts, for workflow steps
66982
68074
  $ lua models set Interactively select a model
66983
68075
  $ lua models set --model openai/gpt-4o Set model non-interactively
66984
68076
  $ lua models unset Remove model \u2014 use platform default