lua-cli 3.31.0 → 3.32.1
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 +81 -5
- package/dist/api-exports.js +686 -126
- package/dist/api-exports.js.map +1 -1
- package/dist/index.js +2003 -308
- package/dist/index.js.map +1 -1
- package/dist/workflow-builder.d.ts +37 -3
- package/dist/workflow-builder.js +658 -117
- package/dist/workflow-builder.js.map +1 -1
- package/docs/README.md +2 -2
- package/docs/api/LuaWorkflow.md +44 -28
- package/docs/api/Workflows.md +2 -1
- package/docs/workflows/approvals.md +14 -1
- package/docs/workflows/connections-in-coding-turns.md +1 -0
- package/docs/workflows/git-credentials.md +22 -1
- package/docs/workflows/goals.md +46 -0
- package/docs/workflows/recovery.md +6 -2
- package/docs/workflows/replay-local.md +10 -10
- package/docs/workflows/schedules.md +15 -0
- package/docs/workflows/testing-offline.md +22 -19
- package/docs/workflows/workspaces-and-long-steps.md +2 -0
- package/package.json +3 -3
- package/template/examples/workflows/CLAUDE.md +16 -13
- package/template/examples/workflows/pr-review-round.ts +57 -20
- package/template/examples/workflows/provision-tenant.ts +25 -8
- package/template/examples/workflows/refund-approval.ts +30 -17
- package/template/examples/workflows/support-triage.ts +59 -22
- package/template/examples/workflows/ticket-to-pr.ts +103 -31
- package/template/examples/workflows/vendor-invoices.ts +69 -16
- package/template/package.json +1 -1
package/dist/index.js
CHANGED
|
@@ -859,7 +859,6 @@ function luaClientMetricLabels(client2) {
|
|
|
859
859
|
const canonical2 = parseLuaClientHeader(serializeLuaClientHeader(client2));
|
|
860
860
|
return {
|
|
861
861
|
client_family: canonical2?.app ?? "unknown",
|
|
862
|
-
client_version: canonical2?.version ?? "unknown",
|
|
863
862
|
client_attribution: canonical2?.attribution ?? "unknown"
|
|
864
863
|
};
|
|
865
864
|
}
|
|
@@ -927,6 +926,59 @@ function scheduledTimeKey(scheduledTime) {
|
|
|
927
926
|
function scheduledWorkflowRunIdForTime(jobId, scheduledTime) {
|
|
928
927
|
return scheduledWorkflowRunId(jobId, scheduledTime);
|
|
929
928
|
}
|
|
929
|
+
function groupCount(re) {
|
|
930
|
+
let n2 = GROUP_COUNT.get(re);
|
|
931
|
+
if (n2 === void 0) {
|
|
932
|
+
n2 = new RegExp(`${re.source}|`, re.flags.replace("g", "")).exec("").length - 1;
|
|
933
|
+
GROUP_COUNT.set(re, n2);
|
|
934
|
+
}
|
|
935
|
+
return n2;
|
|
936
|
+
}
|
|
937
|
+
function applyPatterns(text, patterns) {
|
|
938
|
+
let out = text;
|
|
939
|
+
for (const { re, suffix } of patterns) {
|
|
940
|
+
re.lastIndex = 0;
|
|
941
|
+
if (!re.test(out)) continue;
|
|
942
|
+
re.lastIndex = 0;
|
|
943
|
+
const groups = groupCount(re);
|
|
944
|
+
out = out.replace(re, (...args2) => {
|
|
945
|
+
const kept = args2.slice(1, 1 + groups).map((g) => typeof g === "string" ? g : "");
|
|
946
|
+
if (suffix && kept.length > 0) {
|
|
947
|
+
const tail = kept[kept.length - 1];
|
|
948
|
+
return `${kept.slice(0, -1).join("")}${REDACTED_PLACEHOLDER}${tail}`;
|
|
949
|
+
}
|
|
950
|
+
return `${kept.join("")}${REDACTED_PLACEHOLDER}`;
|
|
951
|
+
});
|
|
952
|
+
}
|
|
953
|
+
return out;
|
|
954
|
+
}
|
|
955
|
+
function scrubSecretText(text) {
|
|
956
|
+
if (typeof text !== "string" || text.length < 4) return text;
|
|
957
|
+
return applyPatterns(applyPatterns(text, SECRET_LITERAL_PATTERNS), SECRET_PAIR_PATTERNS);
|
|
958
|
+
}
|
|
959
|
+
function scrubSecretLines(lines) {
|
|
960
|
+
return lines.map((l) => typeof l === "string" ? scrubSecretText(l) : l);
|
|
961
|
+
}
|
|
962
|
+
function messageText(value3) {
|
|
963
|
+
if (typeof value3 === "string") return value3;
|
|
964
|
+
if (value3 instanceof Error) return value3.message;
|
|
965
|
+
if (value3 && typeof value3 === "object") {
|
|
966
|
+
const m = value3.message;
|
|
967
|
+
if (typeof m === "string") return m;
|
|
968
|
+
try {
|
|
969
|
+
return JSON.stringify(value3);
|
|
970
|
+
} catch {
|
|
971
|
+
return "";
|
|
972
|
+
}
|
|
973
|
+
}
|
|
974
|
+
return value3 === void 0 || value3 === null ? "" : String(value3);
|
|
975
|
+
}
|
|
976
|
+
function scrubProviderMessage(raw, max = PROVIDER_MESSAGE_MAX_CHARS) {
|
|
977
|
+
const text = messageText(raw).replace(/\s+/g, " ").trim();
|
|
978
|
+
if (!text) return void 0;
|
|
979
|
+
const out = scrubSecretText(text);
|
|
980
|
+
return out.length > max ? `${out.slice(0, max - 1)}\u2026` : out;
|
|
981
|
+
}
|
|
930
982
|
function isWorkflowAuditEvent(action) {
|
|
931
983
|
return typeof action === "string" && WORKFLOW_AUDIT_EVENTS.includes(action);
|
|
932
984
|
}
|
|
@@ -1021,7 +1073,7 @@ ${PREAMBLE}
|
|
|
1021
1073
|
|
|
1022
1074
|
${items.join("\n\n")}`;
|
|
1023
1075
|
}
|
|
1024
|
-
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, 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, 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_SIGNAL_PAYLOAD_MAX_BYTES, WORKFLOW_AUDIT_EVENTS, WORKFLOW_AUDIT_METADATA_MAX_BYTES, INDENT, WRAP_WIDTH, NOUNS, GET_TOOL_NAMES, PREAMBLE;
|
|
1076
|
+
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, 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, REDACTED_PLACEHOLDER, PROVIDER_MESSAGE_MAX_CHARS, SECRET_LITERAL_PATTERNS, SECRET_NAME, SECRET_PAIR_PATTERNS, GROUP_COUNT, WORKFLOW_AUDIT_EVENTS, WORKFLOW_AUDIT_METADATA_MAX_BYTES, INDENT, WRAP_WIDTH, NOUNS, GET_TOOL_NAMES, PREAMBLE;
|
|
1025
1077
|
var init_dist = __esm({
|
|
1026
1078
|
"../shared-types/dist/index.mjs"() {
|
|
1027
1079
|
"use strict";
|
|
@@ -2065,6 +2117,27 @@ This text is who you are for this person. As you learn them, their name, their w
|
|
|
2065
2117
|
...WORKFLOW_RUN_IDLE,
|
|
2066
2118
|
...WORKFLOW_RUN_TERMINAL
|
|
2067
2119
|
];
|
|
2120
|
+
WORKFLOW_STEP_STATUSES = [
|
|
2121
|
+
"pending",
|
|
2122
|
+
"ready",
|
|
2123
|
+
"waiting",
|
|
2124
|
+
"dispatched",
|
|
2125
|
+
"claimed",
|
|
2126
|
+
"running",
|
|
2127
|
+
"suspended",
|
|
2128
|
+
"cancellation_requested",
|
|
2129
|
+
"completed",
|
|
2130
|
+
"failed",
|
|
2131
|
+
"skipped",
|
|
2132
|
+
"cancelled",
|
|
2133
|
+
"timeout",
|
|
2134
|
+
"reaped"
|
|
2135
|
+
];
|
|
2136
|
+
WORKFLOW_STEP_IN_FLIGHT = [
|
|
2137
|
+
"claimed",
|
|
2138
|
+
"running",
|
|
2139
|
+
"cancellation_requested"
|
|
2140
|
+
];
|
|
2068
2141
|
ARCHIVE_WINDOW_MARGIN_DAYS = 7;
|
|
2069
2142
|
__name(shouldSkipArchive, "shouldSkipArchive");
|
|
2070
2143
|
__name2(shouldSkipArchive, "shouldSkipArchive");
|
|
@@ -2095,11 +2168,90 @@ This text is who you are for this person. As you learn them, their name, their w
|
|
|
2095
2168
|
__name(workflowOrgSlotKey, "workflowOrgSlotKey");
|
|
2096
2169
|
__name2(workflowOrgSlotKey, "workflowOrgSlotKey");
|
|
2097
2170
|
WORKFLOW_JOURNAL_PROTOCOL_VERSION = 1;
|
|
2171
|
+
WORKFLOW_CONNECTION_KEY_RE = /^[a-z][a-z0-9_-]{0,63}$/;
|
|
2098
2172
|
__name(scheduledTimeKey, "scheduledTimeKey");
|
|
2099
2173
|
__name2(scheduledTimeKey, "scheduledTimeKey");
|
|
2100
2174
|
__name(scheduledWorkflowRunIdForTime, "scheduledWorkflowRunIdForTime");
|
|
2101
2175
|
__name2(scheduledWorkflowRunIdForTime, "scheduledWorkflowRunIdForTime");
|
|
2102
2176
|
WORKFLOW_SIGNAL_PAYLOAD_MAX_BYTES = 64 * 1024;
|
|
2177
|
+
REDACTED_PLACEHOLDER = "[REDACTED]";
|
|
2178
|
+
PROVIDER_MESSAGE_MAX_CHARS = 300;
|
|
2179
|
+
SECRET_LITERAL_PATTERNS = [
|
|
2180
|
+
{
|
|
2181
|
+
re: /\b(github_pat_)[A-Za-z0-9_]{16,}/g
|
|
2182
|
+
},
|
|
2183
|
+
{
|
|
2184
|
+
re: /\b(gh[pousr]_)[A-Za-z0-9]{16,}/g
|
|
2185
|
+
},
|
|
2186
|
+
{
|
|
2187
|
+
re: /\b(glpat-)[A-Za-z0-9_-]{16,}/g
|
|
2188
|
+
},
|
|
2189
|
+
{
|
|
2190
|
+
re: /\b(sk-ant-)[A-Za-z0-9_-]{16,}/g
|
|
2191
|
+
},
|
|
2192
|
+
{
|
|
2193
|
+
re: /\b(sk-)(?!ant-)[A-Za-z0-9_-]{20,}/g
|
|
2194
|
+
},
|
|
2195
|
+
{
|
|
2196
|
+
re: /\b(AKIA)[A-Z0-9]{16}\b/g
|
|
2197
|
+
},
|
|
2198
|
+
{
|
|
2199
|
+
re: /\b(xox[abprs]-)[A-Za-z0-9-]{10,}/g
|
|
2200
|
+
},
|
|
2201
|
+
{
|
|
2202
|
+
re: /\b(AIza)[0-9A-Za-z_-]{35}/g
|
|
2203
|
+
},
|
|
2204
|
+
{
|
|
2205
|
+
re: /\b(ya29\.)[A-Za-z0-9_-]{20,}/g
|
|
2206
|
+
},
|
|
2207
|
+
{
|
|
2208
|
+
re: /\b(eyJ)[A-Za-z0-9_-]{8,}\.[A-Za-z0-9_-]{8,}\.[A-Za-z0-9_-]{8,}/g
|
|
2209
|
+
},
|
|
2210
|
+
{
|
|
2211
|
+
re: /(-----BEGIN [A-Z ]*PRIVATE KEY-----)[\s\S]*?-----END [A-Z ]*PRIVATE KEY-----/g
|
|
2212
|
+
},
|
|
2213
|
+
// `https://x-access-token:<token>@github.com/…` (the git credential shape the pod scrubbed already)
|
|
2214
|
+
{
|
|
2215
|
+
re: /\b(x-access-token:)[^@\s]+(@)/g,
|
|
2216
|
+
suffix: true
|
|
2217
|
+
}
|
|
2218
|
+
];
|
|
2219
|
+
SECRET_NAME = "(?:authorization|proxy-authorization|x-api-key|x-wf-[a-z-]*key|x-internal-auth|api[_-]?key|apikey|access[_-]?key|secret[_-]?key|private[_-]?key|client[_-]?secret|secret|password|passwd|pwd|passphrase|token|credentials?)";
|
|
2220
|
+
SECRET_PAIR_PATTERNS = [
|
|
2221
|
+
// `Authorization: Bearer x`, `x-api-key: x`, `AWS_SECRET_ACCESS_KEY=x`, `SVC_JOB_KEY=x`, `"apiKey": "x"`,
|
|
2222
|
+
// `FOO_TOKEN=x`, `secretKey=x`, `password=x`. Groups: the char before the name, the name, the separator
|
|
2223
|
+
// (with its quotes), the scheme word — all kept; the value goes. A value a literal rule already replaced
|
|
2224
|
+
// (`x-access-token:[REDACTED]@host`) is left alone so the host after it survives.
|
|
2225
|
+
{
|
|
2226
|
+
re: new RegExp(`(^|[^A-Za-z0-9])((?:[A-Za-z0-9-]+[_-])?${SECRET_NAME}|[A-Za-z0-9-]+_key)(["']?\\s*[:=]\\s*["']?)((?:basic\\s+|bearer\\s+|token\\s+)?)(?!\\[REDACTED\\])[^\\s"',;)}&]{4,}`, "gi")
|
|
2227
|
+
},
|
|
2228
|
+
// `?token=x`, `&key=x`, `&X-Amz-Signature=x`, `&sig=x`
|
|
2229
|
+
{
|
|
2230
|
+
re: /([?&](?:token|key|api[_-]?key|apikey|access[_-]?token|id[_-]?token|auth|sig|signature|secret|password|pwd|x-amz-signature|x-amz-credential|x-amz-security-token)=)[^&\s"'#]+/gi
|
|
2231
|
+
},
|
|
2232
|
+
// `mongodb+srv://user:pass@host`, `postgres://user:pass@host`, `https://user:pass@host`
|
|
2233
|
+
{
|
|
2234
|
+
re: /(\/\/[^\s/:@]+:)[^\s/@]+(@)/g,
|
|
2235
|
+
suffix: true
|
|
2236
|
+
},
|
|
2237
|
+
// `Basic <base64>` / `bearer <short token>` (the literal list needs ≥ 16 chars; any case)
|
|
2238
|
+
{
|
|
2239
|
+
re: /\b((?:Basic|Bearer)\s+)(?!\[REDACTED\])[A-Za-z0-9+/=_.-]{8,}/gi
|
|
2240
|
+
}
|
|
2241
|
+
];
|
|
2242
|
+
GROUP_COUNT = /* @__PURE__ */ new WeakMap();
|
|
2243
|
+
__name(groupCount, "groupCount");
|
|
2244
|
+
__name2(groupCount, "groupCount");
|
|
2245
|
+
__name(applyPatterns, "applyPatterns");
|
|
2246
|
+
__name2(applyPatterns, "applyPatterns");
|
|
2247
|
+
__name(scrubSecretText, "scrubSecretText");
|
|
2248
|
+
__name2(scrubSecretText, "scrubSecretText");
|
|
2249
|
+
__name(scrubSecretLines, "scrubSecretLines");
|
|
2250
|
+
__name2(scrubSecretLines, "scrubSecretLines");
|
|
2251
|
+
__name(messageText, "messageText");
|
|
2252
|
+
__name2(messageText, "messageText");
|
|
2253
|
+
__name(scrubProviderMessage, "scrubProviderMessage");
|
|
2254
|
+
__name2(scrubProviderMessage, "scrubProviderMessage");
|
|
2103
2255
|
WORKFLOW_AUDIT_EVENTS = [
|
|
2104
2256
|
// --- definitions / versions / templates (13, 11 §11.11.5) ---
|
|
2105
2257
|
"workflow.published",
|
|
@@ -2719,7 +2871,11 @@ var init_request_credential = __esm({
|
|
|
2719
2871
|
// ../workflow-graph/dist/index.mjs
|
|
2720
2872
|
import { createHash as createHash2 } from "crypto";
|
|
2721
2873
|
import { z as z6 } from "zod";
|
|
2874
|
+
import { z as z22 } from "zod";
|
|
2722
2875
|
import { createHash as createHash22 } from "crypto";
|
|
2876
|
+
function sleepUntilUnsupportedMessage(id) {
|
|
2877
|
+
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} }`;
|
|
2878
|
+
}
|
|
2723
2879
|
function fillPolicy(node, defaultTimeout) {
|
|
2724
2880
|
if (node.tier === void 0 && node.workspace !== void 0 && node.workspace !== "inherit") node.tier = "job";
|
|
2725
2881
|
if (node.timeoutSeconds === void 0) node.timeoutSeconds = node.tier === "job" ? WORKFLOW_JOB_DEFAULT_TIMEOUT_SECONDS : defaultTimeout;
|
|
@@ -2814,6 +2970,12 @@ function withDefaultsFilled(g) {
|
|
|
2814
2970
|
out.definition.graph.forEach(fillEntry);
|
|
2815
2971
|
return out;
|
|
2816
2972
|
}
|
|
2973
|
+
function isConnectionKeyShaped(value22) {
|
|
2974
|
+
return WORKFLOW_CONNECTION_KEY_RE.test(value22) && !CONNECTION_ID_HEX_RE.test(value22);
|
|
2975
|
+
}
|
|
2976
|
+
function connectionKeyUndeclaredMessage(path23, key) {
|
|
2977
|
+
return `${path23} '${key}' is neither a connection id nor a declared connections[].key \u2014 declare it: connections: [{ key: '${key}', integrationType: '<catalog slug, e.g. github>' }] and it resolves on any agent`;
|
|
2978
|
+
}
|
|
2817
2979
|
function classifyModelProvider(model) {
|
|
2818
2980
|
const m = (model ?? "").trim().toLowerCase();
|
|
2819
2981
|
if (!m) return null;
|
|
@@ -2916,6 +3078,33 @@ function validateLuaExtensions(g, caps = WORKFLOW_CAPS_DEFAULT, opts = {
|
|
|
2916
3078
|
if (envelopeWorkspace?.backend && envelopeWorkspace.backend !== "ebs" && opts.policy?.workspaceBackends && !opts.policy.workspaceBackends.includes(envelopeWorkspace.backend)) {
|
|
2917
3079
|
err("workspace-backend-unavailable", `workspace.backend '${envelopeWorkspace.backend}' is not enabled (LUA_WF_WORKSPACE_BACKENDS = ${opts.policy.workspaceBackends.join(",")}) \u2014 'ebs' is the normative fallback`, "workspace.backend");
|
|
2918
3080
|
}
|
|
3081
|
+
const declaredKeys = new Set(opts.connectionKeys ?? []);
|
|
3082
|
+
if (g.connections !== void 0 && !Array.isArray(g.connections)) {
|
|
3083
|
+
err("connection-declaration-invalid", "`connections` must be an array of { key, integrationType }", "connections");
|
|
3084
|
+
}
|
|
3085
|
+
(Array.isArray(g.connections) ? g.connections : []).forEach((c, i) => {
|
|
3086
|
+
const path23 = `connections.${i}`;
|
|
3087
|
+
const key = c?.key;
|
|
3088
|
+
const integrationType = c?.integrationType;
|
|
3089
|
+
if (typeof key !== "string" || !WORKFLOW_CONNECTION_KEY_RE.test(key)) {
|
|
3090
|
+
err("connection-declaration-invalid", `connections[${i}].key must match ${WORKFLOW_CONNECTION_KEY_RE}`, `${path23}.key`);
|
|
3091
|
+
return;
|
|
3092
|
+
}
|
|
3093
|
+
if (declaredKeys.has(key)) {
|
|
3094
|
+
err("connection-declaration-invalid", `connections[${i}].key "${key}" is declared twice`, `${path23}.key`);
|
|
3095
|
+
return;
|
|
3096
|
+
}
|
|
3097
|
+
if (typeof integrationType !== "string" || !integrationType.trim()) {
|
|
3098
|
+
err("connection-declaration-invalid", `connections[${i}] ("${key}") needs an integrationType (the catalog slug, e.g. 'github')`, `${path23}.integrationType`);
|
|
3099
|
+
return;
|
|
3100
|
+
}
|
|
3101
|
+
declaredKeys.add(key);
|
|
3102
|
+
});
|
|
3103
|
+
const undeclaredKey = /* @__PURE__ */ __name3((ref) => typeof ref === "string" && !declaredKeys.has(ref) && isConnectionKeyShaped(ref) && opts.connectionIds?.has(ref) !== true, "undeclaredKey");
|
|
3104
|
+
const credentialsRef = envelopeWorkspace?.credentialsRef;
|
|
3105
|
+
if (undeclaredKey(credentialsRef)) {
|
|
3106
|
+
err("connection-key-undeclared", connectionKeyUndeclaredMessage("workspace.credentialsRef", credentialsRef), "workspace.credentialsRef");
|
|
3107
|
+
}
|
|
2919
3108
|
const seen = /* @__PURE__ */ new Map();
|
|
2920
3109
|
let nodeCount = 0;
|
|
2921
3110
|
const upstream = /* @__PURE__ */ new Set();
|
|
@@ -2927,6 +3116,16 @@ function validateLuaExtensions(g, caps = WORKFLOW_CAPS_DEFAULT, opts = {
|
|
|
2927
3116
|
seen.set(id, path23);
|
|
2928
3117
|
}
|
|
2929
3118
|
}, "checkId");
|
|
3119
|
+
const checkPolicyEnums = /* @__PURE__ */ __name3((node, path23) => {
|
|
3120
|
+
const id = singleId(node);
|
|
3121
|
+
const check = /* @__PURE__ */ __name3((member, allowed) => {
|
|
3122
|
+
const value22 = node[member];
|
|
3123
|
+
if (value22 === void 0 || typeof value22 === "string" && allowed.includes(value22)) return;
|
|
3124
|
+
err("invalid-envelope", `\`${member}\` must be ${allowed.map((a) => `'${a}'`).join(" | ")} (got ${JSON.stringify(value22)})`, `${path23}.${member}`, id);
|
|
3125
|
+
}, "check");
|
|
3126
|
+
check("sideEffects", WORKFLOW_SIDE_EFFECTS);
|
|
3127
|
+
check("jobResources", WORKFLOW_JOB_RESOURCES);
|
|
3128
|
+
}, "checkPolicyEnums");
|
|
2930
3129
|
const checkRetry = /* @__PURE__ */ __name3((node, path23) => {
|
|
2931
3130
|
const r = node.retry;
|
|
2932
3131
|
if (!r) return;
|
|
@@ -2934,6 +3133,9 @@ function validateLuaExtensions(g, caps = WORKFLOW_CAPS_DEFAULT, opts = {
|
|
|
2934
3133
|
if (r.backoff !== void 0 && r.backoff !== "fixed" && r.backoff !== "exponential") {
|
|
2935
3134
|
err("backoff-invalid", `retry.backoff must be 'fixed' | 'exponential'`, `${path23}.retry.backoff`, id);
|
|
2936
3135
|
}
|
|
3136
|
+
if (r.backoffSeconds !== void 0 && r.backoffSeconds < 0) {
|
|
3137
|
+
err("backoff-invalid", "retry.backoffSeconds must be \u2265 0", `${path23}.retry.backoffSeconds`, id);
|
|
3138
|
+
}
|
|
2937
3139
|
if (r.maxBackoffSeconds !== void 0) {
|
|
2938
3140
|
if (r.backoff !== "exponential") {
|
|
2939
3141
|
err("backoff-invalid", "retry.maxBackoffSeconds is only meaningful with backoff:'exponential'", `${path23}.retry`, id);
|
|
@@ -2995,10 +3197,15 @@ function validateLuaExtensions(g, caps = WORKFLOW_CAPS_DEFAULT, opts = {
|
|
|
2995
3197
|
}, "checkSpecialistRole");
|
|
2996
3198
|
const checkRequiredConnections = /* @__PURE__ */ __name3((node, path23) => {
|
|
2997
3199
|
const required = node.requiredConnections;
|
|
2998
|
-
if (!Array.isArray(required)
|
|
2999
|
-
const
|
|
3200
|
+
if (!Array.isArray(required)) return;
|
|
3201
|
+
const undeclared = required.filter(undeclaredKey);
|
|
3202
|
+
if (undeclared.length) {
|
|
3203
|
+
err("connection-key-undeclared", connectionKeyUndeclaredMessage(`${path23}.requiredConnections`, undeclared[0]) + (undeclared.length > 1 ? ` (also undeclared: ${JSON.stringify(undeclared.slice(1))})` : ""), `${path23}.requiredConnections`, singleId(node));
|
|
3204
|
+
}
|
|
3205
|
+
if (!opts.connectionIds) return;
|
|
3206
|
+
const unknown = required.filter((c) => typeof c !== "string" || !declaredKeys.has(c) && !opts.connectionIds.has(c));
|
|
3000
3207
|
if (unknown.length) {
|
|
3001
|
-
err("required-connection-unknown", `requiredConnections ${JSON.stringify(unknown)} are
|
|
3208
|
+
err("required-connection-unknown", `requiredConnections ${JSON.stringify(unknown)} are neither declared connections[].key values nor connections the owner can mount`, `${path23}.requiredConnections`, singleId(node));
|
|
3002
3209
|
}
|
|
3003
3210
|
}, "checkRequiredConnections");
|
|
3004
3211
|
const checkTier = /* @__PURE__ */ __name3((node, path23) => {
|
|
@@ -3084,6 +3291,7 @@ function validateLuaExtensions(g, caps = WORKFLOW_CAPS_DEFAULT, opts = {
|
|
|
3084
3291
|
return;
|
|
3085
3292
|
}
|
|
3086
3293
|
checkId(singleId(node), path23);
|
|
3294
|
+
checkPolicyEnums(node, path23);
|
|
3087
3295
|
checkTimeout(node, path23);
|
|
3088
3296
|
checkTier(node, path23);
|
|
3089
3297
|
checkRetry(node, path23);
|
|
@@ -3150,6 +3358,7 @@ function validateLuaExtensions(g, caps = WORKFLOW_CAPS_DEFAULT, opts = {
|
|
|
3150
3358
|
case "sleepUntil": {
|
|
3151
3359
|
const s = entry;
|
|
3152
3360
|
checkId(s.id, path23);
|
|
3361
|
+
err("node-type-unsupported-by-engine", sleepUntilUnsupportedMessage(s.id), path23, s.id);
|
|
3153
3362
|
if (s.date === void 0 === (s.dateFrom === void 0)) {
|
|
3154
3363
|
err("invalid-envelope", "sleepUntil needs exactly one of `date` | `dateFrom`", path23, s.id);
|
|
3155
3364
|
}
|
|
@@ -3195,7 +3404,7 @@ function validateLuaExtensions(g, caps = WORKFLOW_CAPS_DEFAULT, opts = {
|
|
|
3195
3404
|
err("invalid-envelope", "conditional.predicates must match conditional.steps one-to-one", path23);
|
|
3196
3405
|
}
|
|
3197
3406
|
(c.predicates ?? []).forEach((p, j) => {
|
|
3198
|
-
if (!
|
|
3407
|
+
if (!isWellFormedPredicate(p)) err("closure-predicate", "a conditional predicate must be a well-formed LuaPredicate object ({op, left/right | value | path | args | arg}), not a function or an expression string", `${path23}.predicates.${j}`);
|
|
3199
3408
|
});
|
|
3200
3409
|
c.steps.forEach((arm, j) => {
|
|
3201
3410
|
checkArm(arm, `${path23}.steps.${j}`, 1);
|
|
@@ -3275,7 +3484,7 @@ function validateLuaExtensions(g, caps = WORKFLOW_CAPS_DEFAULT, opts = {
|
|
|
3275
3484
|
if (l.intervalSeconds !== void 0 && (!Number.isInteger(l.intervalSeconds) || l.intervalSeconds < 1 || l.intervalSeconds > caps.maxLoopIntervalSeconds)) {
|
|
3276
3485
|
err("loop-interval-out-of-range", `loop.intervalSeconds must be an integer in 1..${caps.maxLoopIntervalSeconds}`, `${path23}.intervalSeconds`);
|
|
3277
3486
|
}
|
|
3278
|
-
if (!
|
|
3487
|
+
if (!isWellFormedPredicate(l.predicate)) err("closure-predicate", "a loop predicate must be a well-formed LuaPredicate object ({op, left/right | value | path | args | arg}), not a function or an expression string", `${path23}.predicate`);
|
|
3279
3488
|
const bodyType = l.step.type;
|
|
3280
3489
|
if (bodyType === "mapping") err("container-arm-empty", "a loop body needs a step, not a bare mapping", `${path23}.step`);
|
|
3281
3490
|
else if (bodyType === "approval" || bodyType === "waitForSignal") err("approval-inside-container", "approval / waitForSignal are top-level only in v1", `${path23}.step`);
|
|
@@ -3338,6 +3547,41 @@ function validateLuaExtensions(g, caps = WORKFLOW_CAPS_DEFAULT, opts = {
|
|
|
3338
3547
|
function isPredicate(p) {
|
|
3339
3548
|
return typeof p === "object" && p !== null && typeof p.op === "string" && PREDICATE_OPS.has(p.op);
|
|
3340
3549
|
}
|
|
3550
|
+
function isPathOrLiteral(v) {
|
|
3551
|
+
if (typeof v !== "object" || v === null) return false;
|
|
3552
|
+
const r = v;
|
|
3553
|
+
if ("path" in r) return typeof r.path === "string" && r.path.length > 0;
|
|
3554
|
+
return "literal" in r && isPredicateScalar(r.literal);
|
|
3555
|
+
}
|
|
3556
|
+
function isWellFormedPredicate(p) {
|
|
3557
|
+
if (!isPredicate(p)) return false;
|
|
3558
|
+
const r = p;
|
|
3559
|
+
switch (r.op) {
|
|
3560
|
+
case "eq":
|
|
3561
|
+
case "ne":
|
|
3562
|
+
case "lt":
|
|
3563
|
+
case "lte":
|
|
3564
|
+
case "gt":
|
|
3565
|
+
case "gte":
|
|
3566
|
+
return isPathOrLiteral(r.left) && isPathOrLiteral(r.right);
|
|
3567
|
+
case "in":
|
|
3568
|
+
case "notIn":
|
|
3569
|
+
return isPathOrLiteral(r.value) && Array.isArray(r.set) && r.set.every(isPredicateScalar);
|
|
3570
|
+
case "exists":
|
|
3571
|
+
case "notExists":
|
|
3572
|
+
return typeof r.path === "string" && r.path.length > 0;
|
|
3573
|
+
case "truthy":
|
|
3574
|
+
case "falsy":
|
|
3575
|
+
return isPathOrLiteral(r.value);
|
|
3576
|
+
case "and":
|
|
3577
|
+
case "or":
|
|
3578
|
+
return Array.isArray(r.args) && r.args.every(isWellFormedPredicate);
|
|
3579
|
+
case "not":
|
|
3580
|
+
return isWellFormedPredicate(r.arg);
|
|
3581
|
+
default:
|
|
3582
|
+
return false;
|
|
3583
|
+
}
|
|
3584
|
+
}
|
|
3341
3585
|
function canonicalJson(value22) {
|
|
3342
3586
|
const seen = /* @__PURE__ */ new WeakSet();
|
|
3343
3587
|
const encode = /* @__PURE__ */ __name3((v) => {
|
|
@@ -3763,13 +4007,13 @@ function parseTemplatePlaceholder(rawExpr) {
|
|
|
3763
4007
|
rest: dot === -1 ? "" : rawExpr.slice(dot + 1)
|
|
3764
4008
|
};
|
|
3765
4009
|
}
|
|
3766
|
-
function traverseMappingPath(root, path23,
|
|
4010
|
+
function traverseMappingPath(root, path23, errorLabel2) {
|
|
3767
4011
|
if (path23 === "" || path23 === ".") return root;
|
|
3768
4012
|
const parts = path23.split(".");
|
|
3769
4013
|
let value22 = root;
|
|
3770
4014
|
for (const part of parts) {
|
|
3771
4015
|
if (typeof value22 === "object" && value22 !== null) value22 = value22[part];
|
|
3772
|
-
else throw new WorkflowTemplateError(`Invalid path ${path23} in ${
|
|
4016
|
+
else throw new WorkflowTemplateError(`Invalid path ${path23} in ${errorLabel2}`, path23);
|
|
3773
4017
|
}
|
|
3774
4018
|
return value22;
|
|
3775
4019
|
}
|
|
@@ -3900,6 +4144,25 @@ function resolveMapping(cfg, ctx) {
|
|
|
3900
4144
|
value: result
|
|
3901
4145
|
};
|
|
3902
4146
|
}
|
|
4147
|
+
function continuedFailureValue(error, killReason) {
|
|
4148
|
+
const code = typeof error?.code === "string" && error.code || typeof killReason === "string" && killReason || CONTINUED_FAILURE_DEFAULT_CODE;
|
|
4149
|
+
const message = typeof error?.message === "string" && error.message ? error.message : code;
|
|
4150
|
+
return {
|
|
4151
|
+
__lua_workflow: CONTINUED_FAILURE_TAG,
|
|
4152
|
+
failed: true,
|
|
4153
|
+
error: {
|
|
4154
|
+
code,
|
|
4155
|
+
message
|
|
4156
|
+
},
|
|
4157
|
+
text: ""
|
|
4158
|
+
};
|
|
4159
|
+
}
|
|
4160
|
+
function isContinuedFailureValue(v) {
|
|
4161
|
+
if (v === null || typeof v !== "object" || Array.isArray(v)) return false;
|
|
4162
|
+
const o = v;
|
|
4163
|
+
const err = o.error;
|
|
4164
|
+
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";
|
|
4165
|
+
}
|
|
3903
4166
|
function lowerContainerArm(mapping, step22) {
|
|
3904
4167
|
const stepId = nodeIdOf(step22);
|
|
3905
4168
|
return {
|
|
@@ -3997,7 +4260,7 @@ function resolvePlacements(calls) {
|
|
|
3997
4260
|
if (!d) {
|
|
3998
4261
|
issues.push({
|
|
3999
4262
|
code: "unknown-step-ref",
|
|
4000
|
-
message: `"${ref.ref}" is not declared anywhere in the chain \u2014 declare it with agentStep/specialistStep/toolStep/map(\u2026, { id })`,
|
|
4263
|
+
message: `"${ref.ref}" is not declared anywhere in the chain \u2014 declare it with agentStep/specialistStep/toolStep/map(\u2026, { id })/workflow(\u2026)`,
|
|
4001
4264
|
callIndex: i,
|
|
4002
4265
|
stepId: ref.ref
|
|
4003
4266
|
});
|
|
@@ -4049,9 +4312,9 @@ function resolvePlacements(calls) {
|
|
|
4049
4312
|
});
|
|
4050
4313
|
const graph = [];
|
|
4051
4314
|
const lookup = /* @__PURE__ */ __name3((ref) => {
|
|
4052
|
-
const
|
|
4053
|
-
if (!
|
|
4054
|
-
return lowerContainerArm(ref.armMap,
|
|
4315
|
+
const n2 = "node" in ref ? ref.node : declared.get(ref.ref)?.node;
|
|
4316
|
+
if (!n2 || !ref.armMap || n2.type === "mapping") return n2;
|
|
4317
|
+
return lowerContainerArm(ref.armMap, n2);
|
|
4055
4318
|
}, "lookup");
|
|
4056
4319
|
calls.forEach((call, i) => {
|
|
4057
4320
|
switch (call.kind) {
|
|
@@ -4070,7 +4333,7 @@ function resolvePlacements(calls) {
|
|
|
4070
4333
|
return;
|
|
4071
4334
|
}
|
|
4072
4335
|
case "parallel": {
|
|
4073
|
-
const steps = call.arms.map(lookup).filter((
|
|
4336
|
+
const steps = call.arms.map(lookup).filter((n2) => !!n2 && n2.type !== "mapping");
|
|
4074
4337
|
const node = {
|
|
4075
4338
|
type: "parallel",
|
|
4076
4339
|
steps
|
|
@@ -4083,9 +4346,9 @@ function resolvePlacements(calls) {
|
|
|
4083
4346
|
const steps = [];
|
|
4084
4347
|
const predicates = [];
|
|
4085
4348
|
for (const a of call.arms) {
|
|
4086
|
-
const
|
|
4087
|
-
if (!
|
|
4088
|
-
steps.push(
|
|
4349
|
+
const n2 = lookup(a.target);
|
|
4350
|
+
if (!n2) continue;
|
|
4351
|
+
steps.push(n2);
|
|
4089
4352
|
predicates.push(a.predicate);
|
|
4090
4353
|
}
|
|
4091
4354
|
const node = {
|
|
@@ -4189,31 +4452,54 @@ function seedLedgerFromRun(run, steps, targetPlan, opts = {}) {
|
|
|
4189
4452
|
graphChanged
|
|
4190
4453
|
};
|
|
4191
4454
|
}
|
|
4455
|
+
function branchSpecFromConditional(entry) {
|
|
4456
|
+
return {
|
|
4457
|
+
arms: entry.steps.map((arm, i) => ({
|
|
4458
|
+
stepId: branchArmId(arm),
|
|
4459
|
+
predicate: entry.predicates[i]
|
|
4460
|
+
})),
|
|
4461
|
+
...entry.exclusive === true ? {
|
|
4462
|
+
exclusive: true
|
|
4463
|
+
} : {},
|
|
4464
|
+
...entry.otherwise ? {
|
|
4465
|
+
otherwise: branchArmId(entry.otherwise)
|
|
4466
|
+
} : {}
|
|
4467
|
+
};
|
|
4468
|
+
}
|
|
4469
|
+
function selectBranchArms(spec, ctx) {
|
|
4470
|
+
const taken = [];
|
|
4471
|
+
for (const arm of spec.arms) {
|
|
4472
|
+
if (spec.exclusive && taken.length > 0) break;
|
|
4473
|
+
const hit = arm.predicate ? evaluatePredicate(arm.predicate, ctx) : false;
|
|
4474
|
+
if (hit) taken.push(arm.stepId);
|
|
4475
|
+
}
|
|
4476
|
+
if (taken.length === 0 && spec.otherwise) taken.push(spec.otherwise);
|
|
4477
|
+
return taken;
|
|
4478
|
+
}
|
|
4192
4479
|
function replayLedger(g, ledger) {
|
|
4193
4480
|
const plan = compilePlan(g);
|
|
4194
4481
|
const rows22 = new Map(ledger.steps.map((r) => [
|
|
4195
4482
|
r.stepId,
|
|
4196
4483
|
r
|
|
4197
4484
|
]));
|
|
4198
|
-
const
|
|
4199
|
-
|
|
4200
|
-
|
|
4485
|
+
const requestContext = {
|
|
4486
|
+
runId: "replay",
|
|
4487
|
+
workflowId: g.definition.id,
|
|
4488
|
+
orgId: "",
|
|
4489
|
+
agentId: "",
|
|
4490
|
+
userId: "",
|
|
4491
|
+
trigger: "sdk",
|
|
4492
|
+
threadId: "replay",
|
|
4493
|
+
depth: 0,
|
|
4494
|
+
startedAt: 0,
|
|
4495
|
+
...ledger.requestContext
|
|
4496
|
+
};
|
|
4497
|
+
const ctxFor = /* @__PURE__ */ __name3((id) => ({
|
|
4201
4498
|
initData: ledger.initData,
|
|
4202
|
-
stepResults,
|
|
4499
|
+
stepResults: ancestorResults(plan, id, rows22),
|
|
4203
4500
|
state: ledger.state ?? {},
|
|
4204
|
-
requestContext
|
|
4205
|
-
|
|
4206
|
-
workflowId: g.definition.id,
|
|
4207
|
-
orgId: "",
|
|
4208
|
-
agentId: "",
|
|
4209
|
-
userId: "",
|
|
4210
|
-
trigger: "sdk",
|
|
4211
|
-
threadId: "replay",
|
|
4212
|
-
depth: 0,
|
|
4213
|
-
startedAt: 0,
|
|
4214
|
-
...ledger.requestContext
|
|
4215
|
-
}
|
|
4216
|
-
};
|
|
4501
|
+
requestContext
|
|
4502
|
+
}), "ctxFor");
|
|
4217
4503
|
const verdicts = [];
|
|
4218
4504
|
for (const id of plan.order) {
|
|
4219
4505
|
const node = plan.steps[id];
|
|
@@ -4221,17 +4507,7 @@ function replayLedger(g, ledger) {
|
|
|
4221
4507
|
if (!recorded || recorded.status === "pending" || recorded.status === "skipped") continue;
|
|
4222
4508
|
if (node.kind === "branch") {
|
|
4223
4509
|
const entry = node.entry;
|
|
4224
|
-
const taken =
|
|
4225
|
-
entry.steps.forEach((arm, i) => {
|
|
4226
|
-
const pred = entry.predicates[i];
|
|
4227
|
-
const hit = pred ? evaluatePredicate(pred, {
|
|
4228
|
-
initData: ledger.initData,
|
|
4229
|
-
stepResults,
|
|
4230
|
-
state: ledger.state
|
|
4231
|
-
}) : false;
|
|
4232
|
-
if (hit && (!entry.exclusive || taken.length === 0)) taken.push(armId2(arm));
|
|
4233
|
-
});
|
|
4234
|
-
if (taken.length === 0 && entry.otherwise) taken.push(armId2(entry.otherwise));
|
|
4510
|
+
const taken = selectBranchArms(branchSpecFromConditional(entry), ctxFor(id));
|
|
4235
4511
|
const recordedTaken = recorded.taken ?? inferTaken(entry, rows22);
|
|
4236
4512
|
verdicts.push({
|
|
4237
4513
|
stepId: id,
|
|
@@ -4242,7 +4518,7 @@ function replayLedger(g, ledger) {
|
|
|
4242
4518
|
});
|
|
4243
4519
|
} else if (node.kind === "map" && !id.endsWith(".join") && recorded.status === "completed") {
|
|
4244
4520
|
const entry = node.entry;
|
|
4245
|
-
const resolved = resolveMapping(parseMapConfig(entry.mapConfig, id),
|
|
4521
|
+
const resolved = resolveMapping(parseMapConfig(entry.mapConfig, id), ctxFor(id));
|
|
4246
4522
|
const local = "error" in resolved ? {
|
|
4247
4523
|
error: resolved.error,
|
|
4248
4524
|
key: resolved.key
|
|
@@ -4257,7 +4533,7 @@ function replayLedger(g, ledger) {
|
|
|
4257
4533
|
} else if (node.kind === "foreach") {
|
|
4258
4534
|
const entry = node.entry;
|
|
4259
4535
|
const source = node.dependsOn[0];
|
|
4260
|
-
const items = source ? stepResults[source] : void 0;
|
|
4536
|
+
const items = source ? ctxFor(id).stepResults[source] : void 0;
|
|
4261
4537
|
const local = Array.isArray(items) ? items.length : void 0;
|
|
4262
4538
|
const recordedCount = recorded.itemCount ?? countChildren(entry, rows22);
|
|
4263
4539
|
verdicts.push({
|
|
@@ -4274,6 +4550,71 @@ function replayLedger(g, ledger) {
|
|
|
4274
4550
|
diverged: verdicts.some((v) => v.diverged)
|
|
4275
4551
|
};
|
|
4276
4552
|
}
|
|
4553
|
+
function replayResultOf(row2, node) {
|
|
4554
|
+
if (!row2) return void 0;
|
|
4555
|
+
if (row2.status === "completed") return {
|
|
4556
|
+
value: row2.output
|
|
4557
|
+
};
|
|
4558
|
+
if (row2.status === "failed") {
|
|
4559
|
+
const onError = row2.onError ?? node?.entry?.onError;
|
|
4560
|
+
if (onError === "continue") return {
|
|
4561
|
+
value: continuedFailureValue(row2.error, row2.killReason)
|
|
4562
|
+
};
|
|
4563
|
+
}
|
|
4564
|
+
return void 0;
|
|
4565
|
+
}
|
|
4566
|
+
function ancestorResults(plan, id, rows22) {
|
|
4567
|
+
const out = {};
|
|
4568
|
+
const joinAliased = /* @__PURE__ */ new Set();
|
|
4569
|
+
const seen = /* @__PURE__ */ new Set();
|
|
4570
|
+
const take = /* @__PURE__ */ __name3((rowId) => {
|
|
4571
|
+
const hit = replayResultOf(rows22.get(rowId), plan.steps[rowId]);
|
|
4572
|
+
if (!hit) return void 0;
|
|
4573
|
+
if (!joinAliased.has(rowId)) out[rowId] = hit.value;
|
|
4574
|
+
const entryId = entryOfJoin(rowId);
|
|
4575
|
+
if (entryId) {
|
|
4576
|
+
out[entryId] = hit.value;
|
|
4577
|
+
joinAliased.add(entryId);
|
|
4578
|
+
const entryNode = plan.steps[entryId];
|
|
4579
|
+
if (entryNode?.kind === "foreach") {
|
|
4580
|
+
const body = branchArmId(entryNode.entry.step);
|
|
4581
|
+
out[body] = hit.value;
|
|
4582
|
+
joinAliased.add(body);
|
|
4583
|
+
}
|
|
4584
|
+
}
|
|
4585
|
+
return hit;
|
|
4586
|
+
}, "take");
|
|
4587
|
+
const walk22 = /* @__PURE__ */ __name3((ids) => {
|
|
4588
|
+
for (const dep of ids) {
|
|
4589
|
+
if (seen.has(dep)) continue;
|
|
4590
|
+
seen.add(dep);
|
|
4591
|
+
take(dep);
|
|
4592
|
+
const node = plan.steps[dep] ?? plan.steps[entryOfJoin(dep) ?? ""];
|
|
4593
|
+
if (!node) continue;
|
|
4594
|
+
if (node.kind === "foreach") {
|
|
4595
|
+
const body = branchArmId(node.entry.step);
|
|
4596
|
+
for (const rowId of rows22.keys()) if (rowId.startsWith(`${body}[`)) take(rowId);
|
|
4597
|
+
} else if (node.kind === "loop") {
|
|
4598
|
+
const body = branchArmId(node.entry.step);
|
|
4599
|
+
let best = -1;
|
|
4600
|
+
for (const rowId of rows22.keys()) {
|
|
4601
|
+
if (!rowId.startsWith(`${body}#`)) continue;
|
|
4602
|
+
const n2 = Number(rowId.slice(body.length + 1));
|
|
4603
|
+
if (!Number.isInteger(n2)) continue;
|
|
4604
|
+
const hit = take(rowId);
|
|
4605
|
+
if (!hit) continue;
|
|
4606
|
+
if (n2 > best) {
|
|
4607
|
+
best = n2;
|
|
4608
|
+
out[body] = hit.value;
|
|
4609
|
+
}
|
|
4610
|
+
}
|
|
4611
|
+
}
|
|
4612
|
+
walk22(node.dependsOn);
|
|
4613
|
+
}
|
|
4614
|
+
}, "walk");
|
|
4615
|
+
walk22(plan.steps[id]?.dependsOn ?? []);
|
|
4616
|
+
return out;
|
|
4617
|
+
}
|
|
4277
4618
|
function inferTaken(entry, rows22) {
|
|
4278
4619
|
const arms = [
|
|
4279
4620
|
...entry.steps,
|
|
@@ -4281,16 +4622,16 @@ function inferTaken(entry, rows22) {
|
|
|
4281
4622
|
entry.otherwise
|
|
4282
4623
|
] : []
|
|
4283
4624
|
];
|
|
4284
|
-
return arms.map(
|
|
4625
|
+
return arms.map(branchArmId).filter((id) => {
|
|
4285
4626
|
const r = rows22.get(id);
|
|
4286
4627
|
return r !== void 0 && r.status !== "skipped" && r.status !== "pending";
|
|
4287
4628
|
});
|
|
4288
4629
|
}
|
|
4289
4630
|
function countChildren(entry, rows22) {
|
|
4290
|
-
const body =
|
|
4291
|
-
let
|
|
4292
|
-
for (const id of rows22.keys()) if (id.startsWith(`${body}[`))
|
|
4293
|
-
return
|
|
4631
|
+
const body = branchArmId(entry.step);
|
|
4632
|
+
let n2 = 0;
|
|
4633
|
+
for (const id of rows22.keys()) if (id.startsWith(`${body}[`)) n2 += 1;
|
|
4634
|
+
return n2;
|
|
4294
4635
|
}
|
|
4295
4636
|
function isTerminalRunStatus(status) {
|
|
4296
4637
|
return TERMINAL.has(status);
|
|
@@ -4299,19 +4640,48 @@ function pruneUndefined(o) {
|
|
|
4299
4640
|
return Object.fromEntries(Object.entries(o).filter(([, v]) => v !== void 0));
|
|
4300
4641
|
}
|
|
4301
4642
|
function runNextAction(run) {
|
|
4302
|
-
if (isTerminalRunStatus(run.status)
|
|
4643
|
+
if (isTerminalRunStatus(run.status)) return "none";
|
|
4644
|
+
if (run.status === "suspended" && run.gate?.kind === "budget") return "raise_budget";
|
|
4645
|
+
if (!run.cancel?.requestedAt) return "none";
|
|
4303
4646
|
const forceAt = run.cancel.forceAfter ?? run.cancel.requestedAt + FORCE_CANCEL_STALE_MS;
|
|
4304
4647
|
return Date.now() >= forceAt ? "force" : "cancel_again";
|
|
4305
4648
|
}
|
|
4649
|
+
function emptyRunCounts() {
|
|
4650
|
+
const out = {
|
|
4651
|
+
total: 0,
|
|
4652
|
+
inFlight: 0
|
|
4653
|
+
};
|
|
4654
|
+
for (const status of WORKFLOW_STEP_STATUSES) out[status] = 0;
|
|
4655
|
+
return out;
|
|
4656
|
+
}
|
|
4657
|
+
function runCountsFromStatusTally(tally) {
|
|
4658
|
+
const out = emptyRunCounts();
|
|
4659
|
+
for (const [status, n2] of Object.entries(tally)) {
|
|
4660
|
+
if (!Number.isFinite(n2) || n2 <= 0) continue;
|
|
4661
|
+
out.total += n2;
|
|
4662
|
+
if (WORKFLOW_STEP_STATUSES.includes(status)) out[status] += n2;
|
|
4663
|
+
if (IN_FLIGHT.has(status)) out.inFlight += n2;
|
|
4664
|
+
}
|
|
4665
|
+
return out;
|
|
4666
|
+
}
|
|
4667
|
+
function runCountsFromStepStatuses(statuses) {
|
|
4668
|
+
const tally = {};
|
|
4669
|
+
for (const s of statuses) tally[s] = (tally[s] ?? 0) + 1;
|
|
4670
|
+
return runCountsFromStatusTally(tally);
|
|
4671
|
+
}
|
|
4306
4672
|
function runCounts(counts) {
|
|
4673
|
+
const c = counts ?? {};
|
|
4674
|
+
const rawInFlight = c.dispatched !== void 0 || c.claimed !== void 0 || c.running !== void 0 || c.cancellation_requested !== void 0;
|
|
4307
4675
|
return {
|
|
4308
|
-
total:
|
|
4309
|
-
completed:
|
|
4310
|
-
failed:
|
|
4311
|
-
skipped:
|
|
4312
|
-
|
|
4313
|
-
|
|
4314
|
-
|
|
4676
|
+
total: n(c.total),
|
|
4677
|
+
completed: n(c.completed),
|
|
4678
|
+
failed: n(c.failed) + n(c.timeout) + n(c.reaped),
|
|
4679
|
+
skipped: n(c.skipped),
|
|
4680
|
+
// LUA-664: cancelled rows never ran — their own wire bucket, never a failure (the detail's map, verbatim).
|
|
4681
|
+
cancelled: n(c.cancelled),
|
|
4682
|
+
running: rawInFlight ? n(c.dispatched) + n(c.claimed) + n(c.running) + n(c.cancellation_requested) : n(c.inFlight),
|
|
4683
|
+
suspended: n(c.suspended),
|
|
4684
|
+
pending: n(c.pending) + n(c.ready) + n(c.waiting)
|
|
4315
4685
|
};
|
|
4316
4686
|
}
|
|
4317
4687
|
function runUsage(run) {
|
|
@@ -4335,7 +4705,7 @@ function runWorkspaceView(ws) {
|
|
|
4335
4705
|
if (!ws) return void 0;
|
|
4336
4706
|
const w = ws;
|
|
4337
4707
|
return pruneUndefined({
|
|
4338
|
-
kind: w.kind ?? "empty",
|
|
4708
|
+
kind: w.spec?.kind ?? w.kind ?? "empty",
|
|
4339
4709
|
backend: w.backend,
|
|
4340
4710
|
status: String(w.status ?? ""),
|
|
4341
4711
|
branch: w.branch,
|
|
@@ -4397,7 +4767,10 @@ function toWorkflowRunSummary(run) {
|
|
|
4397
4767
|
eventSeq: run.eventSeq ?? 0,
|
|
4398
4768
|
cancellable: !isTerminalRunStatus(status),
|
|
4399
4769
|
nextAction: runNextAction(run),
|
|
4400
|
-
workspace: runWorkspaceView(run.workspace)
|
|
4770
|
+
workspace: runWorkspaceView(run.workspace),
|
|
4771
|
+
// LUA-643: the runs list says a result exists; R4 `fields:'full'` (output-ACL gated, audited) serves it. The
|
|
4772
|
+
// stamped flag is what a list page carries (it projects `output` out); the payload members cover R4's full row.
|
|
4773
|
+
hasOutput: run.hasOutput === true || run.output !== void 0 || run.outputRef !== void 0 ? true : void 0
|
|
4401
4774
|
});
|
|
4402
4775
|
}
|
|
4403
4776
|
function timeZoneSupported(tz) {
|
|
@@ -5092,8 +5465,8 @@ function armEntry(arm) {
|
|
|
5092
5465
|
}
|
|
5093
5466
|
function ofEntry(e) {
|
|
5094
5467
|
if (!e || typeof e !== "object") return ZERO;
|
|
5095
|
-
const
|
|
5096
|
-
switch (
|
|
5468
|
+
const n2 = e;
|
|
5469
|
+
switch (n2.type) {
|
|
5097
5470
|
case "agent":
|
|
5098
5471
|
return {
|
|
5099
5472
|
steps: {
|
|
@@ -5126,17 +5499,17 @@ function ofEntry(e) {
|
|
|
5126
5499
|
agentCalls: 0
|
|
5127
5500
|
};
|
|
5128
5501
|
case "parallel": {
|
|
5129
|
-
const arms = Array.isArray(
|
|
5502
|
+
const arms = Array.isArray(n2.steps) ? n2.steps : [];
|
|
5130
5503
|
return arms.map(armEntry).map(ofEntry).reduce(add, ZERO);
|
|
5131
5504
|
}
|
|
5132
5505
|
case "conditional": {
|
|
5133
|
-
const arms = (Array.isArray(
|
|
5506
|
+
const arms = (Array.isArray(n2.steps) ? n2.steps : []).map(armEntry).map(ofEntry);
|
|
5134
5507
|
if (arms.length === 0) return ZERO;
|
|
5135
|
-
const hasOtherwise =
|
|
5508
|
+
const hasOtherwise = n2.otherwise !== void 0;
|
|
5136
5509
|
const minArm = arms.reduce((a, b) => b.credits.min < a.credits.min ? b : a);
|
|
5137
5510
|
const maxArm = arms.reduce((a, b) => b.credits.max > a.credits.max ? b : a);
|
|
5138
5511
|
const summed = arms.reduce(add, ZERO);
|
|
5139
|
-
const max =
|
|
5512
|
+
const max = n2.exclusive === true ? maxArm : summed;
|
|
5140
5513
|
const min = hasOtherwise ? minArm : {
|
|
5141
5514
|
...ZERO
|
|
5142
5515
|
};
|
|
@@ -5153,17 +5526,14 @@ function ofEntry(e) {
|
|
|
5153
5526
|
};
|
|
5154
5527
|
}
|
|
5155
5528
|
case "foreach": {
|
|
5156
|
-
const body = ofEntry(armEntry(
|
|
5157
|
-
const opts =
|
|
5158
|
-
const cap = typeof opts.maxItems === "number" && opts.maxItems > 0 ? opts.maxItems :
|
|
5529
|
+
const body = ofEntry(armEntry(n2.step));
|
|
5530
|
+
const opts = n2.opts ?? {};
|
|
5531
|
+
const cap = typeof opts.maxItems === "number" && opts.maxItems > 0 ? opts.maxItems : WORKFLOW_FOREACH_DEFAULT_MAX_ITEMS;
|
|
5159
5532
|
return scale(body, 0, cap);
|
|
5160
5533
|
}
|
|
5161
|
-
case "loop":
|
|
5162
|
-
|
|
5163
|
-
|
|
5164
|
-
const body = ofEntry(armEntry(n.step));
|
|
5165
|
-
const opts = n.options ?? {};
|
|
5166
|
-
const cap = typeof opts.maxIterations === "number" && opts.maxIterations > 0 ? opts.maxIterations : 1;
|
|
5534
|
+
case "loop": {
|
|
5535
|
+
const body = ofEntry(armEntry(n2.step));
|
|
5536
|
+
const cap = typeof n2.maxIterations === "number" && n2.maxIterations > 0 ? n2.maxIterations : WORKFLOW_LOOP_DEFAULT_MAX_ITERATIONS;
|
|
5167
5537
|
return scale(body, 1, cap);
|
|
5168
5538
|
}
|
|
5169
5539
|
default:
|
|
@@ -5194,14 +5564,84 @@ function estimateGraph(envelopeOrGraph) {
|
|
|
5194
5564
|
consentCredits: r.credits.max
|
|
5195
5565
|
};
|
|
5196
5566
|
}
|
|
5197
|
-
|
|
5567
|
+
function* singleStepsOf(entry) {
|
|
5568
|
+
if (!isRecord2(entry)) return;
|
|
5569
|
+
switch (entry.type) {
|
|
5570
|
+
case "step":
|
|
5571
|
+
case "agent":
|
|
5572
|
+
case "tool":
|
|
5573
|
+
yield entry;
|
|
5574
|
+
return;
|
|
5575
|
+
case "workflow":
|
|
5576
|
+
yield entry;
|
|
5577
|
+
if (Array.isArray(entry.graph)) yield* singleStepsOf(entry.graph[1]);
|
|
5578
|
+
return;
|
|
5579
|
+
case "parallel":
|
|
5580
|
+
case "conditional":
|
|
5581
|
+
if (Array.isArray(entry.steps)) for (const arm of entry.steps) yield* singleStepsOf(arm);
|
|
5582
|
+
yield* singleStepsOf(entry.otherwise);
|
|
5583
|
+
return;
|
|
5584
|
+
case "foreach":
|
|
5585
|
+
case "loop":
|
|
5586
|
+
yield* singleStepsOf(entry.step);
|
|
5587
|
+
return;
|
|
5588
|
+
default:
|
|
5589
|
+
return;
|
|
5590
|
+
}
|
|
5591
|
+
}
|
|
5592
|
+
function entriesOf(graph) {
|
|
5593
|
+
const definition = isRecord2(graph) ? graph.definition : void 0;
|
|
5594
|
+
const entries = isRecord2(definition) ? definition.graph : void 0;
|
|
5595
|
+
return Array.isArray(entries) ? entries : [];
|
|
5596
|
+
}
|
|
5597
|
+
function inheritTargets(graphs) {
|
|
5598
|
+
const targets = /* @__PURE__ */ new Set();
|
|
5599
|
+
for (const graph of graphs) {
|
|
5600
|
+
for (const entry of entriesOf(graph)) {
|
|
5601
|
+
for (const node of singleStepsOf(entry)) {
|
|
5602
|
+
if (node.type === "workflow" && node.workspace === "inherit" && typeof node.workflowId === "string" && node.workflowId.length > 0) {
|
|
5603
|
+
targets.add(node.workflowId);
|
|
5604
|
+
}
|
|
5605
|
+
}
|
|
5606
|
+
}
|
|
5607
|
+
}
|
|
5608
|
+
return targets;
|
|
5609
|
+
}
|
|
5610
|
+
function needsInheritedWorkspace(graph) {
|
|
5611
|
+
if (!isRecord2(graph) || graph.workspace !== void 0) return false;
|
|
5612
|
+
for (const entry of entriesOf(graph)) {
|
|
5613
|
+
for (const node of singleStepsOf(entry)) {
|
|
5614
|
+
if (node.workspace !== void 0 && node.workspace !== "inherit") return true;
|
|
5615
|
+
}
|
|
5616
|
+
}
|
|
5617
|
+
return false;
|
|
5618
|
+
}
|
|
5619
|
+
var __defProp3, __name3, WORKFLOW_SIDE_EFFECTS, WORKFLOW_JOB_RESOURCES, SideEffectsSchema, JobResourcesSchema, WORKFLOW_ARM_SUBRUN_ID, 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, singleId, armId, TEMPLATE_STEP_REF, EDITABLE_PATH_RE, PREDICATE_OPS, isPredicateScalar, GRAPH_HASH_PREFIX, WorkflowPlanError, SINGLE_STEP_KINDS, isSingleStep, singleStepId, joinIdOf, containerIdOf, PATH_PLACEHOLDER, MISSING, stepIdOf, cmp, eq, ne, gt, gte, lt, lte, inSet, notIn, exists, notExists, truthy, falsy, and, or, not, WorkflowTemplateError, TEMPLATE_PLACEHOLDER, TEMPLATE_NAMESPACES, fromInit, fromStep, value, template, fromRequest, rows, fromKnowledge, CONTINUED_FAILURE_TAG, CONTINUED_FAILURE_DEFAULT_CODE, CONTINUED_FAILURE_OUTPUT_SCHEMA, CONTINUED_FAILURE_LEAF_PATHS, nodeIdOf, branchArmId, canonical, sortKeys, JOIN, entryOfJoin, FORCE_CANCEL_STALE_MS, TERMINAL, IN_FLIGHT, n, 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, APPROVER_SPEC_MAX_USERS, ESCALATION_MAX_HOPS, TemplateBindingSchema, ApproverSpecSchema, FourEyesSchema, EscalationHopSchema, TerminalOutcomeSchema, ApprovalOnTimeoutSchema, BINDING_ROOTS, WORKFLOW_ENV_OVERLAY_MAX_KEYS, WORKFLOW_ENV_OVERLAY_MAX_VALUE_BYTES, WORKFLOW_ENV_TEMPLATE_SECRET_KEY_RE, isEnvRef, looksLikeEmbeddedJson, ZERO, isRecord2;
|
|
5198
5620
|
var init_dist2 = __esm({
|
|
5199
5621
|
"../workflow-graph/dist/index.mjs"() {
|
|
5200
5622
|
"use strict";
|
|
5201
5623
|
init_dist();
|
|
5624
|
+
init_dist();
|
|
5202
5625
|
__defProp3 = Object.defineProperty;
|
|
5203
5626
|
__name3 = /* @__PURE__ */ __name((target, value22) => __defProp3(target, "name", { value: value22, configurable: true }), "__name");
|
|
5627
|
+
WORKFLOW_SIDE_EFFECTS = [
|
|
5628
|
+
"none",
|
|
5629
|
+
"external"
|
|
5630
|
+
];
|
|
5631
|
+
WORKFLOW_JOB_RESOURCES = [
|
|
5632
|
+
"small",
|
|
5633
|
+
"medium",
|
|
5634
|
+
"large"
|
|
5635
|
+
];
|
|
5636
|
+
SideEffectsSchema = z6.enum(WORKFLOW_SIDE_EFFECTS);
|
|
5637
|
+
JobResourcesSchema = z6.enum(WORKFLOW_JOB_RESOURCES);
|
|
5204
5638
|
WORKFLOW_ARM_SUBRUN_ID = "$arm";
|
|
5639
|
+
SLEEP_UNTIL_REPLACEMENT = Object.freeze({
|
|
5640
|
+
type: "sleep",
|
|
5641
|
+
duration: 6e4
|
|
5642
|
+
});
|
|
5643
|
+
__name(sleepUntilUnsupportedMessage, "sleepUntilUnsupportedMessage");
|
|
5644
|
+
__name3(sleepUntilUnsupportedMessage, "sleepUntilUnsupportedMessage");
|
|
5205
5645
|
WORKFLOW_CAPS_DEFAULT = Object.freeze({
|
|
5206
5646
|
maxParallelArms: 16,
|
|
5207
5647
|
maxForeachConcurrency: 16,
|
|
@@ -5237,6 +5677,11 @@ var init_dist2 = __esm({
|
|
|
5237
5677
|
__name3(fillEntry, "fillEntry");
|
|
5238
5678
|
__name(withDefaultsFilled, "withDefaultsFilled");
|
|
5239
5679
|
__name3(withDefaultsFilled, "withDefaultsFilled");
|
|
5680
|
+
CONNECTION_ID_HEX_RE = /^[0-9a-f]{24}$/;
|
|
5681
|
+
__name(isConnectionKeyShaped, "isConnectionKeyShaped");
|
|
5682
|
+
__name3(isConnectionKeyShaped, "isConnectionKeyShaped");
|
|
5683
|
+
__name(connectionKeyUndeclaredMessage, "connectionKeyUndeclaredMessage");
|
|
5684
|
+
__name3(connectionKeyUndeclaredMessage, "connectionKeyUndeclaredMessage");
|
|
5240
5685
|
WORKFLOW_JOB_TOOLS = [
|
|
5241
5686
|
"shell",
|
|
5242
5687
|
"read",
|
|
@@ -5300,6 +5745,11 @@ var init_dist2 = __esm({
|
|
|
5300
5745
|
]);
|
|
5301
5746
|
__name(isPredicate, "isPredicate");
|
|
5302
5747
|
__name3(isPredicate, "isPredicate");
|
|
5748
|
+
isPredicateScalar = /* @__PURE__ */ __name3((v) => v === null || typeof v === "string" || typeof v === "number" || typeof v === "boolean", "isPredicateScalar");
|
|
5749
|
+
__name(isPathOrLiteral, "isPathOrLiteral");
|
|
5750
|
+
__name3(isPathOrLiteral, "isPathOrLiteral");
|
|
5751
|
+
__name(isWellFormedPredicate, "isWellFormedPredicate");
|
|
5752
|
+
__name3(isWellFormedPredicate, "isWellFormedPredicate");
|
|
5303
5753
|
GRAPH_HASH_PREFIX = "sha256-cj1:";
|
|
5304
5754
|
__name(canonicalJson, "canonicalJson");
|
|
5305
5755
|
__name3(canonicalJson, "canonicalJson");
|
|
@@ -5488,16 +5938,71 @@ var init_dist2 = __esm({
|
|
|
5488
5938
|
fromKnowledge = /* @__PURE__ */ __name3((k) => ({
|
|
5489
5939
|
knowledge: k
|
|
5490
5940
|
}), "fromKnowledge");
|
|
5941
|
+
CONTINUED_FAILURE_TAG = "continued_failure";
|
|
5942
|
+
CONTINUED_FAILURE_DEFAULT_CODE = "step_failed";
|
|
5943
|
+
CONTINUED_FAILURE_OUTPUT_SCHEMA = Object.freeze({
|
|
5944
|
+
type: "object",
|
|
5945
|
+
properties: {
|
|
5946
|
+
__lua_workflow: {
|
|
5947
|
+
type: "string",
|
|
5948
|
+
const: CONTINUED_FAILURE_TAG
|
|
5949
|
+
},
|
|
5950
|
+
failed: {
|
|
5951
|
+
type: "boolean",
|
|
5952
|
+
const: true
|
|
5953
|
+
},
|
|
5954
|
+
error: {
|
|
5955
|
+
type: "object",
|
|
5956
|
+
properties: {
|
|
5957
|
+
code: {
|
|
5958
|
+
type: "string"
|
|
5959
|
+
},
|
|
5960
|
+
message: {
|
|
5961
|
+
type: "string"
|
|
5962
|
+
}
|
|
5963
|
+
},
|
|
5964
|
+
required: [
|
|
5965
|
+
"code",
|
|
5966
|
+
"message"
|
|
5967
|
+
]
|
|
5968
|
+
},
|
|
5969
|
+
text: {
|
|
5970
|
+
type: "string",
|
|
5971
|
+
const: ""
|
|
5972
|
+
}
|
|
5973
|
+
},
|
|
5974
|
+
required: [
|
|
5975
|
+
"__lua_workflow",
|
|
5976
|
+
"failed",
|
|
5977
|
+
"error",
|
|
5978
|
+
"text"
|
|
5979
|
+
]
|
|
5980
|
+
});
|
|
5981
|
+
CONTINUED_FAILURE_LEAF_PATHS = Object.freeze([
|
|
5982
|
+
"failed",
|
|
5983
|
+
"error",
|
|
5984
|
+
"error.code",
|
|
5985
|
+
"error.message",
|
|
5986
|
+
"text"
|
|
5987
|
+
]);
|
|
5988
|
+
__name(continuedFailureValue, "continuedFailureValue");
|
|
5989
|
+
__name3(continuedFailureValue, "continuedFailureValue");
|
|
5990
|
+
__name(isContinuedFailureValue, "isContinuedFailureValue");
|
|
5991
|
+
__name3(isContinuedFailureValue, "isContinuedFailureValue");
|
|
5491
5992
|
__name(lowerContainerArm, "lowerContainerArm");
|
|
5492
5993
|
__name3(lowerContainerArm, "lowerContainerArm");
|
|
5493
|
-
nodeIdOf = /* @__PURE__ */ __name3((
|
|
5994
|
+
nodeIdOf = /* @__PURE__ */ __name3((n2) => n2.type === "step" ? n2.step.id : n2.id, "nodeIdOf");
|
|
5494
5995
|
__name(entryIds, "entryIds");
|
|
5495
5996
|
__name3(entryIds, "entryIds");
|
|
5496
5997
|
__name(resolvePlacements, "resolvePlacements");
|
|
5497
5998
|
__name3(resolvePlacements, "resolvePlacements");
|
|
5498
5999
|
__name(seedLedgerFromRun, "seedLedgerFromRun");
|
|
5499
6000
|
__name3(seedLedgerFromRun, "seedLedgerFromRun");
|
|
5500
|
-
|
|
6001
|
+
branchArmId = /* @__PURE__ */ __name3((arm) => arm.type === "step" ? arm.step.id : arm.id, "branchArmId");
|
|
6002
|
+
__name(branchSpecFromConditional, "branchSpecFromConditional");
|
|
6003
|
+
__name3(branchSpecFromConditional, "branchSpecFromConditional");
|
|
6004
|
+
__name(selectBranchArms, "selectBranchArms");
|
|
6005
|
+
__name3(selectBranchArms, "selectBranchArms");
|
|
5501
6006
|
canonical = /* @__PURE__ */ __name3((v) => JSON.stringify(sortKeys(v)), "canonical");
|
|
5502
6007
|
sortKeys = /* @__PURE__ */ __name3((v) => {
|
|
5503
6008
|
if (Array.isArray(v)) return v.map(sortKeys);
|
|
@@ -5511,6 +6016,12 @@ var init_dist2 = __esm({
|
|
|
5511
6016
|
}, "sortKeys");
|
|
5512
6017
|
__name(replayLedger, "replayLedger");
|
|
5513
6018
|
__name3(replayLedger, "replayLedger");
|
|
6019
|
+
JOIN = ".join";
|
|
6020
|
+
entryOfJoin = /* @__PURE__ */ __name3((id) => id.endsWith(JOIN) ? id.slice(0, -JOIN.length) : void 0, "entryOfJoin");
|
|
6021
|
+
__name(replayResultOf, "replayResultOf");
|
|
6022
|
+
__name3(replayResultOf, "replayResultOf");
|
|
6023
|
+
__name(ancestorResults, "ancestorResults");
|
|
6024
|
+
__name3(ancestorResults, "ancestorResults");
|
|
5514
6025
|
__name(inferTaken, "inferTaken");
|
|
5515
6026
|
__name3(inferTaken, "inferTaken");
|
|
5516
6027
|
__name(countChildren, "countChildren");
|
|
@@ -5523,6 +6034,14 @@ var init_dist2 = __esm({
|
|
|
5523
6034
|
__name3(pruneUndefined, "pruneUndefined");
|
|
5524
6035
|
__name(runNextAction, "runNextAction");
|
|
5525
6036
|
__name3(runNextAction, "runNextAction");
|
|
6037
|
+
IN_FLIGHT = new Set(WORKFLOW_STEP_IN_FLIGHT);
|
|
6038
|
+
__name(emptyRunCounts, "emptyRunCounts");
|
|
6039
|
+
__name3(emptyRunCounts, "emptyRunCounts");
|
|
6040
|
+
__name(runCountsFromStatusTally, "runCountsFromStatusTally");
|
|
6041
|
+
__name3(runCountsFromStatusTally, "runCountsFromStatusTally");
|
|
6042
|
+
__name(runCountsFromStepStatuses, "runCountsFromStepStatuses");
|
|
6043
|
+
__name3(runCountsFromStepStatuses, "runCountsFromStepStatuses");
|
|
6044
|
+
n = /* @__PURE__ */ __name3((v) => typeof v === "number" && Number.isFinite(v) ? v : 0, "n");
|
|
5526
6045
|
__name(runCounts, "runCounts");
|
|
5527
6046
|
__name3(runCounts, "runCounts");
|
|
5528
6047
|
__name(runUsage, "runUsage");
|
|
@@ -5626,54 +6145,54 @@ var init_dist2 = __esm({
|
|
|
5626
6145
|
__name3(rebaseItemPointer, "rebaseItemPointer");
|
|
5627
6146
|
APPROVER_SPEC_MAX_USERS = 20;
|
|
5628
6147
|
ESCALATION_MAX_HOPS = 3;
|
|
5629
|
-
TemplateBindingSchema =
|
|
5630
|
-
template:
|
|
6148
|
+
TemplateBindingSchema = z22.object({
|
|
6149
|
+
template: z22.string().min(1).max(2048)
|
|
5631
6150
|
}).strict();
|
|
5632
|
-
ApproverSpecSchema =
|
|
5633
|
-
|
|
5634
|
-
|
|
5635
|
-
|
|
5636
|
-
users:
|
|
5637
|
-
|
|
6151
|
+
ApproverSpecSchema = z22.union([
|
|
6152
|
+
z22.literal("creator"),
|
|
6153
|
+
z22.literal("org-admins"),
|
|
6154
|
+
z22.object({
|
|
6155
|
+
users: z22.union([
|
|
6156
|
+
z22.array(z22.string().min(1).max(128)).min(1).max(APPROVER_SPEC_MAX_USERS),
|
|
5638
6157
|
TemplateBindingSchema
|
|
5639
6158
|
])
|
|
5640
6159
|
}).strict(),
|
|
5641
|
-
|
|
5642
|
-
role:
|
|
5643
|
-
|
|
6160
|
+
z22.object({
|
|
6161
|
+
role: z22.union([
|
|
6162
|
+
z22.string().min(1).max(128),
|
|
5644
6163
|
TemplateBindingSchema
|
|
5645
6164
|
])
|
|
5646
6165
|
}).strict(),
|
|
5647
|
-
|
|
5648
|
-
group:
|
|
5649
|
-
|
|
6166
|
+
z22.object({
|
|
6167
|
+
group: z22.union([
|
|
6168
|
+
z22.string().min(1).max(128),
|
|
5650
6169
|
TemplateBindingSchema
|
|
5651
6170
|
])
|
|
5652
6171
|
}).strict(),
|
|
5653
|
-
|
|
5654
|
-
governance:
|
|
5655
|
-
policyId:
|
|
6172
|
+
z22.object({
|
|
6173
|
+
governance: z22.object({
|
|
6174
|
+
policyId: z22.string().min(1).max(128)
|
|
5656
6175
|
}).strict()
|
|
5657
6176
|
}).strict()
|
|
5658
6177
|
]);
|
|
5659
|
-
FourEyesSchema =
|
|
6178
|
+
FourEyesSchema = z22.object({
|
|
5660
6179
|
edit: ApproverSpecSchema,
|
|
5661
6180
|
approve: ApproverSpecSchema
|
|
5662
6181
|
}).strict();
|
|
5663
|
-
EscalationHopSchema =
|
|
6182
|
+
EscalationHopSchema = z22.object({
|
|
5664
6183
|
escalateTo: ApproverSpecSchema,
|
|
5665
|
-
timeoutHours:
|
|
6184
|
+
timeoutHours: z22.number().finite().min(1).max(720)
|
|
5666
6185
|
}).strict();
|
|
5667
|
-
TerminalOutcomeSchema =
|
|
6186
|
+
TerminalOutcomeSchema = z22.enum([
|
|
5668
6187
|
"deny",
|
|
5669
6188
|
"cancel-run",
|
|
5670
6189
|
"fail",
|
|
5671
6190
|
"continue"
|
|
5672
6191
|
]);
|
|
5673
|
-
ApprovalOnTimeoutSchema =
|
|
6192
|
+
ApprovalOnTimeoutSchema = z22.union([
|
|
5674
6193
|
TerminalOutcomeSchema,
|
|
5675
6194
|
EscalationHopSchema,
|
|
5676
|
-
|
|
6195
|
+
z22.array(z22.union([
|
|
5677
6196
|
TerminalOutcomeSchema,
|
|
5678
6197
|
EscalationHopSchema
|
|
5679
6198
|
])).min(1).max(ESCALATION_MAX_HOPS + 1)
|
|
@@ -5726,6 +6245,15 @@ var init_dist2 = __esm({
|
|
|
5726
6245
|
__name3(ofEntry, "ofEntry");
|
|
5727
6246
|
__name(estimateGraph, "estimateGraph");
|
|
5728
6247
|
__name3(estimateGraph, "estimateGraph");
|
|
6248
|
+
isRecord2 = /* @__PURE__ */ __name3((v) => !!v && typeof v === "object" && !Array.isArray(v), "isRecord");
|
|
6249
|
+
__name(singleStepsOf, "singleStepsOf");
|
|
6250
|
+
__name3(singleStepsOf, "singleStepsOf");
|
|
6251
|
+
__name(entriesOf, "entriesOf");
|
|
6252
|
+
__name3(entriesOf, "entriesOf");
|
|
6253
|
+
__name(inheritTargets, "inheritTargets");
|
|
6254
|
+
__name3(inheritTargets, "inheritTargets");
|
|
6255
|
+
__name(needsInheritedWorkspace, "needsInheritedWorkspace");
|
|
6256
|
+
__name3(needsInheritedWorkspace, "needsInheritedWorkspace");
|
|
5729
6257
|
}
|
|
5730
6258
|
});
|
|
5731
6259
|
|
|
@@ -5784,16 +6312,16 @@ function stepNodeOf(s) {
|
|
|
5784
6312
|
});
|
|
5785
6313
|
}
|
|
5786
6314
|
function materializeEntry(entry, steps) {
|
|
5787
|
-
const single = /* @__PURE__ */ __name((
|
|
5788
|
-
if (
|
|
5789
|
-
if (
|
|
5790
|
-
...
|
|
6315
|
+
const single = /* @__PURE__ */ __name((n2) => {
|
|
6316
|
+
if (n2.type === "step" && steps[n2.step.id]) return stepNodeOf(steps[n2.step.id]);
|
|
6317
|
+
if (n2.type === "workflow" && n2.workflowId === WORKFLOW_ARM_SUBRUN_ID && n2.graph) return {
|
|
6318
|
+
...n2,
|
|
5791
6319
|
graph: [
|
|
5792
|
-
|
|
5793
|
-
single(
|
|
6320
|
+
n2.graph[0],
|
|
6321
|
+
single(n2.graph[1])
|
|
5794
6322
|
]
|
|
5795
6323
|
};
|
|
5796
|
-
return
|
|
6324
|
+
return n2;
|
|
5797
6325
|
}, "single");
|
|
5798
6326
|
switch (entry.type) {
|
|
5799
6327
|
case "step":
|
|
@@ -5838,8 +6366,8 @@ function createWorkflow(cfg) {
|
|
|
5838
6366
|
if (v.roles.length > 20 || (v.users?.length ?? 0) > 50) throw new LuaWorkflowBuildError("cap-exceeded", "outputVisibility allows \u2264 20 roles and \u2264 50 users");
|
|
5839
6367
|
}
|
|
5840
6368
|
if (cfg.backfillOnEnable?.maxOccurrences !== void 0) {
|
|
5841
|
-
const
|
|
5842
|
-
if (!Number.isInteger(
|
|
6369
|
+
const n2 = cfg.backfillOnEnable.maxOccurrences;
|
|
6370
|
+
if (!Number.isInteger(n2) || n2 < 1 || n2 > 200) throw new LuaWorkflowBuildError("invalid-envelope", "backfillOnEnable.maxOccurrences must be an integer in 1..200 (backfill-max-occurrences-out-of-range; the org maxBatchItems twin is checked at publish/R56)");
|
|
5843
6371
|
}
|
|
5844
6372
|
const keys = /* @__PURE__ */ new Set();
|
|
5845
6373
|
envRefKeys(cfg.schedule, keys);
|
|
@@ -6033,7 +6561,7 @@ var init_workflow = __esm({
|
|
|
6033
6561
|
getEnvTemplateKeys() {
|
|
6034
6562
|
return this.built.envTemplateKeys;
|
|
6035
6563
|
}
|
|
6036
|
-
/** `.workflow(id, ref)` targets by name — `ManifestWorkflow.workflowRefs
|
|
6564
|
+
/** `.workflow(id, ref)` targets by name — `ManifestWorkflow.workflowRefs`; `workspace:'inherit'` marks the inherit children the compiler defers `workspace-not-declared` for. */
|
|
6037
6565
|
getNestedWorkflowRefs() {
|
|
6038
6566
|
return this.built.nestedRefs;
|
|
6039
6567
|
}
|
|
@@ -6063,6 +6591,7 @@ var init_workflow = __esm({
|
|
|
6063
6591
|
};
|
|
6064
6592
|
if (cfg.concurrencyPolicy !== void 0) envelope.concurrencyPolicy = cfg.concurrencyPolicy;
|
|
6065
6593
|
if (cfg.workspace !== void 0) envelope.workspace = cfg.workspace;
|
|
6594
|
+
if (cfg.connections !== void 0) envelope.connections = cfg.connections;
|
|
6066
6595
|
return withDefaultsFilled(envelope);
|
|
6067
6596
|
}
|
|
6068
6597
|
};
|
|
@@ -6098,7 +6627,6 @@ var init_workflow = __esm({
|
|
|
6098
6627
|
if (this.steps[s.id] && this.steps[s.id] !== s) throw new LuaWorkflowBuildError("duplicate-step-id", `step id "${s.id}" is declared twice`);
|
|
6099
6628
|
const tier = s.tier ?? (s.workspace ? "job" : void 0);
|
|
6100
6629
|
if (s.workspace && s.tier !== void 0 && s.tier !== "job") throw new LuaWorkflowBuildError("workspace-requires-job-tier", `"${s.id}": a step mounting a workspace must be tier:'job'`);
|
|
6101
|
-
if (s.workspace && !this.config.workspace) throw new LuaWorkflowBuildError("workspace-not-declared", `"${s.id}" mounts a workspace but createWorkflow declares none`);
|
|
6102
6630
|
if (s.jobTools && tier !== "job") throw new LuaWorkflowBuildError("cap-exceeded", `"${s.id}": jobTools require tier:'job' (job-tools-require-job-tier)`);
|
|
6103
6631
|
assertTimeout({
|
|
6104
6632
|
id: s.id,
|
|
@@ -6339,13 +6867,20 @@ var init_workflow = __esm({
|
|
|
6339
6867
|
}
|
|
6340
6868
|
const tier = opts.tier ?? (opts.workspace ? "job" : void 0);
|
|
6341
6869
|
if (opts.workspace && opts.tier !== void 0 && opts.tier !== "job") throw new LuaWorkflowBuildError("workspace-requires-job-tier", `"${id}": a step mounting a workspace must be tier:'job'`);
|
|
6342
|
-
if (opts.workspace && !this.config.workspace) throw new LuaWorkflowBuildError("workspace-not-declared", `"${id}" mounts a workspace but createWorkflow declares none`);
|
|
6343
6870
|
if (opts.harness !== void 0 && tier !== "job") throw new LuaWorkflowBuildError("harness-requires-job-tier", `"${id}": harness is only legal on a tier:'job' agent step`);
|
|
6344
6871
|
if (opts.toolScope?.jobTools && tier !== "job") throw new LuaWorkflowBuildError("cap-exceeded", `"${id}": toolScope.jobTools require tier:'job' (job-tools-require-job-tier)`);
|
|
6345
6872
|
if (opts.maxTurns !== void 0) {
|
|
6346
6873
|
if (tier !== "job") throw new LuaWorkflowBuildError("max-turns-requires-job-tier", `"${id}": maxTurns is only legal on a tier:'job' agent step`);
|
|
6347
6874
|
if (!Number.isInteger(opts.maxTurns) || opts.maxTurns < 1 || opts.maxTurns > 500) throw new LuaWorkflowBuildError("max-turns-invalid", `"${id}": maxTurns must be an integer 1..500`);
|
|
6348
6875
|
}
|
|
6876
|
+
if (opts.maxMessages !== void 0) {
|
|
6877
|
+
if (tier !== "job") throw new LuaWorkflowBuildError("max-turns-requires-job-tier", `"${id}": maxMessages is only legal on a tier:'job' agent step`);
|
|
6878
|
+
if (!Number.isInteger(opts.maxMessages) || opts.maxMessages < 1 || opts.maxMessages > 5e3) throw new LuaWorkflowBuildError("max-turns-invalid", `"${id}": maxMessages must be an integer 1..5000`);
|
|
6879
|
+
}
|
|
6880
|
+
if (opts.maxInputTokens !== void 0) {
|
|
6881
|
+
if (tier !== "job") throw new LuaWorkflowBuildError("max-turns-requires-job-tier", `"${id}": maxInputTokens is only legal on a tier:'job' agent step`);
|
|
6882
|
+
if (!Number.isInteger(opts.maxInputTokens) || opts.maxInputTokens < 1e6 || opts.maxInputTokens > 5e8) throw new LuaWorkflowBuildError("max-turns-invalid", `"${id}": maxInputTokens must be an integer 1000000..500000000`);
|
|
6883
|
+
}
|
|
6349
6884
|
assertTimeout({
|
|
6350
6885
|
id,
|
|
6351
6886
|
timeoutSeconds: opts.timeoutSeconds,
|
|
@@ -6372,7 +6907,9 @@ var init_workflow = __esm({
|
|
|
6372
6907
|
workspace: opts.workspace,
|
|
6373
6908
|
jobResources: opts.jobResources,
|
|
6374
6909
|
harness: opts.harness,
|
|
6375
|
-
maxTurns: opts.maxTurns
|
|
6910
|
+
maxTurns: opts.maxTurns,
|
|
6911
|
+
maxMessages: opts.maxMessages,
|
|
6912
|
+
maxInputTokens: opts.maxInputTokens
|
|
6376
6913
|
});
|
|
6377
6914
|
return this.push({
|
|
6378
6915
|
kind: "declare",
|
|
@@ -6527,7 +7064,11 @@ var init_workflow = __esm({
|
|
|
6527
7064
|
}
|
|
6528
7065
|
assertNoClosure(input, `workflow("${id}").input`);
|
|
6529
7066
|
this.recordEnvRefs(input);
|
|
6530
|
-
this.nestedRefs.push({
|
|
7067
|
+
this.nestedRefs.push(opts?.workspace === "inherit" ? {
|
|
7068
|
+
id,
|
|
7069
|
+
name,
|
|
7070
|
+
workspace: "inherit"
|
|
7071
|
+
} : {
|
|
6531
7072
|
id,
|
|
6532
7073
|
name
|
|
6533
7074
|
});
|
|
@@ -6539,8 +7080,8 @@ var init_workflow = __esm({
|
|
|
6539
7080
|
workspace: opts?.workspace
|
|
6540
7081
|
});
|
|
6541
7082
|
return this.push({
|
|
6542
|
-
kind: "
|
|
6543
|
-
|
|
7083
|
+
kind: "declare",
|
|
7084
|
+
node
|
|
6544
7085
|
});
|
|
6545
7086
|
}
|
|
6546
7087
|
commit() {
|
|
@@ -6550,7 +7091,7 @@ var init_workflow = __esm({
|
|
|
6550
7091
|
const { graph, issues } = resolvePlacements(this.calls);
|
|
6551
7092
|
const fatal = issues[0];
|
|
6552
7093
|
if (fatal) {
|
|
6553
|
-
const hint = fatal.code === "unknown-step-ref" ? "a string StepRef must name an entry declared by agentStep/specialistStep/toolStep/map(\u2026, { id }) somewhere in the chain \u2014 before OR after the reference" : void 0;
|
|
7094
|
+
const hint = fatal.code === "unknown-step-ref" ? "a string StepRef must name an entry declared by agentStep/specialistStep/toolStep/map(\u2026, { id })/workflow(\u2026) somewhere in the chain \u2014 before OR after the reference" : void 0;
|
|
6554
7095
|
throw new LuaWorkflowBuildError(fatal.code, fatal.message, hint);
|
|
6555
7096
|
}
|
|
6556
7097
|
if (graph.length === 0) throw new LuaWorkflowBuildError("empty-graph", `workflow "${this.config.name}" has no entries`);
|
|
@@ -6563,7 +7104,8 @@ var init_workflow = __esm({
|
|
|
6563
7104
|
if (graphHasHitl(graph, this.steps) && this.config.budget?.maxDurationSeconds === void 0) {
|
|
6564
7105
|
this.warnings.push({
|
|
6565
7106
|
code: "hitl-duration-defaulted",
|
|
6566
|
-
|
|
7107
|
+
// LUA-668: names the workflow — two HITL workflows in one project printed two identical lines that read as a duplicate.
|
|
7108
|
+
message: `workflow "${this.config.name}": budget.maxDurationSeconds defaulted to ${WORKFLOW_HITL_MAX_DURATION_SECONDS} s (30 d) because the graph contains an approval / waitForSignal / suspend-capable step \u2014 set it explicitly to silence`
|
|
6567
7109
|
});
|
|
6568
7110
|
}
|
|
6569
7111
|
this.checkScheduleInput();
|
|
@@ -12276,7 +12818,7 @@ function findFileLevelImport(node, state3) {
|
|
|
12276
12818
|
for (const importDecl of sourceFile.getImportDeclarations()) {
|
|
12277
12819
|
const defaultImport = importDecl.getDefaultImport();
|
|
12278
12820
|
const matchesDefault = defaultImport?.getText() === name;
|
|
12279
|
-
const matchesNamed = importDecl.getNamedImports().some((
|
|
12821
|
+
const matchesNamed = importDecl.getNamedImports().some((n2) => (n2.getAliasNode()?.getText() ?? n2.getName()) === name);
|
|
12280
12822
|
if (!matchesDefault && !matchesNamed) continue;
|
|
12281
12823
|
const target = loadImportTarget(importDecl, state3, sourceFile.getFilePath());
|
|
12282
12824
|
if (!target) return void 0;
|
|
@@ -13783,13 +14325,13 @@ function rewritePrimitiveSource(metadata, opts) {
|
|
|
13783
14325
|
}
|
|
13784
14326
|
});
|
|
13785
14327
|
const sf = localProject.createSourceFile(`__rewrite_${metadata.kind}_${metadata.name}.ts`, sourceCode);
|
|
13786
|
-
const isPrimitiveCall = /* @__PURE__ */ __name((
|
|
13787
|
-
if (Node15.isNewExpression(
|
|
13788
|
-
const callee =
|
|
14328
|
+
const isPrimitiveCall = /* @__PURE__ */ __name((n2) => {
|
|
14329
|
+
if (Node15.isNewExpression(n2)) {
|
|
14330
|
+
const callee = n2.getExpression();
|
|
13789
14331
|
return Node15.isIdentifier(callee) && opts.constructorNames.includes(callee.getText());
|
|
13790
14332
|
}
|
|
13791
|
-
if (Node15.isCallExpression(
|
|
13792
|
-
const callee =
|
|
14333
|
+
if (Node15.isCallExpression(n2)) {
|
|
14334
|
+
const callee = n2.getExpression();
|
|
13793
14335
|
return Node15.isIdentifier(callee) && opts.defineFunctionName !== void 0 && callee.getText() === opts.defineFunctionName;
|
|
13794
14336
|
}
|
|
13795
14337
|
return false;
|
|
@@ -13807,9 +14349,9 @@ function rewritePrimitiveSource(metadata, opts) {
|
|
|
13807
14349
|
compilerVersion: COMPILER_VERSION
|
|
13808
14350
|
});
|
|
13809
14351
|
callNode.replaceWithText(synthesized);
|
|
13810
|
-
sf.forEachDescendant((
|
|
13811
|
-
if (
|
|
13812
|
-
if (isPrimitiveCall(
|
|
14352
|
+
sf.forEachDescendant((n2) => {
|
|
14353
|
+
if (n2 === callNode) return;
|
|
14354
|
+
if (isPrimitiveCall(n2)) n2.replaceWithText("undefined");
|
|
13813
14355
|
});
|
|
13814
14356
|
rewriteCrossFileCallsInSourceFile(sf, opts.crossFileSpecs, opts.sdkBaseClassNames);
|
|
13815
14357
|
stripLuaCliImports(sf);
|
|
@@ -13879,14 +14421,14 @@ function stripSdkExtendsClauses(sf, sdkBaseClassNames, aliasMap, specs) {
|
|
|
13879
14421
|
const canonical2 = matchSdkClass(expr.getText());
|
|
13880
14422
|
if (canonical2) strip(classDecl, canonical2);
|
|
13881
14423
|
}
|
|
13882
|
-
sf.forEachDescendant((
|
|
13883
|
-
if (!Node15.isClassExpression(
|
|
13884
|
-
const ext =
|
|
14424
|
+
sf.forEachDescendant((n2) => {
|
|
14425
|
+
if (!Node15.isClassExpression(n2)) return;
|
|
14426
|
+
const ext = n2.getExtends();
|
|
13885
14427
|
if (!ext) return;
|
|
13886
14428
|
const expr = ext.getExpression();
|
|
13887
14429
|
if (!Node15.isIdentifier(expr)) return;
|
|
13888
14430
|
const canonical2 = matchSdkClass(expr.getText());
|
|
13889
|
-
if (canonical2) strip(
|
|
14431
|
+
if (canonical2) strip(n2, canonical2);
|
|
13890
14432
|
});
|
|
13891
14433
|
}
|
|
13892
14434
|
function stripDroppedClassMembers(classNode, dropNames) {
|
|
@@ -13894,9 +14436,9 @@ function stripDroppedClassMembers(classNode, dropNames) {
|
|
|
13894
14436
|
if (dropNames.has(prop.getName())) prop.remove();
|
|
13895
14437
|
}
|
|
13896
14438
|
const statements = [];
|
|
13897
|
-
classNode.forEachDescendant((
|
|
13898
|
-
if (!Node15.isExpressionStatement(
|
|
13899
|
-
if (isThisRootedCallTo(
|
|
14439
|
+
classNode.forEachDescendant((n2) => {
|
|
14440
|
+
if (!Node15.isExpressionStatement(n2)) return;
|
|
14441
|
+
if (isThisRootedCallTo(n2.getExpression(), dropNames)) statements.push(n2);
|
|
13900
14442
|
});
|
|
13901
14443
|
for (const stmt of statements) stmt.remove();
|
|
13902
14444
|
}
|
|
@@ -13929,13 +14471,13 @@ function stripSuperCallsInConstructors(classNode) {
|
|
|
13929
14471
|
}
|
|
13930
14472
|
function warnRemainingSuperReferences(classNode) {
|
|
13931
14473
|
const sf = classNode.getSourceFile();
|
|
13932
|
-
classNode.forEachDescendant((
|
|
13933
|
-
if (
|
|
13934
|
-
const parent =
|
|
13935
|
-
if (parent && Node15.isCallExpression(parent) && parent.getExpression() ===
|
|
14474
|
+
classNode.forEachDescendant((n2) => {
|
|
14475
|
+
if (n2.getKind() !== ts3.SyntaxKind.SuperKeyword) return;
|
|
14476
|
+
const parent = n2.getParent();
|
|
14477
|
+
if (parent && Node15.isCallExpression(parent) && parent.getExpression() === n2 && Node15.isExpressionStatement(parent.getParent())) {
|
|
13936
14478
|
return;
|
|
13937
14479
|
}
|
|
13938
|
-
const pos = sf.getLineAndColumnAtPos(
|
|
14480
|
+
const pos = sf.getLineAndColumnAtPos(n2.getStart());
|
|
13939
14481
|
console.warn(formatSarifWarning({
|
|
13940
14482
|
ruleId: "lua/orphan-super-reference",
|
|
13941
14483
|
filePath: sf.getFilePath(),
|
|
@@ -13979,24 +14521,24 @@ function buildSdkAliasMap(sf, sdkIdentifiers) {
|
|
|
13979
14521
|
}
|
|
13980
14522
|
function findFirstCrossFileSdkCall(sf, specs, aliasMap) {
|
|
13981
14523
|
let found;
|
|
13982
|
-
sf.forEachDescendant((
|
|
14524
|
+
sf.forEachDescendant((n2) => {
|
|
13983
14525
|
if (found) return;
|
|
13984
|
-
if (Node15.isNewExpression(
|
|
13985
|
-
const callee =
|
|
14526
|
+
if (Node15.isNewExpression(n2)) {
|
|
14527
|
+
const callee = n2.getExpression();
|
|
13986
14528
|
if (!Node15.isIdentifier(callee)) return;
|
|
13987
14529
|
const canonical2 = aliasMap.get(callee.getText()) ?? callee.getText();
|
|
13988
14530
|
const spec = specs.find((s) => s.classNames.includes(canonical2));
|
|
13989
14531
|
if (spec) found = {
|
|
13990
|
-
node:
|
|
14532
|
+
node: n2,
|
|
13991
14533
|
spec
|
|
13992
14534
|
};
|
|
13993
|
-
} else if (Node15.isCallExpression(
|
|
13994
|
-
const callee =
|
|
14535
|
+
} else if (Node15.isCallExpression(n2)) {
|
|
14536
|
+
const callee = n2.getExpression();
|
|
13995
14537
|
if (!Node15.isIdentifier(callee)) return;
|
|
13996
14538
|
const canonical2 = aliasMap.get(callee.getText()) ?? callee.getText();
|
|
13997
14539
|
const spec = specs.find((s) => s.defineFunction !== void 0 && s.defineFunction === canonical2);
|
|
13998
14540
|
if (spec) found = {
|
|
13999
|
-
node:
|
|
14541
|
+
node: n2,
|
|
14000
14542
|
spec
|
|
14001
14543
|
};
|
|
14002
14544
|
}
|
|
@@ -15020,14 +15562,14 @@ function buildSandboxRequire(opts) {
|
|
|
15020
15562
|
function v4ToInt(ip) {
|
|
15021
15563
|
const parts = ip.split(".");
|
|
15022
15564
|
if (parts.length !== 4) return null;
|
|
15023
|
-
let
|
|
15565
|
+
let n2 = 0;
|
|
15024
15566
|
for (const p of parts) {
|
|
15025
15567
|
if (!/^\d{1,3}$/.test(p)) return null;
|
|
15026
15568
|
const v = Number(p);
|
|
15027
15569
|
if (v > 255) return null;
|
|
15028
|
-
|
|
15570
|
+
n2 = n2 * 256 + v;
|
|
15029
15571
|
}
|
|
15030
|
-
return
|
|
15572
|
+
return n2;
|
|
15031
15573
|
}
|
|
15032
15574
|
function range(cidr, klass) {
|
|
15033
15575
|
const [ip, prefix] = cidr.split("/");
|
|
@@ -15037,10 +15579,10 @@ function range(cidr, klass) {
|
|
|
15037
15579
|
klass
|
|
15038
15580
|
};
|
|
15039
15581
|
}
|
|
15040
|
-
function inRange(
|
|
15582
|
+
function inRange(n2, r) {
|
|
15041
15583
|
if (r.prefix === 0) return true;
|
|
15042
15584
|
const shift = 32 - r.prefix;
|
|
15043
|
-
return Math.floor(
|
|
15585
|
+
return Math.floor(n2 / 2 ** shift) === Math.floor(r.base / 2 ** shift);
|
|
15044
15586
|
}
|
|
15045
15587
|
function mappedV4(address) {
|
|
15046
15588
|
const m = /^::ffff:(\d{1,3}(?:\.\d{1,3}){3})$/i.exec(address.trim());
|
|
@@ -15049,9 +15591,9 @@ function mappedV4(address) {
|
|
|
15049
15591
|
function classifyPrivateAddress(address) {
|
|
15050
15592
|
const v4 = net.isIPv4(address) ? address : mappedV4(address);
|
|
15051
15593
|
if (!v4) return null;
|
|
15052
|
-
const
|
|
15053
|
-
if (
|
|
15054
|
-
for (const r of PRIVATE_RANGES) if (inRange(
|
|
15594
|
+
const n2 = v4ToInt(v4);
|
|
15595
|
+
if (n2 === null) return null;
|
|
15596
|
+
for (const r of PRIVATE_RANGES) if (inRange(n2, r)) return r.klass;
|
|
15055
15597
|
return null;
|
|
15056
15598
|
}
|
|
15057
15599
|
function egressDeniedMessage(host) {
|
|
@@ -15072,12 +15614,12 @@ function isEgressDeniedError(err) {
|
|
|
15072
15614
|
}
|
|
15073
15615
|
function resolveEgressProbeMs(env = process.env) {
|
|
15074
15616
|
const raw = env.LUA_SANDBOX_EGRESS_PROBE_MS;
|
|
15075
|
-
const
|
|
15076
|
-
return Number.isInteger(
|
|
15617
|
+
const n2 = raw !== void 0 && raw !== "" ? Number.parseInt(raw, 10) : NaN;
|
|
15618
|
+
return Number.isInteger(n2) && n2 > 0 ? n2 : EGRESS_PROBE_DEFAULT_MS;
|
|
15077
15619
|
}
|
|
15078
15620
|
function ipv4ToInt(ip) {
|
|
15079
15621
|
const parts = ip.split(".").map(Number);
|
|
15080
|
-
if (parts.length !== 4 || parts.some((
|
|
15622
|
+
if (parts.length !== 4 || parts.some((n2) => Number.isNaN(n2) || n2 < 0 || n2 > 255)) {
|
|
15081
15623
|
throw new Error(`Invalid IPv4: ${ip}`);
|
|
15082
15624
|
}
|
|
15083
15625
|
return (parts[0] << 24 >>> 0) + (parts[1] << 16) + (parts[2] << 8) + parts[3];
|
|
@@ -16742,6 +17284,7 @@ function serializeViaVm(bundleCode, opts = {}) {
|
|
|
16742
17284
|
...templateKeys
|
|
16743
17285
|
].sort(),
|
|
16744
17286
|
workflowRefs: (wf?.getNestedWorkflowRefs() ?? []).map((r) => r.name),
|
|
17287
|
+
inheritRefs: inheritRefsOf(wf),
|
|
16745
17288
|
buildWarnings: wf?.getBuildWarnings() ?? []
|
|
16746
17289
|
}
|
|
16747
17290
|
};
|
|
@@ -16825,6 +17368,31 @@ function stepRefId(arg) {
|
|
|
16825
17368
|
}
|
|
16826
17369
|
return void 0;
|
|
16827
17370
|
}
|
|
17371
|
+
function workflowRefName(arg) {
|
|
17372
|
+
if (!arg) return void 0;
|
|
17373
|
+
if (Node17.isStringLiteral(arg) || Node17.isNoSubstitutionTemplateLiteral(arg)) return arg.getLiteralText();
|
|
17374
|
+
if (!Node17.isIdentifier(arg)) return void 0;
|
|
17375
|
+
const decl = resolveIdentifier(arg);
|
|
17376
|
+
const init3 = decl && Node17.isVariableDeclaration(decl) ? decl.getInitializer() : decl;
|
|
17377
|
+
if (!init3 || !Node17.isExpression(init3)) return void 0;
|
|
17378
|
+
const root = chainCalls(init3)[0];
|
|
17379
|
+
const cfg = root && [
|
|
17380
|
+
"createWorkflow",
|
|
17381
|
+
"defineWorkflow"
|
|
17382
|
+
].includes(calleeName(root)) ? root.getArguments()[0] : void 0;
|
|
17383
|
+
return cfg && Node17.isObjectLiteralExpression(cfg) ? extractStringProperty(cfg, "name") : void 0;
|
|
17384
|
+
}
|
|
17385
|
+
function sketchInheritRefs(calls) {
|
|
17386
|
+
const out = [];
|
|
17387
|
+
for (const call of calls) {
|
|
17388
|
+
if (calleeName(call) !== "workflow") continue;
|
|
17389
|
+
const [, ref, , opts] = call.getArguments();
|
|
17390
|
+
if (!opts || !Node17.isObjectLiteralExpression(opts) || extractStringProperty(opts, "workspace") !== "inherit") continue;
|
|
17391
|
+
const name = workflowRefName(ref);
|
|
17392
|
+
if (name && !out.includes(name)) out.push(name);
|
|
17393
|
+
}
|
|
17394
|
+
return out;
|
|
17395
|
+
}
|
|
16828
17396
|
function callDeclaredIds(call, mapCounter) {
|
|
16829
17397
|
const name = calleeName(call);
|
|
16830
17398
|
const args2 = call.getArguments();
|
|
@@ -16976,6 +17544,7 @@ function serializeViaAst(sourceFile, exportName) {
|
|
|
16976
17544
|
envKeys: [],
|
|
16977
17545
|
envTemplateKeys: inst?.getEnvTemplateKeys() ?? [],
|
|
16978
17546
|
workflowRefs: (inst?.getNestedWorkflowRefs() ?? []).map((r) => r.name),
|
|
17547
|
+
inheritRefs: inheritRefsOf(inst),
|
|
16979
17548
|
buildWarnings: inst?.getBuildWarnings() ?? []
|
|
16980
17549
|
};
|
|
16981
17550
|
} catch {
|
|
@@ -17021,6 +17590,7 @@ function sketchTopology(sourceFile, exportName, name, description) {
|
|
|
17021
17590
|
envKeys: [],
|
|
17022
17591
|
envTemplateKeys: [],
|
|
17023
17592
|
workflowRefs: [],
|
|
17593
|
+
inheritRefs: sketchInheritRefs(calls),
|
|
17024
17594
|
buildWarnings: [],
|
|
17025
17595
|
partialNodes: [
|
|
17026
17596
|
...seen
|
|
@@ -17028,47 +17598,49 @@ function sketchTopology(sourceFile, exportName, name, description) {
|
|
|
17028
17598
|
};
|
|
17029
17599
|
}
|
|
17030
17600
|
function metaOf(node, sources) {
|
|
17031
|
-
const
|
|
17032
|
-
const id =
|
|
17601
|
+
const n2 = node;
|
|
17602
|
+
const id = n2.type === "step" ? n2.step.id : n2.id;
|
|
17033
17603
|
const meta = {
|
|
17034
17604
|
id,
|
|
17035
|
-
kind: KIND_OF[
|
|
17605
|
+
kind: KIND_OF[n2.type] ?? n2.type
|
|
17036
17606
|
};
|
|
17037
17607
|
const pick = /* @__PURE__ */ __name((k, v) => {
|
|
17038
17608
|
if (v !== void 0) meta[k] = v;
|
|
17039
17609
|
}, "pick");
|
|
17040
|
-
pick("timeoutSeconds",
|
|
17041
|
-
pick("retry",
|
|
17042
|
-
pick("sideEffects",
|
|
17043
|
-
pick("onError",
|
|
17044
|
-
pick("requiredConnections",
|
|
17045
|
-
pick("resumeTimeoutHours",
|
|
17046
|
-
pick("onSuspendTimeout",
|
|
17047
|
-
pick("businessHours",
|
|
17048
|
-
pick("tier",
|
|
17049
|
-
pick("harness",
|
|
17050
|
-
pick("workspace",
|
|
17051
|
-
pick("jobResources",
|
|
17052
|
-
pick("maxTurns",
|
|
17053
|
-
|
|
17054
|
-
|
|
17610
|
+
pick("timeoutSeconds", n2.timeoutSeconds);
|
|
17611
|
+
pick("retry", n2.retry);
|
|
17612
|
+
pick("sideEffects", n2.sideEffects);
|
|
17613
|
+
pick("onError", n2.onError);
|
|
17614
|
+
pick("requiredConnections", n2.requiredConnections);
|
|
17615
|
+
pick("resumeTimeoutHours", n2.resumeTimeoutHours);
|
|
17616
|
+
pick("onSuspendTimeout", n2.onSuspendTimeout);
|
|
17617
|
+
pick("businessHours", n2.businessHours);
|
|
17618
|
+
pick("tier", n2.tier);
|
|
17619
|
+
pick("harness", n2.harness);
|
|
17620
|
+
pick("workspace", n2.workspace);
|
|
17621
|
+
pick("jobResources", n2.jobResources);
|
|
17622
|
+
pick("maxTurns", n2.maxTurns);
|
|
17623
|
+
pick("maxMessages", n2.maxMessages);
|
|
17624
|
+
pick("maxInputTokens", n2.maxInputTokens);
|
|
17625
|
+
if (n2.type === "step") {
|
|
17626
|
+
const s = n2.step;
|
|
17055
17627
|
pick("inputSchema", s.inputSchema);
|
|
17056
17628
|
pick("outputSchema", s.outputSchema);
|
|
17057
17629
|
pick("suspendSchema", s.suspendSchema);
|
|
17058
17630
|
pick("resumeSchema", s.resumeSchema);
|
|
17059
17631
|
}
|
|
17060
|
-
if (
|
|
17061
|
-
pick("outputSchema",
|
|
17062
|
-
const jobTools =
|
|
17632
|
+
if (n2.type === "agent") {
|
|
17633
|
+
pick("outputSchema", n2.outputSchema);
|
|
17634
|
+
const jobTools = n2.toolScope?.jobTools;
|
|
17063
17635
|
pick("jobTools", jobTools);
|
|
17064
17636
|
}
|
|
17065
|
-
if (
|
|
17066
|
-
pick("editedPayloadSchema",
|
|
17067
|
-
pick("itemsPath",
|
|
17068
|
-
pick("itemApprover",
|
|
17069
|
-
pick("itemTimeout",
|
|
17637
|
+
if (n2.type === "approval") {
|
|
17638
|
+
pick("editedPayloadSchema", n2.editedPayloadSchema);
|
|
17639
|
+
pick("itemsPath", n2.itemsPath);
|
|
17640
|
+
pick("itemApprover", n2.itemApprover);
|
|
17641
|
+
pick("itemTimeout", n2.itemTimeout);
|
|
17070
17642
|
}
|
|
17071
|
-
if (
|
|
17643
|
+
if (n2.type === "waitForSignal") pick("outputSchema", n2.schema);
|
|
17072
17644
|
const src = sources.get(id);
|
|
17073
17645
|
if (src) meta.source = src;
|
|
17074
17646
|
return meta;
|
|
@@ -17108,21 +17680,25 @@ function deriveStepMeta(graph, sources) {
|
|
|
17108
17680
|
}
|
|
17109
17681
|
return out;
|
|
17110
17682
|
}
|
|
17111
|
-
function computeDeferred(graph) {
|
|
17683
|
+
function computeDeferred(graph, opts = {}) {
|
|
17112
17684
|
const deferred = /* @__PURE__ */ new Set();
|
|
17113
|
-
|
|
17114
|
-
|
|
17685
|
+
let mounts = false;
|
|
17686
|
+
const declaredKeys = new Set((graph.connections ?? []).map((c) => c.key));
|
|
17687
|
+
const serverDecides = /* @__PURE__ */ __name((ref) => typeof ref === "string" && !declaredKeys.has(ref) && !isConnectionKeyShaped(ref), "serverDecides");
|
|
17688
|
+
const visit = /* @__PURE__ */ __name((n2) => {
|
|
17689
|
+
if (n2.type === "agent" && n2.agentId === "$self") {
|
|
17115
17690
|
deferred.add("ephemeral-tools-not-subset");
|
|
17116
17691
|
deferred.add("ephemeral-specialists-disabled");
|
|
17117
|
-
if (
|
|
17692
|
+
if (n2.role?.ref) deferred.add("role-ref-unknown");
|
|
17118
17693
|
}
|
|
17119
|
-
if (
|
|
17694
|
+
if (n2.workspace !== void 0 && n2.workspace !== "inherit") mounts = true;
|
|
17695
|
+
if (n2.tier === "job") {
|
|
17120
17696
|
deferred.add("job-tier-disabled");
|
|
17121
17697
|
deferred.add("job-tier-provider-unsupported");
|
|
17122
17698
|
}
|
|
17123
|
-
if (Array.isArray(
|
|
17124
|
-
if (
|
|
17125
|
-
const a =
|
|
17699
|
+
if (Array.isArray(n2.requiredConnections) && n2.requiredConnections.some(serverDecides)) deferred.add("required-connection-unknown");
|
|
17700
|
+
if (n2.type === "approval") {
|
|
17701
|
+
const a = n2.approver;
|
|
17126
17702
|
if (a && typeof a === "object") {
|
|
17127
17703
|
if ("role" in a) deferred.add("approver-role-unknown");
|
|
17128
17704
|
if ("users" in a) deferred.add("approver-not-member");
|
|
@@ -17130,7 +17706,7 @@ function computeDeferred(graph) {
|
|
|
17130
17706
|
if ("governance" in a) deferred.add("approver-governance-unavailable");
|
|
17131
17707
|
}
|
|
17132
17708
|
}
|
|
17133
|
-
if (
|
|
17709
|
+
if (n2.type === "foreach") deferred.add("foreach-items-exceed-cap");
|
|
17134
17710
|
}, "visit");
|
|
17135
17711
|
for (const entry of graph.definition.graph) {
|
|
17136
17712
|
visit(entry);
|
|
@@ -17142,16 +17718,20 @@ function computeDeferred(graph) {
|
|
|
17142
17718
|
]) if (child) visit(child);
|
|
17143
17719
|
}
|
|
17144
17720
|
const ws = graph.workspace;
|
|
17145
|
-
if (ws?.credentialsRef) deferred.add("credentials-ref-unknown");
|
|
17721
|
+
if (serverDecides(ws?.credentialsRef)) deferred.add("credentials-ref-unknown");
|
|
17146
17722
|
if (ws?.backend && ws.backend !== "ebs") deferred.add("workspace-backend-unavailable");
|
|
17723
|
+
if (opts.mayInherit && !ws && mounts) deferred.add("workspace-not-declared");
|
|
17147
17724
|
if (graph.budget && graph.budget.maxCredits !== void 0) deferred.add("budget-exceeds-cap");
|
|
17148
17725
|
return [
|
|
17149
17726
|
...deferred
|
|
17150
17727
|
].sort();
|
|
17151
17728
|
}
|
|
17152
|
-
function validateGraph(graph) {
|
|
17729
|
+
function validateGraph(graph, opts = {}) {
|
|
17153
17730
|
return validateLuaExtensions(graph, WORKFLOW_CAPS_DEFAULT, {
|
|
17154
|
-
static: true
|
|
17731
|
+
static: true,
|
|
17732
|
+
...opts.mayInherit ? {
|
|
17733
|
+
mayInherit: true
|
|
17734
|
+
} : {}
|
|
17155
17735
|
});
|
|
17156
17736
|
}
|
|
17157
17737
|
function stampGraphHash(code, graph) {
|
|
@@ -17171,7 +17751,32 @@ function toIssues(issues, sources) {
|
|
|
17171
17751
|
source: i.stepId ? sources.get(i.stepId) : void 0
|
|
17172
17752
|
}));
|
|
17173
17753
|
}
|
|
17174
|
-
|
|
17754
|
+
function applyInheritCandidate(d) {
|
|
17755
|
+
if (d.topology === "sketch") return d;
|
|
17756
|
+
const sources = new Map(d.stepMeta.flatMap((m) => m.source ? [
|
|
17757
|
+
[
|
|
17758
|
+
m.id,
|
|
17759
|
+
m.source
|
|
17760
|
+
]
|
|
17761
|
+
] : []));
|
|
17762
|
+
const before = new Set(toIssues(d.validation, sources).map(issueKey));
|
|
17763
|
+
const validation = validateGraph(d.graph, {
|
|
17764
|
+
mayInherit: true
|
|
17765
|
+
});
|
|
17766
|
+
return {
|
|
17767
|
+
...d,
|
|
17768
|
+
mayInherit: true,
|
|
17769
|
+
validation,
|
|
17770
|
+
issues: [
|
|
17771
|
+
...d.issues.filter((i) => !before.has(issueKey(i))),
|
|
17772
|
+
...toIssues(validation, sources)
|
|
17773
|
+
],
|
|
17774
|
+
deferred: computeDeferred(d.graph, {
|
|
17775
|
+
mayInherit: true
|
|
17776
|
+
})
|
|
17777
|
+
};
|
|
17778
|
+
}
|
|
17779
|
+
var NOT_STATIC, isNotStatic, isBuildError, inheritRefsOf, COMMITTED_WORKFLOW_MEMBERS, isCommittedWorkflow, PLATFORM_GLOBALS, calleeName, KIND_OF, GRAPH_HASH_PLACEHOLDER, issueKey;
|
|
17175
17780
|
var init_graph_serializer = __esm({
|
|
17176
17781
|
"src/compiler/utils/graph-serializer.ts"() {
|
|
17177
17782
|
"use strict";
|
|
@@ -17183,6 +17788,7 @@ var init_graph_serializer = __esm({
|
|
|
17183
17788
|
NOT_STATIC = "WORKFLOW_GRAPH_NOT_STATIC";
|
|
17184
17789
|
isNotStatic = /* @__PURE__ */ __name((e) => typeof e === "object" && e !== null && e.code === NOT_STATIC, "isNotStatic");
|
|
17185
17790
|
isBuildError = /* @__PURE__ */ __name((e) => e instanceof LuaWorkflowBuildError || typeof e === "object" && e !== null && e.name === "LuaWorkflowBuildError" && typeof e.code === "string", "isBuildError");
|
|
17791
|
+
inheritRefsOf = /* @__PURE__ */ __name((wf) => (wf?.getNestedWorkflowRefs() ?? []).filter((r) => r.workspace === "inherit").map((r) => r.name), "inheritRefsOf");
|
|
17186
17792
|
COMMITTED_WORKFLOW_MEMBERS = [
|
|
17187
17793
|
"getName",
|
|
17188
17794
|
"getBuildWarnings",
|
|
@@ -17222,6 +17828,8 @@ var init_graph_serializer = __esm({
|
|
|
17222
17828
|
return Node17.isPropertyAccessExpression(callee) ? callee.getName() : callee.getText();
|
|
17223
17829
|
}, "calleeName");
|
|
17224
17830
|
__name(stepRefId, "stepRefId");
|
|
17831
|
+
__name(workflowRefName, "workflowRefName");
|
|
17832
|
+
__name(sketchInheritRefs, "sketchInheritRefs");
|
|
17225
17833
|
__name(callDeclaredIds, "callDeclaredIds");
|
|
17226
17834
|
__name(stampSources, "stampSources");
|
|
17227
17835
|
__name(collectBuilderCalls, "collectBuilderCalls");
|
|
@@ -17245,6 +17853,13 @@ var init_graph_serializer = __esm({
|
|
|
17245
17853
|
GRAPH_HASH_PLACEHOLDER = "__LUA_GRAPH_HASH__";
|
|
17246
17854
|
__name(stampGraphHash, "stampGraphHash");
|
|
17247
17855
|
__name(toIssues, "toIssues");
|
|
17856
|
+
issueKey = /* @__PURE__ */ __name((i) => [
|
|
17857
|
+
i.code,
|
|
17858
|
+
i.path ?? "",
|
|
17859
|
+
i.stepId ?? "",
|
|
17860
|
+
i.message
|
|
17861
|
+
].join("\0"), "issueKey");
|
|
17862
|
+
__name(applyInheritCandidate, "applyInheritCandidate");
|
|
17248
17863
|
}
|
|
17249
17864
|
});
|
|
17250
17865
|
|
|
@@ -17352,7 +17967,7 @@ function collectSingleSteps(graph) {
|
|
|
17352
17967
|
}
|
|
17353
17968
|
function collectGraphIds(graph) {
|
|
17354
17969
|
const ids = [];
|
|
17355
|
-
const idOf = /* @__PURE__ */ __name((
|
|
17970
|
+
const idOf = /* @__PURE__ */ __name((n2) => n2.type === "step" ? n2.step.id : n2.id, "idOf");
|
|
17356
17971
|
for (const entry of graph.definition.graph) {
|
|
17357
17972
|
const e = entry;
|
|
17358
17973
|
const own = idOf(e);
|
|
@@ -17698,6 +18313,7 @@ ${firstBundleFrame(vmResult.error.stack)}` : ""}`,
|
|
|
17698
18313
|
envKeys: [],
|
|
17699
18314
|
envTemplateKeys: [],
|
|
17700
18315
|
workflowRefs: [],
|
|
18316
|
+
inheritRefs: [],
|
|
17701
18317
|
buildWarnings: []
|
|
17702
18318
|
};
|
|
17703
18319
|
issues.push({
|
|
@@ -17719,6 +18335,7 @@ ${firstBundleFrame(vmResult.error.stack)}` : ""}`,
|
|
|
17719
18335
|
envKeys: [],
|
|
17720
18336
|
envTemplateKeys: [],
|
|
17721
18337
|
workflowRefs: [],
|
|
18338
|
+
inheritRefs: [],
|
|
17722
18339
|
buildWarnings: []
|
|
17723
18340
|
};
|
|
17724
18341
|
}
|
|
@@ -17761,7 +18378,9 @@ ${firstBundleFrame(vmResult.error.stack)}` : ""}`,
|
|
|
17761
18378
|
}
|
|
17762
18379
|
}
|
|
17763
18380
|
}
|
|
17764
|
-
const validation = tier.topology === "sketch" ? [] : validateGraph(graph
|
|
18381
|
+
const validation = tier.topology === "sketch" ? [] : validateGraph(graph, {
|
|
18382
|
+
mayInherit: opts.inheritCandidate
|
|
18383
|
+
});
|
|
17765
18384
|
issues.push(...toIssues(validation, sources));
|
|
17766
18385
|
const stamped = stampGraphHash(artifact.code, graph);
|
|
17767
18386
|
const stampedArtifact = {
|
|
@@ -17778,12 +18397,38 @@ ${firstBundleFrame(vmResult.error.stack)}` : ""}`,
|
|
|
17778
18397
|
envTemplateKeys: tier.envTemplateKeys,
|
|
17779
18398
|
partialNodes: tier.partialNodes,
|
|
17780
18399
|
workflowRefs: tier.workflowRefs,
|
|
18400
|
+
inheritRefs: tier.inheritRefs,
|
|
18401
|
+
...opts.inheritCandidate ? {
|
|
18402
|
+
mayInherit: true
|
|
18403
|
+
} : {},
|
|
17781
18404
|
issues,
|
|
17782
|
-
deferred: computeDeferred(graph
|
|
18405
|
+
deferred: computeDeferred(graph, {
|
|
18406
|
+
mayInherit: opts.inheritCandidate
|
|
18407
|
+
}),
|
|
17783
18408
|
artifact: stampedArtifact,
|
|
17784
18409
|
validation
|
|
17785
18410
|
};
|
|
17786
18411
|
}
|
|
18412
|
+
/**
|
|
18413
|
+
* LUA-635 (03 §3.1 table): once every primitive is derived, a workflow that another workflow of the project starts
|
|
18414
|
+
* with `.workflow(…, { workspace: 'inherit' })` is an inherit candidate — its `workspace-not-declared` defers to
|
|
18415
|
+
* createRun (it mounts the parent's volume). The child's own `.commit()` could not know this: it ran at module
|
|
18416
|
+
* evaluation, before any parent existed.
|
|
18417
|
+
*/
|
|
18418
|
+
linkGraphs(compiled) {
|
|
18419
|
+
const workflows = compiled.filter((p) => p.kind === PrimitiveKind.WORKFLOW && p.graph);
|
|
18420
|
+
const inheritTargets2 = new Set(workflows.flatMap((p) => p.graph?.inheritRefs ?? []));
|
|
18421
|
+
for (const p of workflows) if (p.graph && inheritTargets2.has(p.name)) p.graph = applyInheritCandidate(p.graph);
|
|
18422
|
+
const sketched = workflows.filter((p) => p.graph?.topology === "sketch").map((p) => p.name);
|
|
18423
|
+
if (sketched.length === 0) return;
|
|
18424
|
+
for (const p of workflows) {
|
|
18425
|
+
if (!p.graph || inheritTargets2.has(p.name)) continue;
|
|
18426
|
+
for (const issue of p.graph.issues) {
|
|
18427
|
+
if (issue.code !== "workspace-not-declared") continue;
|
|
18428
|
+
issue.message += ` \u2014 ${sketched.join(", ")} ${sketched.length === 1 ? "is" : "are"} at sketch topology: a \`.workflow(\u2026, { workspace: 'inherit' })\` there that names this workflow through anything but a string or a createWorkflow({ name }) binding is invisible to the compiler; make that file evaluate statically first, or declare the workspace here`;
|
|
18429
|
+
}
|
|
18430
|
+
}
|
|
18431
|
+
}
|
|
17787
18432
|
// ===========================================================================
|
|
17788
18433
|
// MANIFEST — 03 §3.3.3
|
|
17789
18434
|
// ===========================================================================
|
|
@@ -17816,7 +18461,7 @@ ${firstBundleFrame(vmResult.error.stack)}` : ""}`,
|
|
|
17816
18461
|
if (!d) throw new Error(`workflow "${compiled.name}" was compiled without a graph derivation`);
|
|
17817
18462
|
const cfg = d.graph ?? {};
|
|
17818
18463
|
const config = compiled.metadata.config ?? {};
|
|
17819
|
-
const toolIds = collectSingleSteps(d.graph).filter((
|
|
18464
|
+
const toolIds = collectSingleSteps(d.graph).filter((n2) => n2.type === "tool").map((n2) => n2.toolId);
|
|
17820
18465
|
const toolRefs = [
|
|
17821
18466
|
...new Set(toolIds)
|
|
17822
18467
|
].map((toolId) => allPrimitives?.find((p) => p.kind === "tool" && p.name === toolId)?.name ?? toolId);
|
|
@@ -17839,6 +18484,7 @@ ${firstBundleFrame(vmResult.error.stack)}` : ""}`,
|
|
|
17839
18484
|
partialNodes: d.partialNodes,
|
|
17840
18485
|
toolRefs,
|
|
17841
18486
|
workflowRefs: d.workflowRefs,
|
|
18487
|
+
mayInherit: d.mayInherit,
|
|
17842
18488
|
budget: cfg.budget,
|
|
17843
18489
|
concurrencyPolicy: cfg.concurrencyPolicy,
|
|
17844
18490
|
schedule: config.schedule,
|
|
@@ -18838,6 +19484,10 @@ var init_compiler = __esm({
|
|
|
18838
19484
|
});
|
|
18839
19485
|
const CONCURRENCY = 4;
|
|
18840
19486
|
const compileResults = await this.compileInParallel(allMetadata, CONCURRENCY);
|
|
19487
|
+
const compiled = compileResults.flatMap((r) => "compiled" in r && r.compiled ? [
|
|
19488
|
+
r.compiled
|
|
19489
|
+
] : []);
|
|
19490
|
+
for (const plugin of pluginRegistry.getAll()) plugin.linkGraphs?.(compiled);
|
|
18841
19491
|
let graphErrors = 0;
|
|
18842
19492
|
for (const result of compileResults) {
|
|
18843
19493
|
if ("error" in result) {
|
|
@@ -22511,7 +23161,7 @@ function createWorkflowsRuntime(getApi) {
|
|
|
22511
23161
|
}
|
|
22512
23162
|
};
|
|
22513
23163
|
}
|
|
22514
|
-
var WORKFLOW_START_MAX_WAIT_SECONDS, WORKFLOW_START_CLIENT_DEADLINE_SLACK_MS, CONTROL_UNAVAILABLE_HINT, WorkflowApiError, WORKFLOWS_RUNTIME_MEMBERS, unwrap, assertBoundAgent, unavailable, WorkflowApi;
|
|
23164
|
+
var WORKFLOW_START_MAX_WAIT_SECONDS, WORKFLOW_START_CLIENT_DEADLINE_SLACK_MS, CONTROL_UNAVAILABLE_HINT, WorkflowApiError, WORKFLOWS_RUNTIME_MEMBERS, unwrap, assertBoundAgent, pathId, unavailable, WorkflowApi;
|
|
22515
23165
|
var init_workflow_api_service = __esm({
|
|
22516
23166
|
"src/api/workflow.api.service.ts"() {
|
|
22517
23167
|
"use strict";
|
|
@@ -22562,6 +23212,7 @@ var init_workflow_api_service = __esm({
|
|
|
22562
23212
|
throw new WorkflowApiError("FORBIDDEN", `Workflows.${member}: goals are scoped to the bound agent ${api.agentId}`, 403);
|
|
22563
23213
|
}
|
|
22564
23214
|
}, "assertBoundAgent");
|
|
23215
|
+
pathId = /* @__PURE__ */ __name((id) => encodeURIComponent(id), "pathId");
|
|
22565
23216
|
unavailable = /* @__PURE__ */ __name((member, route) => async () => {
|
|
22566
23217
|
throw new WorkflowApiError("WORKFLOWS_API_UNAVAILABLE", `Workflows.${member} is not available in this runtime yet (${route} lands with a later wave)`, 501);
|
|
22567
23218
|
}, "unavailable");
|
|
@@ -22687,7 +23338,7 @@ var init_workflow_api_service = __esm({
|
|
|
22687
23338
|
/** R5 — one step of a run (`?attempt=n` selects from the attempt history). */
|
|
22688
23339
|
async getRunStep(runId, stepId, options = {}) {
|
|
22689
23340
|
const qs = options.attempt !== void 0 ? `?attempt=${options.attempt}` : "";
|
|
22690
|
-
return this.httpGet(`${this.runs}/${runId}/steps/${stepId}${qs}`, await this.auth());
|
|
23341
|
+
return this.httpGet(`${this.runs}/${runId}/steps/${pathId(stepId)}${qs}`, await this.auth());
|
|
22691
23342
|
}
|
|
22692
23343
|
/** R6 — script-form journal page (404 `NOT_SCRIPT_RUN` for graph runs — IF-16). */
|
|
22693
23344
|
async getRunJournal(runId, options = {}) {
|
|
@@ -22707,7 +23358,7 @@ var init_workflow_api_service = __esm({
|
|
|
22707
23358
|
}
|
|
22708
23359
|
/** R12 — resume a suspended step; the loser of a race gets `{ resumed:false, reason:'already_resumed' }`, never a 4xx. */
|
|
22709
23360
|
async resumeRun(runId, stepId, data) {
|
|
22710
|
-
return this.httpPost(`${this.runs}/${runId}/steps/${stepId}/resume`, data, await this.auth());
|
|
23361
|
+
return this.httpPost(`${this.runs}/${runId}/steps/${pathId(stepId)}/resume`, data, await this.auth());
|
|
22711
23362
|
}
|
|
22712
23363
|
/**
|
|
22713
23364
|
* R36 — re-arm a parked step: a failed row past its retries, a gate-2 park, or a billing hold (the only exit
|
|
@@ -22715,15 +23366,15 @@ var init_workflow_api_service = __esm({
|
|
|
22715
23366
|
* STEP_NOT_PARKED.
|
|
22716
23367
|
*/
|
|
22717
23368
|
async retryStep(runId, stepId, data = {}) {
|
|
22718
|
-
return this.httpPost(`${this.runs}/${runId}/steps/${stepId}/retry`, data, await this.auth());
|
|
23369
|
+
return this.httpPost(`${this.runs}/${runId}/steps/${pathId(stepId)}/retry`, data, await this.auth());
|
|
22719
23370
|
}
|
|
22720
23371
|
/** R13 — resolve an approval (human; `expectedFingerprint` guards against an edited payload — 409 `PAYLOAD_MISMATCH`). */
|
|
22721
23372
|
async resolveApproval(runId, approvalId, data) {
|
|
22722
|
-
return this.httpPost(`${this.runs}/${runId}/approvals/${approvalId}/resolve`, data, await this.auth());
|
|
23373
|
+
return this.httpPost(`${this.runs}/${runId}/approvals/${pathId(approvalId)}/resolve`, data, await this.auth());
|
|
22723
23374
|
}
|
|
22724
23375
|
/** R14 — deliver a named signal (`dedupeKey` ⇒ 200 `duplicate:true` on replay). */
|
|
22725
23376
|
async signalRun(runId, name, data = {}) {
|
|
22726
|
-
return this.httpPost(`${this.runs}/${runId}/signals/${
|
|
23377
|
+
return this.httpPost(`${this.runs}/${runId}/signals/${pathId(name)}`, data, await this.auth());
|
|
22727
23378
|
}
|
|
22728
23379
|
/** R31 — `DELETE …/runs/:runId` (`eraseRun`; human principal) → 202 `{ accepted, purgeId }`; 409 `RUN_NOT_TERMINAL { nextAction:'cancel' }`. */
|
|
22729
23380
|
/** R50 — request an evidence-bundle export (202 `{exportId, status:'pending'}`; 409 `RUN_NOT_TERMINAL` / `EXPORT_IN_PROGRESS`). */
|
|
@@ -22780,6 +23431,23 @@ var init_workflow_api_service = __esm({
|
|
|
22780
23431
|
async closeGoal(goalId, data = {}) {
|
|
22781
23432
|
return this.httpPost(`${this.goals}/${encodeURIComponent(goalId)}/close`, data, await this.auth());
|
|
22782
23433
|
}
|
|
23434
|
+
// ─── Schedules (R4-MF-2 list/get + R28 delete — `/workflows/:agentId/schedules`; LUA-627 stanza) ───
|
|
23435
|
+
/** Schedule tree (09 §9.5 — the write-only R27/R56/R28 family plus the R4-MF-2 read rows). */
|
|
23436
|
+
get schedules() {
|
|
23437
|
+
return `/workflows/${this.agentId}/schedules`;
|
|
23438
|
+
}
|
|
23439
|
+
/** R4-MF-2 — every `Job{kind:'workflow'}` of the agent with the PRO-726 strike fields (`goalId` marks a goal's cadence). */
|
|
23440
|
+
async listSchedules() {
|
|
23441
|
+
return this.httpGet(this.schedules, await this.auth());
|
|
23442
|
+
}
|
|
23443
|
+
/** R4-MF-2 — one schedule row; unknown, cross-agent and non-workflow-kind jobs all 404 `SCHEDULE_NOT_FOUND`. */
|
|
23444
|
+
async getSchedule(jobId) {
|
|
23445
|
+
return this.httpGet(`${this.schedules}/${encodeURIComponent(jobId)}`, await this.auth());
|
|
23446
|
+
}
|
|
23447
|
+
/** R28 — delete a schedule Job (404 `SCHEDULE_NOT_FOUND`). The CLI refuses a goal-owned job BEFORE this call (`goal_schedule`). */
|
|
23448
|
+
async deleteSchedule(jobId) {
|
|
23449
|
+
return this.httpDelete(`${this.schedules}/${encodeURIComponent(jobId)}`, await this.auth());
|
|
23450
|
+
}
|
|
22783
23451
|
// ─── Events (R7 — SSE `watch`, WF-204) ───
|
|
22784
23452
|
/**
|
|
22785
23453
|
* R7 SSE — `GET …/runs/:runId/events` as a frame stream (`id:<seq>` / `event:<type>` /
|
|
@@ -22823,7 +23491,7 @@ var init_workflow_api_service = __esm({
|
|
|
22823
23491
|
if (options.attempt !== void 0) query.append("attempt", String(options.attempt));
|
|
22824
23492
|
if (options.tail !== void 0) query.append("tail", String(options.tail));
|
|
22825
23493
|
const qs = query.toString();
|
|
22826
|
-
return this.httpGet(`${this.runs}/${runId}/steps/${stepId}/job${qs ? `?${qs}` : ""}`, await this.auth());
|
|
23494
|
+
return this.httpGet(`${this.runs}/${runId}/steps/${pathId(stepId)}/job${qs ? `?${qs}` : ""}`, await this.auth());
|
|
22827
23495
|
}
|
|
22828
23496
|
};
|
|
22829
23497
|
}
|
|
@@ -29501,6 +30169,7 @@ init_types();
|
|
|
29501
30169
|
init_constants();
|
|
29502
30170
|
init_workflow_api_service();
|
|
29503
30171
|
init_artifact_loader();
|
|
30172
|
+
init_bundle_upload();
|
|
29504
30173
|
|
|
29505
30174
|
// src/utils/sandbox.ts
|
|
29506
30175
|
init_dist4();
|
|
@@ -29740,7 +30409,7 @@ function matchesEditablePath2(leafPath, editablePaths) {
|
|
|
29740
30409
|
});
|
|
29741
30410
|
}
|
|
29742
30411
|
__name(matchesEditablePath2, "matchesEditablePath");
|
|
29743
|
-
var
|
|
30412
|
+
var armId2 = /* @__PURE__ */ __name((arm) => arm.type === "step" ? arm.step.id : arm.id, "armId");
|
|
29744
30413
|
var outputSchemaOf = /* @__PURE__ */ __name((entry) => {
|
|
29745
30414
|
if (!entry) return void 0;
|
|
29746
30415
|
if (entry.type === "step") return entry.step.outputSchema;
|
|
@@ -30254,7 +30923,7 @@ async function runWorkflowLocallyInner(rawOpts) {
|
|
|
30254
30923
|
case "workflow": {
|
|
30255
30924
|
if (single.workflowId === WORKFLOW_ARM_SUBRUN_ID && single.graph) {
|
|
30256
30925
|
const [armMap, inner] = single.graph;
|
|
30257
|
-
const innerId =
|
|
30926
|
+
const innerId = armId2(inner);
|
|
30258
30927
|
const ctx = {
|
|
30259
30928
|
...mappingCtx(),
|
|
30260
30929
|
stepResults: {
|
|
@@ -30430,6 +31099,7 @@ async function runWorkflowLocallyInner(rawOpts) {
|
|
|
30430
31099
|
const onError = single.onError ?? "fail";
|
|
30431
31100
|
if (onError === "continue") {
|
|
30432
31101
|
terminalize(row2, "failed");
|
|
31102
|
+
stepResults[row2.stepId] = continuedFailureValue(row2.error);
|
|
30433
31103
|
return;
|
|
30434
31104
|
}
|
|
30435
31105
|
if (onError === "park") {
|
|
@@ -30472,15 +31142,15 @@ async function runWorkflowLocallyInner(rawOpts) {
|
|
|
30472
31142
|
entry.steps.forEach((arm, i) => {
|
|
30473
31143
|
const pred = entry.predicates[i];
|
|
30474
31144
|
const hit = pred ? evaluatePredicate(pred, ctx) : false;
|
|
30475
|
-
if (hit && (!entry.exclusive || taken.length === 0)) taken.push(
|
|
31145
|
+
if (hit && (!entry.exclusive || taken.length === 0)) taken.push(armId2(arm));
|
|
30476
31146
|
});
|
|
30477
|
-
if (taken.length === 0 && entry.otherwise) taken.push(
|
|
31147
|
+
if (taken.length === 0 && entry.otherwise) taken.push(armId2(entry.otherwise));
|
|
30478
31148
|
const arms = [
|
|
30479
31149
|
...entry.steps,
|
|
30480
31150
|
...entry.otherwise ? [
|
|
30481
31151
|
entry.otherwise
|
|
30482
31152
|
] : []
|
|
30483
|
-
].map(
|
|
31153
|
+
].map(armId2);
|
|
30484
31154
|
terminalize(row2, "completed", {
|
|
30485
31155
|
output: inputFor(row2),
|
|
30486
31156
|
taken
|
|
@@ -30545,7 +31215,7 @@ async function runWorkflowLocallyInner(rawOpts) {
|
|
|
30545
31215
|
};
|
|
30546
31216
|
return;
|
|
30547
31217
|
}
|
|
30548
|
-
const body =
|
|
31218
|
+
const body = armId2(entry.step);
|
|
30549
31219
|
const joinId = joinIdOf(row2.stepId);
|
|
30550
31220
|
const childIds = items.map((_, i) => `${body}[${i}]`);
|
|
30551
31221
|
const childNode = {
|
|
@@ -30590,12 +31260,12 @@ async function runWorkflowLocallyInner(rawOpts) {
|
|
|
30590
31260
|
});
|
|
30591
31261
|
}, "runForeach");
|
|
30592
31262
|
const runLoop = /* @__PURE__ */ __name(async (row2, entry) => {
|
|
30593
|
-
const body =
|
|
31263
|
+
const body = armId2(entry.step);
|
|
30594
31264
|
const max = entry.maxIterations ?? 100;
|
|
30595
31265
|
let last = inputFor(row2);
|
|
30596
31266
|
row2.status = "running";
|
|
30597
|
-
for (let
|
|
30598
|
-
const iterId = `${body}#${
|
|
31267
|
+
for (let n2 = 1; n2 <= max; n2++) {
|
|
31268
|
+
const iterId = `${body}#${n2}`;
|
|
30599
31269
|
const iterRow = addRow(iterId, {
|
|
30600
31270
|
kind: kindOfSingle(entry.step),
|
|
30601
31271
|
dependsOn: [],
|
|
@@ -30627,7 +31297,7 @@ async function runWorkflowLocallyInner(rawOpts) {
|
|
|
30627
31297
|
clock += entry.intervalSeconds * 1e3;
|
|
30628
31298
|
say(`[throttle:${row2.stepId}] kind=loop_interval resumeAt=${new Date(clock).toISOString()}`);
|
|
30629
31299
|
}
|
|
30630
|
-
if (
|
|
31300
|
+
if (n2 === max) {
|
|
30631
31301
|
row2.error = {
|
|
30632
31302
|
code: "loop_max_iterations",
|
|
30633
31303
|
message: `loop ${row2.stepId} hit maxIterations ${max}`
|
|
@@ -30740,14 +31410,16 @@ async function runWorkflowLocallyInner(rawOpts) {
|
|
|
30740
31410
|
case "loop":
|
|
30741
31411
|
await runLoop(row2, entry);
|
|
30742
31412
|
return;
|
|
30743
|
-
case "sleep":
|
|
30744
|
-
|
|
30745
|
-
|
|
30746
|
-
|
|
31413
|
+
case "sleep": {
|
|
31414
|
+
const ms = Math.max(0, Number(entry.duration) || 0);
|
|
31415
|
+
clock += ms;
|
|
31416
|
+
say(`[${stamp()}] ${row2.stepId} \xB7 sleep ${formatSleep(ms)} (${opts.realTime ? "real time" : "virtual clock"})`);
|
|
31417
|
+
if (opts.realTime) await new Promise((r) => setTimeout(r, ms));
|
|
30747
31418
|
terminalize(row2, "completed", {
|
|
30748
31419
|
output: inputFor(row2)
|
|
30749
31420
|
});
|
|
30750
31421
|
return;
|
|
31422
|
+
}
|
|
30751
31423
|
case "sleepUntil": {
|
|
30752
31424
|
let until;
|
|
30753
31425
|
if (entry.date) until = Date.parse(entry.date);
|
|
@@ -30984,6 +31656,13 @@ function writeLedger(file, ledger) {
|
|
|
30984
31656
|
`);
|
|
30985
31657
|
}
|
|
30986
31658
|
__name(writeLedger, "writeLedger");
|
|
31659
|
+
function formatSleep(ms) {
|
|
31660
|
+
if (ms < 1e3) return `${ms} ms`;
|
|
31661
|
+
const s = ms / 1e3;
|
|
31662
|
+
const human = s >= 3600 ? `${+(s / 3600).toFixed(2)} h` : s >= 60 ? `${+(s / 60).toFixed(2)} min` : `${+s.toFixed(3)} s`;
|
|
31663
|
+
return `${ms} ms (${human})`;
|
|
31664
|
+
}
|
|
31665
|
+
__name(formatSleep, "formatSleep");
|
|
30987
31666
|
function parseKeyedJsonFlag(raw, flag) {
|
|
30988
31667
|
const eq3 = raw.indexOf("=");
|
|
30989
31668
|
if (eq3 === -1) throw new WorkflowLocalUsageError("usage", `${flag} expects <id>=@file|<json> (got "${raw}")`);
|
|
@@ -31652,7 +32331,11 @@ var WorkflowHandler = class extends BaseVersionedHandler {
|
|
|
31652
32331
|
name: wf.name,
|
|
31653
32332
|
description: wf.description
|
|
31654
32333
|
});
|
|
31655
|
-
if (!response.success || !response.data?.id)
|
|
32334
|
+
if (!response.success || !response.data?.id) {
|
|
32335
|
+
const hint = workflowNameTakenHint(wf.name, response.error);
|
|
32336
|
+
if (hint) throw new Error(hint);
|
|
32337
|
+
return null;
|
|
32338
|
+
}
|
|
31656
32339
|
return response.data.id;
|
|
31657
32340
|
}
|
|
31658
32341
|
async pushToServer(apiKey, agentId, entityId, pushData) {
|
|
@@ -31680,7 +32363,48 @@ var WorkflowHandler = class extends BaseVersionedHandler {
|
|
|
31680
32363
|
const primitive = findPrimitive(manifest, name, this.kind);
|
|
31681
32364
|
if (!primitive) return null;
|
|
31682
32365
|
if (primitive.form === "script") return this.buildPushData(primitive, void 0);
|
|
31683
|
-
|
|
32366
|
+
const data = super.prepareForPush(manifest, name, projectPath, bundleAccumulator);
|
|
32367
|
+
if (!data) return null;
|
|
32368
|
+
const tools = this.toolBundlesFor(primitive, manifest, projectPath, bundleAccumulator);
|
|
32369
|
+
return tools.length > 0 ? {
|
|
32370
|
+
...data,
|
|
32371
|
+
tools
|
|
32372
|
+
} : data;
|
|
32373
|
+
}
|
|
32374
|
+
/**
|
|
32375
|
+
* LUA-656 (03 §3.5.2 / S3-6): every `.toolStep(id, tool)` reference compiles the tool as its own artifact
|
|
32376
|
+
* (`toolRefs[]`), but nothing ever pushed those artifacts — the version landed with `tools: null`, so the
|
|
32377
|
+
* engine's claim could not resolve `toolId` and every static tool step failed `TOOL_REF_UNRESOLVED`
|
|
32378
|
+
* (prod 2026-09-05, kitchen-sink `armB`, 39/39 runs). Each referenced tool rides the version as
|
|
32379
|
+
* `tools[] = {name, code | codeS3Hash}`, through the same accumulator the workflow bundle uses.
|
|
32380
|
+
*/
|
|
32381
|
+
toolBundlesFor(wf, manifest, projectPath, bundleAccumulator) {
|
|
32382
|
+
const out = [];
|
|
32383
|
+
for (const toolName of [
|
|
32384
|
+
...new Set(wf.toolRefs ?? [])
|
|
32385
|
+
]) {
|
|
32386
|
+
const tool = findPrimitive(manifest, toolName, PrimitiveKind.TOOL);
|
|
32387
|
+
if (!tool) {
|
|
32388
|
+
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)`);
|
|
32389
|
+
continue;
|
|
32390
|
+
}
|
|
32391
|
+
const code = loadArtifact(tool, projectPath);
|
|
32392
|
+
if (bundleAccumulator) {
|
|
32393
|
+
const rawGzip = compressForPushRaw(code);
|
|
32394
|
+
const codeS3Hash = hashBundle(rawGzip);
|
|
32395
|
+
bundleAccumulator.set(codeS3Hash, rawGzip);
|
|
32396
|
+
out.push({
|
|
32397
|
+
name: toolName,
|
|
32398
|
+
codeS3Hash
|
|
32399
|
+
});
|
|
32400
|
+
} else {
|
|
32401
|
+
out.push({
|
|
32402
|
+
name: toolName,
|
|
32403
|
+
code: compressForPush(code)
|
|
32404
|
+
});
|
|
32405
|
+
}
|
|
32406
|
+
}
|
|
32407
|
+
return out;
|
|
31684
32408
|
}
|
|
31685
32409
|
buildPushData(primitive, compressedCode, codeS3Hash) {
|
|
31686
32410
|
const wf = primitive;
|
|
@@ -31746,6 +32470,10 @@ var WorkflowHandler = class extends BaseVersionedHandler {
|
|
|
31746
32470
|
graph: wf.graph,
|
|
31747
32471
|
graphHash: wf.graphHash,
|
|
31748
32472
|
topology: wf.topology,
|
|
32473
|
+
// LUA-650: the compiler's linkGraphs verdict rides the push so the server defers workspace-not-declared too.
|
|
32474
|
+
...wf.mayInherit ? {
|
|
32475
|
+
mayInherit: true
|
|
32476
|
+
} : {},
|
|
31749
32477
|
...wf.schemas ? {
|
|
31750
32478
|
schemas: wf.schemas
|
|
31751
32479
|
} : {},
|
|
@@ -31757,6 +32485,14 @@ var WorkflowHandler = class extends BaseVersionedHandler {
|
|
|
31757
32485
|
}
|
|
31758
32486
|
};
|
|
31759
32487
|
var workflowHandler = new WorkflowHandler();
|
|
32488
|
+
function workflowNameTakenHint(name, error) {
|
|
32489
|
+
if (error?.code !== "WORKFLOW_NAME_TAKEN") return null;
|
|
32490
|
+
const holder = error.dynamic ? "a chat-composed (dynamic) workflow" : "an existing workflow";
|
|
32491
|
+
const id = error.workflowId ? ` (${error.workflowId})` : "";
|
|
32492
|
+
const see = error.dynamic ? "run `lua workflows list --all` to see it" : "run `lua workflows list` to see it";
|
|
32493
|
+
return `workflow name "${name}" is held by ${holder}${id} \u2014 ${see}. Push does not replace it: rename this workflow, or delete the other one first.`;
|
|
32494
|
+
}
|
|
32495
|
+
__name(workflowNameTakenHint, "workflowNameTakenHint");
|
|
31760
32496
|
|
|
31761
32497
|
// src/primitives/index.ts
|
|
31762
32498
|
init_skill_handler();
|
|
@@ -31787,6 +32523,7 @@ async function compileCommand(options) {
|
|
|
31787
32523
|
const debugMode = options?.debug || process.env.LUA_DEBUG === "true";
|
|
31788
32524
|
const verboseMode = options?.verbose || debugMode;
|
|
31789
32525
|
const doSync = options?.sync === true;
|
|
32526
|
+
const doServerSync = options?.serverSync !== false;
|
|
31790
32527
|
if (debugMode) {
|
|
31791
32528
|
console.log("\u{1F41B} Debug mode enabled");
|
|
31792
32529
|
}
|
|
@@ -31858,8 +32595,13 @@ async function compileCommand(options) {
|
|
|
31858
32595
|
}
|
|
31859
32596
|
ensureGitignored(rootDir, "dist-v2/", "dist/");
|
|
31860
32597
|
if (result.warnings.length > 0) {
|
|
32598
|
+
const seen = /* @__PURE__ */ new Set();
|
|
31861
32599
|
for (const warning of result.warnings) {
|
|
31862
|
-
|
|
32600
|
+
const key = `${warning.primitive ?? ""}\0${warning.message}`;
|
|
32601
|
+
if (seen.has(key)) continue;
|
|
32602
|
+
seen.add(key);
|
|
32603
|
+
const who = warning.primitive ? `[${warning.kind ? `${warning.kind} ` : ""}${warning.primitive}] ` : "";
|
|
32604
|
+
console.warn(`\u26A0\uFE0F ${who}${warning.message}`);
|
|
31863
32605
|
}
|
|
31864
32606
|
}
|
|
31865
32607
|
writeProgress("\u{1F504} Syncing YAML with manifest...");
|
|
@@ -31869,13 +32611,17 @@ async function compileCommand(options) {
|
|
|
31869
32611
|
config = readYamlConfig();
|
|
31870
32612
|
}
|
|
31871
32613
|
let apiKey = null;
|
|
31872
|
-
|
|
31873
|
-
|
|
31874
|
-
|
|
32614
|
+
if (doServerSync) {
|
|
32615
|
+
try {
|
|
32616
|
+
apiKey = await resolveRequestCredential();
|
|
32617
|
+
} catch {
|
|
32618
|
+
}
|
|
31875
32619
|
}
|
|
31876
32620
|
let syncConfig = readYamlConfig();
|
|
31877
32621
|
const agentId = syncConfig?.agent?.agentId;
|
|
31878
|
-
if (
|
|
32622
|
+
if (!doServerSync) {
|
|
32623
|
+
writeInfo("\u2139\uFE0F Server sync skipped (offline verb) \u2014 `lua push` when you are ready to publish.");
|
|
32624
|
+
} else if (apiKey && agentId) {
|
|
31879
32625
|
writeProgress("\u{1F504} Syncing with server...");
|
|
31880
32626
|
const fetchResults = await Promise.all(syncableHandlers.map((h) => h.fetchServerState(apiKey, agentId)));
|
|
31881
32627
|
for (let i = 0; i < syncableHandlers.length; i++) {
|
|
@@ -31922,7 +32668,7 @@ async function compileCommand(options) {
|
|
|
31922
32668
|
verbose_mode: verboseMode,
|
|
31923
32669
|
sync_enabled: doSync,
|
|
31924
32670
|
warnings_count: result.warnings.length,
|
|
31925
|
-
server_sync_performed: !!(apiKey && agentId),
|
|
32671
|
+
server_sync_performed: doServerSync && !!(apiKey && agentId),
|
|
31926
32672
|
backup_out_of_sync: backupOutOfSync
|
|
31927
32673
|
});
|
|
31928
32674
|
}, "compilation");
|
|
@@ -31981,18 +32727,18 @@ init_analytics();
|
|
|
31981
32727
|
|
|
31982
32728
|
// src/utils/suggest.ts
|
|
31983
32729
|
function levenshtein(a, b) {
|
|
31984
|
-
const m = a.length,
|
|
32730
|
+
const m = a.length, n2 = b.length;
|
|
31985
32731
|
const dp = Array.from({
|
|
31986
32732
|
length: m + 1
|
|
31987
|
-
}, () => Array(
|
|
32733
|
+
}, () => Array(n2 + 1).fill(0));
|
|
31988
32734
|
for (let i = 0; i <= m; i++) dp[i][0] = i;
|
|
31989
|
-
for (let j = 0; j <=
|
|
32735
|
+
for (let j = 0; j <= n2; j++) dp[0][j] = j;
|
|
31990
32736
|
for (let i = 1; i <= m; i++) {
|
|
31991
|
-
for (let j = 1; j <=
|
|
32737
|
+
for (let j = 1; j <= n2; j++) {
|
|
31992
32738
|
dp[i][j] = a[i - 1] === b[j - 1] ? dp[i - 1][j - 1] : 1 + Math.min(dp[i - 1][j], dp[i][j - 1], dp[i - 1][j - 1]);
|
|
31993
32739
|
}
|
|
31994
32740
|
}
|
|
31995
|
-
return dp[m][
|
|
32741
|
+
return dp[m][n2];
|
|
31996
32742
|
}
|
|
31997
32743
|
__name(levenshtein, "levenshtein");
|
|
31998
32744
|
function suggestClosest(input, candidates) {
|
|
@@ -32394,9 +33140,14 @@ var ALIAS_MAP = {
|
|
|
32394
33140
|
"archive-runs",
|
|
32395
33141
|
"workspace",
|
|
32396
33142
|
"jobs",
|
|
32397
|
-
"job-logs"
|
|
33143
|
+
"job-logs",
|
|
33144
|
+
"goals",
|
|
33145
|
+
"schedules"
|
|
32398
33146
|
],
|
|
32399
33147
|
aliases: lowerKeys({
|
|
33148
|
+
goal: "goals",
|
|
33149
|
+
schedule: "schedules",
|
|
33150
|
+
sched: "schedules",
|
|
32400
33151
|
ws: "workspace",
|
|
32401
33152
|
job: "jobs",
|
|
32402
33153
|
joblogs: "job-logs",
|
|
@@ -32426,6 +33177,45 @@ var ALIAS_MAP = {
|
|
|
32426
33177
|
follow: "watch"
|
|
32427
33178
|
})
|
|
32428
33179
|
},
|
|
33180
|
+
// LUA-627 — the sub-verbs of `lua workflows goals <verb>` / `lua workflows schedules <verb>`.
|
|
33181
|
+
"workflows.goals.action": {
|
|
33182
|
+
canonical: [
|
|
33183
|
+
"list",
|
|
33184
|
+
"get",
|
|
33185
|
+
"create",
|
|
33186
|
+
"pause",
|
|
33187
|
+
"resume",
|
|
33188
|
+
"close"
|
|
33189
|
+
],
|
|
33190
|
+
aliases: lowerKeys({
|
|
33191
|
+
ls: "list",
|
|
33192
|
+
view: "get",
|
|
33193
|
+
show: "get",
|
|
33194
|
+
info: "get",
|
|
33195
|
+
new: "create",
|
|
33196
|
+
add: "create",
|
|
33197
|
+
set: "create",
|
|
33198
|
+
hold: "pause",
|
|
33199
|
+
stop: "pause",
|
|
33200
|
+
unpause: "resume",
|
|
33201
|
+
continue: "resume",
|
|
33202
|
+
end: "close",
|
|
33203
|
+
finish: "close"
|
|
33204
|
+
})
|
|
33205
|
+
},
|
|
33206
|
+
"workflows.schedules.action": {
|
|
33207
|
+
canonical: [
|
|
33208
|
+
"list",
|
|
33209
|
+
"delete"
|
|
33210
|
+
],
|
|
33211
|
+
aliases: lowerKeys({
|
|
33212
|
+
ls: "list",
|
|
33213
|
+
rm: "delete",
|
|
33214
|
+
remove: "delete",
|
|
33215
|
+
del: "delete",
|
|
33216
|
+
unschedule: "delete"
|
|
33217
|
+
})
|
|
33218
|
+
},
|
|
32429
33219
|
"preprocessors.action": preprocessorsAction,
|
|
32430
33220
|
"postprocessors.action": preprocessorsAction,
|
|
32431
33221
|
"devices.action": {
|
|
@@ -32789,6 +33579,14 @@ init_cli();
|
|
|
32789
33579
|
init_command_utils();
|
|
32790
33580
|
init_artifact_loader();
|
|
32791
33581
|
init_types();
|
|
33582
|
+
|
|
33583
|
+
// src/interfaces/workflows.ts
|
|
33584
|
+
function runIdOf(run) {
|
|
33585
|
+
return run.runId ?? run.id ?? "";
|
|
33586
|
+
}
|
|
33587
|
+
__name(runIdOf, "runIdOf");
|
|
33588
|
+
|
|
33589
|
+
// src/commands/workflow-local-run.ts
|
|
32792
33590
|
init_dist2();
|
|
32793
33591
|
|
|
32794
33592
|
// src/utils/workflow-script-local.ts
|
|
@@ -33227,7 +34025,9 @@ async function runWorkflowLocalFromProject(name, flags) {
|
|
|
33227
34025
|
}, "say");
|
|
33228
34026
|
if (!flags.noCompile) {
|
|
33229
34027
|
say("\u{1F4E6} Compiling code first...");
|
|
33230
|
-
await compileCommand(
|
|
34028
|
+
await compileCommand({
|
|
34029
|
+
serverSync: false
|
|
34030
|
+
});
|
|
33231
34031
|
}
|
|
33232
34032
|
const manifest = loadManifest();
|
|
33233
34033
|
const workflows = getPrimitivesByKind(manifest, PrimitiveKind.WORKFLOW);
|
|
@@ -33410,7 +34210,7 @@ async function loadSeedFromRun(runId, wf, apiKey, agentId) {
|
|
|
33410
34210
|
}
|
|
33411
34211
|
}
|
|
33412
34212
|
return seedLedgerFromRun({
|
|
33413
|
-
id: run.data
|
|
34213
|
+
id: runIdOf(run.data),
|
|
33414
34214
|
graphHash: run.data.graphHash
|
|
33415
34215
|
}, rows3, plan, {
|
|
33416
34216
|
targetGraphHash: wf.graphHash
|
|
@@ -36934,6 +37734,19 @@ init_http_client();
|
|
|
36934
37734
|
init_dist();
|
|
36935
37735
|
init_lua_fetch();
|
|
36936
37736
|
init_request_credential();
|
|
37737
|
+
var PLAIN_MARKDOWN_CLIENT_CAPABILITY = "plain-markdown";
|
|
37738
|
+
function withPlainMarkdown(chatData) {
|
|
37739
|
+
const declared = Array.isArray(chatData.clientCapabilities) ? chatData.clientCapabilities : [];
|
|
37740
|
+
if (declared.includes(PLAIN_MARKDOWN_CLIENT_CAPABILITY)) return chatData;
|
|
37741
|
+
return {
|
|
37742
|
+
...chatData,
|
|
37743
|
+
clientCapabilities: [
|
|
37744
|
+
...declared,
|
|
37745
|
+
PLAIN_MARKDOWN_CLIENT_CAPABILITY
|
|
37746
|
+
]
|
|
37747
|
+
};
|
|
37748
|
+
}
|
|
37749
|
+
__name(withPlainMarkdown, "withPlainMarkdown");
|
|
36937
37750
|
var ChatApi = class extends HttpClient {
|
|
36938
37751
|
static {
|
|
36939
37752
|
__name(this, "ChatApi");
|
|
@@ -36956,7 +37769,7 @@ var ChatApi = class extends HttpClient {
|
|
|
36956
37769
|
* @throws Error if the agent is not found or the chat request fails
|
|
36957
37770
|
*/
|
|
36958
37771
|
async sendMessage(agentId, chatData) {
|
|
36959
|
-
return this.httpPostCoreDrainRetry(`/chat/generate/${agentId}?channel=dev`, chatData, {});
|
|
37772
|
+
return this.httpPostCoreDrainRetry(`/chat/generate/${agentId}?channel=dev`, withPlainMarkdown(chatData), {});
|
|
36960
37773
|
}
|
|
36961
37774
|
/**
|
|
36962
37775
|
* Streams a message to an agent and receives chunked responses
|
|
@@ -36978,7 +37791,7 @@ var ChatApi = class extends HttpClient {
|
|
|
36978
37791
|
Authorization: `Bearer ${await bearerFor(this.credential)}`,
|
|
36979
37792
|
"Content-Type": "application/json"
|
|
36980
37793
|
},
|
|
36981
|
-
body: JSON.stringify(chatData)
|
|
37794
|
+
body: JSON.stringify(withPlainMarkdown(chatData))
|
|
36982
37795
|
}), {
|
|
36983
37796
|
signal: controller.signal
|
|
36984
37797
|
});
|
|
@@ -40968,8 +41781,8 @@ async function doSearch(api) {
|
|
|
40968
41781
|
return;
|
|
40969
41782
|
}
|
|
40970
41783
|
writeSuccess(`Found ${numbers.length} number(s):`);
|
|
40971
|
-
for (const
|
|
40972
|
-
console.log(` ${
|
|
41784
|
+
for (const n2 of numbers) {
|
|
41785
|
+
console.log(` ${n2.msisdn} ${n2.country ?? ""} ${n2.type ?? ""} ${smsLabel(n2.transport)} ${n2.monthlyCost ?? ""} ${n2.currency ?? ""}`);
|
|
40973
41786
|
}
|
|
40974
41787
|
}
|
|
40975
41788
|
__name(doSearch, "doSearch");
|
|
@@ -40995,9 +41808,9 @@ async function doPurchase(api, agentId, orgId, apiKey) {
|
|
|
40995
41808
|
// height and silently hides later entries.
|
|
40996
41809
|
pageSize: 15,
|
|
40997
41810
|
message: `Pick a number (${numbers.length} available):`,
|
|
40998
|
-
choices: numbers.map((
|
|
40999
|
-
name: `${
|
|
41000
|
-
value:
|
|
41811
|
+
choices: numbers.map((n2) => ({
|
|
41812
|
+
name: `${n2.msisdn} (${n2.country}, ${n2.type ?? "\u2014"}) \u2014 ${smsLabel(n2.transport)}`,
|
|
41813
|
+
value: n2.msisdn
|
|
41001
41814
|
}))
|
|
41002
41815
|
}
|
|
41003
41816
|
]);
|
|
@@ -41102,13 +41915,13 @@ async function doList(api, orgId) {
|
|
|
41102
41915
|
"Modality",
|
|
41103
41916
|
"Agent",
|
|
41104
41917
|
"Voice"
|
|
41105
|
-
], numbers.map((
|
|
41106
|
-
|
|
41107
|
-
|
|
41108
|
-
|
|
41109
|
-
smsLabel(
|
|
41110
|
-
|
|
41111
|
-
|
|
41918
|
+
], numbers.map((n2) => [
|
|
41919
|
+
n2.msisdn,
|
|
41920
|
+
n2.country ?? "\u2014",
|
|
41921
|
+
n2.status,
|
|
41922
|
+
smsLabel(n2.transport),
|
|
41923
|
+
n2.agentId ?? "\u2014",
|
|
41924
|
+
n2.voiceId ?? "\u2014"
|
|
41112
41925
|
])));
|
|
41113
41926
|
}
|
|
41114
41927
|
__name(doList, "doList");
|
|
@@ -43872,12 +44685,12 @@ function deriveHints(report) {
|
|
|
43872
44685
|
return hints;
|
|
43873
44686
|
}
|
|
43874
44687
|
__name(deriveHints, "deriveHints");
|
|
43875
|
-
function pad(s,
|
|
43876
|
-
return s.length >=
|
|
44688
|
+
function pad(s, n2) {
|
|
44689
|
+
return s.length >= n2 ? s : s + " ".repeat(n2 - s.length);
|
|
43877
44690
|
}
|
|
43878
44691
|
__name(pad, "pad");
|
|
43879
|
-
function truncate2(s,
|
|
43880
|
-
return s.length <=
|
|
44692
|
+
function truncate2(s, n2) {
|
|
44693
|
+
return s.length <= n2 ? s : s.slice(0, Math.max(0, n2 - 1)) + "\u2026";
|
|
43881
44694
|
}
|
|
43882
44695
|
__name(truncate2, "truncate");
|
|
43883
44696
|
function printJson(report) {
|
|
@@ -44947,8 +45760,8 @@ var ACCEPTED_TIMEOUT_MS = 12e4;
|
|
|
44947
45760
|
var DEFAULT_LOGS_LIMIT = 20;
|
|
44948
45761
|
function parseLimitOption(raw) {
|
|
44949
45762
|
if (raw === void 0 || raw === null || raw === "") return void 0;
|
|
44950
|
-
const
|
|
44951
|
-
return Number.isFinite(
|
|
45763
|
+
const n2 = Number.parseInt(String(raw), 10);
|
|
45764
|
+
return Number.isFinite(n2) && n2 > 0 ? n2 : void 0;
|
|
44952
45765
|
}
|
|
44953
45766
|
__name(parseLimitOption, "parseLimitOption");
|
|
44954
45767
|
function isLegacyIntegrationAction(action) {
|
|
@@ -46895,6 +47708,12 @@ async function executeAction(ctx, action, target, extra, o) {
|
|
|
46895
47708
|
return requireRun(runId, "jobs", () => jobsCore(ctx, runId, o));
|
|
46896
47709
|
case "job-logs":
|
|
46897
47710
|
return requireRun(runId, "job-logs", () => jobLogsCore(ctx, runId, extra ?? o.step, o));
|
|
47711
|
+
// ── goals <list|get|create|pause|resume|close> (LUA-627 — R57–R62) ──
|
|
47712
|
+
case "goals":
|
|
47713
|
+
return goalsCore(ctx, target, extra, o);
|
|
47714
|
+
// ── schedules <list|delete> (LUA-627 — R4-MF-2 reads, R28 delete; goal-owned rows refuse) ──
|
|
47715
|
+
case "schedules":
|
|
47716
|
+
return schedulesCore(ctx, target, extra, o);
|
|
46898
47717
|
case "run":
|
|
46899
47718
|
return WORKFLOW_EXIT.OK;
|
|
46900
47719
|
}
|
|
@@ -46934,6 +47753,11 @@ function apiFailure(ctx, res, verb) {
|
|
|
46934
47753
|
}
|
|
46935
47754
|
__name(apiFailure, "apiFailure");
|
|
46936
47755
|
async function resolveWorkflow(ctx, nameOrId) {
|
|
47756
|
+
const list = await loadWorkflowList(ctx);
|
|
47757
|
+
return list && pickWorkflow(list, nameOrId);
|
|
47758
|
+
}
|
|
47759
|
+
__name(resolveWorkflow, "resolveWorkflow");
|
|
47760
|
+
async function loadWorkflowList(ctx) {
|
|
46937
47761
|
const res = await ctx.api.getWorkflows({
|
|
46938
47762
|
includeDynamic: true
|
|
46939
47763
|
});
|
|
@@ -46941,15 +47765,19 @@ async function resolveWorkflow(ctx, nameOrId) {
|
|
|
46941
47765
|
console.error(`\u274C Failed to list workflows: ${res.error?.message ?? "Unknown error"}`);
|
|
46942
47766
|
return void 0;
|
|
46943
47767
|
}
|
|
46944
|
-
|
|
47768
|
+
return res.data.workflows;
|
|
47769
|
+
}
|
|
47770
|
+
__name(loadWorkflowList, "loadWorkflowList");
|
|
47771
|
+
function pickWorkflow(list, nameOrId) {
|
|
47772
|
+
const wf = list.find((w) => w.name === nameOrId) ?? list.find((w) => w.id === nameOrId);
|
|
46945
47773
|
if (!wf) {
|
|
46946
47774
|
console.error(`\u274C Workflow "${nameOrId}" not found`);
|
|
46947
|
-
const names =
|
|
47775
|
+
const names = list.map((w) => w.name);
|
|
46948
47776
|
if (names.length) console.log(` Available: ${names.join(", ")}`);
|
|
46949
47777
|
}
|
|
46950
47778
|
return wf;
|
|
46951
47779
|
}
|
|
46952
|
-
__name(
|
|
47780
|
+
__name(pickWorkflow, "pickWorkflow");
|
|
46953
47781
|
var shortHash = /* @__PURE__ */ __name((h) => h ? h.replace(/^sha256-cj1:/, "").slice(0, 12) : "\u2014", "shortHash");
|
|
46954
47782
|
var when = /* @__PURE__ */ __name((iso) => iso ? new Date(iso).toLocaleString() : "\u2014", "when");
|
|
46955
47783
|
var clockOf = /* @__PURE__ */ __name((at) => {
|
|
@@ -46958,9 +47786,9 @@ var clockOf = /* @__PURE__ */ __name((at) => {
|
|
|
46958
47786
|
}, "clockOf");
|
|
46959
47787
|
var parseIntFlag = /* @__PURE__ */ __name((v, flag) => {
|
|
46960
47788
|
if (v === void 0) return void 0;
|
|
46961
|
-
const
|
|
46962
|
-
if (!Number.isFinite(
|
|
46963
|
-
return
|
|
47789
|
+
const n2 = Number(v);
|
|
47790
|
+
if (!Number.isFinite(n2)) throw new WorkflowLocalUsageError("usage", `${flag}: expected a number (got "${v}")`);
|
|
47791
|
+
return n2;
|
|
46964
47792
|
}, "parseIntFlag");
|
|
46965
47793
|
async function listCore(ctx, opts) {
|
|
46966
47794
|
const res = await ctx.api.getWorkflows({
|
|
@@ -46995,9 +47823,27 @@ async function viewCore(ctx, name) {
|
|
|
46995
47823
|
if (!wf) return WORKFLOW_EXIT.NOT_FOUND;
|
|
46996
47824
|
const res = await ctx.api.getWorkflow(wf.id);
|
|
46997
47825
|
if (!res.success || !res.data) return apiFailure(ctx, res, "view");
|
|
46998
|
-
emitJson(ctx, res);
|
|
46999
|
-
if (ctx.json) return WORKFLOW_EXIT.OK;
|
|
47000
47826
|
const w = res.data;
|
|
47827
|
+
const goals = await loadGoals(ctx, w.id);
|
|
47828
|
+
const sched = await loadSchedules(ctx, w.id, goals.items);
|
|
47829
|
+
if (ctx.json) {
|
|
47830
|
+
const data = {
|
|
47831
|
+
...w,
|
|
47832
|
+
schedules: sched.items ?? null,
|
|
47833
|
+
...sched.error ? {
|
|
47834
|
+
schedulesError: sched.error
|
|
47835
|
+
} : {},
|
|
47836
|
+
goals: goals.items ?? null,
|
|
47837
|
+
...goals.error ? {
|
|
47838
|
+
goalsError: goals.error
|
|
47839
|
+
} : {}
|
|
47840
|
+
};
|
|
47841
|
+
console.log(JSON.stringify({
|
|
47842
|
+
...res,
|
|
47843
|
+
data
|
|
47844
|
+
}, null, 2));
|
|
47845
|
+
return WORKFLOW_EXIT.OK;
|
|
47846
|
+
}
|
|
47001
47847
|
console.log(`
|
|
47002
47848
|
\u{1F9ED} ${w.name}${w.description ? ` \u2014 ${w.description}` : ""}`);
|
|
47003
47849
|
console.log(` Id: ${w.id}`);
|
|
@@ -47011,6 +47857,8 @@ async function viewCore(ctx, name) {
|
|
|
47011
47857
|
if (active?.envTemplateKeys?.length) {
|
|
47012
47858
|
console.log(` Env overlay: ${active.envTemplateKeys.join(", ")}${active.envOverlayHash ? ` \xB7 ${active.envOverlayHash}` : ""}`);
|
|
47013
47859
|
}
|
|
47860
|
+
printViewSchedules(sched);
|
|
47861
|
+
printViewGoals(goals);
|
|
47014
47862
|
printVersions(w.versions ?? [], w.activeVersionId);
|
|
47015
47863
|
return WORKFLOW_EXIT.OK;
|
|
47016
47864
|
}
|
|
@@ -47047,24 +47895,41 @@ async function versionsCore(ctx, name) {
|
|
|
47047
47895
|
return WORKFLOW_EXIT.OK;
|
|
47048
47896
|
}
|
|
47049
47897
|
__name(versionsCore, "versionsCore");
|
|
47050
|
-
async function
|
|
47051
|
-
const wf = await resolveWorkflow(ctx, name);
|
|
47052
|
-
if (!wf) return WORKFLOW_EXIT.NOT_FOUND;
|
|
47898
|
+
async function resolveVersionRef(ctx, wf, raw, verb) {
|
|
47053
47899
|
const versionsRes = await ctx.api.getWorkflowVersions(wf.id);
|
|
47054
|
-
if (!versionsRes.success || !versionsRes.data) return
|
|
47900
|
+
if (!versionsRes.success || !versionsRes.data) return {
|
|
47901
|
+
exit: apiFailure(ctx, versionsRes, verb)
|
|
47902
|
+
};
|
|
47055
47903
|
const sorted = [
|
|
47056
47904
|
...versionsRes.data
|
|
47057
47905
|
].sort((a, b) => new Date(b.createdAt).getTime() - new Date(a.createdAt).getTime());
|
|
47058
47906
|
if (sorted.length === 0) {
|
|
47059
47907
|
console.error(`\u274C "${wf.name}" has no versions \u2014 push one first: lua push workflow`);
|
|
47060
|
-
return
|
|
47908
|
+
return {
|
|
47909
|
+
exit: WORKFLOW_EXIT.NOT_FOUND
|
|
47910
|
+
};
|
|
47061
47911
|
}
|
|
47062
|
-
|
|
47063
|
-
|
|
47064
|
-
|
|
47065
|
-
|
|
47066
|
-
|
|
47912
|
+
if (!raw || raw.toLowerCase() === "latest") return {
|
|
47913
|
+
version: sorted[0]
|
|
47914
|
+
};
|
|
47915
|
+
const hit = sorted.find((v) => v.version === raw) ?? sorted.find((v) => v.id === raw);
|
|
47916
|
+
if (!hit) {
|
|
47917
|
+
console.error(`\u274C Version "${raw}" not found. Available: ${sorted.slice(0, 5).map((v) => v.version).join(", ")}`);
|
|
47918
|
+
return {
|
|
47919
|
+
exit: WORKFLOW_EXIT.NOT_FOUND
|
|
47920
|
+
};
|
|
47067
47921
|
}
|
|
47922
|
+
return {
|
|
47923
|
+
version: hit
|
|
47924
|
+
};
|
|
47925
|
+
}
|
|
47926
|
+
__name(resolveVersionRef, "resolveVersionRef");
|
|
47927
|
+
async function deployCore(ctx, name, version) {
|
|
47928
|
+
const wf = await resolveWorkflow(ctx, name);
|
|
47929
|
+
if (!wf) return WORKFLOW_EXIT.NOT_FOUND;
|
|
47930
|
+
const ref = await resolveVersionRef(ctx, wf, version, "deploy");
|
|
47931
|
+
if ("exit" in ref) return ref.exit;
|
|
47932
|
+
const target = ref.version.version;
|
|
47068
47933
|
if (!ctx.json) writeProgress(`\u{1F504} Deploying version ${target} of "${wf.name}"...`);
|
|
47069
47934
|
const res = await ctx.api.publishWorkflowVersion(wf.id, target);
|
|
47070
47935
|
if (!res.success) return apiFailure(ctx, res, "deploy");
|
|
@@ -47131,6 +47996,12 @@ async function startCore(ctx, name, o) {
|
|
|
47131
47996
|
console.error("\u274C --tag: at most 10 tags");
|
|
47132
47997
|
return WORKFLOW_EXIT.USAGE;
|
|
47133
47998
|
}
|
|
47999
|
+
let workflowVersionId;
|
|
48000
|
+
if (o.workflowVersion) {
|
|
48001
|
+
const ref = await resolveVersionRef(ctx, wf, o.workflowVersion, "start");
|
|
48002
|
+
if ("exit" in ref) return ref.exit;
|
|
48003
|
+
workflowVersionId = ref.version.id;
|
|
48004
|
+
}
|
|
47134
48005
|
const res = await ctx.api.startRun({
|
|
47135
48006
|
workflowId: wf.id,
|
|
47136
48007
|
input,
|
|
@@ -47141,7 +48012,7 @@ async function startCore(ctx, name, o) {
|
|
|
47141
48012
|
maxCredits: budgetCredits
|
|
47142
48013
|
} : void 0,
|
|
47143
48014
|
waitSeconds,
|
|
47144
|
-
workflowVersionId
|
|
48015
|
+
workflowVersionId
|
|
47145
48016
|
});
|
|
47146
48017
|
if (!res.success || !res.data) {
|
|
47147
48018
|
if (res.error?.statusCode === 409 && (res.error.code ?? res.error.error) === "RUNS_IN_FLIGHT") {
|
|
@@ -47223,7 +48094,7 @@ async function runsCore(ctx, o) {
|
|
|
47223
48094
|
"Correlation",
|
|
47224
48095
|
"Tags"
|
|
47225
48096
|
], runs.map((r) => [
|
|
47226
|
-
r
|
|
48097
|
+
runIdOf(r),
|
|
47227
48098
|
r.status,
|
|
47228
48099
|
r.trigger,
|
|
47229
48100
|
when(r.createdAt),
|
|
@@ -47236,6 +48107,30 @@ async function runsCore(ctx, o) {
|
|
|
47236
48107
|
return WORKFLOW_EXIT.OK;
|
|
47237
48108
|
}
|
|
47238
48109
|
__name(runsCore, "runsCore");
|
|
48110
|
+
function formatRunConnections(connections, status) {
|
|
48111
|
+
if (!connections) return void 0;
|
|
48112
|
+
const unresolvedWord = status === "completed" ? "not needed" : "unresolved";
|
|
48113
|
+
const declared = connections.declared ?? [];
|
|
48114
|
+
const resolved = connections.resolved ?? [];
|
|
48115
|
+
if (!declared.length && !resolved.length) return void 0;
|
|
48116
|
+
const byKey = new Map(resolved.map((r) => [
|
|
48117
|
+
r.key,
|
|
48118
|
+
r
|
|
48119
|
+
]));
|
|
48120
|
+
const keys = [
|
|
48121
|
+
.../* @__PURE__ */ new Set([
|
|
48122
|
+
...declared.map((d) => d.key),
|
|
48123
|
+
...resolved.map((r) => r.key)
|
|
48124
|
+
])
|
|
48125
|
+
];
|
|
48126
|
+
return keys.map((key) => {
|
|
48127
|
+
const r = byKey.get(key);
|
|
48128
|
+
if (r) return `${key} \u2192 ${r.connectionId} (${r.integrationType}, ${r.scope})`;
|
|
48129
|
+
const d = declared.find((x) => x.key === key);
|
|
48130
|
+
return `${key} \u2192 ${unresolvedWord} (${d?.integrationType ?? "?"})`;
|
|
48131
|
+
}).join(" \xB7 ");
|
|
48132
|
+
}
|
|
48133
|
+
__name(formatRunConnections, "formatRunConnections");
|
|
47239
48134
|
async function statusCore(ctx, runId, o) {
|
|
47240
48135
|
const res = await ctx.api.getRun(runId, o.steps ? {
|
|
47241
48136
|
fields: "full"
|
|
@@ -47249,28 +48144,40 @@ async function statusCore(ctx, runId, o) {
|
|
|
47249
48144
|
}
|
|
47250
48145
|
__name(statusCore, "statusCore");
|
|
47251
48146
|
function printRun(run, withSteps) {
|
|
48147
|
+
const id = runIdOf(run);
|
|
47252
48148
|
console.log(`
|
|
47253
|
-
\u{1F9ED} Run ${
|
|
48149
|
+
\u{1F9ED} Run ${id} \xB7 ${run.status}`);
|
|
47254
48150
|
console.log(` Workflow: ${run.workflowId} @ ${run.workflowVersionId} (${shortHash(run.graphHash)})`);
|
|
47255
48151
|
console.log(` Trigger: ${run.trigger}${run.correlationKey ? ` \xB7 correlation ${run.correlationKey}` : ""}${run.tags?.length ? ` \xB7 tags ${run.tags.join(",")}` : ""}`);
|
|
47256
48152
|
console.log(` Created: ${when(run.createdAt)}${run.startedAt ? ` \xB7 started ${when(run.startedAt)}` : ""}${run.completedAt ? ` \xB7 completed ${when(run.completedAt)}` : ""}`);
|
|
47257
|
-
if (run.lineageId && run.lineageId !==
|
|
48153
|
+
if (run.lineageId && run.lineageId !== id) console.log(` Lineage: ${run.lineageId}`);
|
|
47258
48154
|
if (run.gate) {
|
|
47259
48155
|
const kind = run.gate.kind;
|
|
47260
48156
|
if (kind === "exception") {
|
|
47261
48157
|
console.log("\n\u26A0\uFE0F Needs a decision \u2014 the run is parked on an exception gate:");
|
|
47262
|
-
console.log(` lua workflows retry-step ${
|
|
48158
|
+
console.log(` lua workflows retry-step ${id} --step <id> \xB7 resolve-step ${id} --step <id> --outcome skip|complete|fail \xB7 repair ${id}`);
|
|
47263
48159
|
} else if (kind === "budget") {
|
|
47264
48160
|
console.log("\n\u23F8\uFE0F Paused \u2014 run budget reached:");
|
|
47265
|
-
console.log(` lua workflows raise-budget ${
|
|
48161
|
+
console.log(` lua workflows raise-budget ${id} --credits <n>`);
|
|
47266
48162
|
} else {
|
|
47267
48163
|
console.log(` Gate: ${kind}${run.gate.reason ? ` (${run.gate.reason})` : ""}${run.gate.since ? ` since ${when(run.gate.since)}` : ""}`);
|
|
47268
48164
|
}
|
|
47269
48165
|
}
|
|
47270
48166
|
if (run.failureReason) console.log(` Failure: ${run.failureReason}`);
|
|
47271
|
-
|
|
47272
|
-
|
|
48167
|
+
const connectionsLine = formatRunConnections(run.connections, run.status);
|
|
48168
|
+
if (connectionsLine) console.log(` Connections: ${connectionsLine}`);
|
|
47273
48169
|
const steps = run.steps;
|
|
48170
|
+
if (run.restricted) console.log(" Outputs: restricted (outputVisibility) \u2014 output not returned");
|
|
48171
|
+
else if (run.output !== void 0 && run.output !== null) {
|
|
48172
|
+
const text = typeof run.outputPreview === "string" ? `${run.outputPreview} (offloaded \u2014 preview)` : JSON.stringify(run.output).slice(0, 2e3);
|
|
48173
|
+
console.log(` Output: ${text}`);
|
|
48174
|
+
} else if (run.hasOutput) {
|
|
48175
|
+
console.log(` Output: present \u2014 lua workflows status ${run.id} --steps`);
|
|
48176
|
+
} else if (RUN_TERMINAL_STATUSES.has(run.status)) {
|
|
48177
|
+
const last = lastCompletedPreview(steps);
|
|
48178
|
+
console.log(` Output: (none${last ? "" : withSteps ? "" : " \u2014 pass --steps for per-step output previews"})`);
|
|
48179
|
+
if (last) console.log(` Last step output (preview): ${last.stepId} \u2192 ${JSON.stringify(last.output).slice(0, 2e3)}`);
|
|
48180
|
+
}
|
|
47274
48181
|
if (withSteps) {
|
|
47275
48182
|
if (!steps?.length) console.log("\n (no step rows in the response)");
|
|
47276
48183
|
else {
|
|
@@ -47286,12 +48193,69 @@ function printRun(run, withSteps) {
|
|
|
47286
48193
|
s.kind ?? "\u2014",
|
|
47287
48194
|
s.status,
|
|
47288
48195
|
String(s.attempt ?? ""),
|
|
47289
|
-
s.error
|
|
48196
|
+
stepErrorCell(s.error)
|
|
47290
48197
|
])));
|
|
48198
|
+
for (const s of steps) {
|
|
48199
|
+
const cause = stepFailureLine(s.error);
|
|
48200
|
+
if (cause) console.log(` \u2716 ${s.stepId}: ${cause}`);
|
|
48201
|
+
for (const a of s.attempts ?? []) {
|
|
48202
|
+
if (a.status === "completed") continue;
|
|
48203
|
+
const what = stepErrorCell(a.error) || a.killReason || "\u2014";
|
|
48204
|
+
console.log(` \u21BA ${s.stepId}: attempt ${a.attempt} ${a.status}: ${what}${priorAttemptTail(a)}`);
|
|
48205
|
+
}
|
|
48206
|
+
}
|
|
47291
48207
|
}
|
|
47292
48208
|
}
|
|
47293
48209
|
}
|
|
47294
48210
|
__name(printRun, "printRun");
|
|
48211
|
+
var RUN_TERMINAL_STATUSES = /* @__PURE__ */ new Set([
|
|
48212
|
+
"completed",
|
|
48213
|
+
"failed",
|
|
48214
|
+
"cancelled",
|
|
48215
|
+
"abandoned",
|
|
48216
|
+
"timed_out"
|
|
48217
|
+
]);
|
|
48218
|
+
function lastCompletedPreview(steps) {
|
|
48219
|
+
if (!steps?.length) return void 0;
|
|
48220
|
+
let best;
|
|
48221
|
+
for (const s of steps) {
|
|
48222
|
+
if (s.status !== "completed" || s.preview?.output === void 0) continue;
|
|
48223
|
+
if (!best || (s.completedAt ?? 0) >= (best.completedAt ?? 0)) best = s;
|
|
48224
|
+
}
|
|
48225
|
+
return best ? {
|
|
48226
|
+
stepId: best.stepId,
|
|
48227
|
+
output: best.preview.output
|
|
48228
|
+
} : void 0;
|
|
48229
|
+
}
|
|
48230
|
+
__name(lastCompletedPreview, "lastCompletedPreview");
|
|
48231
|
+
function stepErrorCell(e) {
|
|
48232
|
+
if (!e?.code) return "";
|
|
48233
|
+
return e.reason ? `${e.code} (${e.reason})` : e.code;
|
|
48234
|
+
}
|
|
48235
|
+
__name(stepErrorCell, "stepErrorCell");
|
|
48236
|
+
function priorAttemptTail(a) {
|
|
48237
|
+
const e = a.error;
|
|
48238
|
+
const parts = [
|
|
48239
|
+
e?.providerStatus !== void 0 ? `HTTP ${e.providerStatus}` : void 0,
|
|
48240
|
+
a.podName ? `pod ${a.podName}` : void 0
|
|
48241
|
+
].filter((p) => !!p);
|
|
48242
|
+
return `${parts.length ? ` \u2014 ${parts.join(" \xB7 ")}` : ""}${e?.providerMessage ? ` \u2014 ${e.providerMessage}` : ""}`;
|
|
48243
|
+
}
|
|
48244
|
+
__name(priorAttemptTail, "priorAttemptTail");
|
|
48245
|
+
function stepFailureLine(e) {
|
|
48246
|
+
if (!e || !e.reason && e.providerStatus === void 0 && !e.providerMessage) return void 0;
|
|
48247
|
+
const b = e.budget;
|
|
48248
|
+
const parts = [
|
|
48249
|
+
e.reason,
|
|
48250
|
+
e.providerStatus !== void 0 ? `HTTP ${e.providerStatus}` : void 0,
|
|
48251
|
+
e.model ? `model ${e.model}` : void 0,
|
|
48252
|
+
e.turnIndex !== void 0 ? `message ${e.turnIndex}${e.assistantTurns !== void 0 ? ` (${e.assistantTurns} replies)` : ""}${b?.maxMessages !== void 0 ? ` of ${b.maxMessages}` : ""}` : void 0,
|
|
48253
|
+
b ? `${b.inputTokens.toLocaleString("en-US")}${b.maxInputTokens !== void 0 ? ` of ${b.maxInputTokens.toLocaleString("en-US")}` : ""} input tokens` : void 0,
|
|
48254
|
+
e.providerRetries ? `${e.providerRetries} provider ${e.providerRetries === 1 ? "retry" : "retries"}` : void 0
|
|
48255
|
+
].filter((p) => !!p);
|
|
48256
|
+
return `${parts.join(" \xB7 ")}${e.providerMessage ? `${parts.length ? " \u2014 " : ""}${e.providerMessage}` : ""}`;
|
|
48257
|
+
}
|
|
48258
|
+
__name(stepFailureLine, "stepFailureLine");
|
|
47295
48259
|
async function watchCore(ctx, runId, o) {
|
|
47296
48260
|
let afterSeq;
|
|
47297
48261
|
let timeoutS;
|
|
@@ -47342,6 +48306,8 @@ async function watchCore(ctx, runId, o) {
|
|
|
47342
48306
|
if (!ctx.json) console.error(`\u2026 reconnecting (Last-Event-ID ${lastEventId ?? "none"})`);
|
|
47343
48307
|
await new Promise((r) => setTimeout(r, Math.min(5e3, 250 * 2 ** reconnects)));
|
|
47344
48308
|
}
|
|
48309
|
+
} catch (e) {
|
|
48310
|
+
if (!controller.signal.aborted) throw e;
|
|
47345
48311
|
} finally {
|
|
47346
48312
|
if (timer) clearTimeout(timer);
|
|
47347
48313
|
process.off("SIGINT", onSigint);
|
|
@@ -47384,7 +48350,7 @@ function handleWatchFrame(ctx, runId, frame, o, throttled) {
|
|
|
47384
48350
|
throttled.set(kind, (throttled.get(kind) ?? 0) + 1);
|
|
47385
48351
|
if (!ctx.json && !o.events) process.stdout.write(`\r throttled \xB7 ${[
|
|
47386
48352
|
...throttled
|
|
47387
|
-
].map(([k,
|
|
48353
|
+
].map(([k, n2]) => `${k} \xD7${n2}`).join(" \xB7 ")}`);
|
|
47388
48354
|
return void 0;
|
|
47389
48355
|
}
|
|
47390
48356
|
if (!ctx.json && !o.events) {
|
|
@@ -47455,13 +48421,28 @@ async function resumeCore(ctx, runId, o) {
|
|
|
47455
48421
|
const res = await ctx.api.resumeRun(runId, o.step, {
|
|
47456
48422
|
resumeData
|
|
47457
48423
|
});
|
|
48424
|
+
const resumeCode = !res.success ? res.error?.code ?? res.error?.error : void 0;
|
|
48425
|
+
const resumeDetail = res.error;
|
|
48426
|
+
if (!ctx.json && res.error?.statusCode === 400 && resumeCode === "RESUME_SCHEMA_INVALID") {
|
|
48427
|
+
console.error(`\u274C resume rejected \u2014 --data does not match the resumeSchema step "${resumeDetail?.stepId ?? o.step}" declares:`);
|
|
48428
|
+
for (const issue of resumeDetail?.issues ?? []) console.error(` \u2022 ${issue.path || "/"}: ${issue.message ?? "invalid"}`);
|
|
48429
|
+
console.error(" fix the data and resume again (the step is still waiting for input)");
|
|
48430
|
+
} else if (!ctx.json && res.error?.statusCode === 422 && resumeCode === "RESUME_SCHEMA_UNCOMPILABLE") {
|
|
48431
|
+
console.error(`\u274C resume could not be checked \u2014 the resumeSchema step "${resumeDetail?.stepId ?? o.step}" declares does not compile:`);
|
|
48432
|
+
for (const issue of resumeDetail?.issues ?? []) console.error(` \u2022 ${issue.message ?? "schema does not compile"}`);
|
|
48433
|
+
console.error(" this is a workflow definition defect, not a data problem \u2014 fix the `resumeSchema` on the step in the workflow source, push a new version, then resume again");
|
|
48434
|
+
}
|
|
47458
48435
|
if (!res.success || !res.data) {
|
|
47459
|
-
|
|
47460
|
-
|
|
48436
|
+
const code = res.error?.code ?? res.error?.error;
|
|
48437
|
+
if (!ctx.json && res.error?.statusCode === 404 && code === "STEP_NOT_FOUND") {
|
|
48438
|
+
console.error(`\u274C step "${o.step}" does not exist on run ${runId} \u2014 list its steps: lua workflows status ${runId} --steps`);
|
|
48439
|
+
} else if (!ctx.json && res.error?.statusCode === 409) {
|
|
47461
48440
|
if (code === "approval_requires_human" || code === "APPROVAL_REQUIRES_HUMAN") {
|
|
47462
48441
|
console.error(`\u274C step "${o.step}" is an approval \u2014 resolve it with: lua workflows approve ${runId} --approval ${o.step} --decision approve`);
|
|
47463
48442
|
} else if (code === "use_signal_route" || code === "USE_SIGNAL_ROUTE") {
|
|
47464
48443
|
console.error(`\u274C step "${o.step}" waits for a signal \u2014 deliver it with: lua workflows signal ${runId} <name> --payload '{}'`);
|
|
48444
|
+
} else if (code === "NOT_SUSPENDED") {
|
|
48445
|
+
console.error(`\u274C step "${o.step}" is not suspended${res.error?.status ? ` (it is ${res.error.status})` : ""} \u2014 nothing to resume: lua workflows status ${runId} --steps`);
|
|
47465
48446
|
}
|
|
47466
48447
|
}
|
|
47467
48448
|
return apiFailure(ctx, res, "resume");
|
|
@@ -47526,7 +48507,9 @@ async function approveCore(ctx, runId, o) {
|
|
|
47526
48507
|
});
|
|
47527
48508
|
if (!res.success || !res.data) {
|
|
47528
48509
|
const code = res.error?.code ?? res.error?.error;
|
|
47529
|
-
if (!ctx.json && res.error?.statusCode ===
|
|
48510
|
+
if (!ctx.json && res.error?.statusCode === 404 && code === "APPROVAL_NOT_FOUND") {
|
|
48511
|
+
console.error(`\u274C approval "${o.approval}" not found on run ${runId} \u2014 pass the pending approval's wfa_\u2026 id: lua workflows status ${runId} --steps --json shows it as the suspended step's suspend.approvalId`);
|
|
48512
|
+
} else if (!ctx.json && res.error?.statusCode === 409 && code === "PAYLOAD_MISMATCH") {
|
|
47530
48513
|
console.error(`\u274C the payload changed since you looked \u2014 refetch: lua workflows approval-payload ${runId} --approval ${o.approval}`);
|
|
47531
48514
|
} else if (!ctx.json && res.error?.statusCode === 403 && code === "STEP_UP_REQUIRED") {
|
|
47532
48515
|
console.error("\u274C approve from the desktop with a fresh login (step-up required)");
|
|
@@ -47557,7 +48540,25 @@ async function signalCore(ctx, runId, name, o) {
|
|
|
47557
48540
|
payload,
|
|
47558
48541
|
dedupeKey: o.dedupeKey
|
|
47559
48542
|
});
|
|
47560
|
-
if (!res.success || !res.data)
|
|
48543
|
+
if (!res.success || !res.data) {
|
|
48544
|
+
const code = res.error?.code ?? res.error?.error;
|
|
48545
|
+
if (!ctx.json && res.error?.statusCode === 400 && code === "SIGNAL_SCHEMA_INVALID") {
|
|
48546
|
+
const where = res.error?.stepId ? `step "${res.error.stepId}"` : "the waiting step";
|
|
48547
|
+
console.error(`\u274C signal "${name}" rejected \u2014 the payload does not match the schema ${where} declares:`);
|
|
48548
|
+
for (const issue of res.error?.issues ?? []) {
|
|
48549
|
+
console.error(` \u2022 ${issue.path || "/"}: ${issue.message ?? "invalid"}`);
|
|
48550
|
+
}
|
|
48551
|
+
console.error(" fix the payload and send it again (a --dedupe-key is not consumed by a rejected signal)");
|
|
48552
|
+
} else if (!ctx.json && res.error?.statusCode === 422 && code === "SIGNAL_SCHEMA_UNCOMPILABLE") {
|
|
48553
|
+
const where = res.error?.stepId ? `step "${res.error.stepId}"` : "the waiting step";
|
|
48554
|
+
console.error(`\u274C signal "${name}" could not be checked \u2014 the schema ${where} declares does not compile:`);
|
|
48555
|
+
for (const issue of res.error?.issues ?? []) {
|
|
48556
|
+
console.error(` \u2022 ${issue.message ?? "schema does not compile"}`);
|
|
48557
|
+
}
|
|
48558
|
+
console.error(` this is a workflow definition defect, not a payload problem \u2014 fix the \`schema\` on the waitForSignal node in the workflow source, push a new version, then send the signal again`);
|
|
48559
|
+
}
|
|
48560
|
+
return apiFailure(ctx, res, "signal");
|
|
48561
|
+
}
|
|
47561
48562
|
emitJson(ctx, res);
|
|
47562
48563
|
const r = res.data;
|
|
47563
48564
|
if (!ctx.json) {
|
|
@@ -47623,10 +48624,25 @@ async function replayCore(ctx, runId, o) {
|
|
|
47623
48624
|
const rows3 = [];
|
|
47624
48625
|
for (const stepId of plan.order) {
|
|
47625
48626
|
const step3 = await ctx.api.getRunStep(runId, stepId);
|
|
47626
|
-
if (step3.success
|
|
48627
|
+
if (!step3.success || !step3.data) continue;
|
|
48628
|
+
const error = step3.data.error;
|
|
48629
|
+
const onError = plan.steps[stepId]?.entry?.onError;
|
|
48630
|
+
rows3.push({
|
|
47627
48631
|
stepId,
|
|
47628
48632
|
status: step3.data.status,
|
|
47629
|
-
output: step3.data.output
|
|
48633
|
+
output: step3.data.output,
|
|
48634
|
+
...onError ? {
|
|
48635
|
+
onError
|
|
48636
|
+
} : {},
|
|
48637
|
+
...error ? {
|
|
48638
|
+
error: {
|
|
48639
|
+
code: error.code,
|
|
48640
|
+
message: error.message
|
|
48641
|
+
}
|
|
48642
|
+
} : {},
|
|
48643
|
+
...error?.killReason ? {
|
|
48644
|
+
killReason: error.killReason
|
|
48645
|
+
} : {}
|
|
47630
48646
|
});
|
|
47631
48647
|
}
|
|
47632
48648
|
const result = replayLedger(wf.graph, {
|
|
@@ -47770,9 +48786,9 @@ function parseSinceFlag(raw, now = Date.now()) {
|
|
|
47770
48786
|
if (!raw) return NaN;
|
|
47771
48787
|
const m = /^(\d+)([dhm])$/i.exec(raw.trim());
|
|
47772
48788
|
if (m) {
|
|
47773
|
-
const
|
|
48789
|
+
const n2 = Number(m[1]);
|
|
47774
48790
|
const unit = m[2].toLowerCase();
|
|
47775
|
-
return now -
|
|
48791
|
+
return now - n2 * (unit === "d" ? 864e5 : unit === "h" ? 36e5 : 6e4);
|
|
47776
48792
|
}
|
|
47777
48793
|
return Date.parse(raw);
|
|
47778
48794
|
}
|
|
@@ -47875,7 +48891,11 @@ async function archiveRunsCore(ctx, o) {
|
|
|
47875
48891
|
}, "say");
|
|
47876
48892
|
const sha256 = /* @__PURE__ */ __name((buf) => crypto5.createHash("sha256").update(buf).digest("hex"), "sha256");
|
|
47877
48893
|
const sleep3 = /* @__PURE__ */ __name((ms) => new Promise((r) => setTimeout(r, ms)), "sleep");
|
|
47878
|
-
const archiveOne = /* @__PURE__ */ __name(async (
|
|
48894
|
+
const archiveOne = /* @__PURE__ */ __name(async (apiRow) => {
|
|
48895
|
+
const run = {
|
|
48896
|
+
...apiRow,
|
|
48897
|
+
id: runIdOf(apiRow)
|
|
48898
|
+
};
|
|
47879
48899
|
const zipFile = path23.join(o.out, `${run.id}.zip`);
|
|
47880
48900
|
const prior = indexed.get(run.id);
|
|
47881
48901
|
const completedAt = run.completedAt ? Date.parse(run.completedAt) : NaN;
|
|
@@ -48128,6 +49148,9 @@ function printJobHeader(v) {
|
|
|
48128
49148
|
\u{1F6E0} ${v.runId} \xB7 ${v.stepId} \xB7 attempt ${v.attempt} \xB7 ${v.status} \xB7 ${v.phase}${v.jobName ? ` \xB7 ${v.jobName}` : ""}${v.sizeClass ? ` (${v.sizeClass})` : ""}`);
|
|
48129
49149
|
console.log(` Segment ${v.segment} of ${v.segmentsTotalMax}${v.checkpoint ? ` \xB7 resumed from the ${Math.round(v.checkpoint.elapsedSeconds / 60)} min checkpoint` : ""}${v.harness ? ` \xB7 ${v.harness}` : ""}${v.podName ? ` \xB7 pod ${v.podName}` : ""}${v.heartbeatAt ? ` \xB7 heartbeat ${ago(v.heartbeatAt)}` : ""}`);
|
|
48130
49150
|
if (v.error) console.log(` Error: ${v.error.code}${v.error.killReason ? ` (${v.error.killReason})` : ""} \u2014 ${v.error.message}`);
|
|
49151
|
+
const cause = stepFailureLine(v.error);
|
|
49152
|
+
if (cause) console.log(` Cause: ${cause}`);
|
|
49153
|
+
if (v.note) console.log(` Note: ${v.note}`);
|
|
48131
49154
|
console.log(` Logs (${v.logsSource}${v.logs.length ? `, ${v.logs.length} lines` : ""}):`);
|
|
48132
49155
|
}
|
|
48133
49156
|
__name(printJobHeader, "printJobHeader");
|
|
@@ -48153,6 +49176,14 @@ async function jobLogsCore(ctx, runId, stepId, o) {
|
|
|
48153
49176
|
if (res.error?.statusCode === 404 && res.error?.code === "JOB_NOT_FOUND" && !ctx.json) {
|
|
48154
49177
|
console.error(`\u274C ${stepId} is not a Job-tier step of ${runId} (try: lua workflows jobs ${runId})`);
|
|
48155
49178
|
}
|
|
49179
|
+
if (res.error?.statusCode === 404 && res.error?.code === "JOB_LOGS_NOT_PERSISTED") {
|
|
49180
|
+
emitJson(ctx, res);
|
|
49181
|
+
if (!ctx.json) {
|
|
49182
|
+
console.error(`\u274C job-logs: ${res.error.message}`);
|
|
49183
|
+
writeInfo(` lua workflows status ${runId} --steps shows the step error; --attempt <n> reads another attempt.`);
|
|
49184
|
+
}
|
|
49185
|
+
return WORKFLOW_EXIT.NOT_FOUND;
|
|
49186
|
+
}
|
|
48156
49187
|
return apiFailure(ctx, res, "job-logs");
|
|
48157
49188
|
}
|
|
48158
49189
|
const v = res.data;
|
|
@@ -48167,7 +49198,7 @@ async function jobLogsCore(ctx, runId, stepId, o) {
|
|
|
48167
49198
|
for (const line of v.logs.slice(printed)) console.log(` ${line}`);
|
|
48168
49199
|
printed = Math.max(printed, v.logs.length);
|
|
48169
49200
|
const terminal = TERMINAL2.has(v.status) || /^(completed|failed|cancelled|skipped|reaped|deleted)$/.test(v.status);
|
|
48170
|
-
if (!o.follow || terminal || v.phase === "deleted") {
|
|
49201
|
+
if (!o.follow || terminal || v.attemptFinished || v.phase === "deleted") {
|
|
48171
49202
|
if (o.follow && !ctx.json) writeInfo(` \u2014 ${v.status} (${v.phase})`);
|
|
48172
49203
|
return WORKFLOW_EXIT.OK;
|
|
48173
49204
|
}
|
|
@@ -48175,6 +49206,659 @@ async function jobLogsCore(ctx, runId, stepId, o) {
|
|
|
48175
49206
|
}
|
|
48176
49207
|
}
|
|
48177
49208
|
__name(jobLogsCore, "jobLogsCore");
|
|
49209
|
+
var GOAL_VERBS = [
|
|
49210
|
+
"list",
|
|
49211
|
+
"get",
|
|
49212
|
+
"create",
|
|
49213
|
+
"pause",
|
|
49214
|
+
"resume",
|
|
49215
|
+
"close"
|
|
49216
|
+
];
|
|
49217
|
+
var SCHEDULE_VERBS = [
|
|
49218
|
+
"list",
|
|
49219
|
+
"delete"
|
|
49220
|
+
];
|
|
49221
|
+
var GOAL_STATUSES = [
|
|
49222
|
+
"active",
|
|
49223
|
+
"paused",
|
|
49224
|
+
"done",
|
|
49225
|
+
"closed"
|
|
49226
|
+
];
|
|
49227
|
+
var GOAL_PREDICATE_OPS = [
|
|
49228
|
+
"exists",
|
|
49229
|
+
"truthy",
|
|
49230
|
+
"eq",
|
|
49231
|
+
"neq",
|
|
49232
|
+
"gt",
|
|
49233
|
+
"gte",
|
|
49234
|
+
"lt",
|
|
49235
|
+
"lte"
|
|
49236
|
+
];
|
|
49237
|
+
var GOAL_CADENCE_MAX = 5;
|
|
49238
|
+
var GOAL_MAX_RUNS_CAP = 100;
|
|
49239
|
+
var GOAL_PAGE_LIMIT = 100;
|
|
49240
|
+
var GOAL_PAGE_MAX = 50;
|
|
49241
|
+
function parseIntegerFlag(v, flag, range2 = {}) {
|
|
49242
|
+
if (v === void 0) return void 0;
|
|
49243
|
+
const text = String(v).trim();
|
|
49244
|
+
if (!/^-?\d+$/.test(text)) throw new WorkflowLocalUsageError("usage", `${flag}: expected an integer (got "${v}")`);
|
|
49245
|
+
const n2 = Number(text);
|
|
49246
|
+
const { min, max } = range2;
|
|
49247
|
+
if (min !== void 0 && n2 < min || max !== void 0 && n2 > max) {
|
|
49248
|
+
const bounds = max !== void 0 ? `${min ?? ""}..${max}` : `\u2265 ${min}`;
|
|
49249
|
+
throw new WorkflowLocalUsageError("usage", `${flag}: expected an integer ${bounds} (got "${v}")`);
|
|
49250
|
+
}
|
|
49251
|
+
return n2;
|
|
49252
|
+
}
|
|
49253
|
+
__name(parseIntegerFlag, "parseIntegerFlag");
|
|
49254
|
+
function goalScheduleRefusal(jobId, goalId) {
|
|
49255
|
+
return `Schedule ${jobId} is the cadence of goal ${goalId} and was NOT removed \u2014 nothing was changed. To stop the goal use \`lua workflows goals pause ${goalId}\` (it can come back) or \`lua workflows goals close ${goalId}\` (final); unscheduling a goal's job is recorded as a failure of the goal, never as stopping it.`;
|
|
49256
|
+
}
|
|
49257
|
+
__name(goalScheduleRefusal, "goalScheduleRefusal");
|
|
49258
|
+
function triggerLabel(t) {
|
|
49259
|
+
if (!t || typeof t !== "object") return "\u2014";
|
|
49260
|
+
if (t.type === "cron") return `cron ${t.expression ?? "?"}${t.timezone ? ` (${t.timezone})` : ""}`;
|
|
49261
|
+
if (t.type === "interval") return `every ${t.seconds ?? "?"}s`;
|
|
49262
|
+
if (t.type === "once") return `once ${t.executeAt ?? "?"}`;
|
|
49263
|
+
return String(t.type ?? "?");
|
|
49264
|
+
}
|
|
49265
|
+
__name(triggerLabel, "triggerLabel");
|
|
49266
|
+
var cadenceLabel = /* @__PURE__ */ __name((cadence) => cadence?.length ? cadence.map((c) => triggerLabel(c)).join(" \xB7 ") : "immediate", "cadenceLabel");
|
|
49267
|
+
var judgeLabel = /* @__PURE__ */ __name((judge) => {
|
|
49268
|
+
if (!judge) return "\u2014";
|
|
49269
|
+
if (judge.predicate) {
|
|
49270
|
+
const p = judge.predicate;
|
|
49271
|
+
return `predicate ${p.path} ${p.op}${p.value !== void 0 ? ` ${JSON.stringify(p.value)}` : ""}`;
|
|
49272
|
+
}
|
|
49273
|
+
return `agent ${judge.agentId ?? "?"}${judge.role?.name ? ` (${judge.role.name})` : ""}${judge.schema ? " \xB7 schema" : ""}`;
|
|
49274
|
+
}, "judgeLabel");
|
|
49275
|
+
var goalStatusLabel = /* @__PURE__ */ __name((g) => `${g.status}${g.pauseReason ? ` (${g.pauseReason})` : ""}`, "goalStatusLabel");
|
|
49276
|
+
var verdictLabel = /* @__PURE__ */ __name((v) => v ? `${v.done ? "done" : "continue"}${v.summary ? ` \xB7 ${v.summary.slice(0, 60)}` : ""}` : "\u2014", "verdictLabel");
|
|
49277
|
+
var scheduleStatus = /* @__PURE__ */ __name((r) => r.autoDisabled ? "auto-disabled" : r.paused ? "paused" : "active", "scheduleStatus");
|
|
49278
|
+
var errorLabel = /* @__PURE__ */ __name((e) => `${e.code ?? e.error ?? e.statusCode ?? "?"} \u2014 ${e.message}`, "errorLabel");
|
|
49279
|
+
async function loadGoals(ctx, workflowId) {
|
|
49280
|
+
const items = [];
|
|
49281
|
+
let cursor;
|
|
49282
|
+
for (let page = 0; page < GOAL_PAGE_MAX; page++) {
|
|
49283
|
+
const res = await ctx.api.getGoals({
|
|
49284
|
+
workflowId,
|
|
49285
|
+
cursor,
|
|
49286
|
+
limit: GOAL_PAGE_LIMIT
|
|
49287
|
+
});
|
|
49288
|
+
if (!res.success || !res.data) return {
|
|
49289
|
+
error: res.error ?? {
|
|
49290
|
+
message: "goals unavailable"
|
|
49291
|
+
}
|
|
49292
|
+
};
|
|
49293
|
+
items.push(...res.data.items ?? []);
|
|
49294
|
+
cursor = res.data.nextCursor;
|
|
49295
|
+
if (!cursor) break;
|
|
49296
|
+
}
|
|
49297
|
+
if (cursor) return {
|
|
49298
|
+
error: {
|
|
49299
|
+
code: "GOAL_LIST_TRUNCATED",
|
|
49300
|
+
message: "goal list truncated; ownership cannot be proven"
|
|
49301
|
+
}
|
|
49302
|
+
};
|
|
49303
|
+
return {
|
|
49304
|
+
items
|
|
49305
|
+
};
|
|
49306
|
+
}
|
|
49307
|
+
__name(loadGoals, "loadGoals");
|
|
49308
|
+
async function loadSchedules(ctx, workflowId, goals) {
|
|
49309
|
+
const res = await ctx.api.listSchedules();
|
|
49310
|
+
if (!res.success || !res.data) return {
|
|
49311
|
+
error: res.error ?? {
|
|
49312
|
+
message: "schedules unavailable"
|
|
49313
|
+
}
|
|
49314
|
+
};
|
|
49315
|
+
const byJob = /* @__PURE__ */ new Map();
|
|
49316
|
+
for (const g of goals ?? []) if (g.jobId) byJob.set(g.jobId, g.goalId);
|
|
49317
|
+
const items = (res.data.items ?? []).filter((r) => !workflowId || r.workflowId === workflowId).map((r) => {
|
|
49318
|
+
const goalId = r.goalId ?? byJob.get(r.jobId);
|
|
49319
|
+
return goalId ? {
|
|
49320
|
+
...r,
|
|
49321
|
+
goalId
|
|
49322
|
+
} : r;
|
|
49323
|
+
});
|
|
49324
|
+
return {
|
|
49325
|
+
items
|
|
49326
|
+
};
|
|
49327
|
+
}
|
|
49328
|
+
__name(loadSchedules, "loadSchedules");
|
|
49329
|
+
function printSchedules(items, names) {
|
|
49330
|
+
if (!items.length) {
|
|
49331
|
+
console.log(" (no schedules)");
|
|
49332
|
+
return;
|
|
49333
|
+
}
|
|
49334
|
+
console.log(renderTable([
|
|
49335
|
+
"Job",
|
|
49336
|
+
"Workflow",
|
|
49337
|
+
"Trigger",
|
|
49338
|
+
"Next",
|
|
49339
|
+
"Last fired",
|
|
49340
|
+
"Status",
|
|
49341
|
+
"Strikes",
|
|
49342
|
+
"Goal"
|
|
49343
|
+
], items.map((r) => [
|
|
49344
|
+
r.jobId,
|
|
49345
|
+
names?.get(r.workflowId) ?? r.workflowId,
|
|
49346
|
+
(r.trigger ?? []).map(triggerLabel).join(" \xB7 ") || "\u2014",
|
|
49347
|
+
when(r.nextRunAt ?? void 0),
|
|
49348
|
+
when(r.lastFiredAt),
|
|
49349
|
+
scheduleStatus(r),
|
|
49350
|
+
String(r.consecutiveFailures ?? 0),
|
|
49351
|
+
r.goalId ?? "\u2014"
|
|
49352
|
+
])));
|
|
49353
|
+
const owned = items.filter((r) => r.goalId).length;
|
|
49354
|
+
if (owned) writeInfo(`\u{1F4A1} ${owned} goal-owned schedule(s) \u2014 stop those with lua workflows goals pause|close <goalId>, never schedules delete`);
|
|
49355
|
+
}
|
|
49356
|
+
__name(printSchedules, "printSchedules");
|
|
49357
|
+
function printGoals(items, names) {
|
|
49358
|
+
if (!items.length) {
|
|
49359
|
+
console.log(" (no goals)");
|
|
49360
|
+
return;
|
|
49361
|
+
}
|
|
49362
|
+
const head = [
|
|
49363
|
+
"Goal",
|
|
49364
|
+
...names ? [
|
|
49365
|
+
"Workflow"
|
|
49366
|
+
] : [],
|
|
49367
|
+
"Status",
|
|
49368
|
+
"Runs",
|
|
49369
|
+
"Iter",
|
|
49370
|
+
"Judge",
|
|
49371
|
+
"Cadence",
|
|
49372
|
+
"Verdict",
|
|
49373
|
+
"Updated"
|
|
49374
|
+
];
|
|
49375
|
+
console.log(renderTable(head, items.map((g) => [
|
|
49376
|
+
g.goalId,
|
|
49377
|
+
...names ? [
|
|
49378
|
+
names.get(g.workflowId) ?? g.workflowId
|
|
49379
|
+
] : [],
|
|
49380
|
+
goalStatusLabel(g),
|
|
49381
|
+
`${g.runsUsed}/${g.maxRuns}`,
|
|
49382
|
+
String(g.iteration ?? 0),
|
|
49383
|
+
judgeLabel(g.judge),
|
|
49384
|
+
cadenceLabel(g.cadence),
|
|
49385
|
+
verdictLabel(g.verdict),
|
|
49386
|
+
when(g.updatedAt)
|
|
49387
|
+
])));
|
|
49388
|
+
}
|
|
49389
|
+
__name(printGoals, "printGoals");
|
|
49390
|
+
function printViewSchedules(sched) {
|
|
49391
|
+
if (sched.error) {
|
|
49392
|
+
console.log(` Schedules: unavailable (${errorLabel(sched.error)})`);
|
|
49393
|
+
return;
|
|
49394
|
+
}
|
|
49395
|
+
const owned = sched.items.filter((r) => r.goalId).length;
|
|
49396
|
+
console.log(` Schedules: ${sched.items.length ? `${sched.items.length}${owned ? ` (${owned} goal-owned)` : ""}` : "none"}`);
|
|
49397
|
+
if (sched.items.length) {
|
|
49398
|
+
console.log("");
|
|
49399
|
+
printSchedules(sched.items);
|
|
49400
|
+
}
|
|
49401
|
+
}
|
|
49402
|
+
__name(printViewSchedules, "printViewSchedules");
|
|
49403
|
+
function printViewGoals(goals) {
|
|
49404
|
+
if (goals.error) {
|
|
49405
|
+
console.log(` Goals: unavailable (${errorLabel(goals.error)})`);
|
|
49406
|
+
return;
|
|
49407
|
+
}
|
|
49408
|
+
const counts = /* @__PURE__ */ new Map();
|
|
49409
|
+
for (const g of goals.items) counts.set(g.status, (counts.get(g.status) ?? 0) + 1);
|
|
49410
|
+
const summary = goals.items.length ? `${goals.items.length} (${[
|
|
49411
|
+
...counts
|
|
49412
|
+
].map(([s, n2]) => `${n2} ${s}`).join(" \xB7 ")})` : "none";
|
|
49413
|
+
console.log(` Goals: ${summary}`);
|
|
49414
|
+
if (goals.items.length) {
|
|
49415
|
+
console.log("");
|
|
49416
|
+
printGoals(goals.items);
|
|
49417
|
+
}
|
|
49418
|
+
}
|
|
49419
|
+
__name(printViewGoals, "printViewGoals");
|
|
49420
|
+
function subVerb(group, noun, raw, verbs) {
|
|
49421
|
+
if (!raw) {
|
|
49422
|
+
console.error(`\u274C ${noun}: usage \u2014 lua workflows ${noun} <${verbs.join("|")}> \u2026`);
|
|
49423
|
+
return void 0;
|
|
49424
|
+
}
|
|
49425
|
+
try {
|
|
49426
|
+
return validateOrSuggest(group, raw);
|
|
49427
|
+
} catch (e) {
|
|
49428
|
+
console.error(`\u274C ${e.message}`);
|
|
49429
|
+
return void 0;
|
|
49430
|
+
}
|
|
49431
|
+
}
|
|
49432
|
+
__name(subVerb, "subVerb");
|
|
49433
|
+
function goalFailure(ctx, res, verb, ref) {
|
|
49434
|
+
const err = res.error;
|
|
49435
|
+
const code = err?.code ?? err?.error;
|
|
49436
|
+
const status = err?.statusCode;
|
|
49437
|
+
if (!ctx.json && err) {
|
|
49438
|
+
if (status === 409 && code === "GOAL_NOT_ACTIVE") {
|
|
49439
|
+
const now = err.status ?? "not active";
|
|
49440
|
+
const rule = verb === "goals resume" ? "only a paused goal resumes" : verb === "goals pause" ? "only an active goal pauses" : "a done/closed goal stays closed";
|
|
49441
|
+
console.error(`\u274C goal ${ref ?? ""} is ${now} \u2014 ${rule}`);
|
|
49442
|
+
} else if (status === 409 && code === "GOAL_CAP") {
|
|
49443
|
+
console.error(`\u274C goal cap reached (${err.cap ?? "?"} per agent) \u2014 close or finish one first: lua workflows goals list --status active`);
|
|
49444
|
+
} else if (status === 400 && code === "VALIDATION_FAILED") {
|
|
49445
|
+
const issues = err.issues ?? [];
|
|
49446
|
+
for (const i of issues) console.error(` ${i.code}${i.path ? ` at ${i.path}` : ""}${i.message ? ` \u2014 ${i.message}` : ""}`);
|
|
49447
|
+
} else if (status === 400 && code === "GOAL_MAX_RUNS_INVALID") {
|
|
49448
|
+
console.error(`\u274C --max-runs must be 1..${GOAL_MAX_RUNS_CAP}`);
|
|
49449
|
+
} else if (status === 400 && code === "WORKFLOW_NOT_ON_AGENT") {
|
|
49450
|
+
console.error(`\u274C that workflow belongs to another agent \u2014 goals are scoped to ${ctx.agentId}`);
|
|
49451
|
+
} else if (status === 409 && code === "GOAL_SCHEDULE") {
|
|
49452
|
+
const goalId = err.goalId ?? "?";
|
|
49453
|
+
console.error(`\u274C GOAL_SCHEDULE: ${goalScheduleRefusal(ref ?? "<jobId>", goalId)}`);
|
|
49454
|
+
}
|
|
49455
|
+
}
|
|
49456
|
+
return apiFailure(ctx, res, verb);
|
|
49457
|
+
}
|
|
49458
|
+
__name(goalFailure, "goalFailure");
|
|
49459
|
+
async function goalsCore(ctx, target, extra, o) {
|
|
49460
|
+
const verb = subVerb("workflows.goals.action", "goals", target, GOAL_VERBS);
|
|
49461
|
+
if (!verb) return WORKFLOW_EXIT.USAGE;
|
|
49462
|
+
if (verb === "list") return goalsListCore(ctx, o, extra);
|
|
49463
|
+
if (verb === "create") return goalsCreateCore(ctx, o, extra);
|
|
49464
|
+
if (!extra) {
|
|
49465
|
+
console.error(`\u274C goals ${verb}: a goal id is required \u2014 lua workflows goals ${verb} <goalId>`);
|
|
49466
|
+
return WORKFLOW_EXIT.USAGE;
|
|
49467
|
+
}
|
|
49468
|
+
if (verb === "get") return goalsGetCore(ctx, extra);
|
|
49469
|
+
return goalsControlCore(ctx, verb, extra, o);
|
|
49470
|
+
}
|
|
49471
|
+
__name(goalsCore, "goalsCore");
|
|
49472
|
+
async function goalsListCore(ctx, o, positional) {
|
|
49473
|
+
if (o.status && !GOAL_STATUSES.includes(o.status)) {
|
|
49474
|
+
console.error(`\u274C goals list: --status must be ${GOAL_STATUSES.join("|")} (got "${o.status}")`);
|
|
49475
|
+
return WORKFLOW_EXIT.USAGE;
|
|
49476
|
+
}
|
|
49477
|
+
let limit;
|
|
49478
|
+
try {
|
|
49479
|
+
limit = parseIntegerFlag(o.limit, "--limit", {
|
|
49480
|
+
min: 1,
|
|
49481
|
+
max: GOAL_PAGE_LIMIT
|
|
49482
|
+
});
|
|
49483
|
+
} catch (e) {
|
|
49484
|
+
console.error(`\u274C ${e.message}`);
|
|
49485
|
+
return WORKFLOW_EXIT.USAGE;
|
|
49486
|
+
}
|
|
49487
|
+
const list = await loadWorkflowList(ctx);
|
|
49488
|
+
if (!list) return WORKFLOW_EXIT.API;
|
|
49489
|
+
const names = new Map(list.map((w) => [
|
|
49490
|
+
w.id,
|
|
49491
|
+
w.name
|
|
49492
|
+
]));
|
|
49493
|
+
const target = positional ?? o.workflowName ?? o.workflow;
|
|
49494
|
+
let workflowId;
|
|
49495
|
+
if (target) {
|
|
49496
|
+
const wf = pickWorkflow(list, target);
|
|
49497
|
+
if (!wf) return WORKFLOW_EXIT.NOT_FOUND;
|
|
49498
|
+
workflowId = wf.id;
|
|
49499
|
+
}
|
|
49500
|
+
const res = await ctx.api.getGoals({
|
|
49501
|
+
status: o.status,
|
|
49502
|
+
workflowId,
|
|
49503
|
+
cursor: o.cursor,
|
|
49504
|
+
limit
|
|
49505
|
+
});
|
|
49506
|
+
if (!res.success || !res.data) return goalFailure(ctx, res, "goals list");
|
|
49507
|
+
emitJson(ctx, res);
|
|
49508
|
+
if (ctx.json) return WORKFLOW_EXIT.OK;
|
|
49509
|
+
console.log(`
|
|
49510
|
+
\u{1F3AF} Goals${target ? ` \u2014 ${names.get(workflowId) ?? target}` : ""}${o.status ? ` \xB7 ${o.status}` : ""}
|
|
49511
|
+
`);
|
|
49512
|
+
printGoals(res.data.items ?? [], names);
|
|
49513
|
+
if (res.data.nextCursor) {
|
|
49514
|
+
const flags = `${target ? ` -i ${target}` : ""}${o.status ? ` --status ${o.status}` : ""}${limit !== void 0 ? ` --limit ${limit}` : ""}`;
|
|
49515
|
+
console.log(`
|
|
49516
|
+
\u2026 more: lua workflows goals list${flags} --cursor ${res.data.nextCursor}`);
|
|
49517
|
+
}
|
|
49518
|
+
return WORKFLOW_EXIT.OK;
|
|
49519
|
+
}
|
|
49520
|
+
__name(goalsListCore, "goalsListCore");
|
|
49521
|
+
async function goalsGetCore(ctx, goalId) {
|
|
49522
|
+
const res = await ctx.api.getGoal(goalId);
|
|
49523
|
+
if (!res.success || !res.data) return goalFailure(ctx, res, "goals get", goalId);
|
|
49524
|
+
emitJson(ctx, res);
|
|
49525
|
+
if (!ctx.json) printGoalDetail(res.data);
|
|
49526
|
+
return WORKFLOW_EXIT.OK;
|
|
49527
|
+
}
|
|
49528
|
+
__name(goalsGetCore, "goalsGetCore");
|
|
49529
|
+
function printGoalDetail(g) {
|
|
49530
|
+
console.log(`
|
|
49531
|
+
\u{1F3AF} Goal ${g.goalId} \xB7 ${goalStatusLabel(g)}`);
|
|
49532
|
+
console.log(` Workflow: ${g.workflowId}${g.workflowVersionId ? ` @ ${g.workflowVersionId}` : ""}`);
|
|
49533
|
+
console.log(` Objective: ${g.objective}`);
|
|
49534
|
+
console.log(` Judge: ${judgeLabel(g.judge)}`);
|
|
49535
|
+
console.log(` Cadence: ${cadenceLabel(g.cadence)} \xB7 mode ${g.evaluation?.mode ?? "immediate"}${g.evaluation?.delaySeconds ? ` \xB7 delay ${g.evaluation.delaySeconds}s` : ""}`);
|
|
49536
|
+
console.log(` Runs: ${g.runsUsed}/${g.maxRuns} used \xB7 iteration ${g.iteration ?? 0}${g.consecutiveContinues ? ` \xB7 ${g.consecutiveContinues} consecutive continue(s)` : ""}${g.currentRunId ? ` \xB7 current ${g.currentRunId}` : ""}`);
|
|
49537
|
+
if (g.budget?.maxCredits || g.maxTotalCredits) console.log(` Budget: ${g.budget?.maxCredits ? `per-run ${g.budget.maxCredits} credits` : ""}${g.budget?.maxCredits && g.maxTotalCredits ? " \xB7 " : ""}${g.maxTotalCredits ? `lineage cap ${g.maxTotalCredits} credits` : ""}`);
|
|
49538
|
+
console.log(` Schedule: ${g.jobId ? `${g.jobId} (goal-owned \u2014 stop it with goals pause|close, never schedules delete)` : "none (immediate)"}`);
|
|
49539
|
+
if (g.verdict) console.log(` Verdict: ${verdictLabel(g.verdict)}${g.verdict.runId ? ` (run ${g.verdict.runId}${g.verdict.at ? ` at ${when(g.verdict.at)}` : ""})` : ""}`);
|
|
49540
|
+
if (g.input !== void 0) console.log(` Input: ${JSON.stringify(g.input).slice(0, 500)}`);
|
|
49541
|
+
console.log(` Created: ${when(g.createdAt)} \xB7 updated ${when(g.updatedAt)}${g.doneAt ? ` \xB7 done ${when(g.doneAt)}` : ""}${g.closedBy ? ` \xB7 closed by ${g.closedBy}` : ""}`);
|
|
49542
|
+
console.log("\n\u{1F4DC} Iterations");
|
|
49543
|
+
const runs = g.runs ?? [];
|
|
49544
|
+
if (!runs.length) console.log(" (no iteration runs yet)");
|
|
49545
|
+
else console.log(renderTable([
|
|
49546
|
+
"Run",
|
|
49547
|
+
"Iteration",
|
|
49548
|
+
"Status",
|
|
49549
|
+
"Verdict",
|
|
49550
|
+
"Credits",
|
|
49551
|
+
"Created"
|
|
49552
|
+
], runs.map((r) => [
|
|
49553
|
+
`${r.runId}${r.purged ? " (purged)" : ""}`,
|
|
49554
|
+
String(r.iteration ?? ""),
|
|
49555
|
+
r.status,
|
|
49556
|
+
verdictLabel(r.verdict),
|
|
49557
|
+
String(r.creditsUsed ?? 0),
|
|
49558
|
+
when(r.createdAt)
|
|
49559
|
+
])));
|
|
49560
|
+
}
|
|
49561
|
+
__name(printGoalDetail, "printGoalDetail");
|
|
49562
|
+
async function goalsControlCore(ctx, verb, goalId, o) {
|
|
49563
|
+
if (o.note && verb !== "close" && !ctx.json) writeInfo(`\u2139\uFE0F --note is recorded on close only; ${verb} takes no note`);
|
|
49564
|
+
const res = verb === "pause" ? await ctx.api.pauseGoal(goalId) : verb === "resume" ? await ctx.api.resumeGoal(goalId) : await ctx.api.closeGoal(goalId, o.note ? {
|
|
49565
|
+
note: o.note
|
|
49566
|
+
} : {});
|
|
49567
|
+
if (!res.success || !res.data) return goalFailure(ctx, res, `goals ${verb}`, goalId);
|
|
49568
|
+
emitJson(ctx, res);
|
|
49569
|
+
if (!ctx.json) {
|
|
49570
|
+
const g = res.data;
|
|
49571
|
+
const past = verb === "pause" ? "paused" : verb === "resume" ? "resumed" : "closed";
|
|
49572
|
+
writeSuccess(`\u2705 goal ${g.goalId} ${past} \xB7 ${goalStatusLabel(g)} \xB7 runs ${g.runsUsed}/${g.maxRuns}${g.jobId ? ` \xB7 schedule ${g.jobId}` : ""}`);
|
|
49573
|
+
if (verb === "pause") writeInfo(` the cadence stays with the goal \u2014 resume with: lua workflows goals resume ${g.goalId}`);
|
|
49574
|
+
if (verb === "resume") writeInfo(" no backfill: missed cadence fires are not replayed");
|
|
49575
|
+
}
|
|
49576
|
+
return WORKFLOW_EXIT.OK;
|
|
49577
|
+
}
|
|
49578
|
+
__name(goalsControlCore, "goalsControlCore");
|
|
49579
|
+
function parseJudgePredicateFlag(raw) {
|
|
49580
|
+
const opList = GOAL_PREDICATE_OPS.join("|");
|
|
49581
|
+
if (raw.startsWith("{") || raw.startsWith("@")) {
|
|
49582
|
+
const obj = parseJsonOrFile(raw, "--judge-predicate");
|
|
49583
|
+
if (!obj || typeof obj !== "object" || typeof obj.path !== "string" || !obj.path || !GOAL_PREDICATE_OPS.includes(String(obj.op))) throw new WorkflowLocalUsageError("usage", `--judge-predicate: expected { path, op: ${opList}, value? }`);
|
|
49584
|
+
return {
|
|
49585
|
+
path: obj.path,
|
|
49586
|
+
op: obj.op,
|
|
49587
|
+
...obj.value !== void 0 ? {
|
|
49588
|
+
value: obj.value
|
|
49589
|
+
} : {}
|
|
49590
|
+
};
|
|
49591
|
+
}
|
|
49592
|
+
const [path23, op, ...rest] = raw.trim().split(/\s+/);
|
|
49593
|
+
if (!path23 || !op || !GOAL_PREDICATE_OPS.includes(op)) throw new WorkflowLocalUsageError("usage", `--judge-predicate: expected "<path> <op> [value]" with op ${opList} (got "${raw}")`);
|
|
49594
|
+
if (rest.length === 0) return {
|
|
49595
|
+
path: path23,
|
|
49596
|
+
op
|
|
49597
|
+
};
|
|
49598
|
+
const text = rest.join(" ");
|
|
49599
|
+
let value3 = text;
|
|
49600
|
+
try {
|
|
49601
|
+
value3 = JSON.parse(text);
|
|
49602
|
+
} catch {
|
|
49603
|
+
}
|
|
49604
|
+
return {
|
|
49605
|
+
path: path23,
|
|
49606
|
+
op,
|
|
49607
|
+
value: value3
|
|
49608
|
+
};
|
|
49609
|
+
}
|
|
49610
|
+
__name(parseJudgePredicateFlag, "parseJudgePredicateFlag");
|
|
49611
|
+
function parseCadenceFlag(entries, timezone) {
|
|
49612
|
+
const out = [];
|
|
49613
|
+
let bareCron = 0;
|
|
49614
|
+
for (const raw of entries ?? []) {
|
|
49615
|
+
const text = raw.trim();
|
|
49616
|
+
if (!text) continue;
|
|
49617
|
+
if (text.startsWith("{") || text.startsWith("[") || text.startsWith("@")) {
|
|
49618
|
+
const parsed = parseJsonOrFile(text, "--cadence");
|
|
49619
|
+
for (const c of Array.isArray(parsed) ? parsed : [
|
|
49620
|
+
parsed
|
|
49621
|
+
]) {
|
|
49622
|
+
const slot = c;
|
|
49623
|
+
if (!slot || typeof slot !== "object" || ![
|
|
49624
|
+
"cron",
|
|
49625
|
+
"once",
|
|
49626
|
+
"interval"
|
|
49627
|
+
].includes(String(slot.type))) throw new WorkflowLocalUsageError("usage", "--cadence: each JSON entry needs type cron|once|interval");
|
|
49628
|
+
out.push(slot);
|
|
49629
|
+
}
|
|
49630
|
+
continue;
|
|
49631
|
+
}
|
|
49632
|
+
if (!/^\S+(\s+\S+){4,5}$/.test(text)) throw new WorkflowLocalUsageError("usage", `--cadence: "${text}" is not a cron expression (5\u20136 fields); pass JSON for once/interval entries`);
|
|
49633
|
+
bareCron += 1;
|
|
49634
|
+
out.push({
|
|
49635
|
+
type: "cron",
|
|
49636
|
+
expression: text,
|
|
49637
|
+
...timezone ? {
|
|
49638
|
+
timezone
|
|
49639
|
+
} : {}
|
|
49640
|
+
});
|
|
49641
|
+
}
|
|
49642
|
+
if (timezone && bareCron === 0) throw new WorkflowLocalUsageError("usage", '--timezone applies to bare cron cadences only \u2014 put "timezone" inside JSON entries, or pass a cron expression');
|
|
49643
|
+
if (out.length > GOAL_CADENCE_MAX) throw new WorkflowLocalUsageError("usage", `--cadence: at most ${GOAL_CADENCE_MAX} entries (goal-cadence-invalid)`);
|
|
49644
|
+
return out;
|
|
49645
|
+
}
|
|
49646
|
+
__name(parseCadenceFlag, "parseCadenceFlag");
|
|
49647
|
+
async function goalsCreateCore(ctx, o, positional) {
|
|
49648
|
+
const target = positional ?? o.workflowName ?? o.workflow;
|
|
49649
|
+
if (!target) {
|
|
49650
|
+
console.error("\u274C goals create: a workflow is required \u2014 lua workflows goals create <workflow> (or -i <workflow>)");
|
|
49651
|
+
return WORKFLOW_EXIT.USAGE;
|
|
49652
|
+
}
|
|
49653
|
+
if (!o.objective?.trim()) {
|
|
49654
|
+
console.error("\u274C goals create: --objective <text> is required");
|
|
49655
|
+
return WORKFLOW_EXIT.USAGE;
|
|
49656
|
+
}
|
|
49657
|
+
if (o.judgeAgent === "") {
|
|
49658
|
+
console.error("\u274C goals create: --judge-agent is empty \u2014 an unquoted $self is expanded by the shell to nothing; write '$self' (quoted) or self");
|
|
49659
|
+
return WORKFLOW_EXIT.USAGE;
|
|
49660
|
+
}
|
|
49661
|
+
if (!o.judgePredicate && !o.judgeAgent) {
|
|
49662
|
+
console.error("\u274C goals create: one of --judge-predicate <spec> | --judge-agent <agentId|'$self'> is required");
|
|
49663
|
+
return WORKFLOW_EXIT.USAGE;
|
|
49664
|
+
}
|
|
49665
|
+
const usage = /* @__PURE__ */ __name((m) => new WorkflowLocalUsageError("usage", m), "usage");
|
|
49666
|
+
let dto;
|
|
49667
|
+
try {
|
|
49668
|
+
const maxRuns = parseIntegerFlag(o.maxRuns, "--max-runs", {
|
|
49669
|
+
min: 1,
|
|
49670
|
+
max: GOAL_MAX_RUNS_CAP
|
|
49671
|
+
});
|
|
49672
|
+
if (maxRuns === void 0) throw usage(`--max-runs <n> is required (an integer 1..${GOAL_MAX_RUNS_CAP})`);
|
|
49673
|
+
const judge = {
|
|
49674
|
+
agentId: o.judgeAgent === "self" ? "$self" : o.judgeAgent ?? "$self"
|
|
49675
|
+
};
|
|
49676
|
+
if (o.judgePredicate) {
|
|
49677
|
+
if (o.schema || o.judgeRole) throw usage("--judge-predicate is the deterministic judge \u2014 --schema / --judge-role belong to --judge-agent");
|
|
49678
|
+
judge.predicate = parseJudgePredicateFlag(o.judgePredicate);
|
|
49679
|
+
} else {
|
|
49680
|
+
if (o.judgeRole) judge.role = parseJsonOrFile(o.judgeRole, "--judge-role");
|
|
49681
|
+
if (judge.agentId === "$self" && !judge.role) throw usage("--judge-role <json|@file> ({ name, instructions, tools }) is required for a '$self' judge");
|
|
49682
|
+
if (judge.agentId !== "$self" && judge.role) throw usage("--judge-role is only for a $self judge");
|
|
49683
|
+
if (!o.schema) throw usage("--schema <json|@file> is required for an agent judge (a JsonSchema with a boolean `done` at the root)");
|
|
49684
|
+
const schema = parseJsonOrFile(o.schema, "--schema");
|
|
49685
|
+
const done = schema?.properties?.done;
|
|
49686
|
+
if (!schema || typeof schema !== "object" || done?.type !== "boolean") throw usage('--schema: must declare a boolean `done` at the root (properties.done.type === "boolean")');
|
|
49687
|
+
judge.schema = schema;
|
|
49688
|
+
}
|
|
49689
|
+
const cadence = parseCadenceFlag(o.cadence, o.timezone);
|
|
49690
|
+
const input = o.input ? parseJsonOrFile(o.input, "--input") : void 0;
|
|
49691
|
+
const budgetCredits = parseIntegerFlag(o.budgetCredits, "--budget-credits", {
|
|
49692
|
+
min: 1
|
|
49693
|
+
});
|
|
49694
|
+
const maxTotalCredits = parseIntegerFlag(o.maxTotalCredits, "--max-total-credits", {
|
|
49695
|
+
min: 1
|
|
49696
|
+
});
|
|
49697
|
+
dto = {
|
|
49698
|
+
workflowId: "",
|
|
49699
|
+
objective: o.objective.trim(),
|
|
49700
|
+
judge,
|
|
49701
|
+
cadence,
|
|
49702
|
+
evaluation: {
|
|
49703
|
+
mode: cadence.length ? "cadence" : "immediate"
|
|
49704
|
+
},
|
|
49705
|
+
maxRuns,
|
|
49706
|
+
...budgetCredits !== void 0 ? {
|
|
49707
|
+
budget: {
|
|
49708
|
+
maxCredits: budgetCredits
|
|
49709
|
+
}
|
|
49710
|
+
} : {},
|
|
49711
|
+
...maxTotalCredits !== void 0 ? {
|
|
49712
|
+
maxTotalCredits
|
|
49713
|
+
} : {},
|
|
49714
|
+
...input !== void 0 ? {
|
|
49715
|
+
input
|
|
49716
|
+
} : {},
|
|
49717
|
+
...o.idempotencyKey ? {
|
|
49718
|
+
idempotencyKey: o.idempotencyKey
|
|
49719
|
+
} : {}
|
|
49720
|
+
};
|
|
49721
|
+
} catch (e) {
|
|
49722
|
+
if (e instanceof WorkflowLocalUsageError) {
|
|
49723
|
+
console.error(`\u274C ${e.message}`);
|
|
49724
|
+
return WORKFLOW_EXIT.USAGE;
|
|
49725
|
+
}
|
|
49726
|
+
throw e;
|
|
49727
|
+
}
|
|
49728
|
+
const wf = await resolveWorkflow(ctx, target);
|
|
49729
|
+
if (!wf) return WORKFLOW_EXIT.NOT_FOUND;
|
|
49730
|
+
dto.workflowId = wf.id;
|
|
49731
|
+
if (o.workflowVersion) {
|
|
49732
|
+
const ref = await resolveVersionRef(ctx, wf, o.workflowVersion, "goals create");
|
|
49733
|
+
if ("exit" in ref) return ref.exit;
|
|
49734
|
+
dto.workflowVersionId = ref.version.id;
|
|
49735
|
+
}
|
|
49736
|
+
const res = await ctx.api.createGoal(dto);
|
|
49737
|
+
if (!res.success || !res.data) return goalFailure(ctx, res, "goals create");
|
|
49738
|
+
emitJson(ctx, res);
|
|
49739
|
+
if (!ctx.json) {
|
|
49740
|
+
const g = res.data;
|
|
49741
|
+
writeSuccess(`\u2705 goal ${g.goalId} created on "${wf.name}" \xB7 ${goalStatusLabel(g)} \xB7 runs ${g.runsUsed}/${g.maxRuns} \xB7 ${cadenceLabel(g.cadence)}${g.jobId ? ` \xB7 schedule ${g.jobId}` : ""}`);
|
|
49742
|
+
writeHintBlock({
|
|
49743
|
+
headline: "Follow the goal:",
|
|
49744
|
+
lines: [
|
|
49745
|
+
{
|
|
49746
|
+
label: "Get:",
|
|
49747
|
+
command: `lua workflows goals get ${g.goalId}`
|
|
49748
|
+
},
|
|
49749
|
+
{
|
|
49750
|
+
label: "Pause:",
|
|
49751
|
+
command: `lua workflows goals pause ${g.goalId}`
|
|
49752
|
+
}
|
|
49753
|
+
],
|
|
49754
|
+
when: "success"
|
|
49755
|
+
});
|
|
49756
|
+
}
|
|
49757
|
+
return WORKFLOW_EXIT.OK;
|
|
49758
|
+
}
|
|
49759
|
+
__name(goalsCreateCore, "goalsCreateCore");
|
|
49760
|
+
async function schedulesCore(ctx, target, extra, o) {
|
|
49761
|
+
const verb = subVerb("workflows.schedules.action", "schedules", target, SCHEDULE_VERBS);
|
|
49762
|
+
if (!verb) return WORKFLOW_EXIT.USAGE;
|
|
49763
|
+
if (verb === "list") return schedulesListCore(ctx, o);
|
|
49764
|
+
if (!extra) {
|
|
49765
|
+
console.error("\u274C schedules delete: a schedule (job) id is required \u2014 lua workflows schedules delete <jobId>");
|
|
49766
|
+
return WORKFLOW_EXIT.USAGE;
|
|
49767
|
+
}
|
|
49768
|
+
return schedulesDeleteCore(ctx, extra, o);
|
|
49769
|
+
}
|
|
49770
|
+
__name(schedulesCore, "schedulesCore");
|
|
49771
|
+
async function schedulesListCore(ctx, o) {
|
|
49772
|
+
const list = await loadWorkflowList(ctx);
|
|
49773
|
+
if (!list) return WORKFLOW_EXIT.API;
|
|
49774
|
+
const names = new Map(list.map((w) => [
|
|
49775
|
+
w.id,
|
|
49776
|
+
w.name
|
|
49777
|
+
]));
|
|
49778
|
+
const target = o.workflowName ?? o.workflow;
|
|
49779
|
+
let wf;
|
|
49780
|
+
if (target) {
|
|
49781
|
+
wf = pickWorkflow(list, target);
|
|
49782
|
+
if (!wf) return WORKFLOW_EXIT.NOT_FOUND;
|
|
49783
|
+
}
|
|
49784
|
+
const goals = await loadGoals(ctx, wf?.id);
|
|
49785
|
+
const sched = await loadSchedules(ctx, wf?.id, goals.items);
|
|
49786
|
+
if (sched.error) return apiFailure(ctx, {
|
|
49787
|
+
success: false,
|
|
49788
|
+
error: sched.error
|
|
49789
|
+
}, "schedules list");
|
|
49790
|
+
if (ctx.json) {
|
|
49791
|
+
console.log(JSON.stringify({
|
|
49792
|
+
success: true,
|
|
49793
|
+
data: {
|
|
49794
|
+
items: sched.items,
|
|
49795
|
+
...goals.error ? {
|
|
49796
|
+
goalsError: goals.error
|
|
49797
|
+
} : {}
|
|
49798
|
+
}
|
|
49799
|
+
}, null, 2));
|
|
49800
|
+
return WORKFLOW_EXIT.OK;
|
|
49801
|
+
}
|
|
49802
|
+
console.log(`
|
|
49803
|
+
\u{1F4C5} Schedules${wf ? ` \u2014 ${wf.name}` : ""}
|
|
49804
|
+
`);
|
|
49805
|
+
if (goals.error) console.error(`\u26A0\uFE0F goals unavailable (${errorLabel(goals.error)}) \u2014 goal-owned rows may be untagged`);
|
|
49806
|
+
printSchedules(sched.items, names);
|
|
49807
|
+
return WORKFLOW_EXIT.OK;
|
|
49808
|
+
}
|
|
49809
|
+
__name(schedulesListCore, "schedulesListCore");
|
|
49810
|
+
async function schedulesDeleteCore(ctx, jobId, o) {
|
|
49811
|
+
const rowRes = await ctx.api.getSchedule(jobId);
|
|
49812
|
+
if (!rowRes.success || !rowRes.data) return apiFailure(ctx, rowRes, "schedules delete");
|
|
49813
|
+
const row2 = rowRes.data;
|
|
49814
|
+
let goalId = row2.goalId;
|
|
49815
|
+
if (!goalId) {
|
|
49816
|
+
const goals = await loadGoals(ctx, row2.workflowId);
|
|
49817
|
+
if (goals.error) {
|
|
49818
|
+
if (!ctx.json) console.error(`\u274C cannot prove ${jobId} is not a goal's cadence (goals unavailable) \u2014 refusing to delete`);
|
|
49819
|
+
return apiFailure(ctx, {
|
|
49820
|
+
success: false,
|
|
49821
|
+
error: goals.error
|
|
49822
|
+
}, "schedules delete");
|
|
49823
|
+
}
|
|
49824
|
+
goalId = goals.items.find((g) => g.jobId === jobId)?.goalId;
|
|
49825
|
+
}
|
|
49826
|
+
if (goalId) {
|
|
49827
|
+
const message = goalScheduleRefusal(jobId, goalId);
|
|
49828
|
+
if (ctx.json) console.log(JSON.stringify({
|
|
49829
|
+
success: false,
|
|
49830
|
+
error: {
|
|
49831
|
+
code: "goal_schedule",
|
|
49832
|
+
statusCode: 409,
|
|
49833
|
+
message,
|
|
49834
|
+
jobId,
|
|
49835
|
+
goalId
|
|
49836
|
+
}
|
|
49837
|
+
}, null, 2));
|
|
49838
|
+
else console.error(`\u274C goal_schedule: ${message}`);
|
|
49839
|
+
return WORKFLOW_EXIT.API;
|
|
49840
|
+
}
|
|
49841
|
+
if (!o.yes) {
|
|
49842
|
+
const answer = await safePrompt([
|
|
49843
|
+
{
|
|
49844
|
+
type: "confirm",
|
|
49845
|
+
name: "confirm",
|
|
49846
|
+
message: `Delete schedule ${jobId} (${(row2.trigger ?? []).map(triggerLabel).join(" \xB7 ") || "no trigger"}) of workflow ${row2.workflowId}?`,
|
|
49847
|
+
default: false
|
|
49848
|
+
}
|
|
49849
|
+
]);
|
|
49850
|
+
if (!answer?.confirm) {
|
|
49851
|
+
console.log("Cancelled.");
|
|
49852
|
+
return WORKFLOW_EXIT.OK;
|
|
49853
|
+
}
|
|
49854
|
+
}
|
|
49855
|
+
const res = await ctx.api.deleteSchedule(jobId);
|
|
49856
|
+
if (!res.success) return goalFailure(ctx, res, "schedules delete", jobId);
|
|
49857
|
+
emitJson(ctx, res);
|
|
49858
|
+
if (!ctx.json) writeSuccess(`\u2705 schedule ${jobId} deleted`);
|
|
49859
|
+
return WORKFLOW_EXIT.OK;
|
|
49860
|
+
}
|
|
49861
|
+
__name(schedulesDeleteCore, "schedulesDeleteCore");
|
|
48178
49862
|
|
|
48179
49863
|
// src/commands/features.ts
|
|
48180
49864
|
init_cli();
|
|
@@ -56841,7 +58525,7 @@ function getProjectToolNames() {
|
|
|
56841
58525
|
if (!hasCompilationOutput(process.cwd())) return [];
|
|
56842
58526
|
try {
|
|
56843
58527
|
const manifest = loadManifest();
|
|
56844
|
-
return getPrimitivesByKind(manifest, PrimitiveKind.TOOL).map((t) => t.name).filter((
|
|
58528
|
+
return getPrimitivesByKind(manifest, PrimitiveKind.TOOL).map((t) => t.name).filter((n2) => typeof n2 === "string" && n2.length > 0).sort();
|
|
56845
58529
|
} catch {
|
|
56846
58530
|
return [];
|
|
56847
58531
|
}
|
|
@@ -58345,11 +60029,11 @@ init_constants();
|
|
|
58345
60029
|
function parseVersion2(arg) {
|
|
58346
60030
|
if (!arg) throw new Error(`Invalid version "${arg}": must be a positive integer like "3" or "v3".`);
|
|
58347
60031
|
const stripped = arg.replace(/^v/i, "");
|
|
58348
|
-
const
|
|
58349
|
-
if (!Number.isFinite(
|
|
60032
|
+
const n2 = Number.parseInt(stripped, 10);
|
|
60033
|
+
if (!Number.isFinite(n2) || n2 <= 0 || String(n2) !== stripped) {
|
|
58350
60034
|
throw new Error(`Invalid version "${arg}": must be a positive integer like "3" or "v3".`);
|
|
58351
60035
|
}
|
|
58352
|
-
return
|
|
60036
|
+
return n2;
|
|
58353
60037
|
}
|
|
58354
60038
|
__name(parseVersion2, "parseVersion");
|
|
58355
60039
|
|
|
@@ -59655,13 +61339,15 @@ Examples:
|
|
|
59655
61339
|
$ lua jobs versions -i myJob View job versions
|
|
59656
61340
|
$ lua jobs history -i myJob View execution history
|
|
59657
61341
|
`).action(jobsCommand);
|
|
59658
|
-
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>", "
|
|
61342
|
+
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: give up after s seconds (exit 7)").option("--events", "watch: print raw frames").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("--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: IANA timezone for bare cron cadences").option("--max-runs <n>", "goals create: iteration cap (1..100)").option("--max-total-credits <n>", "goals create: lineage-wide credit gate").addHelpText("after", `
|
|
59659
61343
|
Arguments:
|
|
59660
61344
|
action list \xB7 view \xB7 versions \xB7 deploy \xB7 activate \xB7 deactivate \xB7 start \xB7 run \xB7 runs \xB7 status \xB7
|
|
59661
|
-
watch \xB7 cancel \xB7 resume \xB7 approve \xB7 signal \xB7 replay \xB7 logs \xB7 delete \xB7 delete-run \xB7
|
|
59662
|
-
env-overlay \xB7 archive-runs \xB7 workspace \xB7 jobs \xB7 job-logs
|
|
59663
|
-
|
|
59664
|
-
|
|
61345
|
+
watch \xB7 cancel \xB7 resume \xB7 retry-step \xB7 approve \xB7 signal \xB7 replay \xB7 logs \xB7 delete \xB7 delete-run \xB7
|
|
61346
|
+
env-overlay \xB7 archive-runs \xB7 workspace \xB7 jobs \xB7 job-logs \xB7
|
|
61347
|
+
goals <list|get|create|pause|resume|close> \xB7 schedules <list|delete>
|
|
61348
|
+
target workflow name (list/view/versions/deploy/activate/deactivate/start/run/delete) or run id (the rest);
|
|
61349
|
+
the sub-verb for goals / schedules
|
|
61350
|
+
extra signal name (signal <runId> <name>) \xB7 goal id (goals get/pause/resume/close) \xB7 job id (schedules delete)
|
|
59665
61351
|
|
|
59666
61352
|
Exit codes: 0 ok \xB7 1 API failure \xB7 2 usage \xB7 3 not found \xB7 4 run failed \xB7 5 run cancelled \xB7
|
|
59667
61353
|
6 run gated (consent) \xB7 7 --timeout reached \xB7 8 run parked (exception/budget gate)
|
|
@@ -59680,10 +61366,19 @@ Examples:
|
|
|
59680
61366
|
$ lua workflows job-logs <runId> build --tail 500 --follow
|
|
59681
61367
|
$ lua workflows cancel <runId> --reason "wrong input"
|
|
59682
61368
|
$ lua workflows resume <runId> --step ask --data '{"answer":42}'
|
|
61369
|
+
$ lua workflows retry-step <runId> --step sendEmails --note "vendor back up"
|
|
59683
61370
|
$ lua workflows approve <runId> --approval reviewDrafts --decision approve
|
|
59684
61371
|
$ lua workflows signal <runId> review --payload '{"ok":true}'
|
|
59685
61372
|
$ lua workflows replay <runId> --local
|
|
59686
61373
|
$ lua workflows deploy outreach -v latest
|
|
61374
|
+
$ lua workflows view outreach --json | jq '.data.schedules, .data.goals'
|
|
61375
|
+
$ lua workflows goals list -i outreach --status active
|
|
61376
|
+
$ lua workflows goals get wfg_1234
|
|
61377
|
+
$ lua workflows goals create -i outreach --objective "Reach 50 signups" --judge-predicate 'output.signups gte 50' \\
|
|
61378
|
+
--cadence '0 9 * * 1' --timezone Europe/London --max-runs 12 --input '{"segment":"trial"}'
|
|
61379
|
+
$ lua workflows goals pause wfg_1234 \xB7 goals resume wfg_1234 \xB7 goals close wfg_1234 --note "shipped"
|
|
61380
|
+
$ lua workflows schedules list -i outreach
|
|
61381
|
+
$ lua workflows schedules delete <jobId> --yes (a goal's cadence is refused: goal_schedule)
|
|
59687
61382
|
`).action(workflowsCommand);
|
|
59688
61383
|
program2.command("features [action]").description("\u{1F3AF} Manage agent features (RAG, webSearch, inquiry, outboundChannels)").option("--feature-name <name>", "Feature name").option("--recipient-scope <scope>", "For configure: outboundChannels recipient scope (current_user | anyone)").addHelpText("after", `
|
|
59689
61384
|
Arguments:
|