lua-cli 3.32.2 → 3.32.4
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/dist/api-exports.d.ts +87 -11
- package/dist/api-exports.js +1554 -756
- package/dist/api-exports.js.map +1 -1
- package/dist/index.js +3512 -1459
- package/dist/index.js.map +1 -1
- package/dist/workflow-builder.d.ts +16 -10
- package/dist/workflow-builder.js +1216 -702
- package/dist/workflow-builder.js.map +1 -1
- package/docs/CLI_REFERENCE.md +126 -4
- package/docs/README.md +2 -2
- package/docs/api/LuaWorkflow.md +1 -1
- package/docs/workflows/approvals.md +26 -6
- package/docs/workflows/goals.md +2 -2
- package/docs/workflows/recovery.md +1 -1
- package/docs/workflows/replay-local.md +9 -3
- package/docs/workflows/schedules.md +13 -4
- package/docs/workflows/script-form.md +4 -4
- package/docs/workflows/testing-offline.md +33 -21
- package/package.json +4 -3
- package/template/examples/workflows/CLAUDE.md +17 -11
- package/template/examples/workflows/adversarial-verify.workflow.script.js +20 -16
- package/template/examples/workflows/outreach.ts +31 -15
- package/template/examples/workflows/refund-approval.ts +26 -12
- package/template/examples/workflows/research-brief.ts +29 -16
- package/template/package.json +1 -1
package/dist/api-exports.js
CHANGED
|
@@ -353,6 +353,84 @@ function isDesktopFileCommandName(value3) {
|
|
|
353
353
|
function isDesktopFileSessionId(value3) {
|
|
354
354
|
return typeof value3 === "string" && /^[0-9a-f]{8}-[0-9a-f]{4}-[1-5][0-9a-f]{3}-[89ab][0-9a-f]{3}-[0-9a-f]{12}$/i.test(value3);
|
|
355
355
|
}
|
|
356
|
+
function isModelIdSentinel(input) {
|
|
357
|
+
const lower = (input ?? "").trim().toLowerCase();
|
|
358
|
+
return lower === "auto" || lower.startsWith("auto/");
|
|
359
|
+
}
|
|
360
|
+
function normalizeModelId(input, registry) {
|
|
361
|
+
const requested = typeof input === "string" ? input.trim() : "";
|
|
362
|
+
if (!requested) return {
|
|
363
|
+
ok: false,
|
|
364
|
+
reason: "empty",
|
|
365
|
+
requested,
|
|
366
|
+
candidates: []
|
|
367
|
+
};
|
|
368
|
+
const lower = requested.toLowerCase();
|
|
369
|
+
if (isModelIdSentinel(lower)) return {
|
|
370
|
+
ok: true,
|
|
371
|
+
id: lower,
|
|
372
|
+
form: "sentinel"
|
|
373
|
+
};
|
|
374
|
+
const slash = requested.indexOf("/");
|
|
375
|
+
const malformed = slash === 0;
|
|
376
|
+
const provider = slash > 0 ? lower.slice(0, slash) : void 0;
|
|
377
|
+
if (provider && MODEL_ID_BYOK_PROVIDERS.includes(provider)) {
|
|
378
|
+
return {
|
|
379
|
+
ok: true,
|
|
380
|
+
id: requested,
|
|
381
|
+
form: "byok"
|
|
382
|
+
};
|
|
383
|
+
}
|
|
384
|
+
const bareId = slash >= 0 ? lower.slice(slash + 1) : lower;
|
|
385
|
+
const lastSegment = bareId.slice(bareId.lastIndexOf("/") + 1);
|
|
386
|
+
const exact = /* @__PURE__ */ new Set();
|
|
387
|
+
const hints = /* @__PURE__ */ new Set();
|
|
388
|
+
for (const code of registry) {
|
|
389
|
+
if (typeof code !== "string" || !code) continue;
|
|
390
|
+
const codeLower = code.toLowerCase();
|
|
391
|
+
if (!malformed && codeLower === lower) return {
|
|
392
|
+
ok: true,
|
|
393
|
+
id: code,
|
|
394
|
+
form: provider ? "canonical" : "bare"
|
|
395
|
+
};
|
|
396
|
+
const i = codeLower.indexOf("/");
|
|
397
|
+
if (i < 0) continue;
|
|
398
|
+
const codeBare = codeLower.slice(i + 1);
|
|
399
|
+
if (bareId && codeBare === bareId) exact.add(code);
|
|
400
|
+
else if (lastSegment && codeBare.slice(codeBare.lastIndexOf("/") + 1) === lastSegment) hints.add(code);
|
|
401
|
+
}
|
|
402
|
+
const sorted = [
|
|
403
|
+
...exact
|
|
404
|
+
].sort();
|
|
405
|
+
if (!provider && !malformed && sorted.length === 1) return {
|
|
406
|
+
ok: true,
|
|
407
|
+
id: sorted[0],
|
|
408
|
+
form: "bare"
|
|
409
|
+
};
|
|
410
|
+
if (!provider && !malformed && sorted.length > 1) {
|
|
411
|
+
return {
|
|
412
|
+
ok: false,
|
|
413
|
+
reason: "ambiguous",
|
|
414
|
+
requested,
|
|
415
|
+
candidates: sorted
|
|
416
|
+
};
|
|
417
|
+
}
|
|
418
|
+
return {
|
|
419
|
+
ok: false,
|
|
420
|
+
reason: "unknown",
|
|
421
|
+
requested,
|
|
422
|
+
candidates: sorted.length ? sorted : [
|
|
423
|
+
...hints
|
|
424
|
+
].sort()
|
|
425
|
+
};
|
|
426
|
+
}
|
|
427
|
+
function modelUnresolvedMessage(r) {
|
|
428
|
+
if (r.reason === "empty") return "model pin is empty \u2014 pin an approved model (provider/model) or omit `model`";
|
|
429
|
+
if (r.reason === "ambiguous") {
|
|
430
|
+
return `model "${r.requested}" does not resolve to one approved model \u2014 it names ${r.candidates.length}; pin one of: ${r.candidates.join(", ")}`;
|
|
431
|
+
}
|
|
432
|
+
return r.candidates.length ? `model "${r.requested}" does not resolve to an approved model \u2014 accepted forms: ${r.candidates.join(", ")}` : `model "${r.requested}" does not resolve to an approved model \u2014 accepted forms are the registry's provider-prefixed ids (provider/model) or a bare id that names exactly one of them`;
|
|
433
|
+
}
|
|
356
434
|
function isImplicitModelSelectionSource(source) {
|
|
357
435
|
return source !== void 0 && IMPLICIT_MODEL_SELECTION_SOURCES.includes(source);
|
|
358
436
|
}
|
|
@@ -653,6 +731,48 @@ function scheduledTimeKey(scheduledTime) {
|
|
|
653
731
|
function scheduledWorkflowRunIdForTime(jobId, scheduledTime) {
|
|
654
732
|
return scheduledWorkflowRunId(jobId, scheduledTime);
|
|
655
733
|
}
|
|
734
|
+
function workflowRetryMaxAttemptsMessage(got) {
|
|
735
|
+
const tail = got === void 0 ? "" : ` (got ${JSON.stringify(got)})`;
|
|
736
|
+
return `\`retry.maxAttempts\` must be an integer ${WORKFLOW_RETRY_MIN_ATTEMPTS}..${WORKFLOW_RETRY_MAX_ATTEMPTS}${tail}`;
|
|
737
|
+
}
|
|
738
|
+
function isWithinWorkflowRetryAttempts(value3) {
|
|
739
|
+
return typeof value3 === "number" && Number.isInteger(value3) && value3 >= WORKFLOW_RETRY_MIN_ATTEMPTS && value3 <= WORKFLOW_RETRY_MAX_ATTEMPTS;
|
|
740
|
+
}
|
|
741
|
+
function workflowRetryUnknownMembersMessage(keys) {
|
|
742
|
+
const named = keys.map((k) => {
|
|
743
|
+
const engine = WORKFLOW_RETRY_ENGINE_KEYS.includes(k);
|
|
744
|
+
return `\`${k}\`${engine ? " (engine-owned \u2014 stamped by resetAttempts, never authored)" : ""}`;
|
|
745
|
+
});
|
|
746
|
+
return `\`retry\` has no member ${named.join(", ")}; members: ${WORKFLOW_RETRY_POLICY_KEYS.join(", ")}`;
|
|
747
|
+
}
|
|
748
|
+
function unknownWorkflowRetryMembers(retry) {
|
|
749
|
+
if (!retry || typeof retry !== "object" || Array.isArray(retry)) return [];
|
|
750
|
+
return Object.keys(retry).filter((k) => !WORKFLOW_RETRY_POLICY_KEYS.includes(k));
|
|
751
|
+
}
|
|
752
|
+
function authoredRetryPolicy(retry) {
|
|
753
|
+
if (!retry || typeof retry !== "object" || Array.isArray(retry)) return void 0;
|
|
754
|
+
const src = retry;
|
|
755
|
+
const out = {};
|
|
756
|
+
for (const k of WORKFLOW_RETRY_POLICY_KEYS) if (src[k] !== void 0) out[k] = src[k];
|
|
757
|
+
return Object.keys(out).length ? out : void 0;
|
|
758
|
+
}
|
|
759
|
+
function retryBudgetBaseAttempt(row) {
|
|
760
|
+
const base = row.retry?.budgetBaseAttempt;
|
|
761
|
+
return typeof base === "number" && Number.isSafeInteger(base) && base > 0 ? base : 0;
|
|
762
|
+
}
|
|
763
|
+
function retryBudgetAttempt(row) {
|
|
764
|
+
return Math.max(0, row.attempt - retryBudgetBaseAttempt(row));
|
|
765
|
+
}
|
|
766
|
+
function retryBudgetMaxAttempts(row) {
|
|
767
|
+
const max = row.retry?.maxAttempts;
|
|
768
|
+
return typeof max === "number" && Number.isFinite(max) && max >= 1 ? max : 1;
|
|
769
|
+
}
|
|
770
|
+
function retryBudgetRemaining(row) {
|
|
771
|
+
return retryBudgetAttempt(row) < retryBudgetMaxAttempts(row);
|
|
772
|
+
}
|
|
773
|
+
function retriesRemaining(row) {
|
|
774
|
+
return Math.max(0, retryBudgetMaxAttempts(row) - retryBudgetAttempt(row));
|
|
775
|
+
}
|
|
656
776
|
function isWithinWorkflowJobRange(member, value3) {
|
|
657
777
|
const { min, max } = WORKFLOW_JOB_RANGES[member];
|
|
658
778
|
return typeof value3 === "number" && Number.isInteger(value3) && value3 >= min && value3 <= max;
|
|
@@ -840,7 +960,66 @@ ${PREAMBLE}
|
|
|
840
960
|
|
|
841
961
|
${items.join("\n\n")}`;
|
|
842
962
|
}
|
|
843
|
-
|
|
963
|
+
function workflowApprovalDecisionOf(resumeData) {
|
|
964
|
+
if (resumeData.timedOut === true) return "timed_out";
|
|
965
|
+
return resumeData.approved === true ? "approved" : "denied";
|
|
966
|
+
}
|
|
967
|
+
function workflowApprovalOutput(resumeData) {
|
|
968
|
+
const decision = typeof resumeData.decision === "string" ? resumeData.decision : workflowApprovalDecisionOf(resumeData);
|
|
969
|
+
const note = typeof resumeData.note === "string" && resumeData.note.trim() !== "" ? resumeData.note : void 0;
|
|
970
|
+
const text = typeof resumeData.text === "string" ? resumeData.text : note ?? decision;
|
|
971
|
+
return {
|
|
972
|
+
...resumeData,
|
|
973
|
+
decision,
|
|
974
|
+
text
|
|
975
|
+
};
|
|
976
|
+
}
|
|
977
|
+
function isWorkflowApprovalOutput(value3) {
|
|
978
|
+
if (typeof value3 !== "object" || value3 === null || Array.isArray(value3)) return false;
|
|
979
|
+
const v = value3;
|
|
980
|
+
return typeof v.approved === "boolean" && WORKFLOW_APPROVAL_OUTPUT_DECISIONS.includes(v.decision) && typeof v.text === "string";
|
|
981
|
+
}
|
|
982
|
+
function extractSingleJsonValue(text) {
|
|
983
|
+
const trimmed = (text ?? "").trim();
|
|
984
|
+
if (!trimmed) return {
|
|
985
|
+
reason: "reply is empty"
|
|
986
|
+
};
|
|
987
|
+
const fenced = [
|
|
988
|
+
...trimmed.matchAll(JSON_FENCE_RE)
|
|
989
|
+
];
|
|
990
|
+
if (fenced.length > 1) return {
|
|
991
|
+
reason: "reply carries more than one fenced block"
|
|
992
|
+
};
|
|
993
|
+
const candidate = fenced.length === 1 ? fenced[0][1].trim() : trimmed;
|
|
994
|
+
try {
|
|
995
|
+
return {
|
|
996
|
+
value: JSON.parse(candidate)
|
|
997
|
+
};
|
|
998
|
+
} catch {
|
|
999
|
+
if (fenced.length === 1) return {
|
|
1000
|
+
reason: "fenced block is not valid JSON"
|
|
1001
|
+
};
|
|
1002
|
+
}
|
|
1003
|
+
const opens = [
|
|
1004
|
+
trimmed.indexOf("{"),
|
|
1005
|
+
trimmed.indexOf("[")
|
|
1006
|
+
].filter((i) => i !== -1);
|
|
1007
|
+
const start = opens.length ? Math.min(...opens) : -1;
|
|
1008
|
+
const end = Math.max(trimmed.lastIndexOf("}"), trimmed.lastIndexOf("]"));
|
|
1009
|
+
if (start === -1 || end <= start) return {
|
|
1010
|
+
reason: "reply is not JSON"
|
|
1011
|
+
};
|
|
1012
|
+
try {
|
|
1013
|
+
return {
|
|
1014
|
+
value: JSON.parse(trimmed.slice(start, end + 1))
|
|
1015
|
+
};
|
|
1016
|
+
} catch {
|
|
1017
|
+
return {
|
|
1018
|
+
reason: "reply does not contain a single JSON value"
|
|
1019
|
+
};
|
|
1020
|
+
}
|
|
1021
|
+
}
|
|
1022
|
+
var __defProp2, __name2, CHANNEL_SEND_CHANNELS, REVIEWABLE_ACTION_EXECUTE_TOOL_ALLOWLIST, REVIEWABLE_MCP_SEND_TOOL_SUFFIX, MCP_TOOL_READ_VERB_RE, MCP_DRAFT_CREATE_VERBS, NON_INTERACTIVE_CHANNELS, RICH_PARTS_MESSAGE_ID_PREFIX, SCREENSHOT_MESSAGE_ID_PREFIX, BROWSER_COMMANDS, BROWSER_COMMAND_NAMES, DESKTOP_FILE_COMMANDS, DESKTOP_FILE_COMMAND_SET, MODEL_ID_BYOK_PROVIDERS, REASONING_EFFORT_VALUES, IMPLICIT_MODEL_SELECTION_SOURCES, PLATFORM_FALLBACK_MODEL_SOURCE, AGENT_NAME_TOKEN, DEFAULT_PERSONA_GUIDE, PERSONAL_SPACE_STARTING_PERSONA, CORE_DRAINING_CODE, CORE_DRAINING_DEFAULT_RETRY_MS, CORE_DRAINING_MAX_RETRY_MS, VoiceNameSchema, PluginProviderSchema, RealtimeProviderSchema, PluginClassSchema, ModelDescriptorSchema, InferenceModelSchema, PluginModelSchema, RealtimeModelSchema, LuaVoiceModelSchema, TurnDetectionSchema, InterruptionSchema, BuiltinAudioClipSchema, AudioConfigSchema, BackgroundAudioEntrySchema, BackgroundAudioSchema, LuaVoiceConfigInnerSchema, LuaVoiceConfigSchema, LuaVoiceRefSchema, LUA_JOB_DEFAULT_TIMEOUT_SECONDS, LUA_JOB_MIN_TIMEOUT_SECONDS, LUA_JOB_MAX_TIMEOUT_SECONDS, TEMPLATE_TRIGGER_URL_ENV_PREFIX, SUBJECT_TYPES, SubjectTypeSchema, CREDENTIAL_TYPES, CredentialTypeSchema, DEVICE_OPERATIONS, DeviceOperationSchema, DEVICE_SCOPE_BY_OPERATION, DeviceBindingSchema, IdSchema, 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_CONNECTION_KEY_RE, WORKFLOW_SIGNAL_PAYLOAD_MAX_BYTES, WORKFLOW_RESOLVE_OUTPUT_MAX_BYTES, WORKFLOW_RETRY_BACKOFFS, WORKFLOW_RETRY_MIN_ATTEMPTS, WORKFLOW_RETRY_POLICY_KEYS, WORKFLOW_RETRY_MAX_ATTEMPTS, WORKFLOW_RETRY_ENGINE_KEYS, WORKFLOW_JOB_RESOURCES, WORKFLOW_SIDE_EFFECTS, WORKFLOW_JOB_RANGES, WORKFLOW_JOB_RANGE_MEMBERS, WORKFLOW_SINGLE_STEP_TYPES, WORKFLOW_HITL_ENTRY_TYPES, WORKFLOW_ARM_ENTRY_TYPES, WORKFLOW_HITL_ARM_CONTAINERS, WORKFLOW_GRAPH_ENTRY_STEP_KINDS, WORKFLOW_ARM_ENTRY_STEP_KINDS, WORKFLOW_BUDGET_MAX_DURATION_SECONDS, REDACTED_PLACEHOLDER, PROVIDER_MESSAGE_MAX_CHARS, ERROR_MESSAGE_MAX_CHARS, SECRET_LITERAL_PATTERNS, SECRET_NAME, SECRET_PAIR_PATTERNS, GROUP_COUNT, WORKFLOW_SECRET_KEY_RE, WORKFLOW_RESERVED_SECRET_KEYS, SCRUB_INPUT_MAX_CHARS, SCRUB_CUT_BACKOFF_CHARS, WORKFLOW_AUDIT_EVENTS, WORKFLOW_AUDIT_METADATA_MAX_BYTES, INDENT, WRAP_WIDTH, NOUNS, GET_TOOL_NAMES, PREAMBLE, WORKFLOW_APPROVAL_OUTPUT_DECISIONS, WORKFLOW_APPROVAL_OUTPUT_SCHEMA, JSON_FENCE_RE;
|
|
844
1023
|
var init_dist = __esm({
|
|
845
1024
|
"../shared-types/dist/index.mjs"() {
|
|
846
1025
|
"use strict";
|
|
@@ -1157,6 +1336,16 @@ var init_dist = __esm({
|
|
|
1157
1336
|
__name2(isDesktopFileCommandName, "isDesktopFileCommandName");
|
|
1158
1337
|
__name(isDesktopFileSessionId, "isDesktopFileSessionId");
|
|
1159
1338
|
__name2(isDesktopFileSessionId, "isDesktopFileSessionId");
|
|
1339
|
+
MODEL_ID_BYOK_PROVIDERS = [
|
|
1340
|
+
"azure",
|
|
1341
|
+
"bedrock"
|
|
1342
|
+
];
|
|
1343
|
+
__name(isModelIdSentinel, "isModelIdSentinel");
|
|
1344
|
+
__name2(isModelIdSentinel, "isModelIdSentinel");
|
|
1345
|
+
__name(normalizeModelId, "normalizeModelId");
|
|
1346
|
+
__name2(normalizeModelId, "normalizeModelId");
|
|
1347
|
+
__name(modelUnresolvedMessage, "modelUnresolvedMessage");
|
|
1348
|
+
__name2(modelUnresolvedMessage, "modelUnresolvedMessage");
|
|
1160
1349
|
REASONING_EFFORT_VALUES = [
|
|
1161
1350
|
"off",
|
|
1162
1351
|
"minimal",
|
|
@@ -1928,6 +2117,37 @@ This text is who you are for this person. As you learn them, their name, their w
|
|
|
1928
2117
|
"fixed",
|
|
1929
2118
|
"exponential"
|
|
1930
2119
|
];
|
|
2120
|
+
WORKFLOW_RETRY_MIN_ATTEMPTS = 1;
|
|
2121
|
+
WORKFLOW_RETRY_POLICY_KEYS = [
|
|
2122
|
+
"maxAttempts",
|
|
2123
|
+
"backoffSeconds",
|
|
2124
|
+
"backoff",
|
|
2125
|
+
"maxBackoffSeconds"
|
|
2126
|
+
];
|
|
2127
|
+
WORKFLOW_RETRY_MAX_ATTEMPTS = 20;
|
|
2128
|
+
__name(workflowRetryMaxAttemptsMessage, "workflowRetryMaxAttemptsMessage");
|
|
2129
|
+
__name2(workflowRetryMaxAttemptsMessage, "workflowRetryMaxAttemptsMessage");
|
|
2130
|
+
__name(isWithinWorkflowRetryAttempts, "isWithinWorkflowRetryAttempts");
|
|
2131
|
+
__name2(isWithinWorkflowRetryAttempts, "isWithinWorkflowRetryAttempts");
|
|
2132
|
+
WORKFLOW_RETRY_ENGINE_KEYS = [
|
|
2133
|
+
"budgetBaseAttempt"
|
|
2134
|
+
];
|
|
2135
|
+
__name(workflowRetryUnknownMembersMessage, "workflowRetryUnknownMembersMessage");
|
|
2136
|
+
__name2(workflowRetryUnknownMembersMessage, "workflowRetryUnknownMembersMessage");
|
|
2137
|
+
__name(unknownWorkflowRetryMembers, "unknownWorkflowRetryMembers");
|
|
2138
|
+
__name2(unknownWorkflowRetryMembers, "unknownWorkflowRetryMembers");
|
|
2139
|
+
__name(authoredRetryPolicy, "authoredRetryPolicy");
|
|
2140
|
+
__name2(authoredRetryPolicy, "authoredRetryPolicy");
|
|
2141
|
+
__name(retryBudgetBaseAttempt, "retryBudgetBaseAttempt");
|
|
2142
|
+
__name2(retryBudgetBaseAttempt, "retryBudgetBaseAttempt");
|
|
2143
|
+
__name(retryBudgetAttempt, "retryBudgetAttempt");
|
|
2144
|
+
__name2(retryBudgetAttempt, "retryBudgetAttempt");
|
|
2145
|
+
__name(retryBudgetMaxAttempts, "retryBudgetMaxAttempts");
|
|
2146
|
+
__name2(retryBudgetMaxAttempts, "retryBudgetMaxAttempts");
|
|
2147
|
+
__name(retryBudgetRemaining, "retryBudgetRemaining");
|
|
2148
|
+
__name2(retryBudgetRemaining, "retryBudgetRemaining");
|
|
2149
|
+
__name(retriesRemaining, "retriesRemaining");
|
|
2150
|
+
__name2(retriesRemaining, "retriesRemaining");
|
|
1931
2151
|
WORKFLOW_JOB_RESOURCES = [
|
|
1932
2152
|
"small",
|
|
1933
2153
|
"medium",
|
|
@@ -2200,6 +2420,8 @@ This text is who you are for this person. As you learn them, their name, their w
|
|
|
2200
2420
|
"workflow.goal.resumed",
|
|
2201
2421
|
"workflow.goal.done",
|
|
2202
2422
|
"workflow.goal.closed",
|
|
2423
|
+
// LUA-760: an ended goal's cadence Job retired (deleted) — inline on done / closed, by R21 / R28, or by sweep #30
|
|
2424
|
+
"workflow.goal.job_retired",
|
|
2203
2425
|
// --- org policy (02 §2.10 / 09 R23) ---
|
|
2204
2426
|
"workflow.policy.retention_changed",
|
|
2205
2427
|
"workflow.policy.pacing_changed",
|
|
@@ -2249,6 +2471,79 @@ listed here; never invent a target.`;
|
|
|
2249
2471
|
__name2(reachingIt, "reachingIt");
|
|
2250
2472
|
__name(renderTargetsBlock, "renderTargetsBlock");
|
|
2251
2473
|
__name2(renderTargetsBlock, "renderTargetsBlock");
|
|
2474
|
+
WORKFLOW_APPROVAL_OUTPUT_DECISIONS = [
|
|
2475
|
+
"approved",
|
|
2476
|
+
"denied",
|
|
2477
|
+
"timed_out"
|
|
2478
|
+
];
|
|
2479
|
+
WORKFLOW_APPROVAL_OUTPUT_SCHEMA = {
|
|
2480
|
+
type: "object",
|
|
2481
|
+
properties: {
|
|
2482
|
+
approved: {
|
|
2483
|
+
type: "boolean"
|
|
2484
|
+
},
|
|
2485
|
+
decision: {
|
|
2486
|
+
type: "string",
|
|
2487
|
+
enum: [
|
|
2488
|
+
...WORKFLOW_APPROVAL_OUTPUT_DECISIONS
|
|
2489
|
+
]
|
|
2490
|
+
},
|
|
2491
|
+
/** the approver's note when given, else the decision word — what `${stepResults.<id>.text}` reads */
|
|
2492
|
+
text: {
|
|
2493
|
+
type: "string"
|
|
2494
|
+
},
|
|
2495
|
+
note: {
|
|
2496
|
+
type: "string"
|
|
2497
|
+
},
|
|
2498
|
+
editedPayload: {},
|
|
2499
|
+
editRevision: {
|
|
2500
|
+
type: "integer"
|
|
2501
|
+
},
|
|
2502
|
+
decidedBy: {
|
|
2503
|
+
type: "object",
|
|
2504
|
+
properties: {
|
|
2505
|
+
id: {
|
|
2506
|
+
type: "string"
|
|
2507
|
+
},
|
|
2508
|
+
kind: {
|
|
2509
|
+
type: "string"
|
|
2510
|
+
}
|
|
2511
|
+
}
|
|
2512
|
+
},
|
|
2513
|
+
timedOut: {
|
|
2514
|
+
type: "boolean"
|
|
2515
|
+
},
|
|
2516
|
+
escalations: {
|
|
2517
|
+
type: "integer"
|
|
2518
|
+
},
|
|
2519
|
+
evidence: {
|
|
2520
|
+
type: "array",
|
|
2521
|
+
items: {
|
|
2522
|
+
type: "string"
|
|
2523
|
+
}
|
|
2524
|
+
},
|
|
2525
|
+
items: {
|
|
2526
|
+
type: "array",
|
|
2527
|
+
items: {
|
|
2528
|
+
type: "object"
|
|
2529
|
+
}
|
|
2530
|
+
}
|
|
2531
|
+
},
|
|
2532
|
+
required: [
|
|
2533
|
+
"approved",
|
|
2534
|
+
"decision",
|
|
2535
|
+
"text"
|
|
2536
|
+
]
|
|
2537
|
+
};
|
|
2538
|
+
__name(workflowApprovalDecisionOf, "workflowApprovalDecisionOf");
|
|
2539
|
+
__name2(workflowApprovalDecisionOf, "workflowApprovalDecisionOf");
|
|
2540
|
+
__name(workflowApprovalOutput, "workflowApprovalOutput");
|
|
2541
|
+
__name2(workflowApprovalOutput, "workflowApprovalOutput");
|
|
2542
|
+
__name(isWorkflowApprovalOutput, "isWorkflowApprovalOutput");
|
|
2543
|
+
__name2(isWorkflowApprovalOutput, "isWorkflowApprovalOutput");
|
|
2544
|
+
JSON_FENCE_RE = /```(?:json)?[ \t]*\r?\n([\s\S]*?)\r?\n?```/g;
|
|
2545
|
+
__name(extractSingleJsonValue, "extractSingleJsonValue");
|
|
2546
|
+
__name2(extractSingleJsonValue, "extractSingleJsonValue");
|
|
2252
2547
|
}
|
|
2253
2548
|
});
|
|
2254
2549
|
|
|
@@ -2257,139 +2552,466 @@ import { createHash } from "crypto";
|
|
|
2257
2552
|
import { z as z4 } from "zod";
|
|
2258
2553
|
import { z as z22 } from "zod";
|
|
2259
2554
|
import { createHash as createHash2 } from "crypto";
|
|
2260
|
-
function
|
|
2261
|
-
|
|
2262
|
-
const expr = WORKSPACE_TEMPLATE_EXPR_RE.exec(key);
|
|
2263
|
-
if (expr) return expr[1].split(".");
|
|
2264
|
-
if (key.includes("${")) return void 0;
|
|
2265
|
-
return key.replace(/^(?:input|initData)\./, "").split(".");
|
|
2555
|
+
function isMapConfigObject(v) {
|
|
2556
|
+
return typeof v === "object" && v !== null && !Array.isArray(v);
|
|
2266
2557
|
}
|
|
2267
|
-
function
|
|
2268
|
-
if (
|
|
2269
|
-
|
|
2558
|
+
function parseMapConfig(raw, stepId) {
|
|
2559
|
+
if (isMapConfigObject(raw)) return raw;
|
|
2560
|
+
if (typeof raw !== "string") {
|
|
2561
|
+
throw new Error(`Stored mapping step "${stepId}" has a mapConfig that is neither a JSON string nor an object.`);
|
|
2562
|
+
}
|
|
2563
|
+
try {
|
|
2564
|
+
return JSON.parse(raw);
|
|
2565
|
+
} catch (e) {
|
|
2566
|
+
throw new Error(`Stored mapping step "${stepId}" has invalid JSON mapConfig: ${e.message}`);
|
|
2270
2567
|
}
|
|
2271
|
-
return WORKFLOW_RETRY_BACKOFFS;
|
|
2272
2568
|
}
|
|
2273
|
-
function
|
|
2274
|
-
|
|
2569
|
+
function mapConfigWire(raw) {
|
|
2570
|
+
if (typeof raw === "string") return raw;
|
|
2571
|
+
if (isMapConfigObject(raw)) return canonicalJson(raw);
|
|
2572
|
+
return void 0;
|
|
2275
2573
|
}
|
|
2276
|
-
function
|
|
2277
|
-
|
|
2278
|
-
if (node.timeoutSeconds === void 0) node.timeoutSeconds = node.tier === "job" ? WORKFLOW_JOB_DEFAULT_TIMEOUT_SECONDS : defaultTimeout;
|
|
2279
|
-
if (node.retry === void 0) node.retry = {
|
|
2280
|
-
maxAttempts: 1
|
|
2281
|
-
};
|
|
2282
|
-
if (node.onError === void 0) node.onError = "fail";
|
|
2283
|
-
if ((node.type === "step" || node.type === "tool") && node.sideEffects === void 0) node.sideEffects = "none";
|
|
2574
|
+
function describeBadPlaceholder(template22, idx, rawExpr) {
|
|
2575
|
+
return `Template placeholder #${idx} (\${${rawExpr}}) in '${template22}'`;
|
|
2284
2576
|
}
|
|
2285
|
-
function
|
|
2286
|
-
|
|
2287
|
-
|
|
2288
|
-
|
|
2289
|
-
|
|
2290
|
-
|
|
2291
|
-
if (s.onSuspendTimeout === void 0) s.onSuspendTimeout = "fail";
|
|
2292
|
-
return;
|
|
2293
|
-
}
|
|
2294
|
-
case "agent":
|
|
2295
|
-
fillPolicy(node, WORKFLOW_AGENT_DEFAULT_TIMEOUT_SECONDS);
|
|
2296
|
-
return;
|
|
2297
|
-
case "tool":
|
|
2298
|
-
fillPolicy(node, WORKFLOW_STEP_DEFAULT_TIMEOUT_SECONDS);
|
|
2299
|
-
return;
|
|
2300
|
-
case "workflow":
|
|
2301
|
-
if (node.workflowId === WORKFLOW_ARM_SUBRUN_ID && Array.isArray(node.graph) && node.graph[1]) fillSingle(node.graph[1]);
|
|
2302
|
-
return;
|
|
2303
|
-
}
|
|
2577
|
+
function parseTemplatePlaceholder(rawExpr) {
|
|
2578
|
+
const dot = rawExpr.indexOf(".");
|
|
2579
|
+
return {
|
|
2580
|
+
scope: dot === -1 ? rawExpr : rawExpr.slice(0, dot),
|
|
2581
|
+
rest: dot === -1 ? "" : rawExpr.slice(dot + 1)
|
|
2582
|
+
};
|
|
2304
2583
|
}
|
|
2305
|
-
function
|
|
2306
|
-
if (
|
|
2307
|
-
|
|
2308
|
-
|
|
2309
|
-
|
|
2310
|
-
if (
|
|
2311
|
-
|
|
2312
|
-
if (a.excludeInitiator === void 0) a.excludeInitiator = false;
|
|
2313
|
-
if (a.editable === void 0) a.editable = false;
|
|
2314
|
-
return;
|
|
2584
|
+
function traverseMappingPath(root, path3, errorLabel) {
|
|
2585
|
+
if (path3 === "" || path3 === ".") return root;
|
|
2586
|
+
const parts = path3.split(".");
|
|
2587
|
+
let value22 = root;
|
|
2588
|
+
for (const part of parts) {
|
|
2589
|
+
if (typeof value22 === "object" && value22 !== null) value22 = value22[part];
|
|
2590
|
+
else throw new WorkflowTemplateError(`Invalid path ${path3} in ${errorLabel}`, path3);
|
|
2315
2591
|
}
|
|
2316
|
-
|
|
2317
|
-
if (w.timeoutHours === void 0) w.timeoutHours = WORKFLOW_SUSPEND_DEFAULT_TIMEOUT_HOURS;
|
|
2318
|
-
if (w.onTimeout === void 0) w.onTimeout = "fail";
|
|
2319
|
-
if (w.acceptedSources === void 0) w.acceptedSources = [
|
|
2320
|
-
...WORKFLOW_SIGNAL_DEFAULT_SOURCES
|
|
2321
|
-
];
|
|
2322
|
-
}
|
|
2323
|
-
function fillArm(arm) {
|
|
2324
|
-
if (arm.type === "mapping") return;
|
|
2325
|
-
if (isHitlNode(arm)) fillHitl(arm);
|
|
2326
|
-
else fillSingle(arm);
|
|
2592
|
+
return value22;
|
|
2327
2593
|
}
|
|
2328
|
-
function
|
|
2329
|
-
|
|
2330
|
-
|
|
2331
|
-
|
|
2332
|
-
|
|
2333
|
-
|
|
2334
|
-
|
|
2335
|
-
return;
|
|
2336
|
-
case "parallel":
|
|
2337
|
-
entry.steps.forEach(fillArm);
|
|
2338
|
-
return;
|
|
2339
|
-
case "conditional": {
|
|
2340
|
-
const c = entry;
|
|
2341
|
-
if (c.exclusive === void 0) c.exclusive = false;
|
|
2342
|
-
c.steps.forEach(fillArm);
|
|
2343
|
-
if (c.otherwise) fillArm(c.otherwise);
|
|
2344
|
-
return;
|
|
2345
|
-
}
|
|
2346
|
-
case "foreach": {
|
|
2347
|
-
const f = entry;
|
|
2348
|
-
f.opts = f.opts ?? {};
|
|
2349
|
-
if (f.opts.concurrency === void 0) f.opts.concurrency = WORKFLOW_FOREACH_DEFAULT_CONCURRENCY;
|
|
2350
|
-
if (f.opts.maxItems === void 0) f.opts.maxItems = WORKFLOW_FOREACH_DEFAULT_MAX_ITEMS;
|
|
2351
|
-
fillArm(f.step);
|
|
2352
|
-
return;
|
|
2353
|
-
}
|
|
2354
|
-
case "loop": {
|
|
2355
|
-
const l = entry;
|
|
2356
|
-
if (l.maxIterations === void 0) l.maxIterations = WORKFLOW_LOOP_DEFAULT_MAX_ITERATIONS;
|
|
2357
|
-
fillArm(l.step);
|
|
2358
|
-
return;
|
|
2594
|
+
function stringifyTemplateValue(v, template22, idx, rawExpr) {
|
|
2595
|
+
if (v === null || v === void 0) return "";
|
|
2596
|
+
if (typeof v === "object") {
|
|
2597
|
+
try {
|
|
2598
|
+
return JSON.stringify(v);
|
|
2599
|
+
} catch (err) {
|
|
2600
|
+
throw new WorkflowTemplateError(`${describeBadPlaceholder(template22, idx, rawExpr)} resolved to a value that could not be JSON-stringified (${err.message}).`, rawExpr);
|
|
2359
2601
|
}
|
|
2360
|
-
case "approval":
|
|
2361
|
-
case "waitForSignal":
|
|
2362
|
-
fillHitl(entry);
|
|
2363
|
-
return;
|
|
2364
|
-
case "mapping":
|
|
2365
|
-
case "sleep":
|
|
2366
|
-
case "sleepUntil":
|
|
2367
|
-
return;
|
|
2368
2602
|
}
|
|
2603
|
+
return String(v);
|
|
2369
2604
|
}
|
|
2370
|
-
function
|
|
2371
|
-
|
|
2372
|
-
out.definition.graph.forEach(fillEntry);
|
|
2373
|
-
return out;
|
|
2374
|
-
}
|
|
2375
|
-
function isConnectionKeyShaped(value22) {
|
|
2376
|
-
return WORKFLOW_CONNECTION_KEY_RE.test(value22) && !CONNECTION_ID_HEX_RE.test(value22);
|
|
2377
|
-
}
|
|
2378
|
-
function connectionKeyUndeclaredMessage(path3, key) {
|
|
2379
|
-
return `${path3} '${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`;
|
|
2605
|
+
function escapeFence(content) {
|
|
2606
|
+
return content.replace(/<\/lua-data/g, "<\\/lua-data");
|
|
2380
2607
|
}
|
|
2381
|
-
function
|
|
2382
|
-
|
|
2383
|
-
if (!m) return null;
|
|
2384
|
-
if (/^(anthropic\/|claude)/.test(m)) return "anthropic";
|
|
2385
|
-
if (/^(openai\/|gpt-|o[1-9](-|$)|chatgpt)/.test(m)) return "openai";
|
|
2386
|
-
if (/^(google\/|gemini)/.test(m)) return "google";
|
|
2387
|
-
return null;
|
|
2608
|
+
function fenceBlock(name, source, content) {
|
|
2609
|
+
return `<lua-data name="${name}" source="${source}" untrusted="true">${escapeFence(content)}</lua-data>`;
|
|
2388
2610
|
}
|
|
2389
|
-
function
|
|
2390
|
-
let
|
|
2391
|
-
|
|
2392
|
-
|
|
2611
|
+
function renderTemplate(template22, ctx, opts) {
|
|
2612
|
+
let idx = 0;
|
|
2613
|
+
return template22.replace(TEMPLATE_PLACEHOLDER, (_match, rawExpr) => {
|
|
2614
|
+
idx += 1;
|
|
2615
|
+
const { scope, rest } = parseTemplatePlaceholder(rawExpr);
|
|
2616
|
+
const label = describeBadPlaceholder(template22, idx, rawExpr);
|
|
2617
|
+
let rendered;
|
|
2618
|
+
let source;
|
|
2619
|
+
switch (scope) {
|
|
2620
|
+
case "initData":
|
|
2621
|
+
rendered = stringifyTemplateValue(traverseMappingPath(ctx.initData, rest, label), template22, idx, rawExpr);
|
|
2622
|
+
source = "initData";
|
|
2623
|
+
break;
|
|
2624
|
+
case "state":
|
|
2625
|
+
rendered = stringifyTemplateValue(traverseMappingPath(ctx.state, rest, label), template22, idx, rawExpr);
|
|
2626
|
+
source = "state";
|
|
2627
|
+
break;
|
|
2628
|
+
case "requestContext":
|
|
2629
|
+
rendered = stringifyTemplateValue(traverseMappingPath(ctx.requestContext, rest, label), template22, idx, rawExpr);
|
|
2630
|
+
source = "requestContext";
|
|
2631
|
+
break;
|
|
2632
|
+
case "stepResults": {
|
|
2633
|
+
const innerDot = rest.indexOf(".");
|
|
2634
|
+
const stepId = innerDot === -1 ? rest : rest.slice(0, innerDot);
|
|
2635
|
+
const subPath = innerDot === -1 ? "" : rest.slice(innerDot + 1);
|
|
2636
|
+
if (!stepId) throw new WorkflowTemplateError(`${label} must name a step: \${stepResults.<stepId>.<path>}.`, rawExpr);
|
|
2637
|
+
if (!(stepId in ctx.stepResults) || ctx.stepResults[stepId] == null) {
|
|
2638
|
+
throw new WorkflowTemplateError(`${label} references stepResults.${stepId} but step "${stepId}" has no resolvable output (not an ancestor, not run, failed, or produced no output).`, rawExpr);
|
|
2639
|
+
}
|
|
2640
|
+
rendered = stringifyTemplateValue(traverseMappingPath(ctx.stepResults[stepId], subPath, label), template22, idx, rawExpr);
|
|
2641
|
+
source = `step:${stepId}`;
|
|
2642
|
+
break;
|
|
2643
|
+
}
|
|
2644
|
+
default:
|
|
2645
|
+
throw new WorkflowTemplateError(`${label} references unknown namespace "${scope}". Use one of: ${TEMPLATE_NAMESPACES.join(", ")}.`, rawExpr);
|
|
2646
|
+
}
|
|
2647
|
+
return opts.fenced ? fenceBlock(rawExpr, source, rendered) : rendered;
|
|
2648
|
+
});
|
|
2649
|
+
}
|
|
2650
|
+
function isMapDescriptor(v) {
|
|
2651
|
+
if (v === null || typeof v !== "object" || Array.isArray(v)) return false;
|
|
2652
|
+
const d = v;
|
|
2653
|
+
const keys = Object.keys(d);
|
|
2654
|
+
const only = /* @__PURE__ */ __name3((...allowed) => keys.every((k) => allowed.includes(k)), "only");
|
|
2655
|
+
if ("value" in d) return keys.length === 1;
|
|
2656
|
+
if ("template" in d) return keys.length === 1 && typeof d.template === "string";
|
|
2657
|
+
if ("requestContextPath" in d) return keys.length === 1 && typeof d.requestContextPath === "string";
|
|
2658
|
+
if ("knowledge" in d) return keys.length === 1 && typeof d.knowledge === "object" && d.knowledge !== null;
|
|
2659
|
+
if ("initData" in d) return d.initData === true && typeof d.path === "string" && only("initData", "path");
|
|
2660
|
+
if ("step" in d) {
|
|
2661
|
+
const stepOk = typeof d.step === "string" || Array.isArray(d.step) && d.step.every((x) => typeof x === "string");
|
|
2662
|
+
return stepOk && typeof d.path === "string" && only("step", "path", "rows");
|
|
2663
|
+
}
|
|
2664
|
+
return false;
|
|
2665
|
+
}
|
|
2666
|
+
function malformedMapMembers(cfg) {
|
|
2667
|
+
if (!cfg || typeof cfg !== "object" || Array.isArray(cfg)) return [];
|
|
2668
|
+
const out = [];
|
|
2669
|
+
for (const [member, v] of Object.entries(cfg)) {
|
|
2670
|
+
if (!v || typeof v !== "object" || Array.isArray(v) || isMapDescriptor(v)) continue;
|
|
2671
|
+
const keys = Object.keys(v).filter((k) => MAP_DESCRIPTOR_KEYS.includes(k));
|
|
2672
|
+
if (keys.length > 0) out.push({
|
|
2673
|
+
member,
|
|
2674
|
+
keys
|
|
2675
|
+
});
|
|
2676
|
+
}
|
|
2677
|
+
return out;
|
|
2678
|
+
}
|
|
2679
|
+
function mapMemberMalformedMessage(id, m) {
|
|
2680
|
+
const keys = m.keys.map((k) => `\`${k}\``).join(", ");
|
|
2681
|
+
return `"${id}".${m.member} carries descriptor key${m.keys.length === 1 ? "" : "s"} ${keys} but is not an exact binding form ({initData:true, path} | {step, path[, rows]} | {value} | {template} | {requestContextPath} | {knowledge}) \u2014 it is passed to the step verbatim as a literal; fix the descriptor, or wrap it in {value: \u2026} if the literal is intended`;
|
|
2682
|
+
}
|
|
2683
|
+
function resolveDescriptor(key, m, ctx) {
|
|
2684
|
+
if (!isMapDescriptor(m)) return {
|
|
2685
|
+
value: m
|
|
2686
|
+
};
|
|
2687
|
+
try {
|
|
2688
|
+
if ("value" in m) return {
|
|
2689
|
+
value: m.value
|
|
2690
|
+
};
|
|
2691
|
+
if ("template" in m && typeof m.template === "string") {
|
|
2692
|
+
return {
|
|
2693
|
+
value: renderTemplate(m.template, ctx, {
|
|
2694
|
+
fenced: false
|
|
2695
|
+
})
|
|
2696
|
+
};
|
|
2697
|
+
}
|
|
2698
|
+
if ("knowledge" in m || "rows" in m && m.rows !== void 0) {
|
|
2699
|
+
return {
|
|
2700
|
+
error: "binding_unresolved",
|
|
2701
|
+
key
|
|
2702
|
+
};
|
|
2703
|
+
}
|
|
2704
|
+
if ("requestContextPath" in m) {
|
|
2705
|
+
const label = `requestContext path for key "${key}"`;
|
|
2706
|
+
return {
|
|
2707
|
+
value: traverseMappingPath(ctx.requestContext, m.requestContextPath, label)
|
|
2708
|
+
};
|
|
2709
|
+
}
|
|
2710
|
+
if ("path" in m) {
|
|
2711
|
+
const source = "initData" in m && m.initData ? "initData" : "step";
|
|
2712
|
+
if (source === "initData") {
|
|
2713
|
+
return {
|
|
2714
|
+
value: traverseMappingPath(ctx.initData, m.path, `initData for key "${key}"`)
|
|
2715
|
+
};
|
|
2716
|
+
}
|
|
2717
|
+
const stepRef = m.step;
|
|
2718
|
+
const candidates = Array.isArray(stepRef) ? stepRef : [
|
|
2719
|
+
stepRef
|
|
2720
|
+
];
|
|
2721
|
+
const stepId = candidates.find((s) => ctx.stepResults[s] !== void 0 && ctx.stepResults[s] !== null);
|
|
2722
|
+
if (stepId === void 0) return {
|
|
2723
|
+
error: "binding_unresolved",
|
|
2724
|
+
key
|
|
2725
|
+
};
|
|
2726
|
+
return {
|
|
2727
|
+
value: traverseMappingPath(ctx.stepResults[stepId], m.path, `step ${candidates.join("|")} for key "${key}"`)
|
|
2728
|
+
};
|
|
2729
|
+
}
|
|
2730
|
+
return {
|
|
2731
|
+
error: "binding_unresolved",
|
|
2732
|
+
key
|
|
2733
|
+
};
|
|
2734
|
+
} catch (err) {
|
|
2735
|
+
if (err instanceof WorkflowTemplateError) return {
|
|
2736
|
+
error: "binding_unresolved",
|
|
2737
|
+
key
|
|
2738
|
+
};
|
|
2739
|
+
throw err;
|
|
2740
|
+
}
|
|
2741
|
+
}
|
|
2742
|
+
function resolveMapping(cfg, ctx) {
|
|
2743
|
+
const keys = Object.keys(cfg);
|
|
2744
|
+
if (keys.length === 1 && keys[0] === "") {
|
|
2745
|
+
return resolveDescriptor("", cfg[""], ctx);
|
|
2746
|
+
}
|
|
2747
|
+
const result = {};
|
|
2748
|
+
for (const key of keys) {
|
|
2749
|
+
const resolved = resolveDescriptor(key, cfg[key], ctx);
|
|
2750
|
+
if ("error" in resolved) return resolved;
|
|
2751
|
+
result[key] = resolved.value;
|
|
2752
|
+
}
|
|
2753
|
+
return {
|
|
2754
|
+
value: result
|
|
2755
|
+
};
|
|
2756
|
+
}
|
|
2757
|
+
function describeApproverSpecRefusal(spec) {
|
|
2758
|
+
const raw = spec === void 0 ? "undefined" : JSON.stringify(spec) ?? String(spec);
|
|
2759
|
+
const written = raw.length > APPROVER_WRITTEN_MAX ? `${raw.slice(0, APPROVER_WRITTEN_MAX - 1)}\u2026` : raw;
|
|
2760
|
+
const users = typeof spec === "object" && spec !== null ? spec.users : void 0;
|
|
2761
|
+
const approver = typeof users === "string" && USER_ID_SHAPED_RE.test(users) ? {
|
|
2762
|
+
users: [
|
|
2763
|
+
users
|
|
2764
|
+
]
|
|
2765
|
+
} : "creator";
|
|
2766
|
+
const message = `approver ${written} is not an approver \u2014 legal: ${APPROVER_SPEC_SHAPES.join(" | ")}. 'creator' is the person who started the run: write approver:'creator' for "ask me" / "I approve"; {users:[\u2026]} takes user ids, never emails, names or {type:'user'}` + (approver === "creator" ? "" : `; here: approver:${JSON.stringify(approver)}`);
|
|
2767
|
+
return {
|
|
2768
|
+
approver,
|
|
2769
|
+
written,
|
|
2770
|
+
message
|
|
2771
|
+
};
|
|
2772
|
+
}
|
|
2773
|
+
function bindingRootsOk(template22) {
|
|
2774
|
+
const refs = [
|
|
2775
|
+
...template22.matchAll(/\$\{\s*([A-Za-z_$][\w$]*)/g)
|
|
2776
|
+
].map((m) => m[1]);
|
|
2777
|
+
return refs.length > 0 && refs.every((r) => BINDING_ROOTS.includes(r));
|
|
2778
|
+
}
|
|
2779
|
+
function isTemplateBinding(v) {
|
|
2780
|
+
return typeof v === "object" && v !== null && typeof v.template === "string";
|
|
2781
|
+
}
|
|
2782
|
+
function approvalEditable(node) {
|
|
2783
|
+
if (node.editable === true) return true;
|
|
2784
|
+
if (node.editable === false) return false;
|
|
2785
|
+
return Array.isArray(node.editablePaths) && node.editablePaths.length > 0;
|
|
2786
|
+
}
|
|
2787
|
+
function validateApproverBlock(node, opts = {
|
|
2788
|
+
path: "approval"
|
|
2789
|
+
}) {
|
|
2790
|
+
const issues = [];
|
|
2791
|
+
const push = /* @__PURE__ */ __name3((code, path3, message, severity = "error") => issues.push({
|
|
2792
|
+
code,
|
|
2793
|
+
path: path3,
|
|
2794
|
+
severity,
|
|
2795
|
+
message
|
|
2796
|
+
}), "push");
|
|
2797
|
+
const checkSpec = /* @__PURE__ */ __name3((spec, path3) => {
|
|
2798
|
+
const r = ApproverSpecSchema.safeParse(spec);
|
|
2799
|
+
if (!r.success) {
|
|
2800
|
+
const users = spec?.users;
|
|
2801
|
+
if (Array.isArray(users) && users.length > APPROVER_SPEC_MAX_USERS) push("cap-exceeded", path3, `at most ${APPROVER_SPEC_MAX_USERS} users`);
|
|
2802
|
+
else {
|
|
2803
|
+
const refusal = describeApproverSpecRefusal(spec);
|
|
2804
|
+
issues.push({
|
|
2805
|
+
code: "approver-invalid",
|
|
2806
|
+
path: path3,
|
|
2807
|
+
severity: "error",
|
|
2808
|
+
message: refusal.message,
|
|
2809
|
+
repair: {
|
|
2810
|
+
approver: refusal.approver,
|
|
2811
|
+
written: refusal.written
|
|
2812
|
+
}
|
|
2813
|
+
});
|
|
2814
|
+
}
|
|
2815
|
+
return;
|
|
2816
|
+
}
|
|
2817
|
+
const s = r.data;
|
|
2818
|
+
if (typeof s === "object") {
|
|
2819
|
+
if ("governance" in s && !opts.governanceEnabled) push("approver-governance-unavailable", path3, "governance reviewer routing is not enabled for this deployment");
|
|
2820
|
+
if ("group" in s && typeof s.group === "string" && !opts.scimEnabled && opts.idpGroups?.includes(s.group)) push("approver-idp-group-unavailable", path3, "IdP-group approvers are not enabled for this deployment");
|
|
2821
|
+
const binding = "users" in s ? s.users : "role" in s ? s.role : "group" in s ? s.group : void 0;
|
|
2822
|
+
if (isTemplateBinding(binding)) {
|
|
2823
|
+
if (!bindingRootsOk(binding.template)) push("approver-binding-invalid", `${path3}.template`, "binding root must be initData / stepResults / requestContext / state");
|
|
2824
|
+
if ("users" in s && opts.customerReachable) push("approver-binding-customer-reachable", `${path3}.users`, "a customer-reachable workflow may not bind its approver list");
|
|
2825
|
+
}
|
|
2826
|
+
}
|
|
2827
|
+
}, "checkSpec");
|
|
2828
|
+
if (node.approver !== void 0) checkSpec(node.approver, `${opts.path}.approver`);
|
|
2829
|
+
if (node.fourEyes !== void 0) {
|
|
2830
|
+
const r = FourEyesSchema.safeParse(node.fourEyes);
|
|
2831
|
+
if (!r.success) push("approver-invalid", `${opts.path}.fourEyes`, "fourEyes needs { edit, approve } approver specs");
|
|
2832
|
+
else {
|
|
2833
|
+
checkSpec(r.data.edit, `${opts.path}.fourEyes.edit`);
|
|
2834
|
+
checkSpec(r.data.approve, `${opts.path}.fourEyes.approve`);
|
|
2835
|
+
}
|
|
2836
|
+
if (!approvalEditable(node)) push("four-eyes-requires-editable", `${opts.path}.fourEyes`, "fourEyes requires editable:true");
|
|
2837
|
+
if (node.approver !== void 0) push("four-eyes-overrides-approver", `${opts.path}.approver`, "fourEyes replaces approver", "warning");
|
|
2838
|
+
if (node.itemsPath) push("four-eyes-items-unsupported", `${opts.path}.fourEyes`, "fourEyes cannot combine with itemsPath");
|
|
2839
|
+
}
|
|
2840
|
+
if (node.excludeInitiator && (node.approver === void 0 || node.approver === "creator") && !node.fourEyes) push("approver-excludes-only-candidate", `${opts.path}.excludeInitiator`, "'creator' with excludeInitiator leaves no approver");
|
|
2841
|
+
if (Array.isArray(node.onTimeout)) {
|
|
2842
|
+
const chain = node.onTimeout;
|
|
2843
|
+
const hops = chain.filter((m) => typeof m === "object" && m !== null && "escalateTo" in m);
|
|
2844
|
+
if (hops.length > ESCALATION_MAX_HOPS) push("escalation-chain-too-long", `${opts.path}.onTimeout`, `at most ${ESCALATION_MAX_HOPS} hops`);
|
|
2845
|
+
const last = chain[chain.length - 1];
|
|
2846
|
+
if (typeof last === "object" && last !== null) push("escalation-chain-not-terminal", `${opts.path}.onTimeout`, "a chain must end in deny | cancel-run | fail");
|
|
2847
|
+
hops.forEach((h, i) => checkSpec(h.escalateTo, `${opts.path}.onTimeout[${i}].escalateTo`));
|
|
2848
|
+
} else if (typeof node.onTimeout === "object" && node.onTimeout !== null) {
|
|
2849
|
+
checkSpec(node.onTimeout.escalateTo, `${opts.path}.onTimeout.escalateTo`);
|
|
2850
|
+
}
|
|
2851
|
+
return issues;
|
|
2852
|
+
}
|
|
2853
|
+
function liftRenderedApprover(row, rendered) {
|
|
2854
|
+
const text = (rendered ?? "").trim();
|
|
2855
|
+
if (!text) return null;
|
|
2856
|
+
if (row === "users") {
|
|
2857
|
+
let members = null;
|
|
2858
|
+
if (text.startsWith("[")) {
|
|
2859
|
+
try {
|
|
2860
|
+
members = JSON.parse(text);
|
|
2861
|
+
} catch {
|
|
2862
|
+
return null;
|
|
2863
|
+
}
|
|
2864
|
+
} else members = text.split(",").map((s) => s.trim());
|
|
2865
|
+
if (!Array.isArray(members) || members.length === 0 || members.length > APPROVER_SPEC_MAX_USERS) return null;
|
|
2866
|
+
if (!members.every((m) => typeof m === "string" && m.length > 0 && m.length <= 128)) return null;
|
|
2867
|
+
return {
|
|
2868
|
+
users: [
|
|
2869
|
+
...new Set(members)
|
|
2870
|
+
].sort()
|
|
2871
|
+
};
|
|
2872
|
+
}
|
|
2873
|
+
if (text.length > 128 || text.startsWith("[") || text.startsWith("{")) return null;
|
|
2874
|
+
return row === "role" ? {
|
|
2875
|
+
role: text
|
|
2876
|
+
} : {
|
|
2877
|
+
group: text
|
|
2878
|
+
};
|
|
2879
|
+
}
|
|
2880
|
+
function workspaceTemplatePath(template22) {
|
|
2881
|
+
const key = template22.trim();
|
|
2882
|
+
const expr = WORKSPACE_TEMPLATE_EXPR_RE.exec(key);
|
|
2883
|
+
if (expr) return expr[1].split(".");
|
|
2884
|
+
if (key.includes("${")) return void 0;
|
|
2885
|
+
return key.replace(/^(?:input|initData)\./, "").split(".");
|
|
2886
|
+
}
|
|
2887
|
+
function retryBackoffs() {
|
|
2888
|
+
if (!Array.isArray(WORKFLOW_RETRY_BACKOFFS)) {
|
|
2889
|
+
throw new Error("@lua/shared-types.WORKFLOW_RETRY_BACKOFFS is not a tuple \u2014 a jest.mock('@lua/shared-types') must spread jest.requireActual('@lua/shared-types')");
|
|
2890
|
+
}
|
|
2891
|
+
return WORKFLOW_RETRY_BACKOFFS;
|
|
2892
|
+
}
|
|
2893
|
+
function sleepUntilUnsupportedMessage(id) {
|
|
2894
|
+
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} }`;
|
|
2895
|
+
}
|
|
2896
|
+
function armSubrunUnsupportedMessage(id, workflowId) {
|
|
2897
|
+
return `the engine does not execute the implicit \`${workflowId}\` arm subrun (node "${id}") \u2014 a [map, step] container arm is the step itself with the map as its \`input\` since lua-cli 3.32.4; re-run \`lua compile\` with the current CLI (a hand-written artifact: put the map on the arm node's \`input\` and drop the \`workflow\` wrapper)`;
|
|
2898
|
+
}
|
|
2899
|
+
function fillPolicy(node, defaultTimeout) {
|
|
2900
|
+
if (node.tier === void 0 && node.workspace !== void 0 && node.workspace !== "inherit") node.tier = "job";
|
|
2901
|
+
if (node.timeoutSeconds === void 0) node.timeoutSeconds = node.tier === "job" ? WORKFLOW_JOB_DEFAULT_TIMEOUT_SECONDS : defaultTimeout;
|
|
2902
|
+
if (node.retry === void 0) node.retry = {
|
|
2903
|
+
maxAttempts: 1
|
|
2904
|
+
};
|
|
2905
|
+
if (node.onError === void 0) node.onError = "fail";
|
|
2906
|
+
if ((node.type === "step" || node.type === "tool") && node.sideEffects === void 0) node.sideEffects = "none";
|
|
2907
|
+
}
|
|
2908
|
+
function fillSingle(node) {
|
|
2909
|
+
switch (node.type) {
|
|
2910
|
+
case "step": {
|
|
2911
|
+
fillPolicy(node, WORKFLOW_STEP_DEFAULT_TIMEOUT_SECONDS);
|
|
2912
|
+
const s = node;
|
|
2913
|
+
if (s.resumeTimeoutHours === void 0) s.resumeTimeoutHours = WORKFLOW_SUSPEND_DEFAULT_TIMEOUT_HOURS;
|
|
2914
|
+
if (s.onSuspendTimeout === void 0) s.onSuspendTimeout = "fail";
|
|
2915
|
+
return;
|
|
2916
|
+
}
|
|
2917
|
+
case "agent":
|
|
2918
|
+
fillPolicy(node, WORKFLOW_AGENT_DEFAULT_TIMEOUT_SECONDS);
|
|
2919
|
+
return;
|
|
2920
|
+
case "tool":
|
|
2921
|
+
fillPolicy(node, WORKFLOW_STEP_DEFAULT_TIMEOUT_SECONDS);
|
|
2922
|
+
return;
|
|
2923
|
+
case "workflow":
|
|
2924
|
+
return;
|
|
2925
|
+
}
|
|
2926
|
+
}
|
|
2927
|
+
function fillHitl(node) {
|
|
2928
|
+
if (node.type === "approval") {
|
|
2929
|
+
const a = node;
|
|
2930
|
+
if (a.approver === void 0) a.approver = "creator";
|
|
2931
|
+
if (a.timeoutHours === void 0) a.timeoutHours = WORKFLOW_SUSPEND_DEFAULT_TIMEOUT_HOURS;
|
|
2932
|
+
if (a.onTimeout === void 0) a.onTimeout = "deny";
|
|
2933
|
+
if (a.onDeny === void 0) a.onDeny = "continue";
|
|
2934
|
+
if (a.excludeInitiator === void 0) a.excludeInitiator = false;
|
|
2935
|
+
if (a.editable === void 0) a.editable = false;
|
|
2936
|
+
return;
|
|
2937
|
+
}
|
|
2938
|
+
const w = node;
|
|
2939
|
+
if (w.timeoutHours === void 0) w.timeoutHours = WORKFLOW_SUSPEND_DEFAULT_TIMEOUT_HOURS;
|
|
2940
|
+
if (w.onTimeout === void 0) w.onTimeout = "fail";
|
|
2941
|
+
if (w.acceptedSources === void 0) w.acceptedSources = [
|
|
2942
|
+
...WORKFLOW_SIGNAL_DEFAULT_SOURCES
|
|
2943
|
+
];
|
|
2944
|
+
}
|
|
2945
|
+
function fillArm(arm) {
|
|
2946
|
+
if (arm.type === "mapping") return;
|
|
2947
|
+
if (isHitlNode(arm)) fillHitl(arm);
|
|
2948
|
+
else fillSingle(arm);
|
|
2949
|
+
}
|
|
2950
|
+
function fillEntry(entry) {
|
|
2951
|
+
switch (entry.type) {
|
|
2952
|
+
case "step":
|
|
2953
|
+
case "agent":
|
|
2954
|
+
case "tool":
|
|
2955
|
+
case "workflow":
|
|
2956
|
+
fillSingle(entry);
|
|
2957
|
+
return;
|
|
2958
|
+
case "parallel":
|
|
2959
|
+
entry.steps.forEach(fillArm);
|
|
2960
|
+
return;
|
|
2961
|
+
case "conditional": {
|
|
2962
|
+
const c = entry;
|
|
2963
|
+
if (c.exclusive === void 0) c.exclusive = false;
|
|
2964
|
+
c.steps.forEach(fillArm);
|
|
2965
|
+
if (c.otherwise) fillArm(c.otherwise);
|
|
2966
|
+
return;
|
|
2967
|
+
}
|
|
2968
|
+
case "foreach": {
|
|
2969
|
+
const f = entry;
|
|
2970
|
+
f.opts = f.opts ?? {};
|
|
2971
|
+
if (f.opts.concurrency === void 0) f.opts.concurrency = WORKFLOW_FOREACH_DEFAULT_CONCURRENCY;
|
|
2972
|
+
if (f.opts.maxItems === void 0) f.opts.maxItems = WORKFLOW_FOREACH_DEFAULT_MAX_ITEMS;
|
|
2973
|
+
fillArm(f.step);
|
|
2974
|
+
return;
|
|
2975
|
+
}
|
|
2976
|
+
case "loop": {
|
|
2977
|
+
const l = entry;
|
|
2978
|
+
if (l.maxIterations === void 0) l.maxIterations = WORKFLOW_LOOP_DEFAULT_MAX_ITERATIONS;
|
|
2979
|
+
fillArm(l.step);
|
|
2980
|
+
return;
|
|
2981
|
+
}
|
|
2982
|
+
case "approval":
|
|
2983
|
+
case "waitForSignal":
|
|
2984
|
+
fillHitl(entry);
|
|
2985
|
+
return;
|
|
2986
|
+
case "mapping":
|
|
2987
|
+
case "sleep":
|
|
2988
|
+
case "sleepUntil":
|
|
2989
|
+
return;
|
|
2990
|
+
}
|
|
2991
|
+
}
|
|
2992
|
+
function withDefaultsFilled(g) {
|
|
2993
|
+
const out = clone(g);
|
|
2994
|
+
out.definition.graph.forEach(fillEntry);
|
|
2995
|
+
return out;
|
|
2996
|
+
}
|
|
2997
|
+
function isConnectionKeyShaped(value22) {
|
|
2998
|
+
return WORKFLOW_CONNECTION_KEY_RE.test(value22) && !CONNECTION_ID_HEX_RE.test(value22);
|
|
2999
|
+
}
|
|
3000
|
+
function connectionKeyUndeclaredMessage(path3, key) {
|
|
3001
|
+
return `${path3} '${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`;
|
|
3002
|
+
}
|
|
3003
|
+
function classifyModelProvider(model) {
|
|
3004
|
+
const m = (model ?? "").trim().toLowerCase();
|
|
3005
|
+
if (!m) return null;
|
|
3006
|
+
if (/^(anthropic\/|claude)/.test(m)) return "anthropic";
|
|
3007
|
+
if (/^(openai\/|gpt-|o[1-9](-|$)|chatgpt)/.test(m)) return "openai";
|
|
3008
|
+
if (/^(google\/|gemini)/.test(m)) return "google";
|
|
3009
|
+
return null;
|
|
3010
|
+
}
|
|
3011
|
+
function schemaAtPath(schema, path3) {
|
|
3012
|
+
let cur = schema;
|
|
3013
|
+
if (!cur || typeof cur !== "object") return void 0;
|
|
3014
|
+
for (const seg of path3.split(".").filter(Boolean)) {
|
|
2393
3015
|
const props = cur.properties;
|
|
2394
3016
|
const next = props?.[seg];
|
|
2395
3017
|
if (!next || typeof next !== "object") return void 0;
|
|
@@ -2417,12 +3039,11 @@ function mapConfigStepRefs(raw) {
|
|
|
2417
3039
|
if (!cfg) return [];
|
|
2418
3040
|
const ids = [];
|
|
2419
3041
|
for (const d of Object.values(cfg)) {
|
|
2420
|
-
if (!d
|
|
2421
|
-
|
|
2422
|
-
|
|
2423
|
-
desc.step
|
|
3042
|
+
if (!isMapDescriptor(d)) continue;
|
|
3043
|
+
if ("step" in d) ids.push(...Array.isArray(d.step) ? d.step : [
|
|
3044
|
+
d.step
|
|
2424
3045
|
]);
|
|
2425
|
-
if (
|
|
3046
|
+
if ("template" in d) ids.push(...templateStepRefs(d.template));
|
|
2426
3047
|
}
|
|
2427
3048
|
return ids;
|
|
2428
3049
|
}
|
|
@@ -2431,8 +3052,14 @@ function nodeStepRefs(entry) {
|
|
|
2431
3052
|
case "agent": {
|
|
2432
3053
|
const a = entry;
|
|
2433
3054
|
const p = a.promptTemplate;
|
|
2434
|
-
|
|
3055
|
+
const prompt = typeof p === "string" ? templateStepRefs(p) : p && "template" in p ? templateStepRefs(p.template) : [];
|
|
3056
|
+
return [
|
|
3057
|
+
...prompt,
|
|
3058
|
+
...mapConfigStepRefs(a.input)
|
|
3059
|
+
];
|
|
2435
3060
|
}
|
|
3061
|
+
case "step":
|
|
3062
|
+
return mapConfigStepRefs(entry.input);
|
|
2436
3063
|
case "tool":
|
|
2437
3064
|
return mapConfigStepRefs(entry.input);
|
|
2438
3065
|
case "workflow":
|
|
@@ -2547,6 +3174,12 @@ function validateLuaExtensions(g, caps = WORKFLOW_CAPS_DEFAULT, opts = {
|
|
|
2547
3174
|
const r = node.retry;
|
|
2548
3175
|
if (!r) return;
|
|
2549
3176
|
const id = singleId(node);
|
|
3177
|
+
const unknown = unknownWorkflowRetryMembers(r);
|
|
3178
|
+
if (unknown.length) err("invalid-envelope", workflowRetryUnknownMembersMessage(unknown), `${path3}.retry`, id);
|
|
3179
|
+
if (r.maxAttempts !== void 0 && !isWithinWorkflowRetryAttempts(r.maxAttempts)) {
|
|
3180
|
+
const over = typeof r.maxAttempts === "number" && r.maxAttempts > WORKFLOW_RETRY_MAX_ATTEMPTS;
|
|
3181
|
+
err(over ? "cap-exceeded" : "invalid-envelope", workflowRetryMaxAttemptsMessage(r.maxAttempts), `${path3}.retry.maxAttempts`, id);
|
|
3182
|
+
}
|
|
2550
3183
|
const backoffs = retryBackoffs();
|
|
2551
3184
|
if (r.backoff !== void 0 && !backoffs.includes(r.backoff)) {
|
|
2552
3185
|
const list = backoffs.map((b) => `'${b}'`).join(" | ");
|
|
@@ -2643,6 +3276,21 @@ function validateLuaExtensions(g, caps = WORKFLOW_CAPS_DEFAULT, opts = {
|
|
|
2643
3276
|
err("job-tier-provider-unsupported", `model provider '${provider}' is outside LUA_WF_JOB_PROVIDERS [${opts.policy.jobProviders.join(", ")}]`, `${path3}.model`, id);
|
|
2644
3277
|
}
|
|
2645
3278
|
}, "checkTier");
|
|
3279
|
+
const checkModel = /* @__PURE__ */ __name3((node, path3) => {
|
|
3280
|
+
if (node.type !== "agent" || typeof node.model !== "string") return;
|
|
3281
|
+
const registry = opts.approvedModels;
|
|
3282
|
+
if (registry === void 0) return;
|
|
3283
|
+
const id = singleId(node);
|
|
3284
|
+
if (registry === "unavailable") {
|
|
3285
|
+
const pin = node.model.trim();
|
|
3286
|
+
if (pin && !normalizeModelId(pin, []).ok) {
|
|
3287
|
+
warn("model-unresolved", `model "${pin}" could not be checked against the approved-model registry (unavailable at push) \u2014 it dispatches only if it resolves there (a provider/model registry code, or a bare id exactly one approved model carries)`, `${path3}.model`, id);
|
|
3288
|
+
}
|
|
3289
|
+
return;
|
|
3290
|
+
}
|
|
3291
|
+
const resolved = normalizeModelId(node.model, registry);
|
|
3292
|
+
if (!resolved.ok) err("model-unresolved", modelUnresolvedMessage(resolved), `${path3}.model`, id);
|
|
3293
|
+
}, "checkModel");
|
|
2646
3294
|
const checkWorkspace = /* @__PURE__ */ __name3((node, path3) => {
|
|
2647
3295
|
const id = singleId(node);
|
|
2648
3296
|
const ws = workspaceOf(node);
|
|
@@ -2689,35 +3337,43 @@ function validateLuaExtensions(g, caps = WORKFLOW_CAPS_DEFAULT, opts = {
|
|
|
2689
3337
|
const schema = node.type === "step" ? node.step.outputSchema : node.type === "agent" ? node.outputSchema : void 0;
|
|
2690
3338
|
if (schema !== void 0) outputSchemas.set(singleId(node), schema);
|
|
2691
3339
|
}, "recordOutputSchema");
|
|
3340
|
+
const checkMapMembers = /* @__PURE__ */ __name3((cfg, basePath, id) => {
|
|
3341
|
+
for (const m of malformedMapMembers(cfg)) {
|
|
3342
|
+
warn(MAP_MEMBER_MALFORMED_CODE, mapMemberMalformedMessage(id, m), `${basePath}.${m.member}`, id);
|
|
3343
|
+
}
|
|
3344
|
+
}, "checkMapMembers");
|
|
3345
|
+
const checkInputShape = /* @__PURE__ */ __name3((node, path3) => {
|
|
3346
|
+
const input = node.input;
|
|
3347
|
+
if (input === void 0) return;
|
|
3348
|
+
const id = singleId(node);
|
|
3349
|
+
if (input !== null && typeof input === "object" && !Array.isArray(input)) {
|
|
3350
|
+
checkMapMembers(input, `${path3}.input`, id);
|
|
3351
|
+
return;
|
|
3352
|
+
}
|
|
3353
|
+
err("invalid-envelope", `\`input\` must be an object map \u2014 each member a binding descriptor ({initData:true, path} | {step, path} | {value} | {template} | {requestContextPath}) or a JSON literal (got ${JSON.stringify(input)})`, `${path3}.input`, id);
|
|
3354
|
+
}, "checkInputShape");
|
|
3355
|
+
const checkBodyInput = /* @__PURE__ */ __name3((body, path3, container) => {
|
|
3356
|
+
if (body.type === "workflow" || body.input === void 0) return;
|
|
3357
|
+
err("arm-input-unsupported", container === "foreach" ? `a foreach body receives each item as its input \u2014 drop \`input\` on "${singleId(body)}" and map the items before the foreach instead` : `a loop body receives the previous output as its input \u2014 drop \`input\` on "${singleId(body)}" and put the map before the loop instead`, `${path3}.input`, singleId(body));
|
|
3358
|
+
}, "checkBodyInput");
|
|
2692
3359
|
const checkSingle = /* @__PURE__ */ __name3((node, path3, depth) => {
|
|
2693
3360
|
recordOutputSchema(node);
|
|
2694
|
-
if (node.type === "workflow" && node.workflowId ===
|
|
3361
|
+
if (node.type === "workflow" && (typeof node.workflowId !== "string" || node.workflowId.length === 0)) {
|
|
2695
3362
|
checkId(node.id, path3);
|
|
2696
|
-
|
|
2697
|
-
|
|
2698
|
-
|
|
2699
|
-
|
|
2700
|
-
|
|
2701
|
-
|
|
2702
|
-
err("container-arm-empty", "a bare mapping arm has nothing to run", `${path3}.graph.1`, node.id);
|
|
2703
|
-
return;
|
|
2704
|
-
}
|
|
2705
|
-
const inner = body[1];
|
|
2706
|
-
if (isHitlNode(inner)) {
|
|
2707
|
-
err("node-type-unsupported-in-container", workflowHitlArmShapeMessage(inner.type, inner.id, "mapped-arm"), `${path3}.graph.1`, inner.id);
|
|
2708
|
-
return;
|
|
2709
|
-
}
|
|
2710
|
-
upstream.add(singleId(body[1]));
|
|
2711
|
-
checkArm(body[0], `${path3}.graph.0`, depth, "parallel");
|
|
2712
|
-
checkSingle(body[1], `${path3}.graph.1`, depth);
|
|
2713
|
-
upstream.add(body[0].id);
|
|
2714
|
-
upstream.add(singleId(body[1]));
|
|
3363
|
+
err("invalid-envelope", `\`workflowId\` must be a non-empty string naming the workflow to start (got ${JSON.stringify(node.workflowId)})`, `${path3}.workflowId`, node.id);
|
|
3364
|
+
return;
|
|
3365
|
+
}
|
|
3366
|
+
if (node.type === "workflow" && (node.workflowId.startsWith("$") || Array.isArray(node.graph))) {
|
|
3367
|
+
checkId(node.id, path3);
|
|
3368
|
+
err("node-type-unsupported-by-engine", armSubrunUnsupportedMessage(node.id, node.workflowId), path3, node.id);
|
|
2715
3369
|
return;
|
|
2716
3370
|
}
|
|
2717
3371
|
checkId(singleId(node), path3);
|
|
2718
3372
|
checkPolicyEnums(node, path3);
|
|
3373
|
+
checkInputShape(node, path3);
|
|
2719
3374
|
checkTimeout(node, path3);
|
|
2720
3375
|
checkTier(node, path3);
|
|
3376
|
+
checkModel(node, path3);
|
|
2721
3377
|
checkRetry(node, path3);
|
|
2722
3378
|
checkWorkspace(node, path3);
|
|
2723
3379
|
if (!opts.static) {
|
|
@@ -2740,7 +3396,7 @@ function validateLuaExtensions(g, caps = WORKFLOW_CAPS_DEFAULT, opts = {
|
|
|
2740
3396
|
if (node.type === "workflow" && node.kind === "subrun" && depth > caps.maxNestingDepth) {
|
|
2741
3397
|
err("cap-exceeded", `nesting depth ${depth} exceeds ${caps.maxNestingDepth}`, path3, node.id);
|
|
2742
3398
|
}
|
|
2743
|
-
if (node.type === "workflow" &&
|
|
3399
|
+
if (node.type === "workflow" && typeof g.definition?.id === "string" && node.workflowId === g.definition.id) {
|
|
2744
3400
|
err("subrun-cycle", `"${node.id}" starts "${node.workflowId}", which is this workflow itself`, path3, node.id);
|
|
2745
3401
|
}
|
|
2746
3402
|
for (const ref of nodeStepRefs(node)) {
|
|
@@ -2761,11 +3417,14 @@ function validateLuaExtensions(g, caps = WORKFLOW_CAPS_DEFAULT, opts = {
|
|
|
2761
3417
|
if (a.approver === "creator" && a.excludeInitiator === true) {
|
|
2762
3418
|
err("approver-excludes-only-candidate", "approver:'creator' with excludeInitiator:true always excludes the only candidate", path3, a.id);
|
|
2763
3419
|
}
|
|
2764
|
-
|
|
3420
|
+
const editable = approvalEditable(a);
|
|
3421
|
+
if (a.fourEyes !== void 0 && !editable) {
|
|
2765
3422
|
err("four-eyes-requires-editable", "`fourEyes` requires editable:true", `${path3}.fourEyes`, a.id);
|
|
2766
3423
|
}
|
|
2767
|
-
if (
|
|
2768
|
-
err("editable-path-invalid", "`editablePaths`
|
|
3424
|
+
if (a.editable === false && Array.isArray(a.editablePaths) && a.editablePaths.length > 0) {
|
|
3425
|
+
err("editable-path-invalid", "`editablePaths` beside editable:false is contradictory \u2014 drop the paths or set editable:true", `${path3}.editablePaths`, a.id);
|
|
3426
|
+
} else if ((a.editablePaths !== void 0 || a.editedPayloadSchema !== void 0) && !editable) {
|
|
3427
|
+
err("editable-path-invalid", "`editablePaths` / `editedPayloadSchema` require editable:true (a non-empty editablePaths implies it)", `${path3}.editablePaths`, a.id);
|
|
2769
3428
|
}
|
|
2770
3429
|
for (const p of a.editablePaths ?? []) {
|
|
2771
3430
|
if (!EDITABLE_PATH_RE.test(p)) err("editable-path-invalid", `editablePaths entry "${p}" is outside the seg(.seg)*[*]/[n] grammar`, `${path3}.editablePaths`, a.id);
|
|
@@ -2796,6 +3455,7 @@ function validateLuaExtensions(g, caps = WORKFLOW_CAPS_DEFAULT, opts = {
|
|
|
2796
3455
|
const checkArm = /* @__PURE__ */ __name3((arm, path3, depth, container) => {
|
|
2797
3456
|
if (arm.type === "mapping") {
|
|
2798
3457
|
checkId(arm.id, path3);
|
|
3458
|
+
checkMapMembers(readMapConfig(arm.mapConfig), `${path3}.mapConfig`, arm.id);
|
|
2799
3459
|
for (const ref of nodeStepRefs(arm)) {
|
|
2800
3460
|
if (!upstream.has(ref)) err("template-reference-unresolved", `"${arm.id}" references stepResults.${ref}, which is not upstream`, path3, arm.id);
|
|
2801
3461
|
}
|
|
@@ -2820,6 +3480,7 @@ function validateLuaExtensions(g, caps = WORKFLOW_CAPS_DEFAULT, opts = {
|
|
|
2820
3480
|
break;
|
|
2821
3481
|
case "mapping":
|
|
2822
3482
|
checkId(entry.id, path3);
|
|
3483
|
+
checkMapMembers(readMapConfig(entry.mapConfig), `${path3}.mapConfig`, entry.id);
|
|
2823
3484
|
for (const ref of nodeStepRefs(entry)) {
|
|
2824
3485
|
if (!upstream.has(ref)) err("template-reference-unresolved", `"${entry.id}" references stepResults.${ref}, which is not upstream`, path3, entry.id);
|
|
2825
3486
|
}
|
|
@@ -2944,6 +3605,7 @@ function validateLuaExtensions(g, caps = WORKFLOW_CAPS_DEFAULT, opts = {
|
|
|
2944
3605
|
} else checkHitlArm(f.step, `${path3}.step`, "foreach");
|
|
2945
3606
|
declared.push(f.step.id);
|
|
2946
3607
|
} else {
|
|
3608
|
+
checkBodyInput(f.step, `${path3}.step`, "foreach");
|
|
2947
3609
|
checkSingle(f.step, `${path3}.step`, o.chunk ? 2 : 1);
|
|
2948
3610
|
declared.push(singleId(f.step));
|
|
2949
3611
|
}
|
|
@@ -2964,6 +3626,7 @@ function validateLuaExtensions(g, caps = WORKFLOW_CAPS_DEFAULT, opts = {
|
|
|
2964
3626
|
checkHitlArm(l.step, `${path3}.step`, "loop");
|
|
2965
3627
|
declared.push(l.step.id);
|
|
2966
3628
|
} else {
|
|
3629
|
+
checkBodyInput(l.step, `${path3}.step`, "loop");
|
|
2967
3630
|
checkSingle(l.step, `${path3}.step`, 1);
|
|
2968
3631
|
declared.push(singleId(l.step));
|
|
2969
3632
|
}
|
|
@@ -3358,230 +4021,64 @@ function renderPredicate(pred) {
|
|
|
3358
4021
|
return `${renderRef(pred.value)} in ${JSON.stringify(pred.set)}`;
|
|
3359
4022
|
case "notIn":
|
|
3360
4023
|
return `${renderRef(pred.value)} not in ${JSON.stringify(pred.set)}`;
|
|
3361
|
-
case "eq":
|
|
3362
|
-
return `${renderRef(pred.left)} == ${renderRef(pred.right)}`;
|
|
3363
|
-
case "ne":
|
|
3364
|
-
return `${renderRef(pred.left)} != ${renderRef(pred.right)}`;
|
|
3365
|
-
case "lt":
|
|
3366
|
-
return `${renderRef(pred.left)} < ${renderRef(pred.right)}`;
|
|
3367
|
-
case "lte":
|
|
3368
|
-
return `${renderRef(pred.left)} <= ${renderRef(pred.right)}`;
|
|
3369
|
-
case "gt":
|
|
3370
|
-
return `${renderRef(pred.left)} > ${renderRef(pred.right)}`;
|
|
3371
|
-
case "gte":
|
|
3372
|
-
return `${renderRef(pred.left)} >= ${renderRef(pred.right)}`;
|
|
3373
|
-
}
|
|
3374
|
-
}
|
|
3375
|
-
function wrapLabel(child, rendered) {
|
|
3376
|
-
return child.op === "and" || child.op === "or" || child.op === "not" ? `(${rendered})` : rendered;
|
|
3377
|
-
}
|
|
3378
|
-
function renderRef(ref) {
|
|
3379
|
-
if ("literal" in ref) return JSON.stringify(ref.literal);
|
|
3380
|
-
return ref.path;
|
|
3381
|
-
}
|
|
3382
|
-
function step(s) {
|
|
3383
|
-
const id = stepIdOf(s);
|
|
3384
|
-
return {
|
|
3385
|
-
path: /* @__PURE__ */ __name3((p) => ({
|
|
3386
|
-
path: p === "" ? `stepResults.${id}` : `stepResults.${id}.${p}`
|
|
3387
|
-
}), "path")
|
|
3388
|
-
};
|
|
3389
|
-
}
|
|
3390
|
-
function stepOf(id) {
|
|
3391
|
-
return step(id);
|
|
3392
|
-
}
|
|
3393
|
-
function init(path3) {
|
|
3394
|
-
return {
|
|
3395
|
-
path: path3 === "" ? "initData" : `initData.${path3}`
|
|
3396
|
-
};
|
|
3397
|
-
}
|
|
3398
|
-
function state(path3) {
|
|
3399
|
-
return {
|
|
3400
|
-
path: path3 === "" ? "state" : `state.${path3}`
|
|
3401
|
-
};
|
|
3402
|
-
}
|
|
3403
|
-
function lit(v) {
|
|
3404
|
-
return {
|
|
3405
|
-
literal: v
|
|
3406
|
-
};
|
|
3407
|
-
}
|
|
3408
|
-
function toPathOrLiteral(v) {
|
|
3409
|
-
if (typeof v === "object" && v !== null) {
|
|
3410
|
-
if ("path" in v) return {
|
|
3411
|
-
path: v.path
|
|
3412
|
-
};
|
|
3413
|
-
if ("literal" in v) return {
|
|
3414
|
-
literal: v.literal
|
|
3415
|
-
};
|
|
3416
|
-
}
|
|
3417
|
-
return {
|
|
3418
|
-
literal: v
|
|
3419
|
-
};
|
|
3420
|
-
}
|
|
3421
|
-
function isMapConfigObject(v) {
|
|
3422
|
-
return typeof v === "object" && v !== null && !Array.isArray(v);
|
|
3423
|
-
}
|
|
3424
|
-
function parseMapConfig(raw, stepId) {
|
|
3425
|
-
if (isMapConfigObject(raw)) return raw;
|
|
3426
|
-
if (typeof raw !== "string") {
|
|
3427
|
-
throw new Error(`Stored mapping step "${stepId}" has a mapConfig that is neither a JSON string nor an object.`);
|
|
3428
|
-
}
|
|
3429
|
-
try {
|
|
3430
|
-
return JSON.parse(raw);
|
|
3431
|
-
} catch (e) {
|
|
3432
|
-
throw new Error(`Stored mapping step "${stepId}" has invalid JSON mapConfig: ${e.message}`);
|
|
3433
|
-
}
|
|
3434
|
-
}
|
|
3435
|
-
function mapConfigWire(raw) {
|
|
3436
|
-
if (typeof raw === "string") return raw;
|
|
3437
|
-
if (isMapConfigObject(raw)) return canonicalJson(raw);
|
|
3438
|
-
return void 0;
|
|
3439
|
-
}
|
|
3440
|
-
function describeBadPlaceholder(template22, idx, rawExpr) {
|
|
3441
|
-
return `Template placeholder #${idx} (\${${rawExpr}}) in '${template22}'`;
|
|
3442
|
-
}
|
|
3443
|
-
function parseTemplatePlaceholder(rawExpr) {
|
|
3444
|
-
const dot = rawExpr.indexOf(".");
|
|
3445
|
-
return {
|
|
3446
|
-
scope: dot === -1 ? rawExpr : rawExpr.slice(0, dot),
|
|
3447
|
-
rest: dot === -1 ? "" : rawExpr.slice(dot + 1)
|
|
3448
|
-
};
|
|
3449
|
-
}
|
|
3450
|
-
function traverseMappingPath(root, path3, errorLabel) {
|
|
3451
|
-
if (path3 === "" || path3 === ".") return root;
|
|
3452
|
-
const parts = path3.split(".");
|
|
3453
|
-
let value22 = root;
|
|
3454
|
-
for (const part of parts) {
|
|
3455
|
-
if (typeof value22 === "object" && value22 !== null) value22 = value22[part];
|
|
3456
|
-
else throw new WorkflowTemplateError(`Invalid path ${path3} in ${errorLabel}`, path3);
|
|
3457
|
-
}
|
|
3458
|
-
return value22;
|
|
3459
|
-
}
|
|
3460
|
-
function stringifyTemplateValue(v, template22, idx, rawExpr) {
|
|
3461
|
-
if (v === null || v === void 0) return "";
|
|
3462
|
-
if (typeof v === "object") {
|
|
3463
|
-
try {
|
|
3464
|
-
return JSON.stringify(v);
|
|
3465
|
-
} catch (err) {
|
|
3466
|
-
throw new WorkflowTemplateError(`${describeBadPlaceholder(template22, idx, rawExpr)} resolved to a value that could not be JSON-stringified (${err.message}).`, rawExpr);
|
|
3467
|
-
}
|
|
3468
|
-
}
|
|
3469
|
-
return String(v);
|
|
3470
|
-
}
|
|
3471
|
-
function escapeFence(content) {
|
|
3472
|
-
return content.replace(/<\/lua-data/g, "<\\/lua-data");
|
|
3473
|
-
}
|
|
3474
|
-
function fenceBlock(name, source, content) {
|
|
3475
|
-
return `<lua-data name="${name}" source="${source}" untrusted="true">${escapeFence(content)}</lua-data>`;
|
|
3476
|
-
}
|
|
3477
|
-
function renderTemplate(template22, ctx, opts) {
|
|
3478
|
-
let idx = 0;
|
|
3479
|
-
return template22.replace(TEMPLATE_PLACEHOLDER, (_match, rawExpr) => {
|
|
3480
|
-
idx += 1;
|
|
3481
|
-
const { scope, rest } = parseTemplatePlaceholder(rawExpr);
|
|
3482
|
-
const label = describeBadPlaceholder(template22, idx, rawExpr);
|
|
3483
|
-
let rendered;
|
|
3484
|
-
let source;
|
|
3485
|
-
switch (scope) {
|
|
3486
|
-
case "initData":
|
|
3487
|
-
rendered = stringifyTemplateValue(traverseMappingPath(ctx.initData, rest, label), template22, idx, rawExpr);
|
|
3488
|
-
source = "initData";
|
|
3489
|
-
break;
|
|
3490
|
-
case "state":
|
|
3491
|
-
rendered = stringifyTemplateValue(traverseMappingPath(ctx.state, rest, label), template22, idx, rawExpr);
|
|
3492
|
-
source = "state";
|
|
3493
|
-
break;
|
|
3494
|
-
case "requestContext":
|
|
3495
|
-
rendered = stringifyTemplateValue(traverseMappingPath(ctx.requestContext, rest, label), template22, idx, rawExpr);
|
|
3496
|
-
source = "requestContext";
|
|
3497
|
-
break;
|
|
3498
|
-
case "stepResults": {
|
|
3499
|
-
const innerDot = rest.indexOf(".");
|
|
3500
|
-
const stepId = innerDot === -1 ? rest : rest.slice(0, innerDot);
|
|
3501
|
-
const subPath = innerDot === -1 ? "" : rest.slice(innerDot + 1);
|
|
3502
|
-
if (!stepId) throw new WorkflowTemplateError(`${label} must name a step: \${stepResults.<stepId>.<path>}.`, rawExpr);
|
|
3503
|
-
if (!(stepId in ctx.stepResults) || ctx.stepResults[stepId] == null) {
|
|
3504
|
-
throw new WorkflowTemplateError(`${label} references stepResults.${stepId} but step "${stepId}" has no resolvable output (not an ancestor, not run, failed, or produced no output).`, rawExpr);
|
|
3505
|
-
}
|
|
3506
|
-
rendered = stringifyTemplateValue(traverseMappingPath(ctx.stepResults[stepId], subPath, label), template22, idx, rawExpr);
|
|
3507
|
-
source = `step:${stepId}`;
|
|
3508
|
-
break;
|
|
3509
|
-
}
|
|
3510
|
-
default:
|
|
3511
|
-
throw new WorkflowTemplateError(`${label} references unknown namespace "${scope}". Use one of: ${TEMPLATE_NAMESPACES.join(", ")}.`, rawExpr);
|
|
3512
|
-
}
|
|
3513
|
-
return opts.fenced ? fenceBlock(rawExpr, source, rendered) : rendered;
|
|
3514
|
-
});
|
|
3515
|
-
}
|
|
3516
|
-
function resolveDescriptor(key, m, ctx) {
|
|
3517
|
-
try {
|
|
3518
|
-
if ("value" in m) return {
|
|
3519
|
-
value: m.value
|
|
3520
|
-
};
|
|
3521
|
-
if ("template" in m && typeof m.template === "string") {
|
|
3522
|
-
return {
|
|
3523
|
-
value: renderTemplate(m.template, ctx, {
|
|
3524
|
-
fenced: false
|
|
3525
|
-
})
|
|
3526
|
-
};
|
|
3527
|
-
}
|
|
3528
|
-
if ("knowledge" in m || "rows" in m && m.rows !== void 0) {
|
|
3529
|
-
return {
|
|
3530
|
-
error: "binding_unresolved",
|
|
3531
|
-
key
|
|
3532
|
-
};
|
|
3533
|
-
}
|
|
3534
|
-
if ("requestContextPath" in m) {
|
|
3535
|
-
const label = `requestContext path for key "${key}"`;
|
|
3536
|
-
return {
|
|
3537
|
-
value: traverseMappingPath(ctx.requestContext, m.requestContextPath, label)
|
|
3538
|
-
};
|
|
3539
|
-
}
|
|
3540
|
-
if ("path" in m) {
|
|
3541
|
-
const source = "initData" in m && m.initData ? "initData" : "step";
|
|
3542
|
-
if (source === "initData") {
|
|
3543
|
-
return {
|
|
3544
|
-
value: traverseMappingPath(ctx.initData, m.path, `initData for key "${key}"`)
|
|
3545
|
-
};
|
|
3546
|
-
}
|
|
3547
|
-
const stepRef = m.step;
|
|
3548
|
-
const candidates = Array.isArray(stepRef) ? stepRef : [
|
|
3549
|
-
stepRef
|
|
3550
|
-
];
|
|
3551
|
-
const stepId = candidates.find((s) => ctx.stepResults[s] !== void 0 && ctx.stepResults[s] !== null);
|
|
3552
|
-
if (stepId === void 0) return {
|
|
3553
|
-
error: "binding_unresolved",
|
|
3554
|
-
key
|
|
3555
|
-
};
|
|
3556
|
-
return {
|
|
3557
|
-
value: traverseMappingPath(ctx.stepResults[stepId], m.path, `step ${candidates.join("|")} for key "${key}"`)
|
|
3558
|
-
};
|
|
3559
|
-
}
|
|
3560
|
-
return {
|
|
3561
|
-
error: "binding_unresolved",
|
|
3562
|
-
key
|
|
3563
|
-
};
|
|
3564
|
-
} catch (err) {
|
|
3565
|
-
if (err instanceof WorkflowTemplateError) return {
|
|
3566
|
-
error: "binding_unresolved",
|
|
3567
|
-
key
|
|
3568
|
-
};
|
|
3569
|
-
throw err;
|
|
4024
|
+
case "eq":
|
|
4025
|
+
return `${renderRef(pred.left)} == ${renderRef(pred.right)}`;
|
|
4026
|
+
case "ne":
|
|
4027
|
+
return `${renderRef(pred.left)} != ${renderRef(pred.right)}`;
|
|
4028
|
+
case "lt":
|
|
4029
|
+
return `${renderRef(pred.left)} < ${renderRef(pred.right)}`;
|
|
4030
|
+
case "lte":
|
|
4031
|
+
return `${renderRef(pred.left)} <= ${renderRef(pred.right)}`;
|
|
4032
|
+
case "gt":
|
|
4033
|
+
return `${renderRef(pred.left)} > ${renderRef(pred.right)}`;
|
|
4034
|
+
case "gte":
|
|
4035
|
+
return `${renderRef(pred.left)} >= ${renderRef(pred.right)}`;
|
|
3570
4036
|
}
|
|
3571
4037
|
}
|
|
3572
|
-
function
|
|
3573
|
-
|
|
3574
|
-
|
|
3575
|
-
|
|
3576
|
-
|
|
3577
|
-
|
|
3578
|
-
|
|
3579
|
-
|
|
3580
|
-
|
|
3581
|
-
|
|
4038
|
+
function wrapLabel(child, rendered) {
|
|
4039
|
+
return child.op === "and" || child.op === "or" || child.op === "not" ? `(${rendered})` : rendered;
|
|
4040
|
+
}
|
|
4041
|
+
function renderRef(ref) {
|
|
4042
|
+
if ("literal" in ref) return JSON.stringify(ref.literal);
|
|
4043
|
+
return ref.path;
|
|
4044
|
+
}
|
|
4045
|
+
function step(s) {
|
|
4046
|
+
const id = stepIdOf(s);
|
|
4047
|
+
return {
|
|
4048
|
+
path: /* @__PURE__ */ __name3((p) => ({
|
|
4049
|
+
path: p === "" ? `stepResults.${id}` : `stepResults.${id}.${p}`
|
|
4050
|
+
}), "path")
|
|
4051
|
+
};
|
|
4052
|
+
}
|
|
4053
|
+
function stepOf(id) {
|
|
4054
|
+
return step(id);
|
|
4055
|
+
}
|
|
4056
|
+
function init(path3) {
|
|
4057
|
+
return {
|
|
4058
|
+
path: path3 === "" ? "initData" : `initData.${path3}`
|
|
4059
|
+
};
|
|
4060
|
+
}
|
|
4061
|
+
function state(path3) {
|
|
4062
|
+
return {
|
|
4063
|
+
path: path3 === "" ? "state" : `state.${path3}`
|
|
4064
|
+
};
|
|
4065
|
+
}
|
|
4066
|
+
function lit(v) {
|
|
4067
|
+
return {
|
|
4068
|
+
literal: v
|
|
4069
|
+
};
|
|
4070
|
+
}
|
|
4071
|
+
function toPathOrLiteral(v) {
|
|
4072
|
+
if (typeof v === "object" && v !== null) {
|
|
4073
|
+
if ("path" in v) return {
|
|
4074
|
+
path: v.path
|
|
4075
|
+
};
|
|
4076
|
+
if ("literal" in v) return {
|
|
4077
|
+
literal: v.literal
|
|
4078
|
+
};
|
|
3582
4079
|
}
|
|
3583
4080
|
return {
|
|
3584
|
-
|
|
4081
|
+
literal: v
|
|
3585
4082
|
};
|
|
3586
4083
|
}
|
|
3587
4084
|
function continuedFailureValue(error, killReason) {
|
|
@@ -3603,17 +4100,10 @@ function isContinuedFailureValue(v) {
|
|
|
3603
4100
|
const err = o.error;
|
|
3604
4101
|
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";
|
|
3605
4102
|
}
|
|
3606
|
-
function
|
|
3607
|
-
const stepId = nodeIdOf(step22);
|
|
4103
|
+
function inlineContainerArm(mapping, step22) {
|
|
3608
4104
|
return {
|
|
3609
|
-
|
|
3610
|
-
|
|
3611
|
-
workflowId: WORKFLOW_ARM_SUBRUN_ID,
|
|
3612
|
-
kind: "subrun",
|
|
3613
|
-
graph: [
|
|
3614
|
-
mapping,
|
|
3615
|
-
step22
|
|
3616
|
-
]
|
|
4105
|
+
...step22,
|
|
4106
|
+
input: parseMapConfig(mapping.mapConfig, mapping.id)
|
|
3617
4107
|
};
|
|
3618
4108
|
}
|
|
3619
4109
|
function entryIds(entry) {
|
|
@@ -3683,6 +4173,27 @@ function resolvePlacements(calls) {
|
|
|
3683
4173
|
break;
|
|
3684
4174
|
}
|
|
3685
4175
|
});
|
|
4176
|
+
const armMapPlacementIssue = /* @__PURE__ */ __name3((node, ref, i, container) => {
|
|
4177
|
+
if (!ref.armMap || node.type === "mapping" || isHitlNode2(node)) return void 0;
|
|
4178
|
+
const id = nodeIdOf(node);
|
|
4179
|
+
if ((container === "foreach" || container === "loop") && node.type !== "workflow") {
|
|
4180
|
+
return {
|
|
4181
|
+
code: "mapping-placement",
|
|
4182
|
+
message: container === "foreach" ? `foreach body "${id}": a [map, step] body is not supported \u2014 the body receives each item as its input; map the items before the foreach instead (foreach(step, { items: \u2026 }) or a .map() before it)` : `loop body "${id}": a [map, step] body is not supported \u2014 the body receives the previous output as its input; put the .map() before the loop instead`,
|
|
4183
|
+
callIndex: i,
|
|
4184
|
+
stepId: id
|
|
4185
|
+
};
|
|
4186
|
+
}
|
|
4187
|
+
if (node.input !== void 0) {
|
|
4188
|
+
return {
|
|
4189
|
+
code: "mapping-placement",
|
|
4190
|
+
message: `"${id}": the [map, step] arm mapping and the node's own input map would both bind its input \u2014 keep one (drop the arm map, or the \`input\` on the declaration)`,
|
|
4191
|
+
callIndex: i,
|
|
4192
|
+
stepId: id
|
|
4193
|
+
};
|
|
4194
|
+
}
|
|
4195
|
+
return void 0;
|
|
4196
|
+
}, "armMapPlacementIssue");
|
|
3686
4197
|
const hitlPlacementIssue = /* @__PURE__ */ __name3((node, ref, i, container) => {
|
|
3687
4198
|
if (!isHitlNode2(node)) return void 0;
|
|
3688
4199
|
const id = node.id;
|
|
@@ -3709,7 +4220,7 @@ function resolvePlacements(calls) {
|
|
|
3709
4220
|
if (ref.node.type === "mapping" && !allowMapping) {
|
|
3710
4221
|
issues.push({
|
|
3711
4222
|
code: "mapping-placement",
|
|
3712
|
-
message: `mapping "${ref.node.id}" cannot be a container arm \u2014 chain it as [map, step]`,
|
|
4223
|
+
message: `mapping "${ref.node.id}" cannot be a container arm \u2014 chain it as [map, step] in a parallel / conditional arm, or place the .map() before the container`,
|
|
3713
4224
|
callIndex: i,
|
|
3714
4225
|
stepId: ref.node.id
|
|
3715
4226
|
});
|
|
@@ -3730,7 +4241,7 @@ function resolvePlacements(calls) {
|
|
|
3730
4241
|
if (d.node.type === "mapping" && !allowMapping) {
|
|
3731
4242
|
issues.push({
|
|
3732
4243
|
code: "mapping-placement",
|
|
3733
|
-
message: `map "${ref.ref}" cannot be a parallel/foreach/loop arm \u2014 chain it as [map, step]`,
|
|
4244
|
+
message: `map "${ref.ref}" cannot be a parallel/foreach/loop arm \u2014 chain it as [map, step] in a parallel arm, or place the .map() before the container`,
|
|
3734
4245
|
callIndex: i,
|
|
3735
4246
|
stepId: ref.ref
|
|
3736
4247
|
});
|
|
@@ -3741,6 +4252,11 @@ function resolvePlacements(calls) {
|
|
|
3741
4252
|
issues.push(hitl);
|
|
3742
4253
|
return void 0;
|
|
3743
4254
|
}
|
|
4255
|
+
const mapped = armMapPlacementIssue(d.node, ref, i, container);
|
|
4256
|
+
if (mapped) {
|
|
4257
|
+
issues.push(mapped);
|
|
4258
|
+
return void 0;
|
|
4259
|
+
}
|
|
3744
4260
|
const prior = placedBy.get(ref.ref);
|
|
3745
4261
|
if (prior !== void 0 && prior !== i) {
|
|
3746
4262
|
issues.push({
|
|
@@ -3761,6 +4277,10 @@ function resolvePlacements(calls) {
|
|
|
3761
4277
|
}
|
|
3762
4278
|
const hitl = hitlPlacementIssue(ref.node, ref, i, container);
|
|
3763
4279
|
if (hitl) issues.push(hitl);
|
|
4280
|
+
else {
|
|
4281
|
+
const mapped = armMapPlacementIssue(ref.node, ref, i, container);
|
|
4282
|
+
if (mapped) issues.push(mapped);
|
|
4283
|
+
}
|
|
3764
4284
|
}, "claim");
|
|
3765
4285
|
calls.forEach((call, i) => {
|
|
3766
4286
|
switch (call.kind) {
|
|
@@ -3788,7 +4308,7 @@ function resolvePlacements(calls) {
|
|
|
3788
4308
|
const lookup = /* @__PURE__ */ __name3((ref) => {
|
|
3789
4309
|
const n2 = "node" in ref ? ref.node : declared.get(ref.ref)?.node;
|
|
3790
4310
|
if (!n2 || !ref.armMap || n2.type === "mapping" || isHitlNode2(n2)) return n2;
|
|
3791
|
-
return
|
|
4311
|
+
return inlineContainerArm(ref.armMap, n2);
|
|
3792
4312
|
}, "lookup");
|
|
3793
4313
|
calls.forEach((call, i) => {
|
|
3794
4314
|
switch (call.kind) {
|
|
@@ -4173,6 +4693,27 @@ function isTerminalRunStatus(status) {
|
|
|
4173
4693
|
function pruneUndefined(o) {
|
|
4174
4694
|
return Object.fromEntries(Object.entries(o).filter(([, v]) => v !== void 0));
|
|
4175
4695
|
}
|
|
4696
|
+
function runOrigin(run) {
|
|
4697
|
+
if (run.goalId) return "goal";
|
|
4698
|
+
if (run.jobId || run.trigger === "schedule") return "schedule";
|
|
4699
|
+
if (run.dynamic === true) return run.tags?.includes(WORKFLOW_INLINE_RUN_TAG) ? "inline" : "compose";
|
|
4700
|
+
return "definition";
|
|
4701
|
+
}
|
|
4702
|
+
function runErrorIssues(issues) {
|
|
4703
|
+
if (!Array.isArray(issues)) return void 0;
|
|
4704
|
+
const out = [];
|
|
4705
|
+
for (const raw of issues.slice(0, RUN_ERROR_ISSUES_MAX)) {
|
|
4706
|
+
if (!raw || typeof raw !== "object") continue;
|
|
4707
|
+
const o = raw;
|
|
4708
|
+
if (typeof o.code !== "string" || !o.code) continue;
|
|
4709
|
+
out.push(pruneUndefined({
|
|
4710
|
+
code: o.code,
|
|
4711
|
+
path: typeof o.path === "string" ? o.path : void 0,
|
|
4712
|
+
message: typeof o.message === "string" ? o.message : void 0
|
|
4713
|
+
}));
|
|
4714
|
+
}
|
|
4715
|
+
return out.length ? out : void 0;
|
|
4716
|
+
}
|
|
4176
4717
|
function runNextAction(run) {
|
|
4177
4718
|
if (isTerminalRunStatus(run.status)) return "none";
|
|
4178
4719
|
if (run.status === "suspended" && run.gate?.kind === "budget") return "raise_budget";
|
|
@@ -4218,15 +4759,64 @@ function runCounts(counts) {
|
|
|
4218
4759
|
pending: n(c.pending) + n(c.ready) + n(c.waiting)
|
|
4219
4760
|
};
|
|
4220
4761
|
}
|
|
4221
|
-
function
|
|
4762
|
+
function isPricedStepReceipt(receipt) {
|
|
4763
|
+
return typeof receipt?.multiplier === "number" && Number.isFinite(receipt.multiplier);
|
|
4764
|
+
}
|
|
4765
|
+
function receiptEngine(engine) {
|
|
4766
|
+
if (engine === "actions") return "seat";
|
|
4767
|
+
if (engine === "credits") return "legacy";
|
|
4768
|
+
return void 0;
|
|
4769
|
+
}
|
|
4770
|
+
function receiptTier(tier) {
|
|
4771
|
+
return tier === "light" || tier === "standard" || tier === "heavy" ? tier : void 0;
|
|
4772
|
+
}
|
|
4773
|
+
function stepBillingView(receipt) {
|
|
4774
|
+
const engine = receiptEngine(receipt?.engine);
|
|
4775
|
+
if (!receipt || engine === void 0) return void 0;
|
|
4776
|
+
return pruneUndefined({
|
|
4777
|
+
engine,
|
|
4778
|
+
attempt: typeof receipt.attempt === "number" ? receipt.attempt : void 0,
|
|
4779
|
+
credits: typeof receipt.credits === "number" ? receipt.credits : void 0,
|
|
4780
|
+
actions: typeof receipt.actionsEstimate === "number" ? receipt.actionsEstimate : void 0,
|
|
4781
|
+
model: typeof receipt.model === "string" ? receipt.model : void 0,
|
|
4782
|
+
tier: receiptTier(receipt.tier),
|
|
4783
|
+
multiplier: typeof receipt.multiplier === "number" ? receipt.multiplier : void 0,
|
|
4784
|
+
byok: typeof receipt.byok === "boolean" ? receipt.byok : void 0,
|
|
4785
|
+
calibrated: typeof receipt.calibrated === "boolean" ? receipt.calibrated : void 0
|
|
4786
|
+
});
|
|
4787
|
+
}
|
|
4788
|
+
function runUsage(run, receipts) {
|
|
4789
|
+
const actions = n(run.budget?.spent?.actionsEstimate);
|
|
4790
|
+
const stamped = run.budget?.engine;
|
|
4791
|
+
const priced = (receipts ?? []).filter(isPricedStepReceipt);
|
|
4792
|
+
const engine = stamped === "seat" || stamped === "legacy" ? stamped : actions > 0 || priced.some((r) => r.engine === "actions") ? "seat" : priced.some((r) => r.engine === "credits") ? "legacy" : void 0;
|
|
4793
|
+
const seat = engine === "seat";
|
|
4794
|
+
const metering = engine ? "priced" : "flat";
|
|
4222
4795
|
return {
|
|
4223
4796
|
creditsUsed: run.budget?.spent?.credits ?? 0,
|
|
4224
4797
|
actionsEstimate: run.budget?.spent?.actionsEstimate ?? 0,
|
|
4798
|
+
...seat ? {
|
|
4799
|
+
actionsUsed: actions
|
|
4800
|
+
} : {},
|
|
4801
|
+
metering,
|
|
4802
|
+
...engine ? {
|
|
4803
|
+
engine
|
|
4804
|
+
} : {},
|
|
4225
4805
|
steps: run.budget?.spent?.steps ?? 0,
|
|
4226
4806
|
inputTokens: run.usage?.inputTokens ?? 0,
|
|
4227
4807
|
outputTokens: run.usage?.outputTokens ?? 0
|
|
4228
4808
|
};
|
|
4229
4809
|
}
|
|
4810
|
+
function runBudgetCap(budget) {
|
|
4811
|
+
const cap = budget?.maxCredits;
|
|
4812
|
+
return typeof cap === "number" && Number.isFinite(cap) && cap > 0 ? cap : void 0;
|
|
4813
|
+
}
|
|
4814
|
+
function runBudgetRemaining(budget) {
|
|
4815
|
+
const cap = runBudgetCap(budget);
|
|
4816
|
+
if (cap === void 0) return void 0;
|
|
4817
|
+
const spent = budget?.spent;
|
|
4818
|
+
return Math.max(0, cap - n(spent?.credits) - n(spent?.actionsEstimate) - n(budget?.reserved));
|
|
4819
|
+
}
|
|
4230
4820
|
function runCancelView(cancel) {
|
|
4231
4821
|
if (!cancel) return void 0;
|
|
4232
4822
|
return {
|
|
@@ -4293,6 +4883,7 @@ function toWorkflowRunSummary(run) {
|
|
|
4293
4883
|
repairOf: run.repairOf,
|
|
4294
4884
|
repairRunIds: run.repairRunIds,
|
|
4295
4885
|
trigger: run.trigger ?? "api",
|
|
4886
|
+
origin: runOrigin(run),
|
|
4296
4887
|
createdBy: {
|
|
4297
4888
|
subjectType: principal?.subjectType ?? "system",
|
|
4298
4889
|
subjectId: principal?.subjectId ?? run.userId ?? ""
|
|
@@ -4310,11 +4901,13 @@ function toWorkflowRunSummary(run) {
|
|
|
4310
4901
|
usage: runUsage(run),
|
|
4311
4902
|
// LUA-697: a row persisted before the write seams (#2406 / #2465 / the script tier) leaves scrubbed here too —
|
|
4312
4903
|
// idempotent on a scrubbed message, bounded input; an empty message falls back to the code.
|
|
4313
|
-
error: run.error ? {
|
|
4904
|
+
error: run.error ? pruneUndefined({
|
|
4314
4905
|
code: run.error.code ?? "error",
|
|
4315
4906
|
message: scrubStepErrorMessage(run.error.message) ?? run.error.code ?? "error",
|
|
4316
|
-
stepId: run.error.stepId
|
|
4317
|
-
|
|
4907
|
+
stepId: run.error.stepId,
|
|
4908
|
+
// LUA-784 (item 3): the unattended pre-start failure's refusal rows (`input_schema_invalid` and kin).
|
|
4909
|
+
issues: runErrorIssues(run.error.issues)
|
|
4910
|
+
}) : void 0,
|
|
4318
4911
|
kind: "run",
|
|
4319
4912
|
aclHash: run.aclHash,
|
|
4320
4913
|
migration: run.migration,
|
|
@@ -4753,208 +5346,90 @@ function applyJsonPatch(doc, ops) {
|
|
|
4753
5346
|
if (Array.isArray(parent) && typeof s === "number") parent = parent[s];
|
|
4754
5347
|
else if (typeof parent === "object" && parent !== null && typeof s === "string") parent = parent[s];
|
|
4755
5348
|
else parent = void 0;
|
|
4756
|
-
if (parent === void 0) return {
|
|
4757
|
-
ok: false,
|
|
4758
|
-
code: "PATH_NOT_FOUND",
|
|
4759
|
-
index: i,
|
|
4760
|
-
path: op.path,
|
|
4761
|
-
message: "path not found"
|
|
4762
|
-
};
|
|
4763
|
-
}
|
|
4764
|
-
if (Array.isArray(parent)) {
|
|
4765
|
-
if (last === "-") {
|
|
4766
|
-
if (op.op !== "add") return {
|
|
4767
|
-
ok: false,
|
|
4768
|
-
code: "PATCH_INVALID",
|
|
4769
|
-
index: i,
|
|
4770
|
-
path: op.path,
|
|
4771
|
-
message: "'-' only with add"
|
|
4772
|
-
};
|
|
4773
|
-
parent.push(structuredClone(op.value));
|
|
4774
|
-
continue;
|
|
4775
|
-
}
|
|
4776
|
-
if (typeof last !== "number") return {
|
|
4777
|
-
ok: false,
|
|
4778
|
-
code: "PATCH_INVALID",
|
|
4779
|
-
index: i,
|
|
4780
|
-
path: op.path,
|
|
4781
|
-
message: "array index expected"
|
|
4782
|
-
};
|
|
4783
|
-
if (op.op === "add") {
|
|
4784
|
-
if (last > parent.length) return {
|
|
4785
|
-
ok: false,
|
|
4786
|
-
code: "PATH_NOT_FOUND",
|
|
4787
|
-
index: i,
|
|
4788
|
-
path: op.path,
|
|
4789
|
-
message: "index out of range"
|
|
4790
|
-
};
|
|
4791
|
-
parent.splice(last, 0, structuredClone(op.value));
|
|
4792
|
-
} else if (last >= parent.length) {
|
|
4793
|
-
return {
|
|
4794
|
-
ok: false,
|
|
4795
|
-
code: "PATH_NOT_FOUND",
|
|
4796
|
-
index: i,
|
|
4797
|
-
path: op.path,
|
|
4798
|
-
message: "index out of range"
|
|
4799
|
-
};
|
|
4800
|
-
} else if (op.op === "replace") parent[last] = structuredClone(op.value);
|
|
4801
|
-
else parent.splice(last, 1);
|
|
4802
|
-
continue;
|
|
4803
|
-
}
|
|
4804
|
-
if (typeof parent !== "object" || parent === null || typeof last !== "string" && typeof last !== "number") return {
|
|
4805
|
-
ok: false,
|
|
4806
|
-
code: "PATH_NOT_FOUND",
|
|
4807
|
-
index: i,
|
|
4808
|
-
path: op.path,
|
|
4809
|
-
message: "path not found"
|
|
4810
|
-
};
|
|
4811
|
-
const obj = parent;
|
|
4812
|
-
const key = String(last);
|
|
4813
|
-
if (key === "__proto__" || key === "constructor" || key === "prototype") return {
|
|
4814
|
-
ok: false,
|
|
4815
|
-
code: "PATCH_INVALID",
|
|
4816
|
-
index: i,
|
|
4817
|
-
path: op.path,
|
|
4818
|
-
message: "path not allowed"
|
|
4819
|
-
};
|
|
4820
|
-
if (op.op === "add") obj[key] = structuredClone(op.value);
|
|
4821
|
-
else if (!(key in obj)) return {
|
|
4822
|
-
ok: false,
|
|
4823
|
-
code: "PATH_NOT_FOUND",
|
|
4824
|
-
index: i,
|
|
4825
|
-
path: op.path,
|
|
4826
|
-
message: "path not found"
|
|
4827
|
-
};
|
|
4828
|
-
else if (op.op === "replace") obj[key] = structuredClone(op.value);
|
|
4829
|
-
else delete obj[key];
|
|
4830
|
-
}
|
|
4831
|
-
return {
|
|
4832
|
-
ok: true,
|
|
4833
|
-
value: value22
|
|
4834
|
-
};
|
|
4835
|
-
}
|
|
4836
|
-
function rebaseItemPointer(pointer, itemsPath, index) {
|
|
4837
|
-
const base = `/${itemsPath.split(".").map(escapePointer).join("/")}/${index}`;
|
|
4838
|
-
return pointer === "/" || pointer === "" ? base : `${base}${pointer}`;
|
|
4839
|
-
}
|
|
4840
|
-
function describeApproverSpecRefusal(spec) {
|
|
4841
|
-
const raw = spec === void 0 ? "undefined" : JSON.stringify(spec) ?? String(spec);
|
|
4842
|
-
const written = raw.length > APPROVER_WRITTEN_MAX ? `${raw.slice(0, APPROVER_WRITTEN_MAX - 1)}\u2026` : raw;
|
|
4843
|
-
const users = typeof spec === "object" && spec !== null ? spec.users : void 0;
|
|
4844
|
-
const approver = typeof users === "string" && USER_ID_SHAPED_RE.test(users) ? {
|
|
4845
|
-
users: [
|
|
4846
|
-
users
|
|
4847
|
-
]
|
|
4848
|
-
} : "creator";
|
|
4849
|
-
const message = `approver ${written} is not an approver \u2014 legal: ${APPROVER_SPEC_SHAPES.join(" | ")}. 'creator' is the person who started the run: write approver:'creator' for "ask me" / "I approve"; {users:[\u2026]} takes user ids, never emails, names or {type:'user'}` + (approver === "creator" ? "" : `; here: approver:${JSON.stringify(approver)}`);
|
|
4850
|
-
return {
|
|
4851
|
-
approver,
|
|
4852
|
-
written,
|
|
4853
|
-
message
|
|
4854
|
-
};
|
|
4855
|
-
}
|
|
4856
|
-
function bindingRootsOk(template22) {
|
|
4857
|
-
const refs = [
|
|
4858
|
-
...template22.matchAll(/\$\{\s*([A-Za-z_$][\w$]*)/g)
|
|
4859
|
-
].map((m) => m[1]);
|
|
4860
|
-
return refs.length > 0 && refs.every((r) => BINDING_ROOTS.includes(r));
|
|
4861
|
-
}
|
|
4862
|
-
function isTemplateBinding(v) {
|
|
4863
|
-
return typeof v === "object" && v !== null && typeof v.template === "string";
|
|
4864
|
-
}
|
|
4865
|
-
function validateApproverBlock(node, opts = {
|
|
4866
|
-
path: "approval"
|
|
4867
|
-
}) {
|
|
4868
|
-
const issues = [];
|
|
4869
|
-
const push = /* @__PURE__ */ __name3((code, path3, message, severity = "error") => issues.push({
|
|
4870
|
-
code,
|
|
4871
|
-
path: path3,
|
|
4872
|
-
severity,
|
|
4873
|
-
message
|
|
4874
|
-
}), "push");
|
|
4875
|
-
const checkSpec = /* @__PURE__ */ __name3((spec, path3) => {
|
|
4876
|
-
const r = ApproverSpecSchema.safeParse(spec);
|
|
4877
|
-
if (!r.success) {
|
|
4878
|
-
const users = spec?.users;
|
|
4879
|
-
if (Array.isArray(users) && users.length > APPROVER_SPEC_MAX_USERS) push("cap-exceeded", path3, `at most ${APPROVER_SPEC_MAX_USERS} users`);
|
|
4880
|
-
else {
|
|
4881
|
-
const refusal = describeApproverSpecRefusal(spec);
|
|
4882
|
-
issues.push({
|
|
4883
|
-
code: "approver-invalid",
|
|
4884
|
-
path: path3,
|
|
4885
|
-
severity: "error",
|
|
4886
|
-
message: refusal.message,
|
|
4887
|
-
repair: {
|
|
4888
|
-
approver: refusal.approver,
|
|
4889
|
-
written: refusal.written
|
|
4890
|
-
}
|
|
4891
|
-
});
|
|
4892
|
-
}
|
|
4893
|
-
return;
|
|
4894
|
-
}
|
|
4895
|
-
const s = r.data;
|
|
4896
|
-
if (typeof s === "object") {
|
|
4897
|
-
if ("governance" in s && !opts.governanceEnabled) push("approver-governance-unavailable", path3, "governance reviewer routing is not enabled for this deployment");
|
|
4898
|
-
if ("group" in s && typeof s.group === "string" && !opts.scimEnabled && opts.idpGroups?.includes(s.group)) push("approver-idp-group-unavailable", path3, "IdP-group approvers are not enabled for this deployment");
|
|
4899
|
-
const binding = "users" in s ? s.users : "role" in s ? s.role : "group" in s ? s.group : void 0;
|
|
4900
|
-
if (isTemplateBinding(binding)) {
|
|
4901
|
-
if (!bindingRootsOk(binding.template)) push("approver-binding-invalid", `${path3}.template`, "binding root must be initData / stepResults / requestContext / state");
|
|
4902
|
-
if ("users" in s && opts.customerReachable) push("approver-binding-customer-reachable", `${path3}.users`, "a customer-reachable workflow may not bind its approver list");
|
|
4903
|
-
}
|
|
4904
|
-
}
|
|
4905
|
-
}, "checkSpec");
|
|
4906
|
-
if (node.approver !== void 0) checkSpec(node.approver, `${opts.path}.approver`);
|
|
4907
|
-
if (node.fourEyes !== void 0) {
|
|
4908
|
-
const r = FourEyesSchema.safeParse(node.fourEyes);
|
|
4909
|
-
if (!r.success) push("approver-invalid", `${opts.path}.fourEyes`, "fourEyes needs { edit, approve } approver specs");
|
|
4910
|
-
else {
|
|
4911
|
-
checkSpec(r.data.edit, `${opts.path}.fourEyes.edit`);
|
|
4912
|
-
checkSpec(r.data.approve, `${opts.path}.fourEyes.approve`);
|
|
5349
|
+
if (parent === void 0) return {
|
|
5350
|
+
ok: false,
|
|
5351
|
+
code: "PATH_NOT_FOUND",
|
|
5352
|
+
index: i,
|
|
5353
|
+
path: op.path,
|
|
5354
|
+
message: "path not found"
|
|
5355
|
+
};
|
|
4913
5356
|
}
|
|
4914
|
-
if (
|
|
4915
|
-
|
|
4916
|
-
|
|
4917
|
-
|
|
4918
|
-
|
|
4919
|
-
|
|
4920
|
-
|
|
4921
|
-
|
|
4922
|
-
|
|
4923
|
-
|
|
4924
|
-
|
|
4925
|
-
hops.forEach((h, i) => checkSpec(h.escalateTo, `${opts.path}.onTimeout[${i}].escalateTo`));
|
|
4926
|
-
} else if (typeof node.onTimeout === "object" && node.onTimeout !== null) {
|
|
4927
|
-
checkSpec(node.onTimeout.escalateTo, `${opts.path}.onTimeout.escalateTo`);
|
|
4928
|
-
}
|
|
4929
|
-
return issues;
|
|
4930
|
-
}
|
|
4931
|
-
function liftRenderedApprover(row, rendered) {
|
|
4932
|
-
const text = (rendered ?? "").trim();
|
|
4933
|
-
if (!text) return null;
|
|
4934
|
-
if (row === "users") {
|
|
4935
|
-
let members = null;
|
|
4936
|
-
if (text.startsWith("[")) {
|
|
4937
|
-
try {
|
|
4938
|
-
members = JSON.parse(text);
|
|
4939
|
-
} catch {
|
|
4940
|
-
return null;
|
|
5357
|
+
if (Array.isArray(parent)) {
|
|
5358
|
+
if (last === "-") {
|
|
5359
|
+
if (op.op !== "add") return {
|
|
5360
|
+
ok: false,
|
|
5361
|
+
code: "PATCH_INVALID",
|
|
5362
|
+
index: i,
|
|
5363
|
+
path: op.path,
|
|
5364
|
+
message: "'-' only with add"
|
|
5365
|
+
};
|
|
5366
|
+
parent.push(structuredClone(op.value));
|
|
5367
|
+
continue;
|
|
4941
5368
|
}
|
|
4942
|
-
|
|
4943
|
-
|
|
4944
|
-
|
|
4945
|
-
|
|
4946
|
-
|
|
4947
|
-
|
|
4948
|
-
|
|
5369
|
+
if (typeof last !== "number") return {
|
|
5370
|
+
ok: false,
|
|
5371
|
+
code: "PATCH_INVALID",
|
|
5372
|
+
index: i,
|
|
5373
|
+
path: op.path,
|
|
5374
|
+
message: "array index expected"
|
|
5375
|
+
};
|
|
5376
|
+
if (op.op === "add") {
|
|
5377
|
+
if (last > parent.length) return {
|
|
5378
|
+
ok: false,
|
|
5379
|
+
code: "PATH_NOT_FOUND",
|
|
5380
|
+
index: i,
|
|
5381
|
+
path: op.path,
|
|
5382
|
+
message: "index out of range"
|
|
5383
|
+
};
|
|
5384
|
+
parent.splice(last, 0, structuredClone(op.value));
|
|
5385
|
+
} else if (last >= parent.length) {
|
|
5386
|
+
return {
|
|
5387
|
+
ok: false,
|
|
5388
|
+
code: "PATH_NOT_FOUND",
|
|
5389
|
+
index: i,
|
|
5390
|
+
path: op.path,
|
|
5391
|
+
message: "index out of range"
|
|
5392
|
+
};
|
|
5393
|
+
} else if (op.op === "replace") parent[last] = structuredClone(op.value);
|
|
5394
|
+
else parent.splice(last, 1);
|
|
5395
|
+
continue;
|
|
5396
|
+
}
|
|
5397
|
+
if (typeof parent !== "object" || parent === null || typeof last !== "string" && typeof last !== "number") return {
|
|
5398
|
+
ok: false,
|
|
5399
|
+
code: "PATH_NOT_FOUND",
|
|
5400
|
+
index: i,
|
|
5401
|
+
path: op.path,
|
|
5402
|
+
message: "path not found"
|
|
5403
|
+
};
|
|
5404
|
+
const obj = parent;
|
|
5405
|
+
const key = String(last);
|
|
5406
|
+
if (key === "__proto__" || key === "constructor" || key === "prototype") return {
|
|
5407
|
+
ok: false,
|
|
5408
|
+
code: "PATCH_INVALID",
|
|
5409
|
+
index: i,
|
|
5410
|
+
path: op.path,
|
|
5411
|
+
message: "path not allowed"
|
|
5412
|
+
};
|
|
5413
|
+
if (op.op === "add") obj[key] = structuredClone(op.value);
|
|
5414
|
+
else if (!(key in obj)) return {
|
|
5415
|
+
ok: false,
|
|
5416
|
+
code: "PATH_NOT_FOUND",
|
|
5417
|
+
index: i,
|
|
5418
|
+
path: op.path,
|
|
5419
|
+
message: "path not found"
|
|
4949
5420
|
};
|
|
5421
|
+
else if (op.op === "replace") obj[key] = structuredClone(op.value);
|
|
5422
|
+
else delete obj[key];
|
|
4950
5423
|
}
|
|
4951
|
-
|
|
4952
|
-
|
|
4953
|
-
|
|
4954
|
-
} : {
|
|
4955
|
-
group: text
|
|
5424
|
+
return {
|
|
5425
|
+
ok: true,
|
|
5426
|
+
value: value22
|
|
4956
5427
|
};
|
|
4957
5428
|
}
|
|
5429
|
+
function rebaseItemPointer(pointer, itemsPath, index) {
|
|
5430
|
+
const base = `/${itemsPath.split(".").map(escapePointer).join("/")}/${index}`;
|
|
5431
|
+
return pointer === "/" || pointer === "" ? base : `${base}${pointer}`;
|
|
5432
|
+
}
|
|
4958
5433
|
function collectEnvTemplateKeys(value22) {
|
|
4959
5434
|
const keys = /* @__PURE__ */ new Set();
|
|
4960
5435
|
const walk22 = /* @__PURE__ */ __name3((v) => {
|
|
@@ -5203,7 +5678,6 @@ function* singleStepsOf(entry) {
|
|
|
5203
5678
|
return;
|
|
5204
5679
|
case "workflow":
|
|
5205
5680
|
yield entry;
|
|
5206
|
-
if (Array.isArray(entry.graph)) yield* singleStepsOf(entry.graph[1]);
|
|
5207
5681
|
return;
|
|
5208
5682
|
case "parallel":
|
|
5209
5683
|
case "conditional":
|
|
@@ -5245,7 +5719,7 @@ function needsInheritedWorkspace(graph) {
|
|
|
5245
5719
|
}
|
|
5246
5720
|
return false;
|
|
5247
5721
|
}
|
|
5248
|
-
var __defProp3, __name3, SideEffectsSchema, JobResourcesSchema,
|
|
5722
|
+
var __defProp3, __name3, WorkflowTemplateError, TEMPLATE_PLACEHOLDER, TEMPLATE_NAMESPACES, MAP_DESCRIPTOR_KEYS, MAP_MEMBER_MALFORMED_CODE, fromInit, fromStep, value, template, fromRequest, rows, fromKnowledge, SideEffectsSchema, JobResourcesSchema, APPROVER_SPEC_MAX_USERS, ESCALATION_MAX_HOPS, TemplateBindingSchema, ApproverSpecSchema, FourEyesSchema, EscalationHopSchema, TerminalOutcomeSchema, ApprovalOnTimeoutSchema, APPROVER_SPEC_SHAPES, APPROVER_WRITTEN_MAX, USER_ID_SHAPED_RE, BINDING_ROOTS, WORKSPACE_TEMPLATE_EXPR_RE, SLEEP_UNTIL_REPLACEMENT, WORKFLOW_CAPS_DEFAULT, WORKFLOW_STEP_DEFAULT_TIMEOUT_SECONDS, WORKFLOW_AGENT_DEFAULT_TIMEOUT_SECONDS, WORKFLOW_JOB_DEFAULT_TIMEOUT_SECONDS, WORKFLOW_FOREACH_DEFAULT_CONCURRENCY, WORKFLOW_FOREACH_DEFAULT_MAX_ITEMS, WORKFLOW_LOOP_DEFAULT_MAX_ITERATIONS, WORKFLOW_SUSPEND_DEFAULT_TIMEOUT_HOURS, WORKFLOW_SIGNAL_DEFAULT_SOURCES, clone, CONNECTION_ID_HEX_RE, WORKFLOW_JOB_TOOLS, WORKFLOW_JOB_MAX_WORKTREE_ARMS, workspaceOf, mountsWorkspace, isJobTier, jobToolsOf, schemaIsArray, isHitlNode, isSingleStep, singleId, armId, TEMPLATE_STEP_REF, EDITABLE_PATH_RE, PREDICATE_OPS, isPredicateScalar, GRAPH_HASH_PREFIX, WorkflowPlanError, isArmStep, armStepId, armStepKind, joinIdOf, containerIdOf, PATH_PLACEHOLDER, MISSING, stepIdOf, cmp, eq, ne, gt, gte, lt, lte, inSet, notIn, exists, notExists, truthy, falsy, and, or, not, CONTINUED_FAILURE_TAG, CONTINUED_FAILURE_DEFAULT_CODE, CONTINUED_FAILURE_OUTPUT_SCHEMA, CONTINUED_FAILURE_LEAF_PATHS, isHitlNode2, nodeIdOf, GOAL_JUDGE_STEP_ID, NON_LEAF_KINDS, CONDITIONAL_JOIN_ID, branchArmId, canonical, sortKeys, JOIN, entryOfJoin, FORCE_CANCEL_STALE_MS, TERMINAL, WORKFLOW_INLINE_RUN_TAG, RUN_ERROR_ISSUES_MAX, IN_FLIGHT, n, STEP_ERROR_DETAIL_KEYS, STEP_ERROR_DETAIL_MAX_BYTES, DETAIL_MAX_DEPTH, DETAIL_MAX_ITEMS, MAX_HOLIDAYS, MAX_WALK_DAYS, HHMM, YMD, MS_PER_MIN, MS_PER_DAY, MON_FRI, supportedTz, fmtCache, WEEKDAYS, JSON_PATCH_OPS, JSON_PATCH_MAX_OPS, JSON_PATCH_MAX_VALUE_BYTES, JSON_PATCH_MAX_TOTAL_BYTES, SEGMENT_RE, WORKFLOW_ENV_OVERLAY_MAX_KEYS, WORKFLOW_ENV_OVERLAY_MAX_VALUE_BYTES, WORKFLOW_ENV_TEMPLATE_SECRET_KEY_RE, isEnvRef, looksLikeEmbeddedJson, ZERO, isRecord2;
|
|
5249
5723
|
var init_dist2 = __esm({
|
|
5250
5724
|
"../workflow-graph/dist/index.mjs"() {
|
|
5251
5725
|
"use strict";
|
|
@@ -5258,9 +5732,178 @@ var init_dist2 = __esm({
|
|
|
5258
5732
|
init_dist();
|
|
5259
5733
|
__defProp3 = Object.defineProperty;
|
|
5260
5734
|
__name3 = /* @__PURE__ */ __name((target, value22) => __defProp3(target, "name", { value: value22, configurable: true }), "__name");
|
|
5735
|
+
WorkflowTemplateError = class extends Error {
|
|
5736
|
+
static {
|
|
5737
|
+
__name(this, "WorkflowTemplateError");
|
|
5738
|
+
}
|
|
5739
|
+
static {
|
|
5740
|
+
__name3(this, "WorkflowTemplateError");
|
|
5741
|
+
}
|
|
5742
|
+
placeholder;
|
|
5743
|
+
constructor(message, placeholder) {
|
|
5744
|
+
super(message), this.placeholder = placeholder;
|
|
5745
|
+
this.name = "WorkflowTemplateError";
|
|
5746
|
+
}
|
|
5747
|
+
};
|
|
5748
|
+
__name(isMapConfigObject, "isMapConfigObject");
|
|
5749
|
+
__name3(isMapConfigObject, "isMapConfigObject");
|
|
5750
|
+
__name(parseMapConfig, "parseMapConfig");
|
|
5751
|
+
__name3(parseMapConfig, "parseMapConfig");
|
|
5752
|
+
__name(mapConfigWire, "mapConfigWire");
|
|
5753
|
+
__name3(mapConfigWire, "mapConfigWire");
|
|
5754
|
+
TEMPLATE_PLACEHOLDER = /\$\{([^}]*)\}/g;
|
|
5755
|
+
TEMPLATE_NAMESPACES = [
|
|
5756
|
+
"initData",
|
|
5757
|
+
"state",
|
|
5758
|
+
"requestContext",
|
|
5759
|
+
"stepResults"
|
|
5760
|
+
];
|
|
5761
|
+
__name(describeBadPlaceholder, "describeBadPlaceholder");
|
|
5762
|
+
__name3(describeBadPlaceholder, "describeBadPlaceholder");
|
|
5763
|
+
__name(parseTemplatePlaceholder, "parseTemplatePlaceholder");
|
|
5764
|
+
__name3(parseTemplatePlaceholder, "parseTemplatePlaceholder");
|
|
5765
|
+
__name(traverseMappingPath, "traverseMappingPath");
|
|
5766
|
+
__name3(traverseMappingPath, "traverseMappingPath");
|
|
5767
|
+
__name(stringifyTemplateValue, "stringifyTemplateValue");
|
|
5768
|
+
__name3(stringifyTemplateValue, "stringifyTemplateValue");
|
|
5769
|
+
__name(escapeFence, "escapeFence");
|
|
5770
|
+
__name3(escapeFence, "escapeFence");
|
|
5771
|
+
__name(fenceBlock, "fenceBlock");
|
|
5772
|
+
__name3(fenceBlock, "fenceBlock");
|
|
5773
|
+
__name(renderTemplate, "renderTemplate");
|
|
5774
|
+
__name3(renderTemplate, "renderTemplate");
|
|
5775
|
+
__name(isMapDescriptor, "isMapDescriptor");
|
|
5776
|
+
__name3(isMapDescriptor, "isMapDescriptor");
|
|
5777
|
+
MAP_DESCRIPTOR_KEYS = [
|
|
5778
|
+
"step",
|
|
5779
|
+
"path",
|
|
5780
|
+
"initData",
|
|
5781
|
+
"value",
|
|
5782
|
+
"template",
|
|
5783
|
+
"requestContextPath",
|
|
5784
|
+
"knowledge"
|
|
5785
|
+
];
|
|
5786
|
+
MAP_MEMBER_MALFORMED_CODE = "map-member-malformed";
|
|
5787
|
+
__name(malformedMapMembers, "malformedMapMembers");
|
|
5788
|
+
__name3(malformedMapMembers, "malformedMapMembers");
|
|
5789
|
+
__name(mapMemberMalformedMessage, "mapMemberMalformedMessage");
|
|
5790
|
+
__name3(mapMemberMalformedMessage, "mapMemberMalformedMessage");
|
|
5791
|
+
__name(resolveDescriptor, "resolveDescriptor");
|
|
5792
|
+
__name3(resolveDescriptor, "resolveDescriptor");
|
|
5793
|
+
__name(resolveMapping, "resolveMapping");
|
|
5794
|
+
__name3(resolveMapping, "resolveMapping");
|
|
5795
|
+
fromInit = /* @__PURE__ */ __name3((path3) => ({
|
|
5796
|
+
initData: true,
|
|
5797
|
+
path: path3
|
|
5798
|
+
}), "fromInit");
|
|
5799
|
+
fromStep = /* @__PURE__ */ __name3((s, path3 = "") => {
|
|
5800
|
+
const idOf = /* @__PURE__ */ __name3((x) => typeof x === "string" ? x : x.id, "idOf");
|
|
5801
|
+
return {
|
|
5802
|
+
step: Array.isArray(s) ? s.map(idOf) : idOf(s),
|
|
5803
|
+
path: path3
|
|
5804
|
+
};
|
|
5805
|
+
}, "fromStep");
|
|
5806
|
+
value = /* @__PURE__ */ __name3((v) => ({
|
|
5807
|
+
value: v
|
|
5808
|
+
}), "value");
|
|
5809
|
+
template = /* @__PURE__ */ __name3((s) => ({
|
|
5810
|
+
template: s
|
|
5811
|
+
}), "template");
|
|
5812
|
+
fromRequest = /* @__PURE__ */ __name3((path3) => ({
|
|
5813
|
+
requestContextPath: path3
|
|
5814
|
+
}), "fromRequest");
|
|
5815
|
+
rows = /* @__PURE__ */ __name3((s, path3, page) => ({
|
|
5816
|
+
step: typeof s === "string" ? s : s.id,
|
|
5817
|
+
path: path3,
|
|
5818
|
+
rows: page
|
|
5819
|
+
}), "rows");
|
|
5820
|
+
fromKnowledge = /* @__PURE__ */ __name3((k) => ({
|
|
5821
|
+
knowledge: k
|
|
5822
|
+
}), "fromKnowledge");
|
|
5261
5823
|
SideEffectsSchema = z4.enum(WORKFLOW_SIDE_EFFECTS);
|
|
5262
5824
|
JobResourcesSchema = z4.enum(WORKFLOW_JOB_RESOURCES);
|
|
5263
|
-
|
|
5825
|
+
APPROVER_SPEC_MAX_USERS = 20;
|
|
5826
|
+
ESCALATION_MAX_HOPS = 3;
|
|
5827
|
+
TemplateBindingSchema = z22.object({
|
|
5828
|
+
template: z22.string().min(1).max(2048)
|
|
5829
|
+
}).strict();
|
|
5830
|
+
ApproverSpecSchema = z22.union([
|
|
5831
|
+
z22.literal("creator"),
|
|
5832
|
+
z22.literal("org-admins"),
|
|
5833
|
+
z22.object({
|
|
5834
|
+
users: z22.union([
|
|
5835
|
+
z22.array(z22.string().min(1).max(128)).min(1).max(APPROVER_SPEC_MAX_USERS),
|
|
5836
|
+
TemplateBindingSchema
|
|
5837
|
+
])
|
|
5838
|
+
}).strict(),
|
|
5839
|
+
z22.object({
|
|
5840
|
+
role: z22.union([
|
|
5841
|
+
z22.string().min(1).max(128),
|
|
5842
|
+
TemplateBindingSchema
|
|
5843
|
+
])
|
|
5844
|
+
}).strict(),
|
|
5845
|
+
z22.object({
|
|
5846
|
+
group: z22.union([
|
|
5847
|
+
z22.string().min(1).max(128),
|
|
5848
|
+
TemplateBindingSchema
|
|
5849
|
+
])
|
|
5850
|
+
}).strict(),
|
|
5851
|
+
z22.object({
|
|
5852
|
+
governance: z22.object({
|
|
5853
|
+
policyId: z22.string().min(1).max(128)
|
|
5854
|
+
}).strict()
|
|
5855
|
+
}).strict()
|
|
5856
|
+
]);
|
|
5857
|
+
FourEyesSchema = z22.object({
|
|
5858
|
+
edit: ApproverSpecSchema,
|
|
5859
|
+
approve: ApproverSpecSchema
|
|
5860
|
+
}).strict();
|
|
5861
|
+
EscalationHopSchema = z22.object({
|
|
5862
|
+
escalateTo: ApproverSpecSchema,
|
|
5863
|
+
timeoutHours: z22.number().finite().min(1).max(720)
|
|
5864
|
+
}).strict();
|
|
5865
|
+
TerminalOutcomeSchema = z22.enum([
|
|
5866
|
+
"deny",
|
|
5867
|
+
"cancel-run",
|
|
5868
|
+
"fail",
|
|
5869
|
+
"continue"
|
|
5870
|
+
]);
|
|
5871
|
+
ApprovalOnTimeoutSchema = z22.union([
|
|
5872
|
+
TerminalOutcomeSchema,
|
|
5873
|
+
EscalationHopSchema,
|
|
5874
|
+
z22.array(z22.union([
|
|
5875
|
+
TerminalOutcomeSchema,
|
|
5876
|
+
EscalationHopSchema
|
|
5877
|
+
])).min(1).max(ESCALATION_MAX_HOPS + 1)
|
|
5878
|
+
]);
|
|
5879
|
+
APPROVER_SPEC_SHAPES = [
|
|
5880
|
+
"'creator'",
|
|
5881
|
+
"'org-admins'",
|
|
5882
|
+
"{users:[userId, \u2026]}",
|
|
5883
|
+
"{role:roleName}",
|
|
5884
|
+
"{group:groupName}",
|
|
5885
|
+
"{governance:{policyId}}"
|
|
5886
|
+
];
|
|
5887
|
+
APPROVER_WRITTEN_MAX = 120;
|
|
5888
|
+
USER_ID_SHAPED_RE = /^[^\s@]{1,128}$/;
|
|
5889
|
+
__name(describeApproverSpecRefusal, "describeApproverSpecRefusal");
|
|
5890
|
+
__name3(describeApproverSpecRefusal, "describeApproverSpecRefusal");
|
|
5891
|
+
BINDING_ROOTS = [
|
|
5892
|
+
"initData",
|
|
5893
|
+
"stepResults",
|
|
5894
|
+
"requestContext",
|
|
5895
|
+
"state"
|
|
5896
|
+
];
|
|
5897
|
+
__name(bindingRootsOk, "bindingRootsOk");
|
|
5898
|
+
__name3(bindingRootsOk, "bindingRootsOk");
|
|
5899
|
+
__name(isTemplateBinding, "isTemplateBinding");
|
|
5900
|
+
__name3(isTemplateBinding, "isTemplateBinding");
|
|
5901
|
+
__name(approvalEditable, "approvalEditable");
|
|
5902
|
+
__name3(approvalEditable, "approvalEditable");
|
|
5903
|
+
__name(validateApproverBlock, "validateApproverBlock");
|
|
5904
|
+
__name3(validateApproverBlock, "validateApproverBlock");
|
|
5905
|
+
__name(liftRenderedApprover, "liftRenderedApprover");
|
|
5906
|
+
__name3(liftRenderedApprover, "liftRenderedApprover");
|
|
5264
5907
|
WORKSPACE_TEMPLATE_EXPR_RE = /^\$\{\s*(?:initData|input)\.([^}]+?)\s*\}$/;
|
|
5265
5908
|
__name(workspaceTemplatePath, "workspaceTemplatePath");
|
|
5266
5909
|
__name3(workspaceTemplatePath, "workspaceTemplatePath");
|
|
@@ -5272,6 +5915,8 @@ var init_dist2 = __esm({
|
|
|
5272
5915
|
});
|
|
5273
5916
|
__name(sleepUntilUnsupportedMessage, "sleepUntilUnsupportedMessage");
|
|
5274
5917
|
__name3(sleepUntilUnsupportedMessage, "sleepUntilUnsupportedMessage");
|
|
5918
|
+
__name(armSubrunUnsupportedMessage, "armSubrunUnsupportedMessage");
|
|
5919
|
+
__name3(armSubrunUnsupportedMessage, "armSubrunUnsupportedMessage");
|
|
5275
5920
|
WORKFLOW_CAPS_DEFAULT = Object.freeze({
|
|
5276
5921
|
maxParallelArms: 16,
|
|
5277
5922
|
maxForeachConcurrency: 16,
|
|
@@ -5501,78 +6146,6 @@ var init_dist2 = __esm({
|
|
|
5501
6146
|
op: "not",
|
|
5502
6147
|
arg
|
|
5503
6148
|
}), "not");
|
|
5504
|
-
WorkflowTemplateError = class extends Error {
|
|
5505
|
-
static {
|
|
5506
|
-
__name(this, "WorkflowTemplateError");
|
|
5507
|
-
}
|
|
5508
|
-
static {
|
|
5509
|
-
__name3(this, "WorkflowTemplateError");
|
|
5510
|
-
}
|
|
5511
|
-
placeholder;
|
|
5512
|
-
constructor(message, placeholder) {
|
|
5513
|
-
super(message), this.placeholder = placeholder;
|
|
5514
|
-
this.name = "WorkflowTemplateError";
|
|
5515
|
-
}
|
|
5516
|
-
};
|
|
5517
|
-
__name(isMapConfigObject, "isMapConfigObject");
|
|
5518
|
-
__name3(isMapConfigObject, "isMapConfigObject");
|
|
5519
|
-
__name(parseMapConfig, "parseMapConfig");
|
|
5520
|
-
__name3(parseMapConfig, "parseMapConfig");
|
|
5521
|
-
__name(mapConfigWire, "mapConfigWire");
|
|
5522
|
-
__name3(mapConfigWire, "mapConfigWire");
|
|
5523
|
-
TEMPLATE_PLACEHOLDER = /\$\{([^}]*)\}/g;
|
|
5524
|
-
TEMPLATE_NAMESPACES = [
|
|
5525
|
-
"initData",
|
|
5526
|
-
"state",
|
|
5527
|
-
"requestContext",
|
|
5528
|
-
"stepResults"
|
|
5529
|
-
];
|
|
5530
|
-
__name(describeBadPlaceholder, "describeBadPlaceholder");
|
|
5531
|
-
__name3(describeBadPlaceholder, "describeBadPlaceholder");
|
|
5532
|
-
__name(parseTemplatePlaceholder, "parseTemplatePlaceholder");
|
|
5533
|
-
__name3(parseTemplatePlaceholder, "parseTemplatePlaceholder");
|
|
5534
|
-
__name(traverseMappingPath, "traverseMappingPath");
|
|
5535
|
-
__name3(traverseMappingPath, "traverseMappingPath");
|
|
5536
|
-
__name(stringifyTemplateValue, "stringifyTemplateValue");
|
|
5537
|
-
__name3(stringifyTemplateValue, "stringifyTemplateValue");
|
|
5538
|
-
__name(escapeFence, "escapeFence");
|
|
5539
|
-
__name3(escapeFence, "escapeFence");
|
|
5540
|
-
__name(fenceBlock, "fenceBlock");
|
|
5541
|
-
__name3(fenceBlock, "fenceBlock");
|
|
5542
|
-
__name(renderTemplate, "renderTemplate");
|
|
5543
|
-
__name3(renderTemplate, "renderTemplate");
|
|
5544
|
-
__name(resolveDescriptor, "resolveDescriptor");
|
|
5545
|
-
__name3(resolveDescriptor, "resolveDescriptor");
|
|
5546
|
-
__name(resolveMapping, "resolveMapping");
|
|
5547
|
-
__name3(resolveMapping, "resolveMapping");
|
|
5548
|
-
fromInit = /* @__PURE__ */ __name3((path3) => ({
|
|
5549
|
-
initData: true,
|
|
5550
|
-
path: path3
|
|
5551
|
-
}), "fromInit");
|
|
5552
|
-
fromStep = /* @__PURE__ */ __name3((s, path3 = "") => {
|
|
5553
|
-
const idOf = /* @__PURE__ */ __name3((x) => typeof x === "string" ? x : x.id, "idOf");
|
|
5554
|
-
return {
|
|
5555
|
-
step: Array.isArray(s) ? s.map(idOf) : idOf(s),
|
|
5556
|
-
path: path3
|
|
5557
|
-
};
|
|
5558
|
-
}, "fromStep");
|
|
5559
|
-
value = /* @__PURE__ */ __name3((v) => ({
|
|
5560
|
-
value: v
|
|
5561
|
-
}), "value");
|
|
5562
|
-
template = /* @__PURE__ */ __name3((s) => ({
|
|
5563
|
-
template: s
|
|
5564
|
-
}), "template");
|
|
5565
|
-
fromRequest = /* @__PURE__ */ __name3((path3) => ({
|
|
5566
|
-
requestContextPath: path3
|
|
5567
|
-
}), "fromRequest");
|
|
5568
|
-
rows = /* @__PURE__ */ __name3((s, path3, page) => ({
|
|
5569
|
-
step: typeof s === "string" ? s : s.id,
|
|
5570
|
-
path: path3,
|
|
5571
|
-
rows: page
|
|
5572
|
-
}), "rows");
|
|
5573
|
-
fromKnowledge = /* @__PURE__ */ __name3((k) => ({
|
|
5574
|
-
knowledge: k
|
|
5575
|
-
}), "fromKnowledge");
|
|
5576
6149
|
CONTINUED_FAILURE_TAG = "continued_failure";
|
|
5577
6150
|
CONTINUED_FAILURE_DEFAULT_CODE = "step_failed";
|
|
5578
6151
|
CONTINUED_FAILURE_OUTPUT_SCHEMA = Object.freeze({
|
|
@@ -5625,8 +6198,8 @@ var init_dist2 = __esm({
|
|
|
5625
6198
|
__name(isContinuedFailureValue, "isContinuedFailureValue");
|
|
5626
6199
|
__name3(isContinuedFailureValue, "isContinuedFailureValue");
|
|
5627
6200
|
isHitlNode2 = /* @__PURE__ */ __name3((n2) => isWorkflowHitlEntryType(n2.type), "isHitlNode");
|
|
5628
|
-
__name(
|
|
5629
|
-
__name3(
|
|
6201
|
+
__name(inlineContainerArm, "inlineContainerArm");
|
|
6202
|
+
__name3(inlineContainerArm, "inlineContainerArm");
|
|
5630
6203
|
nodeIdOf = /* @__PURE__ */ __name3((n2) => n2.type === "step" ? n2.step.id : n2.id, "nodeIdOf");
|
|
5631
6204
|
__name(entryIds, "entryIds");
|
|
5632
6205
|
__name3(entryIds, "entryIds");
|
|
@@ -5686,6 +6259,12 @@ var init_dist2 = __esm({
|
|
|
5686
6259
|
__name3(isTerminalRunStatus, "isTerminalRunStatus");
|
|
5687
6260
|
__name(pruneUndefined, "pruneUndefined");
|
|
5688
6261
|
__name3(pruneUndefined, "pruneUndefined");
|
|
6262
|
+
WORKFLOW_INLINE_RUN_TAG = "inline";
|
|
6263
|
+
__name(runOrigin, "runOrigin");
|
|
6264
|
+
__name3(runOrigin, "runOrigin");
|
|
6265
|
+
RUN_ERROR_ISSUES_MAX = 20;
|
|
6266
|
+
__name(runErrorIssues, "runErrorIssues");
|
|
6267
|
+
__name3(runErrorIssues, "runErrorIssues");
|
|
5689
6268
|
__name(runNextAction, "runNextAction");
|
|
5690
6269
|
__name3(runNextAction, "runNextAction");
|
|
5691
6270
|
IN_FLIGHT = new Set(WORKFLOW_STEP_IN_FLIGHT);
|
|
@@ -5698,8 +6277,20 @@ var init_dist2 = __esm({
|
|
|
5698
6277
|
n = /* @__PURE__ */ __name3((v) => typeof v === "number" && Number.isFinite(v) ? v : 0, "n");
|
|
5699
6278
|
__name(runCounts, "runCounts");
|
|
5700
6279
|
__name3(runCounts, "runCounts");
|
|
6280
|
+
__name(isPricedStepReceipt, "isPricedStepReceipt");
|
|
6281
|
+
__name3(isPricedStepReceipt, "isPricedStepReceipt");
|
|
6282
|
+
__name(receiptEngine, "receiptEngine");
|
|
6283
|
+
__name3(receiptEngine, "receiptEngine");
|
|
6284
|
+
__name(receiptTier, "receiptTier");
|
|
6285
|
+
__name3(receiptTier, "receiptTier");
|
|
6286
|
+
__name(stepBillingView, "stepBillingView");
|
|
6287
|
+
__name3(stepBillingView, "stepBillingView");
|
|
5701
6288
|
__name(runUsage, "runUsage");
|
|
5702
6289
|
__name3(runUsage, "runUsage");
|
|
6290
|
+
__name(runBudgetCap, "runBudgetCap");
|
|
6291
|
+
__name3(runBudgetCap, "runBudgetCap");
|
|
6292
|
+
__name(runBudgetRemaining, "runBudgetRemaining");
|
|
6293
|
+
__name3(runBudgetRemaining, "runBudgetRemaining");
|
|
5703
6294
|
__name(runCancelView, "runCancelView");
|
|
5704
6295
|
__name3(runCancelView, "runCancelView");
|
|
5705
6296
|
__name(runWorkspaceView, "runWorkspaceView");
|
|
@@ -5834,86 +6425,6 @@ var init_dist2 = __esm({
|
|
|
5834
6425
|
__name3(applyJsonPatch, "applyJsonPatch");
|
|
5835
6426
|
__name(rebaseItemPointer, "rebaseItemPointer");
|
|
5836
6427
|
__name3(rebaseItemPointer, "rebaseItemPointer");
|
|
5837
|
-
APPROVER_SPEC_MAX_USERS = 20;
|
|
5838
|
-
ESCALATION_MAX_HOPS = 3;
|
|
5839
|
-
TemplateBindingSchema = z22.object({
|
|
5840
|
-
template: z22.string().min(1).max(2048)
|
|
5841
|
-
}).strict();
|
|
5842
|
-
ApproverSpecSchema = z22.union([
|
|
5843
|
-
z22.literal("creator"),
|
|
5844
|
-
z22.literal("org-admins"),
|
|
5845
|
-
z22.object({
|
|
5846
|
-
users: z22.union([
|
|
5847
|
-
z22.array(z22.string().min(1).max(128)).min(1).max(APPROVER_SPEC_MAX_USERS),
|
|
5848
|
-
TemplateBindingSchema
|
|
5849
|
-
])
|
|
5850
|
-
}).strict(),
|
|
5851
|
-
z22.object({
|
|
5852
|
-
role: z22.union([
|
|
5853
|
-
z22.string().min(1).max(128),
|
|
5854
|
-
TemplateBindingSchema
|
|
5855
|
-
])
|
|
5856
|
-
}).strict(),
|
|
5857
|
-
z22.object({
|
|
5858
|
-
group: z22.union([
|
|
5859
|
-
z22.string().min(1).max(128),
|
|
5860
|
-
TemplateBindingSchema
|
|
5861
|
-
])
|
|
5862
|
-
}).strict(),
|
|
5863
|
-
z22.object({
|
|
5864
|
-
governance: z22.object({
|
|
5865
|
-
policyId: z22.string().min(1).max(128)
|
|
5866
|
-
}).strict()
|
|
5867
|
-
}).strict()
|
|
5868
|
-
]);
|
|
5869
|
-
FourEyesSchema = z22.object({
|
|
5870
|
-
edit: ApproverSpecSchema,
|
|
5871
|
-
approve: ApproverSpecSchema
|
|
5872
|
-
}).strict();
|
|
5873
|
-
EscalationHopSchema = z22.object({
|
|
5874
|
-
escalateTo: ApproverSpecSchema,
|
|
5875
|
-
timeoutHours: z22.number().finite().min(1).max(720)
|
|
5876
|
-
}).strict();
|
|
5877
|
-
TerminalOutcomeSchema = z22.enum([
|
|
5878
|
-
"deny",
|
|
5879
|
-
"cancel-run",
|
|
5880
|
-
"fail",
|
|
5881
|
-
"continue"
|
|
5882
|
-
]);
|
|
5883
|
-
ApprovalOnTimeoutSchema = z22.union([
|
|
5884
|
-
TerminalOutcomeSchema,
|
|
5885
|
-
EscalationHopSchema,
|
|
5886
|
-
z22.array(z22.union([
|
|
5887
|
-
TerminalOutcomeSchema,
|
|
5888
|
-
EscalationHopSchema
|
|
5889
|
-
])).min(1).max(ESCALATION_MAX_HOPS + 1)
|
|
5890
|
-
]);
|
|
5891
|
-
APPROVER_SPEC_SHAPES = [
|
|
5892
|
-
"'creator'",
|
|
5893
|
-
"'org-admins'",
|
|
5894
|
-
"{users:[userId, \u2026]}",
|
|
5895
|
-
"{role:roleName}",
|
|
5896
|
-
"{group:groupName}",
|
|
5897
|
-
"{governance:{policyId}}"
|
|
5898
|
-
];
|
|
5899
|
-
APPROVER_WRITTEN_MAX = 120;
|
|
5900
|
-
USER_ID_SHAPED_RE = /^[^\s@]{1,128}$/;
|
|
5901
|
-
__name(describeApproverSpecRefusal, "describeApproverSpecRefusal");
|
|
5902
|
-
__name3(describeApproverSpecRefusal, "describeApproverSpecRefusal");
|
|
5903
|
-
BINDING_ROOTS = [
|
|
5904
|
-
"initData",
|
|
5905
|
-
"stepResults",
|
|
5906
|
-
"requestContext",
|
|
5907
|
-
"state"
|
|
5908
|
-
];
|
|
5909
|
-
__name(bindingRootsOk, "bindingRootsOk");
|
|
5910
|
-
__name3(bindingRootsOk, "bindingRootsOk");
|
|
5911
|
-
__name(isTemplateBinding, "isTemplateBinding");
|
|
5912
|
-
__name3(isTemplateBinding, "isTemplateBinding");
|
|
5913
|
-
__name(validateApproverBlock, "validateApproverBlock");
|
|
5914
|
-
__name3(validateApproverBlock, "validateApproverBlock");
|
|
5915
|
-
__name(liftRenderedApprover, "liftRenderedApprover");
|
|
5916
|
-
__name3(liftRenderedApprover, "liftRenderedApprover");
|
|
5917
6428
|
WORKFLOW_ENV_OVERLAY_MAX_KEYS = 64;
|
|
5918
6429
|
WORKFLOW_ENV_OVERLAY_MAX_VALUE_BYTES = 4096;
|
|
5919
6430
|
WORKFLOW_ENV_TEMPLATE_SECRET_KEY_RE = /(SECRET|TOKEN|KEY|PASSWORD)$/;
|
|
@@ -6016,14 +6527,13 @@ function stepNodeOf(s) {
|
|
|
6016
6527
|
}
|
|
6017
6528
|
function materializeEntry(entry, steps) {
|
|
6018
6529
|
const single = /* @__PURE__ */ __name((n2) => {
|
|
6019
|
-
if (n2.type === "step" && steps[n2.step.id])
|
|
6020
|
-
|
|
6021
|
-
|
|
6022
|
-
|
|
6023
|
-
n2.
|
|
6024
|
-
|
|
6025
|
-
|
|
6026
|
-
};
|
|
6530
|
+
if (n2.type === "step" && steps[n2.step.id]) {
|
|
6531
|
+
const node = stepNodeOf(steps[n2.step.id]);
|
|
6532
|
+
return n2.input !== void 0 ? {
|
|
6533
|
+
...node,
|
|
6534
|
+
input: n2.input
|
|
6535
|
+
} : node;
|
|
6536
|
+
}
|
|
6027
6537
|
return n2;
|
|
6028
6538
|
}, "single");
|
|
6029
6539
|
switch (entry.type) {
|
|
@@ -6181,6 +6691,10 @@ var init_workflow = __esm({
|
|
|
6181
6691
|
}, "assertPredicate");
|
|
6182
6692
|
assertRetry = /* @__PURE__ */ __name((r, id) => {
|
|
6183
6693
|
if (!r) return;
|
|
6694
|
+
if (r.maxAttempts !== void 0 && !isWithinWorkflowRetryAttempts(r.maxAttempts)) {
|
|
6695
|
+
const over = typeof r.maxAttempts === "number" && r.maxAttempts > WORKFLOW_RETRY_MAX_ATTEMPTS;
|
|
6696
|
+
throw new LuaWorkflowBuildError(over ? "cap-exceeded" : "invalid-envelope", `"${id}": ${workflowRetryMaxAttemptsMessage(r.maxAttempts)}`);
|
|
6697
|
+
}
|
|
6184
6698
|
if (r.backoff !== void 0 && !WORKFLOW_RETRY_BACKOFFS.includes(r.backoff)) throw new LuaWorkflowBuildError("backoff-invalid", `"${id}": retry.backoff must be ${WORKFLOW_RETRY_BACKOFFS.map((b) => `'${b}'`).join(" | ")}`);
|
|
6185
6699
|
if (r.maxBackoffSeconds !== void 0) {
|
|
6186
6700
|
if (r.backoff !== "exponential") throw new LuaWorkflowBuildError("backoff-invalid", `"${id}": retry.maxBackoffSeconds is only meaningful with backoff:'exponential'`);
|
|
@@ -6950,6 +7464,197 @@ var init_auth_error = __esm({
|
|
|
6950
7464
|
}
|
|
6951
7465
|
});
|
|
6952
7466
|
|
|
7467
|
+
// src/errors/cli.error.ts
|
|
7468
|
+
function isAccessDeniedError(error) {
|
|
7469
|
+
if (CliError.isCliError(error)) return error.statusCode === 403;
|
|
7470
|
+
return error instanceof Error && error.message.startsWith("Access denied (403)");
|
|
7471
|
+
}
|
|
7472
|
+
function authHint(error) {
|
|
7473
|
+
if (error.suppressDefaultRemediation) return void 0;
|
|
7474
|
+
if (error.reason === "no_agent_access") {
|
|
7475
|
+
return [
|
|
7476
|
+
"Your API key is valid, but it does not have access to the agentId in lua.skill.yaml \u2014 the agent belongs",
|
|
7477
|
+
"to another account or organization, was deleted or transferred, or the yaml was copied from another project.",
|
|
7478
|
+
"Check the configured agent and switch if needed:",
|
|
7479
|
+
" lua agents (list agents you have access to)",
|
|
7480
|
+
" lua init (re-select the agent for this project)"
|
|
7481
|
+
].join("\n");
|
|
7482
|
+
}
|
|
7483
|
+
return "Re-authenticate or check your API key: lua auth configure \xB7 https://admin.heylua.ai";
|
|
7484
|
+
}
|
|
7485
|
+
function numericStatus(error) {
|
|
7486
|
+
const candidate = error.statusCode ?? error.status;
|
|
7487
|
+
return typeof candidate === "number" && Number.isFinite(candidate) ? candidate : void 0;
|
|
7488
|
+
}
|
|
7489
|
+
function classifyCliError(error) {
|
|
7490
|
+
if (CliError.isCliError(error)) {
|
|
7491
|
+
return {
|
|
7492
|
+
code: error.code,
|
|
7493
|
+
exitCode: error.exitCode,
|
|
7494
|
+
message: error.message,
|
|
7495
|
+
hint: error.hint
|
|
7496
|
+
};
|
|
7497
|
+
}
|
|
7498
|
+
if (AuthenticationError.isAuthenticationError(error)) {
|
|
7499
|
+
return {
|
|
7500
|
+
code: "auth",
|
|
7501
|
+
exitCode: CLI_EXIT.AUTH,
|
|
7502
|
+
message: error.message,
|
|
7503
|
+
hint: authHint(error)
|
|
7504
|
+
};
|
|
7505
|
+
}
|
|
7506
|
+
const e = typeof error === "object" && error !== null ? error : {};
|
|
7507
|
+
const message = typeof e.message === "string" && e.message.length > 0 ? e.message : error instanceof Error ? error.name : String(error ?? "Unknown error");
|
|
7508
|
+
if (e.name === "WorkflowLocalUsageError" || typeof e.code === "string" && e.code.startsWith("commander.")) {
|
|
7509
|
+
return {
|
|
7510
|
+
code: "usage",
|
|
7511
|
+
exitCode: CLI_EXIT.USAGE,
|
|
7512
|
+
message
|
|
7513
|
+
};
|
|
7514
|
+
}
|
|
7515
|
+
const status = numericStatus(e);
|
|
7516
|
+
if (status !== void 0) {
|
|
7517
|
+
if (status === 401) return {
|
|
7518
|
+
code: "auth",
|
|
7519
|
+
exitCode: CLI_EXIT.AUTH,
|
|
7520
|
+
message
|
|
7521
|
+
};
|
|
7522
|
+
if (status === 403) return {
|
|
7523
|
+
code: "forbidden",
|
|
7524
|
+
exitCode: CLI_EXIT.FORBIDDEN,
|
|
7525
|
+
message
|
|
7526
|
+
};
|
|
7527
|
+
if (status === 404) return {
|
|
7528
|
+
code: "not_found",
|
|
7529
|
+
exitCode: CLI_EXIT.NOT_FOUND,
|
|
7530
|
+
message
|
|
7531
|
+
};
|
|
7532
|
+
if (status >= 400 && status < 500) return {
|
|
7533
|
+
code: `http_${status}`,
|
|
7534
|
+
exitCode: CLI_EXIT.FORBIDDEN,
|
|
7535
|
+
message
|
|
7536
|
+
};
|
|
7537
|
+
if (status >= 500 || status === 0) return {
|
|
7538
|
+
code: "unavailable",
|
|
7539
|
+
exitCode: CLI_EXIT.UNAVAILABLE,
|
|
7540
|
+
message
|
|
7541
|
+
};
|
|
7542
|
+
}
|
|
7543
|
+
const causeCode = e.cause?.code;
|
|
7544
|
+
if (typeof e.code === "string" && NETWORK_ERRNO.has(e.code) || typeof causeCode === "string" && NETWORK_ERRNO.has(causeCode) || e.name === "AbortError" || e.name === "TimeoutError" || NETWORK_MESSAGE.test(message)) {
|
|
7545
|
+
return {
|
|
7546
|
+
code: "unavailable",
|
|
7547
|
+
exitCode: CLI_EXIT.UNAVAILABLE,
|
|
7548
|
+
message,
|
|
7549
|
+
hint: UNAVAILABLE_HINT
|
|
7550
|
+
};
|
|
7551
|
+
}
|
|
7552
|
+
return {
|
|
7553
|
+
code: "error",
|
|
7554
|
+
exitCode: CLI_EXIT.ERROR,
|
|
7555
|
+
message
|
|
7556
|
+
};
|
|
7557
|
+
}
|
|
7558
|
+
var CLI_EXIT, CliError, NETWORK_ERRNO, NETWORK_MESSAGE, UNAVAILABLE_HINT;
|
|
7559
|
+
var init_cli_error = __esm({
|
|
7560
|
+
"src/errors/cli.error.ts"() {
|
|
7561
|
+
"use strict";
|
|
7562
|
+
init_auth_error();
|
|
7563
|
+
CLI_EXIT = {
|
|
7564
|
+
OK: 0,
|
|
7565
|
+
ERROR: 1,
|
|
7566
|
+
USAGE: 2,
|
|
7567
|
+
NOT_FOUND: 3,
|
|
7568
|
+
AUTH: 9,
|
|
7569
|
+
FORBIDDEN: 10,
|
|
7570
|
+
UNAVAILABLE: 11
|
|
7571
|
+
};
|
|
7572
|
+
CliError = class _CliError extends Error {
|
|
7573
|
+
static {
|
|
7574
|
+
__name(this, "CliError");
|
|
7575
|
+
}
|
|
7576
|
+
isCliError = true;
|
|
7577
|
+
code;
|
|
7578
|
+
exitCode;
|
|
7579
|
+
hint;
|
|
7580
|
+
statusCode;
|
|
7581
|
+
constructor(code, message, options = {}) {
|
|
7582
|
+
super(message);
|
|
7583
|
+
this.name = "CliError";
|
|
7584
|
+
this.code = code;
|
|
7585
|
+
this.exitCode = options.exitCode ?? CLI_EXIT.ERROR;
|
|
7586
|
+
this.hint = options.hint;
|
|
7587
|
+
this.statusCode = options.statusCode;
|
|
7588
|
+
if (Error.captureStackTrace) Error.captureStackTrace(this, _CliError);
|
|
7589
|
+
}
|
|
7590
|
+
/** Bad arguments, an unknown action, no project — exit 2. */
|
|
7591
|
+
static usage(message, hint) {
|
|
7592
|
+
return new _CliError("usage", message, {
|
|
7593
|
+
exitCode: CLI_EXIT.USAGE,
|
|
7594
|
+
hint
|
|
7595
|
+
});
|
|
7596
|
+
}
|
|
7597
|
+
/** The named thing does not exist — exit 3. */
|
|
7598
|
+
static notFound(message, hint) {
|
|
7599
|
+
return new _CliError("not_found", message, {
|
|
7600
|
+
exitCode: CLI_EXIT.NOT_FOUND,
|
|
7601
|
+
hint,
|
|
7602
|
+
statusCode: 404
|
|
7603
|
+
});
|
|
7604
|
+
}
|
|
7605
|
+
/** The credential may not do this — exit 10. */
|
|
7606
|
+
static forbidden(message, hint) {
|
|
7607
|
+
return new _CliError("forbidden", message, {
|
|
7608
|
+
exitCode: CLI_EXIT.FORBIDDEN,
|
|
7609
|
+
hint,
|
|
7610
|
+
statusCode: 403
|
|
7611
|
+
});
|
|
7612
|
+
}
|
|
7613
|
+
/**
|
|
7614
|
+
* An API refusal the site already holds the status of (LUA-766) — classified by the same table the top-level
|
|
7615
|
+
* classifier applies to an untyped error: 401 auth · 403 forbidden · 404 not_found · other 4xx `http_<status>`
|
|
7616
|
+
* (10) · 5xx / 0 unavailable (11, with the network hint unless the site gives its own) · no status `error` (1).
|
|
7617
|
+
* A command that reads `response.error.statusCode` throws through here, so `lua logs` on a 503 exits 11 like
|
|
7618
|
+
* every other verb instead of printing the message itself and then throwing an exit-1 `Error`.
|
|
7619
|
+
*/
|
|
7620
|
+
static fromStatus(statusCode, message, hint) {
|
|
7621
|
+
const reported = classifyCliError(Object.assign(new Error(message), {
|
|
7622
|
+
statusCode
|
|
7623
|
+
}));
|
|
7624
|
+
const classHint = reported.exitCode === CLI_EXIT.UNAVAILABLE ? UNAVAILABLE_HINT : reported.hint;
|
|
7625
|
+
return new _CliError(reported.code, message, {
|
|
7626
|
+
exitCode: reported.exitCode,
|
|
7627
|
+
hint: hint ?? classHint,
|
|
7628
|
+
statusCode
|
|
7629
|
+
});
|
|
7630
|
+
}
|
|
7631
|
+
static isCliError(error) {
|
|
7632
|
+
return error instanceof _CliError || typeof error === "object" && error !== null && error.isCliError === true;
|
|
7633
|
+
}
|
|
7634
|
+
};
|
|
7635
|
+
__name(isAccessDeniedError, "isAccessDeniedError");
|
|
7636
|
+
NETWORK_ERRNO = /* @__PURE__ */ new Set([
|
|
7637
|
+
"ECONNREFUSED",
|
|
7638
|
+
"ECONNRESET",
|
|
7639
|
+
"ENOTFOUND",
|
|
7640
|
+
"ETIMEDOUT",
|
|
7641
|
+
"EAI_AGAIN",
|
|
7642
|
+
"EPIPE",
|
|
7643
|
+
"EHOSTUNREACH",
|
|
7644
|
+
"ENETUNREACH",
|
|
7645
|
+
"UND_ERR_CONNECT_TIMEOUT",
|
|
7646
|
+
"UND_ERR_HEADERS_TIMEOUT",
|
|
7647
|
+
"UND_ERR_BODY_TIMEOUT",
|
|
7648
|
+
"UND_ERR_SOCKET"
|
|
7649
|
+
]);
|
|
7650
|
+
NETWORK_MESSAGE = /fetch failed|socket hang up|network request failed|request timeout|ECONNREFUSED|ENOTFOUND/i;
|
|
7651
|
+
UNAVAILABLE_HINT = "The Lua API could not be reached \u2014 check your network and https://status.heylua.ai, then retry.";
|
|
7652
|
+
__name(authHint, "authHint");
|
|
7653
|
+
__name(numericStatus, "numericStatus");
|
|
7654
|
+
__name(classifyCliError, "classifyCliError");
|
|
7655
|
+
}
|
|
7656
|
+
});
|
|
7657
|
+
|
|
6953
7658
|
// src/utils/package-root.ts
|
|
6954
7659
|
import { readFileSync, existsSync } from "fs";
|
|
6955
7660
|
import { fileURLToPath, pathToFileURL } from "url";
|
|
@@ -7476,6 +8181,10 @@ async function* parseSseStream(body, signal) {
|
|
|
7476
8181
|
if (frame) yield frame;
|
|
7477
8182
|
}
|
|
7478
8183
|
} finally {
|
|
8184
|
+
try {
|
|
8185
|
+
await reader.cancel();
|
|
8186
|
+
} catch {
|
|
8187
|
+
}
|
|
7479
8188
|
try {
|
|
7480
8189
|
reader.releaseLock();
|
|
7481
8190
|
} catch {
|
|
@@ -7505,6 +8214,7 @@ var init_http_client = __esm({
|
|
|
7505
8214
|
"use strict";
|
|
7506
8215
|
init_dist();
|
|
7507
8216
|
init_auth_error();
|
|
8217
|
+
init_cli_error();
|
|
7508
8218
|
init_lua_fetch();
|
|
7509
8219
|
init_request_credential();
|
|
7510
8220
|
DEFAULT_REQUEST_TIMEOUT_MS = 3e4;
|
|
@@ -7568,7 +8278,7 @@ var init_http_client = __esm({
|
|
|
7568
8278
|
if (AuthenticationError.isAuthenticationError(error)) {
|
|
7569
8279
|
throw error;
|
|
7570
8280
|
}
|
|
7571
|
-
if (error
|
|
8281
|
+
if (isAccessDeniedError(error)) {
|
|
7572
8282
|
throw error;
|
|
7573
8283
|
}
|
|
7574
8284
|
if (error instanceof DOMException && error.name === "AbortError") {
|
|
@@ -7616,8 +8326,11 @@ var init_http_client = __esm({
|
|
|
7616
8326
|
}
|
|
7617
8327
|
if (response.status === 403) {
|
|
7618
8328
|
const detail = errorData.message || "You do not have permission to access this resource.";
|
|
7619
|
-
throw new
|
|
7620
|
-
|
|
8329
|
+
throw new CliError("forbidden", `Access denied (403): ${detail}`, {
|
|
8330
|
+
exitCode: CLI_EXIT.FORBIDDEN,
|
|
8331
|
+
statusCode: 403,
|
|
8332
|
+
hint: "Check that your Lua login has access to this agent or organization."
|
|
8333
|
+
});
|
|
7621
8334
|
}
|
|
7622
8335
|
return {
|
|
7623
8336
|
success: false,
|
|
@@ -7859,6 +8572,7 @@ var init_auth = __esm({
|
|
|
7859
8572
|
init_auth_api_service();
|
|
7860
8573
|
init_constants();
|
|
7861
8574
|
init_auth_error();
|
|
8575
|
+
init_cli_error();
|
|
7862
8576
|
}
|
|
7863
8577
|
});
|
|
7864
8578
|
|
|
@@ -8086,6 +8800,9 @@ function buildSourceArchive(files) {
|
|
|
8086
8800
|
const gz = zlib.gzipSync(Buffer.from(json, "utf-8"));
|
|
8087
8801
|
return gz.toString("base64");
|
|
8088
8802
|
}
|
|
8803
|
+
function getPrimitivesByKind(manifest, kind) {
|
|
8804
|
+
return manifest.primitives.filter((p) => p.kind === kind);
|
|
8805
|
+
}
|
|
8089
8806
|
function findPrimitive(manifest, name, kind) {
|
|
8090
8807
|
return manifest.primitives.find((p) => {
|
|
8091
8808
|
if (kind && p.kind !== kind) return false;
|
|
@@ -8106,6 +8823,7 @@ var init_artifact_loader = __esm({
|
|
|
8106
8823
|
__name(loadOriginalSource, "loadOriginalSource");
|
|
8107
8824
|
__name(normalizeEntryFile, "normalizeEntryFile");
|
|
8108
8825
|
__name(buildSourceArchive, "buildSourceArchive");
|
|
8826
|
+
__name(getPrimitivesByKind, "getPrimitivesByKind");
|
|
8109
8827
|
__name(findPrimitive, "findPrimitive");
|
|
8110
8828
|
}
|
|
8111
8829
|
});
|
|
@@ -8752,6 +9470,7 @@ var init_base_handler = __esm({
|
|
|
8752
9470
|
init_bundle_upload();
|
|
8753
9471
|
init_semver();
|
|
8754
9472
|
init_auth_error();
|
|
9473
|
+
init_cli_error();
|
|
8755
9474
|
DEFAULT_VERSION = SKILL_DEFAULTS.VERSION;
|
|
8756
9475
|
BaseVersionedHandler = class {
|
|
8757
9476
|
static {
|
|
@@ -8833,7 +9552,7 @@ var init_base_handler = __esm({
|
|
|
8833
9552
|
serverItems
|
|
8834
9553
|
};
|
|
8835
9554
|
} catch (error) {
|
|
8836
|
-
if (AuthenticationError.isAuthenticationError(error)) throw error;
|
|
9555
|
+
if (AuthenticationError.isAuthenticationError(error) || isAccessDeniedError(error)) throw error;
|
|
8837
9556
|
return {
|
|
8838
9557
|
serverItems: null,
|
|
8839
9558
|
fetchError: error instanceof Error ? error.message : String(error)
|
|
@@ -8863,13 +9582,24 @@ var init_base_handler = __esm({
|
|
|
8863
9582
|
}
|
|
8864
9583
|
const yamlItems = this.getFromYaml(config);
|
|
8865
9584
|
const { yamlById, yamlByName, serverByName } = this.buildMaps(serverData.serverItems, yamlItems);
|
|
9585
|
+
const idField = this.yamlConfig.idField;
|
|
9586
|
+
const manifestNames = manifest ? new Set(getPrimitivesByKind(manifest, this.kind).map((p) => p.name)) : /* @__PURE__ */ new Set();
|
|
9587
|
+
for (const stale of this.staleYamlRows(yamlItems, serverData.serverItems, manifestNames)) {
|
|
9588
|
+
const idx = yamlItems.indexOf(stale);
|
|
9589
|
+
if (idx < 0) continue;
|
|
9590
|
+
const { [idField]: goneId, ...rest } = stale;
|
|
9591
|
+
yamlItems[idx] = rest;
|
|
9592
|
+
yamlUpdated = true;
|
|
9593
|
+
const msg = `\u2139\uFE0F ${this.displayName} "${stale.name}" (${goneId}) no longer exists on the server \u2014 re-registering it`;
|
|
9594
|
+
messages.push(msg);
|
|
9595
|
+
console.log(msg);
|
|
9596
|
+
}
|
|
8866
9597
|
const orphans = serverData.serverItems.filter((item) => {
|
|
8867
9598
|
const id = item.id;
|
|
8868
9599
|
const name = item.name;
|
|
8869
9600
|
return !yamlById.has(id) && !yamlByName.has(name) && this.isActive(item) && this.shouldConsiderForOrphan(item);
|
|
8870
9601
|
});
|
|
8871
9602
|
if (orphans.length > 0) {
|
|
8872
|
-
const idField = this.yamlConfig.idField;
|
|
8873
9603
|
const stubs = orphans.map((item) => this.cleanItem({
|
|
8874
9604
|
name: item.name,
|
|
8875
9605
|
version: this.getActiveVersion(item) || DEFAULT_VERSION,
|
|
@@ -8912,6 +9642,7 @@ var init_base_handler = __esm({
|
|
|
8912
9642
|
console.log(`\u2705 Server ${this.displayNamePlural} and YAML are fully in sync`);
|
|
8913
9643
|
}
|
|
8914
9644
|
} catch (error) {
|
|
9645
|
+
if (AuthenticationError.isAuthenticationError(error) || isAccessDeniedError(error)) throw error;
|
|
8915
9646
|
console.error(`\u274C Error syncing server ${this.displayNamePlural}:`, error);
|
|
8916
9647
|
}
|
|
8917
9648
|
return {
|
|
@@ -8968,6 +9699,7 @@ var init_base_handler = __esm({
|
|
|
8968
9699
|
console.error(` \u274C Failed to create "${item.name}" - no ID returned`);
|
|
8969
9700
|
}
|
|
8970
9701
|
} catch (error) {
|
|
9702
|
+
if (AuthenticationError.isAuthenticationError(error) || isAccessDeniedError(error)) throw error;
|
|
8971
9703
|
console.error(` \u274C Failed to create "${item.name}": ${error instanceof Error ? error.message : error}`);
|
|
8972
9704
|
}
|
|
8973
9705
|
}
|
|
@@ -9102,6 +9834,15 @@ var init_base_handler = __esm({
|
|
|
9102
9834
|
getItemId(item) {
|
|
9103
9835
|
return item[this.yamlConfig.idField] || "";
|
|
9104
9836
|
}
|
|
9837
|
+
/**
|
|
9838
|
+
* LUA-750: the yaml rows whose server id is gone (deleted server-side) and which `applySyncToYaml` should
|
|
9839
|
+
* re-register. Default none — a handler whose `fetchFromServer` lists EVERY live row of its kind for the
|
|
9840
|
+
* agent overrides this (a kind whose list omits inactive rows must not, or it would duplicate them).
|
|
9841
|
+
* `manifestNames` is the set of primitives in local code: only those are worth re-creating.
|
|
9842
|
+
*/
|
|
9843
|
+
staleYamlRows(_yamlItems, _serverItems, _manifestNames) {
|
|
9844
|
+
return [];
|
|
9845
|
+
}
|
|
9105
9846
|
buildMaps(serverItems, yamlItems) {
|
|
9106
9847
|
const yamlById = /* @__PURE__ */ new Map();
|
|
9107
9848
|
const yamlByName = /* @__PURE__ */ new Map();
|
|
@@ -9500,6 +10241,7 @@ var init_cli = __esm({
|
|
|
9500
10241
|
"src/utils/cli.ts"() {
|
|
9501
10242
|
"use strict";
|
|
9502
10243
|
init_auth_error();
|
|
10244
|
+
init_cli_error();
|
|
9503
10245
|
init_version_check();
|
|
9504
10246
|
init_package_root();
|
|
9505
10247
|
init_analytics();
|
|
@@ -9519,6 +10261,7 @@ var init_command_utils = __esm({
|
|
|
9519
10261
|
init_request_credential();
|
|
9520
10262
|
init_files();
|
|
9521
10263
|
init_cli();
|
|
10264
|
+
init_cli_error();
|
|
9522
10265
|
__name(requireAuth, "requireAuth");
|
|
9523
10266
|
}
|
|
9524
10267
|
});
|
|
@@ -12990,6 +13733,14 @@ var init_workflow_api_service = __esm({
|
|
|
12990
13733
|
async getVersionEnvOverlay(workflowId, version) {
|
|
12991
13734
|
return this.httpGet(`${this.base}/${workflowId}/versions/${encodeURIComponent(version)}/env-overlay`, await this.auth());
|
|
12992
13735
|
}
|
|
13736
|
+
/**
|
|
13737
|
+
* WF-403 (13 §13.14; LUA-752) — `GET …/:workflowId/export?version=`: the active (or named) version as pushable
|
|
13738
|
+
* files (`{ form, version, files:[{ path, contents }], warnings }`). `lua workflows export` writes them to disk.
|
|
13739
|
+
*/
|
|
13740
|
+
async exportWorkflowFiles(workflowId, version) {
|
|
13741
|
+
const qs = version ? `?version=${encodeURIComponent(version)}` : "";
|
|
13742
|
+
return this.httpGet(`${this.base}/${workflowId}/export${qs}`, await this.auth());
|
|
13743
|
+
}
|
|
12993
13744
|
async getWorkflowVersions(workflowId) {
|
|
12994
13745
|
return this.httpGet(`${this.base}/${workflowId}/versions`, await this.auth());
|
|
12995
13746
|
}
|
|
@@ -13067,7 +13818,10 @@ var init_workflow_api_service = __esm({
|
|
|
13067
13818
|
async getRunReplayBundle(runId) {
|
|
13068
13819
|
return this.httpGet(`${this.runs}/${runId}/journal?format=replay`, await this.auth());
|
|
13069
13820
|
}
|
|
13070
|
-
/**
|
|
13821
|
+
/**
|
|
13822
|
+
* R11 — cancel (`mode:'request'` default). A `'force'` before `forceAvailableAt` is the 200 verdict
|
|
13823
|
+
* `{ transitioned:false, nextAction:'cancel_again', forceAvailableAt }` (PRO-979) — never a 409 (LUA-748).
|
|
13824
|
+
*/
|
|
13071
13825
|
async cancelRun(runId, data = {}) {
|
|
13072
13826
|
return this.httpPost(`${this.runs}/${runId}/cancel`, data, await this.auth());
|
|
13073
13827
|
}
|
|
@@ -13083,6 +13837,34 @@ var init_workflow_api_service = __esm({
|
|
|
13083
13837
|
async retryStep(runId, stepId, data = {}) {
|
|
13084
13838
|
return this.httpPost(`${this.runs}/${runId}/steps/${pathId(stepId)}/retry`, data, await this.auth());
|
|
13085
13839
|
}
|
|
13840
|
+
/**
|
|
13841
|
+
* R37 (LUA-752) — a human decides a parked step: `skip` it, `complete` it with the output it would have produced,
|
|
13842
|
+
* or `fail` it (the step's onError policy applies). 400 `VALIDATION_FAILED{output-required}` / `RESOLVE_OUTPUT_INVALID`,
|
|
13843
|
+
* 403 `APPROVAL_REQUIRES_HUMAN` / `NOT_RUN_CREATOR`, 404 `RUN_NOT_FOUND` / `STEP_NOT_FOUND`, 409 `STEP_NOT_PARKED` /
|
|
13844
|
+
* `RUN_TERMINAL`, 413 `OUTPUT_TOO_LARGE`; the CAS loser is a 200 `{ resolved:false, reason, recorded }`.
|
|
13845
|
+
*/
|
|
13846
|
+
async resolveStep(runId, stepId, data) {
|
|
13847
|
+
return this.httpPost(`${this.runs}/${runId}/steps/${pathId(stepId)}/resolve`, data, await this.auth());
|
|
13848
|
+
}
|
|
13849
|
+
/**
|
|
13850
|
+
* R45 (LUA-752) — raise a parked run's budget (`maxCredits` / `maxSteps` / `maxJobSeconds` / `maxDurationSeconds`;
|
|
13851
|
+
* increases only). 400 `VALIDATION_FAILED` / `CAP_EXCEEDED`, 403 `NOT_RUN_CREATOR`, 409 `BUDGET_NOT_RAISABLE`.
|
|
13852
|
+
*/
|
|
13853
|
+
async raiseBudget(runId, data) {
|
|
13854
|
+
return this.httpPost(`${this.runs}/${runId}/budget`, data, await this.auth());
|
|
13855
|
+
}
|
|
13856
|
+
/**
|
|
13857
|
+
* R39 (LUA-752) — the current approval payload with its `payloadFingerprint` / `editRevision` (what
|
|
13858
|
+
* `approve --edit --fingerprint` echoes). `path` pages one array of a large payload.
|
|
13859
|
+
*/
|
|
13860
|
+
async getApprovalPayload(runId, approvalId, query = {}) {
|
|
13861
|
+
const q = new URLSearchParams();
|
|
13862
|
+
if (query.path) q.append("path", query.path);
|
|
13863
|
+
if (query.cursor) q.append("cursor", query.cursor);
|
|
13864
|
+
if (query.limit !== void 0) q.append("limit", String(query.limit));
|
|
13865
|
+
const qs = q.toString();
|
|
13866
|
+
return this.httpGet(`${this.runs}/${runId}/approvals/${pathId(approvalId)}/payload${qs ? `?${qs}` : ""}`, await this.auth());
|
|
13867
|
+
}
|
|
13086
13868
|
/** R13 — resolve an approval (human; `expectedFingerprint` guards against an edited payload — 409 `PAYLOAD_MISMATCH`). */
|
|
13087
13869
|
async resolveApproval(runId, approvalId, data) {
|
|
13088
13870
|
return this.httpPost(`${this.runs}/${runId}/approvals/${pathId(approvalId)}/resolve`, data, await this.auth());
|
|
@@ -13146,6 +13928,14 @@ var init_workflow_api_service = __esm({
|
|
|
13146
13928
|
async closeGoal(goalId, data = {}) {
|
|
13147
13929
|
return this.httpPost(`${this.goals}/${encodeURIComponent(goalId)}/close`, data, await this.auth());
|
|
13148
13930
|
}
|
|
13931
|
+
/** LUA-749 R63 — edit (objective / judge / cadence / caps / note); a `budget` / `max_runs` park re-arms when the cap clears (`rearmed:true`). */
|
|
13932
|
+
async updateGoal(goalId, data) {
|
|
13933
|
+
return this.httpPatch(`${this.goals}/${encodeURIComponent(goalId)}`, data, await this.auth());
|
|
13934
|
+
}
|
|
13935
|
+
/** LUA-749 R64 — raise `maxTotalCredits` / `maxRuns` (increases only; 400 `GOAL_RAISE_BELOW_SPENT{field, value, spent}`). */
|
|
13936
|
+
async raiseGoal(goalId, data) {
|
|
13937
|
+
return this.httpPost(`${this.goals}/${encodeURIComponent(goalId)}/raise`, data, await this.auth());
|
|
13938
|
+
}
|
|
13149
13939
|
// ─── Schedules (R4-MF-2 list/get + R28 delete — `/workflows/:agentId/schedules`; LUA-627 stanza) ───
|
|
13150
13940
|
/** Schedule tree (09 §9.5 — the write-only R27/R56/R28 family plus the R4-MF-2 read rows). */
|
|
13151
13941
|
get schedules() {
|
|
@@ -13159,7 +13949,15 @@ var init_workflow_api_service = __esm({
|
|
|
13159
13949
|
async getSchedule(jobId) {
|
|
13160
13950
|
return this.httpGet(`${this.schedules}/${encodeURIComponent(jobId)}`, await this.auth());
|
|
13161
13951
|
}
|
|
13162
|
-
/**
|
|
13952
|
+
/** R27 (LUA-752) — create or replace the plain schedule Job of a workflow (201; 400 `VALIDATION_FAILED` / `WORKFLOW_NOT_ON_AGENT`, 404 `WORKFLOW_NOT_FOUND`, 409 `SCHEDULE_CAP`). */
|
|
13953
|
+
async createSchedule(data) {
|
|
13954
|
+
return this.httpPost(this.schedules, data, await this.auth());
|
|
13955
|
+
}
|
|
13956
|
+
/** R56 (LUA-752) — pause / resume a schedule, persist `backfillOnEnable`, one-shot `backfillNow` (404 `SCHEDULE_NOT_FOUND`, 400 `VALIDATION_FAILED{issues}`). */
|
|
13957
|
+
async updateSchedule(jobId, data) {
|
|
13958
|
+
return this.httpPatch(`${this.schedules}/${encodeURIComponent(jobId)}`, data, await this.auth());
|
|
13959
|
+
}
|
|
13960
|
+
/** R28 — delete a schedule Job (404 `SCHEDULE_NOT_FOUND`). The CLI refuses a LIVE goal's job BEFORE this call (`goal_schedule`); an ended goal's lingering Job is retired here (LUA-760). */
|
|
13163
13961
|
async deleteSchedule(jobId) {
|
|
13164
13962
|
return this.httpDelete(`${this.schedules}/${encodeURIComponent(jobId)}`, await this.auth());
|
|
13165
13963
|
}
|