lua-cli 3.31.0 → 3.32.1
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/dist/api-exports.d.ts +81 -5
- package/dist/api-exports.js +686 -126
- package/dist/api-exports.js.map +1 -1
- package/dist/index.js +2003 -308
- package/dist/index.js.map +1 -1
- package/dist/workflow-builder.d.ts +37 -3
- package/dist/workflow-builder.js +658 -117
- package/dist/workflow-builder.js.map +1 -1
- package/docs/README.md +2 -2
- package/docs/api/LuaWorkflow.md +44 -28
- package/docs/api/Workflows.md +2 -1
- package/docs/workflows/approvals.md +14 -1
- package/docs/workflows/connections-in-coding-turns.md +1 -0
- package/docs/workflows/git-credentials.md +22 -1
- package/docs/workflows/goals.md +46 -0
- package/docs/workflows/recovery.md +6 -2
- package/docs/workflows/replay-local.md +10 -10
- package/docs/workflows/schedules.md +15 -0
- package/docs/workflows/testing-offline.md +22 -19
- package/docs/workflows/workspaces-and-long-steps.md +2 -0
- package/package.json +3 -3
- package/template/examples/workflows/CLAUDE.md +16 -13
- package/template/examples/workflows/pr-review-round.ts +57 -20
- package/template/examples/workflows/provision-tenant.ts +25 -8
- package/template/examples/workflows/refund-approval.ts +30 -17
- package/template/examples/workflows/support-triage.ts +59 -22
- package/template/examples/workflows/ticket-to-pr.ts +103 -31
- package/template/examples/workflows/vendor-invoices.ts +69 -16
- package/template/package.json +1 -1
package/dist/workflow-builder.js
CHANGED
|
@@ -1348,7 +1348,6 @@ function luaClientMetricLabels(client) {
|
|
|
1348
1348
|
const canonical2 = parseLuaClientHeader(serializeLuaClientHeader(client));
|
|
1349
1349
|
return {
|
|
1350
1350
|
client_family: canonical2?.app ?? "unknown",
|
|
1351
|
-
client_version: canonical2?.version ?? "unknown",
|
|
1352
1351
|
client_attribution: canonical2?.attribution ?? "unknown"
|
|
1353
1352
|
};
|
|
1354
1353
|
}
|
|
@@ -1528,6 +1527,27 @@ var WORKFLOW_RUN_STATUSES = [
|
|
|
1528
1527
|
...WORKFLOW_RUN_IDLE,
|
|
1529
1528
|
...WORKFLOW_RUN_TERMINAL
|
|
1530
1529
|
];
|
|
1530
|
+
var WORKFLOW_STEP_STATUSES = [
|
|
1531
|
+
"pending",
|
|
1532
|
+
"ready",
|
|
1533
|
+
"waiting",
|
|
1534
|
+
"dispatched",
|
|
1535
|
+
"claimed",
|
|
1536
|
+
"running",
|
|
1537
|
+
"suspended",
|
|
1538
|
+
"cancellation_requested",
|
|
1539
|
+
"completed",
|
|
1540
|
+
"failed",
|
|
1541
|
+
"skipped",
|
|
1542
|
+
"cancelled",
|
|
1543
|
+
"timeout",
|
|
1544
|
+
"reaped"
|
|
1545
|
+
];
|
|
1546
|
+
var WORKFLOW_STEP_IN_FLIGHT = [
|
|
1547
|
+
"claimed",
|
|
1548
|
+
"running",
|
|
1549
|
+
"cancellation_requested"
|
|
1550
|
+
];
|
|
1531
1551
|
var ARCHIVE_WINDOW_MARGIN_DAYS = 7;
|
|
1532
1552
|
function shouldSkipArchive(run, manifestSha256, sinkSha256) {
|
|
1533
1553
|
if (!run.completedAt || !run.exportedAt || run.exportedAt < run.completedAt) return false;
|
|
@@ -1588,6 +1608,7 @@ function workflowOrgSlotKey(orgId, kind) {
|
|
|
1588
1608
|
}
|
|
1589
1609
|
__name(workflowOrgSlotKey, "workflowOrgSlotKey");
|
|
1590
1610
|
__name2(workflowOrgSlotKey, "workflowOrgSlotKey");
|
|
1611
|
+
var WORKFLOW_CONNECTION_KEY_RE = /^[a-z][a-z0-9_-]{0,63}$/;
|
|
1591
1612
|
function scheduledTimeKey(scheduledTime) {
|
|
1592
1613
|
return scheduledTime.replace(/[^0-9TZ]/g, "");
|
|
1593
1614
|
}
|
|
@@ -1599,6 +1620,137 @@ function scheduledWorkflowRunIdForTime(jobId, scheduledTime) {
|
|
|
1599
1620
|
__name(scheduledWorkflowRunIdForTime, "scheduledWorkflowRunIdForTime");
|
|
1600
1621
|
__name2(scheduledWorkflowRunIdForTime, "scheduledWorkflowRunIdForTime");
|
|
1601
1622
|
var WORKFLOW_SIGNAL_PAYLOAD_MAX_BYTES = 64 * 1024;
|
|
1623
|
+
var REDACTED_PLACEHOLDER = "[REDACTED]";
|
|
1624
|
+
var PROVIDER_MESSAGE_MAX_CHARS = 300;
|
|
1625
|
+
var SECRET_LITERAL_PATTERNS = [
|
|
1626
|
+
{
|
|
1627
|
+
re: /\b(github_pat_)[A-Za-z0-9_]{16,}/g
|
|
1628
|
+
},
|
|
1629
|
+
{
|
|
1630
|
+
re: /\b(gh[pousr]_)[A-Za-z0-9]{16,}/g
|
|
1631
|
+
},
|
|
1632
|
+
{
|
|
1633
|
+
re: /\b(glpat-)[A-Za-z0-9_-]{16,}/g
|
|
1634
|
+
},
|
|
1635
|
+
{
|
|
1636
|
+
re: /\b(sk-ant-)[A-Za-z0-9_-]{16,}/g
|
|
1637
|
+
},
|
|
1638
|
+
{
|
|
1639
|
+
re: /\b(sk-)(?!ant-)[A-Za-z0-9_-]{20,}/g
|
|
1640
|
+
},
|
|
1641
|
+
{
|
|
1642
|
+
re: /\b(AKIA)[A-Z0-9]{16}\b/g
|
|
1643
|
+
},
|
|
1644
|
+
{
|
|
1645
|
+
re: /\b(xox[abprs]-)[A-Za-z0-9-]{10,}/g
|
|
1646
|
+
},
|
|
1647
|
+
{
|
|
1648
|
+
re: /\b(AIza)[0-9A-Za-z_-]{35}/g
|
|
1649
|
+
},
|
|
1650
|
+
{
|
|
1651
|
+
re: /\b(ya29\.)[A-Za-z0-9_-]{20,}/g
|
|
1652
|
+
},
|
|
1653
|
+
{
|
|
1654
|
+
re: /\b(eyJ)[A-Za-z0-9_-]{8,}\.[A-Za-z0-9_-]{8,}\.[A-Za-z0-9_-]{8,}/g
|
|
1655
|
+
},
|
|
1656
|
+
{
|
|
1657
|
+
re: /(-----BEGIN [A-Z ]*PRIVATE KEY-----)[\s\S]*?-----END [A-Z ]*PRIVATE KEY-----/g
|
|
1658
|
+
},
|
|
1659
|
+
// `https://x-access-token:<token>@github.com/…` (the git credential shape the pod scrubbed already)
|
|
1660
|
+
{
|
|
1661
|
+
re: /\b(x-access-token:)[^@\s]+(@)/g,
|
|
1662
|
+
suffix: true
|
|
1663
|
+
}
|
|
1664
|
+
];
|
|
1665
|
+
var SECRET_NAME = "(?:authorization|proxy-authorization|x-api-key|x-wf-[a-z-]*key|x-internal-auth|api[_-]?key|apikey|access[_-]?key|secret[_-]?key|private[_-]?key|client[_-]?secret|secret|password|passwd|pwd|passphrase|token|credentials?)";
|
|
1666
|
+
var SECRET_PAIR_PATTERNS = [
|
|
1667
|
+
// `Authorization: Bearer x`, `x-api-key: x`, `AWS_SECRET_ACCESS_KEY=x`, `SVC_JOB_KEY=x`, `"apiKey": "x"`,
|
|
1668
|
+
// `FOO_TOKEN=x`, `secretKey=x`, `password=x`. Groups: the char before the name, the name, the separator
|
|
1669
|
+
// (with its quotes), the scheme word — all kept; the value goes. A value a literal rule already replaced
|
|
1670
|
+
// (`x-access-token:[REDACTED]@host`) is left alone so the host after it survives.
|
|
1671
|
+
{
|
|
1672
|
+
re: new RegExp(`(^|[^A-Za-z0-9])((?:[A-Za-z0-9-]+[_-])?${SECRET_NAME}|[A-Za-z0-9-]+_key)(["']?\\s*[:=]\\s*["']?)((?:basic\\s+|bearer\\s+|token\\s+)?)(?!\\[REDACTED\\])[^\\s"',;)}&]{4,}`, "gi")
|
|
1673
|
+
},
|
|
1674
|
+
// `?token=x`, `&key=x`, `&X-Amz-Signature=x`, `&sig=x`
|
|
1675
|
+
{
|
|
1676
|
+
re: /([?&](?:token|key|api[_-]?key|apikey|access[_-]?token|id[_-]?token|auth|sig|signature|secret|password|pwd|x-amz-signature|x-amz-credential|x-amz-security-token)=)[^&\s"'#]+/gi
|
|
1677
|
+
},
|
|
1678
|
+
// `mongodb+srv://user:pass@host`, `postgres://user:pass@host`, `https://user:pass@host`
|
|
1679
|
+
{
|
|
1680
|
+
re: /(\/\/[^\s/:@]+:)[^\s/@]+(@)/g,
|
|
1681
|
+
suffix: true
|
|
1682
|
+
},
|
|
1683
|
+
// `Basic <base64>` / `bearer <short token>` (the literal list needs ≥ 16 chars; any case)
|
|
1684
|
+
{
|
|
1685
|
+
re: /\b((?:Basic|Bearer)\s+)(?!\[REDACTED\])[A-Za-z0-9+/=_.-]{8,}/gi
|
|
1686
|
+
}
|
|
1687
|
+
];
|
|
1688
|
+
var GROUP_COUNT = /* @__PURE__ */ new WeakMap();
|
|
1689
|
+
function groupCount(re) {
|
|
1690
|
+
let n2 = GROUP_COUNT.get(re);
|
|
1691
|
+
if (n2 === void 0) {
|
|
1692
|
+
n2 = new RegExp(`${re.source}|`, re.flags.replace("g", "")).exec("").length - 1;
|
|
1693
|
+
GROUP_COUNT.set(re, n2);
|
|
1694
|
+
}
|
|
1695
|
+
return n2;
|
|
1696
|
+
}
|
|
1697
|
+
__name(groupCount, "groupCount");
|
|
1698
|
+
__name2(groupCount, "groupCount");
|
|
1699
|
+
function applyPatterns(text, patterns) {
|
|
1700
|
+
let out = text;
|
|
1701
|
+
for (const { re, suffix } of patterns) {
|
|
1702
|
+
re.lastIndex = 0;
|
|
1703
|
+
if (!re.test(out)) continue;
|
|
1704
|
+
re.lastIndex = 0;
|
|
1705
|
+
const groups = groupCount(re);
|
|
1706
|
+
out = out.replace(re, (...args) => {
|
|
1707
|
+
const kept = args.slice(1, 1 + groups).map((g) => typeof g === "string" ? g : "");
|
|
1708
|
+
if (suffix && kept.length > 0) {
|
|
1709
|
+
const tail = kept[kept.length - 1];
|
|
1710
|
+
return `${kept.slice(0, -1).join("")}${REDACTED_PLACEHOLDER}${tail}`;
|
|
1711
|
+
}
|
|
1712
|
+
return `${kept.join("")}${REDACTED_PLACEHOLDER}`;
|
|
1713
|
+
});
|
|
1714
|
+
}
|
|
1715
|
+
return out;
|
|
1716
|
+
}
|
|
1717
|
+
__name(applyPatterns, "applyPatterns");
|
|
1718
|
+
__name2(applyPatterns, "applyPatterns");
|
|
1719
|
+
function scrubSecretText(text) {
|
|
1720
|
+
if (typeof text !== "string" || text.length < 4) return text;
|
|
1721
|
+
return applyPatterns(applyPatterns(text, SECRET_LITERAL_PATTERNS), SECRET_PAIR_PATTERNS);
|
|
1722
|
+
}
|
|
1723
|
+
__name(scrubSecretText, "scrubSecretText");
|
|
1724
|
+
__name2(scrubSecretText, "scrubSecretText");
|
|
1725
|
+
function scrubSecretLines(lines) {
|
|
1726
|
+
return lines.map((l) => typeof l === "string" ? scrubSecretText(l) : l);
|
|
1727
|
+
}
|
|
1728
|
+
__name(scrubSecretLines, "scrubSecretLines");
|
|
1729
|
+
__name2(scrubSecretLines, "scrubSecretLines");
|
|
1730
|
+
function messageText(value3) {
|
|
1731
|
+
if (typeof value3 === "string") return value3;
|
|
1732
|
+
if (value3 instanceof Error) return value3.message;
|
|
1733
|
+
if (value3 && typeof value3 === "object") {
|
|
1734
|
+
const m = value3.message;
|
|
1735
|
+
if (typeof m === "string") return m;
|
|
1736
|
+
try {
|
|
1737
|
+
return JSON.stringify(value3);
|
|
1738
|
+
} catch {
|
|
1739
|
+
return "";
|
|
1740
|
+
}
|
|
1741
|
+
}
|
|
1742
|
+
return value3 === void 0 || value3 === null ? "" : String(value3);
|
|
1743
|
+
}
|
|
1744
|
+
__name(messageText, "messageText");
|
|
1745
|
+
__name2(messageText, "messageText");
|
|
1746
|
+
function scrubProviderMessage(raw, max = PROVIDER_MESSAGE_MAX_CHARS) {
|
|
1747
|
+
const text = messageText(raw).replace(/\s+/g, " ").trim();
|
|
1748
|
+
if (!text) return void 0;
|
|
1749
|
+
const out = scrubSecretText(text);
|
|
1750
|
+
return out.length > max ? `${out.slice(0, max - 1)}\u2026` : out;
|
|
1751
|
+
}
|
|
1752
|
+
__name(scrubProviderMessage, "scrubProviderMessage");
|
|
1753
|
+
__name2(scrubProviderMessage, "scrubProviderMessage");
|
|
1602
1754
|
var WORKFLOW_AUDIT_EVENTS = [
|
|
1603
1755
|
// --- definitions / versions / templates (13, 11 §11.11.5) ---
|
|
1604
1756
|
"workflow.published",
|
|
@@ -1811,10 +1963,31 @@ __name2(renderTargetsBlock, "renderTargetsBlock");
|
|
|
1811
1963
|
|
|
1812
1964
|
// ../workflow-graph/dist/index.mjs
|
|
1813
1965
|
import { z as z4 } from "zod";
|
|
1966
|
+
import { z as z22 } from "zod";
|
|
1814
1967
|
import { createHash as createHash2 } from "crypto";
|
|
1815
1968
|
var __defProp3 = Object.defineProperty;
|
|
1816
1969
|
var __name3 = /* @__PURE__ */ __name((target, value22) => __defProp3(target, "name", { value: value22, configurable: true }), "__name");
|
|
1970
|
+
var WORKFLOW_SIDE_EFFECTS = [
|
|
1971
|
+
"none",
|
|
1972
|
+
"external"
|
|
1973
|
+
];
|
|
1974
|
+
var WORKFLOW_JOB_RESOURCES = [
|
|
1975
|
+
"small",
|
|
1976
|
+
"medium",
|
|
1977
|
+
"large"
|
|
1978
|
+
];
|
|
1979
|
+
var SideEffectsSchema = z4.enum(WORKFLOW_SIDE_EFFECTS);
|
|
1980
|
+
var JobResourcesSchema = z4.enum(WORKFLOW_JOB_RESOURCES);
|
|
1817
1981
|
var WORKFLOW_ARM_SUBRUN_ID = "$arm";
|
|
1982
|
+
var SLEEP_UNTIL_REPLACEMENT = Object.freeze({
|
|
1983
|
+
type: "sleep",
|
|
1984
|
+
duration: 6e4
|
|
1985
|
+
});
|
|
1986
|
+
function sleepUntilUnsupportedMessage(id) {
|
|
1987
|
+
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} }`;
|
|
1988
|
+
}
|
|
1989
|
+
__name(sleepUntilUnsupportedMessage, "sleepUntilUnsupportedMessage");
|
|
1990
|
+
__name3(sleepUntilUnsupportedMessage, "sleepUntilUnsupportedMessage");
|
|
1818
1991
|
var WORKFLOW_CAPS_DEFAULT = Object.freeze({
|
|
1819
1992
|
maxParallelArms: 16,
|
|
1820
1993
|
maxForeachConcurrency: 16,
|
|
@@ -1944,6 +2117,17 @@ function withDefaultsFilled(g) {
|
|
|
1944
2117
|
}
|
|
1945
2118
|
__name(withDefaultsFilled, "withDefaultsFilled");
|
|
1946
2119
|
__name3(withDefaultsFilled, "withDefaultsFilled");
|
|
2120
|
+
var CONNECTION_ID_HEX_RE = /^[0-9a-f]{24}$/;
|
|
2121
|
+
function isConnectionKeyShaped(value22) {
|
|
2122
|
+
return WORKFLOW_CONNECTION_KEY_RE.test(value22) && !CONNECTION_ID_HEX_RE.test(value22);
|
|
2123
|
+
}
|
|
2124
|
+
__name(isConnectionKeyShaped, "isConnectionKeyShaped");
|
|
2125
|
+
__name3(isConnectionKeyShaped, "isConnectionKeyShaped");
|
|
2126
|
+
function connectionKeyUndeclaredMessage(path, key) {
|
|
2127
|
+
return `${path} '${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`;
|
|
2128
|
+
}
|
|
2129
|
+
__name(connectionKeyUndeclaredMessage, "connectionKeyUndeclaredMessage");
|
|
2130
|
+
__name3(connectionKeyUndeclaredMessage, "connectionKeyUndeclaredMessage");
|
|
1947
2131
|
var WORKFLOW_JOB_TOOLS = [
|
|
1948
2132
|
"shell",
|
|
1949
2133
|
"read",
|
|
@@ -2087,6 +2271,33 @@ function validateLuaExtensions(g, caps = WORKFLOW_CAPS_DEFAULT, opts = {
|
|
|
2087
2271
|
if (envelopeWorkspace?.backend && envelopeWorkspace.backend !== "ebs" && opts.policy?.workspaceBackends && !opts.policy.workspaceBackends.includes(envelopeWorkspace.backend)) {
|
|
2088
2272
|
err("workspace-backend-unavailable", `workspace.backend '${envelopeWorkspace.backend}' is not enabled (LUA_WF_WORKSPACE_BACKENDS = ${opts.policy.workspaceBackends.join(",")}) \u2014 'ebs' is the normative fallback`, "workspace.backend");
|
|
2089
2273
|
}
|
|
2274
|
+
const declaredKeys = new Set(opts.connectionKeys ?? []);
|
|
2275
|
+
if (g.connections !== void 0 && !Array.isArray(g.connections)) {
|
|
2276
|
+
err("connection-declaration-invalid", "`connections` must be an array of { key, integrationType }", "connections");
|
|
2277
|
+
}
|
|
2278
|
+
(Array.isArray(g.connections) ? g.connections : []).forEach((c, i) => {
|
|
2279
|
+
const path = `connections.${i}`;
|
|
2280
|
+
const key = c?.key;
|
|
2281
|
+
const integrationType = c?.integrationType;
|
|
2282
|
+
if (typeof key !== "string" || !WORKFLOW_CONNECTION_KEY_RE.test(key)) {
|
|
2283
|
+
err("connection-declaration-invalid", `connections[${i}].key must match ${WORKFLOW_CONNECTION_KEY_RE}`, `${path}.key`);
|
|
2284
|
+
return;
|
|
2285
|
+
}
|
|
2286
|
+
if (declaredKeys.has(key)) {
|
|
2287
|
+
err("connection-declaration-invalid", `connections[${i}].key "${key}" is declared twice`, `${path}.key`);
|
|
2288
|
+
return;
|
|
2289
|
+
}
|
|
2290
|
+
if (typeof integrationType !== "string" || !integrationType.trim()) {
|
|
2291
|
+
err("connection-declaration-invalid", `connections[${i}] ("${key}") needs an integrationType (the catalog slug, e.g. 'github')`, `${path}.integrationType`);
|
|
2292
|
+
return;
|
|
2293
|
+
}
|
|
2294
|
+
declaredKeys.add(key);
|
|
2295
|
+
});
|
|
2296
|
+
const undeclaredKey = /* @__PURE__ */ __name3((ref) => typeof ref === "string" && !declaredKeys.has(ref) && isConnectionKeyShaped(ref) && opts.connectionIds?.has(ref) !== true, "undeclaredKey");
|
|
2297
|
+
const credentialsRef = envelopeWorkspace?.credentialsRef;
|
|
2298
|
+
if (undeclaredKey(credentialsRef)) {
|
|
2299
|
+
err("connection-key-undeclared", connectionKeyUndeclaredMessage("workspace.credentialsRef", credentialsRef), "workspace.credentialsRef");
|
|
2300
|
+
}
|
|
2090
2301
|
const seen = /* @__PURE__ */ new Map();
|
|
2091
2302
|
let nodeCount = 0;
|
|
2092
2303
|
const upstream = /* @__PURE__ */ new Set();
|
|
@@ -2098,6 +2309,16 @@ function validateLuaExtensions(g, caps = WORKFLOW_CAPS_DEFAULT, opts = {
|
|
|
2098
2309
|
seen.set(id, path);
|
|
2099
2310
|
}
|
|
2100
2311
|
}, "checkId");
|
|
2312
|
+
const checkPolicyEnums = /* @__PURE__ */ __name3((node, path) => {
|
|
2313
|
+
const id = singleId(node);
|
|
2314
|
+
const check = /* @__PURE__ */ __name3((member, allowed) => {
|
|
2315
|
+
const value22 = node[member];
|
|
2316
|
+
if (value22 === void 0 || typeof value22 === "string" && allowed.includes(value22)) return;
|
|
2317
|
+
err("invalid-envelope", `\`${member}\` must be ${allowed.map((a) => `'${a}'`).join(" | ")} (got ${JSON.stringify(value22)})`, `${path}.${member}`, id);
|
|
2318
|
+
}, "check");
|
|
2319
|
+
check("sideEffects", WORKFLOW_SIDE_EFFECTS);
|
|
2320
|
+
check("jobResources", WORKFLOW_JOB_RESOURCES);
|
|
2321
|
+
}, "checkPolicyEnums");
|
|
2101
2322
|
const checkRetry = /* @__PURE__ */ __name3((node, path) => {
|
|
2102
2323
|
const r = node.retry;
|
|
2103
2324
|
if (!r) return;
|
|
@@ -2105,6 +2326,9 @@ function validateLuaExtensions(g, caps = WORKFLOW_CAPS_DEFAULT, opts = {
|
|
|
2105
2326
|
if (r.backoff !== void 0 && r.backoff !== "fixed" && r.backoff !== "exponential") {
|
|
2106
2327
|
err("backoff-invalid", `retry.backoff must be 'fixed' | 'exponential'`, `${path}.retry.backoff`, id);
|
|
2107
2328
|
}
|
|
2329
|
+
if (r.backoffSeconds !== void 0 && r.backoffSeconds < 0) {
|
|
2330
|
+
err("backoff-invalid", "retry.backoffSeconds must be \u2265 0", `${path}.retry.backoffSeconds`, id);
|
|
2331
|
+
}
|
|
2108
2332
|
if (r.maxBackoffSeconds !== void 0) {
|
|
2109
2333
|
if (r.backoff !== "exponential") {
|
|
2110
2334
|
err("backoff-invalid", "retry.maxBackoffSeconds is only meaningful with backoff:'exponential'", `${path}.retry`, id);
|
|
@@ -2166,10 +2390,15 @@ function validateLuaExtensions(g, caps = WORKFLOW_CAPS_DEFAULT, opts = {
|
|
|
2166
2390
|
}, "checkSpecialistRole");
|
|
2167
2391
|
const checkRequiredConnections = /* @__PURE__ */ __name3((node, path) => {
|
|
2168
2392
|
const required = node.requiredConnections;
|
|
2169
|
-
if (!Array.isArray(required)
|
|
2170
|
-
const
|
|
2393
|
+
if (!Array.isArray(required)) return;
|
|
2394
|
+
const undeclared = required.filter(undeclaredKey);
|
|
2395
|
+
if (undeclared.length) {
|
|
2396
|
+
err("connection-key-undeclared", connectionKeyUndeclaredMessage(`${path}.requiredConnections`, undeclared[0]) + (undeclared.length > 1 ? ` (also undeclared: ${JSON.stringify(undeclared.slice(1))})` : ""), `${path}.requiredConnections`, singleId(node));
|
|
2397
|
+
}
|
|
2398
|
+
if (!opts.connectionIds) return;
|
|
2399
|
+
const unknown = required.filter((c) => typeof c !== "string" || !declaredKeys.has(c) && !opts.connectionIds.has(c));
|
|
2171
2400
|
if (unknown.length) {
|
|
2172
|
-
err("required-connection-unknown", `requiredConnections ${JSON.stringify(unknown)} are
|
|
2401
|
+
err("required-connection-unknown", `requiredConnections ${JSON.stringify(unknown)} are neither declared connections[].key values nor connections the owner can mount`, `${path}.requiredConnections`, singleId(node));
|
|
2173
2402
|
}
|
|
2174
2403
|
}, "checkRequiredConnections");
|
|
2175
2404
|
const checkTier = /* @__PURE__ */ __name3((node, path) => {
|
|
@@ -2255,6 +2484,7 @@ function validateLuaExtensions(g, caps = WORKFLOW_CAPS_DEFAULT, opts = {
|
|
|
2255
2484
|
return;
|
|
2256
2485
|
}
|
|
2257
2486
|
checkId(singleId(node), path);
|
|
2487
|
+
checkPolicyEnums(node, path);
|
|
2258
2488
|
checkTimeout(node, path);
|
|
2259
2489
|
checkTier(node, path);
|
|
2260
2490
|
checkRetry(node, path);
|
|
@@ -2321,6 +2551,7 @@ function validateLuaExtensions(g, caps = WORKFLOW_CAPS_DEFAULT, opts = {
|
|
|
2321
2551
|
case "sleepUntil": {
|
|
2322
2552
|
const s = entry;
|
|
2323
2553
|
checkId(s.id, path);
|
|
2554
|
+
err("node-type-unsupported-by-engine", sleepUntilUnsupportedMessage(s.id), path, s.id);
|
|
2324
2555
|
if (s.date === void 0 === (s.dateFrom === void 0)) {
|
|
2325
2556
|
err("invalid-envelope", "sleepUntil needs exactly one of `date` | `dateFrom`", path, s.id);
|
|
2326
2557
|
}
|
|
@@ -2366,7 +2597,7 @@ function validateLuaExtensions(g, caps = WORKFLOW_CAPS_DEFAULT, opts = {
|
|
|
2366
2597
|
err("invalid-envelope", "conditional.predicates must match conditional.steps one-to-one", path);
|
|
2367
2598
|
}
|
|
2368
2599
|
(c.predicates ?? []).forEach((p, j) => {
|
|
2369
|
-
if (!
|
|
2600
|
+
if (!isWellFormedPredicate(p)) err("closure-predicate", "a conditional predicate must be a well-formed LuaPredicate object ({op, left/right | value | path | args | arg}), not a function or an expression string", `${path}.predicates.${j}`);
|
|
2370
2601
|
});
|
|
2371
2602
|
c.steps.forEach((arm, j) => {
|
|
2372
2603
|
checkArm(arm, `${path}.steps.${j}`, 1);
|
|
@@ -2446,7 +2677,7 @@ function validateLuaExtensions(g, caps = WORKFLOW_CAPS_DEFAULT, opts = {
|
|
|
2446
2677
|
if (l.intervalSeconds !== void 0 && (!Number.isInteger(l.intervalSeconds) || l.intervalSeconds < 1 || l.intervalSeconds > caps.maxLoopIntervalSeconds)) {
|
|
2447
2678
|
err("loop-interval-out-of-range", `loop.intervalSeconds must be an integer in 1..${caps.maxLoopIntervalSeconds}`, `${path}.intervalSeconds`);
|
|
2448
2679
|
}
|
|
2449
|
-
if (!
|
|
2680
|
+
if (!isWellFormedPredicate(l.predicate)) err("closure-predicate", "a loop predicate must be a well-formed LuaPredicate object ({op, left/right | value | path | args | arg}), not a function or an expression string", `${path}.predicate`);
|
|
2450
2681
|
const bodyType = l.step.type;
|
|
2451
2682
|
if (bodyType === "mapping") err("container-arm-empty", "a loop body needs a step, not a bare mapping", `${path}.step`);
|
|
2452
2683
|
else if (bodyType === "approval" || bodyType === "waitForSignal") err("approval-inside-container", "approval / waitForSignal are top-level only in v1", `${path}.step`);
|
|
@@ -2531,6 +2762,46 @@ function isPredicate(p) {
|
|
|
2531
2762
|
}
|
|
2532
2763
|
__name(isPredicate, "isPredicate");
|
|
2533
2764
|
__name3(isPredicate, "isPredicate");
|
|
2765
|
+
var isPredicateScalar = /* @__PURE__ */ __name3((v) => v === null || typeof v === "string" || typeof v === "number" || typeof v === "boolean", "isPredicateScalar");
|
|
2766
|
+
function isPathOrLiteral(v) {
|
|
2767
|
+
if (typeof v !== "object" || v === null) return false;
|
|
2768
|
+
const r = v;
|
|
2769
|
+
if ("path" in r) return typeof r.path === "string" && r.path.length > 0;
|
|
2770
|
+
return "literal" in r && isPredicateScalar(r.literal);
|
|
2771
|
+
}
|
|
2772
|
+
__name(isPathOrLiteral, "isPathOrLiteral");
|
|
2773
|
+
__name3(isPathOrLiteral, "isPathOrLiteral");
|
|
2774
|
+
function isWellFormedPredicate(p) {
|
|
2775
|
+
if (!isPredicate(p)) return false;
|
|
2776
|
+
const r = p;
|
|
2777
|
+
switch (r.op) {
|
|
2778
|
+
case "eq":
|
|
2779
|
+
case "ne":
|
|
2780
|
+
case "lt":
|
|
2781
|
+
case "lte":
|
|
2782
|
+
case "gt":
|
|
2783
|
+
case "gte":
|
|
2784
|
+
return isPathOrLiteral(r.left) && isPathOrLiteral(r.right);
|
|
2785
|
+
case "in":
|
|
2786
|
+
case "notIn":
|
|
2787
|
+
return isPathOrLiteral(r.value) && Array.isArray(r.set) && r.set.every(isPredicateScalar);
|
|
2788
|
+
case "exists":
|
|
2789
|
+
case "notExists":
|
|
2790
|
+
return typeof r.path === "string" && r.path.length > 0;
|
|
2791
|
+
case "truthy":
|
|
2792
|
+
case "falsy":
|
|
2793
|
+
return isPathOrLiteral(r.value);
|
|
2794
|
+
case "and":
|
|
2795
|
+
case "or":
|
|
2796
|
+
return Array.isArray(r.args) && r.args.every(isWellFormedPredicate);
|
|
2797
|
+
case "not":
|
|
2798
|
+
return isWellFormedPredicate(r.arg);
|
|
2799
|
+
default:
|
|
2800
|
+
return false;
|
|
2801
|
+
}
|
|
2802
|
+
}
|
|
2803
|
+
__name(isWellFormedPredicate, "isWellFormedPredicate");
|
|
2804
|
+
__name3(isWellFormedPredicate, "isWellFormedPredicate");
|
|
2534
2805
|
var GRAPH_HASH_PREFIX = "sha256-cj1:";
|
|
2535
2806
|
function canonicalJson(value22) {
|
|
2536
2807
|
const seen = /* @__PURE__ */ new WeakSet();
|
|
@@ -3281,6 +3552,76 @@ var rows = /* @__PURE__ */ __name3((s, path, page) => ({
|
|
|
3281
3552
|
var fromKnowledge = /* @__PURE__ */ __name3((k) => ({
|
|
3282
3553
|
knowledge: k
|
|
3283
3554
|
}), "fromKnowledge");
|
|
3555
|
+
var CONTINUED_FAILURE_TAG = "continued_failure";
|
|
3556
|
+
var CONTINUED_FAILURE_DEFAULT_CODE = "step_failed";
|
|
3557
|
+
var CONTINUED_FAILURE_OUTPUT_SCHEMA = Object.freeze({
|
|
3558
|
+
type: "object",
|
|
3559
|
+
properties: {
|
|
3560
|
+
__lua_workflow: {
|
|
3561
|
+
type: "string",
|
|
3562
|
+
const: CONTINUED_FAILURE_TAG
|
|
3563
|
+
},
|
|
3564
|
+
failed: {
|
|
3565
|
+
type: "boolean",
|
|
3566
|
+
const: true
|
|
3567
|
+
},
|
|
3568
|
+
error: {
|
|
3569
|
+
type: "object",
|
|
3570
|
+
properties: {
|
|
3571
|
+
code: {
|
|
3572
|
+
type: "string"
|
|
3573
|
+
},
|
|
3574
|
+
message: {
|
|
3575
|
+
type: "string"
|
|
3576
|
+
}
|
|
3577
|
+
},
|
|
3578
|
+
required: [
|
|
3579
|
+
"code",
|
|
3580
|
+
"message"
|
|
3581
|
+
]
|
|
3582
|
+
},
|
|
3583
|
+
text: {
|
|
3584
|
+
type: "string",
|
|
3585
|
+
const: ""
|
|
3586
|
+
}
|
|
3587
|
+
},
|
|
3588
|
+
required: [
|
|
3589
|
+
"__lua_workflow",
|
|
3590
|
+
"failed",
|
|
3591
|
+
"error",
|
|
3592
|
+
"text"
|
|
3593
|
+
]
|
|
3594
|
+
});
|
|
3595
|
+
var CONTINUED_FAILURE_LEAF_PATHS = Object.freeze([
|
|
3596
|
+
"failed",
|
|
3597
|
+
"error",
|
|
3598
|
+
"error.code",
|
|
3599
|
+
"error.message",
|
|
3600
|
+
"text"
|
|
3601
|
+
]);
|
|
3602
|
+
function continuedFailureValue(error, killReason) {
|
|
3603
|
+
const code = typeof error?.code === "string" && error.code || typeof killReason === "string" && killReason || CONTINUED_FAILURE_DEFAULT_CODE;
|
|
3604
|
+
const message = typeof error?.message === "string" && error.message ? error.message : code;
|
|
3605
|
+
return {
|
|
3606
|
+
__lua_workflow: CONTINUED_FAILURE_TAG,
|
|
3607
|
+
failed: true,
|
|
3608
|
+
error: {
|
|
3609
|
+
code,
|
|
3610
|
+
message
|
|
3611
|
+
},
|
|
3612
|
+
text: ""
|
|
3613
|
+
};
|
|
3614
|
+
}
|
|
3615
|
+
__name(continuedFailureValue, "continuedFailureValue");
|
|
3616
|
+
__name3(continuedFailureValue, "continuedFailureValue");
|
|
3617
|
+
function isContinuedFailureValue(v) {
|
|
3618
|
+
if (v === null || typeof v !== "object" || Array.isArray(v)) return false;
|
|
3619
|
+
const o = v;
|
|
3620
|
+
const err = o.error;
|
|
3621
|
+
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";
|
|
3622
|
+
}
|
|
3623
|
+
__name(isContinuedFailureValue, "isContinuedFailureValue");
|
|
3624
|
+
__name3(isContinuedFailureValue, "isContinuedFailureValue");
|
|
3284
3625
|
function lowerContainerArm(mapping, step22) {
|
|
3285
3626
|
const stepId = nodeIdOf(step22);
|
|
3286
3627
|
return {
|
|
@@ -3296,7 +3637,7 @@ function lowerContainerArm(mapping, step22) {
|
|
|
3296
3637
|
}
|
|
3297
3638
|
__name(lowerContainerArm, "lowerContainerArm");
|
|
3298
3639
|
__name3(lowerContainerArm, "lowerContainerArm");
|
|
3299
|
-
var nodeIdOf = /* @__PURE__ */ __name3((
|
|
3640
|
+
var nodeIdOf = /* @__PURE__ */ __name3((n2) => n2.type === "step" ? n2.step.id : n2.id, "nodeIdOf");
|
|
3300
3641
|
function entryIds(entry) {
|
|
3301
3642
|
switch (entry.type) {
|
|
3302
3643
|
case "parallel":
|
|
@@ -3383,7 +3724,7 @@ function resolvePlacements(calls) {
|
|
|
3383
3724
|
if (!d) {
|
|
3384
3725
|
issues.push({
|
|
3385
3726
|
code: "unknown-step-ref",
|
|
3386
|
-
message: `"${ref.ref}" is not declared anywhere in the chain \u2014 declare it with agentStep/specialistStep/toolStep/map(\u2026, { id })`,
|
|
3727
|
+
message: `"${ref.ref}" is not declared anywhere in the chain \u2014 declare it with agentStep/specialistStep/toolStep/map(\u2026, { id })/workflow(\u2026)`,
|
|
3387
3728
|
callIndex: i,
|
|
3388
3729
|
stepId: ref.ref
|
|
3389
3730
|
});
|
|
@@ -3435,9 +3776,9 @@ function resolvePlacements(calls) {
|
|
|
3435
3776
|
});
|
|
3436
3777
|
const graph = [];
|
|
3437
3778
|
const lookup = /* @__PURE__ */ __name3((ref) => {
|
|
3438
|
-
const
|
|
3439
|
-
if (!
|
|
3440
|
-
return lowerContainerArm(ref.armMap,
|
|
3779
|
+
const n2 = "node" in ref ? ref.node : declared.get(ref.ref)?.node;
|
|
3780
|
+
if (!n2 || !ref.armMap || n2.type === "mapping") return n2;
|
|
3781
|
+
return lowerContainerArm(ref.armMap, n2);
|
|
3441
3782
|
}, "lookup");
|
|
3442
3783
|
calls.forEach((call, i) => {
|
|
3443
3784
|
switch (call.kind) {
|
|
@@ -3456,7 +3797,7 @@ function resolvePlacements(calls) {
|
|
|
3456
3797
|
return;
|
|
3457
3798
|
}
|
|
3458
3799
|
case "parallel": {
|
|
3459
|
-
const steps = call.arms.map(lookup).filter((
|
|
3800
|
+
const steps = call.arms.map(lookup).filter((n2) => !!n2 && n2.type !== "mapping");
|
|
3460
3801
|
const node = {
|
|
3461
3802
|
type: "parallel",
|
|
3462
3803
|
steps
|
|
@@ -3469,9 +3810,9 @@ function resolvePlacements(calls) {
|
|
|
3469
3810
|
const steps = [];
|
|
3470
3811
|
const predicates = [];
|
|
3471
3812
|
for (const a of call.arms) {
|
|
3472
|
-
const
|
|
3473
|
-
if (!
|
|
3474
|
-
steps.push(
|
|
3813
|
+
const n2 = lookup(a.target);
|
|
3814
|
+
if (!n2) continue;
|
|
3815
|
+
steps.push(n2);
|
|
3475
3816
|
predicates.push(a.predicate);
|
|
3476
3817
|
}
|
|
3477
3818
|
const node = {
|
|
@@ -3579,7 +3920,35 @@ function seedLedgerFromRun(run, steps, targetPlan, opts = {}) {
|
|
|
3579
3920
|
}
|
|
3580
3921
|
__name(seedLedgerFromRun, "seedLedgerFromRun");
|
|
3581
3922
|
__name3(seedLedgerFromRun, "seedLedgerFromRun");
|
|
3582
|
-
var
|
|
3923
|
+
var branchArmId = /* @__PURE__ */ __name3((arm) => arm.type === "step" ? arm.step.id : arm.id, "branchArmId");
|
|
3924
|
+
function branchSpecFromConditional(entry) {
|
|
3925
|
+
return {
|
|
3926
|
+
arms: entry.steps.map((arm, i) => ({
|
|
3927
|
+
stepId: branchArmId(arm),
|
|
3928
|
+
predicate: entry.predicates[i]
|
|
3929
|
+
})),
|
|
3930
|
+
...entry.exclusive === true ? {
|
|
3931
|
+
exclusive: true
|
|
3932
|
+
} : {},
|
|
3933
|
+
...entry.otherwise ? {
|
|
3934
|
+
otherwise: branchArmId(entry.otherwise)
|
|
3935
|
+
} : {}
|
|
3936
|
+
};
|
|
3937
|
+
}
|
|
3938
|
+
__name(branchSpecFromConditional, "branchSpecFromConditional");
|
|
3939
|
+
__name3(branchSpecFromConditional, "branchSpecFromConditional");
|
|
3940
|
+
function selectBranchArms(spec, ctx) {
|
|
3941
|
+
const taken = [];
|
|
3942
|
+
for (const arm of spec.arms) {
|
|
3943
|
+
if (spec.exclusive && taken.length > 0) break;
|
|
3944
|
+
const hit = arm.predicate ? evaluatePredicate(arm.predicate, ctx) : false;
|
|
3945
|
+
if (hit) taken.push(arm.stepId);
|
|
3946
|
+
}
|
|
3947
|
+
if (taken.length === 0 && spec.otherwise) taken.push(spec.otherwise);
|
|
3948
|
+
return taken;
|
|
3949
|
+
}
|
|
3950
|
+
__name(selectBranchArms, "selectBranchArms");
|
|
3951
|
+
__name3(selectBranchArms, "selectBranchArms");
|
|
3583
3952
|
var canonical = /* @__PURE__ */ __name3((v) => JSON.stringify(sortKeys(v)), "canonical");
|
|
3584
3953
|
var sortKeys = /* @__PURE__ */ __name3((v) => {
|
|
3585
3954
|
if (Array.isArray(v)) return v.map(sortKeys);
|
|
@@ -3597,25 +3966,24 @@ function replayLedger(g, ledger) {
|
|
|
3597
3966
|
r.stepId,
|
|
3598
3967
|
r
|
|
3599
3968
|
]));
|
|
3600
|
-
const
|
|
3601
|
-
|
|
3602
|
-
|
|
3969
|
+
const requestContext = {
|
|
3970
|
+
runId: "replay",
|
|
3971
|
+
workflowId: g.definition.id,
|
|
3972
|
+
orgId: "",
|
|
3973
|
+
agentId: "",
|
|
3974
|
+
userId: "",
|
|
3975
|
+
trigger: "sdk",
|
|
3976
|
+
threadId: "replay",
|
|
3977
|
+
depth: 0,
|
|
3978
|
+
startedAt: 0,
|
|
3979
|
+
...ledger.requestContext
|
|
3980
|
+
};
|
|
3981
|
+
const ctxFor = /* @__PURE__ */ __name3((id) => ({
|
|
3603
3982
|
initData: ledger.initData,
|
|
3604
|
-
stepResults,
|
|
3983
|
+
stepResults: ancestorResults(plan, id, rows22),
|
|
3605
3984
|
state: ledger.state ?? {},
|
|
3606
|
-
requestContext
|
|
3607
|
-
|
|
3608
|
-
workflowId: g.definition.id,
|
|
3609
|
-
orgId: "",
|
|
3610
|
-
agentId: "",
|
|
3611
|
-
userId: "",
|
|
3612
|
-
trigger: "sdk",
|
|
3613
|
-
threadId: "replay",
|
|
3614
|
-
depth: 0,
|
|
3615
|
-
startedAt: 0,
|
|
3616
|
-
...ledger.requestContext
|
|
3617
|
-
}
|
|
3618
|
-
};
|
|
3985
|
+
requestContext
|
|
3986
|
+
}), "ctxFor");
|
|
3619
3987
|
const verdicts = [];
|
|
3620
3988
|
for (const id of plan.order) {
|
|
3621
3989
|
const node = plan.steps[id];
|
|
@@ -3623,17 +3991,7 @@ function replayLedger(g, ledger) {
|
|
|
3623
3991
|
if (!recorded || recorded.status === "pending" || recorded.status === "skipped") continue;
|
|
3624
3992
|
if (node.kind === "branch") {
|
|
3625
3993
|
const entry = node.entry;
|
|
3626
|
-
const taken =
|
|
3627
|
-
entry.steps.forEach((arm, i) => {
|
|
3628
|
-
const pred = entry.predicates[i];
|
|
3629
|
-
const hit = pred ? evaluatePredicate(pred, {
|
|
3630
|
-
initData: ledger.initData,
|
|
3631
|
-
stepResults,
|
|
3632
|
-
state: ledger.state
|
|
3633
|
-
}) : false;
|
|
3634
|
-
if (hit && (!entry.exclusive || taken.length === 0)) taken.push(armId2(arm));
|
|
3635
|
-
});
|
|
3636
|
-
if (taken.length === 0 && entry.otherwise) taken.push(armId2(entry.otherwise));
|
|
3994
|
+
const taken = selectBranchArms(branchSpecFromConditional(entry), ctxFor(id));
|
|
3637
3995
|
const recordedTaken = recorded.taken ?? inferTaken(entry, rows22);
|
|
3638
3996
|
verdicts.push({
|
|
3639
3997
|
stepId: id,
|
|
@@ -3644,7 +4002,7 @@ function replayLedger(g, ledger) {
|
|
|
3644
4002
|
});
|
|
3645
4003
|
} else if (node.kind === "map" && !id.endsWith(".join") && recorded.status === "completed") {
|
|
3646
4004
|
const entry = node.entry;
|
|
3647
|
-
const resolved = resolveMapping(parseMapConfig(entry.mapConfig, id),
|
|
4005
|
+
const resolved = resolveMapping(parseMapConfig(entry.mapConfig, id), ctxFor(id));
|
|
3648
4006
|
const local = "error" in resolved ? {
|
|
3649
4007
|
error: resolved.error,
|
|
3650
4008
|
key: resolved.key
|
|
@@ -3659,7 +4017,7 @@ function replayLedger(g, ledger) {
|
|
|
3659
4017
|
} else if (node.kind === "foreach") {
|
|
3660
4018
|
const entry = node.entry;
|
|
3661
4019
|
const source = node.dependsOn[0];
|
|
3662
|
-
const items = source ? stepResults[source] : void 0;
|
|
4020
|
+
const items = source ? ctxFor(id).stepResults[source] : void 0;
|
|
3663
4021
|
const local = Array.isArray(items) ? items.length : void 0;
|
|
3664
4022
|
const recordedCount = recorded.itemCount ?? countChildren(entry, rows22);
|
|
3665
4023
|
verdicts.push({
|
|
@@ -3678,6 +4036,77 @@ function replayLedger(g, ledger) {
|
|
|
3678
4036
|
}
|
|
3679
4037
|
__name(replayLedger, "replayLedger");
|
|
3680
4038
|
__name3(replayLedger, "replayLedger");
|
|
4039
|
+
var JOIN = ".join";
|
|
4040
|
+
var entryOfJoin = /* @__PURE__ */ __name3((id) => id.endsWith(JOIN) ? id.slice(0, -JOIN.length) : void 0, "entryOfJoin");
|
|
4041
|
+
function replayResultOf(row, node) {
|
|
4042
|
+
if (!row) return void 0;
|
|
4043
|
+
if (row.status === "completed") return {
|
|
4044
|
+
value: row.output
|
|
4045
|
+
};
|
|
4046
|
+
if (row.status === "failed") {
|
|
4047
|
+
const onError = row.onError ?? node?.entry?.onError;
|
|
4048
|
+
if (onError === "continue") return {
|
|
4049
|
+
value: continuedFailureValue(row.error, row.killReason)
|
|
4050
|
+
};
|
|
4051
|
+
}
|
|
4052
|
+
return void 0;
|
|
4053
|
+
}
|
|
4054
|
+
__name(replayResultOf, "replayResultOf");
|
|
4055
|
+
__name3(replayResultOf, "replayResultOf");
|
|
4056
|
+
function ancestorResults(plan, id, rows22) {
|
|
4057
|
+
const out = {};
|
|
4058
|
+
const joinAliased = /* @__PURE__ */ new Set();
|
|
4059
|
+
const seen = /* @__PURE__ */ new Set();
|
|
4060
|
+
const take = /* @__PURE__ */ __name3((rowId) => {
|
|
4061
|
+
const hit = replayResultOf(rows22.get(rowId), plan.steps[rowId]);
|
|
4062
|
+
if (!hit) return void 0;
|
|
4063
|
+
if (!joinAliased.has(rowId)) out[rowId] = hit.value;
|
|
4064
|
+
const entryId = entryOfJoin(rowId);
|
|
4065
|
+
if (entryId) {
|
|
4066
|
+
out[entryId] = hit.value;
|
|
4067
|
+
joinAliased.add(entryId);
|
|
4068
|
+
const entryNode = plan.steps[entryId];
|
|
4069
|
+
if (entryNode?.kind === "foreach") {
|
|
4070
|
+
const body = branchArmId(entryNode.entry.step);
|
|
4071
|
+
out[body] = hit.value;
|
|
4072
|
+
joinAliased.add(body);
|
|
4073
|
+
}
|
|
4074
|
+
}
|
|
4075
|
+
return hit;
|
|
4076
|
+
}, "take");
|
|
4077
|
+
const walk2 = /* @__PURE__ */ __name3((ids) => {
|
|
4078
|
+
for (const dep of ids) {
|
|
4079
|
+
if (seen.has(dep)) continue;
|
|
4080
|
+
seen.add(dep);
|
|
4081
|
+
take(dep);
|
|
4082
|
+
const node = plan.steps[dep] ?? plan.steps[entryOfJoin(dep) ?? ""];
|
|
4083
|
+
if (!node) continue;
|
|
4084
|
+
if (node.kind === "foreach") {
|
|
4085
|
+
const body = branchArmId(node.entry.step);
|
|
4086
|
+
for (const rowId of rows22.keys()) if (rowId.startsWith(`${body}[`)) take(rowId);
|
|
4087
|
+
} else if (node.kind === "loop") {
|
|
4088
|
+
const body = branchArmId(node.entry.step);
|
|
4089
|
+
let best = -1;
|
|
4090
|
+
for (const rowId of rows22.keys()) {
|
|
4091
|
+
if (!rowId.startsWith(`${body}#`)) continue;
|
|
4092
|
+
const n2 = Number(rowId.slice(body.length + 1));
|
|
4093
|
+
if (!Number.isInteger(n2)) continue;
|
|
4094
|
+
const hit = take(rowId);
|
|
4095
|
+
if (!hit) continue;
|
|
4096
|
+
if (n2 > best) {
|
|
4097
|
+
best = n2;
|
|
4098
|
+
out[body] = hit.value;
|
|
4099
|
+
}
|
|
4100
|
+
}
|
|
4101
|
+
}
|
|
4102
|
+
walk2(node.dependsOn);
|
|
4103
|
+
}
|
|
4104
|
+
}, "walk");
|
|
4105
|
+
walk2(plan.steps[id]?.dependsOn ?? []);
|
|
4106
|
+
return out;
|
|
4107
|
+
}
|
|
4108
|
+
__name(ancestorResults, "ancestorResults");
|
|
4109
|
+
__name3(ancestorResults, "ancestorResults");
|
|
3681
4110
|
function inferTaken(entry, rows22) {
|
|
3682
4111
|
const arms = [
|
|
3683
4112
|
...entry.steps,
|
|
@@ -3685,7 +4114,7 @@ function inferTaken(entry, rows22) {
|
|
|
3685
4114
|
entry.otherwise
|
|
3686
4115
|
] : []
|
|
3687
4116
|
];
|
|
3688
|
-
return arms.map(
|
|
4117
|
+
return arms.map(branchArmId).filter((id) => {
|
|
3689
4118
|
const r = rows22.get(id);
|
|
3690
4119
|
return r !== void 0 && r.status !== "skipped" && r.status !== "pending";
|
|
3691
4120
|
});
|
|
@@ -3693,10 +4122,10 @@ function inferTaken(entry, rows22) {
|
|
|
3693
4122
|
__name(inferTaken, "inferTaken");
|
|
3694
4123
|
__name3(inferTaken, "inferTaken");
|
|
3695
4124
|
function countChildren(entry, rows22) {
|
|
3696
|
-
const body =
|
|
3697
|
-
let
|
|
3698
|
-
for (const id of rows22.keys()) if (id.startsWith(`${body}[`))
|
|
3699
|
-
return
|
|
4125
|
+
const body = branchArmId(entry.step);
|
|
4126
|
+
let n2 = 0;
|
|
4127
|
+
for (const id of rows22.keys()) if (id.startsWith(`${body}[`)) n2 += 1;
|
|
4128
|
+
return n2;
|
|
3700
4129
|
}
|
|
3701
4130
|
__name(countChildren, "countChildren");
|
|
3702
4131
|
__name3(countChildren, "countChildren");
|
|
@@ -3713,21 +4142,58 @@ function pruneUndefined(o) {
|
|
|
3713
4142
|
__name(pruneUndefined, "pruneUndefined");
|
|
3714
4143
|
__name3(pruneUndefined, "pruneUndefined");
|
|
3715
4144
|
function runNextAction(run) {
|
|
3716
|
-
if (isTerminalRunStatus(run.status)
|
|
4145
|
+
if (isTerminalRunStatus(run.status)) return "none";
|
|
4146
|
+
if (run.status === "suspended" && run.gate?.kind === "budget") return "raise_budget";
|
|
4147
|
+
if (!run.cancel?.requestedAt) return "none";
|
|
3717
4148
|
const forceAt = run.cancel.forceAfter ?? run.cancel.requestedAt + FORCE_CANCEL_STALE_MS;
|
|
3718
4149
|
return Date.now() >= forceAt ? "force" : "cancel_again";
|
|
3719
4150
|
}
|
|
3720
4151
|
__name(runNextAction, "runNextAction");
|
|
3721
4152
|
__name3(runNextAction, "runNextAction");
|
|
4153
|
+
var IN_FLIGHT = new Set(WORKFLOW_STEP_IN_FLIGHT);
|
|
4154
|
+
function emptyRunCounts() {
|
|
4155
|
+
const out = {
|
|
4156
|
+
total: 0,
|
|
4157
|
+
inFlight: 0
|
|
4158
|
+
};
|
|
4159
|
+
for (const status of WORKFLOW_STEP_STATUSES) out[status] = 0;
|
|
4160
|
+
return out;
|
|
4161
|
+
}
|
|
4162
|
+
__name(emptyRunCounts, "emptyRunCounts");
|
|
4163
|
+
__name3(emptyRunCounts, "emptyRunCounts");
|
|
4164
|
+
function runCountsFromStatusTally(tally) {
|
|
4165
|
+
const out = emptyRunCounts();
|
|
4166
|
+
for (const [status, n2] of Object.entries(tally)) {
|
|
4167
|
+
if (!Number.isFinite(n2) || n2 <= 0) continue;
|
|
4168
|
+
out.total += n2;
|
|
4169
|
+
if (WORKFLOW_STEP_STATUSES.includes(status)) out[status] += n2;
|
|
4170
|
+
if (IN_FLIGHT.has(status)) out.inFlight += n2;
|
|
4171
|
+
}
|
|
4172
|
+
return out;
|
|
4173
|
+
}
|
|
4174
|
+
__name(runCountsFromStatusTally, "runCountsFromStatusTally");
|
|
4175
|
+
__name3(runCountsFromStatusTally, "runCountsFromStatusTally");
|
|
4176
|
+
function runCountsFromStepStatuses(statuses) {
|
|
4177
|
+
const tally = {};
|
|
4178
|
+
for (const s of statuses) tally[s] = (tally[s] ?? 0) + 1;
|
|
4179
|
+
return runCountsFromStatusTally(tally);
|
|
4180
|
+
}
|
|
4181
|
+
__name(runCountsFromStepStatuses, "runCountsFromStepStatuses");
|
|
4182
|
+
__name3(runCountsFromStepStatuses, "runCountsFromStepStatuses");
|
|
4183
|
+
var n = /* @__PURE__ */ __name3((v) => typeof v === "number" && Number.isFinite(v) ? v : 0, "n");
|
|
3722
4184
|
function runCounts(counts) {
|
|
4185
|
+
const c = counts ?? {};
|
|
4186
|
+
const rawInFlight = c.dispatched !== void 0 || c.claimed !== void 0 || c.running !== void 0 || c.cancellation_requested !== void 0;
|
|
3723
4187
|
return {
|
|
3724
|
-
total:
|
|
3725
|
-
completed:
|
|
3726
|
-
failed:
|
|
3727
|
-
skipped:
|
|
3728
|
-
|
|
3729
|
-
|
|
3730
|
-
|
|
4188
|
+
total: n(c.total),
|
|
4189
|
+
completed: n(c.completed),
|
|
4190
|
+
failed: n(c.failed) + n(c.timeout) + n(c.reaped),
|
|
4191
|
+
skipped: n(c.skipped),
|
|
4192
|
+
// LUA-664: cancelled rows never ran — their own wire bucket, never a failure (the detail's map, verbatim).
|
|
4193
|
+
cancelled: n(c.cancelled),
|
|
4194
|
+
running: rawInFlight ? n(c.dispatched) + n(c.claimed) + n(c.running) + n(c.cancellation_requested) : n(c.inFlight),
|
|
4195
|
+
suspended: n(c.suspended),
|
|
4196
|
+
pending: n(c.pending) + n(c.ready) + n(c.waiting)
|
|
3731
4197
|
};
|
|
3732
4198
|
}
|
|
3733
4199
|
__name(runCounts, "runCounts");
|
|
@@ -3757,7 +4223,7 @@ function runWorkspaceView(ws) {
|
|
|
3757
4223
|
if (!ws) return void 0;
|
|
3758
4224
|
const w = ws;
|
|
3759
4225
|
return pruneUndefined({
|
|
3760
|
-
kind: w.kind ?? "empty",
|
|
4226
|
+
kind: w.spec?.kind ?? w.kind ?? "empty",
|
|
3761
4227
|
backend: w.backend,
|
|
3762
4228
|
status: String(w.status ?? ""),
|
|
3763
4229
|
branch: w.branch,
|
|
@@ -3821,7 +4287,10 @@ function toWorkflowRunSummary(run) {
|
|
|
3821
4287
|
eventSeq: run.eventSeq ?? 0,
|
|
3822
4288
|
cancellable: !isTerminalRunStatus(status),
|
|
3823
4289
|
nextAction: runNextAction(run),
|
|
3824
|
-
workspace: runWorkspaceView(run.workspace)
|
|
4290
|
+
workspace: runWorkspaceView(run.workspace),
|
|
4291
|
+
// LUA-643: the runs list says a result exists; R4 `fields:'full'` (output-ACL gated, audited) serves it. The
|
|
4292
|
+
// stamped flag is what a list page carries (it projects `output` out); the payload members cover R4's full row.
|
|
4293
|
+
hasOutput: run.hasOutput === true || run.output !== void 0 || run.outputRef !== void 0 ? true : void 0
|
|
3825
4294
|
});
|
|
3826
4295
|
}
|
|
3827
4296
|
__name(toWorkflowRunSummary, "toWorkflowRunSummary");
|
|
@@ -4382,54 +4851,54 @@ __name(rebaseItemPointer, "rebaseItemPointer");
|
|
|
4382
4851
|
__name3(rebaseItemPointer, "rebaseItemPointer");
|
|
4383
4852
|
var APPROVER_SPEC_MAX_USERS = 20;
|
|
4384
4853
|
var ESCALATION_MAX_HOPS = 3;
|
|
4385
|
-
var TemplateBindingSchema =
|
|
4386
|
-
template:
|
|
4854
|
+
var TemplateBindingSchema = z22.object({
|
|
4855
|
+
template: z22.string().min(1).max(2048)
|
|
4387
4856
|
}).strict();
|
|
4388
|
-
var ApproverSpecSchema =
|
|
4389
|
-
|
|
4390
|
-
|
|
4391
|
-
|
|
4392
|
-
users:
|
|
4393
|
-
|
|
4857
|
+
var ApproverSpecSchema = z22.union([
|
|
4858
|
+
z22.literal("creator"),
|
|
4859
|
+
z22.literal("org-admins"),
|
|
4860
|
+
z22.object({
|
|
4861
|
+
users: z22.union([
|
|
4862
|
+
z22.array(z22.string().min(1).max(128)).min(1).max(APPROVER_SPEC_MAX_USERS),
|
|
4394
4863
|
TemplateBindingSchema
|
|
4395
4864
|
])
|
|
4396
4865
|
}).strict(),
|
|
4397
|
-
|
|
4398
|
-
role:
|
|
4399
|
-
|
|
4866
|
+
z22.object({
|
|
4867
|
+
role: z22.union([
|
|
4868
|
+
z22.string().min(1).max(128),
|
|
4400
4869
|
TemplateBindingSchema
|
|
4401
4870
|
])
|
|
4402
4871
|
}).strict(),
|
|
4403
|
-
|
|
4404
|
-
group:
|
|
4405
|
-
|
|
4872
|
+
z22.object({
|
|
4873
|
+
group: z22.union([
|
|
4874
|
+
z22.string().min(1).max(128),
|
|
4406
4875
|
TemplateBindingSchema
|
|
4407
4876
|
])
|
|
4408
4877
|
}).strict(),
|
|
4409
|
-
|
|
4410
|
-
governance:
|
|
4411
|
-
policyId:
|
|
4878
|
+
z22.object({
|
|
4879
|
+
governance: z22.object({
|
|
4880
|
+
policyId: z22.string().min(1).max(128)
|
|
4412
4881
|
}).strict()
|
|
4413
4882
|
}).strict()
|
|
4414
4883
|
]);
|
|
4415
|
-
var FourEyesSchema =
|
|
4884
|
+
var FourEyesSchema = z22.object({
|
|
4416
4885
|
edit: ApproverSpecSchema,
|
|
4417
4886
|
approve: ApproverSpecSchema
|
|
4418
4887
|
}).strict();
|
|
4419
|
-
var EscalationHopSchema =
|
|
4888
|
+
var EscalationHopSchema = z22.object({
|
|
4420
4889
|
escalateTo: ApproverSpecSchema,
|
|
4421
|
-
timeoutHours:
|
|
4890
|
+
timeoutHours: z22.number().finite().min(1).max(720)
|
|
4422
4891
|
}).strict();
|
|
4423
|
-
var TerminalOutcomeSchema =
|
|
4892
|
+
var TerminalOutcomeSchema = z22.enum([
|
|
4424
4893
|
"deny",
|
|
4425
4894
|
"cancel-run",
|
|
4426
4895
|
"fail",
|
|
4427
4896
|
"continue"
|
|
4428
4897
|
]);
|
|
4429
|
-
var ApprovalOnTimeoutSchema =
|
|
4898
|
+
var ApprovalOnTimeoutSchema = z22.union([
|
|
4430
4899
|
TerminalOutcomeSchema,
|
|
4431
4900
|
EscalationHopSchema,
|
|
4432
|
-
|
|
4901
|
+
z22.array(z22.union([
|
|
4433
4902
|
TerminalOutcomeSchema,
|
|
4434
4903
|
EscalationHopSchema
|
|
4435
4904
|
])).min(1).max(ESCALATION_MAX_HOPS + 1)
|
|
@@ -4707,8 +5176,8 @@ __name(armEntry, "armEntry");
|
|
|
4707
5176
|
__name3(armEntry, "armEntry");
|
|
4708
5177
|
function ofEntry(e) {
|
|
4709
5178
|
if (!e || typeof e !== "object") return ZERO;
|
|
4710
|
-
const
|
|
4711
|
-
switch (
|
|
5179
|
+
const n2 = e;
|
|
5180
|
+
switch (n2.type) {
|
|
4712
5181
|
case "agent":
|
|
4713
5182
|
return {
|
|
4714
5183
|
steps: {
|
|
@@ -4741,17 +5210,17 @@ function ofEntry(e) {
|
|
|
4741
5210
|
agentCalls: 0
|
|
4742
5211
|
};
|
|
4743
5212
|
case "parallel": {
|
|
4744
|
-
const arms = Array.isArray(
|
|
5213
|
+
const arms = Array.isArray(n2.steps) ? n2.steps : [];
|
|
4745
5214
|
return arms.map(armEntry).map(ofEntry).reduce(add, ZERO);
|
|
4746
5215
|
}
|
|
4747
5216
|
case "conditional": {
|
|
4748
|
-
const arms = (Array.isArray(
|
|
5217
|
+
const arms = (Array.isArray(n2.steps) ? n2.steps : []).map(armEntry).map(ofEntry);
|
|
4749
5218
|
if (arms.length === 0) return ZERO;
|
|
4750
|
-
const hasOtherwise =
|
|
5219
|
+
const hasOtherwise = n2.otherwise !== void 0;
|
|
4751
5220
|
const minArm = arms.reduce((a, b) => b.credits.min < a.credits.min ? b : a);
|
|
4752
5221
|
const maxArm = arms.reduce((a, b) => b.credits.max > a.credits.max ? b : a);
|
|
4753
5222
|
const summed = arms.reduce(add, ZERO);
|
|
4754
|
-
const max =
|
|
5223
|
+
const max = n2.exclusive === true ? maxArm : summed;
|
|
4755
5224
|
const min = hasOtherwise ? minArm : {
|
|
4756
5225
|
...ZERO
|
|
4757
5226
|
};
|
|
@@ -4768,17 +5237,14 @@ function ofEntry(e) {
|
|
|
4768
5237
|
};
|
|
4769
5238
|
}
|
|
4770
5239
|
case "foreach": {
|
|
4771
|
-
const body = ofEntry(armEntry(
|
|
4772
|
-
const opts =
|
|
4773
|
-
const cap = typeof opts.maxItems === "number" && opts.maxItems > 0 ? opts.maxItems :
|
|
5240
|
+
const body = ofEntry(armEntry(n2.step));
|
|
5241
|
+
const opts = n2.opts ?? {};
|
|
5242
|
+
const cap = typeof opts.maxItems === "number" && opts.maxItems > 0 ? opts.maxItems : WORKFLOW_FOREACH_DEFAULT_MAX_ITEMS;
|
|
4774
5243
|
return scale(body, 0, cap);
|
|
4775
5244
|
}
|
|
4776
|
-
case "loop":
|
|
4777
|
-
|
|
4778
|
-
|
|
4779
|
-
const body = ofEntry(armEntry(n.step));
|
|
4780
|
-
const opts = n.options ?? {};
|
|
4781
|
-
const cap = typeof opts.maxIterations === "number" && opts.maxIterations > 0 ? opts.maxIterations : 1;
|
|
5245
|
+
case "loop": {
|
|
5246
|
+
const body = ofEntry(armEntry(n2.step));
|
|
5247
|
+
const cap = typeof n2.maxIterations === "number" && n2.maxIterations > 0 ? n2.maxIterations : WORKFLOW_LOOP_DEFAULT_MAX_ITERATIONS;
|
|
4782
5248
|
return scale(body, 1, cap);
|
|
4783
5249
|
}
|
|
4784
5250
|
default:
|
|
@@ -4813,6 +5279,67 @@ function estimateGraph(envelopeOrGraph) {
|
|
|
4813
5279
|
}
|
|
4814
5280
|
__name(estimateGraph, "estimateGraph");
|
|
4815
5281
|
__name3(estimateGraph, "estimateGraph");
|
|
5282
|
+
var isRecord2 = /* @__PURE__ */ __name3((v) => !!v && typeof v === "object" && !Array.isArray(v), "isRecord");
|
|
5283
|
+
function* singleStepsOf(entry) {
|
|
5284
|
+
if (!isRecord2(entry)) return;
|
|
5285
|
+
switch (entry.type) {
|
|
5286
|
+
case "step":
|
|
5287
|
+
case "agent":
|
|
5288
|
+
case "tool":
|
|
5289
|
+
yield entry;
|
|
5290
|
+
return;
|
|
5291
|
+
case "workflow":
|
|
5292
|
+
yield entry;
|
|
5293
|
+
if (Array.isArray(entry.graph)) yield* singleStepsOf(entry.graph[1]);
|
|
5294
|
+
return;
|
|
5295
|
+
case "parallel":
|
|
5296
|
+
case "conditional":
|
|
5297
|
+
if (Array.isArray(entry.steps)) for (const arm of entry.steps) yield* singleStepsOf(arm);
|
|
5298
|
+
yield* singleStepsOf(entry.otherwise);
|
|
5299
|
+
return;
|
|
5300
|
+
case "foreach":
|
|
5301
|
+
case "loop":
|
|
5302
|
+
yield* singleStepsOf(entry.step);
|
|
5303
|
+
return;
|
|
5304
|
+
default:
|
|
5305
|
+
return;
|
|
5306
|
+
}
|
|
5307
|
+
}
|
|
5308
|
+
__name(singleStepsOf, "singleStepsOf");
|
|
5309
|
+
__name3(singleStepsOf, "singleStepsOf");
|
|
5310
|
+
function entriesOf(graph) {
|
|
5311
|
+
const definition = isRecord2(graph) ? graph.definition : void 0;
|
|
5312
|
+
const entries = isRecord2(definition) ? definition.graph : void 0;
|
|
5313
|
+
return Array.isArray(entries) ? entries : [];
|
|
5314
|
+
}
|
|
5315
|
+
__name(entriesOf, "entriesOf");
|
|
5316
|
+
__name3(entriesOf, "entriesOf");
|
|
5317
|
+
function inheritTargets(graphs) {
|
|
5318
|
+
const targets = /* @__PURE__ */ new Set();
|
|
5319
|
+
for (const graph of graphs) {
|
|
5320
|
+
for (const entry of entriesOf(graph)) {
|
|
5321
|
+
for (const node of singleStepsOf(entry)) {
|
|
5322
|
+
if (node.type === "workflow" && node.workspace === "inherit" && typeof node.workflowId === "string" && node.workflowId.length > 0) {
|
|
5323
|
+
targets.add(node.workflowId);
|
|
5324
|
+
}
|
|
5325
|
+
}
|
|
5326
|
+
}
|
|
5327
|
+
}
|
|
5328
|
+
return targets;
|
|
5329
|
+
}
|
|
5330
|
+
__name(inheritTargets, "inheritTargets");
|
|
5331
|
+
__name3(inheritTargets, "inheritTargets");
|
|
5332
|
+
function needsInheritedWorkspace(graph) {
|
|
5333
|
+
if (!isRecord2(graph) || graph.workspace !== void 0) return false;
|
|
5334
|
+
for (const entry of entriesOf(graph)) {
|
|
5335
|
+
for (const node of singleStepsOf(entry)) {
|
|
5336
|
+
if (node.workspace !== void 0 && node.workspace !== "inherit") return true;
|
|
5337
|
+
}
|
|
5338
|
+
}
|
|
5339
|
+
return false;
|
|
5340
|
+
}
|
|
5341
|
+
__name(needsInheritedWorkspace, "needsInheritedWorkspace");
|
|
5342
|
+
__name3(needsInheritedWorkspace, "needsInheritedWorkspace");
|
|
4816
5343
|
|
|
4817
5344
|
// src/types/workflow.ts
|
|
4818
5345
|
function createStep(s) {
|
|
@@ -5008,7 +5535,7 @@ var LuaWorkflow = class {
|
|
|
5008
5535
|
getEnvTemplateKeys() {
|
|
5009
5536
|
return this.built.envTemplateKeys;
|
|
5010
5537
|
}
|
|
5011
|
-
/** `.workflow(id, ref)` targets by name — `ManifestWorkflow.workflowRefs
|
|
5538
|
+
/** `.workflow(id, ref)` targets by name — `ManifestWorkflow.workflowRefs`; `workspace:'inherit'` marks the inherit children the compiler defers `workspace-not-declared` for. */
|
|
5012
5539
|
getNestedWorkflowRefs() {
|
|
5013
5540
|
return this.built.nestedRefs;
|
|
5014
5541
|
}
|
|
@@ -5038,6 +5565,7 @@ var LuaWorkflow = class {
|
|
|
5038
5565
|
};
|
|
5039
5566
|
if (cfg.concurrencyPolicy !== void 0) envelope.concurrencyPolicy = cfg.concurrencyPolicy;
|
|
5040
5567
|
if (cfg.workspace !== void 0) envelope.workspace = cfg.workspace;
|
|
5568
|
+
if (cfg.connections !== void 0) envelope.connections = cfg.connections;
|
|
5041
5569
|
return withDefaultsFilled(envelope);
|
|
5042
5570
|
}
|
|
5043
5571
|
};
|
|
@@ -5069,16 +5597,16 @@ function stepNodeOf(s) {
|
|
|
5069
5597
|
}
|
|
5070
5598
|
__name(stepNodeOf, "stepNodeOf");
|
|
5071
5599
|
function materializeEntry(entry, steps) {
|
|
5072
|
-
const single = /* @__PURE__ */ __name((
|
|
5073
|
-
if (
|
|
5074
|
-
if (
|
|
5075
|
-
...
|
|
5600
|
+
const single = /* @__PURE__ */ __name((n2) => {
|
|
5601
|
+
if (n2.type === "step" && steps[n2.step.id]) return stepNodeOf(steps[n2.step.id]);
|
|
5602
|
+
if (n2.type === "workflow" && n2.workflowId === WORKFLOW_ARM_SUBRUN_ID && n2.graph) return {
|
|
5603
|
+
...n2,
|
|
5076
5604
|
graph: [
|
|
5077
|
-
|
|
5078
|
-
single(
|
|
5605
|
+
n2.graph[0],
|
|
5606
|
+
single(n2.graph[1])
|
|
5079
5607
|
]
|
|
5080
5608
|
};
|
|
5081
|
-
return
|
|
5609
|
+
return n2;
|
|
5082
5610
|
}, "single");
|
|
5083
5611
|
switch (entry.type) {
|
|
5084
5612
|
case "step":
|
|
@@ -5143,7 +5671,6 @@ var WorkflowBuilderImpl = class WorkflowBuilderImpl2 {
|
|
|
5143
5671
|
if (this.steps[s.id] && this.steps[s.id] !== s) throw new LuaWorkflowBuildError("duplicate-step-id", `step id "${s.id}" is declared twice`);
|
|
5144
5672
|
const tier = s.tier ?? (s.workspace ? "job" : void 0);
|
|
5145
5673
|
if (s.workspace && s.tier !== void 0 && s.tier !== "job") throw new LuaWorkflowBuildError("workspace-requires-job-tier", `"${s.id}": a step mounting a workspace must be tier:'job'`);
|
|
5146
|
-
if (s.workspace && !this.config.workspace) throw new LuaWorkflowBuildError("workspace-not-declared", `"${s.id}" mounts a workspace but createWorkflow declares none`);
|
|
5147
5674
|
if (s.jobTools && tier !== "job") throw new LuaWorkflowBuildError("cap-exceeded", `"${s.id}": jobTools require tier:'job' (job-tools-require-job-tier)`);
|
|
5148
5675
|
assertTimeout({
|
|
5149
5676
|
id: s.id,
|
|
@@ -5384,13 +5911,20 @@ var WorkflowBuilderImpl = class WorkflowBuilderImpl2 {
|
|
|
5384
5911
|
}
|
|
5385
5912
|
const tier = opts.tier ?? (opts.workspace ? "job" : void 0);
|
|
5386
5913
|
if (opts.workspace && opts.tier !== void 0 && opts.tier !== "job") throw new LuaWorkflowBuildError("workspace-requires-job-tier", `"${id}": a step mounting a workspace must be tier:'job'`);
|
|
5387
|
-
if (opts.workspace && !this.config.workspace) throw new LuaWorkflowBuildError("workspace-not-declared", `"${id}" mounts a workspace but createWorkflow declares none`);
|
|
5388
5914
|
if (opts.harness !== void 0 && tier !== "job") throw new LuaWorkflowBuildError("harness-requires-job-tier", `"${id}": harness is only legal on a tier:'job' agent step`);
|
|
5389
5915
|
if (opts.toolScope?.jobTools && tier !== "job") throw new LuaWorkflowBuildError("cap-exceeded", `"${id}": toolScope.jobTools require tier:'job' (job-tools-require-job-tier)`);
|
|
5390
5916
|
if (opts.maxTurns !== void 0) {
|
|
5391
5917
|
if (tier !== "job") throw new LuaWorkflowBuildError("max-turns-requires-job-tier", `"${id}": maxTurns is only legal on a tier:'job' agent step`);
|
|
5392
5918
|
if (!Number.isInteger(opts.maxTurns) || opts.maxTurns < 1 || opts.maxTurns > 500) throw new LuaWorkflowBuildError("max-turns-invalid", `"${id}": maxTurns must be an integer 1..500`);
|
|
5393
5919
|
}
|
|
5920
|
+
if (opts.maxMessages !== void 0) {
|
|
5921
|
+
if (tier !== "job") throw new LuaWorkflowBuildError("max-turns-requires-job-tier", `"${id}": maxMessages is only legal on a tier:'job' agent step`);
|
|
5922
|
+
if (!Number.isInteger(opts.maxMessages) || opts.maxMessages < 1 || opts.maxMessages > 5e3) throw new LuaWorkflowBuildError("max-turns-invalid", `"${id}": maxMessages must be an integer 1..5000`);
|
|
5923
|
+
}
|
|
5924
|
+
if (opts.maxInputTokens !== void 0) {
|
|
5925
|
+
if (tier !== "job") throw new LuaWorkflowBuildError("max-turns-requires-job-tier", `"${id}": maxInputTokens is only legal on a tier:'job' agent step`);
|
|
5926
|
+
if (!Number.isInteger(opts.maxInputTokens) || opts.maxInputTokens < 1e6 || opts.maxInputTokens > 5e8) throw new LuaWorkflowBuildError("max-turns-invalid", `"${id}": maxInputTokens must be an integer 1000000..500000000`);
|
|
5927
|
+
}
|
|
5394
5928
|
assertTimeout({
|
|
5395
5929
|
id,
|
|
5396
5930
|
timeoutSeconds: opts.timeoutSeconds,
|
|
@@ -5417,7 +5951,9 @@ var WorkflowBuilderImpl = class WorkflowBuilderImpl2 {
|
|
|
5417
5951
|
workspace: opts.workspace,
|
|
5418
5952
|
jobResources: opts.jobResources,
|
|
5419
5953
|
harness: opts.harness,
|
|
5420
|
-
maxTurns: opts.maxTurns
|
|
5954
|
+
maxTurns: opts.maxTurns,
|
|
5955
|
+
maxMessages: opts.maxMessages,
|
|
5956
|
+
maxInputTokens: opts.maxInputTokens
|
|
5421
5957
|
});
|
|
5422
5958
|
return this.push({
|
|
5423
5959
|
kind: "declare",
|
|
@@ -5572,7 +6108,11 @@ var WorkflowBuilderImpl = class WorkflowBuilderImpl2 {
|
|
|
5572
6108
|
}
|
|
5573
6109
|
assertNoClosure(input, `workflow("${id}").input`);
|
|
5574
6110
|
this.recordEnvRefs(input);
|
|
5575
|
-
this.nestedRefs.push({
|
|
6111
|
+
this.nestedRefs.push(opts?.workspace === "inherit" ? {
|
|
6112
|
+
id,
|
|
6113
|
+
name,
|
|
6114
|
+
workspace: "inherit"
|
|
6115
|
+
} : {
|
|
5576
6116
|
id,
|
|
5577
6117
|
name
|
|
5578
6118
|
});
|
|
@@ -5584,8 +6124,8 @@ var WorkflowBuilderImpl = class WorkflowBuilderImpl2 {
|
|
|
5584
6124
|
workspace: opts?.workspace
|
|
5585
6125
|
});
|
|
5586
6126
|
return this.push({
|
|
5587
|
-
kind: "
|
|
5588
|
-
|
|
6127
|
+
kind: "declare",
|
|
6128
|
+
node
|
|
5589
6129
|
});
|
|
5590
6130
|
}
|
|
5591
6131
|
commit() {
|
|
@@ -5595,7 +6135,7 @@ var WorkflowBuilderImpl = class WorkflowBuilderImpl2 {
|
|
|
5595
6135
|
const { graph, issues } = resolvePlacements(this.calls);
|
|
5596
6136
|
const fatal = issues[0];
|
|
5597
6137
|
if (fatal) {
|
|
5598
|
-
const hint = fatal.code === "unknown-step-ref" ? "a string StepRef must name an entry declared by agentStep/specialistStep/toolStep/map(\u2026, { id }) somewhere in the chain \u2014 before OR after the reference" : void 0;
|
|
6138
|
+
const hint = fatal.code === "unknown-step-ref" ? "a string StepRef must name an entry declared by agentStep/specialistStep/toolStep/map(\u2026, { id })/workflow(\u2026) somewhere in the chain \u2014 before OR after the reference" : void 0;
|
|
5599
6139
|
throw new LuaWorkflowBuildError(fatal.code, fatal.message, hint);
|
|
5600
6140
|
}
|
|
5601
6141
|
if (graph.length === 0) throw new LuaWorkflowBuildError("empty-graph", `workflow "${this.config.name}" has no entries`);
|
|
@@ -5608,7 +6148,8 @@ var WorkflowBuilderImpl = class WorkflowBuilderImpl2 {
|
|
|
5608
6148
|
if (graphHasHitl(graph, this.steps) && this.config.budget?.maxDurationSeconds === void 0) {
|
|
5609
6149
|
this.warnings.push({
|
|
5610
6150
|
code: "hitl-duration-defaulted",
|
|
5611
|
-
|
|
6151
|
+
// LUA-668: names the workflow — two HITL workflows in one project printed two identical lines that read as a duplicate.
|
|
6152
|
+
message: `workflow "${this.config.name}": budget.maxDurationSeconds defaulted to ${WORKFLOW_HITL_MAX_DURATION_SECONDS} s (30 d) because the graph contains an approval / waitForSignal / suspend-capable step \u2014 set it explicitly to silence`
|
|
5612
6153
|
});
|
|
5613
6154
|
}
|
|
5614
6155
|
this.checkScheduleInput();
|
|
@@ -5671,8 +6212,8 @@ function createWorkflow(cfg) {
|
|
|
5671
6212
|
if (v.roles.length > 20 || (v.users?.length ?? 0) > 50) throw new LuaWorkflowBuildError("cap-exceeded", "outputVisibility allows \u2264 20 roles and \u2264 50 users");
|
|
5672
6213
|
}
|
|
5673
6214
|
if (cfg.backfillOnEnable?.maxOccurrences !== void 0) {
|
|
5674
|
-
const
|
|
5675
|
-
if (!Number.isInteger(
|
|
6215
|
+
const n2 = cfg.backfillOnEnable.maxOccurrences;
|
|
6216
|
+
if (!Number.isInteger(n2) || n2 < 1 || n2 > 200) throw new LuaWorkflowBuildError("invalid-envelope", "backfillOnEnable.maxOccurrences must be an integer in 1..200 (backfill-max-occurrences-out-of-range; the org maxBatchItems twin is checked at publish/R56)");
|
|
5676
6217
|
}
|
|
5677
6218
|
const keys = /* @__PURE__ */ new Set();
|
|
5678
6219
|
envRefKeys(cfg.schedule, keys);
|