lua-cli 3.32.3 → 3.32.4
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 +5 -3
- package/dist/api-exports.js +634 -297
- package/dist/api-exports.js.map +1 -1
- package/dist/index.js +1443 -923
- package/dist/index.js.map +1 -1
- package/dist/workflow-builder.d.ts +5 -3
- package/dist/workflow-builder.js +426 -256
- package/dist/workflow-builder.js.map +1 -1
- package/docs/README.md +2 -2
- package/docs/api/LuaWorkflow.md +1 -1
- package/docs/workflows/approvals.md +2 -0
- package/docs/workflows/recovery.md +1 -1
- package/docs/workflows/schedules.md +13 -4
- package/package.json +4 -4
- package/template/examples/workflows/research-brief.ts +29 -16
- package/template/package.json +1 -1
package/dist/index.js
CHANGED
|
@@ -65,6 +65,20 @@ var init_auth_error = __esm({
|
|
|
65
65
|
});
|
|
66
66
|
|
|
67
67
|
// src/errors/cli.error.ts
|
|
68
|
+
function isTypedCliError(error) {
|
|
69
|
+
return CliError.isCliError(error) || AuthenticationError.isAuthenticationError(error);
|
|
70
|
+
}
|
|
71
|
+
function listHint(title, items, bullet = "- ") {
|
|
72
|
+
if (items.length === 0) return void 0;
|
|
73
|
+
return [
|
|
74
|
+
title,
|
|
75
|
+
...items.map((item) => ` ${bullet}${item}`)
|
|
76
|
+
].join("\n");
|
|
77
|
+
}
|
|
78
|
+
function joinHint(...parts) {
|
|
79
|
+
const lines = parts.filter((part) => typeof part === "string" && part.length > 0);
|
|
80
|
+
return lines.length > 0 ? lines.join("\n") : void 0;
|
|
81
|
+
}
|
|
68
82
|
function isAccessDeniedError(error) {
|
|
69
83
|
if (CliError.isCliError(error)) return error.statusCode === 403;
|
|
70
84
|
return error instanceof Error && error.message.startsWith("Access denied (403)");
|
|
@@ -265,10 +279,31 @@ var init_cli_error = __esm({
|
|
|
265
279
|
statusCode: 403
|
|
266
280
|
});
|
|
267
281
|
}
|
|
282
|
+
/**
|
|
283
|
+
* An API refusal the site already holds the status of (LUA-766) — classified by the same table the top-level
|
|
284
|
+
* classifier applies to an untyped error: 401 auth · 403 forbidden · 404 not_found · other 4xx `http_<status>`
|
|
285
|
+
* (10) · 5xx / 0 unavailable (11, with the network hint unless the site gives its own) · no status `error` (1).
|
|
286
|
+
* A command that reads `response.error.statusCode` throws through here, so `lua logs` on a 503 exits 11 like
|
|
287
|
+
* every other verb instead of printing the message itself and then throwing an exit-1 `Error`.
|
|
288
|
+
*/
|
|
289
|
+
static fromStatus(statusCode, message, hint) {
|
|
290
|
+
const reported = classifyCliError(Object.assign(new Error(message), {
|
|
291
|
+
statusCode
|
|
292
|
+
}));
|
|
293
|
+
const classHint = reported.exitCode === CLI_EXIT.UNAVAILABLE ? UNAVAILABLE_HINT : reported.hint;
|
|
294
|
+
return new _CliError(reported.code, message, {
|
|
295
|
+
exitCode: reported.exitCode,
|
|
296
|
+
hint: hint ?? classHint,
|
|
297
|
+
statusCode
|
|
298
|
+
});
|
|
299
|
+
}
|
|
268
300
|
static isCliError(error) {
|
|
269
301
|
return error instanceof _CliError || typeof error === "object" && error !== null && error.isCliError === true;
|
|
270
302
|
}
|
|
271
303
|
};
|
|
304
|
+
__name(isTypedCliError, "isTypedCliError");
|
|
305
|
+
__name(listHint, "listHint");
|
|
306
|
+
__name(joinHint, "joinHint");
|
|
272
307
|
__name(isAccessDeniedError, "isAccessDeniedError");
|
|
273
308
|
HandledCliError = class extends Error {
|
|
274
309
|
static {
|
|
@@ -953,6 +988,84 @@ function isDesktopFileCommandName(value3) {
|
|
|
953
988
|
function isDesktopFileSessionId(value3) {
|
|
954
989
|
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);
|
|
955
990
|
}
|
|
991
|
+
function isModelIdSentinel(input) {
|
|
992
|
+
const lower = (input ?? "").trim().toLowerCase();
|
|
993
|
+
return lower === "auto" || lower.startsWith("auto/");
|
|
994
|
+
}
|
|
995
|
+
function normalizeModelId(input, registry) {
|
|
996
|
+
const requested = typeof input === "string" ? input.trim() : "";
|
|
997
|
+
if (!requested) return {
|
|
998
|
+
ok: false,
|
|
999
|
+
reason: "empty",
|
|
1000
|
+
requested,
|
|
1001
|
+
candidates: []
|
|
1002
|
+
};
|
|
1003
|
+
const lower = requested.toLowerCase();
|
|
1004
|
+
if (isModelIdSentinel(lower)) return {
|
|
1005
|
+
ok: true,
|
|
1006
|
+
id: lower,
|
|
1007
|
+
form: "sentinel"
|
|
1008
|
+
};
|
|
1009
|
+
const slash = requested.indexOf("/");
|
|
1010
|
+
const malformed = slash === 0;
|
|
1011
|
+
const provider = slash > 0 ? lower.slice(0, slash) : void 0;
|
|
1012
|
+
if (provider && MODEL_ID_BYOK_PROVIDERS.includes(provider)) {
|
|
1013
|
+
return {
|
|
1014
|
+
ok: true,
|
|
1015
|
+
id: requested,
|
|
1016
|
+
form: "byok"
|
|
1017
|
+
};
|
|
1018
|
+
}
|
|
1019
|
+
const bareId = slash >= 0 ? lower.slice(slash + 1) : lower;
|
|
1020
|
+
const lastSegment = bareId.slice(bareId.lastIndexOf("/") + 1);
|
|
1021
|
+
const exact = /* @__PURE__ */ new Set();
|
|
1022
|
+
const hints = /* @__PURE__ */ new Set();
|
|
1023
|
+
for (const code of registry) {
|
|
1024
|
+
if (typeof code !== "string" || !code) continue;
|
|
1025
|
+
const codeLower = code.toLowerCase();
|
|
1026
|
+
if (!malformed && codeLower === lower) return {
|
|
1027
|
+
ok: true,
|
|
1028
|
+
id: code,
|
|
1029
|
+
form: provider ? "canonical" : "bare"
|
|
1030
|
+
};
|
|
1031
|
+
const i = codeLower.indexOf("/");
|
|
1032
|
+
if (i < 0) continue;
|
|
1033
|
+
const codeBare = codeLower.slice(i + 1);
|
|
1034
|
+
if (bareId && codeBare === bareId) exact.add(code);
|
|
1035
|
+
else if (lastSegment && codeBare.slice(codeBare.lastIndexOf("/") + 1) === lastSegment) hints.add(code);
|
|
1036
|
+
}
|
|
1037
|
+
const sorted = [
|
|
1038
|
+
...exact
|
|
1039
|
+
].sort();
|
|
1040
|
+
if (!provider && !malformed && sorted.length === 1) return {
|
|
1041
|
+
ok: true,
|
|
1042
|
+
id: sorted[0],
|
|
1043
|
+
form: "bare"
|
|
1044
|
+
};
|
|
1045
|
+
if (!provider && !malformed && sorted.length > 1) {
|
|
1046
|
+
return {
|
|
1047
|
+
ok: false,
|
|
1048
|
+
reason: "ambiguous",
|
|
1049
|
+
requested,
|
|
1050
|
+
candidates: sorted
|
|
1051
|
+
};
|
|
1052
|
+
}
|
|
1053
|
+
return {
|
|
1054
|
+
ok: false,
|
|
1055
|
+
reason: "unknown",
|
|
1056
|
+
requested,
|
|
1057
|
+
candidates: sorted.length ? sorted : [
|
|
1058
|
+
...hints
|
|
1059
|
+
].sort()
|
|
1060
|
+
};
|
|
1061
|
+
}
|
|
1062
|
+
function modelUnresolvedMessage(r) {
|
|
1063
|
+
if (r.reason === "empty") return "model pin is empty \u2014 pin an approved model (provider/model) or omit `model`";
|
|
1064
|
+
if (r.reason === "ambiguous") {
|
|
1065
|
+
return `model "${r.requested}" does not resolve to one approved model \u2014 it names ${r.candidates.length}; pin one of: ${r.candidates.join(", ")}`;
|
|
1066
|
+
}
|
|
1067
|
+
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`;
|
|
1068
|
+
}
|
|
956
1069
|
function isImplicitModelSelectionSource(source) {
|
|
957
1070
|
return source !== void 0 && IMPLICIT_MODEL_SELECTION_SOURCES.includes(source);
|
|
958
1071
|
}
|
|
@@ -1541,7 +1654,7 @@ function extractSingleJsonValue(text) {
|
|
|
1541
1654
|
};
|
|
1542
1655
|
}
|
|
1543
1656
|
}
|
|
1544
|
-
var __defProp2, __name2, 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, 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, TEMPLATE_TRIGGER_URL_ENV_PREFIX, SUBJECT_TYPES, SubjectTypeSchema, CREDENTIAL_TYPES, CredentialTypeSchema, DEVICE_OPERATIONS, DeviceOperationSchema, DEVICE_SCOPE_BY_OPERATION, DeviceBindingSchema, TYPED_API_KEY, IdSchema, PrincipalDescriptorSchema, ActorDescriptorSchema, PrincipalOwnerSchema, CredentialLifecycleSchema, GeneralCredentialDescriptorSchema, DeviceCredentialDescriptorSchema, GeneralPrincipalContextSchema, DeviceCredentialPrincipalContextSchema, RawPrincipalContextSchema, PrincipalContextSchema, DeviceCredentialClaimSchema, LUA_CLIENT_HEADER, LUA_CLIENT_APPS, SEMVER_PATTERN, WEB_RELEASE_PATTERN, CLIENT_HEADER_PATTERN, AUTHZ_PROJECTION_VERSION, ProjectedScopeSchema, DisplayRoleSchema, AuthorizationPrincipalSchema, CredentialContextSchema, ProjectionAnomalySchema, ProjectedOrgSchema, ProjectedResourceSchema, CapabilityProfilesSchema, RoleCatalogSchema, EffectiveAuthorizationSchema, ResourcePageSchema, SYSTEM_USER_PREFIX, WORKFLOW_RUN_IN_FLIGHT, WORKFLOW_RUN_IDLE, WORKFLOW_RUN_TERMINAL, WORKFLOW_RUN_STATUSES, WORKFLOW_STEP_STATUSES, WORKFLOW_STEP_IN_FLIGHT, ARCHIVE_WINDOW_MARGIN_DAYS, WORKFLOW_ORG_PURGING_TTL_S, WORKFLOW_ORG_PURGE_FORCE_AFTER_MS, IDEMPOTENCY_HOLDING_STATUSES, WORKFLOW_SCHEDULED_RUN_ID_PREFIX, CLOUD_TASK_RUN_ID_PREFIX, WORKFLOW_OPERATION_ID_PREFIX, WORKFLOW_JOURNAL_PROTOCOL_VERSION, 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;
|
|
1657
|
+
var __defProp2, __name2, REVIEWABLE_ACTION_EXECUTE_TOOL_ALLOWLIST, REVIEWABLE_MCP_SEND_TOOL_SUFFIX, MCP_TOOL_READ_VERB_RE, MCP_DRAFT_CREATE_VERBS, NON_INTERACTIVE_CHANNELS, RICH_PARTS_MESSAGE_ID_PREFIX, SCREENSHOT_MESSAGE_ID_PREFIX, BROWSER_COMMANDS, BROWSER_COMMAND_NAMES, DESKTOP_FILE_COMMANDS, DESKTOP_FILE_COMMAND_SET, MODEL_ID_BYOK_PROVIDERS, REASONING_EFFORT_VALUES, IMPLICIT_MODEL_SELECTION_SOURCES, PLATFORM_FALLBACK_MODEL_SOURCE, AGENT_NAME_TOKEN, DEFAULT_PERSONA_GUIDE, PERSONAL_SPACE_STARTING_PERSONA, 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, TEMPLATE_TRIGGER_URL_ENV_PREFIX, SUBJECT_TYPES, SubjectTypeSchema, CREDENTIAL_TYPES, CredentialTypeSchema, DEVICE_OPERATIONS, DeviceOperationSchema, DEVICE_SCOPE_BY_OPERATION, DeviceBindingSchema, TYPED_API_KEY, IdSchema, PrincipalDescriptorSchema, ActorDescriptorSchema, PrincipalOwnerSchema, CredentialLifecycleSchema, GeneralCredentialDescriptorSchema, DeviceCredentialDescriptorSchema, GeneralPrincipalContextSchema, DeviceCredentialPrincipalContextSchema, RawPrincipalContextSchema, PrincipalContextSchema, DeviceCredentialClaimSchema, LUA_CLIENT_HEADER, LUA_CLIENT_APPS, SEMVER_PATTERN, WEB_RELEASE_PATTERN, CLIENT_HEADER_PATTERN, AUTHZ_PROJECTION_VERSION, ProjectedScopeSchema, DisplayRoleSchema, AuthorizationPrincipalSchema, CredentialContextSchema, ProjectionAnomalySchema, ProjectedOrgSchema, ProjectedResourceSchema, CapabilityProfilesSchema, RoleCatalogSchema, EffectiveAuthorizationSchema, ResourcePageSchema, SYSTEM_USER_PREFIX, WORKFLOW_RUN_IN_FLIGHT, WORKFLOW_RUN_IDLE, WORKFLOW_RUN_TERMINAL, WORKFLOW_RUN_STATUSES, WORKFLOW_STEP_STATUSES, WORKFLOW_STEP_IN_FLIGHT, ARCHIVE_WINDOW_MARGIN_DAYS, WORKFLOW_ORG_PURGING_TTL_S, WORKFLOW_ORG_PURGE_FORCE_AFTER_MS, IDEMPOTENCY_HOLDING_STATUSES, WORKFLOW_SCHEDULED_RUN_ID_PREFIX, CLOUD_TASK_RUN_ID_PREFIX, WORKFLOW_OPERATION_ID_PREFIX, WORKFLOW_JOURNAL_PROTOCOL_VERSION, 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;
|
|
1545
1658
|
var init_dist = __esm({
|
|
1546
1659
|
"../shared-types/dist/index.mjs"() {
|
|
1547
1660
|
"use strict";
|
|
@@ -1849,6 +1962,16 @@ var init_dist = __esm({
|
|
|
1849
1962
|
__name2(isDesktopFileCommandName, "isDesktopFileCommandName");
|
|
1850
1963
|
__name(isDesktopFileSessionId, "isDesktopFileSessionId");
|
|
1851
1964
|
__name2(isDesktopFileSessionId, "isDesktopFileSessionId");
|
|
1965
|
+
MODEL_ID_BYOK_PROVIDERS = [
|
|
1966
|
+
"azure",
|
|
1967
|
+
"bedrock"
|
|
1968
|
+
];
|
|
1969
|
+
__name(isModelIdSentinel, "isModelIdSentinel");
|
|
1970
|
+
__name2(isModelIdSentinel, "isModelIdSentinel");
|
|
1971
|
+
__name(normalizeModelId, "normalizeModelId");
|
|
1972
|
+
__name2(normalizeModelId, "normalizeModelId");
|
|
1973
|
+
__name(modelUnresolvedMessage, "modelUnresolvedMessage");
|
|
1974
|
+
__name2(modelUnresolvedMessage, "modelUnresolvedMessage");
|
|
1852
1975
|
REASONING_EFFORT_VALUES = [
|
|
1853
1976
|
"off",
|
|
1854
1977
|
"minimal",
|
|
@@ -3797,6 +3920,129 @@ function resolveMapping(cfg, ctx) {
|
|
|
3797
3920
|
value: result
|
|
3798
3921
|
};
|
|
3799
3922
|
}
|
|
3923
|
+
function describeApproverSpecRefusal(spec) {
|
|
3924
|
+
const raw = spec === void 0 ? "undefined" : JSON.stringify(spec) ?? String(spec);
|
|
3925
|
+
const written = raw.length > APPROVER_WRITTEN_MAX ? `${raw.slice(0, APPROVER_WRITTEN_MAX - 1)}\u2026` : raw;
|
|
3926
|
+
const users = typeof spec === "object" && spec !== null ? spec.users : void 0;
|
|
3927
|
+
const approver = typeof users === "string" && USER_ID_SHAPED_RE.test(users) ? {
|
|
3928
|
+
users: [
|
|
3929
|
+
users
|
|
3930
|
+
]
|
|
3931
|
+
} : "creator";
|
|
3932
|
+
const message = `approver ${written} is not an approver \u2014 legal: ${APPROVER_SPEC_SHAPES.join(" | ")}. 'creator' is the person who started the run: write approver:'creator' for "ask me" / "I approve"; {users:[\u2026]} takes user ids, never emails, names or {type:'user'}` + (approver === "creator" ? "" : `; here: approver:${JSON.stringify(approver)}`);
|
|
3933
|
+
return {
|
|
3934
|
+
approver,
|
|
3935
|
+
written,
|
|
3936
|
+
message
|
|
3937
|
+
};
|
|
3938
|
+
}
|
|
3939
|
+
function bindingRootsOk(template22) {
|
|
3940
|
+
const refs = [
|
|
3941
|
+
...template22.matchAll(/\$\{\s*([A-Za-z_$][\w$]*)/g)
|
|
3942
|
+
].map((m) => m[1]);
|
|
3943
|
+
return refs.length > 0 && refs.every((r) => BINDING_ROOTS.includes(r));
|
|
3944
|
+
}
|
|
3945
|
+
function isTemplateBinding(v) {
|
|
3946
|
+
return typeof v === "object" && v !== null && typeof v.template === "string";
|
|
3947
|
+
}
|
|
3948
|
+
function approvalEditable(node) {
|
|
3949
|
+
if (node.editable === true) return true;
|
|
3950
|
+
if (node.editable === false) return false;
|
|
3951
|
+
return Array.isArray(node.editablePaths) && node.editablePaths.length > 0;
|
|
3952
|
+
}
|
|
3953
|
+
function validateApproverBlock(node, opts = {
|
|
3954
|
+
path: "approval"
|
|
3955
|
+
}) {
|
|
3956
|
+
const issues = [];
|
|
3957
|
+
const push = /* @__PURE__ */ __name3((code, path25, message, severity = "error") => issues.push({
|
|
3958
|
+
code,
|
|
3959
|
+
path: path25,
|
|
3960
|
+
severity,
|
|
3961
|
+
message
|
|
3962
|
+
}), "push");
|
|
3963
|
+
const checkSpec = /* @__PURE__ */ __name3((spec, path25) => {
|
|
3964
|
+
const r = ApproverSpecSchema.safeParse(spec);
|
|
3965
|
+
if (!r.success) {
|
|
3966
|
+
const users = spec?.users;
|
|
3967
|
+
if (Array.isArray(users) && users.length > APPROVER_SPEC_MAX_USERS) push("cap-exceeded", path25, `at most ${APPROVER_SPEC_MAX_USERS} users`);
|
|
3968
|
+
else {
|
|
3969
|
+
const refusal = describeApproverSpecRefusal(spec);
|
|
3970
|
+
issues.push({
|
|
3971
|
+
code: "approver-invalid",
|
|
3972
|
+
path: path25,
|
|
3973
|
+
severity: "error",
|
|
3974
|
+
message: refusal.message,
|
|
3975
|
+
repair: {
|
|
3976
|
+
approver: refusal.approver,
|
|
3977
|
+
written: refusal.written
|
|
3978
|
+
}
|
|
3979
|
+
});
|
|
3980
|
+
}
|
|
3981
|
+
return;
|
|
3982
|
+
}
|
|
3983
|
+
const s = r.data;
|
|
3984
|
+
if (typeof s === "object") {
|
|
3985
|
+
if ("governance" in s && !opts.governanceEnabled) push("approver-governance-unavailable", path25, "governance reviewer routing is not enabled for this deployment");
|
|
3986
|
+
if ("group" in s && typeof s.group === "string" && !opts.scimEnabled && opts.idpGroups?.includes(s.group)) push("approver-idp-group-unavailable", path25, "IdP-group approvers are not enabled for this deployment");
|
|
3987
|
+
const binding = "users" in s ? s.users : "role" in s ? s.role : "group" in s ? s.group : void 0;
|
|
3988
|
+
if (isTemplateBinding(binding)) {
|
|
3989
|
+
if (!bindingRootsOk(binding.template)) push("approver-binding-invalid", `${path25}.template`, "binding root must be initData / stepResults / requestContext / state");
|
|
3990
|
+
if ("users" in s && opts.customerReachable) push("approver-binding-customer-reachable", `${path25}.users`, "a customer-reachable workflow may not bind its approver list");
|
|
3991
|
+
}
|
|
3992
|
+
}
|
|
3993
|
+
}, "checkSpec");
|
|
3994
|
+
if (node.approver !== void 0) checkSpec(node.approver, `${opts.path}.approver`);
|
|
3995
|
+
if (node.fourEyes !== void 0) {
|
|
3996
|
+
const r = FourEyesSchema.safeParse(node.fourEyes);
|
|
3997
|
+
if (!r.success) push("approver-invalid", `${opts.path}.fourEyes`, "fourEyes needs { edit, approve } approver specs");
|
|
3998
|
+
else {
|
|
3999
|
+
checkSpec(r.data.edit, `${opts.path}.fourEyes.edit`);
|
|
4000
|
+
checkSpec(r.data.approve, `${opts.path}.fourEyes.approve`);
|
|
4001
|
+
}
|
|
4002
|
+
if (!approvalEditable(node)) push("four-eyes-requires-editable", `${opts.path}.fourEyes`, "fourEyes requires editable:true");
|
|
4003
|
+
if (node.approver !== void 0) push("four-eyes-overrides-approver", `${opts.path}.approver`, "fourEyes replaces approver", "warning");
|
|
4004
|
+
if (node.itemsPath) push("four-eyes-items-unsupported", `${opts.path}.fourEyes`, "fourEyes cannot combine with itemsPath");
|
|
4005
|
+
}
|
|
4006
|
+
if (node.excludeInitiator && (node.approver === void 0 || node.approver === "creator") && !node.fourEyes) push("approver-excludes-only-candidate", `${opts.path}.excludeInitiator`, "'creator' with excludeInitiator leaves no approver");
|
|
4007
|
+
if (Array.isArray(node.onTimeout)) {
|
|
4008
|
+
const chain = node.onTimeout;
|
|
4009
|
+
const hops = chain.filter((m) => typeof m === "object" && m !== null && "escalateTo" in m);
|
|
4010
|
+
if (hops.length > ESCALATION_MAX_HOPS) push("escalation-chain-too-long", `${opts.path}.onTimeout`, `at most ${ESCALATION_MAX_HOPS} hops`);
|
|
4011
|
+
const last = chain[chain.length - 1];
|
|
4012
|
+
if (typeof last === "object" && last !== null) push("escalation-chain-not-terminal", `${opts.path}.onTimeout`, "a chain must end in deny | cancel-run | fail");
|
|
4013
|
+
hops.forEach((h, i) => checkSpec(h.escalateTo, `${opts.path}.onTimeout[${i}].escalateTo`));
|
|
4014
|
+
} else if (typeof node.onTimeout === "object" && node.onTimeout !== null) {
|
|
4015
|
+
checkSpec(node.onTimeout.escalateTo, `${opts.path}.onTimeout.escalateTo`);
|
|
4016
|
+
}
|
|
4017
|
+
return issues;
|
|
4018
|
+
}
|
|
4019
|
+
function liftRenderedApprover(row2, rendered) {
|
|
4020
|
+
const text = (rendered ?? "").trim();
|
|
4021
|
+
if (!text) return null;
|
|
4022
|
+
if (row2 === "users") {
|
|
4023
|
+
let members = null;
|
|
4024
|
+
if (text.startsWith("[")) {
|
|
4025
|
+
try {
|
|
4026
|
+
members = JSON.parse(text);
|
|
4027
|
+
} catch {
|
|
4028
|
+
return null;
|
|
4029
|
+
}
|
|
4030
|
+
} else members = text.split(",").map((s) => s.trim());
|
|
4031
|
+
if (!Array.isArray(members) || members.length === 0 || members.length > APPROVER_SPEC_MAX_USERS) return null;
|
|
4032
|
+
if (!members.every((m) => typeof m === "string" && m.length > 0 && m.length <= 128)) return null;
|
|
4033
|
+
return {
|
|
4034
|
+
users: [
|
|
4035
|
+
...new Set(members)
|
|
4036
|
+
].sort()
|
|
4037
|
+
};
|
|
4038
|
+
}
|
|
4039
|
+
if (text.length > 128 || text.startsWith("[") || text.startsWith("{")) return null;
|
|
4040
|
+
return row2 === "role" ? {
|
|
4041
|
+
role: text
|
|
4042
|
+
} : {
|
|
4043
|
+
group: text
|
|
4044
|
+
};
|
|
4045
|
+
}
|
|
3800
4046
|
function workspaceTemplatePath(template22) {
|
|
3801
4047
|
const key = template22.trim();
|
|
3802
4048
|
const expr = WORKSPACE_TEMPLATE_EXPR_RE.exec(key);
|
|
@@ -3813,6 +4059,9 @@ function retryBackoffs() {
|
|
|
3813
4059
|
function sleepUntilUnsupportedMessage(id) {
|
|
3814
4060
|
return `the engine does not execute \`sleepUntil\` yet (node "${id}") \u2014 replace it with a \`sleep\` node with a \`duration\` in ms, e.g. { type: 'sleep', id: '${id}', duration: ${SLEEP_UNTIL_REPLACEMENT.duration} }`;
|
|
3815
4061
|
}
|
|
4062
|
+
function armSubrunUnsupportedMessage(id, workflowId) {
|
|
4063
|
+
return `the engine does not execute the implicit \`${workflowId}\` arm subrun (node "${id}") \u2014 a [map, step] container arm is the step itself with the map as its \`input\` since lua-cli 3.32.4; re-run \`lua compile\` with the current CLI (a hand-written artifact: put the map on the arm node's \`input\` and drop the \`workflow\` wrapper)`;
|
|
4064
|
+
}
|
|
3816
4065
|
function fillPolicy(node, defaultTimeout) {
|
|
3817
4066
|
if (node.tier === void 0 && node.workspace !== void 0 && node.workspace !== "inherit") node.tier = "job";
|
|
3818
4067
|
if (node.timeoutSeconds === void 0) node.timeoutSeconds = node.tier === "job" ? WORKFLOW_JOB_DEFAULT_TIMEOUT_SECONDS : defaultTimeout;
|
|
@@ -3838,7 +4087,6 @@ function fillSingle(node) {
|
|
|
3838
4087
|
fillPolicy(node, WORKFLOW_STEP_DEFAULT_TIMEOUT_SECONDS);
|
|
3839
4088
|
return;
|
|
3840
4089
|
case "workflow":
|
|
3841
|
-
if (node.workflowId === WORKFLOW_ARM_SUBRUN_ID && Array.isArray(node.graph) && node.graph[1]) fillSingle(node.graph[1]);
|
|
3842
4090
|
return;
|
|
3843
4091
|
}
|
|
3844
4092
|
}
|
|
@@ -3970,8 +4218,14 @@ function nodeStepRefs(entry) {
|
|
|
3970
4218
|
case "agent": {
|
|
3971
4219
|
const a = entry;
|
|
3972
4220
|
const p = a.promptTemplate;
|
|
3973
|
-
|
|
4221
|
+
const prompt = typeof p === "string" ? templateStepRefs(p) : p && "template" in p ? templateStepRefs(p.template) : [];
|
|
4222
|
+
return [
|
|
4223
|
+
...prompt,
|
|
4224
|
+
...mapConfigStepRefs(a.input)
|
|
4225
|
+
];
|
|
3974
4226
|
}
|
|
4227
|
+
case "step":
|
|
4228
|
+
return mapConfigStepRefs(entry.input);
|
|
3975
4229
|
case "tool":
|
|
3976
4230
|
return mapConfigStepRefs(entry.input);
|
|
3977
4231
|
case "workflow":
|
|
@@ -4188,6 +4442,21 @@ function validateLuaExtensions(g, caps = WORKFLOW_CAPS_DEFAULT, opts = {
|
|
|
4188
4442
|
err("job-tier-provider-unsupported", `model provider '${provider}' is outside LUA_WF_JOB_PROVIDERS [${opts.policy.jobProviders.join(", ")}]`, `${path25}.model`, id);
|
|
4189
4443
|
}
|
|
4190
4444
|
}, "checkTier");
|
|
4445
|
+
const checkModel = /* @__PURE__ */ __name3((node, path25) => {
|
|
4446
|
+
if (node.type !== "agent" || typeof node.model !== "string") return;
|
|
4447
|
+
const registry = opts.approvedModels;
|
|
4448
|
+
if (registry === void 0) return;
|
|
4449
|
+
const id = singleId(node);
|
|
4450
|
+
if (registry === "unavailable") {
|
|
4451
|
+
const pin = node.model.trim();
|
|
4452
|
+
if (pin && !normalizeModelId(pin, []).ok) {
|
|
4453
|
+
warn("model-unresolved", `model "${pin}" could not be checked against the approved-model registry (unavailable at push) \u2014 it dispatches only if it resolves there (a provider/model registry code, or a bare id exactly one approved model carries)`, `${path25}.model`, id);
|
|
4454
|
+
}
|
|
4455
|
+
return;
|
|
4456
|
+
}
|
|
4457
|
+
const resolved = normalizeModelId(node.model, registry);
|
|
4458
|
+
if (!resolved.ok) err("model-unresolved", modelUnresolvedMessage(resolved), `${path25}.model`, id);
|
|
4459
|
+
}, "checkModel");
|
|
4191
4460
|
const checkWorkspace = /* @__PURE__ */ __name3((node, path25) => {
|
|
4192
4461
|
const id = singleId(node);
|
|
4193
4462
|
const ws = workspaceOf(node);
|
|
@@ -4240,38 +4509,29 @@ function validateLuaExtensions(g, caps = WORKFLOW_CAPS_DEFAULT, opts = {
|
|
|
4240
4509
|
}
|
|
4241
4510
|
}, "checkMapMembers");
|
|
4242
4511
|
const checkInputShape = /* @__PURE__ */ __name3((node, path25) => {
|
|
4243
|
-
if (node.type !== "tool" && node.type !== "workflow") return;
|
|
4244
4512
|
const input = node.input;
|
|
4245
4513
|
if (input === void 0) return;
|
|
4514
|
+
const id = singleId(node);
|
|
4246
4515
|
if (input !== null && typeof input === "object" && !Array.isArray(input)) {
|
|
4247
|
-
checkMapMembers(input, `${path25}.input`,
|
|
4516
|
+
checkMapMembers(input, `${path25}.input`, id);
|
|
4248
4517
|
return;
|
|
4249
4518
|
}
|
|
4250
|
-
err("invalid-envelope", `\`input\` must be an object map \u2014 each member a binding descriptor ({initData:true, path} | {step, path} | {value} | {template} | {requestContextPath}) or a JSON literal (got ${JSON.stringify(input)})`, `${path25}.input`,
|
|
4519
|
+
err("invalid-envelope", `\`input\` must be an object map \u2014 each member a binding descriptor ({initData:true, path} | {step, path} | {value} | {template} | {requestContextPath}) or a JSON literal (got ${JSON.stringify(input)})`, `${path25}.input`, id);
|
|
4251
4520
|
}, "checkInputShape");
|
|
4521
|
+
const checkBodyInput = /* @__PURE__ */ __name3((body, path25, container) => {
|
|
4522
|
+
if (body.type === "workflow" || body.input === void 0) return;
|
|
4523
|
+
err("arm-input-unsupported", container === "foreach" ? `a foreach body receives each item as its input \u2014 drop \`input\` on "${singleId(body)}" and map the items before the foreach instead` : `a loop body receives the previous output as its input \u2014 drop \`input\` on "${singleId(body)}" and put the map before the loop instead`, `${path25}.input`, singleId(body));
|
|
4524
|
+
}, "checkBodyInput");
|
|
4252
4525
|
const checkSingle = /* @__PURE__ */ __name3((node, path25, depth) => {
|
|
4253
4526
|
recordOutputSchema(node);
|
|
4254
|
-
if (node.type === "workflow" && node.workflowId ===
|
|
4527
|
+
if (node.type === "workflow" && (typeof node.workflowId !== "string" || node.workflowId.length === 0)) {
|
|
4255
4528
|
checkId(node.id, path25);
|
|
4256
|
-
|
|
4257
|
-
|
|
4258
|
-
|
|
4259
|
-
|
|
4260
|
-
|
|
4261
|
-
|
|
4262
|
-
err("container-arm-empty", "a bare mapping arm has nothing to run", `${path25}.graph.1`, node.id);
|
|
4263
|
-
return;
|
|
4264
|
-
}
|
|
4265
|
-
const inner = body[1];
|
|
4266
|
-
if (isHitlNode(inner)) {
|
|
4267
|
-
err("node-type-unsupported-in-container", workflowHitlArmShapeMessage(inner.type, inner.id, "mapped-arm"), `${path25}.graph.1`, inner.id);
|
|
4268
|
-
return;
|
|
4269
|
-
}
|
|
4270
|
-
upstream.add(singleId(body[1]));
|
|
4271
|
-
checkArm(body[0], `${path25}.graph.0`, depth, "parallel");
|
|
4272
|
-
checkSingle(body[1], `${path25}.graph.1`, depth);
|
|
4273
|
-
upstream.add(body[0].id);
|
|
4274
|
-
upstream.add(singleId(body[1]));
|
|
4529
|
+
err("invalid-envelope", `\`workflowId\` must be a non-empty string naming the workflow to start (got ${JSON.stringify(node.workflowId)})`, `${path25}.workflowId`, node.id);
|
|
4530
|
+
return;
|
|
4531
|
+
}
|
|
4532
|
+
if (node.type === "workflow" && (node.workflowId.startsWith("$") || Array.isArray(node.graph))) {
|
|
4533
|
+
checkId(node.id, path25);
|
|
4534
|
+
err("node-type-unsupported-by-engine", armSubrunUnsupportedMessage(node.id, node.workflowId), path25, node.id);
|
|
4275
4535
|
return;
|
|
4276
4536
|
}
|
|
4277
4537
|
checkId(singleId(node), path25);
|
|
@@ -4279,6 +4539,7 @@ function validateLuaExtensions(g, caps = WORKFLOW_CAPS_DEFAULT, opts = {
|
|
|
4279
4539
|
checkInputShape(node, path25);
|
|
4280
4540
|
checkTimeout(node, path25);
|
|
4281
4541
|
checkTier(node, path25);
|
|
4542
|
+
checkModel(node, path25);
|
|
4282
4543
|
checkRetry(node, path25);
|
|
4283
4544
|
checkWorkspace(node, path25);
|
|
4284
4545
|
if (!opts.static) {
|
|
@@ -4301,7 +4562,7 @@ function validateLuaExtensions(g, caps = WORKFLOW_CAPS_DEFAULT, opts = {
|
|
|
4301
4562
|
if (node.type === "workflow" && node.kind === "subrun" && depth > caps.maxNestingDepth) {
|
|
4302
4563
|
err("cap-exceeded", `nesting depth ${depth} exceeds ${caps.maxNestingDepth}`, path25, node.id);
|
|
4303
4564
|
}
|
|
4304
|
-
if (node.type === "workflow" &&
|
|
4565
|
+
if (node.type === "workflow" && typeof g.definition?.id === "string" && node.workflowId === g.definition.id) {
|
|
4305
4566
|
err("subrun-cycle", `"${node.id}" starts "${node.workflowId}", which is this workflow itself`, path25, node.id);
|
|
4306
4567
|
}
|
|
4307
4568
|
for (const ref of nodeStepRefs(node)) {
|
|
@@ -4322,11 +4583,14 @@ function validateLuaExtensions(g, caps = WORKFLOW_CAPS_DEFAULT, opts = {
|
|
|
4322
4583
|
if (a.approver === "creator" && a.excludeInitiator === true) {
|
|
4323
4584
|
err("approver-excludes-only-candidate", "approver:'creator' with excludeInitiator:true always excludes the only candidate", path25, a.id);
|
|
4324
4585
|
}
|
|
4325
|
-
|
|
4586
|
+
const editable = approvalEditable(a);
|
|
4587
|
+
if (a.fourEyes !== void 0 && !editable) {
|
|
4326
4588
|
err("four-eyes-requires-editable", "`fourEyes` requires editable:true", `${path25}.fourEyes`, a.id);
|
|
4327
4589
|
}
|
|
4328
|
-
if (
|
|
4329
|
-
err("editable-path-invalid", "`editablePaths`
|
|
4590
|
+
if (a.editable === false && Array.isArray(a.editablePaths) && a.editablePaths.length > 0) {
|
|
4591
|
+
err("editable-path-invalid", "`editablePaths` beside editable:false is contradictory \u2014 drop the paths or set editable:true", `${path25}.editablePaths`, a.id);
|
|
4592
|
+
} else if ((a.editablePaths !== void 0 || a.editedPayloadSchema !== void 0) && !editable) {
|
|
4593
|
+
err("editable-path-invalid", "`editablePaths` / `editedPayloadSchema` require editable:true (a non-empty editablePaths implies it)", `${path25}.editablePaths`, a.id);
|
|
4330
4594
|
}
|
|
4331
4595
|
for (const p of a.editablePaths ?? []) {
|
|
4332
4596
|
if (!EDITABLE_PATH_RE.test(p)) err("editable-path-invalid", `editablePaths entry "${p}" is outside the seg(.seg)*[*]/[n] grammar`, `${path25}.editablePaths`, a.id);
|
|
@@ -4507,6 +4771,7 @@ function validateLuaExtensions(g, caps = WORKFLOW_CAPS_DEFAULT, opts = {
|
|
|
4507
4771
|
} else checkHitlArm(f.step, `${path25}.step`, "foreach");
|
|
4508
4772
|
declared.push(f.step.id);
|
|
4509
4773
|
} else {
|
|
4774
|
+
checkBodyInput(f.step, `${path25}.step`, "foreach");
|
|
4510
4775
|
checkSingle(f.step, `${path25}.step`, o.chunk ? 2 : 1);
|
|
4511
4776
|
declared.push(singleId(f.step));
|
|
4512
4777
|
}
|
|
@@ -4527,6 +4792,7 @@ function validateLuaExtensions(g, caps = WORKFLOW_CAPS_DEFAULT, opts = {
|
|
|
4527
4792
|
checkHitlArm(l.step, `${path25}.step`, "loop");
|
|
4528
4793
|
declared.push(l.step.id);
|
|
4529
4794
|
} else {
|
|
4795
|
+
checkBodyInput(l.step, `${path25}.step`, "loop");
|
|
4530
4796
|
checkSingle(l.step, `${path25}.step`, 1);
|
|
4531
4797
|
declared.push(singleId(l.step));
|
|
4532
4798
|
}
|
|
@@ -5000,17 +5266,10 @@ function isContinuedFailureValue(v) {
|
|
|
5000
5266
|
const err = o.error;
|
|
5001
5267
|
return o.__lua_workflow === CONTINUED_FAILURE_TAG && o.failed === true && o.text === "" && err !== null && typeof err === "object" && typeof err.code === "string" && typeof err.message === "string";
|
|
5002
5268
|
}
|
|
5003
|
-
function
|
|
5004
|
-
const stepId = nodeIdOf(step22);
|
|
5269
|
+
function inlineContainerArm(mapping, step22) {
|
|
5005
5270
|
return {
|
|
5006
|
-
|
|
5007
|
-
|
|
5008
|
-
workflowId: WORKFLOW_ARM_SUBRUN_ID,
|
|
5009
|
-
kind: "subrun",
|
|
5010
|
-
graph: [
|
|
5011
|
-
mapping,
|
|
5012
|
-
step22
|
|
5013
|
-
]
|
|
5271
|
+
...step22,
|
|
5272
|
+
input: parseMapConfig(mapping.mapConfig, mapping.id)
|
|
5014
5273
|
};
|
|
5015
5274
|
}
|
|
5016
5275
|
function entryIds(entry) {
|
|
@@ -5080,6 +5339,27 @@ function resolvePlacements(calls) {
|
|
|
5080
5339
|
break;
|
|
5081
5340
|
}
|
|
5082
5341
|
});
|
|
5342
|
+
const armMapPlacementIssue = /* @__PURE__ */ __name3((node, ref, i, container) => {
|
|
5343
|
+
if (!ref.armMap || node.type === "mapping" || isHitlNode2(node)) return void 0;
|
|
5344
|
+
const id = nodeIdOf(node);
|
|
5345
|
+
if ((container === "foreach" || container === "loop") && node.type !== "workflow") {
|
|
5346
|
+
return {
|
|
5347
|
+
code: "mapping-placement",
|
|
5348
|
+
message: container === "foreach" ? `foreach body "${id}": a [map, step] body is not supported \u2014 the body receives each item as its input; map the items before the foreach instead (foreach(step, { items: \u2026 }) or a .map() before it)` : `loop body "${id}": a [map, step] body is not supported \u2014 the body receives the previous output as its input; put the .map() before the loop instead`,
|
|
5349
|
+
callIndex: i,
|
|
5350
|
+
stepId: id
|
|
5351
|
+
};
|
|
5352
|
+
}
|
|
5353
|
+
if (node.input !== void 0) {
|
|
5354
|
+
return {
|
|
5355
|
+
code: "mapping-placement",
|
|
5356
|
+
message: `"${id}": the [map, step] arm mapping and the node's own input map would both bind its input \u2014 keep one (drop the arm map, or the \`input\` on the declaration)`,
|
|
5357
|
+
callIndex: i,
|
|
5358
|
+
stepId: id
|
|
5359
|
+
};
|
|
5360
|
+
}
|
|
5361
|
+
return void 0;
|
|
5362
|
+
}, "armMapPlacementIssue");
|
|
5083
5363
|
const hitlPlacementIssue = /* @__PURE__ */ __name3((node, ref, i, container) => {
|
|
5084
5364
|
if (!isHitlNode2(node)) return void 0;
|
|
5085
5365
|
const id = node.id;
|
|
@@ -5106,7 +5386,7 @@ function resolvePlacements(calls) {
|
|
|
5106
5386
|
if (ref.node.type === "mapping" && !allowMapping) {
|
|
5107
5387
|
issues.push({
|
|
5108
5388
|
code: "mapping-placement",
|
|
5109
|
-
message: `mapping "${ref.node.id}" cannot be a container arm \u2014 chain it as [map, step]`,
|
|
5389
|
+
message: `mapping "${ref.node.id}" cannot be a container arm \u2014 chain it as [map, step] in a parallel / conditional arm, or place the .map() before the container`,
|
|
5110
5390
|
callIndex: i,
|
|
5111
5391
|
stepId: ref.node.id
|
|
5112
5392
|
});
|
|
@@ -5127,7 +5407,7 @@ function resolvePlacements(calls) {
|
|
|
5127
5407
|
if (d.node.type === "mapping" && !allowMapping) {
|
|
5128
5408
|
issues.push({
|
|
5129
5409
|
code: "mapping-placement",
|
|
5130
|
-
message: `map "${ref.ref}" cannot be a parallel/foreach/loop arm \u2014 chain it as [map, step]`,
|
|
5410
|
+
message: `map "${ref.ref}" cannot be a parallel/foreach/loop arm \u2014 chain it as [map, step] in a parallel arm, or place the .map() before the container`,
|
|
5131
5411
|
callIndex: i,
|
|
5132
5412
|
stepId: ref.ref
|
|
5133
5413
|
});
|
|
@@ -5138,6 +5418,11 @@ function resolvePlacements(calls) {
|
|
|
5138
5418
|
issues.push(hitl);
|
|
5139
5419
|
return void 0;
|
|
5140
5420
|
}
|
|
5421
|
+
const mapped = armMapPlacementIssue(d.node, ref, i, container);
|
|
5422
|
+
if (mapped) {
|
|
5423
|
+
issues.push(mapped);
|
|
5424
|
+
return void 0;
|
|
5425
|
+
}
|
|
5141
5426
|
const prior = placedBy.get(ref.ref);
|
|
5142
5427
|
if (prior !== void 0 && prior !== i) {
|
|
5143
5428
|
issues.push({
|
|
@@ -5158,6 +5443,10 @@ function resolvePlacements(calls) {
|
|
|
5158
5443
|
}
|
|
5159
5444
|
const hitl = hitlPlacementIssue(ref.node, ref, i, container);
|
|
5160
5445
|
if (hitl) issues.push(hitl);
|
|
5446
|
+
else {
|
|
5447
|
+
const mapped = armMapPlacementIssue(ref.node, ref, i, container);
|
|
5448
|
+
if (mapped) issues.push(mapped);
|
|
5449
|
+
}
|
|
5161
5450
|
}, "claim");
|
|
5162
5451
|
calls.forEach((call, i) => {
|
|
5163
5452
|
switch (call.kind) {
|
|
@@ -5185,7 +5474,7 @@ function resolvePlacements(calls) {
|
|
|
5185
5474
|
const lookup = /* @__PURE__ */ __name3((ref) => {
|
|
5186
5475
|
const n2 = "node" in ref ? ref.node : declared.get(ref.ref)?.node;
|
|
5187
5476
|
if (!n2 || !ref.armMap || n2.type === "mapping" || isHitlNode2(n2)) return n2;
|
|
5188
|
-
return
|
|
5477
|
+
return inlineContainerArm(ref.armMap, n2);
|
|
5189
5478
|
}, "lookup");
|
|
5190
5479
|
calls.forEach((call, i) => {
|
|
5191
5480
|
switch (call.kind) {
|
|
@@ -5570,6 +5859,27 @@ function isTerminalRunStatus(status) {
|
|
|
5570
5859
|
function pruneUndefined(o) {
|
|
5571
5860
|
return Object.fromEntries(Object.entries(o).filter(([, v]) => v !== void 0));
|
|
5572
5861
|
}
|
|
5862
|
+
function runOrigin(run) {
|
|
5863
|
+
if (run.goalId) return "goal";
|
|
5864
|
+
if (run.jobId || run.trigger === "schedule") return "schedule";
|
|
5865
|
+
if (run.dynamic === true) return run.tags?.includes(WORKFLOW_INLINE_RUN_TAG) ? "inline" : "compose";
|
|
5866
|
+
return "definition";
|
|
5867
|
+
}
|
|
5868
|
+
function runErrorIssues(issues) {
|
|
5869
|
+
if (!Array.isArray(issues)) return void 0;
|
|
5870
|
+
const out = [];
|
|
5871
|
+
for (const raw of issues.slice(0, RUN_ERROR_ISSUES_MAX)) {
|
|
5872
|
+
if (!raw || typeof raw !== "object") continue;
|
|
5873
|
+
const o = raw;
|
|
5874
|
+
if (typeof o.code !== "string" || !o.code) continue;
|
|
5875
|
+
out.push(pruneUndefined({
|
|
5876
|
+
code: o.code,
|
|
5877
|
+
path: typeof o.path === "string" ? o.path : void 0,
|
|
5878
|
+
message: typeof o.message === "string" ? o.message : void 0
|
|
5879
|
+
}));
|
|
5880
|
+
}
|
|
5881
|
+
return out.length ? out : void 0;
|
|
5882
|
+
}
|
|
5573
5883
|
function runNextAction(run) {
|
|
5574
5884
|
if (isTerminalRunStatus(run.status)) return "none";
|
|
5575
5885
|
if (run.status === "suspended" && run.gate?.kind === "budget") return "raise_budget";
|
|
@@ -5739,6 +6049,7 @@ function toWorkflowRunSummary(run) {
|
|
|
5739
6049
|
repairOf: run.repairOf,
|
|
5740
6050
|
repairRunIds: run.repairRunIds,
|
|
5741
6051
|
trigger: run.trigger ?? "api",
|
|
6052
|
+
origin: runOrigin(run),
|
|
5742
6053
|
createdBy: {
|
|
5743
6054
|
subjectType: principal?.subjectType ?? "system",
|
|
5744
6055
|
subjectId: principal?.subjectId ?? run.userId ?? ""
|
|
@@ -5756,11 +6067,13 @@ function toWorkflowRunSummary(run) {
|
|
|
5756
6067
|
usage: runUsage(run),
|
|
5757
6068
|
// LUA-697: a row persisted before the write seams (#2406 / #2465 / the script tier) leaves scrubbed here too —
|
|
5758
6069
|
// idempotent on a scrubbed message, bounded input; an empty message falls back to the code.
|
|
5759
|
-
error: run.error ? {
|
|
6070
|
+
error: run.error ? pruneUndefined({
|
|
5760
6071
|
code: run.error.code ?? "error",
|
|
5761
6072
|
message: scrubStepErrorMessage(run.error.message) ?? run.error.code ?? "error",
|
|
5762
|
-
stepId: run.error.stepId
|
|
5763
|
-
|
|
6073
|
+
stepId: run.error.stepId,
|
|
6074
|
+
// LUA-784 (item 3): the unattended pre-start failure's refusal rows (`input_schema_invalid` and kin).
|
|
6075
|
+
issues: runErrorIssues(run.error.issues)
|
|
6076
|
+
}) : void 0,
|
|
5764
6077
|
kind: "run",
|
|
5765
6078
|
aclHash: run.aclHash,
|
|
5766
6079
|
migration: run.migration,
|
|
@@ -6283,124 +6596,6 @@ function rebaseItemPointer(pointer, itemsPath, index) {
|
|
|
6283
6596
|
const base = `/${itemsPath.split(".").map(escapePointer).join("/")}/${index}`;
|
|
6284
6597
|
return pointer === "/" || pointer === "" ? base : `${base}${pointer}`;
|
|
6285
6598
|
}
|
|
6286
|
-
function describeApproverSpecRefusal(spec) {
|
|
6287
|
-
const raw = spec === void 0 ? "undefined" : JSON.stringify(spec) ?? String(spec);
|
|
6288
|
-
const written = raw.length > APPROVER_WRITTEN_MAX ? `${raw.slice(0, APPROVER_WRITTEN_MAX - 1)}\u2026` : raw;
|
|
6289
|
-
const users = typeof spec === "object" && spec !== null ? spec.users : void 0;
|
|
6290
|
-
const approver = typeof users === "string" && USER_ID_SHAPED_RE.test(users) ? {
|
|
6291
|
-
users: [
|
|
6292
|
-
users
|
|
6293
|
-
]
|
|
6294
|
-
} : "creator";
|
|
6295
|
-
const message = `approver ${written} is not an approver \u2014 legal: ${APPROVER_SPEC_SHAPES.join(" | ")}. 'creator' is the person who started the run: write approver:'creator' for "ask me" / "I approve"; {users:[\u2026]} takes user ids, never emails, names or {type:'user'}` + (approver === "creator" ? "" : `; here: approver:${JSON.stringify(approver)}`);
|
|
6296
|
-
return {
|
|
6297
|
-
approver,
|
|
6298
|
-
written,
|
|
6299
|
-
message
|
|
6300
|
-
};
|
|
6301
|
-
}
|
|
6302
|
-
function bindingRootsOk(template22) {
|
|
6303
|
-
const refs = [
|
|
6304
|
-
...template22.matchAll(/\$\{\s*([A-Za-z_$][\w$]*)/g)
|
|
6305
|
-
].map((m) => m[1]);
|
|
6306
|
-
return refs.length > 0 && refs.every((r) => BINDING_ROOTS.includes(r));
|
|
6307
|
-
}
|
|
6308
|
-
function isTemplateBinding(v) {
|
|
6309
|
-
return typeof v === "object" && v !== null && typeof v.template === "string";
|
|
6310
|
-
}
|
|
6311
|
-
function validateApproverBlock(node, opts = {
|
|
6312
|
-
path: "approval"
|
|
6313
|
-
}) {
|
|
6314
|
-
const issues = [];
|
|
6315
|
-
const push = /* @__PURE__ */ __name3((code, path25, message, severity = "error") => issues.push({
|
|
6316
|
-
code,
|
|
6317
|
-
path: path25,
|
|
6318
|
-
severity,
|
|
6319
|
-
message
|
|
6320
|
-
}), "push");
|
|
6321
|
-
const checkSpec = /* @__PURE__ */ __name3((spec, path25) => {
|
|
6322
|
-
const r = ApproverSpecSchema.safeParse(spec);
|
|
6323
|
-
if (!r.success) {
|
|
6324
|
-
const users = spec?.users;
|
|
6325
|
-
if (Array.isArray(users) && users.length > APPROVER_SPEC_MAX_USERS) push("cap-exceeded", path25, `at most ${APPROVER_SPEC_MAX_USERS} users`);
|
|
6326
|
-
else {
|
|
6327
|
-
const refusal = describeApproverSpecRefusal(spec);
|
|
6328
|
-
issues.push({
|
|
6329
|
-
code: "approver-invalid",
|
|
6330
|
-
path: path25,
|
|
6331
|
-
severity: "error",
|
|
6332
|
-
message: refusal.message,
|
|
6333
|
-
repair: {
|
|
6334
|
-
approver: refusal.approver,
|
|
6335
|
-
written: refusal.written
|
|
6336
|
-
}
|
|
6337
|
-
});
|
|
6338
|
-
}
|
|
6339
|
-
return;
|
|
6340
|
-
}
|
|
6341
|
-
const s = r.data;
|
|
6342
|
-
if (typeof s === "object") {
|
|
6343
|
-
if ("governance" in s && !opts.governanceEnabled) push("approver-governance-unavailable", path25, "governance reviewer routing is not enabled for this deployment");
|
|
6344
|
-
if ("group" in s && typeof s.group === "string" && !opts.scimEnabled && opts.idpGroups?.includes(s.group)) push("approver-idp-group-unavailable", path25, "IdP-group approvers are not enabled for this deployment");
|
|
6345
|
-
const binding = "users" in s ? s.users : "role" in s ? s.role : "group" in s ? s.group : void 0;
|
|
6346
|
-
if (isTemplateBinding(binding)) {
|
|
6347
|
-
if (!bindingRootsOk(binding.template)) push("approver-binding-invalid", `${path25}.template`, "binding root must be initData / stepResults / requestContext / state");
|
|
6348
|
-
if ("users" in s && opts.customerReachable) push("approver-binding-customer-reachable", `${path25}.users`, "a customer-reachable workflow may not bind its approver list");
|
|
6349
|
-
}
|
|
6350
|
-
}
|
|
6351
|
-
}, "checkSpec");
|
|
6352
|
-
if (node.approver !== void 0) checkSpec(node.approver, `${opts.path}.approver`);
|
|
6353
|
-
if (node.fourEyes !== void 0) {
|
|
6354
|
-
const r = FourEyesSchema.safeParse(node.fourEyes);
|
|
6355
|
-
if (!r.success) push("approver-invalid", `${opts.path}.fourEyes`, "fourEyes needs { edit, approve } approver specs");
|
|
6356
|
-
else {
|
|
6357
|
-
checkSpec(r.data.edit, `${opts.path}.fourEyes.edit`);
|
|
6358
|
-
checkSpec(r.data.approve, `${opts.path}.fourEyes.approve`);
|
|
6359
|
-
}
|
|
6360
|
-
if (!node.editable) push("four-eyes-requires-editable", `${opts.path}.fourEyes`, "fourEyes requires editable:true");
|
|
6361
|
-
if (node.approver !== void 0) push("four-eyes-overrides-approver", `${opts.path}.approver`, "fourEyes replaces approver", "warning");
|
|
6362
|
-
if (node.itemsPath) push("four-eyes-items-unsupported", `${opts.path}.fourEyes`, "fourEyes cannot combine with itemsPath");
|
|
6363
|
-
}
|
|
6364
|
-
if (node.excludeInitiator && (node.approver === void 0 || node.approver === "creator") && !node.fourEyes) push("approver-excludes-only-candidate", `${opts.path}.excludeInitiator`, "'creator' with excludeInitiator leaves no approver");
|
|
6365
|
-
if (Array.isArray(node.onTimeout)) {
|
|
6366
|
-
const chain = node.onTimeout;
|
|
6367
|
-
const hops = chain.filter((m) => typeof m === "object" && m !== null && "escalateTo" in m);
|
|
6368
|
-
if (hops.length > ESCALATION_MAX_HOPS) push("escalation-chain-too-long", `${opts.path}.onTimeout`, `at most ${ESCALATION_MAX_HOPS} hops`);
|
|
6369
|
-
const last = chain[chain.length - 1];
|
|
6370
|
-
if (typeof last === "object" && last !== null) push("escalation-chain-not-terminal", `${opts.path}.onTimeout`, "a chain must end in deny | cancel-run | fail");
|
|
6371
|
-
hops.forEach((h, i) => checkSpec(h.escalateTo, `${opts.path}.onTimeout[${i}].escalateTo`));
|
|
6372
|
-
} else if (typeof node.onTimeout === "object" && node.onTimeout !== null) {
|
|
6373
|
-
checkSpec(node.onTimeout.escalateTo, `${opts.path}.onTimeout.escalateTo`);
|
|
6374
|
-
}
|
|
6375
|
-
return issues;
|
|
6376
|
-
}
|
|
6377
|
-
function liftRenderedApprover(row2, rendered) {
|
|
6378
|
-
const text = (rendered ?? "").trim();
|
|
6379
|
-
if (!text) return null;
|
|
6380
|
-
if (row2 === "users") {
|
|
6381
|
-
let members = null;
|
|
6382
|
-
if (text.startsWith("[")) {
|
|
6383
|
-
try {
|
|
6384
|
-
members = JSON.parse(text);
|
|
6385
|
-
} catch {
|
|
6386
|
-
return null;
|
|
6387
|
-
}
|
|
6388
|
-
} else members = text.split(",").map((s) => s.trim());
|
|
6389
|
-
if (!Array.isArray(members) || members.length === 0 || members.length > APPROVER_SPEC_MAX_USERS) return null;
|
|
6390
|
-
if (!members.every((m) => typeof m === "string" && m.length > 0 && m.length <= 128)) return null;
|
|
6391
|
-
return {
|
|
6392
|
-
users: [
|
|
6393
|
-
...new Set(members)
|
|
6394
|
-
].sort()
|
|
6395
|
-
};
|
|
6396
|
-
}
|
|
6397
|
-
if (text.length > 128 || text.startsWith("[") || text.startsWith("{")) return null;
|
|
6398
|
-
return row2 === "role" ? {
|
|
6399
|
-
role: text
|
|
6400
|
-
} : {
|
|
6401
|
-
group: text
|
|
6402
|
-
};
|
|
6403
|
-
}
|
|
6404
6599
|
function collectEnvTemplateKeys(value22) {
|
|
6405
6600
|
const keys = /* @__PURE__ */ new Set();
|
|
6406
6601
|
const walk22 = /* @__PURE__ */ __name3((v) => {
|
|
@@ -6649,7 +6844,6 @@ function* singleStepsOf(entry) {
|
|
|
6649
6844
|
return;
|
|
6650
6845
|
case "workflow":
|
|
6651
6846
|
yield entry;
|
|
6652
|
-
if (Array.isArray(entry.graph)) yield* singleStepsOf(entry.graph[1]);
|
|
6653
6847
|
return;
|
|
6654
6848
|
case "parallel":
|
|
6655
6849
|
case "conditional":
|
|
@@ -6691,7 +6885,7 @@ function needsInheritedWorkspace(graph) {
|
|
|
6691
6885
|
}
|
|
6692
6886
|
return false;
|
|
6693
6887
|
}
|
|
6694
|
-
var __defProp3, __name3, WorkflowTemplateError, TEMPLATE_PLACEHOLDER, TEMPLATE_NAMESPACES, MAP_DESCRIPTOR_KEYS, MAP_MEMBER_MALFORMED_CODE, fromInit, fromStep, value, template, fromRequest, rows, fromKnowledge, SideEffectsSchema, JobResourcesSchema,
|
|
6888
|
+
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;
|
|
6695
6889
|
var init_dist2 = __esm({
|
|
6696
6890
|
"../workflow-graph/dist/index.mjs"() {
|
|
6697
6891
|
"use strict";
|
|
@@ -6794,7 +6988,88 @@ var init_dist2 = __esm({
|
|
|
6794
6988
|
}), "fromKnowledge");
|
|
6795
6989
|
SideEffectsSchema = z6.enum(WORKFLOW_SIDE_EFFECTS);
|
|
6796
6990
|
JobResourcesSchema = z6.enum(WORKFLOW_JOB_RESOURCES);
|
|
6797
|
-
|
|
6991
|
+
APPROVER_SPEC_MAX_USERS = 20;
|
|
6992
|
+
ESCALATION_MAX_HOPS = 3;
|
|
6993
|
+
TemplateBindingSchema = z22.object({
|
|
6994
|
+
template: z22.string().min(1).max(2048)
|
|
6995
|
+
}).strict();
|
|
6996
|
+
ApproverSpecSchema = z22.union([
|
|
6997
|
+
z22.literal("creator"),
|
|
6998
|
+
z22.literal("org-admins"),
|
|
6999
|
+
z22.object({
|
|
7000
|
+
users: z22.union([
|
|
7001
|
+
z22.array(z22.string().min(1).max(128)).min(1).max(APPROVER_SPEC_MAX_USERS),
|
|
7002
|
+
TemplateBindingSchema
|
|
7003
|
+
])
|
|
7004
|
+
}).strict(),
|
|
7005
|
+
z22.object({
|
|
7006
|
+
role: z22.union([
|
|
7007
|
+
z22.string().min(1).max(128),
|
|
7008
|
+
TemplateBindingSchema
|
|
7009
|
+
])
|
|
7010
|
+
}).strict(),
|
|
7011
|
+
z22.object({
|
|
7012
|
+
group: z22.union([
|
|
7013
|
+
z22.string().min(1).max(128),
|
|
7014
|
+
TemplateBindingSchema
|
|
7015
|
+
])
|
|
7016
|
+
}).strict(),
|
|
7017
|
+
z22.object({
|
|
7018
|
+
governance: z22.object({
|
|
7019
|
+
policyId: z22.string().min(1).max(128)
|
|
7020
|
+
}).strict()
|
|
7021
|
+
}).strict()
|
|
7022
|
+
]);
|
|
7023
|
+
FourEyesSchema = z22.object({
|
|
7024
|
+
edit: ApproverSpecSchema,
|
|
7025
|
+
approve: ApproverSpecSchema
|
|
7026
|
+
}).strict();
|
|
7027
|
+
EscalationHopSchema = z22.object({
|
|
7028
|
+
escalateTo: ApproverSpecSchema,
|
|
7029
|
+
timeoutHours: z22.number().finite().min(1).max(720)
|
|
7030
|
+
}).strict();
|
|
7031
|
+
TerminalOutcomeSchema = z22.enum([
|
|
7032
|
+
"deny",
|
|
7033
|
+
"cancel-run",
|
|
7034
|
+
"fail",
|
|
7035
|
+
"continue"
|
|
7036
|
+
]);
|
|
7037
|
+
ApprovalOnTimeoutSchema = z22.union([
|
|
7038
|
+
TerminalOutcomeSchema,
|
|
7039
|
+
EscalationHopSchema,
|
|
7040
|
+
z22.array(z22.union([
|
|
7041
|
+
TerminalOutcomeSchema,
|
|
7042
|
+
EscalationHopSchema
|
|
7043
|
+
])).min(1).max(ESCALATION_MAX_HOPS + 1)
|
|
7044
|
+
]);
|
|
7045
|
+
APPROVER_SPEC_SHAPES = [
|
|
7046
|
+
"'creator'",
|
|
7047
|
+
"'org-admins'",
|
|
7048
|
+
"{users:[userId, \u2026]}",
|
|
7049
|
+
"{role:roleName}",
|
|
7050
|
+
"{group:groupName}",
|
|
7051
|
+
"{governance:{policyId}}"
|
|
7052
|
+
];
|
|
7053
|
+
APPROVER_WRITTEN_MAX = 120;
|
|
7054
|
+
USER_ID_SHAPED_RE = /^[^\s@]{1,128}$/;
|
|
7055
|
+
__name(describeApproverSpecRefusal, "describeApproverSpecRefusal");
|
|
7056
|
+
__name3(describeApproverSpecRefusal, "describeApproverSpecRefusal");
|
|
7057
|
+
BINDING_ROOTS = [
|
|
7058
|
+
"initData",
|
|
7059
|
+
"stepResults",
|
|
7060
|
+
"requestContext",
|
|
7061
|
+
"state"
|
|
7062
|
+
];
|
|
7063
|
+
__name(bindingRootsOk, "bindingRootsOk");
|
|
7064
|
+
__name3(bindingRootsOk, "bindingRootsOk");
|
|
7065
|
+
__name(isTemplateBinding, "isTemplateBinding");
|
|
7066
|
+
__name3(isTemplateBinding, "isTemplateBinding");
|
|
7067
|
+
__name(approvalEditable, "approvalEditable");
|
|
7068
|
+
__name3(approvalEditable, "approvalEditable");
|
|
7069
|
+
__name(validateApproverBlock, "validateApproverBlock");
|
|
7070
|
+
__name3(validateApproverBlock, "validateApproverBlock");
|
|
7071
|
+
__name(liftRenderedApprover, "liftRenderedApprover");
|
|
7072
|
+
__name3(liftRenderedApprover, "liftRenderedApprover");
|
|
6798
7073
|
WORKSPACE_TEMPLATE_EXPR_RE = /^\$\{\s*(?:initData|input)\.([^}]+?)\s*\}$/;
|
|
6799
7074
|
__name(workspaceTemplatePath, "workspaceTemplatePath");
|
|
6800
7075
|
__name3(workspaceTemplatePath, "workspaceTemplatePath");
|
|
@@ -6806,6 +7081,8 @@ var init_dist2 = __esm({
|
|
|
6806
7081
|
});
|
|
6807
7082
|
__name(sleepUntilUnsupportedMessage, "sleepUntilUnsupportedMessage");
|
|
6808
7083
|
__name3(sleepUntilUnsupportedMessage, "sleepUntilUnsupportedMessage");
|
|
7084
|
+
__name(armSubrunUnsupportedMessage, "armSubrunUnsupportedMessage");
|
|
7085
|
+
__name3(armSubrunUnsupportedMessage, "armSubrunUnsupportedMessage");
|
|
6809
7086
|
WORKFLOW_CAPS_DEFAULT = Object.freeze({
|
|
6810
7087
|
maxParallelArms: 16,
|
|
6811
7088
|
maxForeachConcurrency: 16,
|
|
@@ -7087,8 +7364,8 @@ var init_dist2 = __esm({
|
|
|
7087
7364
|
__name(isContinuedFailureValue, "isContinuedFailureValue");
|
|
7088
7365
|
__name3(isContinuedFailureValue, "isContinuedFailureValue");
|
|
7089
7366
|
isHitlNode2 = /* @__PURE__ */ __name3((n2) => isWorkflowHitlEntryType(n2.type), "isHitlNode");
|
|
7090
|
-
__name(
|
|
7091
|
-
__name3(
|
|
7367
|
+
__name(inlineContainerArm, "inlineContainerArm");
|
|
7368
|
+
__name3(inlineContainerArm, "inlineContainerArm");
|
|
7092
7369
|
nodeIdOf = /* @__PURE__ */ __name3((n2) => n2.type === "step" ? n2.step.id : n2.id, "nodeIdOf");
|
|
7093
7370
|
__name(entryIds, "entryIds");
|
|
7094
7371
|
__name3(entryIds, "entryIds");
|
|
@@ -7148,6 +7425,12 @@ var init_dist2 = __esm({
|
|
|
7148
7425
|
__name3(isTerminalRunStatus, "isTerminalRunStatus");
|
|
7149
7426
|
__name(pruneUndefined, "pruneUndefined");
|
|
7150
7427
|
__name3(pruneUndefined, "pruneUndefined");
|
|
7428
|
+
WORKFLOW_INLINE_RUN_TAG = "inline";
|
|
7429
|
+
__name(runOrigin, "runOrigin");
|
|
7430
|
+
__name3(runOrigin, "runOrigin");
|
|
7431
|
+
RUN_ERROR_ISSUES_MAX = 20;
|
|
7432
|
+
__name(runErrorIssues, "runErrorIssues");
|
|
7433
|
+
__name3(runErrorIssues, "runErrorIssues");
|
|
7151
7434
|
__name(runNextAction, "runNextAction");
|
|
7152
7435
|
__name3(runNextAction, "runNextAction");
|
|
7153
7436
|
IN_FLIGHT = new Set(WORKFLOW_STEP_IN_FLIGHT);
|
|
@@ -7308,86 +7591,6 @@ var init_dist2 = __esm({
|
|
|
7308
7591
|
__name3(applyJsonPatch, "applyJsonPatch");
|
|
7309
7592
|
__name(rebaseItemPointer, "rebaseItemPointer");
|
|
7310
7593
|
__name3(rebaseItemPointer, "rebaseItemPointer");
|
|
7311
|
-
APPROVER_SPEC_MAX_USERS = 20;
|
|
7312
|
-
ESCALATION_MAX_HOPS = 3;
|
|
7313
|
-
TemplateBindingSchema = z22.object({
|
|
7314
|
-
template: z22.string().min(1).max(2048)
|
|
7315
|
-
}).strict();
|
|
7316
|
-
ApproverSpecSchema = z22.union([
|
|
7317
|
-
z22.literal("creator"),
|
|
7318
|
-
z22.literal("org-admins"),
|
|
7319
|
-
z22.object({
|
|
7320
|
-
users: z22.union([
|
|
7321
|
-
z22.array(z22.string().min(1).max(128)).min(1).max(APPROVER_SPEC_MAX_USERS),
|
|
7322
|
-
TemplateBindingSchema
|
|
7323
|
-
])
|
|
7324
|
-
}).strict(),
|
|
7325
|
-
z22.object({
|
|
7326
|
-
role: z22.union([
|
|
7327
|
-
z22.string().min(1).max(128),
|
|
7328
|
-
TemplateBindingSchema
|
|
7329
|
-
])
|
|
7330
|
-
}).strict(),
|
|
7331
|
-
z22.object({
|
|
7332
|
-
group: z22.union([
|
|
7333
|
-
z22.string().min(1).max(128),
|
|
7334
|
-
TemplateBindingSchema
|
|
7335
|
-
])
|
|
7336
|
-
}).strict(),
|
|
7337
|
-
z22.object({
|
|
7338
|
-
governance: z22.object({
|
|
7339
|
-
policyId: z22.string().min(1).max(128)
|
|
7340
|
-
}).strict()
|
|
7341
|
-
}).strict()
|
|
7342
|
-
]);
|
|
7343
|
-
FourEyesSchema = z22.object({
|
|
7344
|
-
edit: ApproverSpecSchema,
|
|
7345
|
-
approve: ApproverSpecSchema
|
|
7346
|
-
}).strict();
|
|
7347
|
-
EscalationHopSchema = z22.object({
|
|
7348
|
-
escalateTo: ApproverSpecSchema,
|
|
7349
|
-
timeoutHours: z22.number().finite().min(1).max(720)
|
|
7350
|
-
}).strict();
|
|
7351
|
-
TerminalOutcomeSchema = z22.enum([
|
|
7352
|
-
"deny",
|
|
7353
|
-
"cancel-run",
|
|
7354
|
-
"fail",
|
|
7355
|
-
"continue"
|
|
7356
|
-
]);
|
|
7357
|
-
ApprovalOnTimeoutSchema = z22.union([
|
|
7358
|
-
TerminalOutcomeSchema,
|
|
7359
|
-
EscalationHopSchema,
|
|
7360
|
-
z22.array(z22.union([
|
|
7361
|
-
TerminalOutcomeSchema,
|
|
7362
|
-
EscalationHopSchema
|
|
7363
|
-
])).min(1).max(ESCALATION_MAX_HOPS + 1)
|
|
7364
|
-
]);
|
|
7365
|
-
APPROVER_SPEC_SHAPES = [
|
|
7366
|
-
"'creator'",
|
|
7367
|
-
"'org-admins'",
|
|
7368
|
-
"{users:[userId, \u2026]}",
|
|
7369
|
-
"{role:roleName}",
|
|
7370
|
-
"{group:groupName}",
|
|
7371
|
-
"{governance:{policyId}}"
|
|
7372
|
-
];
|
|
7373
|
-
APPROVER_WRITTEN_MAX = 120;
|
|
7374
|
-
USER_ID_SHAPED_RE = /^[^\s@]{1,128}$/;
|
|
7375
|
-
__name(describeApproverSpecRefusal, "describeApproverSpecRefusal");
|
|
7376
|
-
__name3(describeApproverSpecRefusal, "describeApproverSpecRefusal");
|
|
7377
|
-
BINDING_ROOTS = [
|
|
7378
|
-
"initData",
|
|
7379
|
-
"stepResults",
|
|
7380
|
-
"requestContext",
|
|
7381
|
-
"state"
|
|
7382
|
-
];
|
|
7383
|
-
__name(bindingRootsOk, "bindingRootsOk");
|
|
7384
|
-
__name3(bindingRootsOk, "bindingRootsOk");
|
|
7385
|
-
__name(isTemplateBinding, "isTemplateBinding");
|
|
7386
|
-
__name3(isTemplateBinding, "isTemplateBinding");
|
|
7387
|
-
__name(validateApproverBlock, "validateApproverBlock");
|
|
7388
|
-
__name3(validateApproverBlock, "validateApproverBlock");
|
|
7389
|
-
__name(liftRenderedApprover, "liftRenderedApprover");
|
|
7390
|
-
__name3(liftRenderedApprover, "liftRenderedApprover");
|
|
7391
7594
|
WORKFLOW_ENV_OVERLAY_MAX_KEYS = 64;
|
|
7392
7595
|
WORKFLOW_ENV_OVERLAY_MAX_VALUE_BYTES = 4096;
|
|
7393
7596
|
WORKFLOW_ENV_TEMPLATE_SECRET_KEY_RE = /(SECRET|TOKEN|KEY|PASSWORD)$/;
|
|
@@ -7490,14 +7693,13 @@ function stepNodeOf(s) {
|
|
|
7490
7693
|
}
|
|
7491
7694
|
function materializeEntry(entry, steps) {
|
|
7492
7695
|
const single = /* @__PURE__ */ __name((n2) => {
|
|
7493
|
-
if (n2.type === "step" && steps[n2.step.id])
|
|
7494
|
-
|
|
7495
|
-
|
|
7496
|
-
|
|
7497
|
-
n2.
|
|
7498
|
-
|
|
7499
|
-
|
|
7500
|
-
};
|
|
7696
|
+
if (n2.type === "step" && steps[n2.step.id]) {
|
|
7697
|
+
const node = stepNodeOf(steps[n2.step.id]);
|
|
7698
|
+
return n2.input !== void 0 ? {
|
|
7699
|
+
...node,
|
|
7700
|
+
input: n2.input
|
|
7701
|
+
} : node;
|
|
7702
|
+
}
|
|
7501
7703
|
return n2;
|
|
7502
7704
|
}, "single");
|
|
7503
7705
|
switch (entry.type) {
|
|
@@ -7658,7 +7860,10 @@ var init_workflow = __esm({
|
|
|
7658
7860
|
}, "assertPredicate");
|
|
7659
7861
|
assertRetry = /* @__PURE__ */ __name((r, id) => {
|
|
7660
7862
|
if (!r) return;
|
|
7661
|
-
if (
|
|
7863
|
+
if (r.maxAttempts !== void 0 && !isWithinWorkflowRetryAttempts(r.maxAttempts)) {
|
|
7864
|
+
const over = typeof r.maxAttempts === "number" && r.maxAttempts > WORKFLOW_RETRY_MAX_ATTEMPTS;
|
|
7865
|
+
throw new LuaWorkflowBuildError(over ? "cap-exceeded" : "invalid-envelope", `"${id}": ${workflowRetryMaxAttemptsMessage(r.maxAttempts)}`);
|
|
7866
|
+
}
|
|
7662
7867
|
if (r.backoff !== void 0 && !WORKFLOW_RETRY_BACKOFFS.includes(r.backoff)) throw new LuaWorkflowBuildError("backoff-invalid", `"${id}": retry.backoff must be ${WORKFLOW_RETRY_BACKOFFS.map((b) => `'${b}'`).join(" | ")}`);
|
|
7663
7868
|
if (r.maxBackoffSeconds !== void 0) {
|
|
7664
7869
|
if (r.backoff !== "exponential") throw new LuaWorkflowBuildError("backoff-invalid", `"${id}": retry.maxBackoffSeconds is only meaningful with backoff:'exponential'`);
|
|
@@ -11790,6 +11995,17 @@ function resolveIdentifier(node, maxDepth = 10) {
|
|
|
11790
11995
|
}
|
|
11791
11996
|
return identNode;
|
|
11792
11997
|
}
|
|
11998
|
+
function unwrapExpression(node) {
|
|
11999
|
+
let cur = node;
|
|
12000
|
+
while (cur) {
|
|
12001
|
+
if (Node.isAsExpression(cur) || Node.isSatisfiesExpression(cur) || Node.isParenthesizedExpression(cur) || Node.isNonNullExpression(cur) || Node.isTypeAssertion(cur)) {
|
|
12002
|
+
cur = cur.getExpression();
|
|
12003
|
+
continue;
|
|
12004
|
+
}
|
|
12005
|
+
return cur;
|
|
12006
|
+
}
|
|
12007
|
+
return void 0;
|
|
12008
|
+
}
|
|
11793
12009
|
function findImportSource(identifier, sourceFile, resolveImportPath) {
|
|
11794
12010
|
for (const importDecl of sourceFile.getImportDeclarations()) {
|
|
11795
12011
|
const defaultImport = importDecl.getDefaultImport();
|
|
@@ -11824,6 +12040,7 @@ var init_ast_helpers = __esm({
|
|
|
11824
12040
|
__name(isFunction, "isFunction");
|
|
11825
12041
|
__name(getFunctionBody, "getFunctionBody");
|
|
11826
12042
|
__name(resolveIdentifier, "resolveIdentifier");
|
|
12043
|
+
__name(unwrapExpression, "unwrapExpression");
|
|
11827
12044
|
__name(findImportSource, "findImportSource");
|
|
11828
12045
|
}
|
|
11829
12046
|
});
|
|
@@ -12519,6 +12736,19 @@ var init_schema_converter = __esm({
|
|
|
12519
12736
|
|
|
12520
12737
|
// src/compiler/plugins/tool.plugin.ts
|
|
12521
12738
|
import { Node as Node4 } from "ts-morph";
|
|
12739
|
+
function isToolShapedLiteral(literal, typeAnnotation, initializerText) {
|
|
12740
|
+
if (!extractStringProperty(literal, "name")) return false;
|
|
12741
|
+
const execute = literal.getProperty("execute");
|
|
12742
|
+
if (!execute) return false;
|
|
12743
|
+
const executeIsCallable = Node4.isMethodDeclaration(execute) || Node4.isShorthandPropertyAssignment(execute) || Node4.isPropertyAssignment(execute) && (() => {
|
|
12744
|
+
const init3 = unwrapExpression(execute.getInitializer());
|
|
12745
|
+
return !!init3 && (Node4.isArrowFunction(init3) || Node4.isFunctionExpression(init3) || Node4.isIdentifier(init3) || Node4.isPropertyAccessExpression(init3) || Node4.isCallExpression(init3));
|
|
12746
|
+
})();
|
|
12747
|
+
if (!executeIsCallable) return false;
|
|
12748
|
+
if (literal.getProperty("description") || literal.getProperty("inputSchema")) return true;
|
|
12749
|
+
const annotated = /* @__PURE__ */ __name((text) => !!text && /\bLua(Voice)?Tool\b/.test(text), "annotated");
|
|
12750
|
+
return annotated(typeAnnotation) || annotated(initializerText);
|
|
12751
|
+
}
|
|
12522
12752
|
var ToolPlugin;
|
|
12523
12753
|
var init_tool_plugin = __esm({
|
|
12524
12754
|
"src/compiler/plugins/tool.plugin.ts"() {
|
|
@@ -12542,6 +12772,34 @@ var init_tool_plugin = __esm({
|
|
|
12542
12772
|
copyAllFields: true
|
|
12543
12773
|
};
|
|
12544
12774
|
supportsClassDefinition = true;
|
|
12775
|
+
/** The three call / class shapes, then (LUA-781) the object-literal shape for the identifiers they did not claim. */
|
|
12776
|
+
detect(sourceFile) {
|
|
12777
|
+
const primitives = super.detect(sourceFile);
|
|
12778
|
+
this.detectObjectLiterals(sourceFile, primitives);
|
|
12779
|
+
return primitives;
|
|
12780
|
+
}
|
|
12781
|
+
/**
|
|
12782
|
+
* LUA-781: `const t = { name: 'x', description, inputSchema, execute }` (any export form; the initializer may sit
|
|
12783
|
+
* under `as` / `satisfies` / parentheses). The export IS the tool object, exactly like a `defineTool({...})`
|
|
12784
|
+
* result, so it compiles as the `function` pattern: the entry point imports it and the runtime validation asserts
|
|
12785
|
+
* `execute`. A literal counts when it carries a string `name`, an `execute` member and — so a random
|
|
12786
|
+
* `{ name, execute }` registry entry is not mistaken for one — a `description`, an `inputSchema` or a `LuaTool`
|
|
12787
|
+
* type annotation (`const t: LuaTool = …`, `… as LuaTool`, `… satisfies LuaTool`).
|
|
12788
|
+
*/
|
|
12789
|
+
detectObjectLiterals(sourceFile, primitives) {
|
|
12790
|
+
const claimed = new Set(primitives.map((p) => p.exportName));
|
|
12791
|
+
for (const varDecl of sourceFile.getVariableDeclarations()) {
|
|
12792
|
+
const exportName = varDecl.getName();
|
|
12793
|
+
if (claimed.has(exportName)) continue;
|
|
12794
|
+
const initializer = varDecl.getInitializer();
|
|
12795
|
+
const literal = unwrapExpression(initializer);
|
|
12796
|
+
if (!literal || !Node4.isObjectLiteralExpression(literal)) continue;
|
|
12797
|
+
if (!isToolShapedLiteral(literal, varDecl.getTypeNode()?.getText(), initializer?.getText())) continue;
|
|
12798
|
+
const pos = sourceFile.getLineAndColumnAtPos(varDecl.getStart());
|
|
12799
|
+
const metadata = this.extractFromConfig(literal, exportName, sourceFile.getFilePath(), pos, "function");
|
|
12800
|
+
if (metadata) primitives.push(metadata);
|
|
12801
|
+
}
|
|
12802
|
+
}
|
|
12545
12803
|
/**
|
|
12546
12804
|
* Extract metadata from a `defineTool({...})` / `new LuaTool({...})`
|
|
12547
12805
|
* config object literal. (Class-definition shape is handled by the
|
|
@@ -12663,12 +12921,12 @@ var init_tool_plugin = __esm({
|
|
|
12663
12921
|
} else {
|
|
12664
12922
|
const varDecl = sourceFile.getVariableDeclaration(metadata.exportName);
|
|
12665
12923
|
if (!varDecl) return void 0;
|
|
12666
|
-
const initializer = varDecl.getInitializer();
|
|
12667
|
-
if (!initializer
|
|
12668
|
-
|
|
12669
|
-
if (
|
|
12670
|
-
|
|
12671
|
-
if (!Node4.isObjectLiteralExpression(config)) return void 0;
|
|
12924
|
+
const initializer = unwrapExpression(varDecl.getInitializer());
|
|
12925
|
+
if (!initializer) return void 0;
|
|
12926
|
+
let config;
|
|
12927
|
+
if (Node4.isObjectLiteralExpression(initializer)) config = initializer;
|
|
12928
|
+
else if (Node4.isCallExpression(initializer)) config = initializer.getArguments()[0];
|
|
12929
|
+
if (!config || !Node4.isObjectLiteralExpression(config)) return void 0;
|
|
12672
12930
|
schemaNode = extractSchemaProperty(config, "inputSchema");
|
|
12673
12931
|
}
|
|
12674
12932
|
if (!schemaNode) return void 0;
|
|
@@ -12693,6 +12951,7 @@ var init_tool_plugin = __esm({
|
|
|
12693
12951
|
};
|
|
12694
12952
|
}
|
|
12695
12953
|
};
|
|
12954
|
+
__name(isToolShapedLiteral, "isToolShapedLiteral");
|
|
12696
12955
|
}
|
|
12697
12956
|
});
|
|
12698
12957
|
|
|
@@ -19025,6 +19284,7 @@ function computeDeferred(graph, opts = {}) {
|
|
|
19025
19284
|
deferred.add("job-tier-disabled");
|
|
19026
19285
|
deferred.add("job-tier-provider-unsupported");
|
|
19027
19286
|
}
|
|
19287
|
+
if (n2.type === "agent" && typeof n2.model === "string" && !isModelIdSentinel(n2.model)) deferred.add("model-unresolved");
|
|
19028
19288
|
if (Array.isArray(n2.requiredConnections) && n2.requiredConnections.some(serverDecides)) deferred.add("required-connection-unknown");
|
|
19029
19289
|
if (n2.type === "approval") {
|
|
19030
19290
|
const a = n2.approver;
|
|
@@ -19287,22 +19547,24 @@ function collectSingleSteps(graph) {
|
|
|
19287
19547
|
}
|
|
19288
19548
|
function collectGraphIds(graph) {
|
|
19289
19549
|
const ids = [];
|
|
19290
|
-
const
|
|
19291
|
-
|
|
19292
|
-
const
|
|
19293
|
-
|
|
19294
|
-
|
|
19295
|
-
|
|
19296
|
-
|
|
19297
|
-
|
|
19298
|
-
|
|
19550
|
+
const visit = /* @__PURE__ */ __name((node) => {
|
|
19551
|
+
if (!node || typeof node !== "object" || Array.isArray(node)) return;
|
|
19552
|
+
const n2 = node;
|
|
19553
|
+
if (typeof n2.type !== "string") return;
|
|
19554
|
+
const own = n2.type === "step" ? n2.step?.id : n2.id;
|
|
19555
|
+
if (typeof own === "string") ids.push(own);
|
|
19556
|
+
for (const key of [
|
|
19557
|
+
"steps",
|
|
19558
|
+
"step",
|
|
19559
|
+
"otherwise",
|
|
19560
|
+
"graph"
|
|
19299
19561
|
]) {
|
|
19300
|
-
|
|
19301
|
-
|
|
19302
|
-
|
|
19303
|
-
}
|
|
19562
|
+
const child = n2[key];
|
|
19563
|
+
if (Array.isArray(child)) child.forEach(visit);
|
|
19564
|
+
else visit(child);
|
|
19304
19565
|
}
|
|
19305
|
-
}
|
|
19566
|
+
}, "visit");
|
|
19567
|
+
for (const entry of graph.definition.graph) visit(entry);
|
|
19306
19568
|
return ids;
|
|
19307
19569
|
}
|
|
19308
19570
|
function stripFunctions(v) {
|
|
@@ -19347,6 +19609,8 @@ var init_workflow_plugin = __esm({
|
|
|
19347
19609
|
STEP_EXECUTE_MISSING: "WORKFLOW_STEP_EXECUTE_MISSING",
|
|
19348
19610
|
UNPLACED_STEP: "WORKFLOW_UNPLACED_STEP",
|
|
19349
19611
|
TOOL_REF_UNRESOLVED: "WORKFLOW_TOOL_REF_UNRESOLVED",
|
|
19612
|
+
/** LUA-781: a tool node whose `toolId` names no compiled tool of the project — an ERROR; the push refuses it too. */
|
|
19613
|
+
TOOL_UNBUNDLED: "WORKFLOW_TOOL_UNBUNDLED",
|
|
19350
19614
|
NESTED_NOT_REGISTERED: "WORKFLOW_NESTED_NOT_REGISTERED",
|
|
19351
19615
|
SCHEMA_UNSUPPORTED: "WORKFLOW_SCHEMA_UNSUPPORTED",
|
|
19352
19616
|
SKETCH_TOPOLOGY: "WORKFLOW_SKETCH_TOPOLOGY",
|
|
@@ -19425,7 +19689,7 @@ var init_workflow_plugin = __esm({
|
|
|
19425
19689
|
for (const call of chain) {
|
|
19426
19690
|
const callee = call.getExpression();
|
|
19427
19691
|
if (Node18.isPropertyAccessExpression(callee) && callee.getName() === "toolStep") {
|
|
19428
|
-
const ref = call.getArguments()[1];
|
|
19692
|
+
const ref = unwrapExpression(call.getArguments()[1]);
|
|
19429
19693
|
if (ref && Node18.isIdentifier(ref)) toolRefIdentifiers.push(ref.getText());
|
|
19430
19694
|
}
|
|
19431
19695
|
}
|
|
@@ -19678,7 +19942,7 @@ ${firstBundleFrame(vmResult.error.stack)}` : ""}`,
|
|
|
19678
19942
|
if (!graphIds.has(id) && tier.topology !== "sketch") {
|
|
19679
19943
|
issues.push({
|
|
19680
19944
|
code: WORKFLOW_COMPILE_CODES.UNPLACED_STEP,
|
|
19681
|
-
message: `createStep "${id}" is declared in ${relative(rootDir, metadata.sourcePath)} but
|
|
19945
|
+
message: `createStep "${id}" is declared in ${relative(rootDir, metadata.sourcePath)} but placed in no workflow of the project (compiled with "${metadata.name}"; error at push \u2014 lua push workflow refuses the version: place it in a chain or delete the declaration)`,
|
|
19682
19946
|
severity: "warning",
|
|
19683
19947
|
stepId: id,
|
|
19684
19948
|
source: sources.get(id)
|
|
@@ -19739,6 +20003,26 @@ ${firstBundleFrame(vmResult.error.stack)}` : ""}`,
|
|
|
19739
20003
|
const workflows = compiled.filter((p) => p.kind === PrimitiveKind.WORKFLOW && p.graph);
|
|
19740
20004
|
const inheritTargets2 = new Set(workflows.flatMap((p) => p.graph?.inheritRefs ?? []));
|
|
19741
20005
|
for (const p of workflows) if (p.graph && inheritTargets2.has(p.name)) p.graph = applyInheritCandidate(p.graph);
|
|
20006
|
+
const placed = /* @__PURE__ */ new Set();
|
|
20007
|
+
for (const p of workflows) for (const id of collectGraphIds(p.graph.graph)) placed.add(id);
|
|
20008
|
+
for (const p of workflows) {
|
|
20009
|
+
if (!p.graph) continue;
|
|
20010
|
+
p.graph.issues = p.graph.issues.filter((i) => i.code !== WORKFLOW_COMPILE_CODES.UNPLACED_STEP || !i.stepId || !placed.has(i.stepId));
|
|
20011
|
+
}
|
|
20012
|
+
const bundledTools = new Set(compiled.filter((p) => p.kind === "tool").map((p) => p.name));
|
|
20013
|
+
for (const p of workflows) {
|
|
20014
|
+
if (!p.graph || p.graph.topology === "sketch") continue;
|
|
20015
|
+
for (const node of collectSingleSteps(p.graph.graph)) {
|
|
20016
|
+
if (node.type !== "tool" || bundledTools.has(node.toolId)) continue;
|
|
20017
|
+
p.graph.issues.push({
|
|
20018
|
+
code: WORKFLOW_COMPILE_CODES.TOOL_UNBUNDLED,
|
|
20019
|
+
message: `toolStep "${node.id}" references tool "${node.toolId}" but no compiled tool artifact of that name exists in this project \u2014 the version would push without it and every run would fail the step TOOL_REF_UNRESOLVED (not_in_version_bundle). Declare the tool where the compiler sees it (defineTool({ name: '${node.toolId}', \u2026 }), a class implementing LuaTool, or an exported { name, description, inputSchema, execute } object) and pass that export to toolStep()`,
|
|
20020
|
+
severity: "error",
|
|
20021
|
+
stepId: node.id,
|
|
20022
|
+
source: p.graph.stepMeta.find((m) => m.id === node.id)?.source
|
|
20023
|
+
});
|
|
20024
|
+
}
|
|
20025
|
+
}
|
|
19742
20026
|
const sketched = workflows.filter((p) => p.graph?.topology === "sketch").map((p) => p.name);
|
|
19743
20027
|
if (sketched.length === 0) return;
|
|
19744
20028
|
for (const p of workflows) {
|
|
@@ -19790,6 +20074,9 @@ ${firstBundleFrame(vmResult.error.stack)}` : ""}`,
|
|
|
19790
20074
|
output: d.graph.definition.outputSchema,
|
|
19791
20075
|
state: d.graph.definition.stateSchema
|
|
19792
20076
|
};
|
|
20077
|
+
const unplacedStepIds = [
|
|
20078
|
+
...new Set(d.issues.filter((i) => i.code === WORKFLOW_COMPILE_CODES.UNPLACED_STEP && typeof i.stepId === "string").map((i) => i.stepId))
|
|
20079
|
+
].sort();
|
|
19793
20080
|
const entry = {
|
|
19794
20081
|
...this.baseManifestFields(compiled),
|
|
19795
20082
|
kind: PrimitiveKind.WORKFLOW,
|
|
@@ -19805,6 +20092,7 @@ ${firstBundleFrame(vmResult.error.stack)}` : ""}`,
|
|
|
19805
20092
|
toolRefs,
|
|
19806
20093
|
workflowRefs: d.workflowRefs,
|
|
19807
20094
|
mayInherit: d.mayInherit,
|
|
20095
|
+
unplacedStepIds: unplacedStepIds.length > 0 ? unplacedStepIds : void 0,
|
|
19808
20096
|
budget: cfg.budget,
|
|
19809
20097
|
concurrencyPolicy: cfg.concurrencyPolicy,
|
|
19810
20098
|
schedule: config.schedule,
|
|
@@ -20418,8 +20706,16 @@ var init_agent_traverser = __esm({
|
|
|
20418
20706
|
}
|
|
20419
20707
|
this.log(`\u{1F916} Found agent: ${agentConfig.name} in ${agentConfig.sourcePath}`);
|
|
20420
20708
|
const primitives = [];
|
|
20709
|
+
const seen = /* @__PURE__ */ new Set();
|
|
20710
|
+
const add2 = /* @__PURE__ */ __name((p) => {
|
|
20711
|
+
const key = `${p.kind}\0${p.sourcePath}\0${p.exportName}`;
|
|
20712
|
+
if (seen.has(key)) return false;
|
|
20713
|
+
seen.add(key);
|
|
20714
|
+
primitives.push(p);
|
|
20715
|
+
return true;
|
|
20716
|
+
}, "add");
|
|
20421
20717
|
const { refs: _refs, ...agentMetadata } = agentConfig;
|
|
20422
|
-
|
|
20718
|
+
add2(agentMetadata);
|
|
20423
20719
|
for (const config of PRIMITIVE_TYPES) {
|
|
20424
20720
|
const refs = agentConfig.refs.get(config.kind) || [];
|
|
20425
20721
|
for (const ref of refs) {
|
|
@@ -20441,10 +20737,9 @@ var init_agent_traverser = __esm({
|
|
|
20441
20737
|
viaDefaultImport: ref.viaDefaultImport === true
|
|
20442
20738
|
});
|
|
20443
20739
|
if (!primitive) continue;
|
|
20444
|
-
|
|
20740
|
+
if (!add2(primitive)) continue;
|
|
20445
20741
|
if (config.resolveNested) {
|
|
20446
|
-
const nested
|
|
20447
|
-
primitives.push(...nested);
|
|
20742
|
+
for (const nested of this.resolveReferencesForPrimitive(primitive, sourcePath)) add2(nested);
|
|
20448
20743
|
}
|
|
20449
20744
|
}
|
|
20450
20745
|
}
|
|
@@ -24642,6 +24937,14 @@ var init_workflow_api_service = __esm({
|
|
|
24642
24937
|
async getVersionEnvOverlay(workflowId, version) {
|
|
24643
24938
|
return this.httpGet(`${this.base}/${workflowId}/versions/${encodeURIComponent(version)}/env-overlay`, await this.auth());
|
|
24644
24939
|
}
|
|
24940
|
+
/**
|
|
24941
|
+
* WF-403 (13 §13.14; LUA-752) — `GET …/:workflowId/export?version=`: the active (or named) version as pushable
|
|
24942
|
+
* files (`{ form, version, files:[{ path, contents }], warnings }`). `lua workflows export` writes them to disk.
|
|
24943
|
+
*/
|
|
24944
|
+
async exportWorkflowFiles(workflowId, version) {
|
|
24945
|
+
const qs = version ? `?version=${encodeURIComponent(version)}` : "";
|
|
24946
|
+
return this.httpGet(`${this.base}/${workflowId}/export${qs}`, await this.auth());
|
|
24947
|
+
}
|
|
24645
24948
|
async getWorkflowVersions(workflowId) {
|
|
24646
24949
|
return this.httpGet(`${this.base}/${workflowId}/versions`, await this.auth());
|
|
24647
24950
|
}
|
|
@@ -24738,6 +25041,34 @@ var init_workflow_api_service = __esm({
|
|
|
24738
25041
|
async retryStep(runId, stepId, data = {}) {
|
|
24739
25042
|
return this.httpPost(`${this.runs}/${runId}/steps/${pathId(stepId)}/retry`, data, await this.auth());
|
|
24740
25043
|
}
|
|
25044
|
+
/**
|
|
25045
|
+
* R37 (LUA-752) — a human decides a parked step: `skip` it, `complete` it with the output it would have produced,
|
|
25046
|
+
* or `fail` it (the step's onError policy applies). 400 `VALIDATION_FAILED{output-required}` / `RESOLVE_OUTPUT_INVALID`,
|
|
25047
|
+
* 403 `APPROVAL_REQUIRES_HUMAN` / `NOT_RUN_CREATOR`, 404 `RUN_NOT_FOUND` / `STEP_NOT_FOUND`, 409 `STEP_NOT_PARKED` /
|
|
25048
|
+
* `RUN_TERMINAL`, 413 `OUTPUT_TOO_LARGE`; the CAS loser is a 200 `{ resolved:false, reason, recorded }`.
|
|
25049
|
+
*/
|
|
25050
|
+
async resolveStep(runId, stepId, data) {
|
|
25051
|
+
return this.httpPost(`${this.runs}/${runId}/steps/${pathId(stepId)}/resolve`, data, await this.auth());
|
|
25052
|
+
}
|
|
25053
|
+
/**
|
|
25054
|
+
* R45 (LUA-752) — raise a parked run's budget (`maxCredits` / `maxSteps` / `maxJobSeconds` / `maxDurationSeconds`;
|
|
25055
|
+
* increases only). 400 `VALIDATION_FAILED` / `CAP_EXCEEDED`, 403 `NOT_RUN_CREATOR`, 409 `BUDGET_NOT_RAISABLE`.
|
|
25056
|
+
*/
|
|
25057
|
+
async raiseBudget(runId, data) {
|
|
25058
|
+
return this.httpPost(`${this.runs}/${runId}/budget`, data, await this.auth());
|
|
25059
|
+
}
|
|
25060
|
+
/**
|
|
25061
|
+
* R39 (LUA-752) — the current approval payload with its `payloadFingerprint` / `editRevision` (what
|
|
25062
|
+
* `approve --edit --fingerprint` echoes). `path` pages one array of a large payload.
|
|
25063
|
+
*/
|
|
25064
|
+
async getApprovalPayload(runId, approvalId, query = {}) {
|
|
25065
|
+
const q = new URLSearchParams();
|
|
25066
|
+
if (query.path) q.append("path", query.path);
|
|
25067
|
+
if (query.cursor) q.append("cursor", query.cursor);
|
|
25068
|
+
if (query.limit !== void 0) q.append("limit", String(query.limit));
|
|
25069
|
+
const qs = q.toString();
|
|
25070
|
+
return this.httpGet(`${this.runs}/${runId}/approvals/${pathId(approvalId)}/payload${qs ? `?${qs}` : ""}`, await this.auth());
|
|
25071
|
+
}
|
|
24741
25072
|
/** R13 — resolve an approval (human; `expectedFingerprint` guards against an edited payload — 409 `PAYLOAD_MISMATCH`). */
|
|
24742
25073
|
async resolveApproval(runId, approvalId, data) {
|
|
24743
25074
|
return this.httpPost(`${this.runs}/${runId}/approvals/${pathId(approvalId)}/resolve`, data, await this.auth());
|
|
@@ -24822,6 +25153,14 @@ var init_workflow_api_service = __esm({
|
|
|
24822
25153
|
async getSchedule(jobId) {
|
|
24823
25154
|
return this.httpGet(`${this.schedules}/${encodeURIComponent(jobId)}`, await this.auth());
|
|
24824
25155
|
}
|
|
25156
|
+
/** R27 (LUA-752) — create or replace the plain schedule Job of a workflow (201; 400 `VALIDATION_FAILED` / `WORKFLOW_NOT_ON_AGENT`, 404 `WORKFLOW_NOT_FOUND`, 409 `SCHEDULE_CAP`). */
|
|
25157
|
+
async createSchedule(data) {
|
|
25158
|
+
return this.httpPost(this.schedules, data, await this.auth());
|
|
25159
|
+
}
|
|
25160
|
+
/** R56 (LUA-752) — pause / resume a schedule, persist `backfillOnEnable`, one-shot `backfillNow` (404 `SCHEDULE_NOT_FOUND`, 400 `VALIDATION_FAILED{issues}`). */
|
|
25161
|
+
async updateSchedule(jobId, data) {
|
|
25162
|
+
return this.httpPatch(`${this.schedules}/${encodeURIComponent(jobId)}`, data, await this.auth());
|
|
25163
|
+
}
|
|
24825
25164
|
/** R28 — delete a schedule Job (404 `SCHEDULE_NOT_FOUND`). The CLI refuses a LIVE goal's job BEFORE this call (`goal_schedule`); an ended goal's lingering Job is retired here (LUA-760). */
|
|
24826
25165
|
async deleteSchedule(jobId) {
|
|
24827
25166
|
return this.httpDelete(`${this.schedules}/${encodeURIComponent(jobId)}`, await this.auth());
|
|
@@ -26945,6 +27284,7 @@ var AgentApi = class extends HttpClient {
|
|
|
26945
27284
|
// src/utils/init-agent.ts
|
|
26946
27285
|
init_constants();
|
|
26947
27286
|
init_cli();
|
|
27287
|
+
init_cli_error();
|
|
26948
27288
|
async function fetchAgentTypes(apiKey) {
|
|
26949
27289
|
writeProgress("\u{1F504} Fetching agent types...");
|
|
26950
27290
|
const agentApi = new AgentApi(BASE_URLS.API, apiKey);
|
|
@@ -27037,12 +27377,18 @@ async function fetchExistingAgentDetails(apiKey, agentId) {
|
|
|
27037
27377
|
return fetchAgentDetails(agentApi, agentId);
|
|
27038
27378
|
}
|
|
27039
27379
|
__name(fetchExistingAgentDetails, "fetchExistingAgentDetails");
|
|
27380
|
+
async function fetchApprovedModelsOrThrow(apiKey, agentId, orgId) {
|
|
27381
|
+
const agentApi = new AgentApi(BASE_URLS.API, apiKey);
|
|
27382
|
+
const result = await agentApi.getApprovedModels(void 0, agentId, orgId);
|
|
27383
|
+
if (!result.success) {
|
|
27384
|
+
throw CliError.fromStatus(result.error?.statusCode, `Could not fetch models from the server: ${result.error?.message || "Unknown error"}`);
|
|
27385
|
+
}
|
|
27386
|
+
return result.data ?? [];
|
|
27387
|
+
}
|
|
27388
|
+
__name(fetchApprovedModelsOrThrow, "fetchApprovedModelsOrThrow");
|
|
27040
27389
|
async function fetchApprovedModels(apiKey, agentId, orgId) {
|
|
27041
27390
|
try {
|
|
27042
|
-
|
|
27043
|
-
const result = await agentApi.getApprovedModels(void 0, agentId, orgId);
|
|
27044
|
-
if (!result.success) return null;
|
|
27045
|
-
return result.data ?? [];
|
|
27391
|
+
return await fetchApprovedModelsOrThrow(apiKey, agentId, orgId);
|
|
27046
27392
|
} catch {
|
|
27047
27393
|
return null;
|
|
27048
27394
|
}
|
|
@@ -28709,12 +29055,7 @@ async function duplicateAgentNonInteractive(apiKey, userData, mode, options) {
|
|
|
28709
29055
|
if (mode.orgId) {
|
|
28710
29056
|
const existingOrg = orgs.find((o) => o.id === mode.orgId);
|
|
28711
29057
|
if (!existingOrg) {
|
|
28712
|
-
|
|
28713
|
-
writeInfo("\nAvailable organizations:");
|
|
28714
|
-
for (const org of orgs) {
|
|
28715
|
-
writeInfo(` - ${org.registeredName} (${org.id})`);
|
|
28716
|
-
}
|
|
28717
|
-
throw new Error("Operation failed");
|
|
29058
|
+
throw CliError.notFound(`Organization not found: ${mode.orgId}`, availableOrgsHint(orgs));
|
|
28718
29059
|
}
|
|
28719
29060
|
targetOrgId = mode.orgId;
|
|
28720
29061
|
writeProgress(`\u2705 Using target organization: ${existingOrg.registeredName}`);
|
|
@@ -28724,12 +29065,7 @@ async function duplicateAgentNonInteractive(apiKey, userData, mode, options) {
|
|
|
28724
29065
|
targetOrgId = matchedOrg.id;
|
|
28725
29066
|
writeProgress(`\u2705 Found target organization: ${matchedOrg.registeredName}`);
|
|
28726
29067
|
} else {
|
|
28727
|
-
|
|
28728
|
-
writeInfo("\nAvailable organizations:");
|
|
28729
|
-
for (const org of orgs) {
|
|
28730
|
-
writeInfo(` - ${org.registeredName} (${org.id})`);
|
|
28731
|
-
}
|
|
28732
|
-
throw new Error("Operation failed");
|
|
29068
|
+
throw CliError.notFound(`Organization not found: ${mode.orgName}`, availableOrgsHint(orgs));
|
|
28733
29069
|
}
|
|
28734
29070
|
} else {
|
|
28735
29071
|
targetOrgId = sourceOrgId;
|
|
@@ -29210,10 +29546,13 @@ async function selectExistingAgent(orgs, apiKey) {
|
|
|
29210
29546
|
};
|
|
29211
29547
|
}
|
|
29212
29548
|
__name(selectExistingAgent, "selectExistingAgent");
|
|
29549
|
+
function availableOrgsHint(orgs) {
|
|
29550
|
+
return listHint("Available organizations:", orgs.map((org) => `${org.registeredName} (${org.id})`));
|
|
29551
|
+
}
|
|
29552
|
+
__name(availableOrgsHint, "availableOrgsHint");
|
|
29213
29553
|
async function selectExistingAgentById(orgs, apiKey, agentId) {
|
|
29214
29554
|
if (orgs.length === 0) {
|
|
29215
|
-
|
|
29216
|
-
throw new Error("No organizations found.");
|
|
29555
|
+
throw CliError.notFound("No organizations found.");
|
|
29217
29556
|
}
|
|
29218
29557
|
for (const org of orgs) {
|
|
29219
29558
|
const agent = org.agents.find((candidate) => candidate.agentId === agentId);
|
|
@@ -29235,17 +29574,14 @@ async function selectExistingAgentById(orgs, apiKey, agentId) {
|
|
|
29235
29574
|
};
|
|
29236
29575
|
}
|
|
29237
29576
|
}
|
|
29238
|
-
|
|
29239
|
-
writeInfo("\nAvailable agents:");
|
|
29577
|
+
const available = [];
|
|
29240
29578
|
for (const org of orgs) {
|
|
29241
29579
|
if (org.agents && org.agents.length > 0) {
|
|
29242
|
-
|
|
29243
|
-
for (const agent of org.agents) {
|
|
29244
|
-
writeInfo(` - ${agent.name} (${agent.agentId})`);
|
|
29245
|
-
}
|
|
29580
|
+
available.push(`${org.registeredName ?? org.name ?? org.id}:`);
|
|
29581
|
+
for (const agent of org.agents) available.push(` - ${agent.name} (${agent.agentId})`);
|
|
29246
29582
|
}
|
|
29247
29583
|
}
|
|
29248
|
-
throw
|
|
29584
|
+
throw CliError.notFound(`Agent not found: ${agentId}`, listHint("Available agents:", available, ""));
|
|
29249
29585
|
}
|
|
29250
29586
|
__name(selectExistingAgentById, "selectExistingAgentById");
|
|
29251
29587
|
async function createNewAgentNonInteractive(apiKey, userData, agentName, orgId, orgName, promoCode, model) {
|
|
@@ -29255,12 +29591,7 @@ async function createNewAgentNonInteractive(apiKey, userData, agentName, orgId,
|
|
|
29255
29591
|
const orgs = userData.admin?.orgs || [];
|
|
29256
29592
|
const existingOrg = orgs.find((o) => o.id === orgId);
|
|
29257
29593
|
if (!existingOrg) {
|
|
29258
|
-
|
|
29259
|
-
writeInfo("\nAvailable organizations:");
|
|
29260
|
-
for (const org of orgs) {
|
|
29261
|
-
writeInfo(` - ${org.registeredName} (${org.id})`);
|
|
29262
|
-
}
|
|
29263
|
-
throw new Error("Operation failed");
|
|
29594
|
+
throw CliError.notFound(`Organization not found: ${orgId}`, availableOrgsHint(orgs));
|
|
29264
29595
|
}
|
|
29265
29596
|
writeProgress(`\u2705 Using organization: ${existingOrg.registeredName}`);
|
|
29266
29597
|
} else if (orgName) {
|
|
@@ -31576,6 +31907,7 @@ var voiceHandler = new VoiceHandler();
|
|
|
31576
31907
|
// src/primitives/workflow.handler.ts
|
|
31577
31908
|
init_types();
|
|
31578
31909
|
init_constants();
|
|
31910
|
+
init_cli_error();
|
|
31579
31911
|
init_workflow_api_service();
|
|
31580
31912
|
init_artifact_loader();
|
|
31581
31913
|
init_bundle_upload();
|
|
@@ -32732,6 +33064,15 @@ async function runWorkflowLocallyInner(rawOpts) {
|
|
|
32732
33064
|
stepResults[d]
|
|
32733
33065
|
]));
|
|
32734
33066
|
}, "inputFor");
|
|
33067
|
+
const nodeInputFor = /* @__PURE__ */ __name((row2, single, base) => {
|
|
33068
|
+
const cfg = single.input;
|
|
33069
|
+
if (!cfg || typeof cfg !== "object" || Array.isArray(cfg) || Object.keys(cfg).length === 0) return base;
|
|
33070
|
+
const resolved = resolveMapping(parseMapConfig(cfg, row2.stepId), mappingCtx());
|
|
33071
|
+
if ("error" in resolved) {
|
|
33072
|
+
throw new StepFailure("binding_unresolved", `input map of "${row2.stepId}": ${"key" in resolved && resolved.key ? resolved.key : resolved.error}`);
|
|
33073
|
+
}
|
|
33074
|
+
return resolved.value;
|
|
33075
|
+
}, "nodeInputFor");
|
|
32735
33076
|
let runFailure;
|
|
32736
33077
|
let bailed;
|
|
32737
33078
|
const terminalize = /* @__PURE__ */ __name((row2, status, extra = {}) => {
|
|
@@ -33015,8 +33356,9 @@ async function runWorkflowLocallyInner(rawOpts) {
|
|
|
33015
33356
|
const fakeObject = /* @__PURE__ */ __name((single) => single.outputSchema ? {
|
|
33016
33357
|
object: stubFromSchema(single.outputSchema)
|
|
33017
33358
|
} : {}, "fakeObject");
|
|
33018
|
-
const executeSingle = /* @__PURE__ */ __name(async (row2, single,
|
|
33359
|
+
const executeSingle = /* @__PURE__ */ __name(async (row2, single, rawInput) => {
|
|
33019
33360
|
const id = row2.stepId;
|
|
33361
|
+
const input = nodeInputFor(row2, single, rawInput);
|
|
33020
33362
|
const drift = stepInputIssue(single, input);
|
|
33021
33363
|
if (drift) throw drift;
|
|
33022
33364
|
if (opts.stepOutputs && id in opts.stepOutputs) {
|
|
@@ -33077,33 +33419,6 @@ async function runWorkflowLocallyInner(rawOpts) {
|
|
|
33077
33419
|
return out;
|
|
33078
33420
|
}
|
|
33079
33421
|
case "workflow": {
|
|
33080
|
-
if (single.workflowId === WORKFLOW_ARM_SUBRUN_ID && single.graph) {
|
|
33081
|
-
const [armMap, inner] = single.graph;
|
|
33082
|
-
const innerId = armId2(inner);
|
|
33083
|
-
const ctx = {
|
|
33084
|
-
...mappingCtx(),
|
|
33085
|
-
stepResults: {
|
|
33086
|
-
...stepResults,
|
|
33087
|
-
[innerId]: input,
|
|
33088
|
-
[row2.stepId]: input,
|
|
33089
|
-
$item: input
|
|
33090
|
-
}
|
|
33091
|
-
};
|
|
33092
|
-
const resolved = resolveMapping(parseMapConfig(armMap.mapConfig, armMap.id), ctx);
|
|
33093
|
-
if ("error" in resolved) throw new StepFailure("binding_unresolved", `arm map "${armMap.id}": ${resolved.key ?? resolved.error}`);
|
|
33094
|
-
stepResults[armMap.id] = resolved.value;
|
|
33095
|
-
const innerRow = {
|
|
33096
|
-
...row2,
|
|
33097
|
-
stepId: innerId,
|
|
33098
|
-
node: {
|
|
33099
|
-
...row2.node,
|
|
33100
|
-
entry: inner
|
|
33101
|
-
}
|
|
33102
|
-
};
|
|
33103
|
-
const out = await executeSingle(innerRow, inner, resolved.value);
|
|
33104
|
-
stepResults[innerId] = out;
|
|
33105
|
-
return out;
|
|
33106
|
-
}
|
|
33107
33422
|
throw new StepFailure("SUBRUN_NOT_SUPPORTED_OFFLINE", `nested workflow "${single.workflowId}" cannot run offline \u2014 supply --step-output ${id}=<json>`);
|
|
33108
33423
|
}
|
|
33109
33424
|
}
|
|
@@ -33576,7 +33891,13 @@ async function runWorkflowLocallyInner(rawOpts) {
|
|
|
33576
33891
|
}
|
|
33577
33892
|
const suppliedId = stepOutputIdFor(row2);
|
|
33578
33893
|
if (opts.stepOutputs && suppliedId !== void 0) {
|
|
33579
|
-
|
|
33894
|
+
let drift;
|
|
33895
|
+
try {
|
|
33896
|
+
drift = entry.type === "step" ? stepInputIssue(entry, nodeInputFor(row2, entry, inputFor(row2))) : void 0;
|
|
33897
|
+
} catch (e) {
|
|
33898
|
+
if (!(e instanceof StepFailure)) throw e;
|
|
33899
|
+
drift = e;
|
|
33900
|
+
}
|
|
33580
33901
|
if (drift) {
|
|
33581
33902
|
row2.status = "running";
|
|
33582
33903
|
row2.error = {
|
|
@@ -34584,6 +34905,7 @@ var WorkflowHandler = class extends BaseVersionedHandler {
|
|
|
34584
34905
|
prepareForPush(manifest, name, projectPath = process.cwd(), bundleAccumulator) {
|
|
34585
34906
|
const primitive = findPrimitive(manifest, name, this.kind);
|
|
34586
34907
|
if (!primitive) return null;
|
|
34908
|
+
if (primitive.unplacedStepIds?.length) throw unplacedStepError(primitive.name, primitive.unplacedStepIds);
|
|
34587
34909
|
if (primitive.form === "script") return this.buildPushData(primitive, void 0);
|
|
34588
34910
|
const data = super.prepareForPush(manifest, name, projectPath, bundleAccumulator);
|
|
34589
34911
|
if (!data) return null;
|
|
@@ -34599,6 +34921,11 @@ var WorkflowHandler = class extends BaseVersionedHandler {
|
|
|
34599
34921
|
* engine's claim could not resolve `toolId` and every static tool step failed `TOOL_REF_UNRESOLVED`
|
|
34600
34922
|
* (prod 2026-09-05, kitchen-sink `armB`, 39/39 runs). Each referenced tool rides the version as
|
|
34601
34923
|
* `tools[] = {name, code | codeS3Hash}`, through the same accumulator the workflow bundle uses.
|
|
34924
|
+
*
|
|
34925
|
+
* LUA-781: a reference with NO compiled artifact used to warn and push anyway (exit 0) — the version carried no
|
|
34926
|
+
* `tools[]` and every run failed the node `not_in_version_bundle` (staging 2026-09-08: a `LuaTool` written as a
|
|
34927
|
+
* plain object was never detected). The compile now refuses it (`WORKFLOW_TOOL_UNBUNDLED`, an error); this is the
|
|
34928
|
+
* belt for a stale manifest — one typed line, exit 1, nothing sent.
|
|
34602
34929
|
*/
|
|
34603
34930
|
toolBundlesFor(wf, manifest, projectPath, bundleAccumulator) {
|
|
34604
34931
|
const out = [];
|
|
@@ -34606,10 +34933,7 @@ var WorkflowHandler = class extends BaseVersionedHandler {
|
|
|
34606
34933
|
...new Set(wf.toolRefs ?? [])
|
|
34607
34934
|
]) {
|
|
34608
34935
|
const tool = findPrimitive(manifest, toolName, PrimitiveKind.TOOL);
|
|
34609
|
-
if (!tool)
|
|
34610
|
-
console.warn(`\u26A0\uFE0F workflow "${wf.name}" references tool "${toolName}" but the manifest carries no compiled artifact for it \u2014 the engine can only resolve it through the agent's skills (TOOL_REF_UNRESOLVED otherwise)`);
|
|
34611
|
-
continue;
|
|
34612
|
-
}
|
|
34936
|
+
if (!tool) throw toolUnbundledError(wf.name, toolName);
|
|
34613
34937
|
const code = loadArtifact(tool, projectPath);
|
|
34614
34938
|
if (bundleAccumulator) {
|
|
34615
34939
|
const rawGzip = compressForPushRaw(code);
|
|
@@ -34707,6 +35031,19 @@ var WorkflowHandler = class extends BaseVersionedHandler {
|
|
|
34707
35031
|
}
|
|
34708
35032
|
};
|
|
34709
35033
|
var workflowHandler = new WorkflowHandler();
|
|
35034
|
+
function unplacedStepError(workflowName, stepIds) {
|
|
35035
|
+
const list = stepIds.map((id) => `"${id}"`).join(", ");
|
|
35036
|
+
return new CliError("unplaced_step", `workflow "${workflowName}" is not pushed: createStep ${list} ${stepIds.length === 1 ? "is" : "are"} declared in its source file but placed in no workflow (WORKFLOW_UNPLACED_STEP)`, {
|
|
35037
|
+
hint: `place ${stepIds.length === 1 ? "it" : "them"} in a chain (.then(step) / .parallel([...])) or delete the declaration, then push again \u2014 lua compile lists every unplaced step`
|
|
35038
|
+
});
|
|
35039
|
+
}
|
|
35040
|
+
__name(unplacedStepError, "unplacedStepError");
|
|
35041
|
+
function toolUnbundledError(workflowName, toolName) {
|
|
35042
|
+
return new CliError("tool_unbundled", `workflow "${workflowName}" is not pushed: toolStep tool "${toolName}" has no compiled artifact in this project (WORKFLOW_TOOL_UNBUNDLED) \u2014 the version would carry no tools[] entry for it and every run would fail the step TOOL_REF_UNRESOLVED (not_in_version_bundle)`, {
|
|
35043
|
+
hint: `declare "${toolName}" where the compiler sees it \u2014 defineTool({ name: '${toolName}', \u2026 }), a class implementing LuaTool, or an exported { name, description, inputSchema, execute } object \u2014 pass that export to toolStep(), then run lua compile (it lists every unbundled tool) and push again`
|
|
35044
|
+
});
|
|
35045
|
+
}
|
|
35046
|
+
__name(toolUnbundledError, "toolUnbundledError");
|
|
34710
35047
|
function workflowNameTakenHint(name, error) {
|
|
34711
35048
|
if (error?.code !== "WORKFLOW_NAME_TAKEN") return null;
|
|
34712
35049
|
const holder = error.dynamic ? "a chat-composed (dynamic) workflow" : "an existing workflow";
|
|
@@ -35354,13 +35691,19 @@ var ALIAS_MAP = {
|
|
|
35354
35691
|
"cancel",
|
|
35355
35692
|
"resume",
|
|
35356
35693
|
"retry-step",
|
|
35694
|
+
// LUA-752: the R37 / R45 / R39 verbs the park hints and the approve refusal already named (they did not exist).
|
|
35695
|
+
"resolve-step",
|
|
35696
|
+
"raise-budget",
|
|
35357
35697
|
"approve",
|
|
35698
|
+
"approval-payload",
|
|
35358
35699
|
"signal",
|
|
35359
35700
|
"replay",
|
|
35360
35701
|
"logs",
|
|
35361
35702
|
"delete",
|
|
35362
35703
|
"delete-run",
|
|
35363
35704
|
"env-overlay",
|
|
35705
|
+
// LUA-752 (L6.3): WF-403 — the active / named version back as pushable files.
|
|
35706
|
+
"export",
|
|
35364
35707
|
"archive-runs",
|
|
35365
35708
|
"workspace",
|
|
35366
35709
|
"jobs",
|
|
@@ -35380,6 +35723,12 @@ var ALIAS_MAP = {
|
|
|
35380
35723
|
env: "env-overlay",
|
|
35381
35724
|
overlay: "env-overlay",
|
|
35382
35725
|
archive: "archive-runs",
|
|
35726
|
+
resolve: "resolve-step",
|
|
35727
|
+
budget: "raise-budget",
|
|
35728
|
+
raise: "raise-budget",
|
|
35729
|
+
payload: "approval-payload",
|
|
35730
|
+
codegen: "export",
|
|
35731
|
+
"export-workflow": "export",
|
|
35383
35732
|
show: "view",
|
|
35384
35733
|
info: "view",
|
|
35385
35734
|
ls: "list",
|
|
@@ -35436,12 +35785,28 @@ var ALIAS_MAP = {
|
|
|
35436
35785
|
})
|
|
35437
35786
|
},
|
|
35438
35787
|
"workflows.schedules.action": {
|
|
35788
|
+
// LUA-752: `create` (R27) · `patch` / `pause` / `resume` (R56) beside the LUA-627 reads and R28 delete.
|
|
35439
35789
|
canonical: [
|
|
35440
35790
|
"list",
|
|
35791
|
+
"create",
|
|
35792
|
+
"patch",
|
|
35793
|
+
"pause",
|
|
35794
|
+
"resume",
|
|
35441
35795
|
"delete"
|
|
35442
35796
|
],
|
|
35443
35797
|
aliases: lowerKeys({
|
|
35444
35798
|
ls: "list",
|
|
35799
|
+
new: "create",
|
|
35800
|
+
add: "create",
|
|
35801
|
+
set: "create",
|
|
35802
|
+
update: "patch",
|
|
35803
|
+
edit: "patch",
|
|
35804
|
+
hold: "pause",
|
|
35805
|
+
stop: "pause",
|
|
35806
|
+
disable: "pause",
|
|
35807
|
+
unpause: "resume",
|
|
35808
|
+
enable: "resume",
|
|
35809
|
+
continue: "resume",
|
|
35445
35810
|
rm: "delete",
|
|
35446
35811
|
remove: "delete",
|
|
35447
35812
|
del: "delete",
|
|
@@ -37032,6 +37397,7 @@ function writeLedgerFile(file, value3) {
|
|
|
37032
37397
|
__name(writeLedgerFile, "writeLedgerFile");
|
|
37033
37398
|
|
|
37034
37399
|
// src/commands/test.ts
|
|
37400
|
+
init_cli_error();
|
|
37035
37401
|
async function loadAuthOrFail() {
|
|
37036
37402
|
const { config, agentId, apiKey } = await initializeCommand({
|
|
37037
37403
|
showProgress: false
|
|
@@ -37079,9 +37445,7 @@ function parseJsonInputOrFail(inputJson, expectedFormat) {
|
|
|
37079
37445
|
try {
|
|
37080
37446
|
return JSON.parse(inputJson);
|
|
37081
37447
|
} catch (error) {
|
|
37082
|
-
|
|
37083
|
-
console.log(`Expected format: ${expectedFormat}`);
|
|
37084
|
-
throw new Error(`Invalid JSON input: ${error instanceof Error ? error.message : "Unknown error"}`);
|
|
37448
|
+
throw CliError.usage(`Invalid JSON input: ${error instanceof Error ? error.message : "Unknown error"}`, `Expected format: ${expectedFormat}`);
|
|
37085
37449
|
}
|
|
37086
37450
|
}
|
|
37087
37451
|
__name(parseJsonInputOrFail, "parseJsonInputOrFail");
|
|
@@ -37090,8 +37454,7 @@ async function selectEntityOrPrompt(options) {
|
|
|
37090
37454
|
if (entityName) {
|
|
37091
37455
|
const selected = items.find((item) => item[idProperty] === entityName || item[nameProperty] === entityName);
|
|
37092
37456
|
if (!selected) {
|
|
37093
|
-
|
|
37094
|
-
throw new Error(`${entityType} "${entityName}" not found`);
|
|
37457
|
+
throw CliError.notFound(`${entityType} "${entityName}" not found`);
|
|
37095
37458
|
}
|
|
37096
37459
|
progress(asJson ?? false, `\u2705 Selected ${entityType.toLowerCase()}: ${selected[nameProperty]}`);
|
|
37097
37460
|
return selected;
|
|
@@ -37182,11 +37545,11 @@ async function testCommand(type, cmdObj) {
|
|
|
37182
37545
|
type = validateOrSuggest("test.type", type);
|
|
37183
37546
|
selectedType = type;
|
|
37184
37547
|
} else if (entityName) {
|
|
37185
|
-
|
|
37186
|
-
|
|
37187
|
-
|
|
37188
|
-
|
|
37189
|
-
|
|
37548
|
+
throw CliError.usage("Type must be specified when using the --name option.", [
|
|
37549
|
+
"Usage:",
|
|
37550
|
+
' lua test skill --name mySkill --input "{...}" Test skill with JSON input',
|
|
37551
|
+
' lua test webhook --name myWebhook --input "{...}" Test webhook with JSON input'
|
|
37552
|
+
].join("\n"));
|
|
37190
37553
|
} else {
|
|
37191
37554
|
const typeAnswer = await safePrompt([
|
|
37192
37555
|
{
|
|
@@ -37273,15 +37636,13 @@ async function testSkill(entityName, inputJson, asJson = false) {
|
|
|
37273
37636
|
progress(asJson, `\u{1F4C4} Loaded environment variables from .env file`);
|
|
37274
37637
|
}
|
|
37275
37638
|
if (allTools.length === 0) {
|
|
37276
|
-
|
|
37277
|
-
throw new Error("No tools found in compiled output.");
|
|
37639
|
+
throw new CliError("error", "No tools found in compiled output.");
|
|
37278
37640
|
}
|
|
37279
37641
|
let selectedTool;
|
|
37280
37642
|
if (entityName) {
|
|
37281
37643
|
selectedTool = allTools.find((t) => t.id === entityName || t.name === entityName);
|
|
37282
37644
|
if (!selectedTool) {
|
|
37283
|
-
|
|
37284
|
-
throw new Error("Tool");
|
|
37645
|
+
throw CliError.notFound(`Tool "${entityName}" not found`);
|
|
37285
37646
|
}
|
|
37286
37647
|
progress(asJson, `\u2705 Selected tool: ${selectedTool.name}`);
|
|
37287
37648
|
} else {
|
|
@@ -41382,6 +41743,7 @@ async function probeAgentErrorsSince(apiKey, agentId, sinceISO) {
|
|
|
41382
41743
|
__name(probeAgentErrorsSince, "probeAgentErrorsSince");
|
|
41383
41744
|
|
|
41384
41745
|
// src/commands/chat.ts
|
|
41746
|
+
init_cli_error();
|
|
41385
41747
|
async function runChatProbe(chatEnv, window) {
|
|
41386
41748
|
if (hintsDisabled()) return;
|
|
41387
41749
|
try {
|
|
@@ -41508,8 +41870,7 @@ async function chatCommand(cmdObj) {
|
|
|
41508
41870
|
break;
|
|
41509
41871
|
}
|
|
41510
41872
|
case "error":
|
|
41511
|
-
|
|
41512
|
-
throw new Error(`${envResolution.message}`);
|
|
41873
|
+
throw CliError.usage(envResolution.message);
|
|
41513
41874
|
}
|
|
41514
41875
|
}
|
|
41515
41876
|
let chatEnv = {
|
|
@@ -41890,8 +42251,6 @@ async function sendSingleMessage(chatEnv, message, probeWindow) {
|
|
|
41890
42251
|
}
|
|
41891
42252
|
await runChatProbe(chatEnv, probeWindow);
|
|
41892
42253
|
} catch (error) {
|
|
41893
|
-
console.error(`
|
|
41894
|
-
\u274C Error: ${error instanceof Error ? error.message : "Unknown error"}`);
|
|
41895
42254
|
writeHintBlock({
|
|
41896
42255
|
headline: "Something went wrong. Debug options:",
|
|
41897
42256
|
lines: [
|
|
@@ -41907,7 +42266,8 @@ async function sendSingleMessage(chatEnv, message, probeWindow) {
|
|
|
41907
42266
|
when: "error"
|
|
41908
42267
|
});
|
|
41909
42268
|
await runChatProbe(chatEnv, probeWindow);
|
|
41910
|
-
|
|
42269
|
+
if (isTypedCliError(error)) throw error;
|
|
42270
|
+
throw new CliError("error", error instanceof Error ? error.message : "Unknown error");
|
|
41911
42271
|
}
|
|
41912
42272
|
}
|
|
41913
42273
|
__name(sendSingleMessage, "sendSingleMessage");
|
|
@@ -42052,6 +42412,7 @@ import fs18 from "fs";
|
|
|
42052
42412
|
import path24 from "path";
|
|
42053
42413
|
import inquirer10 from "inquirer";
|
|
42054
42414
|
init_analytics();
|
|
42415
|
+
init_cli_error();
|
|
42055
42416
|
function resolveEnvironment(env, hasNonInteractiveFlags) {
|
|
42056
42417
|
if (env) {
|
|
42057
42418
|
const normalized = validateOrSuggest("env.environment", env);
|
|
@@ -42166,12 +42527,7 @@ async function envCommand(env, cmdObj) {
|
|
|
42166
42527
|
selectedEnvironment = environment;
|
|
42167
42528
|
break;
|
|
42168
42529
|
case "error":
|
|
42169
|
-
|
|
42170
|
-
if (envResolution.usage) {
|
|
42171
|
-
console.log("\nUsage:");
|
|
42172
|
-
envResolution.usage.forEach((line) => console.log(` ${line}`));
|
|
42173
|
-
}
|
|
42174
|
-
throw new Error("Operation failed");
|
|
42530
|
+
throw CliError.usage(envResolution.message, listHint("Usage:", envResolution.usage ?? [], ""));
|
|
42175
42531
|
}
|
|
42176
42532
|
let context = {
|
|
42177
42533
|
environment: selectedEnvironment,
|
|
@@ -42201,12 +42557,7 @@ async function envCommand(env, cmdObj) {
|
|
|
42201
42557
|
await manageEnvironmentVariables(context);
|
|
42202
42558
|
break;
|
|
42203
42559
|
case "error":
|
|
42204
|
-
|
|
42205
|
-
if (mode.examples) {
|
|
42206
|
-
console.log("\nExamples:");
|
|
42207
|
-
mode.examples.forEach((ex) => console.log(` ${ex}`));
|
|
42208
|
-
}
|
|
42209
|
-
throw new Error("Operation failed");
|
|
42560
|
+
throw CliError.usage(mode.message, listHint("Examples:", mode.examples ?? [], ""));
|
|
42210
42561
|
}
|
|
42211
42562
|
trackEvent("cli_env_action", {
|
|
42212
42563
|
environment: env || "interactive",
|
|
@@ -42304,8 +42655,7 @@ __name(listVariables, "listVariables");
|
|
|
42304
42655
|
async function setVariable(context, key, value3) {
|
|
42305
42656
|
const validationError2 = validateKeyFormat(key);
|
|
42306
42657
|
if (validationError2) {
|
|
42307
|
-
|
|
42308
|
-
throw new Error(`${validationError2}`);
|
|
42658
|
+
throw CliError.usage(validationError2);
|
|
42309
42659
|
}
|
|
42310
42660
|
try {
|
|
42311
42661
|
const { created } = await saveVariableCore(context, key, value3);
|
|
@@ -42319,8 +42669,8 @@ async function setVariable(context, key, value3) {
|
|
|
42319
42669
|
});
|
|
42320
42670
|
}
|
|
42321
42671
|
} catch (error) {
|
|
42322
|
-
|
|
42323
|
-
throw new
|
|
42672
|
+
if (isTypedCliError(error)) throw error;
|
|
42673
|
+
throw new CliError("error", `Error setting variable: ${error instanceof Error ? error.message : "Unknown error"}`);
|
|
42324
42674
|
}
|
|
42325
42675
|
}
|
|
42326
42676
|
__name(setVariable, "setVariable");
|
|
@@ -42336,8 +42686,8 @@ async function removeVariable(context, key) {
|
|
|
42336
42686
|
});
|
|
42337
42687
|
}
|
|
42338
42688
|
} catch (error) {
|
|
42339
|
-
|
|
42340
|
-
throw new
|
|
42689
|
+
if (isTypedCliError(error)) throw error;
|
|
42690
|
+
throw new CliError("error", error instanceof Error ? error.message : "Unknown error");
|
|
42341
42691
|
}
|
|
42342
42692
|
}
|
|
42343
42693
|
__name(removeVariable, "removeVariable");
|
|
@@ -42604,6 +42954,7 @@ init_command_utils();
|
|
|
42604
42954
|
init_compiler2();
|
|
42605
42955
|
init_artifact_loader();
|
|
42606
42956
|
init_analytics();
|
|
42957
|
+
init_cli_error();
|
|
42607
42958
|
async function personaCommand(env, action, cmdObj) {
|
|
42608
42959
|
return withErrorHandling(async () => {
|
|
42609
42960
|
const options = {
|
|
@@ -42759,39 +43110,24 @@ async function executeProductionNonInteractive(context, action, options) {
|
|
|
42759
43110
|
break;
|
|
42760
43111
|
case "deploy": {
|
|
42761
43112
|
if (!options.personaVersion) {
|
|
42762
|
-
|
|
42763
|
-
console.log("\nUsage: lua persona production deploy --persona-version <version>");
|
|
42764
|
-
console.log(" lua persona production deploy -v latest");
|
|
42765
|
-
if (versions.length > 0) {
|
|
42766
|
-
console.log("\nAvailable versions:");
|
|
42767
|
-
versions.slice(0, 5).forEach((v) => {
|
|
42768
|
-
const mark = v.isCurrent ? " (current)" : "";
|
|
42769
|
-
console.log(` - ${v.version}${mark}`);
|
|
42770
|
-
});
|
|
42771
|
-
}
|
|
42772
|
-
throw new Error("--persona-version is required for deploy action");
|
|
43113
|
+
throw CliError.usage("--persona-version is required for deploy action", joinHint("Usage: lua persona production deploy --persona-version <version>\n lua persona production deploy -v latest", listHint("Available versions:", versions.slice(0, 5).map((v) => `${v.version}${v.isCurrent ? " (current)" : ""}`))));
|
|
42773
43114
|
}
|
|
42774
43115
|
let versionNumber;
|
|
42775
43116
|
if (options.personaVersion.toLowerCase() === "latest") {
|
|
42776
43117
|
if (versions.length === 0) {
|
|
42777
|
-
|
|
42778
|
-
throw new Error("No versions available to deploy");
|
|
43118
|
+
throw CliError.notFound("No versions available to deploy");
|
|
42779
43119
|
}
|
|
42780
43120
|
versionNumber = versions[0].version;
|
|
42781
43121
|
console.log(`\u2139\uFE0F Latest version is ${versionNumber}`);
|
|
42782
43122
|
} else {
|
|
42783
43123
|
versionNumber = parseInt(options.personaVersion, 10);
|
|
42784
43124
|
if (isNaN(versionNumber)) {
|
|
42785
|
-
|
|
42786
|
-
throw new Error(`Invalid version number: "${options.personaVersion}"`);
|
|
43125
|
+
throw CliError.usage(`Invalid version number: "${options.personaVersion}"`);
|
|
42787
43126
|
}
|
|
42788
43127
|
}
|
|
42789
43128
|
const versionExists = versions.find((v) => v.version === versionNumber);
|
|
42790
43129
|
if (!versionExists) {
|
|
42791
|
-
|
|
42792
|
-
console.log("\nAvailable versions:");
|
|
42793
|
-
versions.forEach((v) => console.log(` - ${v.version}`));
|
|
42794
|
-
throw new Error(`Version ${versionNumber} not found`);
|
|
43130
|
+
throw CliError.notFound(`Version ${versionNumber} not found`, listHint("Available versions:", versions.map((v) => String(v.version))));
|
|
42795
43131
|
}
|
|
42796
43132
|
if (versionExists.isCurrent) {
|
|
42797
43133
|
console.log(`\u2139\uFE0F Version ${versionNumber} is already deployed.`);
|
|
@@ -43783,6 +44119,7 @@ var ResourceApi = class extends HttpClient {
|
|
|
43783
44119
|
|
|
43784
44120
|
// src/commands/resources.ts
|
|
43785
44121
|
init_analytics();
|
|
44122
|
+
init_cli_error();
|
|
43786
44123
|
async function resourcesCommand(action, cmdObj) {
|
|
43787
44124
|
return withErrorHandling(async () => {
|
|
43788
44125
|
const options = {
|
|
@@ -43902,25 +44239,11 @@ async function executeNonInteractive2(context, action, options) {
|
|
|
43902
44239
|
return;
|
|
43903
44240
|
}
|
|
43904
44241
|
if (!options.resourceName) {
|
|
43905
|
-
|
|
43906
|
-
console.log(`
|
|
43907
|
-
Usage: lua resources ${normalizedAction} --resource-name <name>`);
|
|
43908
|
-
if (resources.length > 0) {
|
|
43909
|
-
console.log("\nAvailable resources:");
|
|
43910
|
-
resources.forEach((r) => console.log(` - ${r.name}`));
|
|
43911
|
-
}
|
|
43912
|
-
throw new Error("Operation failed");
|
|
44242
|
+
throw CliError.usage(`--resource-name is required for action "${normalizedAction}"`, joinHint(`Usage: lua resources ${normalizedAction} --resource-name <name>`, listHint("Available resources:", resources.map((r) => r.name))));
|
|
43913
44243
|
}
|
|
43914
44244
|
const selectedResource = findResource(resources, options.resourceName);
|
|
43915
44245
|
if (!selectedResource) {
|
|
43916
|
-
|
|
43917
|
-
if (resources.length > 0) {
|
|
43918
|
-
console.log("\nAvailable resources:");
|
|
43919
|
-
resources.forEach((r) => console.log(` - ${r.name}`));
|
|
43920
|
-
} else {
|
|
43921
|
-
console.log("\nNo resources found.");
|
|
43922
|
-
}
|
|
43923
|
-
throw new Error("Operation failed");
|
|
44246
|
+
throw CliError.notFound(`Resource "${options.resourceName}" not found`, listHint("Available resources:", resources.map((r) => r.name)) ?? "No resources found.");
|
|
43924
44247
|
}
|
|
43925
44248
|
switch (normalizedAction) {
|
|
43926
44249
|
case "view":
|
|
@@ -44681,6 +45004,7 @@ __name(doRelease, "doRelease");
|
|
|
44681
45004
|
// src/commands/channels.ts
|
|
44682
45005
|
init_constants();
|
|
44683
45006
|
init_analytics();
|
|
45007
|
+
init_cli_error();
|
|
44684
45008
|
async function channelsCommand(action) {
|
|
44685
45009
|
return withErrorHandling(async () => {
|
|
44686
45010
|
const { config, agentId, apiKey } = await initializeCommand();
|
|
@@ -44697,6 +45021,14 @@ async function channelsCommand(action) {
|
|
|
44697
45021
|
}, "channels management");
|
|
44698
45022
|
}
|
|
44699
45023
|
__name(channelsCommand, "channelsCommand");
|
|
45024
|
+
function channelCreateError(error, alreadyConnected) {
|
|
45025
|
+
if (error?.statusCode === 400 && error?.message?.includes("already exists")) {
|
|
45026
|
+
return CliError.fromStatus(400, "Channel already exists", `${alreadyConnected}
|
|
45027
|
+
Use 'lua channels' to list existing channels.`);
|
|
45028
|
+
}
|
|
45029
|
+
return CliError.fromStatus(error?.statusCode, error?.message || "Unknown error", error?.error);
|
|
45030
|
+
}
|
|
45031
|
+
__name(channelCreateError, "channelCreateError");
|
|
44700
45032
|
async function fetchChannelsCore(agentApi, agentId) {
|
|
44701
45033
|
const response = await agentApi.getAgentChannels(agentId);
|
|
44702
45034
|
if (!response.success) {
|
|
@@ -45108,22 +45440,7 @@ async function createWhatsAppChannel(agentApi, agentId) {
|
|
|
45108
45440
|
writeInfo("\n\u{1F4E1} Creating WhatsApp channel...");
|
|
45109
45441
|
const response = await agentApi.createWhatsAppChannel(agentId, channelData);
|
|
45110
45442
|
if (!response.success) {
|
|
45111
|
-
|
|
45112
|
-
if (error?.statusCode === 400 && error?.message?.includes("already exists")) {
|
|
45113
|
-
console.error(`
|
|
45114
|
-
\u274C Channel already exists`);
|
|
45115
|
-
console.error(`\u{1F4A1} This WhatsApp number is already connected to this agent.`);
|
|
45116
|
-
console.error(` Use 'lua channels' to list existing channels.
|
|
45117
|
-
`);
|
|
45118
|
-
} else {
|
|
45119
|
-
console.error(`
|
|
45120
|
-
\u274C Error: ${error?.message || "Unknown error"}`);
|
|
45121
|
-
if (error?.error) {
|
|
45122
|
-
console.error(` ${error.error}
|
|
45123
|
-
`);
|
|
45124
|
-
}
|
|
45125
|
-
}
|
|
45126
|
-
throw new Error("Operation failed");
|
|
45443
|
+
throw channelCreateError(response.error, "This WhatsApp number is already connected to this agent.");
|
|
45127
45444
|
}
|
|
45128
45445
|
const data = response.data;
|
|
45129
45446
|
writeSuccess("\n\u2705 WhatsApp channel created successfully!\n");
|
|
@@ -45165,22 +45482,7 @@ async function createFacebookChannel(agentApi, agentId) {
|
|
|
45165
45482
|
writeInfo("\n\u{1F4E1} Creating Facebook channel...");
|
|
45166
45483
|
const response = await agentApi.createFacebookChannel(agentId, channelData);
|
|
45167
45484
|
if (!response.success) {
|
|
45168
|
-
|
|
45169
|
-
if (error?.statusCode === 400 && error?.message?.includes("already exists")) {
|
|
45170
|
-
console.error(`
|
|
45171
|
-
\u274C Channel already exists`);
|
|
45172
|
-
console.error(`\u{1F4A1} This Facebook page is already connected to this agent.`);
|
|
45173
|
-
console.error(` Use 'lua channels' to list existing channels.
|
|
45174
|
-
`);
|
|
45175
|
-
} else {
|
|
45176
|
-
console.error(`
|
|
45177
|
-
\u274C Error: ${error?.message || "Unknown error"}`);
|
|
45178
|
-
if (error?.error) {
|
|
45179
|
-
console.error(` ${error.error}
|
|
45180
|
-
`);
|
|
45181
|
-
}
|
|
45182
|
-
}
|
|
45183
|
-
throw new Error("Operation failed");
|
|
45485
|
+
throw channelCreateError(response.error, "This Facebook page is already connected to this agent.");
|
|
45184
45486
|
}
|
|
45185
45487
|
const data = response.data;
|
|
45186
45488
|
writeSuccess("\n\u2705 Facebook channel created successfully!\n");
|
|
@@ -45251,22 +45553,7 @@ async function createEmailChannel(agentApi, agentId) {
|
|
|
45251
45553
|
writeInfo("\n\u{1F4E1} Creating Email channel...");
|
|
45252
45554
|
const response = await agentApi.createEmailChannel(agentId, channelData);
|
|
45253
45555
|
if (!response.success) {
|
|
45254
|
-
|
|
45255
|
-
if (error?.statusCode === 400 && error?.message?.includes("already exists")) {
|
|
45256
|
-
console.error(`
|
|
45257
|
-
\u274C Channel already exists`);
|
|
45258
|
-
console.error(`\u{1F4A1} This email address is already connected to this agent.`);
|
|
45259
|
-
console.error(` Use 'lua channels' to list existing channels.
|
|
45260
|
-
`);
|
|
45261
|
-
} else {
|
|
45262
|
-
console.error(`
|
|
45263
|
-
\u274C Error: ${error?.message || "Unknown error"}`);
|
|
45264
|
-
if (error?.error) {
|
|
45265
|
-
console.error(` ${error.error}
|
|
45266
|
-
`);
|
|
45267
|
-
}
|
|
45268
|
-
}
|
|
45269
|
-
throw new Error("Operation failed");
|
|
45556
|
+
throw channelCreateError(response.error, "This email address is already connected to this agent.");
|
|
45270
45557
|
}
|
|
45271
45558
|
const data = response.data;
|
|
45272
45559
|
writeSuccess("\n\u2705 Email channel created successfully!\n");
|
|
@@ -45339,22 +45626,7 @@ async function createSlackPrivateChannel(agentApi, agentId) {
|
|
|
45339
45626
|
writeInfo("\n\u{1F4E1} Creating Slack private channel...");
|
|
45340
45627
|
const response = await agentApi.createSlackChannel(agentId, channelData);
|
|
45341
45628
|
if (!response.success) {
|
|
45342
|
-
|
|
45343
|
-
if (error?.statusCode === 400 && error?.message?.includes("already exists")) {
|
|
45344
|
-
console.error(`
|
|
45345
|
-
\u274C Channel already exists`);
|
|
45346
|
-
console.error(`\u{1F4A1} This Slack workspace is already connected to this agent.`);
|
|
45347
|
-
console.error(` Use 'lua channels' to list existing channels.
|
|
45348
|
-
`);
|
|
45349
|
-
} else {
|
|
45350
|
-
console.error(`
|
|
45351
|
-
\u274C Error: ${error?.message || "Unknown error"}`);
|
|
45352
|
-
if (error?.error) {
|
|
45353
|
-
console.error(` ${error.error}
|
|
45354
|
-
`);
|
|
45355
|
-
}
|
|
45356
|
-
}
|
|
45357
|
-
throw new Error("Operation failed");
|
|
45629
|
+
throw channelCreateError(response.error, "This Slack workspace is already connected to this agent.");
|
|
45358
45630
|
}
|
|
45359
45631
|
const data = response.data;
|
|
45360
45632
|
if ("slack" in data && "botName" in data.slack) {
|
|
@@ -45409,22 +45681,7 @@ async function createSlackPublicChannel(agentApi, agentId) {
|
|
|
45409
45681
|
writeInfo("\n\u{1F4E1} Creating Slack public channel...");
|
|
45410
45682
|
const response = await agentApi.createSlackChannel(agentId, channelData);
|
|
45411
45683
|
if (!response.success) {
|
|
45412
|
-
|
|
45413
|
-
if (error?.statusCode === 400 && error?.message?.includes("already exists")) {
|
|
45414
|
-
console.error(`
|
|
45415
|
-
\u274C Channel already exists`);
|
|
45416
|
-
console.error(`\u{1F4A1} This Slack app is already connected to this agent.`);
|
|
45417
|
-
console.error(` Use 'lua channels' to list existing channels.
|
|
45418
|
-
`);
|
|
45419
|
-
} else {
|
|
45420
|
-
console.error(`
|
|
45421
|
-
\u274C Error: ${error?.message || "Unknown error"}`);
|
|
45422
|
-
if (error?.error) {
|
|
45423
|
-
console.error(` ${error.error}
|
|
45424
|
-
`);
|
|
45425
|
-
}
|
|
45426
|
-
}
|
|
45427
|
-
throw new Error("Operation failed");
|
|
45684
|
+
throw channelCreateError(response.error, "This Slack app is already connected to this agent.");
|
|
45428
45685
|
}
|
|
45429
45686
|
const data = response.data;
|
|
45430
45687
|
if ("redirectUri" in data) {
|
|
@@ -45481,6 +45738,7 @@ var CallMetricsApi = class extends HttpClient {
|
|
|
45481
45738
|
};
|
|
45482
45739
|
|
|
45483
45740
|
// src/commands/logs.ts
|
|
45741
|
+
init_cli_error();
|
|
45484
45742
|
var ALL_VALID_SOURCES = AGENT_LOG_SOURCES;
|
|
45485
45743
|
var ENTITY_SOURCES = /* @__PURE__ */ new Set([
|
|
45486
45744
|
"skill",
|
|
@@ -45688,20 +45946,14 @@ async function nonInteractiveLogs(logsApi, agentId, apiKey, options) {
|
|
|
45688
45946
|
}
|
|
45689
45947
|
if (options.name) {
|
|
45690
45948
|
if (!filters.logSource) {
|
|
45691
|
-
|
|
45692
|
-
console.log("\nUsage: lua logs --type skill --name mySkill");
|
|
45693
|
-
throw new Error("--type is required when using --name");
|
|
45949
|
+
throw CliError.usage("--type is required when using --name", "Usage: lua logs --type skill --name mySkill");
|
|
45694
45950
|
}
|
|
45695
45951
|
if (NON_ENTITY_SOURCES.has(filters.logSource)) {
|
|
45696
|
-
|
|
45697
|
-
console.log(`
|
|
45698
|
-
Usage: lua logs --type ${filters.logSource} (no --name needed)`);
|
|
45699
|
-
throw new Error("--name is not applicable for ${filters.logSource} type");
|
|
45952
|
+
throw CliError.usage(`--name is not applicable for ${filters.logSource} type`, `Usage: lua logs --type ${filters.logSource} (no --name needed)`);
|
|
45700
45953
|
}
|
|
45701
45954
|
const entityId = await resolveEntityId(apiKey, agentId, filters.logSource, options.name);
|
|
45702
45955
|
if (!entityId) {
|
|
45703
|
-
|
|
45704
|
-
throw new Error(`${capitalize(filters.logSource ?? "")} "${options.name}" not found`);
|
|
45956
|
+
throw CliError.notFound(`${capitalize(filters.logSource ?? "")} "${options.name}" not found`);
|
|
45705
45957
|
}
|
|
45706
45958
|
filters.primitiveId = entityId;
|
|
45707
45959
|
}
|
|
@@ -45710,8 +45962,7 @@ Usage: lua logs --type ${filters.logSource} (no --name needed)`);
|
|
|
45710
45962
|
}
|
|
45711
45963
|
const response = await logsApi.getAgentLogs(agentId, options.limit || 20, options.page || 1, filters);
|
|
45712
45964
|
if (!response.success) {
|
|
45713
|
-
|
|
45714
|
-
throw new Error(`Error: ${response.error?.message || "Unknown error"}`);
|
|
45965
|
+
throw CliError.fromStatus(response.error?.statusCode, response.error?.message || "Unknown error");
|
|
45715
45966
|
}
|
|
45716
45967
|
const data = response.data;
|
|
45717
45968
|
if (options.json) {
|
|
@@ -45923,8 +46174,7 @@ async function viewAgentLogsInteractive(logsApi, agentId, filters = {}) {
|
|
|
45923
46174
|
while (keepViewing) {
|
|
45924
46175
|
const response = await logsApi.getAgentLogs(agentId, limit, currentPage, filters);
|
|
45925
46176
|
if (!response.success) {
|
|
45926
|
-
|
|
45927
|
-
throw new Error("Operation failed");
|
|
46177
|
+
throw CliError.fromStatus(response.error?.statusCode, response.error?.message || "Unknown error");
|
|
45928
46178
|
}
|
|
45929
46179
|
const data = response.data;
|
|
45930
46180
|
displayLogsCore(data.logs, data.pagination, "All Agent Logs", true);
|
|
@@ -46300,6 +46550,7 @@ __name(localVersionLine, "localVersionLine");
|
|
|
46300
46550
|
init_skills_api_service();
|
|
46301
46551
|
init_skill_handler();
|
|
46302
46552
|
init_analytics();
|
|
46553
|
+
init_cli_error();
|
|
46303
46554
|
async function skillsCommand(actionOrEnv, actionArg, cmdObj) {
|
|
46304
46555
|
return withErrorHandling(async () => {
|
|
46305
46556
|
const options = {
|
|
@@ -46580,10 +46831,7 @@ async function executeNonInteractive4(context, config, action, options) {
|
|
|
46580
46831
|
return;
|
|
46581
46832
|
}
|
|
46582
46833
|
if (!options.skillName) {
|
|
46583
|
-
|
|
46584
|
-
console.log(`
|
|
46585
|
-
Usage: lua skills ${action} --skill-name <name>`);
|
|
46586
|
-
throw new Error(`--skill-name is required for action "${action}"`);
|
|
46834
|
+
throw CliError.usage(`--skill-name is required for action "${action}"`, `Usage: lua skills ${action} --skill-name <name>`);
|
|
46587
46835
|
}
|
|
46588
46836
|
let selectedSkill = skills.find((s) => s.skillId === options.skillName || s.name === options.skillName);
|
|
46589
46837
|
if (!selectedSkill && action === "delete") {
|
|
@@ -46602,13 +46850,7 @@ Usage: lua skills ${action} --skill-name <name>`);
|
|
|
46602
46850
|
}
|
|
46603
46851
|
}
|
|
46604
46852
|
if (!selectedSkill) {
|
|
46605
|
-
|
|
46606
|
-
console.log("\nAvailable skills in local config:");
|
|
46607
|
-
skills.forEach((s) => console.log(` - ${s.name} (${s.skillId})`));
|
|
46608
|
-
if (action === "delete") {
|
|
46609
|
-
console.log("\n\u{1F4A1} Tip: The skill may have already been deleted from the server.");
|
|
46610
|
-
}
|
|
46611
|
-
throw new Error(`Skill "${options.skillName}" not found`);
|
|
46853
|
+
throw CliError.notFound(`Skill "${options.skillName}" not found`, joinHint(listHint("Available skills in local config:", skills.map((s) => `${s.name} (${s.skillId})`)), action === "delete" && "Tip: The skill may have already been deleted from the server."));
|
|
46612
46854
|
}
|
|
46613
46855
|
switch (action) {
|
|
46614
46856
|
case "versions": {
|
|
@@ -46624,17 +46866,12 @@ Usage: lua skills ${action} --skill-name <name>`);
|
|
|
46624
46866
|
}
|
|
46625
46867
|
case "deploy": {
|
|
46626
46868
|
if (!options.skillVersion) {
|
|
46627
|
-
|
|
46628
|
-
console.log("\nUsage: lua skills deploy --skill-name mySkill --skill-version 1.0.3");
|
|
46629
|
-
console.log(" lua skills deploy -i mySkill -v latest");
|
|
46630
|
-
throw new Error("--skill-version is required for deploy action");
|
|
46869
|
+
throw CliError.usage("--skill-version is required for deploy action", "Usage: lua skills deploy --skill-name mySkill --skill-version 1.0.3\n lua skills deploy -i mySkill -v latest");
|
|
46631
46870
|
}
|
|
46632
46871
|
const data = await fetchVersionsCore2(context, selectedSkill);
|
|
46633
46872
|
if (!data) throw new Error("Failed to fetch skill versions");
|
|
46634
46873
|
if (data.versions.length === 0) {
|
|
46635
|
-
|
|
46636
|
-
console.log("\u{1F4A1} Push a version first using 'lua push skill'.");
|
|
46637
|
-
throw new Error(`No versions found for ${selectedSkill.name}`);
|
|
46874
|
+
throw CliError.notFound(`No versions found for ${selectedSkill.name}.`, "Push a version first using 'lua push skill'.");
|
|
46638
46875
|
}
|
|
46639
46876
|
const resolvedVersion = resolveVersion(data.versions, options.skillVersion);
|
|
46640
46877
|
if (!resolvedVersion) throw new Error("Failed to resolve skill version");
|
|
@@ -47727,6 +47964,7 @@ init_command_utils();
|
|
|
47727
47964
|
init_webhook_api_service();
|
|
47728
47965
|
init_analytics();
|
|
47729
47966
|
init_dist();
|
|
47967
|
+
init_cli_error();
|
|
47730
47968
|
var AVAILABLE_EVENT_TYPES = Object.values(EventType).filter((event) => event.startsWith("message."));
|
|
47731
47969
|
async function webhooksCommand(action, cmdObj) {
|
|
47732
47970
|
return withErrorHandling(async () => {
|
|
@@ -48055,10 +48293,7 @@ async function executeNonInteractive5(context, config, action, options) {
|
|
|
48055
48293
|
return;
|
|
48056
48294
|
}
|
|
48057
48295
|
if (!options.webhookName) {
|
|
48058
|
-
|
|
48059
|
-
console.log(`
|
|
48060
|
-
Usage: lua webhooks ${normalizedAction} --webhook-name <name>`);
|
|
48061
|
-
throw new Error(`--webhook-name is required for action "${normalizedAction}"`);
|
|
48296
|
+
throw CliError.usage(`--webhook-name is required for action "${normalizedAction}"`, `Usage: lua webhooks ${normalizedAction} --webhook-name <name>`);
|
|
48062
48297
|
}
|
|
48063
48298
|
let selectedWebhook = webhooks.find((w) => w.webhookId === options.webhookName || w.name === options.webhookName);
|
|
48064
48299
|
if (!selectedWebhook && normalizedAction === "delete") {
|
|
@@ -48077,13 +48312,7 @@ Usage: lua webhooks ${normalizedAction} --webhook-name <name>`);
|
|
|
48077
48312
|
}
|
|
48078
48313
|
}
|
|
48079
48314
|
if (!selectedWebhook) {
|
|
48080
|
-
|
|
48081
|
-
console.log("\nAvailable webhooks in local config:");
|
|
48082
|
-
webhooks.forEach((w) => console.log(` - ${w.name} (${w.webhookId})`));
|
|
48083
|
-
if (normalizedAction === "delete") {
|
|
48084
|
-
console.log("\n\u{1F4A1} Tip: The webhook may have already been deleted from the server.");
|
|
48085
|
-
}
|
|
48086
|
-
throw new Error(`Webhook "${options.webhookName}" not found`);
|
|
48315
|
+
throw CliError.notFound(`Webhook "${options.webhookName}" not found`, joinHint(listHint("Available webhooks in local config:", webhooks.map((w) => `${w.name} (${w.webhookId})`)), normalizedAction === "delete" && "Tip: The webhook may have already been deleted from the server."));
|
|
48087
48316
|
}
|
|
48088
48317
|
switch (normalizedAction) {
|
|
48089
48318
|
case "versions": {
|
|
@@ -48099,17 +48328,12 @@ Usage: lua webhooks ${normalizedAction} --webhook-name <name>`);
|
|
|
48099
48328
|
}
|
|
48100
48329
|
case "deploy": {
|
|
48101
48330
|
if (!options.webhookVersion) {
|
|
48102
|
-
|
|
48103
|
-
console.log("\nUsage: lua webhooks deploy --webhook-name myWebhook --webhook-version 1.0.3");
|
|
48104
|
-
console.log(" lua webhooks deploy -i myWebhook -v latest");
|
|
48105
|
-
throw new Error("--webhook-version is required for deploy action");
|
|
48331
|
+
throw CliError.usage("--webhook-version is required for deploy action", "Usage: lua webhooks deploy --webhook-name myWebhook --webhook-version 1.0.3\n lua webhooks deploy -i myWebhook -v latest");
|
|
48106
48332
|
}
|
|
48107
48333
|
const data = await fetchVersionsCore3(context, selectedWebhook);
|
|
48108
48334
|
if (!data) throw new Error("Failed to fetch webhook versions");
|
|
48109
48335
|
if (data.versions.length === 0) {
|
|
48110
|
-
|
|
48111
|
-
console.log("\u{1F4A1} Push a version first using 'lua push webhook'.");
|
|
48112
|
-
throw new Error(`No versions found for ${selectedWebhook.name}`);
|
|
48336
|
+
throw CliError.notFound(`No versions found for ${selectedWebhook.name}.`, "Push a version first using 'lua push webhook'.");
|
|
48113
48337
|
}
|
|
48114
48338
|
const resolvedVersion = resolveVersion2(data.versions, options.webhookVersion);
|
|
48115
48339
|
if (!resolvedVersion) throw new Error("Failed to resolve webhook version");
|
|
@@ -48134,11 +48358,7 @@ Usage: lua webhooks ${normalizedAction} --webhook-name <name>`);
|
|
|
48134
48358
|
}
|
|
48135
48359
|
case "subscribe": {
|
|
48136
48360
|
if (!options.event) {
|
|
48137
|
-
|
|
48138
|
-
console.log("\nUsage: lua webhooks subscribe --webhook-name myWebhook --event message.delivered");
|
|
48139
|
-
console.log("\nAvailable events:");
|
|
48140
|
-
AVAILABLE_EVENT_TYPES.forEach((e) => console.log(` \u2022 ${e}`));
|
|
48141
|
-
throw new Error("--event is required for subscribe action");
|
|
48361
|
+
throw CliError.usage("--event is required for subscribe action", joinHint("Usage: lua webhooks subscribe --webhook-name myWebhook --event message.delivered", listHint("Available events:", AVAILABLE_EVENT_TYPES)));
|
|
48142
48362
|
}
|
|
48143
48363
|
const success2 = await subscribeCore(context, selectedWebhook.webhookId, selectedWebhook.name, options.event);
|
|
48144
48364
|
if (!success2) throw new Error("Failed to subscribe webhook to event");
|
|
@@ -48146,9 +48366,7 @@ Usage: lua webhooks ${normalizedAction} --webhook-name <name>`);
|
|
|
48146
48366
|
}
|
|
48147
48367
|
case "unsubscribe": {
|
|
48148
48368
|
if (!options.event) {
|
|
48149
|
-
|
|
48150
|
-
console.log("\nUsage: lua webhooks unsubscribe --webhook-name myWebhook --event message.delivered");
|
|
48151
|
-
throw new Error("--event is required for unsubscribe action");
|
|
48369
|
+
throw CliError.usage("--event is required for unsubscribe action", "Usage: lua webhooks unsubscribe --webhook-name myWebhook --event message.delivered");
|
|
48152
48370
|
}
|
|
48153
48371
|
const success2 = await unsubscribeCore(context, selectedWebhook.webhookId, selectedWebhook.name, options.event);
|
|
48154
48372
|
if (!success2) throw new Error("Failed to unsubscribe webhook from event");
|
|
@@ -48483,6 +48701,7 @@ init_cli();
|
|
|
48483
48701
|
init_constants();
|
|
48484
48702
|
init_command_utils();
|
|
48485
48703
|
init_analytics();
|
|
48704
|
+
init_cli_error();
|
|
48486
48705
|
var ACCEPTED_TIMEOUT_MS = 12e4;
|
|
48487
48706
|
var DEFAULT_LOGS_LIMIT = 20;
|
|
48488
48707
|
function parseLimitOption(raw) {
|
|
@@ -48866,19 +49085,14 @@ async function executeNonInteractive6(context, action, options) {
|
|
|
48866
49085
|
}
|
|
48867
49086
|
if (normalizedAction === "create") {
|
|
48868
49087
|
if (!options.name) {
|
|
48869
|
-
|
|
48870
|
-
console.log('\nUsage: lua triggers create --name order-created [--description "Fires on new orders"] [--instruction "Reply with the current date and time"]');
|
|
48871
|
-
throw new Error("--name is required for create action");
|
|
49088
|
+
throw CliError.usage("--name is required for create action", 'Usage: lua triggers create --name order-created [--description "Fires on new orders"] [--instruction "Reply with the current date and time"]');
|
|
48872
49089
|
}
|
|
48873
49090
|
const success2 = await createTriggerCore(context, options.name, options.description, options.instruction);
|
|
48874
49091
|
if (!success2) throw new Error("Failed to create trigger");
|
|
48875
49092
|
return;
|
|
48876
49093
|
}
|
|
48877
49094
|
if (!options.trigger) {
|
|
48878
|
-
|
|
48879
|
-
console.log(`
|
|
48880
|
-
Usage: lua triggers ${normalizedAction} --trigger <name|id>`);
|
|
48881
|
-
throw new Error(`--trigger is required for action "${normalizedAction}"`);
|
|
49095
|
+
throw CliError.usage(`--trigger is required for action "${normalizedAction}"`, `Usage: lua triggers ${normalizedAction} --trigger <name|id>`);
|
|
48882
49096
|
}
|
|
48883
49097
|
const triggers = await fetchTriggersCore(context);
|
|
48884
49098
|
if (!triggers) throw new Error("Failed to fetch triggers");
|
|
@@ -49461,6 +49675,7 @@ init_constants();
|
|
|
49461
49675
|
init_command_utils();
|
|
49462
49676
|
init_job_api_service();
|
|
49463
49677
|
init_analytics();
|
|
49678
|
+
init_cli_error();
|
|
49464
49679
|
async function jobsCommand(action, cmdObj) {
|
|
49465
49680
|
return withErrorHandling(async () => {
|
|
49466
49681
|
const options = {
|
|
@@ -49783,10 +49998,7 @@ async function executeNonInteractive7(context, config, action, options) {
|
|
|
49783
49998
|
return;
|
|
49784
49999
|
}
|
|
49785
50000
|
if (!options.jobName) {
|
|
49786
|
-
|
|
49787
|
-
console.log(`
|
|
49788
|
-
Usage: lua jobs ${normalizedAction} --job-name <name>`);
|
|
49789
|
-
throw new Error(`--job-name is required for action "${normalizedAction}"`);
|
|
50001
|
+
throw CliError.usage(`--job-name is required for action "${normalizedAction}"`, `Usage: lua jobs ${normalizedAction} --job-name <name>`);
|
|
49790
50002
|
}
|
|
49791
50003
|
let selectedJob = jobs.find((j) => j.jobId === options.jobName || j.name === options.jobName);
|
|
49792
50004
|
if (!selectedJob && (normalizedAction === "delete" || normalizedAction === "trigger")) {
|
|
@@ -49805,13 +50017,7 @@ Usage: lua jobs ${normalizedAction} --job-name <name>`);
|
|
|
49805
50017
|
}
|
|
49806
50018
|
}
|
|
49807
50019
|
if (!selectedJob) {
|
|
49808
|
-
|
|
49809
|
-
console.log("\nAvailable jobs in local config:");
|
|
49810
|
-
jobs.forEach((j) => console.log(` - ${j.name} (${j.jobId})`));
|
|
49811
|
-
if (normalizedAction === "delete" || normalizedAction === "trigger") {
|
|
49812
|
-
console.log("\n\u{1F4A1} Tip: The job may have already been deleted from the server.");
|
|
49813
|
-
}
|
|
49814
|
-
throw new Error(`Job "${options.jobName}" not found`);
|
|
50020
|
+
throw CliError.notFound(`Job "${options.jobName}" not found`, joinHint(listHint("Available jobs in local config:", jobs.map((j) => `${j.name} (${j.jobId})`)), (normalizedAction === "delete" || normalizedAction === "trigger") && "Tip: The job may have already been deleted from the server."));
|
|
49815
50021
|
}
|
|
49816
50022
|
switch (normalizedAction) {
|
|
49817
50023
|
case "versions": {
|
|
@@ -49827,17 +50033,12 @@ Usage: lua jobs ${normalizedAction} --job-name <name>`);
|
|
|
49827
50033
|
}
|
|
49828
50034
|
case "deploy": {
|
|
49829
50035
|
if (!options.jobVersion) {
|
|
49830
|
-
|
|
49831
|
-
console.log("\nUsage: lua jobs deploy --job-name myJob --job-version 1.0.3");
|
|
49832
|
-
console.log(" lua jobs deploy -i myJob -v latest");
|
|
49833
|
-
throw new Error("--job-version is required for deploy action");
|
|
50036
|
+
throw CliError.usage("--job-version is required for deploy action", "Usage: lua jobs deploy --job-name myJob --job-version 1.0.3\n lua jobs deploy -i myJob -v latest");
|
|
49834
50037
|
}
|
|
49835
50038
|
const dData = await fetchVersionsCore4(context, selectedJob);
|
|
49836
50039
|
if (!dData) throw new Error("Failed to fetch job versions");
|
|
49837
50040
|
if (dData.versions.length === 0) {
|
|
49838
|
-
|
|
49839
|
-
console.log("\u{1F4A1} Push a version first using 'lua push job'.");
|
|
49840
|
-
throw new Error(`No versions found for ${selectedJob.name}`);
|
|
50041
|
+
throw CliError.notFound(`No versions found for ${selectedJob.name}.`, "Push a version first using 'lua push job'.");
|
|
49841
50042
|
}
|
|
49842
50043
|
const resolvedVersion = resolveVersion3(dData.versions, options.jobVersion);
|
|
49843
50044
|
if (!resolvedVersion) throw new Error("Failed to resolve job version");
|
|
@@ -50408,9 +50609,18 @@ async function executeAction(ctx, action, target, extra, o) {
|
|
|
50408
50609
|
// ── retry-step ──
|
|
50409
50610
|
case "retry-step":
|
|
50410
50611
|
return requireRun(runId, "retry-step", () => retryStepCore(ctx, runId, o));
|
|
50612
|
+
// ── resolve-step (LUA-752 — R37; L2.6) ──
|
|
50613
|
+
case "resolve-step":
|
|
50614
|
+
return requireRun(runId, "resolve-step", () => resolveStepCore(ctx, runId, o));
|
|
50615
|
+
// ── raise-budget (LUA-752 — R45; the verb every budget-park hint named) ──
|
|
50616
|
+
case "raise-budget":
|
|
50617
|
+
return requireRun(runId, "raise-budget", () => raiseBudgetCore(ctx, runId, o));
|
|
50411
50618
|
// ── approve ──
|
|
50412
50619
|
case "approve":
|
|
50413
50620
|
return requireRun(runId, "approve", () => approveCore(ctx, runId, o));
|
|
50621
|
+
// ── approval-payload (LUA-752 — R39; the fingerprint `approve --edit` needs) ──
|
|
50622
|
+
case "approval-payload":
|
|
50623
|
+
return requireRun(runId, "approval-payload", () => approvalPayloadCore(ctx, runId, o));
|
|
50414
50624
|
// ── signal ──
|
|
50415
50625
|
case "signal":
|
|
50416
50626
|
return requireRun(runId, "signal", () => signalCore(ctx, runId, extra, o));
|
|
@@ -50429,6 +50639,9 @@ async function executeAction(ctx, action, target, extra, o) {
|
|
|
50429
50639
|
// ── env-overlay (Cluster K, B33 — WF-543; R69) ──
|
|
50430
50640
|
case "env-overlay":
|
|
50431
50641
|
return requireName(name, "env-overlay", () => envOverlayCore(ctx, name, o));
|
|
50642
|
+
// ── export (LUA-752 — WF-403; L6.3): the version back as pushable files ──
|
|
50643
|
+
case "export":
|
|
50644
|
+
return requireName(name, "export", () => exportCore(ctx, name, o));
|
|
50432
50645
|
// ── archive-runs (WF-443 retention hop — client half; R2 → R50 → R51) ──
|
|
50433
50646
|
case "archive-runs":
|
|
50434
50647
|
return archiveRunsCore(ctx, o);
|
|
@@ -50442,7 +50655,7 @@ async function executeAction(ctx, action, target, extra, o) {
|
|
|
50442
50655
|
// ── goals <list|get|create|pause|resume|close> (LUA-627 — R57–R62) ──
|
|
50443
50656
|
case "goals":
|
|
50444
50657
|
return goalsCore(ctx, target, extra, o);
|
|
50445
|
-
// ── schedules <list|delete> (LUA-627
|
|
50658
|
+
// ── schedules <list|create|patch|pause|resume|delete> (LUA-627 reads + R28; LUA-752 R27 / R56; goal-owned rows refuse) ──
|
|
50446
50659
|
case "schedules":
|
|
50447
50660
|
return schedulesCore(ctx, target, extra, o);
|
|
50448
50661
|
case "run":
|
|
@@ -50475,12 +50688,12 @@ function apiFailure(ctx, res, verb) {
|
|
|
50475
50688
|
const err = res.error;
|
|
50476
50689
|
const status = err?.statusCode;
|
|
50477
50690
|
const code = err?.code ?? err?.error;
|
|
50478
|
-
|
|
50479
|
-
|
|
50480
|
-
|
|
50691
|
+
const message = `${verb} failed${code ? ` (${code})` : ""}: ${err?.message ?? "Unknown error"}`;
|
|
50692
|
+
if (status === 0 || status !== void 0 && status >= 500) {
|
|
50693
|
+
throw CliError.fromStatus(status, message, status === 503 && code === "CONTROL_UNAVAILABLE" ? CONTROL_UNAVAILABLE_HINT : void 0);
|
|
50481
50694
|
}
|
|
50695
|
+
if (!ctx.json) console.error(`\u274C ${message}`);
|
|
50482
50696
|
if (status === 404) return WORKFLOW_EXIT.NOT_FOUND;
|
|
50483
|
-
if (status === 0 || status !== void 0 && status >= 500) return WORKFLOW_EXIT.UNAVAILABLE;
|
|
50484
50697
|
return WORKFLOW_EXIT.API;
|
|
50485
50698
|
}
|
|
50486
50699
|
__name(apiFailure, "apiFailure");
|
|
@@ -50716,7 +50929,9 @@ async function startCore(ctx, name, o) {
|
|
|
50716
50929
|
try {
|
|
50717
50930
|
if (o.input) input = parseJsonOrFile(o.input, "--input");
|
|
50718
50931
|
waitSeconds = parseIntFlag(o.wait, "--wait");
|
|
50719
|
-
budgetCredits =
|
|
50932
|
+
budgetCredits = parseIntegerFlag(o.budgetCredits, "--budget-credits", {
|
|
50933
|
+
min: 1
|
|
50934
|
+
});
|
|
50720
50935
|
} catch (e) {
|
|
50721
50936
|
if (e instanceof WorkflowLocalUsageError) {
|
|
50722
50937
|
console.error(`\u274C ${e.message}`);
|
|
@@ -50939,7 +51154,8 @@ function printRun(run, withSteps) {
|
|
|
50939
51154
|
if (kind === "exception") {
|
|
50940
51155
|
console.log(run.status === "running" ? "\n\u26A0\uFE0F Needs a decision \u2014 a step is parked on an exception gate (the run continues past it):" : "\n\u26A0\uFE0F Needs a decision \u2014 the run is parked on an exception gate:");
|
|
50941
51156
|
console.log(` lua workflows retry-step ${id} --step <id>`);
|
|
50942
|
-
console.log(
|
|
51157
|
+
console.log(` lua workflows resolve-step ${id} --step <id> --outcome skip|complete|fail [--output <json|@file>]`);
|
|
51158
|
+
console.log(" To start a repair run instead, decide it from the desktop run page.");
|
|
50943
51159
|
} else if (kind === "budget") {
|
|
50944
51160
|
console.log(`
|
|
50945
51161
|
\u23F8\uFE0F Paused \u2014 run budget reached (${budgetCopy(run)}):`);
|
|
@@ -51257,7 +51473,8 @@ async function cancelCore(ctx, runId, o) {
|
|
|
51257
51473
|
emitJson(ctx, res);
|
|
51258
51474
|
if (!ctx.json) {
|
|
51259
51475
|
const v = res.data;
|
|
51260
|
-
|
|
51476
|
+
const alreadyTerminal = v.transitioned !== true && (v.state === "terminal" || v.state === "abandoned" || TERMINAL2.has(v.status));
|
|
51477
|
+
if (alreadyTerminal) {
|
|
51261
51478
|
writeInfo(`\u2139\uFE0F run ${runId} was already ${v.status} \u2014 nothing to cancel`);
|
|
51262
51479
|
return WORKFLOW_EXIT.OK;
|
|
51263
51480
|
}
|
|
@@ -51337,6 +51554,13 @@ async function retryStepCore(ctx, runId, o) {
|
|
|
51337
51554
|
} else if (res.error?.statusCode === 409 && !ctx.json) {
|
|
51338
51555
|
if (code === "STEP_NOT_PARKED" || code === "step_not_parked") console.error(`\u274C step "${o.step}" is not parked (running, pending or already re-armed) \u2014 nothing to retry`);
|
|
51339
51556
|
else if (code === "RUN_TERMINAL" || code === "run_terminal") console.error(`\u274C run ${runId} is terminal \u2014 start a new run instead`);
|
|
51557
|
+
else if (code === "STEP_RETRY_CAP" || code === "step_retry_cap") {
|
|
51558
|
+
const cap = res.error;
|
|
51559
|
+
const at = typeof cap?.attempt === "number" && typeof cap?.maxAttempts === "number" ? ` (attempt ${cap.attempt} of ${cap.maxAttempts})` : "";
|
|
51560
|
+
console.error(`\u274C step "${o.step}" has reached the retry cap${at} \u2014 resolve it or repair the run:
|
|
51561
|
+
lua workflows resolve-step ${runId} --step ${o.step} --outcome skip|complete|fail
|
|
51562
|
+
to start a repair run instead, decide it from the desktop run page`);
|
|
51563
|
+
}
|
|
51340
51564
|
}
|
|
51341
51565
|
return apiFailure(ctx, res, "retry-step");
|
|
51342
51566
|
}
|
|
@@ -51354,6 +51578,165 @@ async function retryStepCore(ctx, runId, o) {
|
|
|
51354
51578
|
return WORKFLOW_EXIT.OK;
|
|
51355
51579
|
}
|
|
51356
51580
|
__name(retryStepCore, "retryStepCore");
|
|
51581
|
+
function refusalIssues(err) {
|
|
51582
|
+
return err?.issues ?? [];
|
|
51583
|
+
}
|
|
51584
|
+
__name(refusalIssues, "refusalIssues");
|
|
51585
|
+
async function resolveStepCore(ctx, runId, o) {
|
|
51586
|
+
const usage = "lua workflows resolve-step <runId> --step <id> --outcome skip|complete|fail [--output <json|@file>] [--note <text>]";
|
|
51587
|
+
if (!o.step) {
|
|
51588
|
+
console.error(`\u274C --step <id> is required: ${usage}`);
|
|
51589
|
+
return WORKFLOW_EXIT.USAGE;
|
|
51590
|
+
}
|
|
51591
|
+
const raw = (o.outcome ?? o.action)?.trim().toLowerCase();
|
|
51592
|
+
if (raw !== "skip" && raw !== "complete" && raw !== "fail") {
|
|
51593
|
+
console.error(`\u274C --outcome must be skip|complete|fail${raw ? ` (got "${raw}")` : ""}: ${usage}`);
|
|
51594
|
+
return WORKFLOW_EXIT.USAGE;
|
|
51595
|
+
}
|
|
51596
|
+
const outcome = raw;
|
|
51597
|
+
let output;
|
|
51598
|
+
try {
|
|
51599
|
+
if (o.output !== void 0) output = parseJsonOrFile(o.output, "--output");
|
|
51600
|
+
} catch (e) {
|
|
51601
|
+
console.error(`\u274C ${e.message}`);
|
|
51602
|
+
return WORKFLOW_EXIT.USAGE;
|
|
51603
|
+
}
|
|
51604
|
+
if (outcome === "complete" && output === void 0) {
|
|
51605
|
+
console.error(`\u274C --outcome complete needs --output <json|@file> (the output the step would have produced): ${usage}`);
|
|
51606
|
+
return WORKFLOW_EXIT.USAGE;
|
|
51607
|
+
}
|
|
51608
|
+
if (outcome !== "complete" && output !== void 0) {
|
|
51609
|
+
console.error(`\u274C --output rides with --outcome complete only (a ${outcome} carries no output)`);
|
|
51610
|
+
return WORKFLOW_EXIT.USAGE;
|
|
51611
|
+
}
|
|
51612
|
+
const dto = {
|
|
51613
|
+
outcome,
|
|
51614
|
+
...output !== void 0 ? {
|
|
51615
|
+
output
|
|
51616
|
+
} : {},
|
|
51617
|
+
...o.note ? {
|
|
51618
|
+
note: o.note
|
|
51619
|
+
} : {}
|
|
51620
|
+
};
|
|
51621
|
+
const res = await ctx.api.resolveStep(runId, o.step, dto);
|
|
51622
|
+
if (!res.success || !res.data) {
|
|
51623
|
+
const err = res.error;
|
|
51624
|
+
const code = err?.code ?? err?.error;
|
|
51625
|
+
const status = err?.statusCode;
|
|
51626
|
+
if (!ctx.json && err) {
|
|
51627
|
+
if (status === 404 && code === "STEP_NOT_FOUND") {
|
|
51628
|
+
console.error(`\u274C step "${o.step}" does not exist on run ${runId} \u2014 list its steps: lua workflows status ${runId} --steps`);
|
|
51629
|
+
} else if (status === 409 && (code === "STEP_NOT_PARKED" || code === "step_not_parked")) {
|
|
51630
|
+
console.error(`\u274C step "${o.step}" is not parked (running, pending or already decided) \u2014 nothing to resolve`);
|
|
51631
|
+
} else if (status === 409 && (code === "RUN_TERMINAL" || code === "run_terminal")) {
|
|
51632
|
+
console.error(`\u274C run ${runId} is terminal \u2014 start a new run instead`);
|
|
51633
|
+
} else if (status === 400 && code === "RESOLVE_OUTPUT_INVALID") {
|
|
51634
|
+
console.error(`\u274C --output does not satisfy the outputSchema of step "${o.step}":`);
|
|
51635
|
+
for (const i of refusalIssues(err)) console.error(` \u2022 ${i.path ?? "$"}: ${i.message ?? i.code}`);
|
|
51636
|
+
} else if (status === 403 && code === "APPROVAL_REQUIRES_HUMAN") {
|
|
51637
|
+
console.error("\u274C resolve-step is a person's decision \u2014 sign in (lua login) instead of an API key");
|
|
51638
|
+
} else if (status === 413 && code === "OUTPUT_TOO_LARGE") {
|
|
51639
|
+
const { bytes, maxBytes } = err;
|
|
51640
|
+
console.error(`\u274C --output is over the cap (${bytes ?? "?"} of ${maxBytes ?? 262144} bytes serialized)`);
|
|
51641
|
+
}
|
|
51642
|
+
}
|
|
51643
|
+
return apiFailure(ctx, res, "resolve-step");
|
|
51644
|
+
}
|
|
51645
|
+
emitJson(ctx, res);
|
|
51646
|
+
if (!ctx.json) {
|
|
51647
|
+
const d = res.data;
|
|
51648
|
+
if (d.resolved) {
|
|
51649
|
+
const past = d.outcome === "complete" ? "completed" : d.outcome === "skip" ? "skipped" : "failed";
|
|
51650
|
+
writeSuccess(`\u2705 ${past} ${o.step} \xB7 run is ${d.runStatus}` + (d.remainingParks ? ` \xB7 ${d.remainingParks} other parked step(s)` : ""));
|
|
51651
|
+
} else {
|
|
51652
|
+
const standing = d.reason === "already_retried" ? "retried" : `resolved${d.recorded?.outcome ? ` (${d.recorded.outcome})` : ""}`;
|
|
51653
|
+
const by = actorLabel(d.recorded?.by);
|
|
51654
|
+
writeInfo(`\u2139\uFE0F step "${o.step}" was already ${standing}` + (by ? ` by ${by}` : "") + (d.recorded?.at ? ` at ${when(d.recorded.at)}` : "") + ` \xB7 run is ${d.runStatus}`);
|
|
51655
|
+
}
|
|
51656
|
+
}
|
|
51657
|
+
return WORKFLOW_EXIT.OK;
|
|
51658
|
+
}
|
|
51659
|
+
__name(resolveStepCore, "resolveStepCore");
|
|
51660
|
+
function budgetCapFlag(cap) {
|
|
51661
|
+
if (cap === "maxSteps") return "--max-steps";
|
|
51662
|
+
if (cap === "maxJobSeconds") return "--max-job-seconds";
|
|
51663
|
+
if (cap === "maxDurationSeconds") return "--max-duration-seconds";
|
|
51664
|
+
return "--credits";
|
|
51665
|
+
}
|
|
51666
|
+
__name(budgetCapFlag, "budgetCapFlag");
|
|
51667
|
+
function budgetCapsLabel(b) {
|
|
51668
|
+
if (!b) return "";
|
|
51669
|
+
const parts = [];
|
|
51670
|
+
if (b.maxCredits !== void 0) parts.push(`${b.maxCredits} credits`);
|
|
51671
|
+
if (b.maxSteps !== void 0) parts.push(`${b.maxSteps} steps`);
|
|
51672
|
+
if (b.maxJobSeconds !== void 0) parts.push(`${b.maxJobSeconds}s job`);
|
|
51673
|
+
if (b.maxDurationSeconds !== void 0) parts.push(`${b.maxDurationSeconds}s wall`);
|
|
51674
|
+
return parts.join(" \xB7 ");
|
|
51675
|
+
}
|
|
51676
|
+
__name(budgetCapsLabel, "budgetCapsLabel");
|
|
51677
|
+
async function raiseBudgetCore(ctx, runId, o) {
|
|
51678
|
+
let dto;
|
|
51679
|
+
try {
|
|
51680
|
+
dto = {};
|
|
51681
|
+
const credits = parseIntegerFlag(o.credits, "--credits", {
|
|
51682
|
+
min: 1
|
|
51683
|
+
});
|
|
51684
|
+
if (credits !== void 0) dto.maxCredits = credits;
|
|
51685
|
+
const steps = parseIntegerFlag(o.maxSteps, "--max-steps", {
|
|
51686
|
+
min: 1
|
|
51687
|
+
});
|
|
51688
|
+
if (steps !== void 0) dto.maxSteps = steps;
|
|
51689
|
+
const jobSeconds = parseIntegerFlag(o.maxJobSeconds, "--max-job-seconds", {
|
|
51690
|
+
min: 1
|
|
51691
|
+
});
|
|
51692
|
+
if (jobSeconds !== void 0) dto.maxJobSeconds = jobSeconds;
|
|
51693
|
+
const duration = parseIntegerFlag(o.maxDurationSeconds, "--max-duration-seconds", {
|
|
51694
|
+
min: 1
|
|
51695
|
+
});
|
|
51696
|
+
if (duration !== void 0) dto.maxDurationSeconds = duration;
|
|
51697
|
+
if (Object.keys(dto).length === 0) throw new WorkflowLocalUsageError("usage", `--credits <n> (or --max-steps / --max-job-seconds / --max-duration-seconds) is required \u2014 the new cap, above the current one (lua workflows status ${runId} shows it)`);
|
|
51698
|
+
if (o.note) dto.note = o.note;
|
|
51699
|
+
} catch (e) {
|
|
51700
|
+
if (e instanceof WorkflowLocalUsageError) throw CliError.usage(`raise-budget: ${e.message}`);
|
|
51701
|
+
throw e;
|
|
51702
|
+
}
|
|
51703
|
+
const res = await ctx.api.raiseBudget(runId, dto);
|
|
51704
|
+
if (!res.success || !res.data) {
|
|
51705
|
+
const err = res.error;
|
|
51706
|
+
const code = err?.code ?? err?.error;
|
|
51707
|
+
const status = err?.statusCode;
|
|
51708
|
+
if (!ctx.json && err) {
|
|
51709
|
+
if (status === 400 && code === "CAP_EXCEEDED") {
|
|
51710
|
+
const { cap, value: value3, ceiling } = err;
|
|
51711
|
+
console.error(`\u274C ${budgetCapFlag(cap)} ${value3 ?? "?"} is above the org ceiling${ceiling !== void 0 ? ` (${ceiling})` : ""} \u2014 ask an org admin to raise the org cap, or cancel the run`);
|
|
51712
|
+
} else if (status === 400 && code === "VALIDATION_FAILED") {
|
|
51713
|
+
for (const i of refusalIssues(err)) console.error(` ${i.code}${i.path ? ` at ${i.path}` : ""}${i.message ? ` \u2014 ${i.message}` : ""}`);
|
|
51714
|
+
console.error(` the raise must be above the current cap \u2014 lua workflows status ${runId} shows it`);
|
|
51715
|
+
} else if (status === 409 && code === "BUDGET_NOT_RAISABLE") {
|
|
51716
|
+
const { status: runStatus, notRaisableReason } = err;
|
|
51717
|
+
console.error(notRaisableReason === "raise_cap" ? `\u274C run ${runId} has reached its raise cap \u2014 cancel it, or start a new run with a larger --budget-credits` : `\u274C run ${runId} is ${runStatus ?? "not parked on its budget"} \u2014 only a run parked on its budget takes a raise`);
|
|
51718
|
+
} else if (status === 403 && code === "NOT_RUN_CREATOR") {
|
|
51719
|
+
console.error("\u274C only the run creator or an org admin can raise a run budget");
|
|
51720
|
+
}
|
|
51721
|
+
}
|
|
51722
|
+
return apiFailure(ctx, res, "raise-budget");
|
|
51723
|
+
}
|
|
51724
|
+
emitJson(ctx, res);
|
|
51725
|
+
if (!ctx.json) {
|
|
51726
|
+
const d = res.data;
|
|
51727
|
+
const caps = budgetCapsLabel(d.budget ?? d.to);
|
|
51728
|
+
if (d.raised) {
|
|
51729
|
+
const delta = d.from && d.to ? ` (${budgetCapsLabel(d.from)} \u2192 ${budgetCapsLabel(d.to)})` : caps ? ` to ${caps}` : "";
|
|
51730
|
+
writeSuccess(`\u2705 budget raised${delta}${d.runStatus ? ` \xB7 run is ${d.runStatus}` : ""}`);
|
|
51731
|
+
if (d.resumed === false) writeInfo(`\u2139\uFE0F the run did not resume on this raise \u2014 the next step's reserve is still short (raise again), or nothing was parked: lua workflows status ${runId}`);
|
|
51732
|
+
else if (d.resumed) writeInfo(`\u{1F4A1} Follow it: lua workflows watch ${runId}`);
|
|
51733
|
+
} else {
|
|
51734
|
+
writeInfo(`\u2139\uFE0F budget unchanged (${d.reason ?? "already_raised"})${caps ? ` \xB7 ${caps}` : ""}${d.runStatus ? ` \xB7 run is ${d.runStatus}` : ""}`);
|
|
51735
|
+
}
|
|
51736
|
+
}
|
|
51737
|
+
return WORKFLOW_EXIT.OK;
|
|
51738
|
+
}
|
|
51739
|
+
__name(raiseBudgetCore, "raiseBudgetCore");
|
|
51357
51740
|
function approveResultLine(d) {
|
|
51358
51741
|
if (d.resolved) return `\u2705 ${d.outcome} \xB7 run is ${d.runStatus}`;
|
|
51359
51742
|
const ref = d.decidedBy;
|
|
@@ -51407,6 +51790,73 @@ async function approveCore(ctx, runId, o) {
|
|
|
51407
51790
|
return WORKFLOW_EXIT.OK;
|
|
51408
51791
|
}
|
|
51409
51792
|
__name(approveCore, "approveCore");
|
|
51793
|
+
var indentBlock = /* @__PURE__ */ __name((text, pad2 = " ") => text.split("\n").map((l) => `${pad2}${l}`).join("\n"), "indentBlock");
|
|
51794
|
+
var APPROVAL_PAYLOAD_PAGE_MAX = 100;
|
|
51795
|
+
async function approvalPayloadCore(ctx, runId, o) {
|
|
51796
|
+
if (!o.approval) {
|
|
51797
|
+
console.error("\u274C approval-payload: --approval <id> is required \u2014 lua workflows approval-payload <runId> --approval <wfa_\u2026> [--path <array.path>]");
|
|
51798
|
+
return WORKFLOW_EXIT.USAGE;
|
|
51799
|
+
}
|
|
51800
|
+
let limit;
|
|
51801
|
+
try {
|
|
51802
|
+
limit = parseIntegerFlag(o.limit, "--limit", {
|
|
51803
|
+
min: 1,
|
|
51804
|
+
max: APPROVAL_PAYLOAD_PAGE_MAX
|
|
51805
|
+
});
|
|
51806
|
+
} catch (e) {
|
|
51807
|
+
if (e instanceof WorkflowLocalUsageError) throw CliError.usage(`approval-payload: ${e.message}`);
|
|
51808
|
+
throw e;
|
|
51809
|
+
}
|
|
51810
|
+
if ((o.cursor || limit !== void 0) && !o.path) {
|
|
51811
|
+
console.error("\u274C approval-payload: --cursor / --limit page one array \u2014 pass --path <array.path> with them");
|
|
51812
|
+
return WORKFLOW_EXIT.USAGE;
|
|
51813
|
+
}
|
|
51814
|
+
const res = await ctx.api.getApprovalPayload(runId, o.approval, {
|
|
51815
|
+
path: o.path,
|
|
51816
|
+
cursor: o.cursor,
|
|
51817
|
+
limit
|
|
51818
|
+
});
|
|
51819
|
+
if (!res.success || !res.data) {
|
|
51820
|
+
const code = res.error?.code ?? res.error?.error;
|
|
51821
|
+
if (!ctx.json && res.error?.statusCode === 404 && code === "APPROVAL_NOT_FOUND") {
|
|
51822
|
+
console.error(`\u274C approval "${o.approval}" not found on run ${runId} \u2014 lua workflows status ${runId} --steps --json shows the suspended step's suspend.approvalId`);
|
|
51823
|
+
} else if (!ctx.json && res.error?.statusCode === 413 && code === "PAYLOAD_PAGE_REQUIRED") {
|
|
51824
|
+
console.error("\u274C the payload is too large to read whole \u2014 page an array with --path <array.path> [--limit <n>] [--cursor <c>]");
|
|
51825
|
+
}
|
|
51826
|
+
return apiFailure(ctx, res, "approval-payload");
|
|
51827
|
+
}
|
|
51828
|
+
emitJson(ctx, res);
|
|
51829
|
+
if (!ctx.json) {
|
|
51830
|
+
const v = res.data;
|
|
51831
|
+
console.log(`
|
|
51832
|
+
\u{1F9FE} Approval ${v.approvalId} \xB7 revision ${v.editRevision} \xB7 fingerprint ${v.payloadFingerprint ?? "(none)"}`);
|
|
51833
|
+
console.log(` Editable: ${v.editable ? `yes \u2014 ${v.editablePaths.length ? v.editablePaths.join(", ") : "any path"}` : "no"}${v.size !== void 0 ? ` \xB7 ${v.size} bytes` : ""}`);
|
|
51834
|
+
if (v.kind === "whole") {
|
|
51835
|
+
console.log(` Payload:
|
|
51836
|
+
${indentBlock(JSON.stringify(v.payload, null, 2))}`);
|
|
51837
|
+
} else if (v.kind === "paged") {
|
|
51838
|
+
console.log(" Payload: paged \u2014 read one array at a time with --path <array.path>:");
|
|
51839
|
+
for (const [p, a] of Object.entries(v.arrays)) console.log(` ${p} (${a.totalItems} items)`);
|
|
51840
|
+
} else {
|
|
51841
|
+
console.log(` ${v.path}: ${v.items.length} of ${v.totalItems} item(s)${v.nextCursor ? ` \xB7 next page: --cursor ${v.nextCursor}` : ""}`);
|
|
51842
|
+
for (const it of v.items) console.log(` [${it.index}] ${JSON.stringify(it.value)}`);
|
|
51843
|
+
}
|
|
51844
|
+
if (v.editable && v.payloadFingerprint) {
|
|
51845
|
+
writeHintBlock({
|
|
51846
|
+
headline: "Edit and approve against this revision:",
|
|
51847
|
+
lines: [
|
|
51848
|
+
{
|
|
51849
|
+
label: "Approve:",
|
|
51850
|
+
command: `lua workflows approve ${runId} --approval ${v.approvalId} --edit @edited.json --fingerprint ${v.payloadFingerprint}`
|
|
51851
|
+
}
|
|
51852
|
+
],
|
|
51853
|
+
when: "success"
|
|
51854
|
+
});
|
|
51855
|
+
}
|
|
51856
|
+
}
|
|
51857
|
+
return WORKFLOW_EXIT.OK;
|
|
51858
|
+
}
|
|
51859
|
+
__name(approvalPayloadCore, "approvalPayloadCore");
|
|
51410
51860
|
function actorLabel(by, now = Date.now()) {
|
|
51411
51861
|
if (by === void 0 || by === null) return void 0;
|
|
51412
51862
|
if (typeof by === "string") return by;
|
|
@@ -51790,6 +52240,51 @@ async function envOverlayCore(ctx, name, o) {
|
|
|
51790
52240
|
return missing.length > 0 ? WORKFLOW_EXIT.API : WORKFLOW_EXIT.OK;
|
|
51791
52241
|
}
|
|
51792
52242
|
__name(envOverlayCore, "envOverlayCore");
|
|
52243
|
+
async function exportCore(ctx, name, o) {
|
|
52244
|
+
const wf = await resolveWorkflow(ctx, name);
|
|
52245
|
+
if (!wf) return WORKFLOW_EXIT.NOT_FOUND;
|
|
52246
|
+
let version;
|
|
52247
|
+
if (o.workflowVersion) {
|
|
52248
|
+
const ref = await resolveVersionRef(ctx, wf, o.workflowVersion, "export");
|
|
52249
|
+
if ("exit" in ref) return ref.exit;
|
|
52250
|
+
version = ref.version.id;
|
|
52251
|
+
}
|
|
52252
|
+
const res = await ctx.api.exportWorkflowFiles(wf.id, version);
|
|
52253
|
+
if (!res.success || !res.data) {
|
|
52254
|
+
const code = res.error?.code ?? res.error?.error;
|
|
52255
|
+
if (!ctx.json && res.error?.statusCode === 404 && code === "VERSION_NOT_FOUND") console.error(`\u274C "${wf.name}" has no active version to export \u2014 pass -v <version|latest>`);
|
|
52256
|
+
return apiFailure(ctx, res, "export");
|
|
52257
|
+
}
|
|
52258
|
+
emitJson(ctx, res);
|
|
52259
|
+
if (ctx.json) return WORKFLOW_EXIT.OK;
|
|
52260
|
+
const fs19 = await import("fs");
|
|
52261
|
+
const path25 = await import("path");
|
|
52262
|
+
const outDir = path25.resolve(o.out ?? ".");
|
|
52263
|
+
const d = res.data;
|
|
52264
|
+
const escaping = d.files.filter((f) => !path25.resolve(outDir, f.path).startsWith(outDir + path25.sep));
|
|
52265
|
+
if (escaping.length > 0) {
|
|
52266
|
+
console.error(`\u274C EXPORT_PATH_ESCAPES: the server named ${escaping.map((f) => JSON.stringify(f.path)).join(", ")} \u2014 outside --out ${outDir}; nothing written`);
|
|
52267
|
+
return WORKFLOW_EXIT.API;
|
|
52268
|
+
}
|
|
52269
|
+
const clash = d.files.filter((f) => fs19.existsSync(path25.join(outDir, f.path)));
|
|
52270
|
+
if (clash.length > 0 && !o.force) {
|
|
52271
|
+
console.error(`\u274C export: ${clash.map((f) => f.path).join(", ")} already exist${clash.length === 1 ? "s" : ""} under ${outDir} \u2014 pass --force to overwrite, or --out <dir>`);
|
|
52272
|
+
return WORKFLOW_EXIT.API;
|
|
52273
|
+
}
|
|
52274
|
+
for (const f of d.files) {
|
|
52275
|
+
const target = path25.join(outDir, f.path);
|
|
52276
|
+
fs19.mkdirSync(path25.dirname(target), {
|
|
52277
|
+
recursive: true
|
|
52278
|
+
});
|
|
52279
|
+
fs19.writeFileSync(target, f.contents);
|
|
52280
|
+
console.log(` ${f.path}`);
|
|
52281
|
+
}
|
|
52282
|
+
writeSuccess(`\u2705 exported "${wf.name}" v${d.version} (${d.form} form) \u2014 ${d.files.length} file(s) under ${outDir}`);
|
|
52283
|
+
for (const w of d.warnings ?? []) console.warn(`\u26A0\uFE0F ${w.code}${w.path ? ` at ${w.path}` : ""}: ${w.message}`);
|
|
52284
|
+
if (d.warnings?.length) writeInfo("\u{1F4A1} Review the TODOs the warnings name; `lua push workflow` then mints a static version from the file.");
|
|
52285
|
+
return WORKFLOW_EXIT.OK;
|
|
52286
|
+
}
|
|
52287
|
+
__name(exportCore, "exportCore");
|
|
51793
52288
|
function parseSinceFlag(raw, now = Date.now()) {
|
|
51794
52289
|
if (!raw) return NaN;
|
|
51795
52290
|
const m = /^(\d+)([dhm])$/i.exec(raw.trim());
|
|
@@ -51802,6 +52297,9 @@ function parseSinceFlag(raw, now = Date.now()) {
|
|
|
51802
52297
|
}
|
|
51803
52298
|
__name(parseSinceFlag, "parseSinceFlag");
|
|
51804
52299
|
var ARCHIVE_EXPORT_TTL_DAYS = 7;
|
|
52300
|
+
var ARCHIVE_TERMINAL_STATUS_FILTER = [
|
|
52301
|
+
...TERMINAL2
|
|
52302
|
+
].join(",");
|
|
51805
52303
|
var ARCHIVE_DEFAULT_RETENTION_DAYS = 90;
|
|
51806
52304
|
var archiveDownload = {
|
|
51807
52305
|
fetchBytes: /* @__PURE__ */ __name(async (url) => {
|
|
@@ -51865,8 +52363,8 @@ async function archiveRunsCore(ctx, o) {
|
|
|
51865
52363
|
let cursor;
|
|
51866
52364
|
do {
|
|
51867
52365
|
const res = await ctx.api.getRuns({
|
|
51868
|
-
status:
|
|
51869
|
-
since:
|
|
52366
|
+
status: ARCHIVE_TERMINAL_STATUS_FILTER,
|
|
52367
|
+
since: String(since),
|
|
51870
52368
|
workflowId,
|
|
51871
52369
|
tag: o.tag,
|
|
51872
52370
|
cursor,
|
|
@@ -52238,6 +52736,10 @@ var GOAL_VERBS = [
|
|
|
52238
52736
|
];
|
|
52239
52737
|
var SCHEDULE_VERBS = [
|
|
52240
52738
|
"list",
|
|
52739
|
+
"create",
|
|
52740
|
+
"patch",
|
|
52741
|
+
"pause",
|
|
52742
|
+
"resume",
|
|
52241
52743
|
"delete"
|
|
52242
52744
|
];
|
|
52243
52745
|
var GOAL_STATUSES = [
|
|
@@ -52920,11 +53422,13 @@ async function schedulesCore(ctx, target, extra, o) {
|
|
|
52920
53422
|
const verb = subVerb("workflows.schedules.action", "schedules", target, SCHEDULE_VERBS);
|
|
52921
53423
|
if (!verb) return WORKFLOW_EXIT.USAGE;
|
|
52922
53424
|
if (verb === "list") return schedulesListCore(ctx, o);
|
|
53425
|
+
if (verb === "create") return schedulesCreateCore(ctx, o, extra);
|
|
52923
53426
|
if (!extra) {
|
|
52924
|
-
console.error(
|
|
53427
|
+
console.error(`\u274C schedules ${verb}: a schedule (job) id is required \u2014 lua workflows schedules ${verb} <jobId>`);
|
|
52925
53428
|
return WORKFLOW_EXIT.USAGE;
|
|
52926
53429
|
}
|
|
52927
|
-
return schedulesDeleteCore(ctx, extra, o);
|
|
53430
|
+
if (verb === "delete") return schedulesDeleteCore(ctx, extra, o);
|
|
53431
|
+
return schedulesPatchCore(ctx, extra, verb, o);
|
|
52928
53432
|
}
|
|
52929
53433
|
__name(schedulesCore, "schedulesCore");
|
|
52930
53434
|
async function schedulesListCore(ctx, o) {
|
|
@@ -53028,12 +53532,183 @@ async function schedulesDeleteCore(ctx, jobId, o) {
|
|
|
53028
53532
|
return WORKFLOW_EXIT.OK;
|
|
53029
53533
|
}
|
|
53030
53534
|
__name(schedulesDeleteCore, "schedulesDeleteCore");
|
|
53535
|
+
var SCHEDULE_NOTIFY = [
|
|
53536
|
+
"emailApp",
|
|
53537
|
+
"email",
|
|
53538
|
+
"app",
|
|
53539
|
+
"off"
|
|
53540
|
+
];
|
|
53541
|
+
async function schedulesCreateCore(ctx, o, positional) {
|
|
53542
|
+
const target = positional ?? o.workflowName ?? o.workflow;
|
|
53543
|
+
if (!target) {
|
|
53544
|
+
console.error('\u274C schedules create: a workflow is required \u2014 lua workflows schedules create <workflow> --cadence "0 9 * * 1" --timezone Europe/London');
|
|
53545
|
+
return WORKFLOW_EXIT.USAGE;
|
|
53546
|
+
}
|
|
53547
|
+
let draft;
|
|
53548
|
+
try {
|
|
53549
|
+
const usage = /* @__PURE__ */ __name((m) => new WorkflowLocalUsageError("usage", m), "usage");
|
|
53550
|
+
if (o.every && o.cadence?.length) throw usage("--every and --cadence are alternatives \u2014 pass one");
|
|
53551
|
+
const schedules = o.every ? parseEveryFlag(o.every) : parseCadenceFlag(o.cadence, o.timezone);
|
|
53552
|
+
if (schedules.length === 0) throw usage("--cadence <cron|json|@file> (repeatable, \u2264 5) or --every <interval> is required");
|
|
53553
|
+
draft = {
|
|
53554
|
+
schedules
|
|
53555
|
+
};
|
|
53556
|
+
if (o.input) draft.input = parseJsonOrFile(o.input, "--input");
|
|
53557
|
+
if (o.tag?.length) {
|
|
53558
|
+
if (o.tag.length > 10) throw usage("--tag: at most 10");
|
|
53559
|
+
draft.tags = o.tag;
|
|
53560
|
+
}
|
|
53561
|
+
if (o.notify !== void 0) {
|
|
53562
|
+
if (!SCHEDULE_NOTIFY.includes(o.notify)) throw usage(`--notify: expected ${SCHEDULE_NOTIFY.join("|")} (got "${o.notify}")`);
|
|
53563
|
+
draft.notify = o.notify;
|
|
53564
|
+
}
|
|
53565
|
+
const credits = parseIntegerFlag(o.budgetCredits, "--budget-credits", {
|
|
53566
|
+
min: 1
|
|
53567
|
+
});
|
|
53568
|
+
if (credits !== void 0) draft.budget = {
|
|
53569
|
+
maxCredits: credits
|
|
53570
|
+
};
|
|
53571
|
+
const backfill = parseIntegerFlag(o.backfillOnEnable, "--backfill-on-enable", {
|
|
53572
|
+
min: 1
|
|
53573
|
+
});
|
|
53574
|
+
if (backfill !== void 0) draft.backfillOnEnable = {
|
|
53575
|
+
maxOccurrences: backfill
|
|
53576
|
+
};
|
|
53577
|
+
} catch (e) {
|
|
53578
|
+
if (e instanceof WorkflowLocalUsageError) throw CliError.usage(`schedules create: ${e.message}`);
|
|
53579
|
+
throw e;
|
|
53580
|
+
}
|
|
53581
|
+
const wf = await resolveWorkflow(ctx, target);
|
|
53582
|
+
if (!wf) return WORKFLOW_EXIT.NOT_FOUND;
|
|
53583
|
+
const dto = {
|
|
53584
|
+
workflowId: wf.id,
|
|
53585
|
+
...draft
|
|
53586
|
+
};
|
|
53587
|
+
if (o.workflowVersion) {
|
|
53588
|
+
const ref = await resolveVersionRef(ctx, wf, o.workflowVersion, "schedules create");
|
|
53589
|
+
if ("exit" in ref) return ref.exit;
|
|
53590
|
+
dto.workflowVersionId = ref.version.id;
|
|
53591
|
+
}
|
|
53592
|
+
const res = await ctx.api.createSchedule(dto);
|
|
53593
|
+
if (!res.success || !res.data) {
|
|
53594
|
+
const code = res.error?.code ?? res.error?.error;
|
|
53595
|
+
if (!ctx.json && res.error?.statusCode === 409 && code === "SCHEDULE_CAP") console.error("\u274C a schedule takes at most 5 trigger slots (SCHEDULE_CAP) \u2014 fewer --cadence entries");
|
|
53596
|
+
return goalFailure(ctx, res, "schedules create", wf.name);
|
|
53597
|
+
}
|
|
53598
|
+
emitJson(ctx, res);
|
|
53599
|
+
if (!ctx.json) {
|
|
53600
|
+
const s = res.data;
|
|
53601
|
+
const slots = (s.schedules ?? []).map((t) => triggerLabel(t)).join(" \xB7 ") || cadenceLabel(dto.schedules);
|
|
53602
|
+
writeSuccess(`\u2705 schedule ${s.jobId} on "${wf.name}" \xB7 ${slots} \xB7 next ${when(s.nextRunAt ?? void 0)}${s.notify ? ` \xB7 notify ${s.notify}` : ""}`);
|
|
53603
|
+
writeHintBlock({
|
|
53604
|
+
headline: "Manage it:",
|
|
53605
|
+
lines: [
|
|
53606
|
+
{
|
|
53607
|
+
label: "List:",
|
|
53608
|
+
command: `lua workflows schedules list -i ${wf.name}`
|
|
53609
|
+
},
|
|
53610
|
+
{
|
|
53611
|
+
label: "Pause:",
|
|
53612
|
+
command: `lua workflows schedules pause ${s.jobId}`
|
|
53613
|
+
},
|
|
53614
|
+
{
|
|
53615
|
+
label: "Delete:",
|
|
53616
|
+
command: `lua workflows schedules delete ${s.jobId}`
|
|
53617
|
+
}
|
|
53618
|
+
],
|
|
53619
|
+
when: "success"
|
|
53620
|
+
});
|
|
53621
|
+
}
|
|
53622
|
+
return WORKFLOW_EXIT.OK;
|
|
53623
|
+
}
|
|
53624
|
+
__name(schedulesCreateCore, "schedulesCreateCore");
|
|
53625
|
+
async function scheduleGoalOwner(ctx, row2) {
|
|
53626
|
+
if (row2.goalId) return {
|
|
53627
|
+
goalId: row2.goalId
|
|
53628
|
+
};
|
|
53629
|
+
const goals = await loadGoals(ctx, row2.workflowId);
|
|
53630
|
+
if (goals.error) return {
|
|
53631
|
+
error: goals.error
|
|
53632
|
+
};
|
|
53633
|
+
return {
|
|
53634
|
+
goalId: goals.items.find((g) => g.jobId === row2.jobId)?.goalId
|
|
53635
|
+
};
|
|
53636
|
+
}
|
|
53637
|
+
__name(scheduleGoalOwner, "scheduleGoalOwner");
|
|
53638
|
+
async function schedulesPatchCore(ctx, jobId, verb, o) {
|
|
53639
|
+
const label = `schedules ${verb}`;
|
|
53640
|
+
let dto;
|
|
53641
|
+
try {
|
|
53642
|
+
const usage = /* @__PURE__ */ __name((m) => new WorkflowLocalUsageError("usage", m), "usage");
|
|
53643
|
+
dto = {};
|
|
53644
|
+
if (verb === "pause") dto.paused = true;
|
|
53645
|
+
else if (verb === "resume") dto.paused = false;
|
|
53646
|
+
else if (o.paused !== void 0) {
|
|
53647
|
+
const v = String(o.paused).trim().toLowerCase();
|
|
53648
|
+
if (v !== "true" && v !== "false") throw usage(`--paused: expected true|false (got "${o.paused}")`);
|
|
53649
|
+
dto.paused = v === "true";
|
|
53650
|
+
}
|
|
53651
|
+
if (o.backfillOnEnable !== void 0) {
|
|
53652
|
+
if (String(o.backfillOnEnable).trim().toLowerCase() === "none") dto.backfillOnEnable = null;
|
|
53653
|
+
else dto.backfillOnEnable = {
|
|
53654
|
+
maxOccurrences: parseIntegerFlag(o.backfillOnEnable, "--backfill-on-enable", {
|
|
53655
|
+
min: 1
|
|
53656
|
+
})
|
|
53657
|
+
};
|
|
53658
|
+
}
|
|
53659
|
+
if (o.backfillNow) {
|
|
53660
|
+
if (dto.paused !== false) throw usage("--backfill-now rides a re-enable only \u2014 lua workflows schedules resume <jobId> --backfill-now (or patch --paused false)");
|
|
53661
|
+
dto.backfillNow = true;
|
|
53662
|
+
}
|
|
53663
|
+
if (Object.keys(dto).length === 0) throw usage("nothing to change \u2014 pass --paused true|false, --backfill-on-enable <n|none> and/or --backfill-now");
|
|
53664
|
+
} catch (e) {
|
|
53665
|
+
if (e instanceof WorkflowLocalUsageError) throw CliError.usage(`${label}: ${e.message}`);
|
|
53666
|
+
throw e;
|
|
53667
|
+
}
|
|
53668
|
+
const rowRes = await ctx.api.getSchedule(jobId);
|
|
53669
|
+
if (!rowRes.success || !rowRes.data) return apiFailure(ctx, rowRes, label);
|
|
53670
|
+
const owner = await scheduleGoalOwner(ctx, rowRes.data);
|
|
53671
|
+
if (owner.error) {
|
|
53672
|
+
if (!ctx.json) console.error(`\u274C cannot prove ${jobId} is not a goal's cadence (goals unavailable) \u2014 refusing to ${verb}`);
|
|
53673
|
+
return apiFailure(ctx, {
|
|
53674
|
+
success: false,
|
|
53675
|
+
error: owner.error
|
|
53676
|
+
}, label);
|
|
53677
|
+
}
|
|
53678
|
+
if (owner.goalId) {
|
|
53679
|
+
const message = `Schedule ${jobId} is the cadence of goal ${owner.goalId} and was NOT changed. Pause or resume the goal instead: lua workflows goals pause ${owner.goalId} / lua workflows goals resume ${owner.goalId} \u2014 a goal's Job follows its goal, never the other way round.`;
|
|
53680
|
+
if (ctx.json) console.log(JSON.stringify({
|
|
53681
|
+
success: false,
|
|
53682
|
+
error: {
|
|
53683
|
+
code: "goal_schedule",
|
|
53684
|
+
statusCode: 409,
|
|
53685
|
+
message,
|
|
53686
|
+
jobId,
|
|
53687
|
+
goalId: owner.goalId
|
|
53688
|
+
}
|
|
53689
|
+
}, null, 2));
|
|
53690
|
+
else console.error(`\u274C goal_schedule: ${message}`);
|
|
53691
|
+
return WORKFLOW_EXIT.API;
|
|
53692
|
+
}
|
|
53693
|
+
const res = await ctx.api.updateSchedule(jobId, dto);
|
|
53694
|
+
if (!res.success || !res.data) return goalFailure(ctx, res, label, jobId);
|
|
53695
|
+
emitJson(ctx, res);
|
|
53696
|
+
if (!ctx.json) {
|
|
53697
|
+
const s = res.data;
|
|
53698
|
+
writeSuccess(`\u2705 schedule ${s.jobId} ${s.status}${s.backfillOnEnable ? ` \xB7 backfill on enable \u2264 ${s.backfillOnEnable.maxOccurrences}` : ""}`);
|
|
53699
|
+
if (s.backfill) writeInfo(`\u2139\uFE0F backfill on this re-enable: ${JSON.stringify(s.backfill)}`);
|
|
53700
|
+
if (dto.paused === false && s.status !== "active") writeInfo(`\u2139\uFE0F the schedule reads ${s.status} after the re-enable \u2014 lua workflows schedules list shows why (strikes / autoDisabled)`);
|
|
53701
|
+
}
|
|
53702
|
+
return WORKFLOW_EXIT.OK;
|
|
53703
|
+
}
|
|
53704
|
+
__name(schedulesPatchCore, "schedulesPatchCore");
|
|
53031
53705
|
|
|
53032
53706
|
// src/commands/features.ts
|
|
53033
53707
|
init_cli();
|
|
53034
53708
|
init_constants();
|
|
53035
53709
|
init_command_utils();
|
|
53036
53710
|
init_analytics();
|
|
53711
|
+
init_cli_error();
|
|
53037
53712
|
async function featuresCommand(action, cmdObj) {
|
|
53038
53713
|
return withErrorHandling(async () => {
|
|
53039
53714
|
const options = {
|
|
@@ -53206,21 +53881,11 @@ async function executeNonInteractive8(context, action, options) {
|
|
|
53206
53881
|
return;
|
|
53207
53882
|
}
|
|
53208
53883
|
if (!options.featureName) {
|
|
53209
|
-
|
|
53210
|
-
console.log(`
|
|
53211
|
-
Usage: lua features ${normalizedAction} --feature-name <name>`);
|
|
53212
|
-
if (features.length > 0) {
|
|
53213
|
-
console.log("\nAvailable features:");
|
|
53214
|
-
features.forEach((f) => console.log(` - ${f.name} (${f.title})`));
|
|
53215
|
-
}
|
|
53216
|
-
throw new Error("Operation failed");
|
|
53884
|
+
throw CliError.usage(`--feature-name is required for action "${normalizedAction}"`, joinHint(`Usage: lua features ${normalizedAction} --feature-name <name>`, listHint("Available features:", features.map((f) => `${f.name} (${f.title})`))));
|
|
53217
53885
|
}
|
|
53218
53886
|
const selectedFeature = findFeature(features, options.featureName);
|
|
53219
53887
|
if (!selectedFeature) {
|
|
53220
|
-
|
|
53221
|
-
console.log("\nAvailable features:");
|
|
53222
|
-
features.forEach((f) => console.log(` - ${f.name} (${f.title})`));
|
|
53223
|
-
throw new Error("Feature");
|
|
53888
|
+
throw CliError.notFound(`Feature "${options.featureName}" not found`, listHint("Available features:", features.map((f) => `${f.name} (${f.title})`)));
|
|
53224
53889
|
}
|
|
53225
53890
|
switch (normalizedAction) {
|
|
53226
53891
|
case "view":
|
|
@@ -53533,6 +54198,7 @@ init_cli();
|
|
|
53533
54198
|
init_constants();
|
|
53534
54199
|
init_command_utils();
|
|
53535
54200
|
init_analytics();
|
|
54201
|
+
init_cli_error();
|
|
53536
54202
|
async function preprocessorsCommand(action, cmdObj) {
|
|
53537
54203
|
return withErrorHandling(async () => {
|
|
53538
54204
|
const options = {
|
|
@@ -53761,10 +54427,7 @@ async function executeNonInteractive9(context, config, action, options) {
|
|
|
53761
54427
|
return;
|
|
53762
54428
|
}
|
|
53763
54429
|
if (!options.preprocessorName) {
|
|
53764
|
-
|
|
53765
|
-
console.log(`
|
|
53766
|
-
Usage: lua preprocessors ${normalizedAction} --preprocessor-name <name>`);
|
|
53767
|
-
throw new Error(`--preprocessor-name is required for action "${normalizedAction}"`);
|
|
54430
|
+
throw CliError.usage(`--preprocessor-name is required for action "${normalizedAction}"`, `Usage: lua preprocessors ${normalizedAction} --preprocessor-name <name>`);
|
|
53768
54431
|
}
|
|
53769
54432
|
let selected = preprocessors.find((p) => p.preprocessorId === options.preprocessorName || p.name === options.preprocessorName);
|
|
53770
54433
|
if (!selected && normalizedAction === "delete") {
|
|
@@ -53783,10 +54446,7 @@ Usage: lua preprocessors ${normalizedAction} --preprocessor-name <name>`);
|
|
|
53783
54446
|
}
|
|
53784
54447
|
}
|
|
53785
54448
|
if (!selected) {
|
|
53786
|
-
|
|
53787
|
-
console.log("\nAvailable preprocessors:");
|
|
53788
|
-
preprocessors.forEach((p) => console.log(` - ${p.name} (${p.preprocessorId})`));
|
|
53789
|
-
throw new Error(`PreProcessor "${options.preprocessorName}" not found`);
|
|
54449
|
+
throw CliError.notFound(`PreProcessor "${options.preprocessorName}" not found`, listHint("Available preprocessors:", preprocessors.map((p) => `${p.name} (${p.preprocessorId})`)));
|
|
53790
54450
|
}
|
|
53791
54451
|
switch (normalizedAction) {
|
|
53792
54452
|
case "versions": {
|
|
@@ -53802,17 +54462,12 @@ Usage: lua preprocessors ${normalizedAction} --preprocessor-name <name>`);
|
|
|
53802
54462
|
}
|
|
53803
54463
|
case "deploy": {
|
|
53804
54464
|
if (!options.preprocessorVersion) {
|
|
53805
|
-
|
|
53806
|
-
console.log("\nUsage: lua preprocessors deploy --preprocessor-name myPre --preprocessor-version 1.0.3");
|
|
53807
|
-
console.log(" lua preprocessors deploy -i myPre -v latest");
|
|
53808
|
-
throw new Error("--preprocessor-version is required for deploy action");
|
|
54465
|
+
throw CliError.usage("--preprocessor-version is required for deploy action", "Usage: lua preprocessors deploy --preprocessor-name myPre --preprocessor-version 1.0.3\n lua preprocessors deploy -i myPre -v latest");
|
|
53809
54466
|
}
|
|
53810
54467
|
const data = await fetchVersionsCore5(context, selected);
|
|
53811
54468
|
if (!data) throw new Error("Failed to fetch preprocessor versions");
|
|
53812
54469
|
if (data.versions.length === 0) {
|
|
53813
|
-
|
|
53814
|
-
console.log("\u{1F4A1} Push a version first using 'lua push preprocessor'.");
|
|
53815
|
-
throw new Error(`No versions found for ${selected.name}`);
|
|
54470
|
+
throw CliError.notFound(`No versions found for ${selected.name}.`, "Push a version first using 'lua push preprocessor'.");
|
|
53816
54471
|
}
|
|
53817
54472
|
const resolvedVersion = resolveVersion4(data.versions, options.preprocessorVersion);
|
|
53818
54473
|
if (!resolvedVersion) throw new Error("Failed to resolve preprocessor version");
|
|
@@ -54120,6 +54775,7 @@ init_cli();
|
|
|
54120
54775
|
init_constants();
|
|
54121
54776
|
init_command_utils();
|
|
54122
54777
|
init_analytics();
|
|
54778
|
+
init_cli_error();
|
|
54123
54779
|
async function postprocessorsCommand(action, cmdObj) {
|
|
54124
54780
|
return withErrorHandling(async () => {
|
|
54125
54781
|
const options = {
|
|
@@ -54348,10 +55004,7 @@ async function executeNonInteractive10(context, config, action, options) {
|
|
|
54348
55004
|
return;
|
|
54349
55005
|
}
|
|
54350
55006
|
if (!options.postprocessorName) {
|
|
54351
|
-
|
|
54352
|
-
console.log(`
|
|
54353
|
-
Usage: lua postprocessors ${normalizedAction} --postprocessor-name <name>`);
|
|
54354
|
-
throw new Error(`--postprocessor-name is required for action "${normalizedAction}"`);
|
|
55007
|
+
throw CliError.usage(`--postprocessor-name is required for action "${normalizedAction}"`, `Usage: lua postprocessors ${normalizedAction} --postprocessor-name <name>`);
|
|
54355
55008
|
}
|
|
54356
55009
|
let selected = postprocessors.find((p) => p.postprocessorId === options.postprocessorName || p.name === options.postprocessorName);
|
|
54357
55010
|
if (!selected && normalizedAction === "delete") {
|
|
@@ -54370,10 +55023,7 @@ Usage: lua postprocessors ${normalizedAction} --postprocessor-name <name>`);
|
|
|
54370
55023
|
}
|
|
54371
55024
|
}
|
|
54372
55025
|
if (!selected) {
|
|
54373
|
-
|
|
54374
|
-
console.log("\nAvailable postprocessors:");
|
|
54375
|
-
postprocessors.forEach((p) => console.log(` - ${p.name} (${p.postprocessorId})`));
|
|
54376
|
-
throw new Error(`PostProcessor "${options.postprocessorName}" not found`);
|
|
55026
|
+
throw CliError.notFound(`PostProcessor "${options.postprocessorName}" not found`, listHint("Available postprocessors:", postprocessors.map((p) => `${p.name} (${p.postprocessorId})`)));
|
|
54377
55027
|
}
|
|
54378
55028
|
switch (normalizedAction) {
|
|
54379
55029
|
case "versions": {
|
|
@@ -54389,17 +55039,12 @@ Usage: lua postprocessors ${normalizedAction} --postprocessor-name <name>`);
|
|
|
54389
55039
|
}
|
|
54390
55040
|
case "deploy": {
|
|
54391
55041
|
if (!options.postprocessorVersion) {
|
|
54392
|
-
|
|
54393
|
-
console.log("\nUsage: lua postprocessors deploy --postprocessor-name myPost --postprocessor-version 1.0.3");
|
|
54394
|
-
console.log(" lua postprocessors deploy -i myPost -v latest");
|
|
54395
|
-
throw new Error("--postprocessor-version is required for deploy action");
|
|
55042
|
+
throw CliError.usage("--postprocessor-version is required for deploy action", "Usage: lua postprocessors deploy --postprocessor-name myPost --postprocessor-version 1.0.3\n lua postprocessors deploy -i myPost -v latest");
|
|
54396
55043
|
}
|
|
54397
55044
|
const data = await fetchVersionsCore6(context, selected);
|
|
54398
55045
|
if (!data) throw new Error("Failed to fetch postprocessor versions");
|
|
54399
55046
|
if (data.versions.length === 0) {
|
|
54400
|
-
|
|
54401
|
-
console.log("\u{1F4A1} Push a version first using 'lua push postprocessor'.");
|
|
54402
|
-
throw new Error(`No versions found for ${selected.name}`);
|
|
55047
|
+
throw CliError.notFound(`No versions found for ${selected.name}.`, "Push a version first using 'lua push postprocessor'.");
|
|
54403
55048
|
}
|
|
54404
55049
|
const resolvedVersion = resolveVersion5(data.versions, options.postprocessorVersion);
|
|
54405
55050
|
if (!resolvedVersion) throw new Error("Failed to resolve postprocessor version");
|
|
@@ -54970,6 +55615,7 @@ var TemplateApiService = class {
|
|
|
54970
55615
|
init_command_utils();
|
|
54971
55616
|
init_analytics();
|
|
54972
55617
|
init_files();
|
|
55618
|
+
init_cli_error();
|
|
54973
55619
|
function showTemplateUsage() {
|
|
54974
55620
|
console.log("\nUsage:");
|
|
54975
55621
|
console.log(" lua marketplace template Interactive mode");
|
|
@@ -55344,6 +55990,9 @@ async function templateDraftAction(templateApi, options) {
|
|
|
55344
55990
|
return;
|
|
55345
55991
|
}
|
|
55346
55992
|
writeSuccess("\u2705 template: section written to lua.skill.yaml");
|
|
55993
|
+
for (const warning of result.warnings ?? []) {
|
|
55994
|
+
console.log(` \u26A0 ${warning.message}`);
|
|
55995
|
+
}
|
|
55347
55996
|
for (const [section2, diff] of Object.entries(result.diff)) {
|
|
55348
55997
|
const annotations = Object.entries(diff.annotations ?? {});
|
|
55349
55998
|
console.log(` ${section2}: +${diff.added.length} added (${diff.added.join(", ") || "\u2014"}), ${diff.kept.length} kept`);
|
|
@@ -55546,8 +56195,7 @@ async function templateInstallAction(templateApi, config, options) {
|
|
|
55546
56195
|
if (envValues && Object.keys(envValues).length > 0) {
|
|
55547
56196
|
writeInfo(` Env values: ${Object.keys(envValues).length} configured`);
|
|
55548
56197
|
}
|
|
55549
|
-
|
|
55550
|
-
throw new Error("This action requires --force to confirm");
|
|
56198
|
+
throw CliError.usage("This action requires --force to confirm", "Use --force to confirm installation");
|
|
55551
56199
|
}
|
|
55552
56200
|
if (options.skipEnvCheck) {
|
|
55553
56201
|
writeInfo("\u26A0\uFE0F --skip-env-check is deprecated: the env-contract check is server-enforced; use `lua env` to satisfy the contract.");
|
|
@@ -55849,9 +56497,7 @@ async function templateUninstallAction(templateApi, config, options) {
|
|
|
55849
56497
|
if (!agentId) throw new Error("Agent ID not found in configuration.");
|
|
55850
56498
|
const templateId = await resolveTemplateId(templateApi, options, "Which template would you like to uninstall?");
|
|
55851
56499
|
if (!options.force) {
|
|
55852
|
-
|
|
55853
|
-
\u274C Use --force to confirm uninstalling template ${templateId} from this agent`);
|
|
55854
|
-
throw new Error("This action requires --force to confirm");
|
|
56500
|
+
throw CliError.usage("This action requires --force to confirm", `Use --force to confirm uninstalling template ${templateId} from this agent`);
|
|
55855
56501
|
}
|
|
55856
56502
|
writeProgress("\u{1F504} Uninstalling template...");
|
|
55857
56503
|
await templateApi.uninstall(templateId, agentId);
|
|
@@ -55860,6 +56506,7 @@ async function templateUninstallAction(templateApi, config, options) {
|
|
|
55860
56506
|
__name(templateUninstallAction, "templateUninstallAction");
|
|
55861
56507
|
|
|
55862
56508
|
// src/commands/marketplace.ts
|
|
56509
|
+
init_cli_error();
|
|
55863
56510
|
var SKILL_ACTIONS = [
|
|
55864
56511
|
"list",
|
|
55865
56512
|
"publish",
|
|
@@ -56075,40 +56722,29 @@ __name(executeSkillActionInteractive, "executeSkillActionInteractive");
|
|
|
56075
56722
|
async function listSkillNonInteractive(marketplaceApi, config, apiKey, options) {
|
|
56076
56723
|
const { skillName, displayName, visibility } = options;
|
|
56077
56724
|
if (!skillName || !displayName) {
|
|
56078
|
-
|
|
56079
|
-
console.log("\nUsage: lua marketplace skill list --skill-name <name> --display-name <name>");
|
|
56080
|
-
throw new Error("Missing required options");
|
|
56725
|
+
throw CliError.usage("Missing required options", "Usage: lua marketplace skill list --skill-name <name> --display-name <name>");
|
|
56081
56726
|
}
|
|
56082
56727
|
if (visibility && visibility !== "public" && visibility !== "private") {
|
|
56083
|
-
|
|
56084
|
-
throw new Error('Invalid --visibility: must be "public" or "private"');
|
|
56728
|
+
throw CliError.usage('Invalid --visibility: must be "public" or "private"');
|
|
56085
56729
|
}
|
|
56086
56730
|
const agentId = config.agent?.agentId;
|
|
56087
56731
|
if (!agentId) {
|
|
56088
|
-
|
|
56089
|
-
throw new Error("Agent ID not found in configuration.");
|
|
56732
|
+
throw CliError.usage("Agent ID not found in configuration.", "Run `lua init` in a project directory first.");
|
|
56090
56733
|
}
|
|
56091
56734
|
const skillApi = new SkillApi(BASE_URLS.API, apiKey, agentId);
|
|
56092
56735
|
writeProgress("\u{1F504} Verifying skill...");
|
|
56093
56736
|
const agentSkillsResponse = await skillApi.getSkills();
|
|
56094
56737
|
if (!agentSkillsResponse.success || !agentSkillsResponse.data) {
|
|
56095
|
-
|
|
56096
|
-
throw new Error("Failed to fetch agent skills: ${agentSkillsResponse.message}");
|
|
56738
|
+
throw CliError.fromStatus(agentSkillsResponse.error?.statusCode, `Failed to fetch agent skills: ${agentSkillsResponse.error?.message ?? agentSkillsResponse.message ?? "Unknown error"}`);
|
|
56097
56739
|
}
|
|
56098
56740
|
const skill = agentSkillsResponse.data.skills?.find((s) => s.name === skillName);
|
|
56099
56741
|
if (!skill) {
|
|
56100
|
-
|
|
56101
|
-
writeInfo("\nAvailable skills:");
|
|
56102
|
-
agentSkillsResponse.data.skills?.forEach((s) => {
|
|
56103
|
-
writeInfo(` - ${s.name}`);
|
|
56104
|
-
});
|
|
56105
|
-
throw new Error("Skill not found: ${skillName}");
|
|
56742
|
+
throw CliError.notFound(`Skill not found: ${skillName}`, listHint("Available skills:", (agentSkillsResponse.data.skills ?? []).map((s) => s.name)));
|
|
56106
56743
|
}
|
|
56107
56744
|
const creatorSkills = await marketplaceApi.getOrgSkills();
|
|
56108
56745
|
const existingSkill = creatorSkills?.find((s) => s.sourceSkillId === skill.id);
|
|
56109
56746
|
if (existingSkill?.listed) {
|
|
56110
|
-
|
|
56111
|
-
throw new Error("Skill");
|
|
56747
|
+
throw new CliError("error", `Skill "${skill.name}" is already listed as "${existingSkill.displayName}".`);
|
|
56112
56748
|
}
|
|
56113
56749
|
writeProgress("\u{1F504} Listing skill on marketplace...");
|
|
56114
56750
|
const marketplaceSkill = await marketplaceApi.listSkill({
|
|
@@ -56125,17 +56761,14 @@ __name(listSkillNonInteractive, "listSkillNonInteractive");
|
|
|
56125
56761
|
async function publishVersionNonInteractive(marketplaceApi, config, apiKey, options) {
|
|
56126
56762
|
const { marketplaceId, versionId, changelog, envVarsJson } = options;
|
|
56127
56763
|
if (!marketplaceId || !versionId) {
|
|
56128
|
-
|
|
56129
|
-
console.log("\nUsage: lua marketplace skill publish --marketplace-id <id> --version-id <id> [--changelog <text>]");
|
|
56130
|
-
throw new Error("Missing required options");
|
|
56764
|
+
throw CliError.usage("Missing required options", "Usage: lua marketplace skill publish --marketplace-id <id> --version-id <id> [--changelog <text>]");
|
|
56131
56765
|
}
|
|
56132
56766
|
let envVars;
|
|
56133
56767
|
if (envVarsJson) {
|
|
56134
56768
|
try {
|
|
56135
56769
|
envVars = JSON.parse(envVarsJson);
|
|
56136
|
-
} catch
|
|
56137
|
-
|
|
56138
|
-
throw new Error("Invalid --env-vars-json: must be valid JSON");
|
|
56770
|
+
} catch {
|
|
56771
|
+
throw CliError.usage("Invalid --env-vars-json: must be valid JSON");
|
|
56139
56772
|
}
|
|
56140
56773
|
}
|
|
56141
56774
|
writeProgress("\u{1F504} Publishing version...");
|
|
@@ -56152,13 +56785,10 @@ __name(publishVersionNonInteractive, "publishVersionNonInteractive");
|
|
|
56152
56785
|
async function updateMetadataNonInteractive(marketplaceApi, options) {
|
|
56153
56786
|
const { marketplaceId, displayName } = options;
|
|
56154
56787
|
if (!marketplaceId) {
|
|
56155
|
-
|
|
56156
|
-
console.log("\nUsage: lua marketplace skill edit --marketplace-id <id> --display-name <name>");
|
|
56157
|
-
throw new Error("Missing required option: --marketplace-id");
|
|
56788
|
+
throw CliError.usage("Missing required option: --marketplace-id", "Usage: lua marketplace skill edit --marketplace-id <id> --display-name <name>");
|
|
56158
56789
|
}
|
|
56159
56790
|
if (!displayName) {
|
|
56160
|
-
|
|
56161
|
-
throw new Error("No update specified. Provide --display-name to update.");
|
|
56791
|
+
throw CliError.usage("No update specified. Provide --display-name to update.");
|
|
56162
56792
|
}
|
|
56163
56793
|
writeProgress("\u{1F504} Updating skill metadata...");
|
|
56164
56794
|
await marketplaceApi.updateSkill(marketplaceId, {
|
|
@@ -56170,14 +56800,10 @@ __name(updateMetadataNonInteractive, "updateMetadataNonInteractive");
|
|
|
56170
56800
|
async function unlistSkillNonInteractive(marketplaceApi, options) {
|
|
56171
56801
|
const { marketplaceId, force } = options;
|
|
56172
56802
|
if (!marketplaceId) {
|
|
56173
|
-
|
|
56174
|
-
console.log("\nUsage: lua marketplace skill unlist --marketplace-id <id> [--force]");
|
|
56175
|
-
throw new Error("Missing required option: --marketplace-id");
|
|
56803
|
+
throw CliError.usage("Missing required option: --marketplace-id", "Usage: lua marketplace skill unlist --marketplace-id <id> [--force]");
|
|
56176
56804
|
}
|
|
56177
56805
|
if (!force) {
|
|
56178
|
-
|
|
56179
|
-
console.log("\nUsage: lua marketplace skill unlist --marketplace-id <id> --force");
|
|
56180
|
-
throw new Error("This action requires --force to confirm");
|
|
56806
|
+
throw CliError.usage("This action requires --force to confirm", "Usage: lua marketplace skill unlist --marketplace-id <id> --force");
|
|
56181
56807
|
}
|
|
56182
56808
|
writeProgress("\u{1F504} Unlisting skill...");
|
|
56183
56809
|
await marketplaceApi.unlistSkill(marketplaceId);
|
|
@@ -56188,13 +56814,10 @@ __name(unlistSkillNonInteractive, "unlistSkillNonInteractive");
|
|
|
56188
56814
|
async function unpublishVersionNonInteractive(marketplaceApi, options) {
|
|
56189
56815
|
const { marketplaceId, versionId, force } = options;
|
|
56190
56816
|
if (!marketplaceId || !versionId) {
|
|
56191
|
-
|
|
56192
|
-
console.log("\nUsage: lua marketplace skill unpublish --marketplace-id <id> --version-id <id> [--force]");
|
|
56193
|
-
throw new Error("Missing required options");
|
|
56817
|
+
throw CliError.usage("Missing required options", "Usage: lua marketplace skill unpublish --marketplace-id <id> --version-id <id> [--force]");
|
|
56194
56818
|
}
|
|
56195
56819
|
if (!force) {
|
|
56196
|
-
|
|
56197
|
-
throw new Error("This action requires --force to confirm");
|
|
56820
|
+
throw CliError.usage("This action requires --force to confirm");
|
|
56198
56821
|
}
|
|
56199
56822
|
writeProgress("\u{1F504} Unpublishing version...");
|
|
56200
56823
|
await marketplaceApi.unpublishVersion(marketplaceId, versionId);
|
|
@@ -56204,8 +56827,7 @@ async function unpublishVersionNonInteractive(marketplaceApi, options) {
|
|
|
56204
56827
|
__name(unpublishVersionNonInteractive, "unpublishVersionNonInteractive");
|
|
56205
56828
|
async function transferOwnershipNonInteractive(marketplaceApi, options) {
|
|
56206
56829
|
if (!options.marketplaceId || !options.newOrgId || !options.force) {
|
|
56207
|
-
|
|
56208
|
-
throw new Error("Missing transfer options");
|
|
56830
|
+
throw CliError.usage("--marketplace-id, --new-org-id and --force are required");
|
|
56209
56831
|
}
|
|
56210
56832
|
writeProgress("\u{1F504} Transferring organization ownership...");
|
|
56211
56833
|
const skill = await marketplaceApi.transferSkillOwnership(options.marketplaceId, options.newOrgId);
|
|
@@ -56284,9 +56906,7 @@ __name(searchSkillsNonInteractive, "searchSkillsNonInteractive");
|
|
|
56284
56906
|
async function viewSkillNonInteractive(marketplaceApi, options) {
|
|
56285
56907
|
const { marketplaceId } = options;
|
|
56286
56908
|
if (!marketplaceId) {
|
|
56287
|
-
|
|
56288
|
-
console.log("\nUsage: lua marketplace skill view --marketplace-id <id>");
|
|
56289
|
-
throw new Error("Missing required option: --marketplace-id");
|
|
56909
|
+
throw CliError.usage("Missing required option: --marketplace-id", "Usage: lua marketplace skill view --marketplace-id <id>");
|
|
56290
56910
|
}
|
|
56291
56911
|
writeProgress("\u{1F504} Loading skill details...");
|
|
56292
56912
|
const skill = await marketplaceApi.getSkillById(marketplaceId);
|
|
@@ -56328,14 +56948,11 @@ __name(viewSkillNonInteractive, "viewSkillNonInteractive");
|
|
|
56328
56948
|
async function installSkillNonInteractive(marketplaceApi, config, options) {
|
|
56329
56949
|
const { marketplaceId, versionId, envVars, force } = options;
|
|
56330
56950
|
if (!marketplaceId || !versionId) {
|
|
56331
|
-
|
|
56332
|
-
console.log("\nUsage: lua marketplace skill install --marketplace-id <id> --version-id <id> [--env-vars <k=v,...>]");
|
|
56333
|
-
throw new Error("Missing required options");
|
|
56951
|
+
throw CliError.usage("Missing required options", "Usage: lua marketplace skill install --marketplace-id <id> --version-id <id> [--env-vars <k=v,...>]");
|
|
56334
56952
|
}
|
|
56335
56953
|
const agentId = config.agent?.agentId;
|
|
56336
56954
|
if (!agentId) {
|
|
56337
|
-
|
|
56338
|
-
throw new Error("Agent ID not found in configuration.");
|
|
56955
|
+
throw CliError.usage("Agent ID not found in configuration.", "Run `lua init` in a project directory first.");
|
|
56339
56956
|
}
|
|
56340
56957
|
const envVarsConfig = {};
|
|
56341
56958
|
if (envVars) {
|
|
@@ -56356,8 +56973,7 @@ async function installSkillNonInteractive(marketplaceApi, config, options) {
|
|
|
56356
56973
|
if (Object.keys(envVarsConfig).length > 0) {
|
|
56357
56974
|
writeInfo(` Env vars: ${Object.keys(envVarsConfig).length} configured`);
|
|
56358
56975
|
}
|
|
56359
|
-
|
|
56360
|
-
throw new Error("Operation failed");
|
|
56976
|
+
throw CliError.usage("Use --force to confirm installation");
|
|
56361
56977
|
}
|
|
56362
56978
|
writeProgress("\u{1F504} Installing skill...");
|
|
56363
56979
|
await marketplaceApi.installSkill(marketplaceId, agentId, {
|
|
@@ -56385,31 +57001,20 @@ __name(installSkillNonInteractive, "installSkillNonInteractive");
|
|
|
56385
57001
|
async function updateInstalledSkillNonInteractive(marketplaceApi, config, apiKey, options) {
|
|
56386
57002
|
const { skillName, versionId, envVars } = options;
|
|
56387
57003
|
if (!skillName) {
|
|
56388
|
-
|
|
56389
|
-
console.log("\nUsage: lua marketplace skill update --skill-name <name> [--version-id <id>] [--env-vars <k=v,...>]");
|
|
56390
|
-
throw new Error("Missing required option: --skill-name");
|
|
57004
|
+
throw CliError.usage("Missing required option: --skill-name", "Usage: lua marketplace skill update --skill-name <name> [--version-id <id>] [--env-vars <k=v,...>]");
|
|
56391
57005
|
}
|
|
56392
57006
|
const agentId = config.agent?.agentId;
|
|
56393
57007
|
if (!agentId) {
|
|
56394
|
-
|
|
56395
|
-
throw new Error("Agent ID not found in configuration.");
|
|
57008
|
+
throw CliError.usage("Agent ID not found in configuration.", "Run `lua init` in a project directory first.");
|
|
56396
57009
|
}
|
|
56397
57010
|
writeProgress("\u{1F504} Loading installed skills...");
|
|
56398
57011
|
const installedSkills = await marketplaceApi.getInstalledSkills(agentId);
|
|
56399
57012
|
const installedSkill = installedSkills?.find((s) => s.name === skillName || s.title === skillName);
|
|
56400
57013
|
if (!installedSkill) {
|
|
56401
|
-
|
|
56402
|
-
if (installedSkills?.length) {
|
|
56403
|
-
writeInfo("\nInstalled skills:");
|
|
56404
|
-
installedSkills.forEach((s) => {
|
|
56405
|
-
writeInfo(` - ${s.title || s.name}`);
|
|
56406
|
-
});
|
|
56407
|
-
}
|
|
56408
|
-
throw new Error("Operation failed");
|
|
57014
|
+
throw CliError.notFound(`Installed skill not found: ${skillName}`, listHint("Installed skills:", (installedSkills ?? []).map((s) => s.title || s.name)));
|
|
56409
57015
|
}
|
|
56410
57016
|
if (!installedSkill.marketplaceSkillId) {
|
|
56411
|
-
|
|
56412
|
-
throw new Error("Skill is missing marketplace skill ID.");
|
|
57017
|
+
throw new CliError("error", "Skill is missing marketplace skill ID.");
|
|
56413
57018
|
}
|
|
56414
57019
|
let newEnvVars;
|
|
56415
57020
|
if (envVars) {
|
|
@@ -56426,8 +57031,7 @@ async function updateInstalledSkillNonInteractive(marketplaceApi, config, apiKey
|
|
|
56426
57031
|
if (versionId) updatePayload.versionId = versionId;
|
|
56427
57032
|
if (newEnvVars) updatePayload.envVars = newEnvVars;
|
|
56428
57033
|
if (!updatePayload.versionId && !updatePayload.envVars) {
|
|
56429
|
-
|
|
56430
|
-
throw new Error("No update specified. Provide --version-id or --env-vars.");
|
|
57034
|
+
throw CliError.usage("No update specified. Provide --version-id or --env-vars.");
|
|
56431
57035
|
}
|
|
56432
57036
|
writeProgress("\u{1F504} Updating installed skill...");
|
|
56433
57037
|
await marketplaceApi.updateInstallation(installedSkill.marketplaceSkillId, agentId, updatePayload);
|
|
@@ -56437,29 +57041,23 @@ __name(updateInstalledSkillNonInteractive, "updateInstalledSkillNonInteractive")
|
|
|
56437
57041
|
async function uninstallSkillNonInteractive(marketplaceApi, config, options) {
|
|
56438
57042
|
const { skillName, force } = options;
|
|
56439
57043
|
if (!skillName) {
|
|
56440
|
-
|
|
56441
|
-
console.log("\nUsage: lua marketplace skill uninstall --skill-name <name> [--force]");
|
|
56442
|
-
throw new Error("Missing required option: --skill-name");
|
|
57044
|
+
throw CliError.usage("Missing required option: --skill-name", "Usage: lua marketplace skill uninstall --skill-name <name> [--force]");
|
|
56443
57045
|
}
|
|
56444
57046
|
const agentId = config.agent?.agentId;
|
|
56445
57047
|
if (!agentId) {
|
|
56446
|
-
|
|
56447
|
-
throw new Error("Agent ID not found in configuration.");
|
|
57048
|
+
throw CliError.usage("Agent ID not found in configuration.", "Run `lua init` in a project directory first.");
|
|
56448
57049
|
}
|
|
56449
57050
|
writeProgress("\u{1F504} Loading installed skills...");
|
|
56450
57051
|
const installedSkills = await marketplaceApi.getInstalledSkills(agentId);
|
|
56451
57052
|
const installedSkill = installedSkills?.find((s) => s.name === skillName || s.title === skillName);
|
|
56452
57053
|
if (!installedSkill) {
|
|
56453
|
-
|
|
56454
|
-
throw new Error("Installed skill not found: ${skillName}");
|
|
57054
|
+
throw CliError.notFound(`Installed skill not found: ${skillName}`);
|
|
56455
57055
|
}
|
|
56456
57056
|
if (!installedSkill.marketplaceSkillId) {
|
|
56457
|
-
|
|
56458
|
-
throw new Error("Skill is missing marketplace skill ID.");
|
|
57057
|
+
throw new CliError("error", "Skill is missing marketplace skill ID.");
|
|
56459
57058
|
}
|
|
56460
57059
|
if (!force) {
|
|
56461
|
-
|
|
56462
|
-
throw new Error("Use --force to confirm uninstalling");
|
|
57060
|
+
throw CliError.usage(`Use --force to confirm uninstalling "${installedSkill.title || installedSkill.name}"`);
|
|
56463
57061
|
}
|
|
56464
57062
|
writeProgress("\u{1F504} Uninstalling skill...");
|
|
56465
57063
|
await marketplaceApi.uninstallSkill(installedSkill.marketplaceSkillId, agentId);
|
|
@@ -56469,8 +57067,7 @@ __name(uninstallSkillNonInteractive, "uninstallSkillNonInteractive");
|
|
|
56469
57067
|
async function listInstalledSkillsNonInteractive(marketplaceApi, config, options) {
|
|
56470
57068
|
const agentId = config.agent?.agentId;
|
|
56471
57069
|
if (!agentId) {
|
|
56472
|
-
|
|
56473
|
-
throw new Error("Agent ID not found in configuration.");
|
|
57070
|
+
throw CliError.usage("Agent ID not found in configuration.", "Run `lua init` in a project directory first.");
|
|
56474
57071
|
}
|
|
56475
57072
|
writeProgress("\u{1F504} Loading installed marketplace skills...");
|
|
56476
57073
|
const skills = await marketplaceApi.getInstalledSkills(agentId);
|
|
@@ -57951,6 +58548,7 @@ init_constants();
|
|
|
57951
58548
|
init_command_utils();
|
|
57952
58549
|
init_developer_api_service();
|
|
57953
58550
|
init_analytics();
|
|
58551
|
+
init_cli_error();
|
|
57954
58552
|
async function mcpCommand(action, serverNamePositional, cmdObj) {
|
|
57955
58553
|
return withErrorHandling(async () => {
|
|
57956
58554
|
const options = {
|
|
@@ -58135,23 +58733,11 @@ async function executeNonInteractive11(context, action, options) {
|
|
|
58135
58733
|
return;
|
|
58136
58734
|
}
|
|
58137
58735
|
if (!options.serverName) {
|
|
58138
|
-
|
|
58139
|
-
console.log(`
|
|
58140
|
-
Usage: lua mcp ${resolvedAction} --server-name <name>`);
|
|
58141
|
-
if (servers.length > 0) {
|
|
58142
|
-
console.log("\nAvailable servers:");
|
|
58143
|
-
servers.forEach((s) => console.log(` - ${s.name} ${s.active ? "(active)" : "(inactive)"}`));
|
|
58144
|
-
}
|
|
58145
|
-
throw new Error("Operation failed");
|
|
58736
|
+
throw CliError.usage(`--server-name is required for action "${resolvedAction}"`, joinHint(`Usage: lua mcp ${resolvedAction} --server-name <name>`, listHint("Available servers:", servers.map((s) => `${s.name} ${s.active ? "(active)" : "(inactive)"}`))));
|
|
58146
58737
|
}
|
|
58147
58738
|
const selectedServer = findServer(servers, options.serverName);
|
|
58148
58739
|
if (!selectedServer) {
|
|
58149
|
-
|
|
58150
|
-
if (servers.length > 0) {
|
|
58151
|
-
console.log("\nAvailable servers:");
|
|
58152
|
-
servers.forEach((s) => console.log(` - ${s.name}`));
|
|
58153
|
-
}
|
|
58154
|
-
throw new Error("Operation failed");
|
|
58740
|
+
throw CliError.notFound(`MCP server "${options.serverName}" not found`, listHint("Available servers:", servers.map((s) => s.name)));
|
|
58155
58741
|
}
|
|
58156
58742
|
switch (resolvedAction) {
|
|
58157
58743
|
case "activate": {
|
|
@@ -58549,6 +59135,7 @@ var UnifiedToApi = class extends HttpClient {
|
|
|
58549
59135
|
|
|
58550
59136
|
// src/commands/integrations.ts
|
|
58551
59137
|
init_analytics();
|
|
59138
|
+
init_cli_error();
|
|
58552
59139
|
var CALLBACK_PORT = 19837;
|
|
58553
59140
|
var CALLBACK_HOST = "127.0.0.1";
|
|
58554
59141
|
var CALLBACK_URL = `http://${CALLBACK_HOST}:${CALLBACK_PORT}/callback`;
|
|
@@ -58745,9 +59332,7 @@ async function executeNonInteractive12(context, action, cmdOptions) {
|
|
|
58745
59332
|
break;
|
|
58746
59333
|
case "update":
|
|
58747
59334
|
if (!options.integration && !options.connectionId) {
|
|
58748
|
-
|
|
58749
|
-
console.log("\n\u{1F4A1} Run 'lua integrations list' to see connected integrations");
|
|
58750
|
-
throw new Error("--connection-id or --integration is required for update");
|
|
59335
|
+
throw CliError.usage("--connection-id (preferred) or --integration is required for update", "Run 'lua integrations list' to see connected integrations");
|
|
58751
59336
|
}
|
|
58752
59337
|
if (options.scope === "user") {
|
|
58753
59338
|
await updateUserConnectionFlow(context, options);
|
|
@@ -58767,9 +59352,7 @@ async function executeNonInteractive12(context, action, cmdOptions) {
|
|
|
58767
59352
|
break;
|
|
58768
59353
|
case "convert":
|
|
58769
59354
|
if (!options.connectionId) {
|
|
58770
|
-
|
|
58771
|
-
console.log("\n\u{1F4A1} Run 'lua integrations list' to see connection IDs");
|
|
58772
|
-
throw new Error("--connection-id is required for convert");
|
|
59355
|
+
throw CliError.usage("--connection-id is required for convert", "Run 'lua integrations list' to see connection IDs");
|
|
58773
59356
|
}
|
|
58774
59357
|
await convertConnectionFlow(context, options.connectionId, cmdOptions?.force === true);
|
|
58775
59358
|
break;
|
|
@@ -58779,18 +59362,13 @@ async function executeNonInteractive12(context, action, cmdOptions) {
|
|
|
58779
59362
|
case "info":
|
|
58780
59363
|
const infoIntegrationType = options.integration || cmdOptions?._?.[0];
|
|
58781
59364
|
if (!infoIntegrationType) {
|
|
58782
|
-
|
|
58783
|
-
console.log("\nUsage: lua integrations info <type>");
|
|
58784
|
-
console.log(" lua integrations info <type> --json");
|
|
58785
|
-
throw new Error("Integration type is required");
|
|
59365
|
+
throw CliError.usage("Integration type is required", "Usage: lua integrations info <type>\n lua integrations info <type> --json");
|
|
58786
59366
|
}
|
|
58787
59367
|
await showIntegrationInfo(context, infoIntegrationType, jsonOutput);
|
|
58788
59368
|
break;
|
|
58789
59369
|
case "disconnect":
|
|
58790
59370
|
if (!options.connectionId) {
|
|
58791
|
-
|
|
58792
|
-
console.log("\n\u{1F4A1} Run 'lua integrations list' to see connection IDs");
|
|
58793
|
-
throw new Error("--connection-id is required for disconnect");
|
|
59371
|
+
throw CliError.usage("--connection-id is required for disconnect", "Run 'lua integrations list' to see connection IDs");
|
|
58794
59372
|
}
|
|
58795
59373
|
if (options.scope === "user") {
|
|
58796
59374
|
await disconnectUserConnection(context, options.connectionId);
|
|
@@ -58805,9 +59383,7 @@ async function executeNonInteractive12(context, action, cmdOptions) {
|
|
|
58805
59383
|
await mcpSubcommand(context, cmdOptions);
|
|
58806
59384
|
break;
|
|
58807
59385
|
default:
|
|
58808
|
-
|
|
58809
|
-
showUsage();
|
|
58810
|
-
throw new Error("Invalid action:");
|
|
59386
|
+
throw CliError.usage(`Invalid action: "${action}"`, INTEGRATIONS_USAGE.join("\n"));
|
|
58811
59387
|
}
|
|
58812
59388
|
}
|
|
58813
59389
|
__name(executeNonInteractive12, "executeNonInteractive");
|
|
@@ -58936,16 +59512,7 @@ async function showIntegrationInfo(context, integrationType, jsonOutput = false)
|
|
|
58936
59512
|
const integrations = await fetchAvailableIntegrations(context.unifiedToApi);
|
|
58937
59513
|
const integration = integrations.find((i) => i.value === integrationType);
|
|
58938
59514
|
if (!integration) {
|
|
58939
|
-
|
|
58940
|
-
console.log(JSON.stringify({
|
|
58941
|
-
error: `Integration not found: ${integrationType}`
|
|
58942
|
-
}));
|
|
58943
|
-
} else {
|
|
58944
|
-
console.error(`\u274C Integration not found: ${integrationType}`);
|
|
58945
|
-
console.log("\nAvailable integrations:");
|
|
58946
|
-
integrations.forEach((i) => console.log(` - ${i.value} (${i.name})`));
|
|
58947
|
-
}
|
|
58948
|
-
throw new Error("Operation failed");
|
|
59515
|
+
throw CliError.notFound(`Integration not found: ${integrationType}`, listHint("Available integrations:", integrations.map((i) => `${i.value} (${i.name})`)));
|
|
58949
59516
|
}
|
|
58950
59517
|
let webhookEvents = [];
|
|
58951
59518
|
try {
|
|
@@ -59028,14 +59595,11 @@ async function showIntegrationInfo(context, integrationType, jsonOutput = false)
|
|
|
59028
59595
|
console.log();
|
|
59029
59596
|
}
|
|
59030
59597
|
} catch (error) {
|
|
59031
|
-
if (jsonOutput) {
|
|
59032
|
-
|
|
59033
|
-
|
|
59034
|
-
|
|
59035
|
-
|
|
59036
|
-
writeError(`\u274C Failed to get integration info: ${error.message}`);
|
|
59037
|
-
}
|
|
59038
|
-
throw new Error("Operation failed");
|
|
59598
|
+
if (jsonOutput) console.log(JSON.stringify({
|
|
59599
|
+
error: error.message
|
|
59600
|
+
}));
|
|
59601
|
+
if (isTypedCliError(error)) throw error;
|
|
59602
|
+
throw new CliError("error", `Failed to get integration info: ${error.message}`);
|
|
59039
59603
|
}
|
|
59040
59604
|
}
|
|
59041
59605
|
__name(showIntegrationInfo, "showIntegrationInfo");
|
|
@@ -59055,8 +59619,7 @@ function normalizeScopeFlag(raw) {
|
|
|
59055
59619
|
if (!raw) return void 0;
|
|
59056
59620
|
const normalized = raw.toLowerCase();
|
|
59057
59621
|
if (normalized !== "agent" && normalized !== "user") {
|
|
59058
|
-
|
|
59059
|
-
throw new Error("Invalid --scope");
|
|
59622
|
+
throw CliError.usage(`Invalid --scope: "${raw}". Use 'agent' or 'user'`);
|
|
59060
59623
|
}
|
|
59061
59624
|
return normalized;
|
|
59062
59625
|
}
|
|
@@ -59216,22 +59779,13 @@ async function connectIntegrationFlow(context, options = {}) {
|
|
|
59216
59779
|
"oauth",
|
|
59217
59780
|
"token"
|
|
59218
59781
|
].includes(options.authMethod)) {
|
|
59219
|
-
|
|
59220
|
-
throw new Error("Invalid --auth-method:");
|
|
59782
|
+
throw CliError.usage(`Invalid --auth-method: "${options.authMethod}". Use 'oauth' or 'token'`);
|
|
59221
59783
|
}
|
|
59222
59784
|
if (options.authMethod === "oauth" && !canUseOAuth) {
|
|
59223
|
-
|
|
59224
|
-
if (canUseToken) {
|
|
59225
|
-
console.log(`\u{1F4A1} Use --auth-method token instead.`);
|
|
59226
|
-
}
|
|
59227
|
-
throw new Error("Operation failed");
|
|
59785
|
+
throw CliError.usage(`OAuth is not available for ${selectedIntegration.name}.`, canUseToken ? "Use --auth-method token instead." : void 0);
|
|
59228
59786
|
}
|
|
59229
59787
|
if (options.authMethod === "token" && !canUseToken) {
|
|
59230
|
-
|
|
59231
|
-
if (canUseOAuth) {
|
|
59232
|
-
console.log(`\u{1F4A1} Use --auth-method oauth instead.`);
|
|
59233
|
-
}
|
|
59234
|
-
throw new Error("Operation failed");
|
|
59788
|
+
throw CliError.usage(`Token authentication is not available for ${selectedIntegration.name}.`, canUseOAuth ? "Use --auth-method oauth instead." : void 0);
|
|
59235
59789
|
}
|
|
59236
59790
|
authMethod = options.authMethod;
|
|
59237
59791
|
writeInfo(`Using ${authMethod === "oauth" ? "OAuth 2.0" : "API Token"} authentication`);
|
|
@@ -59277,11 +59831,7 @@ async function connectIntegrationFlow(context, options = {}) {
|
|
|
59277
59831
|
const requestedScopes = options.scopes.split(",").map((s) => s.trim());
|
|
59278
59832
|
const invalidScopes = requestedScopes.filter((s) => !availableScopes.includes(s));
|
|
59279
59833
|
if (invalidScopes.length > 0) {
|
|
59280
|
-
|
|
59281
|
-
console.log(`
|
|
59282
|
-
Available scopes for ${selectedIntegration.name}:`);
|
|
59283
|
-
availableScopes.forEach((s) => console.log(` - ${s}`));
|
|
59284
|
-
throw new Error("Invalid scopes: ${invalidScopes.join(");
|
|
59834
|
+
throw CliError.usage(`Invalid scopes: ${invalidScopes.join(", ")}`, listHint(`Available scopes for ${selectedIntegration.name}:`, availableScopes));
|
|
59285
59835
|
}
|
|
59286
59836
|
selectedScopes = requestedScopes;
|
|
59287
59837
|
writeInfo(`Using ${selectedScopes.length} specified scope(s)`);
|
|
@@ -59367,13 +59917,7 @@ Available scopes for ${selectedIntegration.name}:`);
|
|
|
59367
59917
|
const [objectType, event] = trigger.split(".");
|
|
59368
59918
|
const matchingEvent = availableEvents.find((e) => e.objectType === objectType && e.event === event);
|
|
59369
59919
|
if (!matchingEvent) {
|
|
59370
|
-
|
|
59371
|
-
console.log(`
|
|
59372
|
-
Available triggers for ${selectedIntegration.name}:`);
|
|
59373
|
-
availableEvents.forEach((e) => {
|
|
59374
|
-
console.log(` - ${e.objectType}.${e.event} [${e.webhookType}] - ${e.friendlyDescription}`);
|
|
59375
|
-
});
|
|
59376
|
-
throw new Error("Invalid trigger: ${trigger}");
|
|
59920
|
+
throw CliError.usage(`Invalid trigger: ${trigger}`, listHint(`Available triggers for ${selectedIntegration.name}:`, availableEvents.map((e) => `${e.objectType}.${e.event} [${e.webhookType}] - ${e.friendlyDescription}`)));
|
|
59377
59921
|
}
|
|
59378
59922
|
selectedTriggers.push(matchingEvent);
|
|
59379
59923
|
}
|
|
@@ -60001,10 +60545,7 @@ async function updateConnectionFlow(context, options = {}) {
|
|
|
60001
60545
|
}
|
|
60002
60546
|
selectedConnection = matches[0];
|
|
60003
60547
|
if (!selectedConnection) {
|
|
60004
|
-
|
|
60005
|
-
console.log("\nConnected integrations:");
|
|
60006
|
-
connections.forEach((c) => console.log(` - ${c.integrationType} (${c.integrationName || c.integrationType})`));
|
|
60007
|
-
throw new Error("No connection found for integration");
|
|
60548
|
+
throw CliError.notFound(`No connection found for integration "${options.integration}".`, listHint("Connected integrations:", connections.map((c) => `${c.integrationType} (${c.integrationName || c.integrationType})`)));
|
|
60008
60549
|
}
|
|
60009
60550
|
selectedIntegration = integrations.find((i) => i.value === options.integration);
|
|
60010
60551
|
} else {
|
|
@@ -60049,11 +60590,7 @@ async function updateConnectionFlow(context, options = {}) {
|
|
|
60049
60590
|
const requestedScopes = options.scopes.split(",").map((s) => s.trim());
|
|
60050
60591
|
const invalidScopes = requestedScopes.filter((s) => !availableScopes.includes(s));
|
|
60051
60592
|
if (invalidScopes.length > 0) {
|
|
60052
|
-
|
|
60053
|
-
console.log(`
|
|
60054
|
-
Available scopes for ${selectedIntegration.name}:`);
|
|
60055
|
-
availableScopes.forEach((s) => console.log(` - ${s}`));
|
|
60056
|
-
throw new Error("Invalid scopes: ${invalidScopes.join(");
|
|
60593
|
+
throw CliError.usage(`Invalid scopes: ${invalidScopes.join(", ")}`, listHint(`Available scopes for ${selectedIntegration.name}:`, availableScopes));
|
|
60057
60594
|
}
|
|
60058
60595
|
selectedScopes = requestedScopes;
|
|
60059
60596
|
writeInfo(`Using ${selectedScopes.length} specified scope(s)`);
|
|
@@ -60287,9 +60824,7 @@ async function webhooksSubcommand(context, cmdOptions) {
|
|
|
60287
60824
|
break;
|
|
60288
60825
|
case "delete":
|
|
60289
60826
|
if (!options.webhookId) {
|
|
60290
|
-
|
|
60291
|
-
console.log("\n\u{1F4A1} Run 'lua integrations webhooks list' to see trigger IDs");
|
|
60292
|
-
throw new Error("--webhook-id is required for delete");
|
|
60827
|
+
throw CliError.usage("--webhook-id is required for delete", "Run 'lua integrations webhooks list' to see trigger IDs");
|
|
60293
60828
|
}
|
|
60294
60829
|
await webhooksDeleteFlow(context, options.webhookId);
|
|
60295
60830
|
break;
|
|
@@ -60299,9 +60834,7 @@ async function webhooksSubcommand(context, cmdOptions) {
|
|
|
60299
60834
|
} else if (options.connectionId) {
|
|
60300
60835
|
await connectionPauseFlow(context, options.connectionId);
|
|
60301
60836
|
} else {
|
|
60302
|
-
|
|
60303
|
-
console.log("\n\u{1F4A1} Run 'lua integrations webhooks list' to see trigger IDs");
|
|
60304
|
-
throw new Error("--webhook-id or --connection-id is required for pause");
|
|
60837
|
+
throw CliError.usage("--webhook-id or --connection-id is required for pause", "Run 'lua integrations webhooks list' to see trigger IDs");
|
|
60305
60838
|
}
|
|
60306
60839
|
break;
|
|
60307
60840
|
case "resume":
|
|
@@ -60310,9 +60843,7 @@ async function webhooksSubcommand(context, cmdOptions) {
|
|
|
60310
60843
|
} else if (options.connectionId) {
|
|
60311
60844
|
await connectionResumeFlow(context, options.connectionId);
|
|
60312
60845
|
} else {
|
|
60313
|
-
|
|
60314
|
-
console.log("\n\u{1F4A1} Run 'lua integrations webhooks list' to see trigger IDs");
|
|
60315
|
-
throw new Error("--webhook-id or --connection-id is required for resume");
|
|
60846
|
+
throw CliError.usage("--webhook-id or --connection-id is required for resume", "Run 'lua integrations webhooks list' to see trigger IDs");
|
|
60316
60847
|
}
|
|
60317
60848
|
break;
|
|
60318
60849
|
case "events":
|
|
@@ -60355,17 +60886,7 @@ async function webhooksEventsFlow(context, options, jsonOutput = false) {
|
|
|
60355
60886
|
}
|
|
60356
60887
|
sourceName = `integration ${options.integration}`;
|
|
60357
60888
|
} else {
|
|
60358
|
-
|
|
60359
|
-
console.log(JSON.stringify({
|
|
60360
|
-
error: "Either --connection or --integration is required"
|
|
60361
|
-
}));
|
|
60362
|
-
} else {
|
|
60363
|
-
console.error("\u274C Either --connection <id> or --integration <type> is required");
|
|
60364
|
-
console.log("\nUsage:");
|
|
60365
|
-
console.log(" lua integrations webhooks events --connection <id>");
|
|
60366
|
-
console.log(" lua integrations webhooks events --integration <type>");
|
|
60367
|
-
}
|
|
60368
|
-
throw new Error("Operation failed");
|
|
60889
|
+
throw CliError.usage("Either --connection <id> or --integration <type> is required", "Usage:\n lua integrations webhooks events --connection <id>\n lua integrations webhooks events --integration <type>");
|
|
60369
60890
|
}
|
|
60370
60891
|
if (jsonOutput) {
|
|
60371
60892
|
const output = {
|
|
@@ -60409,14 +60930,11 @@ async function webhooksEventsFlow(context, options, jsonOutput = false) {
|
|
|
60409
60930
|
}
|
|
60410
60931
|
}
|
|
60411
60932
|
} catch (error) {
|
|
60412
|
-
if (jsonOutput) {
|
|
60413
|
-
|
|
60414
|
-
|
|
60415
|
-
|
|
60416
|
-
|
|
60417
|
-
writeError(`\u274C Failed to get trigger events: ${error.message}`);
|
|
60418
|
-
}
|
|
60419
|
-
throw new Error("Operation failed");
|
|
60933
|
+
if (jsonOutput) console.log(JSON.stringify({
|
|
60934
|
+
error: error.message
|
|
60935
|
+
}));
|
|
60936
|
+
if (isTypedCliError(error)) throw error;
|
|
60937
|
+
throw new CliError("error", `Failed to get trigger events: ${error.message}`);
|
|
60420
60938
|
}
|
|
60421
60939
|
}
|
|
60422
60940
|
__name(webhooksEventsFlow, "webhooksEventsFlow");
|
|
@@ -60849,10 +61367,7 @@ async function webhooksCreateFlow(context, options) {
|
|
|
60849
61367
|
if (options.connectionId) {
|
|
60850
61368
|
selectedConnection = connections.find((c) => c.id === options.connectionId);
|
|
60851
61369
|
if (!selectedConnection) {
|
|
60852
|
-
|
|
60853
|
-
console.log("\nAvailable connections:");
|
|
60854
|
-
connections.forEach((c) => console.log(` - ${c.id} (${c.integrationName || c.integrationType})`));
|
|
60855
|
-
throw new Error("Connection");
|
|
61370
|
+
throw CliError.notFound(`Connection "${options.connectionId}" not found.`, listHint("Available connections:", connections.map((c) => `${c.id} (${c.integrationName || c.integrationType})`)));
|
|
60856
61371
|
}
|
|
60857
61372
|
} else {
|
|
60858
61373
|
const connectionAnswer = await safePrompt([
|
|
@@ -60891,11 +61406,7 @@ async function webhooksCreateFlow(context, options) {
|
|
|
60891
61406
|
if (options.objectType && options.event) {
|
|
60892
61407
|
selectedEvent = availableEvents.find((e) => e.objectType === options.objectType && e.event === options.event);
|
|
60893
61408
|
if (!selectedEvent) {
|
|
60894
|
-
|
|
60895
|
-
console.log(`
|
|
60896
|
-
Available events for ${selectedConnection.integrationName || selectedConnection.integrationType}:`);
|
|
60897
|
-
availableEvents.forEach((e) => console.log(` - ${e.objectType}.${e.event} [${e.webhookType}]`));
|
|
60898
|
-
throw new Error("Event");
|
|
61409
|
+
throw CliError.usage(`Event '${options.objectType}.${options.event}' is not supported.`, listHint(`Available events for ${selectedConnection.integrationName || selectedConnection.integrationType}:`, availableEvents.map((e) => `${e.objectType}.${e.event} [${e.webhookType}]`)));
|
|
60899
61410
|
}
|
|
60900
61411
|
} else {
|
|
60901
61412
|
console.log(`
|
|
@@ -61405,44 +61916,48 @@ async function mcpDeactivateInteractive(context) {
|
|
|
61405
61916
|
}
|
|
61406
61917
|
}
|
|
61407
61918
|
__name(mcpDeactivateInteractive, "mcpDeactivateInteractive");
|
|
61408
|
-
|
|
61409
|
-
|
|
61410
|
-
|
|
61411
|
-
|
|
61412
|
-
|
|
61413
|
-
|
|
61414
|
-
|
|
61415
|
-
|
|
61416
|
-
|
|
61417
|
-
|
|
61418
|
-
|
|
61419
|
-
|
|
61420
|
-
|
|
61421
|
-
|
|
61422
|
-
|
|
61423
|
-
|
|
61424
|
-
|
|
61425
|
-
|
|
61426
|
-
|
|
61427
|
-
|
|
61428
|
-
|
|
61429
|
-
|
|
61430
|
-
|
|
61431
|
-
|
|
61432
|
-
|
|
61433
|
-
|
|
61434
|
-
|
|
61435
|
-
|
|
61436
|
-
|
|
61437
|
-
|
|
61438
|
-
|
|
61439
|
-
|
|
61440
|
-
|
|
61441
|
-
|
|
61442
|
-
|
|
61443
|
-
|
|
61444
|
-
|
|
61445
|
-
|
|
61919
|
+
var INTEGRATIONS_USAGE = [
|
|
61920
|
+
"",
|
|
61921
|
+
"Usage:",
|
|
61922
|
+
" lua integrations Interactive integration management",
|
|
61923
|
+
" lua integrations connect Connect a new integration (interactive)",
|
|
61924
|
+
" lua integrations connect --integration <type> Connect a specific integration",
|
|
61925
|
+
" lua integrations connect --integration <type> --triggers <events> Connect with triggers",
|
|
61926
|
+
" lua integrations update Update connection scopes (interactive)",
|
|
61927
|
+
" lua integrations update --integration <type> Update scopes for a specific integration",
|
|
61928
|
+
" lua integrations list List connected integrations",
|
|
61929
|
+
" lua integrations available List available integrations",
|
|
61930
|
+
" lua integrations info <type> Show integration details (scopes, triggers)",
|
|
61931
|
+
" lua integrations info <type> --json Output as JSON for scripting",
|
|
61932
|
+
" lua integrations disconnect --connection-id <id> Disconnect an integration",
|
|
61933
|
+
"",
|
|
61934
|
+
"Triggers (also available as: lua triggers <action>):",
|
|
61935
|
+
" lua integrations webhooks list List all triggers",
|
|
61936
|
+
" lua integrations webhooks list --json Output as JSON",
|
|
61937
|
+
" lua integrations webhooks events --connection <id> List available events for a connection",
|
|
61938
|
+
" lua integrations webhooks events --integration <type> List available events for an integration",
|
|
61939
|
+
" lua integrations webhooks create Create trigger (interactive)",
|
|
61940
|
+
" lua integrations webhooks create --connection <id> --object <type> --event <event> --hook-url <url>",
|
|
61941
|
+
" lua integrations webhooks delete --webhook-id <id> Delete a trigger",
|
|
61942
|
+
" lua integrations webhooks pause --webhook-id <id> Pause a trigger",
|
|
61943
|
+
" lua integrations webhooks pause --connection-id <id> Pause all triggers for a connection",
|
|
61944
|
+
" lua integrations webhooks resume --webhook-id <id> Resume a trigger",
|
|
61945
|
+
" lua integrations webhooks resume --connection-id <id> Resume all triggers for a connection",
|
|
61946
|
+
"",
|
|
61947
|
+
"MCP Server Management:",
|
|
61948
|
+
" lua integrations mcp list List connections with MCP status",
|
|
61949
|
+
" lua integrations mcp activate --connection <id> Activate MCP server",
|
|
61950
|
+
" lua integrations mcp deactivate --connection <id> Deactivate MCP server",
|
|
61951
|
+
"",
|
|
61952
|
+
"Trigger Options (use with connect):",
|
|
61953
|
+
" --triggers <events> Comma-separated triggers (e.g., task_task.created,task_task.updated)",
|
|
61954
|
+
" Omit to skip triggers and add them later",
|
|
61955
|
+
" --custom-webhook Use custom URL instead of agent trigger",
|
|
61956
|
+
" --hook-url <url> Custom URL for triggers",
|
|
61957
|
+
"",
|
|
61958
|
+
"Pause Options (use with webhooks pause):",
|
|
61959
|
+
" --reason <text> Optional reason for pausing (informational)"
|
|
61960
|
+
];
|
|
61446
61961
|
|
|
61447
61962
|
// src/commands/agents.ts
|
|
61448
61963
|
init_cli();
|
|
@@ -61904,6 +62419,19 @@ init_compiler2();
|
|
|
61904
62419
|
init_artifact_loader();
|
|
61905
62420
|
init_analytics();
|
|
61906
62421
|
init_cli_error();
|
|
62422
|
+
function noAgentConfigured() {
|
|
62423
|
+
return CliError.usage("No agent configured.", "Run `lua init` first to set up a project.");
|
|
62424
|
+
}
|
|
62425
|
+
__name(noAgentConfigured, "noAgentConfigured");
|
|
62426
|
+
async function fetchModelsWithProgress(apiKey, agentId) {
|
|
62427
|
+
writeProgress("\u{1F504} Fetching available models...");
|
|
62428
|
+
try {
|
|
62429
|
+
return await fetchApprovedModelsOrThrow(apiKey, agentId);
|
|
62430
|
+
} finally {
|
|
62431
|
+
writeProgress("");
|
|
62432
|
+
}
|
|
62433
|
+
}
|
|
62434
|
+
__name(fetchModelsWithProgress, "fetchModelsWithProgress");
|
|
61907
62435
|
async function resolveCurrentModel(apiKey, agentId) {
|
|
61908
62436
|
const serverModel = await fetchServerModel(apiKey, agentId);
|
|
61909
62437
|
if (serverModel) return serverModel;
|
|
@@ -61963,14 +62491,7 @@ async function modelsCommand(action, opts) {
|
|
|
61963
62491
|
const config = readYamlConfig();
|
|
61964
62492
|
const agentId = config?.agent?.agentId;
|
|
61965
62493
|
if (resolvedAction === "list") {
|
|
61966
|
-
|
|
61967
|
-
const models = await fetchApprovedModels(apiKey, agentId);
|
|
61968
|
-
writeProgress("");
|
|
61969
|
-
if (models === null) {
|
|
61970
|
-
throw new CliError("error", "Could not fetch models from the server.", {
|
|
61971
|
-
hint: "Check your connection and API key, then retry."
|
|
61972
|
-
});
|
|
61973
|
-
}
|
|
62494
|
+
const models = await fetchModelsWithProgress(apiKey, agentId);
|
|
61974
62495
|
if (models.length === 0) {
|
|
61975
62496
|
writeInfo("\u2139\uFE0F No models are currently available. If your organization restricts models, an admin may need to review its excluded-models list.");
|
|
61976
62497
|
trackEvent("cli_models_listed", {
|
|
@@ -61990,19 +62511,10 @@ async function modelsCommand(action, opts) {
|
|
|
61990
62511
|
return;
|
|
61991
62512
|
}
|
|
61992
62513
|
if (resolvedAction === "set") {
|
|
61993
|
-
if (!agentId)
|
|
61994
|
-
|
|
61995
|
-
|
|
61996
|
-
|
|
61997
|
-
writeProgress("\u{1F504} Fetching available models...");
|
|
61998
|
-
const models = await fetchApprovedModels(apiKey, agentId);
|
|
61999
|
-
writeProgress("");
|
|
62000
|
-
if (models === null) {
|
|
62001
|
-
writeError("\u274C Could not fetch models from the server. Check your connection and API key.");
|
|
62002
|
-
process.exit(1);
|
|
62003
|
-
} else if (models.length === 0) {
|
|
62004
|
-
writeError("\u274C No models are currently available. If your organization restricts models, an admin may need to review its excluded-models list.");
|
|
62005
|
-
process.exit(1);
|
|
62514
|
+
if (!agentId) throw noAgentConfigured();
|
|
62515
|
+
const models = await fetchModelsWithProgress(apiKey, agentId);
|
|
62516
|
+
if (models.length === 0) {
|
|
62517
|
+
throw new CliError("error", "No models are currently available. If your organization restricts models, an admin may need to review its excluded-models list.");
|
|
62006
62518
|
}
|
|
62007
62519
|
let selectedModel;
|
|
62008
62520
|
if (opts.model) {
|
|
@@ -62047,10 +62559,7 @@ async function modelsCommand(action, opts) {
|
|
|
62047
62559
|
return;
|
|
62048
62560
|
}
|
|
62049
62561
|
if (resolvedAction === "unset") {
|
|
62050
|
-
if (!agentId)
|
|
62051
|
-
writeError("\u274C No agent configured. Run `lua init` first to set up a project.");
|
|
62052
|
-
process.exit(1);
|
|
62053
|
-
}
|
|
62562
|
+
if (!agentId) throw noAgentConfigured();
|
|
62054
62563
|
const currentModel = await resolveCurrentModel(apiKey, agentId);
|
|
62055
62564
|
if (!currentModel) {
|
|
62056
62565
|
writeInfo("\u2139\uFE0F No model is currently set \u2014 the platform default is already in use.");
|
|
@@ -62077,8 +62586,7 @@ async function modelsCommand(action, opts) {
|
|
|
62077
62586
|
});
|
|
62078
62587
|
return;
|
|
62079
62588
|
}
|
|
62080
|
-
|
|
62081
|
-
process.exit(1);
|
|
62589
|
+
throw CliError.usage(`Unknown action '${resolvedAction}'. Use 'list', 'set', or 'unset'.`);
|
|
62082
62590
|
}, "models");
|
|
62083
62591
|
}
|
|
62084
62592
|
__name(modelsCommand, "modelsCommand");
|
|
@@ -62627,15 +63135,15 @@ function renderTryPage(wsUrl, token) {
|
|
|
62627
63135
|
__name(renderTryPage, "renderTryPage");
|
|
62628
63136
|
|
|
62629
63137
|
// src/commands/voice.ts
|
|
63138
|
+
init_cli_error();
|
|
62630
63139
|
async function voiceTestCommand(options = {}) {
|
|
62631
63140
|
return withErrorHandling(async () => {
|
|
62632
63141
|
const cwd = process.cwd();
|
|
62633
63142
|
const runner = options.runner === "auto" || !options.runner ? detectRunner(cwd) : options.runner;
|
|
62634
63143
|
if (!runner) {
|
|
62635
|
-
|
|
62636
|
-
|
|
62637
|
-
|
|
62638
|
-
throw new Error("no test runner");
|
|
63144
|
+
throw new CliError("error", "No supported test runner found.", {
|
|
63145
|
+
hint: "Install jest or vitest in this project, then re-run.\nExample: pnpm add -D jest ts-jest @types/jest"
|
|
63146
|
+
});
|
|
62639
63147
|
}
|
|
62640
63148
|
const pattern = options.pattern ?? (options.voice ? `${escapeRegex(options.voice)}\\.voice\\.test\\.` : "\\.voice\\.test\\.");
|
|
62641
63149
|
const files = findVoiceTestFiles(cwd);
|
|
@@ -63775,14 +64283,18 @@ __name(versionStatusCommand, "versionStatusCommand");
|
|
|
63775
64283
|
init_cli();
|
|
63776
64284
|
init_files();
|
|
63777
64285
|
init_analytics();
|
|
64286
|
+
init_cli_error();
|
|
63778
64287
|
var NO_YAML_MESSAGE = "No lua.skill.yaml found. Please run this command from a skill directory.";
|
|
63779
|
-
function failConnect(status, banner, errorMessage) {
|
|
63780
|
-
if (banner) writeError(banner);
|
|
64288
|
+
function failConnect(status, banner, errorMessage, cls = "error") {
|
|
63781
64289
|
trackEvent("cli_git_connect_completed", {
|
|
63782
64290
|
...status,
|
|
63783
64291
|
succeeded: false
|
|
63784
64292
|
});
|
|
63785
|
-
|
|
64293
|
+
const hint = banner?.split("\n").map((line) => line.replace(/^✗\s*/, "").trim()).join("\n");
|
|
64294
|
+
if (cls === "usage") throw CliError.usage(errorMessage, hint);
|
|
64295
|
+
throw new CliError("error", errorMessage, {
|
|
64296
|
+
hint
|
|
64297
|
+
});
|
|
63786
64298
|
}
|
|
63787
64299
|
__name(failConnect, "failConnect");
|
|
63788
64300
|
async function gitConnectCommand(opts = {}) {
|
|
@@ -63793,7 +64305,7 @@ async function gitConnectCommand(opts = {}) {
|
|
|
63793
64305
|
git_available: false,
|
|
63794
64306
|
in_repo: false,
|
|
63795
64307
|
user_configured: false
|
|
63796
|
-
}, null, NO_YAML_MESSAGE);
|
|
64308
|
+
}, null, NO_YAML_MESSAGE, "usage");
|
|
63797
64309
|
}
|
|
63798
64310
|
if (!await isGitAvailable()) {
|
|
63799
64311
|
failConnect({
|
|
@@ -63862,7 +64374,7 @@ async function gitDisconnectCommand() {
|
|
|
63862
64374
|
return withErrorHandling(async () => {
|
|
63863
64375
|
const config = readYamlConfig();
|
|
63864
64376
|
if (!config) {
|
|
63865
|
-
throw
|
|
64377
|
+
throw CliError.usage(NO_YAML_MESSAGE);
|
|
63866
64378
|
}
|
|
63867
64379
|
config.git = {
|
|
63868
64380
|
enabled: false
|
|
@@ -64510,15 +65022,17 @@ Examples:
|
|
|
64510
65022
|
$ lua jobs versions -i myJob View job versions
|
|
64511
65023
|
$ lua jobs history -i myJob View execution history
|
|
64512
65024
|
`).action(jobsCommand);
|
|
64513
|
-
program2.command("workflows [action] [target] [extra]").description("\u{1F9ED} Manage workflows and their runs (list, start, watch, cancel, resume, approve, signal, replay)").option("-i, --workflow-name <name>", "Workflow name (or id)").option("-r, --run-id <id>", "Run id").option("-v, --workflow-version <ver>", "deploy/start/goals 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: run input").option("--idempotency-key <key>", "start: idempotency key").option("--correlation-key <key>", "start/runs: correlation key").option("--tag <tag>", "start/runs: tag (repeatable, \u2264 10)", collect, []).option("--budget-credits <n>", "start: 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: page size").option("--cursor <c>", "runs/goals list: 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/logs: step id").option("--data <json|@file>", "resume: resumeData").option("--approval <id>", "approve: approval id").option("--decision <approve|deny>", "approve: decision (default approve)").option("--note <text>", "approve/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").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)").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: cadence entry (repeatable, \u2264 5); none \u21D2 immediate", collect, []).option("--timezone <tz>", "goals create/edit: IANA timezone for bare cron cadences").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: 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", `
|
|
65025
|
+
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", `
|
|
64514
65026
|
Arguments:
|
|
64515
65027
|
action list \xB7 view \xB7 versions \xB7 deploy \xB7 activate \xB7 deactivate \xB7 start \xB7 run \xB7 runs \xB7 status \xB7
|
|
64516
|
-
watch \xB7 cancel \xB7 resume \xB7 retry-step \xB7
|
|
64517
|
-
|
|
64518
|
-
goals <list|get|create|edit|raise|pause|resume|close> \xB7
|
|
64519
|
-
|
|
64520
|
-
|
|
64521
|
-
|
|
65028
|
+
watch \xB7 cancel \xB7 resume \xB7 retry-step \xB7 resolve-step \xB7 raise-budget \xB7 approve \xB7 approval-payload \xB7
|
|
65029
|
+
signal \xB7 replay \xB7 logs \xB7 delete \xB7 delete-run \xB7 env-overlay \xB7 export \xB7 archive-runs \xB7
|
|
65030
|
+
workspace \xB7 jobs \xB7 job-logs \xB7 goals <list|get|create|edit|raise|pause|resume|close> \xB7
|
|
65031
|
+
schedules <list|create|patch|pause|resume|delete>
|
|
65032
|
+
target workflow name (list/view/versions/deploy/activate/deactivate/start/run/delete/env-overlay/export) or
|
|
65033
|
+
run id (the rest); the sub-verb for goals / schedules
|
|
65034
|
+
extra signal name (signal <runId> <name>) \xB7 goal id (goals get/edit/raise/pause/resume/close) \xB7
|
|
65035
|
+
workflow (schedules create) \xB7 job id (schedules patch/pause/resume/delete)
|
|
64522
65036
|
|
|
64523
65037
|
Exit codes: 0 ok \xB7 1 API refusal (a 4xx other than 404) \xB7 2 usage \xB7 3 not found \xB7 4 run failed \xB7 5 run cancelled \xB7
|
|
64524
65038
|
6 run gated (consent) \xB7 7 --timeout reached \xB7 8 run parked \u2014 waiting for a human
|
|
@@ -64545,10 +65059,16 @@ Examples:
|
|
|
64545
65059
|
$ lua workflows cancel <runId> --reason "wrong input"
|
|
64546
65060
|
$ lua workflows resume <runId> --step ask --data '{"answer":42}'
|
|
64547
65061
|
$ lua workflows retry-step <runId> --step sendEmails --note "vendor back up"
|
|
65062
|
+
$ lua workflows resolve-step <runId> --step sendEmails --outcome complete --output '{"sent":0}'
|
|
65063
|
+
$ lua workflows raise-budget <runId> --credits 20
|
|
65064
|
+
$ lua workflows approval-payload <runId> --approval wfa_1234
|
|
64548
65065
|
$ lua workflows approve <runId> --approval reviewDrafts --decision approve
|
|
64549
65066
|
$ lua workflows signal <runId> review --payload '{"ok":true}'
|
|
64550
65067
|
$ lua workflows replay <runId> --local
|
|
64551
65068
|
$ lua workflows deploy outreach -v latest
|
|
65069
|
+
$ lua workflows export outreach --out ./exported
|
|
65070
|
+
$ lua workflows schedules create outreach --cadence '0 9 * * 1' --timezone Europe/London --input '{"segment":"trial"}'
|
|
65071
|
+
$ lua workflows schedules resume <jobId> --backfill-now
|
|
64552
65072
|
$ lua workflows view outreach --json | jq '.data.schedules, .data.goals'
|
|
64553
65073
|
$ lua workflows goals list -i outreach --status active
|
|
64554
65074
|
$ lua workflows goals get wfg_1234
|