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