lua-cli 3.38.0 → 3.39.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 +100 -18
- package/dist/api-exports.js +1445 -285
- package/dist/api-exports.js.map +1 -1
- package/dist/index.js +2424 -558
- package/dist/index.js.map +1 -1
- package/dist/voice/test/index.d.ts +18 -18
- package/dist/workflow-builder.js +1379 -243
- package/dist/workflow-builder.js.map +1 -1
- package/docs/CLI_REFERENCE.md +16 -1
- package/package.json +6 -5
- package/template/package.json +1 -1
package/dist/workflow-builder.js
CHANGED
|
@@ -8,6 +8,7 @@ import { zodToJsonSchema } from "zod-to-json-schema";
|
|
|
8
8
|
import { z } from "zod";
|
|
9
9
|
import { z as z2 } from "zod";
|
|
10
10
|
import { z as z3 } from "zod";
|
|
11
|
+
import { z as z4 } from "zod";
|
|
11
12
|
var __defProp2 = Object.defineProperty;
|
|
12
13
|
var __name2 = /* @__PURE__ */ __name((target, value3) => __defProp2(target, "name", { value: value3, configurable: true }), "__name");
|
|
13
14
|
var PLUMBING_THREAD_CHANNELS = [
|
|
@@ -184,9 +185,9 @@ __name2(isMcpDraftCreateTool, "isMcpDraftCreateTool");
|
|
|
184
185
|
function mcpSendSiblingForDraftTool(tool, availableToolIds) {
|
|
185
186
|
const candidates = [
|
|
186
187
|
...availableToolIds
|
|
187
|
-
].filter((
|
|
188
|
-
id,
|
|
189
|
-
serverName:
|
|
188
|
+
].filter((id2) => id2.endsWith(REVIEWABLE_MCP_SEND_TOOL_SUFFIX)).map((id2) => ({
|
|
189
|
+
id: id2,
|
|
190
|
+
serverName: id2.slice(0, -REVIEWABLE_MCP_SEND_TOOL_SUFFIX.length)
|
|
190
191
|
})).filter(({ serverName }) => tool.startsWith(`${serverName}_`)).sort((a, b) => b.serverName.length - a.serverName.length);
|
|
191
192
|
return candidates[0]?.id;
|
|
192
193
|
}
|
|
@@ -367,8 +368,8 @@ __name(transformChatHistoryContentParts, "transformChatHistoryContentParts");
|
|
|
367
368
|
__name2(transformChatHistoryContentParts, "transformChatHistoryContentParts");
|
|
368
369
|
var RICH_PARTS_MESSAGE_ID_PREFIX = "rich-parts:";
|
|
369
370
|
var SCREENSHOT_MESSAGE_ID_PREFIX = "screenshot:";
|
|
370
|
-
function isSyntheticSideRow(
|
|
371
|
-
return
|
|
371
|
+
function isSyntheticSideRow(id2) {
|
|
372
|
+
return id2.startsWith(SCREENSHOT_MESSAGE_ID_PREFIX) || id2.startsWith(RICH_PARTS_MESSAGE_ID_PREFIX);
|
|
372
373
|
}
|
|
373
374
|
__name(isSyntheticSideRow, "isSyntheticSideRow");
|
|
374
375
|
__name2(isSyntheticSideRow, "isSyntheticSideRow");
|
|
@@ -664,6 +665,199 @@ var BROWSER_COMMANDS = [
|
|
|
664
665
|
}
|
|
665
666
|
];
|
|
666
667
|
var BROWSER_COMMAND_NAMES = BROWSER_COMMANDS.map((c) => c.name);
|
|
668
|
+
var LOG_FIELDS_MAX_KEYS = 32;
|
|
669
|
+
var LOG_FIELD_MAX_VALUE_BYTES = 1024;
|
|
670
|
+
var LOG_FIELDS_MAX_BYTES = 8192;
|
|
671
|
+
var LOG_FIELD_KEY_PATTERN = /^[a-z][a-z0-9_]{0,63}$/;
|
|
672
|
+
var LOG_FIELD_SECRET_SHAPED_KEY_PATTERNS = Object.freeze([
|
|
673
|
+
/^api_[0-9a-f]{24,}$/,
|
|
674
|
+
/^gh[pousr]_[a-z0-9]{36}$/,
|
|
675
|
+
/^(?:sk|rk|pk)_(?:live|test)_[a-z0-9]{16,}$/,
|
|
676
|
+
/^lua_hc_[a-z0-9]{20,}/,
|
|
677
|
+
/^lua_sk_[a-z0-9]{20,}/
|
|
678
|
+
]);
|
|
679
|
+
var LOG_FIELDS_CLAMPED_KEY = "lua_fields_clamped";
|
|
680
|
+
var LOG_FIELD_ARRAY_COUNT_SUFFIX = ".count";
|
|
681
|
+
var LuaLogFieldsError = class _LuaLogFieldsError extends Error {
|
|
682
|
+
static {
|
|
683
|
+
__name(this, "_LuaLogFieldsError");
|
|
684
|
+
}
|
|
685
|
+
static {
|
|
686
|
+
__name2(this, "LuaLogFieldsError");
|
|
687
|
+
}
|
|
688
|
+
constructor(message) {
|
|
689
|
+
super(message);
|
|
690
|
+
this.name = "LuaLogFieldsError";
|
|
691
|
+
Object.setPrototypeOf(this, _LuaLogFieldsError.prototype);
|
|
692
|
+
}
|
|
693
|
+
};
|
|
694
|
+
function utf8WidthAt(value3, index) {
|
|
695
|
+
const code = value3.charCodeAt(index);
|
|
696
|
+
if (code < 128) return {
|
|
697
|
+
bytes: 1,
|
|
698
|
+
units: 1
|
|
699
|
+
};
|
|
700
|
+
if (code < 2048) return {
|
|
701
|
+
bytes: 2,
|
|
702
|
+
units: 1
|
|
703
|
+
};
|
|
704
|
+
if (code >= 55296 && code <= 56319) {
|
|
705
|
+
const next = value3.charCodeAt(index + 1);
|
|
706
|
+
if (next >= 56320 && next <= 57343) return {
|
|
707
|
+
bytes: 4,
|
|
708
|
+
units: 2
|
|
709
|
+
};
|
|
710
|
+
}
|
|
711
|
+
return {
|
|
712
|
+
bytes: 3,
|
|
713
|
+
units: 1
|
|
714
|
+
};
|
|
715
|
+
}
|
|
716
|
+
__name(utf8WidthAt, "utf8WidthAt");
|
|
717
|
+
__name2(utf8WidthAt, "utf8WidthAt");
|
|
718
|
+
function utf8ByteLength(value3) {
|
|
719
|
+
let bytes = 0;
|
|
720
|
+
for (let i = 0; i < value3.length; ) {
|
|
721
|
+
const width = utf8WidthAt(value3, i);
|
|
722
|
+
bytes += width.bytes;
|
|
723
|
+
i += width.units;
|
|
724
|
+
}
|
|
725
|
+
return bytes;
|
|
726
|
+
}
|
|
727
|
+
__name(utf8ByteLength, "utf8ByteLength");
|
|
728
|
+
__name2(utf8ByteLength, "utf8ByteLength");
|
|
729
|
+
function clampUtf8(value3, maxBytes) {
|
|
730
|
+
let bytes = 0;
|
|
731
|
+
for (let i = 0; i < value3.length; ) {
|
|
732
|
+
const width = utf8WidthAt(value3, i);
|
|
733
|
+
if (bytes + width.bytes > maxBytes) return value3.slice(0, i);
|
|
734
|
+
bytes += width.bytes;
|
|
735
|
+
i += width.units;
|
|
736
|
+
}
|
|
737
|
+
return value3;
|
|
738
|
+
}
|
|
739
|
+
__name(clampUtf8, "clampUtf8");
|
|
740
|
+
__name2(clampUtf8, "clampUtf8");
|
|
741
|
+
function mapBytes(fields, withMark) {
|
|
742
|
+
return utf8ByteLength(JSON.stringify(withMark ? {
|
|
743
|
+
...fields,
|
|
744
|
+
[LOG_FIELDS_CLAMPED_KEY]: true
|
|
745
|
+
} : fields));
|
|
746
|
+
}
|
|
747
|
+
__name(mapBytes, "mapBytes");
|
|
748
|
+
__name2(mapBytes, "mapBytes");
|
|
749
|
+
function withValueCap(fields, capBytes) {
|
|
750
|
+
const out = {};
|
|
751
|
+
for (const [key, value3] of Object.entries(fields)) {
|
|
752
|
+
out[key] = typeof value3 === "string" ? clampUtf8(value3, capBytes) : value3;
|
|
753
|
+
}
|
|
754
|
+
return out;
|
|
755
|
+
}
|
|
756
|
+
__name(withValueCap, "withValueCap");
|
|
757
|
+
__name2(withValueCap, "withValueCap");
|
|
758
|
+
function describeValue(value3) {
|
|
759
|
+
if (value3 === null) return "null";
|
|
760
|
+
if (value3 === void 0) return "undefined";
|
|
761
|
+
if (Array.isArray(value3)) return "an array";
|
|
762
|
+
return typeof value3 === "object" ? "an object" : `a ${typeof value3}`;
|
|
763
|
+
}
|
|
764
|
+
__name(describeValue, "describeValue");
|
|
765
|
+
__name2(describeValue, "describeValue");
|
|
766
|
+
function assertValidLogFieldKey(key) {
|
|
767
|
+
if (!LOG_FIELD_KEY_PATTERN.test(key)) {
|
|
768
|
+
throw new LuaLogFieldsError(`log fields: key \`${key}\` is not allowed \u2014 a key must match ${LOG_FIELD_KEY_PATTERN.source} (lower-case, starts with a letter, then letters/digits/underscore, at most 64 characters)`);
|
|
769
|
+
}
|
|
770
|
+
if (LOG_FIELD_SECRET_SHAPED_KEY_PATTERNS.some((pattern) => pattern.test(key))) {
|
|
771
|
+
throw new LuaLogFieldsError(`log fields: key \`${key}\` is not allowed \u2014 it has the shape of a credential that the log-drain scrubber masks in values; a field KEY is never scrubbed, so it may never carry a secret shape`);
|
|
772
|
+
}
|
|
773
|
+
if (key === LOG_FIELDS_CLAMPED_KEY) {
|
|
774
|
+
throw new LuaLogFieldsError(`log fields: key \`${key}\` is reserved \u2014 the platform sets it to mark a field map it had to clamp`);
|
|
775
|
+
}
|
|
776
|
+
}
|
|
777
|
+
__name(assertValidLogFieldKey, "assertValidLogFieldKey");
|
|
778
|
+
__name2(assertValidLogFieldKey, "assertValidLogFieldKey");
|
|
779
|
+
function normalizeLogFields(fields) {
|
|
780
|
+
if (fields === void 0 || fields === null) return void 0;
|
|
781
|
+
if (typeof fields !== "object" || Array.isArray(fields)) {
|
|
782
|
+
throw new LuaLogFieldsError(`log fields: expected a plain object of fields, received ${describeValue(fields)}`);
|
|
783
|
+
}
|
|
784
|
+
const entries = Object.entries(fields);
|
|
785
|
+
if (entries.length > LOG_FIELDS_MAX_KEYS) {
|
|
786
|
+
throw new LuaLogFieldsError(`log fields: ${entries.length} keys exceeds the cap of ${LOG_FIELDS_MAX_KEYS} keys per call`);
|
|
787
|
+
}
|
|
788
|
+
const out = {};
|
|
789
|
+
for (const [key, value3] of entries) {
|
|
790
|
+
assertValidLogFieldKey(key);
|
|
791
|
+
if (typeof value3 === "string" || typeof value3 === "boolean") {
|
|
792
|
+
out[key] = value3;
|
|
793
|
+
continue;
|
|
794
|
+
}
|
|
795
|
+
if (typeof value3 === "number") {
|
|
796
|
+
if (!Number.isFinite(value3)) {
|
|
797
|
+
throw new LuaLogFieldsError(`log fields: \`${key}\` must be a finite number \u2014 NaN and Infinity have no JSON form`);
|
|
798
|
+
}
|
|
799
|
+
out[key] = value3;
|
|
800
|
+
continue;
|
|
801
|
+
}
|
|
802
|
+
if (Array.isArray(value3)) {
|
|
803
|
+
const parts = [];
|
|
804
|
+
for (const element of value3) {
|
|
805
|
+
if (typeof element !== "string") {
|
|
806
|
+
throw new LuaLogFieldsError(`log fields: \`${key}\` is an array, so every element must be a string (found ${describeValue(element)})`);
|
|
807
|
+
}
|
|
808
|
+
if (element.includes(",")) {
|
|
809
|
+
throw new LuaLogFieldsError(`log fields: \`${key}\` \u2014 an array element may not contain a comma; elements are comma-joined into one value (with \`${key}${LOG_FIELD_ARRAY_COUNT_SUFFIX}\` beside it), so a comma inside one would be indistinguishable from the separator`);
|
|
810
|
+
}
|
|
811
|
+
parts.push(element);
|
|
812
|
+
}
|
|
813
|
+
out[key] = parts.join(",");
|
|
814
|
+
out[`${key}${LOG_FIELD_ARRAY_COUNT_SUFFIX}`] = parts.length;
|
|
815
|
+
continue;
|
|
816
|
+
}
|
|
817
|
+
throw new LuaLogFieldsError(`log fields: \`${key}\` must be a string, number, boolean or string[] \u2014 received ${describeValue(value3)}` + (value3 !== null && typeof value3 === "object" ? " (nested objects are not supported)" : ""));
|
|
818
|
+
}
|
|
819
|
+
const keys = Object.keys(out);
|
|
820
|
+
if (keys.length === 0) return void 0;
|
|
821
|
+
if (keys.length > LOG_FIELDS_MAX_KEYS) {
|
|
822
|
+
throw new LuaLogFieldsError(`log fields: ${keys.length} keys exceeds the cap of ${LOG_FIELDS_MAX_KEYS} keys per call \u2014 an array field also contributes its \`${LOG_FIELD_ARRAY_COUNT_SUFFIX.slice(1)}\` sibling`);
|
|
823
|
+
}
|
|
824
|
+
if (clampLogFields(out)) out[LOG_FIELDS_CLAMPED_KEY] = true;
|
|
825
|
+
return out;
|
|
826
|
+
}
|
|
827
|
+
__name(normalizeLogFields, "normalizeLogFields");
|
|
828
|
+
__name2(normalizeLogFields, "normalizeLogFields");
|
|
829
|
+
function clampLogFields(out) {
|
|
830
|
+
let clamped = false;
|
|
831
|
+
for (const [key, value3] of Object.entries(out)) {
|
|
832
|
+
if (typeof value3 !== "string") continue;
|
|
833
|
+
const capped = clampUtf8(value3, LOG_FIELD_MAX_VALUE_BYTES);
|
|
834
|
+
if (capped !== value3) {
|
|
835
|
+
out[key] = capped;
|
|
836
|
+
clamped = true;
|
|
837
|
+
}
|
|
838
|
+
}
|
|
839
|
+
if (mapBytes(out, clamped) <= LOG_FIELDS_MAX_BYTES) return clamped;
|
|
840
|
+
const base = {
|
|
841
|
+
...out
|
|
842
|
+
};
|
|
843
|
+
let low = 0;
|
|
844
|
+
let high = LOG_FIELD_MAX_VALUE_BYTES;
|
|
845
|
+
let best = 0;
|
|
846
|
+
while (low <= high) {
|
|
847
|
+
const mid = Math.floor((low + high) / 2);
|
|
848
|
+
if (mapBytes(withValueCap(base, mid), true) <= LOG_FIELDS_MAX_BYTES) {
|
|
849
|
+
best = mid;
|
|
850
|
+
low = mid + 1;
|
|
851
|
+
} else {
|
|
852
|
+
high = mid - 1;
|
|
853
|
+
}
|
|
854
|
+
}
|
|
855
|
+
const fitted = withValueCap(base, best);
|
|
856
|
+
for (const key of Object.keys(out)) out[key] = fitted[key];
|
|
857
|
+
return true;
|
|
858
|
+
}
|
|
859
|
+
__name(clampLogFields, "clampLogFields");
|
|
860
|
+
__name2(clampLogFields, "clampLogFields");
|
|
667
861
|
var DESKTOP_FILE_COMMANDS = [
|
|
668
862
|
"files_roots",
|
|
669
863
|
"files_stat",
|
|
@@ -925,14 +1119,14 @@ function workflowContainerRunsHitlArm(container) {
|
|
|
925
1119
|
}
|
|
926
1120
|
__name(workflowContainerRunsHitlArm, "workflowContainerRunsHitlArm");
|
|
927
1121
|
__name2(workflowContainerRunsHitlArm, "workflowContainerRunsHitlArm");
|
|
928
|
-
function workflowHitlArmUnsupportedMessage(type,
|
|
1122
|
+
function workflowHitlArmUnsupportedMessage(type, id2, container) {
|
|
929
1123
|
const legal = WORKFLOW_HITL_ARM_CONTAINERS.map((c) => `\`${c}\``).join(" / ");
|
|
930
|
-
return `the engine does not run \`${type}\` inside a \`${container}\` yet (node "${
|
|
1124
|
+
return `the engine does not run \`${type}\` inside a \`${container}\` yet (node "${id2}") \u2014 place it at the top level, as a ${legal} arm, or inside a child \`workflow\``;
|
|
931
1125
|
}
|
|
932
1126
|
__name(workflowHitlArmUnsupportedMessage, "workflowHitlArmUnsupportedMessage");
|
|
933
1127
|
__name2(workflowHitlArmUnsupportedMessage, "workflowHitlArmUnsupportedMessage");
|
|
934
|
-
function workflowHitlArmShapeMessage(type,
|
|
935
|
-
return shape === "mapped-arm" ? `\`${type}\` arm "${
|
|
1128
|
+
function workflowHitlArmShapeMessage(type, id2, shape) {
|
|
1129
|
+
return shape === "mapped-arm" ? `\`${type}\` arm "${id2}" takes the previous output as its payload \u2014 it cannot head a [mapping, step] chain; map before the container instead` : `a chunked foreach hands each child a slice of items, not one \u2014 \`${type}\` body "${id2}" takes one item; drop \`chunk\``;
|
|
936
1130
|
}
|
|
937
1131
|
__name(workflowHitlArmShapeMessage, "workflowHitlArmShapeMessage");
|
|
938
1132
|
__name2(workflowHitlArmShapeMessage, "workflowHitlArmShapeMessage");
|
|
@@ -1227,6 +1421,112 @@ var AGENT_LOG_SOURCES = [
|
|
|
1227
1421
|
"workflow-script",
|
|
1228
1422
|
"workflow"
|
|
1229
1423
|
];
|
|
1424
|
+
var AGENT_LOG_FIELDS_MAX_WIRE_KEYS = LOG_FIELDS_MAX_KEYS + 1;
|
|
1425
|
+
function utf8Bytes(value3) {
|
|
1426
|
+
let bytes = 0;
|
|
1427
|
+
for (let i = 0; i < value3.length; ) {
|
|
1428
|
+
const code = value3.charCodeAt(i);
|
|
1429
|
+
if (code < 128) {
|
|
1430
|
+
bytes += 1;
|
|
1431
|
+
i += 1;
|
|
1432
|
+
} else if (code < 2048) {
|
|
1433
|
+
bytes += 2;
|
|
1434
|
+
i += 1;
|
|
1435
|
+
} else if (code >= 55296 && code <= 56319) {
|
|
1436
|
+
const next = value3.charCodeAt(i + 1);
|
|
1437
|
+
if (next >= 56320 && next <= 57343) {
|
|
1438
|
+
bytes += 4;
|
|
1439
|
+
i += 2;
|
|
1440
|
+
} else {
|
|
1441
|
+
bytes += 3;
|
|
1442
|
+
i += 1;
|
|
1443
|
+
}
|
|
1444
|
+
} else {
|
|
1445
|
+
bytes += 3;
|
|
1446
|
+
i += 1;
|
|
1447
|
+
}
|
|
1448
|
+
}
|
|
1449
|
+
return bytes;
|
|
1450
|
+
}
|
|
1451
|
+
__name(utf8Bytes, "utf8Bytes");
|
|
1452
|
+
__name2(utf8Bytes, "utf8Bytes");
|
|
1453
|
+
function isPlainFieldKey(key) {
|
|
1454
|
+
if (!LOG_FIELD_KEY_PATTERN.test(key)) return false;
|
|
1455
|
+
return !LOG_FIELD_SECRET_SHAPED_KEY_PATTERNS.some((pattern) => pattern.test(key));
|
|
1456
|
+
}
|
|
1457
|
+
__name(isPlainFieldKey, "isPlainFieldKey");
|
|
1458
|
+
__name2(isPlainFieldKey, "isPlainFieldKey");
|
|
1459
|
+
function describeAgentLogFieldsViolation(value3) {
|
|
1460
|
+
if (typeof value3 !== "object" || value3 === null || Array.isArray(value3)) {
|
|
1461
|
+
return "fields must be an object";
|
|
1462
|
+
}
|
|
1463
|
+
const entries = Object.entries(value3);
|
|
1464
|
+
let userKeys = 0;
|
|
1465
|
+
for (const [key, entry] of entries) {
|
|
1466
|
+
if (key === LOG_FIELDS_CLAMPED_KEY) {
|
|
1467
|
+
if (entry !== true) return `fields.${key} must be true`;
|
|
1468
|
+
continue;
|
|
1469
|
+
}
|
|
1470
|
+
userKeys += 1;
|
|
1471
|
+
if (key.endsWith(LOG_FIELD_ARRAY_COUNT_SUFFIX)) {
|
|
1472
|
+
const base = key.slice(0, -LOG_FIELD_ARRAY_COUNT_SUFFIX.length);
|
|
1473
|
+
if (!isPlainFieldKey(base)) return `fields key \`${key}\` is not a legal field key`;
|
|
1474
|
+
if (typeof entry !== "number" || !Number.isFinite(entry)) {
|
|
1475
|
+
return `fields.${key} must be a finite number`;
|
|
1476
|
+
}
|
|
1477
|
+
continue;
|
|
1478
|
+
}
|
|
1479
|
+
if (!isPlainFieldKey(key)) return `fields key \`${key}\` is not a legal field key`;
|
|
1480
|
+
if (typeof entry === "string") {
|
|
1481
|
+
if (utf8Bytes(entry) > LOG_FIELD_MAX_VALUE_BYTES) {
|
|
1482
|
+
return `fields.${key} exceeds ${LOG_FIELD_MAX_VALUE_BYTES} bytes`;
|
|
1483
|
+
}
|
|
1484
|
+
continue;
|
|
1485
|
+
}
|
|
1486
|
+
if (typeof entry === "boolean") continue;
|
|
1487
|
+
if (typeof entry === "number") {
|
|
1488
|
+
if (!Number.isFinite(entry)) return `fields.${key} must be a finite number`;
|
|
1489
|
+
continue;
|
|
1490
|
+
}
|
|
1491
|
+
return `fields.${key} must be a string, number or boolean`;
|
|
1492
|
+
}
|
|
1493
|
+
if (userKeys > LOG_FIELDS_MAX_KEYS) {
|
|
1494
|
+
return `fields has ${userKeys} keys, over the cap of ${LOG_FIELDS_MAX_KEYS}`;
|
|
1495
|
+
}
|
|
1496
|
+
if (utf8Bytes(JSON.stringify(value3)) > LOG_FIELDS_MAX_BYTES) {
|
|
1497
|
+
return `fields exceeds ${LOG_FIELDS_MAX_BYTES} bytes`;
|
|
1498
|
+
}
|
|
1499
|
+
return void 0;
|
|
1500
|
+
}
|
|
1501
|
+
__name(describeAgentLogFieldsViolation, "describeAgentLogFieldsViolation");
|
|
1502
|
+
__name2(describeAgentLogFieldsViolation, "describeAgentLogFieldsViolation");
|
|
1503
|
+
function isAgentLogFields(value3) {
|
|
1504
|
+
return describeAgentLogFieldsViolation(value3) === void 0;
|
|
1505
|
+
}
|
|
1506
|
+
__name(isAgentLogFields, "isAgentLogFields");
|
|
1507
|
+
__name2(isAgentLogFields, "isAgentLogFields");
|
|
1508
|
+
var LOG_DRAIN_TYPES_PHASE1 = [
|
|
1509
|
+
"http",
|
|
1510
|
+
"otlp",
|
|
1511
|
+
"datadog",
|
|
1512
|
+
"betterstack"
|
|
1513
|
+
];
|
|
1514
|
+
var LOG_DRAIN_TYPES_PHASE2 = [
|
|
1515
|
+
"splunk",
|
|
1516
|
+
"loki",
|
|
1517
|
+
"axiom",
|
|
1518
|
+
"newrelic",
|
|
1519
|
+
"sumologic"
|
|
1520
|
+
];
|
|
1521
|
+
var LOG_DRAIN_TYPES_IMPLEMENTED = [
|
|
1522
|
+
...LOG_DRAIN_TYPES_PHASE1,
|
|
1523
|
+
...LOG_DRAIN_TYPES_PHASE2,
|
|
1524
|
+
// RECONCILE-4 (W4-4). `s3` is implemented (H4 / PRO-1887) but is NOT in
|
|
1525
|
+
// `LOG_DRAIN_TYPES_PHASE2`, because its own flag opens it and `*` must not. It
|
|
1526
|
+
// belongs here all the same: this list is what a CLIENT may offer, and the server
|
|
1527
|
+
// remains the authority that answers 422 with the live list.
|
|
1528
|
+
"s3"
|
|
1529
|
+
];
|
|
1230
1530
|
var LOG_DRAIN_SOURCES = [
|
|
1231
1531
|
...AGENT_LOG_SOURCES,
|
|
1232
1532
|
"execution",
|
|
@@ -1235,7 +1535,10 @@ var LOG_DRAIN_SOURCES = [
|
|
|
1235
1535
|
"trigger-execution",
|
|
1236
1536
|
"job-execution",
|
|
1237
1537
|
"workflow-run",
|
|
1238
|
-
"workflow-audit"
|
|
1538
|
+
"workflow-audit",
|
|
1539
|
+
// PRO-1884 (H2). Appended AFTER 'workflow-audit' so the enum stays additive and
|
|
1540
|
+
// no existing member changes position.
|
|
1541
|
+
"voice-call"
|
|
1239
1542
|
];
|
|
1240
1543
|
var LOG_DRAIN_MAX_PER_ORG = 5;
|
|
1241
1544
|
var LOG_DRAIN_MAX_PER_ORG_ENTERPRISE = 10;
|
|
@@ -1244,8 +1547,26 @@ function maxDrainsForTier(tier) {
|
|
|
1244
1547
|
}
|
|
1245
1548
|
__name(maxDrainsForTier, "maxDrainsForTier");
|
|
1246
1549
|
__name2(maxDrainsForTier, "maxDrainsForTier");
|
|
1550
|
+
var LOG_DRAIN_DATADOG_SITES = [
|
|
1551
|
+
"datadoghq.com",
|
|
1552
|
+
"datadoghq.eu",
|
|
1553
|
+
"us3.datadoghq.com",
|
|
1554
|
+
"us5.datadoghq.com",
|
|
1555
|
+
"ap1.datadoghq.com",
|
|
1556
|
+
"ddog-gov.com"
|
|
1557
|
+
];
|
|
1558
|
+
var LOG_DRAIN_NEWRELIC_SITES = [
|
|
1559
|
+
"log-api.newrelic.com",
|
|
1560
|
+
"log-api.eu.newrelic.com",
|
|
1561
|
+
"log-api.jp.newrelic.com"
|
|
1562
|
+
];
|
|
1247
1563
|
var LOG_DRAIN_ENDPOINT_TEMPLATES = {
|
|
1248
|
-
datadog: "https://http-intake.logs.{site}/api/v2/logs"
|
|
1564
|
+
datadog: "https://http-intake.logs.{site}/api/v2/logs",
|
|
1565
|
+
newrelic: "https://{site}/log/v1"
|
|
1566
|
+
};
|
|
1567
|
+
var LOG_DRAIN_PRESET_SITES = {
|
|
1568
|
+
datadog: LOG_DRAIN_DATADOG_SITES,
|
|
1569
|
+
newrelic: LOG_DRAIN_NEWRELIC_SITES
|
|
1249
1570
|
};
|
|
1250
1571
|
function resolvePresetEndpoint(type, site) {
|
|
1251
1572
|
const template3 = LOG_DRAIN_ENDPOINT_TEMPLATES[type];
|
|
@@ -1254,6 +1575,233 @@ function resolvePresetEndpoint(type, site) {
|
|
|
1254
1575
|
}
|
|
1255
1576
|
__name(resolvePresetEndpoint, "resolvePresetEndpoint");
|
|
1256
1577
|
__name2(resolvePresetEndpoint, "resolvePresetEndpoint");
|
|
1578
|
+
var LOG_DRAIN_BUCKET_NAME_PATTERN = /^[a-z0-9][a-z0-9-]{1,61}[a-z0-9]$/;
|
|
1579
|
+
var LOG_DRAIN_BUCKET_HOST_PATTERNS = Object.freeze({
|
|
1580
|
+
aws: [
|
|
1581
|
+
// virtual-host style, regional and legacy global
|
|
1582
|
+
/^[a-z0-9][a-z0-9-]{1,61}[a-z0-9]\.s3(\.dualstack)?(\.[a-z0-9-]+)?\.amazonaws\.com$/,
|
|
1583
|
+
// path style
|
|
1584
|
+
/^s3(\.dualstack)?(\.[a-z0-9-]+)?\.amazonaws\.com$/
|
|
1585
|
+
],
|
|
1586
|
+
r2: [
|
|
1587
|
+
/^[a-f0-9]{32}\.r2\.cloudflarestorage\.com$/
|
|
1588
|
+
],
|
|
1589
|
+
gcs: [
|
|
1590
|
+
/^storage\.googleapis\.com$/
|
|
1591
|
+
]
|
|
1592
|
+
});
|
|
1593
|
+
function isLogDrainBucketHostAllowed(provider, host) {
|
|
1594
|
+
const normalized = host.trim().toLowerCase().replace(/^\[|\]$/g, "");
|
|
1595
|
+
if (!normalized) return false;
|
|
1596
|
+
return (LOG_DRAIN_BUCKET_HOST_PATTERNS[provider] ?? []).some((pattern) => pattern.test(normalized));
|
|
1597
|
+
}
|
|
1598
|
+
__name(isLogDrainBucketHostAllowed, "isLogDrainBucketHostAllowed");
|
|
1599
|
+
__name2(isLogDrainBucketHostAllowed, "isLogDrainBucketHostAllowed");
|
|
1600
|
+
function resolveDrainBucketEndpoint(bucket) {
|
|
1601
|
+
if (!LOG_DRAIN_BUCKET_NAME_PATTERN.test(bucket.bucket)) {
|
|
1602
|
+
throw new Error("log drain bucket name is not a valid S3 bucket label");
|
|
1603
|
+
}
|
|
1604
|
+
if (bucket.provider === "aws") {
|
|
1605
|
+
const region = bucket.region.trim().toLowerCase();
|
|
1606
|
+
if (!/^[a-z0-9-]{1,32}$/.test(region)) throw new Error("log drain bucket region is not an AWS region");
|
|
1607
|
+
return `https://${bucket.bucket}.s3.${region}.amazonaws.com`;
|
|
1608
|
+
}
|
|
1609
|
+
if (!bucket.endpoint) throw new Error(`log drain '${bucket.provider}' bucket requires an endpoint`);
|
|
1610
|
+
let url;
|
|
1611
|
+
try {
|
|
1612
|
+
url = new URL(bucket.endpoint);
|
|
1613
|
+
} catch {
|
|
1614
|
+
throw new Error(`log drain '${bucket.provider}' bucket endpoint is not an absolute URL`);
|
|
1615
|
+
}
|
|
1616
|
+
if (url.protocol !== "https:") throw new Error(`log drain '${bucket.provider}' bucket endpoint must be https`);
|
|
1617
|
+
return `https://${url.host}/${bucket.bucket}`;
|
|
1618
|
+
}
|
|
1619
|
+
__name(resolveDrainBucketEndpoint, "resolveDrainBucketEndpoint");
|
|
1620
|
+
__name2(resolveDrainBucketEndpoint, "resolveDrainBucketEndpoint");
|
|
1621
|
+
function drainBucketUsesPathStyle(provider) {
|
|
1622
|
+
return provider !== "aws";
|
|
1623
|
+
}
|
|
1624
|
+
__name(drainBucketUsesPathStyle, "drainBucketUsesPathStyle");
|
|
1625
|
+
__name2(drainBucketUsesPathStyle, "drainBucketUsesPathStyle");
|
|
1626
|
+
function presetIntakeHosts(type) {
|
|
1627
|
+
const template3 = LOG_DRAIN_ENDPOINT_TEMPLATES[type];
|
|
1628
|
+
const sites = LOG_DRAIN_PRESET_SITES[type];
|
|
1629
|
+
if (!template3 || !sites) return [];
|
|
1630
|
+
const hosts = [];
|
|
1631
|
+
for (const site of sites) {
|
|
1632
|
+
try {
|
|
1633
|
+
hosts.push(new URL(template3.replace("{site}", site)).hostname.toLowerCase());
|
|
1634
|
+
} catch {
|
|
1635
|
+
}
|
|
1636
|
+
}
|
|
1637
|
+
return hosts;
|
|
1638
|
+
}
|
|
1639
|
+
__name(presetIntakeHosts, "presetIntakeHosts");
|
|
1640
|
+
__name2(presetIntakeHosts, "presetIntakeHosts");
|
|
1641
|
+
var LOG_DRAIN_PRESET_HOST_SUFFIXES = {
|
|
1642
|
+
axiom: [
|
|
1643
|
+
".axiom.co"
|
|
1644
|
+
],
|
|
1645
|
+
sumologic: [
|
|
1646
|
+
".sumologic.com"
|
|
1647
|
+
]
|
|
1648
|
+
};
|
|
1649
|
+
function presetHostAllowlist(type) {
|
|
1650
|
+
return [
|
|
1651
|
+
...presetIntakeHosts(type),
|
|
1652
|
+
...LOG_DRAIN_PRESET_HOST_SUFFIXES[type] ?? []
|
|
1653
|
+
];
|
|
1654
|
+
}
|
|
1655
|
+
__name(presetHostAllowlist, "presetHostAllowlist");
|
|
1656
|
+
__name2(presetHostAllowlist, "presetHostAllowlist");
|
|
1657
|
+
function drainHostAllowlistAllows(allowlist, host) {
|
|
1658
|
+
const needle = host.toLowerCase();
|
|
1659
|
+
return allowlist.some((raw) => {
|
|
1660
|
+
const entry = raw.toLowerCase();
|
|
1661
|
+
if (entry.startsWith(".")) return needle === entry.slice(1) || needle.endsWith(entry);
|
|
1662
|
+
return entry === needle;
|
|
1663
|
+
});
|
|
1664
|
+
}
|
|
1665
|
+
__name(drainHostAllowlistAllows, "drainHostAllowlistAllows");
|
|
1666
|
+
__name2(drainHostAllowlistAllows, "drainHostAllowlistAllows");
|
|
1667
|
+
function drainDestinationIsVendorPinned(type) {
|
|
1668
|
+
if (LOG_DRAIN_ENDPOINT_TEMPLATES[type]) return true;
|
|
1669
|
+
return presetHostAllowlist(type).length > 0;
|
|
1670
|
+
}
|
|
1671
|
+
__name(drainDestinationIsVendorPinned, "drainDestinationIsVendorPinned");
|
|
1672
|
+
__name2(drainDestinationIsVendorPinned, "drainDestinationIsVendorPinned");
|
|
1673
|
+
function drainVerificationOwnership(input) {
|
|
1674
|
+
if (input.proved === true) return "verified";
|
|
1675
|
+
if (input.mode === "test-post" && drainDestinationIsVendorPinned(input.type)) return "verified";
|
|
1676
|
+
return "reachability-only";
|
|
1677
|
+
}
|
|
1678
|
+
__name(drainVerificationOwnership, "drainVerificationOwnership");
|
|
1679
|
+
__name2(drainVerificationOwnership, "drainVerificationOwnership");
|
|
1680
|
+
function drainOwnershipOrDefault(ownership) {
|
|
1681
|
+
return ownership === "verified" ? "verified" : "reachability-only";
|
|
1682
|
+
}
|
|
1683
|
+
__name(drainOwnershipOrDefault, "drainOwnershipOrDefault");
|
|
1684
|
+
__name2(drainOwnershipOrDefault, "drainOwnershipOrDefault");
|
|
1685
|
+
var DRAIN_CONTENT_ACK_ERROR_CODE = "DRAIN_CONTENT_ACK_REQUIRED";
|
|
1686
|
+
var DRAIN_CONTENT_ACK_FIELD = "includeContentAck";
|
|
1687
|
+
var DrainContentAckRequiredError = class extends Error {
|
|
1688
|
+
static {
|
|
1689
|
+
__name(this, "DrainContentAckRequiredError");
|
|
1690
|
+
}
|
|
1691
|
+
static {
|
|
1692
|
+
__name2(this, "DrainContentAckRequiredError");
|
|
1693
|
+
}
|
|
1694
|
+
code = DRAIN_CONTENT_ACK_ERROR_CODE;
|
|
1695
|
+
field = DRAIN_CONTENT_ACK_FIELD;
|
|
1696
|
+
constructor() {
|
|
1697
|
+
super("includeContent ships end-user message content to a third party; set includeContentAck: true to confirm.");
|
|
1698
|
+
this.name = "DrainContentAckRequiredError";
|
|
1699
|
+
}
|
|
1700
|
+
};
|
|
1701
|
+
function assertDrainContentAck(input) {
|
|
1702
|
+
const turningOn = input.next === true && input.was !== true;
|
|
1703
|
+
if (!turningOn) return void 0;
|
|
1704
|
+
if (input.ack !== true) throw new DrainContentAckRequiredError();
|
|
1705
|
+
return {
|
|
1706
|
+
by: input.actor,
|
|
1707
|
+
source: input.source,
|
|
1708
|
+
at: input.at,
|
|
1709
|
+
...input.inheritedFrom ? {
|
|
1710
|
+
inheritedFrom: input.inheritedFrom
|
|
1711
|
+
} : {}
|
|
1712
|
+
};
|
|
1713
|
+
}
|
|
1714
|
+
__name(assertDrainContentAck, "assertDrainContentAck");
|
|
1715
|
+
__name2(assertDrainContentAck, "assertDrainContentAck");
|
|
1716
|
+
var LOG_DRAIN_PRESET_PATHS = {
|
|
1717
|
+
// https://docs.splunk.com/Documentation/Splunk/latest/Data/HECExamples
|
|
1718
|
+
splunk: {
|
|
1719
|
+
path: "/services/collector/event"
|
|
1720
|
+
},
|
|
1721
|
+
// https://grafana.com/docs/loki/latest/reference/loki-http-api/#ingest-logs
|
|
1722
|
+
loki: {
|
|
1723
|
+
path: "/loki/api/v1/push"
|
|
1724
|
+
},
|
|
1725
|
+
// https://axiom.co/docs/restapi/endpoints/ingestIntoDataset
|
|
1726
|
+
axiom: {
|
|
1727
|
+
path: "/v1/datasets",
|
|
1728
|
+
segment: "dataset",
|
|
1729
|
+
suffix: "/ingest"
|
|
1730
|
+
},
|
|
1731
|
+
// https://help.sumologic.com/docs/send-data/hosted-collectors/http-source/logs-metrics/upload-logs/
|
|
1732
|
+
sumologic: {
|
|
1733
|
+
path: "/receiver/v1/http",
|
|
1734
|
+
segment: "token"
|
|
1735
|
+
}
|
|
1736
|
+
};
|
|
1737
|
+
var PRESET_SEGMENT_RE = /^[A-Za-z0-9._~%=+-]{1,512}$/;
|
|
1738
|
+
function composePresetEndpoint(type, endpoint) {
|
|
1739
|
+
const rule = LOG_DRAIN_PRESET_PATHS[type];
|
|
1740
|
+
if (!rule) return void 0;
|
|
1741
|
+
let url;
|
|
1742
|
+
try {
|
|
1743
|
+
url = new URL(endpoint);
|
|
1744
|
+
} catch {
|
|
1745
|
+
return {
|
|
1746
|
+
ok: false,
|
|
1747
|
+
reason: "invalid_url"
|
|
1748
|
+
};
|
|
1749
|
+
}
|
|
1750
|
+
if (url.protocol !== "https:" || !url.hostname) return {
|
|
1751
|
+
ok: false,
|
|
1752
|
+
reason: "invalid_url"
|
|
1753
|
+
};
|
|
1754
|
+
const origin = url.origin;
|
|
1755
|
+
const path = url.pathname.replace(/\/+$/, "");
|
|
1756
|
+
if (!rule.segment) {
|
|
1757
|
+
const base2 = path.endsWith(rule.path) ? path.slice(0, path.length - rule.path.length) : path;
|
|
1758
|
+
return {
|
|
1759
|
+
ok: true,
|
|
1760
|
+
endpoint: `${origin}${base2}${rule.path}`
|
|
1761
|
+
};
|
|
1762
|
+
}
|
|
1763
|
+
const marker = `${rule.path}/`;
|
|
1764
|
+
const at = path.indexOf(marker);
|
|
1765
|
+
if (at < 0) {
|
|
1766
|
+
return {
|
|
1767
|
+
ok: false,
|
|
1768
|
+
reason: rule.segment === "dataset" ? "missing_dataset" : "missing_token"
|
|
1769
|
+
};
|
|
1770
|
+
}
|
|
1771
|
+
const base = path.slice(0, at);
|
|
1772
|
+
const afterMarker = path.slice(at + marker.length);
|
|
1773
|
+
const rest = rule.suffix && afterMarker.endsWith(rule.suffix) ? afterMarker.slice(0, afterMarker.length - rule.suffix.length) : afterMarker;
|
|
1774
|
+
if (!rest || rest.includes("/")) {
|
|
1775
|
+
return {
|
|
1776
|
+
ok: false,
|
|
1777
|
+
reason: rule.segment === "dataset" ? "missing_dataset" : "missing_token"
|
|
1778
|
+
};
|
|
1779
|
+
}
|
|
1780
|
+
if (!PRESET_SEGMENT_RE.test(rest)) return {
|
|
1781
|
+
ok: false,
|
|
1782
|
+
reason: "bad_segment"
|
|
1783
|
+
};
|
|
1784
|
+
if (rule.segment === "dataset") {
|
|
1785
|
+
return {
|
|
1786
|
+
ok: true,
|
|
1787
|
+
endpoint: `${origin}${base}${rule.path}/${rest}${rule.suffix ?? ""}`,
|
|
1788
|
+
dataset: rest
|
|
1789
|
+
};
|
|
1790
|
+
}
|
|
1791
|
+
return {
|
|
1792
|
+
ok: true,
|
|
1793
|
+
endpoint: `${origin}${base}${rule.path}/`,
|
|
1794
|
+
token: rest
|
|
1795
|
+
};
|
|
1796
|
+
}
|
|
1797
|
+
__name(composePresetEndpoint, "composePresetEndpoint");
|
|
1798
|
+
__name2(composePresetEndpoint, "composePresetEndpoint");
|
|
1799
|
+
function joinPresetEndpointToken(endpoint, token) {
|
|
1800
|
+
if (typeof token !== "string" || !PRESET_SEGMENT_RE.test(token)) return endpoint;
|
|
1801
|
+
return endpoint.endsWith("/") ? `${endpoint}${token}` : `${endpoint}/${token}`;
|
|
1802
|
+
}
|
|
1803
|
+
__name(joinPresetEndpointToken, "joinPresetEndpointToken");
|
|
1804
|
+
__name2(joinPresetEndpointToken, "joinPresetEndpointToken");
|
|
1257
1805
|
var LOG_DRAIN_QUOTAS = {
|
|
1258
1806
|
team: {
|
|
1259
1807
|
eventsPerDay: 1e6,
|
|
@@ -1332,6 +1880,358 @@ function logDrainQuotaDroppedSeverities(degradation) {
|
|
|
1332
1880
|
}
|
|
1333
1881
|
__name(logDrainQuotaDroppedSeverities, "logDrainQuotaDroppedSeverities");
|
|
1334
1882
|
__name2(logDrainQuotaDroppedSeverities, "logDrainQuotaDroppedSeverities");
|
|
1883
|
+
var LOG_EXPORT_SOURCES = [
|
|
1884
|
+
...AGENT_LOG_SOURCES,
|
|
1885
|
+
"execution"
|
|
1886
|
+
];
|
|
1887
|
+
var LOG_EXPORT_MAX_WINDOW_DAYS = 31;
|
|
1888
|
+
var LOG_EXPORT_MAX_WINDOW_MS = LOG_EXPORT_MAX_WINDOW_DAYS * 24 * 60 * 60 * 1e3;
|
|
1889
|
+
var LOG_EXPORT_URL_TTL_SECONDS = 24 * 60 * 60;
|
|
1890
|
+
var LOG_EXPORT_FILE_RETENTION_DAYS = 7;
|
|
1891
|
+
var LOG_EXPORT_FILE_RETENTION_MS = LOG_EXPORT_FILE_RETENTION_DAYS * 24 * 60 * 60 * 1e3;
|
|
1892
|
+
var LOG_EXPORT_PART_MAX_BYTES = 256 * 1024 * 1024;
|
|
1893
|
+
function isLogExportSource(source) {
|
|
1894
|
+
return LOG_EXPORT_SOURCES.includes(source);
|
|
1895
|
+
}
|
|
1896
|
+
__name(isLogExportSource, "isLogExportSource");
|
|
1897
|
+
__name2(isLogExportSource, "isLogExportSource");
|
|
1898
|
+
var LOG_DRAIN_NOTICE_RATE_LIMIT_MS = 60 * 6e4;
|
|
1899
|
+
var LOG_DRAIN_VERIFICATION_STALE_MS = 24 * 60 * 6e4;
|
|
1900
|
+
var LOG_DRAIN_DIGEST_INTERVAL_MS = 24 * 60 * 6e4;
|
|
1901
|
+
var LOG_DRAIN_DIGEST_MAX_ENTRIES = 50;
|
|
1902
|
+
var LOG_DRAIN_NOTICE_ERROR_MAX_CHARS = 200;
|
|
1903
|
+
function clamp(value3, max) {
|
|
1904
|
+
if (typeof value3 !== "string") return void 0;
|
|
1905
|
+
const trimmed = value3.trim();
|
|
1906
|
+
if (!trimmed) return void 0;
|
|
1907
|
+
return trimmed.length <= max ? trimmed : `${trimmed.slice(0, max - 1)}\u2026`;
|
|
1908
|
+
}
|
|
1909
|
+
__name(clamp, "clamp");
|
|
1910
|
+
__name2(clamp, "clamp");
|
|
1911
|
+
function numberOr(value3, fallback) {
|
|
1912
|
+
return typeof value3 === "number" && Number.isFinite(value3) ? value3 : fallback;
|
|
1913
|
+
}
|
|
1914
|
+
__name(numberOr, "numberOr");
|
|
1915
|
+
__name2(numberOr, "numberOr");
|
|
1916
|
+
function isoOr(value3) {
|
|
1917
|
+
return typeof value3 === "string" && value3.length > 0 ? value3 : void 0;
|
|
1918
|
+
}
|
|
1919
|
+
__name(isoOr, "isoOr");
|
|
1920
|
+
__name2(isoOr, "isoOr");
|
|
1921
|
+
function logDrainNoticeView(drain, now) {
|
|
1922
|
+
const health = drain.health ?? {};
|
|
1923
|
+
const quota = drain.quota;
|
|
1924
|
+
const view = {
|
|
1925
|
+
id: String(drain.id ?? ""),
|
|
1926
|
+
name: String(drain.name ?? ""),
|
|
1927
|
+
type: drain.type,
|
|
1928
|
+
state: drain.state,
|
|
1929
|
+
deliveredCount24h: numberOr(health.deliveredCount24h, 0),
|
|
1930
|
+
droppedCount24h: numberOr(health.droppedCount24h, 0),
|
|
1931
|
+
rejectedCount24h: numberOr(health.rejectedCount24h, 0),
|
|
1932
|
+
backlog: numberOr(health.backlog, 0),
|
|
1933
|
+
quotaRatio: quota ? logDrainQuotaRatio(quota, now) : 0
|
|
1934
|
+
};
|
|
1935
|
+
if (health.pauseReason) view.pauseReason = health.pauseReason;
|
|
1936
|
+
const lastError = clamp(health.lastError, LOG_DRAIN_NOTICE_ERROR_MAX_CHARS);
|
|
1937
|
+
if (lastError) view.lastError = lastError;
|
|
1938
|
+
if (typeof health.lastStatusCode === "number") view.lastStatusCode = health.lastStatusCode;
|
|
1939
|
+
const lastSuccessAt = isoOr(health.lastSuccessAt);
|
|
1940
|
+
if (lastSuccessAt) view.lastSuccessAt = lastSuccessAt;
|
|
1941
|
+
const lastFailureAt = isoOr(health.lastFailureAt);
|
|
1942
|
+
if (lastFailureAt) view.lastFailureAt = lastFailureAt;
|
|
1943
|
+
const resetsAt = isoOr(quota?.resetsAt);
|
|
1944
|
+
if (resetsAt) view.quotaResetsAt = resetsAt;
|
|
1945
|
+
return view;
|
|
1946
|
+
}
|
|
1947
|
+
__name(logDrainNoticeView, "logDrainNoticeView");
|
|
1948
|
+
__name2(logDrainNoticeView, "logDrainNoticeView");
|
|
1949
|
+
function logDrainHealthCardPath(orgId, drainId) {
|
|
1950
|
+
return `/orgs/${encodeURIComponent(orgId)}/log-drains/${encodeURIComponent(drainId)}`;
|
|
1951
|
+
}
|
|
1952
|
+
__name(logDrainHealthCardPath, "logDrainHealthCardPath");
|
|
1953
|
+
__name2(logDrainHealthCardPath, "logDrainHealthCardPath");
|
|
1954
|
+
function percent(ratio) {
|
|
1955
|
+
if (!Number.isFinite(ratio) || ratio <= 0) return "0%";
|
|
1956
|
+
return `${Math.round(ratio * 100)}%`;
|
|
1957
|
+
}
|
|
1958
|
+
__name(percent, "percent");
|
|
1959
|
+
__name2(percent, "percent");
|
|
1960
|
+
function becauseClause(view) {
|
|
1961
|
+
const bits = [];
|
|
1962
|
+
if (view.lastStatusCode) bits.push(`HTTP ${view.lastStatusCode}`);
|
|
1963
|
+
if (view.lastError) bits.push(view.lastError);
|
|
1964
|
+
return bits.length ? ` Last error: ${bits.join(" \u2014 ")}.` : "";
|
|
1965
|
+
}
|
|
1966
|
+
__name(becauseClause, "becauseClause");
|
|
1967
|
+
__name2(becauseClause, "becauseClause");
|
|
1968
|
+
function logDrainNoticeCopy(payload) {
|
|
1969
|
+
const view = payload.drain;
|
|
1970
|
+
const name = view.name || view.id;
|
|
1971
|
+
const backlog = view.backlog > 0 ? ` ${view.backlog.toLocaleString("en-US")} records are buffered.` : "";
|
|
1972
|
+
switch (payload.kind) {
|
|
1973
|
+
case "failing":
|
|
1974
|
+
return {
|
|
1975
|
+
title: name,
|
|
1976
|
+
subject: `Log drain "${name}" is failing`,
|
|
1977
|
+
previewLine: "Failing \u2014 15 minutes without a successful delivery",
|
|
1978
|
+
summary: `The log drain "${name}" (${view.type}) has gone 15 minutes without a successful delivery and is now failing.${becauseClause(view)}${backlog} Records keep buffering; the drain pauses itself after 24 hours without a success.`,
|
|
1979
|
+
status: "failed",
|
|
1980
|
+
priority: "high"
|
|
1981
|
+
};
|
|
1982
|
+
case "paused_auto":
|
|
1983
|
+
return {
|
|
1984
|
+
title: name,
|
|
1985
|
+
subject: `Log drain "${name}" was paused`,
|
|
1986
|
+
previewLine: "Paused \u2014 24 hours without a successful delivery",
|
|
1987
|
+
summary: `The log drain "${name}" (${view.type}) was paused automatically after 24 hours without a successful delivery.${becauseClause(view)}${backlog} Nothing is being sent while it is paused, and the buffer is delivered on resume. Fix the destination, then resume it from the drain's health card or with \`lua drains resume ${view.id}\`.`,
|
|
1988
|
+
status: "failed",
|
|
1989
|
+
priority: "high"
|
|
1990
|
+
};
|
|
1991
|
+
case "paused_quota":
|
|
1992
|
+
return {
|
|
1993
|
+
title: name,
|
|
1994
|
+
subject: `Log drain "${name}" was paused \u2014 daily quota exhausted`,
|
|
1995
|
+
previewLine: `Paused \u2014 ${percent(view.quotaRatio)} of the daily allowance used`,
|
|
1996
|
+
summary: `The log drain "${name}" (${view.type}) reached ${percent(view.quotaRatio)} of its daily allowance and was paused.${backlog} Records keep buffering. The allowance resets${view.quotaResetsAt ? ` at ${view.quotaResetsAt}` : " at 00:00 UTC"}; narrow the drain's sources or raise the plan's limit to stop it happening again, then resume it with \`lua drains resume ${view.id}\`.`,
|
|
1997
|
+
status: "failed",
|
|
1998
|
+
priority: "high"
|
|
1999
|
+
};
|
|
2000
|
+
case "quota_warning":
|
|
2001
|
+
return {
|
|
2002
|
+
title: name,
|
|
2003
|
+
subject: `Log drain "${name}" has used 80% of its daily allowance`,
|
|
2004
|
+
previewLine: `${percent(view.quotaRatio)} of the daily allowance used`,
|
|
2005
|
+
summary: `The log drain "${name}" (${view.type}) has used ${percent(view.quotaRatio)} of today's allowance. Past 100% debug records are dropped, past 125% info records as well, and at 150% the drain pauses. The allowance resets${view.quotaResetsAt ? ` at ${view.quotaResetsAt}` : " at 00:00 UTC"}.`,
|
|
2006
|
+
status: "failed",
|
|
2007
|
+
priority: "normal"
|
|
2008
|
+
};
|
|
2009
|
+
case "dropped": {
|
|
2010
|
+
const dropped = payload.droppedCount ?? view.droppedCount24h;
|
|
2011
|
+
return {
|
|
2012
|
+
title: name,
|
|
2013
|
+
subject: `Log drain "${name}" is dropping records`,
|
|
2014
|
+
previewLine: `${dropped.toLocaleString("en-US")} records dropped`,
|
|
2015
|
+
summary: `The log drain "${name}" (${view.type}) dropped ${dropped.toLocaleString("en-US")} records because its buffer filled up faster than the destination accepted them.${becauseClause(view)} The gap is reported in band on the next successful batch, so the range is recoverable from the destination itself.`,
|
|
2016
|
+
status: "failed",
|
|
2017
|
+
priority: "high"
|
|
2018
|
+
};
|
|
2019
|
+
}
|
|
2020
|
+
case "verification_pending":
|
|
2021
|
+
return {
|
|
2022
|
+
title: name,
|
|
2023
|
+
subject: `Log drain "${name}" is still unverified`,
|
|
2024
|
+
previewLine: "Unverified after 24 hours \u2014 nothing is being delivered",
|
|
2025
|
+
summary: `The log drain "${name}" (${view.type}) was created more than 24 hours ago and has never completed verification, so nothing is being delivered to it.${becauseClause(view)} Run \`lua drains verify ${view.id}\` once the destination echoes the verification token.`,
|
|
2026
|
+
status: "failed",
|
|
2027
|
+
priority: "normal"
|
|
2028
|
+
};
|
|
2029
|
+
default: {
|
|
2030
|
+
const exhaustive = payload.kind;
|
|
2031
|
+
throw new Error(`unhandled log-drain notice kind: ${String(exhaustive)}`);
|
|
2032
|
+
}
|
|
2033
|
+
}
|
|
2034
|
+
}
|
|
2035
|
+
__name(logDrainNoticeCopy, "logDrainNoticeCopy");
|
|
2036
|
+
__name2(logDrainNoticeCopy, "logDrainNoticeCopy");
|
|
2037
|
+
function logDrainNoticeLabel(kind) {
|
|
2038
|
+
switch (kind) {
|
|
2039
|
+
case "failing":
|
|
2040
|
+
return "failing";
|
|
2041
|
+
case "paused_auto":
|
|
2042
|
+
return "paused (no success for 24 h)";
|
|
2043
|
+
case "paused_quota":
|
|
2044
|
+
return "paused (daily allowance exhausted)";
|
|
2045
|
+
case "quota_warning":
|
|
2046
|
+
return "80% of the daily allowance used";
|
|
2047
|
+
case "dropped":
|
|
2048
|
+
return "dropping records";
|
|
2049
|
+
case "verification_pending":
|
|
2050
|
+
return "still unverified";
|
|
2051
|
+
default: {
|
|
2052
|
+
const exhaustive = kind;
|
|
2053
|
+
throw new Error(`unhandled log-drain notice kind: ${String(exhaustive)}`);
|
|
2054
|
+
}
|
|
2055
|
+
}
|
|
2056
|
+
}
|
|
2057
|
+
__name(logDrainNoticeLabel, "logDrainNoticeLabel");
|
|
2058
|
+
__name2(logDrainNoticeLabel, "logDrainNoticeLabel");
|
|
2059
|
+
function logDrainNoticeDigestCopy(payload) {
|
|
2060
|
+
const entries = [
|
|
2061
|
+
...payload.entries ?? []
|
|
2062
|
+
].sort((a, b) => a.at < b.at ? -1 : a.at > b.at ? 1 : 0).slice(0, LOG_DRAIN_DIGEST_MAX_ENTRIES);
|
|
2063
|
+
const drains = new Set(entries.map((entry) => entry.drainId));
|
|
2064
|
+
const noun = `${entries.length} notice${entries.length === 1 ? "" : "s"}`;
|
|
2065
|
+
const across = `${drains.size} drain${drains.size === 1 ? "" : "s"}`;
|
|
2066
|
+
const lines = entries.map((entry) => `${entry.drainName || entry.drainId} \u2014 ${logDrainNoticeLabel(entry.kind)}`);
|
|
2067
|
+
return {
|
|
2068
|
+
title: "Log drains \u2014 daily summary",
|
|
2069
|
+
subject: `Log drains \u2014 ${noun} in the last day`,
|
|
2070
|
+
previewLine: `${noun} across ${across}`,
|
|
2071
|
+
summary: `${noun} across ${across} in the last day: ${lines.join("; ")}.`,
|
|
2072
|
+
status: "failed",
|
|
2073
|
+
priority: "normal"
|
|
2074
|
+
};
|
|
2075
|
+
}
|
|
2076
|
+
__name(logDrainNoticeDigestCopy, "logDrainNoticeDigestCopy");
|
|
2077
|
+
__name2(logDrainNoticeDigestCopy, "logDrainNoticeDigestCopy");
|
|
2078
|
+
var LOG_DRAIN_USAGE_LINE_ITEM = "log_drain_events";
|
|
2079
|
+
var LOG_DRAIN_BYTES_PER_GIB = 1024 ** 3;
|
|
2080
|
+
var DEFAULT_LOG_DRAIN_PLAN_CONFIG = {
|
|
2081
|
+
version: 1,
|
|
2082
|
+
tiers: {
|
|
2083
|
+
team: {
|
|
2084
|
+
...LOG_DRAIN_QUOTAS.team
|
|
2085
|
+
},
|
|
2086
|
+
business: {
|
|
2087
|
+
...LOG_DRAIN_QUOTAS.business
|
|
2088
|
+
},
|
|
2089
|
+
enterprise: {
|
|
2090
|
+
...LOG_DRAIN_QUOTAS.enterprise
|
|
2091
|
+
}
|
|
2092
|
+
},
|
|
2093
|
+
pricing: {
|
|
2094
|
+
team: {
|
|
2095
|
+
includedEventsPerMonth: 0,
|
|
2096
|
+
includedBytesPerMonth: 0,
|
|
2097
|
+
usdPerMillionEvents: 0,
|
|
2098
|
+
usdPerGiB: 0
|
|
2099
|
+
},
|
|
2100
|
+
business: {
|
|
2101
|
+
includedEventsPerMonth: 0,
|
|
2102
|
+
includedBytesPerMonth: 0,
|
|
2103
|
+
usdPerMillionEvents: 0,
|
|
2104
|
+
usdPerGiB: 0
|
|
2105
|
+
},
|
|
2106
|
+
enterprise: {
|
|
2107
|
+
includedEventsPerMonth: 0,
|
|
2108
|
+
includedBytesPerMonth: 0,
|
|
2109
|
+
usdPerMillionEvents: 0,
|
|
2110
|
+
usdPerGiB: 0
|
|
2111
|
+
}
|
|
2112
|
+
}
|
|
2113
|
+
};
|
|
2114
|
+
var TIERS = [
|
|
2115
|
+
"team",
|
|
2116
|
+
"business",
|
|
2117
|
+
"enterprise"
|
|
2118
|
+
];
|
|
2119
|
+
function finiteNonNegative(value3) {
|
|
2120
|
+
return typeof value3 === "number" && Number.isFinite(value3) && value3 >= 0 ? value3 : void 0;
|
|
2121
|
+
}
|
|
2122
|
+
__name(finiteNonNegative, "finiteNonNegative");
|
|
2123
|
+
__name2(finiteNonNegative, "finiteNonNegative");
|
|
2124
|
+
function mergeLimits(base, stored) {
|
|
2125
|
+
const patch = stored ?? {};
|
|
2126
|
+
return {
|
|
2127
|
+
eventsPerDay: finiteNonNegative(patch.eventsPerDay) ?? base.eventsPerDay,
|
|
2128
|
+
bytesPerDay: finiteNonNegative(patch.bytesPerDay) ?? base.bytesPerDay
|
|
2129
|
+
};
|
|
2130
|
+
}
|
|
2131
|
+
__name(mergeLimits, "mergeLimits");
|
|
2132
|
+
__name2(mergeLimits, "mergeLimits");
|
|
2133
|
+
function mergeCard(base, stored) {
|
|
2134
|
+
const patch = stored ?? {};
|
|
2135
|
+
return {
|
|
2136
|
+
includedEventsPerMonth: finiteNonNegative(patch.includedEventsPerMonth) ?? base.includedEventsPerMonth,
|
|
2137
|
+
includedBytesPerMonth: finiteNonNegative(patch.includedBytesPerMonth) ?? base.includedBytesPerMonth,
|
|
2138
|
+
usdPerMillionEvents: finiteNonNegative(patch.usdPerMillionEvents) ?? base.usdPerMillionEvents,
|
|
2139
|
+
usdPerGiB: finiteNonNegative(patch.usdPerGiB) ?? base.usdPerGiB
|
|
2140
|
+
};
|
|
2141
|
+
}
|
|
2142
|
+
__name(mergeCard, "mergeCard");
|
|
2143
|
+
__name2(mergeCard, "mergeCard");
|
|
2144
|
+
function resolveStoredLogDrainPlanConfig(stored) {
|
|
2145
|
+
const values = stored;
|
|
2146
|
+
if (!values || typeof values.version !== "number" || !Number.isFinite(values.version)) {
|
|
2147
|
+
return DEFAULT_LOG_DRAIN_PLAN_CONFIG;
|
|
2148
|
+
}
|
|
2149
|
+
const tiers = {};
|
|
2150
|
+
const pricing = {};
|
|
2151
|
+
for (const tier of TIERS) {
|
|
2152
|
+
tiers[tier] = mergeLimits(DEFAULT_LOG_DRAIN_PLAN_CONFIG.tiers[tier], values.tiers?.[tier]);
|
|
2153
|
+
pricing[tier] = mergeCard(DEFAULT_LOG_DRAIN_PLAN_CONFIG.pricing[tier], values.pricing?.[tier]);
|
|
2154
|
+
}
|
|
2155
|
+
const orgs = {};
|
|
2156
|
+
for (const [orgId, override] of Object.entries(values.orgs ?? {})) {
|
|
2157
|
+
if (!orgId || !override || typeof override !== "object") continue;
|
|
2158
|
+
const row = {};
|
|
2159
|
+
if (override.tier && TIERS.includes(override.tier)) row.tier = override.tier;
|
|
2160
|
+
const events = finiteNonNegative(override.eventsPerDay);
|
|
2161
|
+
const bytes = finiteNonNegative(override.bytesPerDay);
|
|
2162
|
+
if (events !== void 0) row.eventsPerDay = events;
|
|
2163
|
+
if (bytes !== void 0) row.bytesPerDay = bytes;
|
|
2164
|
+
if (override.pricing && typeof override.pricing === "object") row.pricing = {
|
|
2165
|
+
...override.pricing
|
|
2166
|
+
};
|
|
2167
|
+
if (Object.keys(row).length) orgs[orgId] = row;
|
|
2168
|
+
}
|
|
2169
|
+
return {
|
|
2170
|
+
version: values.version,
|
|
2171
|
+
tiers,
|
|
2172
|
+
pricing,
|
|
2173
|
+
...Object.keys(orgs).length ? {
|
|
2174
|
+
orgs
|
|
2175
|
+
} : {}
|
|
2176
|
+
};
|
|
2177
|
+
}
|
|
2178
|
+
__name(resolveStoredLogDrainPlanConfig, "resolveStoredLogDrainPlanConfig");
|
|
2179
|
+
__name2(resolveStoredLogDrainPlanConfig, "resolveStoredLogDrainPlanConfig");
|
|
2180
|
+
function logDrainPlanTierOverride(config, orgId) {
|
|
2181
|
+
return orgId ? config.orgs?.[orgId]?.tier : void 0;
|
|
2182
|
+
}
|
|
2183
|
+
__name(logDrainPlanTierOverride, "logDrainPlanTierOverride");
|
|
2184
|
+
__name2(logDrainPlanTierOverride, "logDrainPlanTierOverride");
|
|
2185
|
+
function logDrainQuotaLimitsFor(config, orgId, tier) {
|
|
2186
|
+
const base = config.tiers[tier] ?? config.tiers.team ?? LOG_DRAIN_QUOTAS.team;
|
|
2187
|
+
const override = orgId ? config.orgs?.[orgId] : void 0;
|
|
2188
|
+
if (!override) return {
|
|
2189
|
+
...base
|
|
2190
|
+
};
|
|
2191
|
+
return {
|
|
2192
|
+
eventsPerDay: override.eventsPerDay ?? base.eventsPerDay,
|
|
2193
|
+
bytesPerDay: override.bytesPerDay ?? base.bytesPerDay
|
|
2194
|
+
};
|
|
2195
|
+
}
|
|
2196
|
+
__name(logDrainQuotaLimitsFor, "logDrainQuotaLimitsFor");
|
|
2197
|
+
__name2(logDrainQuotaLimitsFor, "logDrainQuotaLimitsFor");
|
|
2198
|
+
function logDrainPriceCardFor(config, orgId, tier) {
|
|
2199
|
+
const base = config.pricing[tier] ?? config.pricing.team ?? DEFAULT_LOG_DRAIN_PLAN_CONFIG.pricing.team;
|
|
2200
|
+
const override = orgId ? config.orgs?.[orgId]?.pricing : void 0;
|
|
2201
|
+
return override ? mergeCard(base, override) : {
|
|
2202
|
+
...base
|
|
2203
|
+
};
|
|
2204
|
+
}
|
|
2205
|
+
__name(logDrainPriceCardFor, "logDrainPriceCardFor");
|
|
2206
|
+
__name2(logDrainPriceCardFor, "logDrainPriceCardFor");
|
|
2207
|
+
function priceDrainUsage(totals, card, tier) {
|
|
2208
|
+
const billableRecords = Math.max(0, Math.floor(finiteNonNegative(totals?.billableRecords) ?? 0));
|
|
2209
|
+
const billableBytes = Math.max(0, Math.floor(finiteNonNegative(totals?.billableBytes) ?? 0));
|
|
2210
|
+
const includedEvents = card.includedEventsPerMonth;
|
|
2211
|
+
const includedBytes = card.includedBytesPerMonth;
|
|
2212
|
+
const overageEvents = Math.max(0, billableRecords - includedEvents);
|
|
2213
|
+
const overageBytes = Math.max(0, billableBytes - includedBytes);
|
|
2214
|
+
const eventsUsd = overageEvents / 1e6 * card.usdPerMillionEvents;
|
|
2215
|
+
const bytesUsd = overageBytes / LOG_DRAIN_BYTES_PER_GIB * card.usdPerGiB;
|
|
2216
|
+
const unpriced = card.usdPerMillionEvents === 0 && card.usdPerGiB === 0;
|
|
2217
|
+
const round = /* @__PURE__ */ __name2((usd) => Math.round(usd * 100) / 100, "round");
|
|
2218
|
+
return {
|
|
2219
|
+
lineItem: LOG_DRAIN_USAGE_LINE_ITEM,
|
|
2220
|
+
tier,
|
|
2221
|
+
billableRecords,
|
|
2222
|
+
billableBytes,
|
|
2223
|
+
includedEvents,
|
|
2224
|
+
includedBytes,
|
|
2225
|
+
overageEvents,
|
|
2226
|
+
overageBytes,
|
|
2227
|
+
eventsUsd: round(eventsUsd),
|
|
2228
|
+
bytesUsd: round(bytesUsd),
|
|
2229
|
+
usd: round(Math.max(eventsUsd, bytesUsd)),
|
|
2230
|
+
unpriced
|
|
2231
|
+
};
|
|
2232
|
+
}
|
|
2233
|
+
__name(priceDrainUsage, "priceDrainUsage");
|
|
2234
|
+
__name2(priceDrainUsage, "priceDrainUsage");
|
|
1335
2235
|
var LOG_CURSOR_MAX_LENGTH = 512;
|
|
1336
2236
|
var LOG_CURSOR_MAX_ID_LENGTH = 128;
|
|
1337
2237
|
var LOG_RELATIVE_TIME_PATTERN = /^(\d{1,9})([smhd])$/;
|
|
@@ -1361,12 +2261,12 @@ function decodeLogCursor(raw) {
|
|
|
1361
2261
|
return null;
|
|
1362
2262
|
}
|
|
1363
2263
|
if (!parsed || typeof parsed !== "object" || Array.isArray(parsed)) return null;
|
|
1364
|
-
const { t, id } = parsed;
|
|
2264
|
+
const { t, id: id2 } = parsed;
|
|
1365
2265
|
if (typeof t !== "number" || !Number.isSafeInteger(t) || t < 0) return null;
|
|
1366
|
-
if (typeof
|
|
2266
|
+
if (typeof id2 !== "string" || !id2 || id2.length > LOG_CURSOR_MAX_ID_LENGTH) return null;
|
|
1367
2267
|
return {
|
|
1368
2268
|
t,
|
|
1369
|
-
id
|
|
2269
|
+
id: id2
|
|
1370
2270
|
};
|
|
1371
2271
|
}
|
|
1372
2272
|
__name(decodeLogCursor, "decodeLogCursor");
|
|
@@ -2232,64 +3132,64 @@ function hasCapability(profiles, profileId, required) {
|
|
|
2232
3132
|
}
|
|
2233
3133
|
__name(hasCapability, "hasCapability");
|
|
2234
3134
|
__name2(hasCapability, "hasCapability");
|
|
2235
|
-
function workflowJobId(
|
|
2236
|
-
switch (
|
|
3135
|
+
function workflowJobId(id2) {
|
|
3136
|
+
switch (id2.kind) {
|
|
2237
3137
|
case "start":
|
|
2238
|
-
return `wft_${
|
|
3138
|
+
return `wft_${id2.runId}_0`;
|
|
2239
3139
|
case "start-redrive":
|
|
2240
|
-
return `wft_${
|
|
3140
|
+
return `wft_${id2.runId}_start_r${id2.now}`;
|
|
2241
3141
|
case "tick":
|
|
2242
|
-
return `wft_${
|
|
3142
|
+
return `wft_${id2.runId}_${id2.seq}`;
|
|
2243
3143
|
case "timer":
|
|
2244
|
-
return `wft_${
|
|
3144
|
+
return `wft_${id2.runId}_timer_${id2.stepId}_${id2.attempt}`;
|
|
2245
3145
|
case "timer-remainder":
|
|
2246
|
-
return `wft_${
|
|
3146
|
+
return `wft_${id2.runId}_timer_${id2.stepId}_${id2.attempt}_r${id2.now}`;
|
|
2247
3147
|
case "timer-deferral":
|
|
2248
|
-
return `wft_${
|
|
3148
|
+
return `wft_${id2.runId}_timer_${id2.stepId}_${id2.attempt}_d${id2.now}`;
|
|
2249
3149
|
case "timer-sibling":
|
|
2250
|
-
return `wft_${
|
|
3150
|
+
return `wft_${id2.runId}_timer_${id2.stepId}_${id2.attempt}_w${id2.now}`;
|
|
2251
3151
|
case "retry":
|
|
2252
|
-
return `wft_${
|
|
3152
|
+
return `wft_${id2.runId}_retry_${id2.stepId}_${id2.attempt}`;
|
|
2253
3153
|
case "respawn":
|
|
2254
|
-
return `wft_${
|
|
3154
|
+
return `wft_${id2.runId}_respawn_${id2.stepId}_${id2.attempt}_s${id2.segment}_r${id2.now}`;
|
|
2255
3155
|
case "redrive":
|
|
2256
|
-
return `wft_${
|
|
3156
|
+
return `wft_${id2.runId}_redrive_${id2.stepId}_${id2.attempt}_r${id2.now}`;
|
|
2257
3157
|
case "redispatch":
|
|
2258
|
-
return `wft_${
|
|
3158
|
+
return `wft_${id2.runId}_redispatch_${id2.stepId}_${id2.attempt}_x${id2.executionId ?? "none"}_r${id2.now}`;
|
|
2259
3159
|
case "expiry":
|
|
2260
|
-
return `wft_${
|
|
3160
|
+
return `wft_${id2.runId}_expire_${id2.stepId}_${id2.attempt}_t${id2.suspendedAt}${id2.hop > 0 ? `_h${id2.hop}` : ""}`;
|
|
2261
3161
|
case "step-terminal":
|
|
2262
|
-
return `wft_${
|
|
3162
|
+
return `wft_${id2.runId}_term_${id2.stepId}_${id2.attempt}_r${id2.now}`;
|
|
2263
3163
|
case "handback":
|
|
2264
|
-
return `wft_${
|
|
3164
|
+
return `wft_${id2.runId}_handback_${id2.stepId}_${id2.attempt}_${id2.now}`;
|
|
2265
3165
|
case "foreach-rate":
|
|
2266
|
-
return `wft_${
|
|
3166
|
+
return `wft_${id2.runId}_fe_${id2.stepId}_${id2.attempt}_${id2.bucket}`;
|
|
2267
3167
|
case "budget-expiry":
|
|
2268
|
-
return `wft_${
|
|
3168
|
+
return `wft_${id2.runId}_expiry_budget_r${id2.now}`;
|
|
2269
3169
|
case "budget-resume":
|
|
2270
|
-
return `wft_${
|
|
3170
|
+
return `wft_${id2.runId}_resume_budget_${id2.now}`;
|
|
2271
3171
|
case "deadline":
|
|
2272
|
-
return `wft_${
|
|
3172
|
+
return `wft_${id2.runId}_deadline_${id2.deadlineAt}`;
|
|
2273
3173
|
case "deadline-remainder":
|
|
2274
|
-
return `wft_${
|
|
3174
|
+
return `wft_${id2.runId}_deadline_${id2.deadlineAt}_r${id2.now}`;
|
|
2275
3175
|
case "readmit":
|
|
2276
|
-
return `wft_${
|
|
3176
|
+
return `wft_${id2.runId}_readmit_${id2.now}`;
|
|
2277
3177
|
case "cancel":
|
|
2278
|
-
return `wft_${
|
|
3178
|
+
return `wft_${id2.runId}_cancel`;
|
|
2279
3179
|
case "reconcile":
|
|
2280
|
-
return `wft_${
|
|
3180
|
+
return `wft_${id2.runId}_reconcile_${id2.now}`;
|
|
2281
3181
|
case "replay":
|
|
2282
|
-
return `wft_${
|
|
3182
|
+
return `wft_${id2.runId}_replay_g${id2.leaseGeneration}`;
|
|
2283
3183
|
case "migration":
|
|
2284
|
-
return `wfm_${
|
|
3184
|
+
return `wfm_${id2.migrationId}`;
|
|
2285
3185
|
default:
|
|
2286
|
-
return assertNever(
|
|
3186
|
+
return assertNever(id2);
|
|
2287
3187
|
}
|
|
2288
3188
|
}
|
|
2289
3189
|
__name(workflowJobId, "workflowJobId");
|
|
2290
3190
|
__name2(workflowJobId, "workflowJobId");
|
|
2291
|
-
function assertNever(
|
|
2292
|
-
throw new Error(`workflowJobId: unknown wake kind ${JSON.stringify(
|
|
3191
|
+
function assertNever(id2) {
|
|
3192
|
+
throw new Error(`workflowJobId: unknown wake kind ${JSON.stringify(id2)}`);
|
|
2293
3193
|
}
|
|
2294
3194
|
__name(assertNever, "assertNever");
|
|
2295
3195
|
__name2(assertNever, "assertNever");
|
|
@@ -2420,13 +3320,13 @@ var IDEMPOTENCY_HOLDING_STATUSES = [
|
|
|
2420
3320
|
];
|
|
2421
3321
|
var WORKFLOW_SCHEDULED_RUN_ID_PREFIX = "wfr_sched_";
|
|
2422
3322
|
var CLOUD_TASK_RUN_ID_PREFIX = "ct_";
|
|
2423
|
-
function isCloudTaskRunId(
|
|
2424
|
-
return
|
|
3323
|
+
function isCloudTaskRunId(id2) {
|
|
3324
|
+
return id2.startsWith(CLOUD_TASK_RUN_ID_PREFIX);
|
|
2425
3325
|
}
|
|
2426
3326
|
__name(isCloudTaskRunId, "isCloudTaskRunId");
|
|
2427
3327
|
__name2(isCloudTaskRunId, "isCloudTaskRunId");
|
|
2428
|
-
function isScheduledWorkflowRunId(
|
|
2429
|
-
return
|
|
3328
|
+
function isScheduledWorkflowRunId(id2) {
|
|
3329
|
+
return id2.startsWith(WORKFLOW_SCHEDULED_RUN_ID_PREFIX);
|
|
2430
3330
|
}
|
|
2431
3331
|
__name(isScheduledWorkflowRunId, "isScheduledWorkflowRunId");
|
|
2432
3332
|
__name2(isScheduledWorkflowRunId, "isScheduledWorkflowRunId");
|
|
@@ -3210,10 +4110,246 @@ function effectiveAgentFeatures(base, override, rule) {
|
|
|
3210
4110
|
}
|
|
3211
4111
|
__name(effectiveAgentFeatures, "effectiveAgentFeatures");
|
|
3212
4112
|
__name2(effectiveAgentFeatures, "effectiveAgentFeatures");
|
|
4113
|
+
var ONBOARDING_FLOW_KEY = "alpha-choose-meet";
|
|
4114
|
+
var ONBOARDING_SCHEMA_VERSION = 1;
|
|
4115
|
+
var id = z4.string().min(1).max(80).regex(/^[A-Za-z0-9][A-Za-z0-9_-]*$/);
|
|
4116
|
+
var copy = /* @__PURE__ */ __name2((max) => z4.string().max(max), "copy");
|
|
4117
|
+
var onboardingHeadingSchema = z4.discriminatedUnion("kind", [
|
|
4118
|
+
z4.object({
|
|
4119
|
+
kind: z4.literal("plain"),
|
|
4120
|
+
text: copy(240)
|
|
4121
|
+
}).strict(),
|
|
4122
|
+
z4.object({
|
|
4123
|
+
kind: z4.literal("highlighted"),
|
|
4124
|
+
before: copy(240),
|
|
4125
|
+
highlight: copy(240),
|
|
4126
|
+
after: copy(240)
|
|
4127
|
+
}).strict()
|
|
4128
|
+
]);
|
|
4129
|
+
var onboardingRichTextInlineSchema = z4.discriminatedUnion("kind", [
|
|
4130
|
+
z4.object({
|
|
4131
|
+
kind: z4.literal("text"),
|
|
4132
|
+
text: copy(2e3),
|
|
4133
|
+
marks: z4.array(z4.enum([
|
|
4134
|
+
"bold",
|
|
4135
|
+
"italic"
|
|
4136
|
+
])).max(2).refine((marks) => new Set(marks).size === marks.length, "Text marks must be unique").optional()
|
|
4137
|
+
}).strict(),
|
|
4138
|
+
z4.object({
|
|
4139
|
+
kind: z4.literal("lineBreak")
|
|
4140
|
+
}).strict()
|
|
4141
|
+
]);
|
|
4142
|
+
var onboardingRichTextSchema = z4.object({
|
|
4143
|
+
blocks: z4.array(z4.object({
|
|
4144
|
+
kind: z4.literal("paragraph"),
|
|
4145
|
+
content: z4.array(onboardingRichTextInlineSchema).max(100)
|
|
4146
|
+
}).strict()).max(40)
|
|
4147
|
+
}).strict();
|
|
4148
|
+
var onboardingDestinationSchema = z4.discriminatedUnion("kind", [
|
|
4149
|
+
z4.object({
|
|
4150
|
+
kind: z4.literal("question"),
|
|
4151
|
+
questionId: id
|
|
4152
|
+
}).strict(),
|
|
4153
|
+
z4.object({
|
|
4154
|
+
kind: z4.literal("template"),
|
|
4155
|
+
templateContentId: id
|
|
4156
|
+
}).strict(),
|
|
4157
|
+
z4.object({
|
|
4158
|
+
kind: z4.literal("unavailable"),
|
|
4159
|
+
unavailableId: id
|
|
4160
|
+
}).strict()
|
|
4161
|
+
]);
|
|
4162
|
+
var onboardingArtworkSchema = z4.discriminatedUnion("kind", [
|
|
4163
|
+
z4.object({
|
|
4164
|
+
kind: z4.literal("builtinRing")
|
|
4165
|
+
}).strict(),
|
|
4166
|
+
z4.object({
|
|
4167
|
+
kind: z4.literal("uploaded"),
|
|
4168
|
+
assetId: id,
|
|
4169
|
+
accessibility: z4.discriminatedUnion("kind", [
|
|
4170
|
+
z4.object({
|
|
4171
|
+
kind: z4.literal("decorative")
|
|
4172
|
+
}).strict(),
|
|
4173
|
+
z4.object({
|
|
4174
|
+
kind: z4.literal("described"),
|
|
4175
|
+
altText: copy(500)
|
|
4176
|
+
}).strict()
|
|
4177
|
+
])
|
|
4178
|
+
}).strict()
|
|
4179
|
+
]);
|
|
4180
|
+
var onboardingAnswerSchema = z4.object({
|
|
4181
|
+
id,
|
|
4182
|
+
label: copy(160),
|
|
4183
|
+
supportingText: copy(500).optional(),
|
|
4184
|
+
destination: onboardingDestinationSchema.nullable()
|
|
4185
|
+
}).strict();
|
|
4186
|
+
var onboardingQuestionSchema = z4.object({
|
|
4187
|
+
id,
|
|
4188
|
+
heading: onboardingHeadingSchema,
|
|
4189
|
+
helperText: onboardingRichTextSchema.optional(),
|
|
4190
|
+
continueButtonLabel: copy(80),
|
|
4191
|
+
answers: z4.array(onboardingAnswerSchema).max(30)
|
|
4192
|
+
}).strict();
|
|
4193
|
+
var onboardingTemplateSectionSchema = z4.object({
|
|
4194
|
+
id,
|
|
4195
|
+
label: copy(100),
|
|
4196
|
+
body: onboardingRichTextSchema
|
|
4197
|
+
}).strict();
|
|
4198
|
+
var onboardingTemplateContentSchema = z4.object({
|
|
4199
|
+
id,
|
|
4200
|
+
templateId: copy(160),
|
|
4201
|
+
displayName: copy(100),
|
|
4202
|
+
eyebrow: copy(100).optional(),
|
|
4203
|
+
heading: onboardingHeadingSchema,
|
|
4204
|
+
description: onboardingRichTextSchema,
|
|
4205
|
+
badges: z4.array(copy(80)).max(12),
|
|
4206
|
+
sections: z4.array(onboardingTemplateSectionSchema).max(20),
|
|
4207
|
+
artwork: onboardingArtworkSchema,
|
|
4208
|
+
hireButtonLabel: copy(80),
|
|
4209
|
+
changeRoleButtonLabel: copy(80),
|
|
4210
|
+
nextStepText: onboardingRichTextSchema
|
|
4211
|
+
}).strict();
|
|
4212
|
+
var onboardingUnavailableOutcomeSchema = z4.object({
|
|
4213
|
+
id,
|
|
4214
|
+
heading: onboardingHeadingSchema,
|
|
4215
|
+
explanation: onboardingRichTextSchema,
|
|
4216
|
+
backButtonLabel: copy(80),
|
|
4217
|
+
alternative: z4.object({
|
|
4218
|
+
templateContentId: id,
|
|
4219
|
+
introduction: onboardingRichTextSchema,
|
|
4220
|
+
buttonLabel: copy(80)
|
|
4221
|
+
}).strict().optional()
|
|
4222
|
+
}).strict();
|
|
4223
|
+
var onboardingFlowSchema = z4.object({
|
|
4224
|
+
key: z4.literal(ONBOARDING_FLOW_KEY),
|
|
4225
|
+
schemaVersion: z4.literal(ONBOARDING_SCHEMA_VERSION),
|
|
4226
|
+
entryQuestionId: id.nullable(),
|
|
4227
|
+
questions: z4.array(onboardingQuestionSchema).max(100),
|
|
4228
|
+
templateContents: z4.array(onboardingTemplateContentSchema).max(100),
|
|
4229
|
+
unavailableOutcomes: z4.array(onboardingUnavailableOutcomeSchema).max(100)
|
|
4230
|
+
}).strict();
|
|
4231
|
+
var onboardingActorSchema = z4.object({
|
|
4232
|
+
subjectId: z4.string(),
|
|
4233
|
+
email: z4.string().email()
|
|
4234
|
+
}).strict();
|
|
4235
|
+
var onboardingEditorSchema = onboardingActorSchema.extend({
|
|
4236
|
+
editedAt: z4.string().datetime({
|
|
4237
|
+
offset: true
|
|
4238
|
+
})
|
|
4239
|
+
}).strict();
|
|
4240
|
+
var onboardingPublicationSummarySchema = z4.object({
|
|
4241
|
+
publicationId: id,
|
|
4242
|
+
revision: z4.number().int().positive(),
|
|
4243
|
+
sourceDraftVersion: z4.number().int().nonnegative(),
|
|
4244
|
+
contentHash: z4.string().regex(/^[a-f0-9]{64}$/),
|
|
4245
|
+
publishedAt: z4.string().datetime({
|
|
4246
|
+
offset: true
|
|
4247
|
+
}),
|
|
4248
|
+
publishedBy: onboardingActorSchema,
|
|
4249
|
+
questionCount: z4.number().int().nonnegative(),
|
|
4250
|
+
templateCount: z4.number().int().nonnegative(),
|
|
4251
|
+
unavailableCount: z4.number().int().nonnegative()
|
|
4252
|
+
}).strict();
|
|
4253
|
+
var onboardingValidationIssueSchema = z4.object({
|
|
4254
|
+
code: z4.string(),
|
|
4255
|
+
path: z4.string(),
|
|
4256
|
+
message: z4.string()
|
|
4257
|
+
}).strict();
|
|
4258
|
+
var onboardingValidationResponseSchema = z4.discriminatedUnion("valid", [
|
|
4259
|
+
z4.object({
|
|
4260
|
+
valid: z4.literal(true),
|
|
4261
|
+
summary: z4.object({
|
|
4262
|
+
questionCount: z4.number().int().nonnegative(),
|
|
4263
|
+
templateCount: z4.number().int().nonnegative(),
|
|
4264
|
+
unavailableCount: z4.number().int().nonnegative()
|
|
4265
|
+
}).strict()
|
|
4266
|
+
}).strict(),
|
|
4267
|
+
z4.object({
|
|
4268
|
+
valid: z4.literal(false),
|
|
4269
|
+
issues: z4.array(onboardingValidationIssueSchema)
|
|
4270
|
+
}).strict()
|
|
4271
|
+
]);
|
|
4272
|
+
var onboardingAssetSchema = z4.object({
|
|
4273
|
+
assetId: id,
|
|
4274
|
+
url: z4.string().url(),
|
|
4275
|
+
width: z4.number().int().positive(),
|
|
4276
|
+
height: z4.number().int().positive(),
|
|
4277
|
+
contentType: z4.enum([
|
|
4278
|
+
"image/png",
|
|
4279
|
+
"image/jpeg",
|
|
4280
|
+
"image/webp"
|
|
4281
|
+
]),
|
|
4282
|
+
bytes: z4.number().int().positive(),
|
|
4283
|
+
sha256: z4.string().regex(/^[a-f0-9]{64}$/),
|
|
4284
|
+
createdAt: z4.string().datetime({
|
|
4285
|
+
offset: true
|
|
4286
|
+
}),
|
|
4287
|
+
uploadedBy: onboardingActorSchema
|
|
4288
|
+
}).strict();
|
|
4289
|
+
var onboardingPublicAssetSchema = onboardingAssetSchema.pick({
|
|
4290
|
+
assetId: true,
|
|
4291
|
+
url: true,
|
|
4292
|
+
width: true,
|
|
4293
|
+
height: true,
|
|
4294
|
+
contentType: true
|
|
4295
|
+
}).strict();
|
|
4296
|
+
var getOnboardingConfigResponseSchema = z4.object({
|
|
4297
|
+
flowKey: z4.literal(ONBOARDING_FLOW_KEY),
|
|
4298
|
+
draftVersion: z4.number().int().nonnegative(),
|
|
4299
|
+
draft: onboardingFlowSchema,
|
|
4300
|
+
assets: z4.array(onboardingAssetSchema),
|
|
4301
|
+
lastEditor: onboardingEditorSchema.nullable(),
|
|
4302
|
+
activePublication: onboardingPublicationSummarySchema.nullable()
|
|
4303
|
+
}).strict();
|
|
4304
|
+
var saveOnboardingDraftRequestSchema = z4.object({
|
|
4305
|
+
expectedDraftVersion: z4.number().int().nonnegative(),
|
|
4306
|
+
draft: onboardingFlowSchema
|
|
4307
|
+
}).strict();
|
|
4308
|
+
var validateOnboardingRequestSchema = z4.object({
|
|
4309
|
+
draft: onboardingFlowSchema
|
|
4310
|
+
}).strict();
|
|
4311
|
+
var publishOnboardingRequestSchema = z4.object({
|
|
4312
|
+
expectedDraftVersion: z4.number().int().nonnegative(),
|
|
4313
|
+
expectedActivePublicationId: id.nullable()
|
|
4314
|
+
}).strict();
|
|
4315
|
+
var rollbackOnboardingRequestSchema = z4.object({
|
|
4316
|
+
publicationId: id,
|
|
4317
|
+
expectedActivePublicationId: id.nullable()
|
|
4318
|
+
}).strict();
|
|
4319
|
+
var onboardingTemplateCatalogItemSchema = z4.object({
|
|
4320
|
+
templateId: z4.string(),
|
|
4321
|
+
name: z4.string(),
|
|
4322
|
+
description: z4.string().optional()
|
|
4323
|
+
}).strict();
|
|
4324
|
+
var getPublishedOnboardingResponseSchema = z4.discriminatedUnion("status", [
|
|
4325
|
+
z4.object({
|
|
4326
|
+
status: z4.literal("available"),
|
|
4327
|
+
publicationId: id,
|
|
4328
|
+
revision: z4.number().int().positive(),
|
|
4329
|
+
contentHash: z4.string().regex(/^[a-f0-9]{64}$/),
|
|
4330
|
+
flow: onboardingFlowSchema,
|
|
4331
|
+
assets: z4.array(onboardingPublicAssetSchema)
|
|
4332
|
+
}).strict(),
|
|
4333
|
+
z4.object({
|
|
4334
|
+
status: z4.literal("unavailable"),
|
|
4335
|
+
reason: z4.literal("not_published"),
|
|
4336
|
+
message: z4.string()
|
|
4337
|
+
}).strict()
|
|
4338
|
+
]);
|
|
4339
|
+
function parseOnboardingFlow(value3) {
|
|
4340
|
+
return onboardingFlowSchema.parse(value3);
|
|
4341
|
+
}
|
|
4342
|
+
__name(parseOnboardingFlow, "parseOnboardingFlow");
|
|
4343
|
+
__name2(parseOnboardingFlow, "parseOnboardingFlow");
|
|
4344
|
+
function parsePublishedOnboardingResponse(value3) {
|
|
4345
|
+
return getPublishedOnboardingResponseSchema.parse(value3);
|
|
4346
|
+
}
|
|
4347
|
+
__name(parsePublishedOnboardingResponse, "parsePublishedOnboardingResponse");
|
|
4348
|
+
__name2(parsePublishedOnboardingResponse, "parsePublishedOnboardingResponse");
|
|
3213
4349
|
|
|
3214
4350
|
// ../workflow-graph/dist/index.mjs
|
|
3215
4351
|
import { createHash } from "crypto";
|
|
3216
|
-
import { z as
|
|
4352
|
+
import { z as z5 } from "zod";
|
|
3217
4353
|
import { z as z22 } from "zod";
|
|
3218
4354
|
|
|
3219
4355
|
// ../shared-types/dist/workflow-job-tools.mjs
|
|
@@ -3249,9 +4385,9 @@ var WORKFLOW_JOB_DEFAULT_TOOLS = [
|
|
|
3249
4385
|
function effectiveJobTools(jobTools, readOnly) {
|
|
3250
4386
|
const base = jobTools?.length ? jobTools : WORKFLOW_JOB_DEFAULT_TOOLS;
|
|
3251
4387
|
const out = [];
|
|
3252
|
-
for (const
|
|
3253
|
-
if (readOnly && WORKFLOW_JOB_READ_ONLY_DROPPED.includes(
|
|
3254
|
-
if (!out.includes(
|
|
4388
|
+
for (const id2 of base) {
|
|
4389
|
+
if (readOnly && WORKFLOW_JOB_READ_ONLY_DROPPED.includes(id2)) continue;
|
|
4390
|
+
if (!out.includes(id2)) out.push(id2);
|
|
3255
4391
|
}
|
|
3256
4392
|
return out;
|
|
3257
4393
|
}
|
|
@@ -3440,9 +4576,9 @@ function malformedMapMembers(cfg) {
|
|
|
3440
4576
|
}
|
|
3441
4577
|
__name(malformedMapMembers, "malformedMapMembers");
|
|
3442
4578
|
__name4(malformedMapMembers, "malformedMapMembers");
|
|
3443
|
-
function mapMemberMalformedMessage(
|
|
4579
|
+
function mapMemberMalformedMessage(id2, m) {
|
|
3444
4580
|
const keys = m.keys.map((k) => `\`${k}\``).join(", ");
|
|
3445
|
-
return `"${
|
|
4581
|
+
return `"${id2}".${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`;
|
|
3446
4582
|
}
|
|
3447
4583
|
__name(mapMemberMalformedMessage, "mapMemberMalformedMessage");
|
|
3448
4584
|
__name4(mapMemberMalformedMessage, "mapMemberMalformedMessage");
|
|
@@ -3552,8 +4688,8 @@ var rows = /* @__PURE__ */ __name4((s, path, page) => ({
|
|
|
3552
4688
|
var fromKnowledge = /* @__PURE__ */ __name4((k) => ({
|
|
3553
4689
|
knowledge: k
|
|
3554
4690
|
}), "fromKnowledge");
|
|
3555
|
-
var SideEffectsSchema =
|
|
3556
|
-
var JobResourcesSchema =
|
|
4691
|
+
var SideEffectsSchema = z5.enum(WORKFLOW_SIDE_EFFECTS);
|
|
4692
|
+
var JobResourcesSchema = z5.enum(WORKFLOW_JOB_RESOURCES);
|
|
3557
4693
|
var WORKFLOW_MODEL_TEMPLATE_ROOT = "initData";
|
|
3558
4694
|
var WORKFLOW_MODEL_TEMPLATE_RE = /^\$\{\s*initData\.([A-Za-z0-9_.\-[\]]+)\s*(?:\|([^}]*))?\}$/;
|
|
3559
4695
|
var PATH_SEGMENT_RE = /^[A-Za-z0-9_-]+(?:\[(?:0|[1-9]\d*)\])*$/;
|
|
@@ -3944,13 +5080,13 @@ var SLEEP_UNTIL_REPLACEMENT = Object.freeze({
|
|
|
3944
5080
|
type: "sleep",
|
|
3945
5081
|
duration: 6e4
|
|
3946
5082
|
});
|
|
3947
|
-
function sleepUntilUnsupportedMessage(
|
|
3948
|
-
return `the engine does not execute \`sleepUntil\` yet (node "${
|
|
5083
|
+
function sleepUntilUnsupportedMessage(id2) {
|
|
5084
|
+
return `the engine does not execute \`sleepUntil\` yet (node "${id2}") \u2014 replace it with a \`sleep\` node with a \`duration\` in ms, e.g. { type: 'sleep', id: '${id2}', duration: ${SLEEP_UNTIL_REPLACEMENT.duration} }`;
|
|
3949
5085
|
}
|
|
3950
5086
|
__name(sleepUntilUnsupportedMessage, "sleepUntilUnsupportedMessage");
|
|
3951
5087
|
__name4(sleepUntilUnsupportedMessage, "sleepUntilUnsupportedMessage");
|
|
3952
|
-
function armSubrunUnsupportedMessage(
|
|
3953
|
-
return `the engine does not execute the implicit \`${workflowId}\` arm subrun (node "${
|
|
5088
|
+
function armSubrunUnsupportedMessage(id2, workflowId) {
|
|
5089
|
+
return `the engine does not execute the implicit \`${workflowId}\` arm subrun (node "${id2}") \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)`;
|
|
3954
5090
|
}
|
|
3955
5091
|
__name(armSubrunUnsupportedMessage, "armSubrunUnsupportedMessage");
|
|
3956
5092
|
__name4(armSubrunUnsupportedMessage, "armSubrunUnsupportedMessage");
|
|
@@ -4288,20 +5424,20 @@ function validateLuaExtensions(g, caps = WORKFLOW_CAPS_DEFAULT, opts = {
|
|
|
4288
5424
|
const seen = /* @__PURE__ */ new Map();
|
|
4289
5425
|
let nodeCount = 0;
|
|
4290
5426
|
const upstream = /* @__PURE__ */ new Set();
|
|
4291
|
-
const checkId = /* @__PURE__ */ __name4((
|
|
5427
|
+
const checkId = /* @__PURE__ */ __name4((id2, path) => {
|
|
4292
5428
|
nodeCount += 1;
|
|
4293
|
-
if (seen.has(
|
|
4294
|
-
err("duplicate-step-id", `step id "${
|
|
5429
|
+
if (seen.has(id2)) {
|
|
5430
|
+
err("duplicate-step-id", `step id "${id2}" is declared twice (first at ${seen.get(id2)})`, path, id2);
|
|
4295
5431
|
} else {
|
|
4296
|
-
seen.set(
|
|
5432
|
+
seen.set(id2, path);
|
|
4297
5433
|
}
|
|
4298
5434
|
}, "checkId");
|
|
4299
5435
|
const checkPolicyEnums = /* @__PURE__ */ __name4((node, path) => {
|
|
4300
|
-
const
|
|
5436
|
+
const id2 = singleId(node);
|
|
4301
5437
|
const check = /* @__PURE__ */ __name4((member, allowed) => {
|
|
4302
5438
|
const value22 = node[member];
|
|
4303
5439
|
if (value22 === void 0 || typeof value22 === "string" && allowed.includes(value22)) return;
|
|
4304
|
-
err("invalid-envelope", `\`${member}\` must be ${allowed.map((a) => `'${a}'`).join(" | ")} (got ${JSON.stringify(value22)})`, `${path}.${member}`,
|
|
5440
|
+
err("invalid-envelope", `\`${member}\` must be ${allowed.map((a) => `'${a}'`).join(" | ")} (got ${JSON.stringify(value22)})`, `${path}.${member}`, id2);
|
|
4305
5441
|
}, "check");
|
|
4306
5442
|
check("sideEffects", WORKFLOW_SIDE_EFFECTS);
|
|
4307
5443
|
check("jobResources", WORKFLOW_JOB_RESOURCES);
|
|
@@ -4309,46 +5445,46 @@ function validateLuaExtensions(g, caps = WORKFLOW_CAPS_DEFAULT, opts = {
|
|
|
4309
5445
|
const checkRetry = /* @__PURE__ */ __name4((node, path) => {
|
|
4310
5446
|
const r = node.retry;
|
|
4311
5447
|
if (!r) return;
|
|
4312
|
-
const
|
|
5448
|
+
const id2 = singleId(node);
|
|
4313
5449
|
const unknown = unknownWorkflowRetryMembers(r);
|
|
4314
|
-
if (unknown.length) err("invalid-envelope", workflowRetryUnknownMembersMessage(unknown), `${path}.retry`,
|
|
5450
|
+
if (unknown.length) err("invalid-envelope", workflowRetryUnknownMembersMessage(unknown), `${path}.retry`, id2);
|
|
4315
5451
|
if (!isWithinWorkflowRetryAttempts(r.maxAttempts)) {
|
|
4316
5452
|
const over = typeof r.maxAttempts === "number" && r.maxAttempts > WORKFLOW_RETRY_MAX_ATTEMPTS;
|
|
4317
|
-
err(over ? "cap-exceeded" : "invalid-envelope", workflowRetryMaxAttemptsMessage(r.maxAttempts), `${path}.retry.maxAttempts`,
|
|
5453
|
+
err(over ? "cap-exceeded" : "invalid-envelope", workflowRetryMaxAttemptsMessage(r.maxAttempts), `${path}.retry.maxAttempts`, id2);
|
|
4318
5454
|
}
|
|
4319
5455
|
const backoffs = retryBackoffs();
|
|
4320
5456
|
if (r.backoff !== void 0 && !backoffs.includes(r.backoff)) {
|
|
4321
5457
|
const list = backoffs.map((b) => `'${b}'`).join(" | ");
|
|
4322
|
-
err("backoff-invalid", `retry.backoff must be ${list}`, `${path}.retry.backoff`,
|
|
5458
|
+
err("backoff-invalid", `retry.backoff must be ${list}`, `${path}.retry.backoff`, id2);
|
|
4323
5459
|
}
|
|
4324
5460
|
if (r.backoffSeconds !== void 0 && r.backoffSeconds < 0) {
|
|
4325
|
-
err("backoff-invalid", "retry.backoffSeconds must be \u2265 0", `${path}.retry.backoffSeconds`,
|
|
5461
|
+
err("backoff-invalid", "retry.backoffSeconds must be \u2265 0", `${path}.retry.backoffSeconds`, id2);
|
|
4326
5462
|
}
|
|
4327
5463
|
if (r.maxBackoffSeconds !== void 0) {
|
|
4328
5464
|
if (r.backoff !== "exponential") {
|
|
4329
|
-
err("backoff-invalid", "retry.maxBackoffSeconds is only meaningful with backoff:'exponential'", `${path}.retry`,
|
|
5465
|
+
err("backoff-invalid", "retry.maxBackoffSeconds is only meaningful with backoff:'exponential'", `${path}.retry`, id2);
|
|
4330
5466
|
} else if (r.maxBackoffSeconds <= 0 || r.backoffSeconds !== void 0 && r.maxBackoffSeconds < r.backoffSeconds) {
|
|
4331
|
-
err("backoff-invalid", "retry.maxBackoffSeconds must be > 0 and \u2265 backoffSeconds", `${path}.retry.maxBackoffSeconds`,
|
|
5467
|
+
err("backoff-invalid", "retry.maxBackoffSeconds must be > 0 and \u2265 backoffSeconds", `${path}.retry.maxBackoffSeconds`, id2);
|
|
4332
5468
|
}
|
|
4333
5469
|
}
|
|
4334
5470
|
}, "checkRetry");
|
|
4335
5471
|
const checkTimeout = /* @__PURE__ */ __name4((node, path) => {
|
|
4336
5472
|
const t = node.timeoutSeconds;
|
|
4337
5473
|
if (t === void 0) return;
|
|
4338
|
-
const
|
|
5474
|
+
const id2 = singleId(node);
|
|
4339
5475
|
if (!Number.isInteger(t) || t < 1) {
|
|
4340
|
-
err("timeout-out-of-range", `timeoutSeconds must be an integer \u2265 1 (got ${t})`, `${path}.timeoutSeconds`,
|
|
5476
|
+
err("timeout-out-of-range", `timeoutSeconds must be an integer \u2265 1 (got ${t})`, `${path}.timeoutSeconds`, id2);
|
|
4341
5477
|
return;
|
|
4342
5478
|
}
|
|
4343
5479
|
if (node.tier === "job") {
|
|
4344
5480
|
const cap = node.type === "agent" ? caps.maxJobTimeoutSeconds : caps.maxJobSegmentSeconds;
|
|
4345
5481
|
if (t > cap) {
|
|
4346
|
-
err("job-timeout-exceeds-cap", `timeoutSeconds ${t} exceeds the Job-tier cap of ${cap} s`, `${path}.timeoutSeconds`,
|
|
5482
|
+
err("job-timeout-exceeds-cap", `timeoutSeconds ${t} exceeds the Job-tier cap of ${cap} s`, `${path}.timeoutSeconds`, id2);
|
|
4347
5483
|
} else if (node.type === "agent" && t > caps.maxJobSegmentSeconds && !node.workspace) {
|
|
4348
|
-
err("long-job-requires-workspace", `steps longer than 4 h checkpoint to the run workspace \u2014 add workspace:{mount:'rw'} (and workspace on createWorkflow) or split the step`, `${path}.timeoutSeconds`,
|
|
5484
|
+
err("long-job-requires-workspace", `steps longer than 4 h checkpoint to the run workspace \u2014 add workspace:{mount:'rw'} (and workspace on createWorkflow) or split the step`, `${path}.timeoutSeconds`, id2);
|
|
4349
5485
|
}
|
|
4350
5486
|
} else if (t > caps.maxWorkerTimeoutSeconds) {
|
|
4351
|
-
err("timeout-exceeds-tier", `timeoutSeconds ${t} exceeds the worker tier's ${caps.maxWorkerTimeoutSeconds} s \u2014 steps longer than 10 min run on the Job tier: add tier:'job' (up to ${caps.maxJobSegmentSeconds} s)`, `${path}.timeoutSeconds`,
|
|
5487
|
+
err("timeout-exceeds-tier", `timeoutSeconds ${t} exceeds the worker tier's ${caps.maxWorkerTimeoutSeconds} s \u2014 steps longer than 10 min run on the Job tier: add tier:'job' (up to ${caps.maxJobSegmentSeconds} s)`, `${path}.timeoutSeconds`, id2);
|
|
4352
5488
|
}
|
|
4353
5489
|
}, "checkTimeout");
|
|
4354
5490
|
const checkSpecialistRole = /* @__PURE__ */ __name4((node, path) => {
|
|
@@ -4412,32 +5548,32 @@ function validateLuaExtensions(g, caps = WORKFLOW_CAPS_DEFAULT, opts = {
|
|
|
4412
5548
|
return void 0;
|
|
4413
5549
|
}, "jobClassifiablePin");
|
|
4414
5550
|
const checkTier = /* @__PURE__ */ __name4((node, path) => {
|
|
4415
|
-
const
|
|
5551
|
+
const id2 = singleId(node);
|
|
4416
5552
|
if (node.workspace && node.workspace !== "inherit" && node.tier !== void 0 && node.tier !== "job") {
|
|
4417
|
-
err("workspace-requires-job-tier", "a step mounting a workspace must be tier:'job'", `${path}.workspace`,
|
|
5553
|
+
err("workspace-requires-job-tier", "a step mounting a workspace must be tier:'job'", `${path}.workspace`, id2);
|
|
4418
5554
|
}
|
|
4419
5555
|
if (node.harness !== void 0 && node.tier !== "job") {
|
|
4420
|
-
err("harness-requires-job-tier", "`harness` is only legal on a tier:'job' agent step", `${path}.harness`,
|
|
5556
|
+
err("harness-requires-job-tier", "`harness` is only legal on a tier:'job' agent step", `${path}.harness`, id2);
|
|
4421
5557
|
}
|
|
4422
5558
|
const provider = node.type === "agent" ? classifyModelProvider(jobClassifiablePin(node.model)) : null;
|
|
4423
5559
|
if (node.harness === "claude-code" && provider !== null && provider !== "anthropic") {
|
|
4424
|
-
err("harness-provider-mismatch", `harness:'claude-code' needs an Anthropic model (model "${node.type === "agent" ? node.model : ""}" is ${provider})`, `${path}.harness`,
|
|
5560
|
+
err("harness-provider-mismatch", `harness:'claude-code' needs an Anthropic model (model "${node.type === "agent" ? node.model : ""}" is ${provider})`, `${path}.harness`, id2);
|
|
4425
5561
|
}
|
|
4426
5562
|
if (isJobTier(node) && provider !== null && opts.policy?.jobProviders && !opts.policy.jobProviders.includes(provider)) {
|
|
4427
|
-
err("job-tier-provider-unsupported", `model provider '${provider}' is outside LUA_WF_JOB_PROVIDERS [${opts.policy.jobProviders.join(", ")}]`, `${path}.model`,
|
|
5563
|
+
err("job-tier-provider-unsupported", `model provider '${provider}' is outside LUA_WF_JOB_PROVIDERS [${opts.policy.jobProviders.join(", ")}]`, `${path}.model`, id2);
|
|
4428
5564
|
}
|
|
4429
5565
|
}, "checkTier");
|
|
4430
5566
|
const checkModel = /* @__PURE__ */ __name4((node, path) => {
|
|
4431
5567
|
if (node.type !== "agent" || typeof node.model !== "string") return;
|
|
4432
|
-
const
|
|
5568
|
+
const id2 = singleId(node);
|
|
4433
5569
|
const parsed = parseModelTemplate(node.model);
|
|
4434
5570
|
if (parsed.kind === "invalid") {
|
|
4435
|
-
err("model-template-invalid", parsed.message, `${path}.model`,
|
|
5571
|
+
err("model-template-invalid", parsed.message, `${path}.model`, id2);
|
|
4436
5572
|
return;
|
|
4437
5573
|
}
|
|
4438
5574
|
if (parsed.kind === "template" && parsed.template.default === void 0) {
|
|
4439
5575
|
if (isJobTier(node)) {
|
|
4440
|
-
err("model-template-default-required", modelTemplateDefaultRequiredMessage(node.model), `${path}.model`,
|
|
5576
|
+
err("model-template-default-required", modelTemplateDefaultRequiredMessage(node.model), `${path}.model`, id2);
|
|
4441
5577
|
}
|
|
4442
5578
|
return;
|
|
4443
5579
|
}
|
|
@@ -4450,12 +5586,12 @@ function validateLuaExtensions(g, caps = WORKFLOW_CAPS_DEFAULT, opts = {
|
|
|
4450
5586
|
if (registry === "unavailable") {
|
|
4451
5587
|
const trimmed = pin.trim();
|
|
4452
5588
|
if (trimmed && !normalizeModelId(trimmed, []).ok) {
|
|
4453
|
-
warn("model-unresolved", inContext(`model "${trimmed}" 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)`), `${path}.model`,
|
|
5589
|
+
warn("model-unresolved", inContext(`model "${trimmed}" 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)`), `${path}.model`, id2);
|
|
4454
5590
|
}
|
|
4455
5591
|
return;
|
|
4456
5592
|
}
|
|
4457
5593
|
const resolved = normalizeModelId(pin, registry);
|
|
4458
|
-
if (!resolved.ok) err("model-unresolved", inContext(modelUnresolvedMessage(resolved)), `${path}.model`,
|
|
5594
|
+
if (!resolved.ok) err("model-unresolved", inContext(modelUnresolvedMessage(resolved)), `${path}.model`, id2);
|
|
4459
5595
|
}, "checkModel");
|
|
4460
5596
|
const checkTaskClass = /* @__PURE__ */ __name4((node, path) => {
|
|
4461
5597
|
if (node.type !== "agent" || node.taskClass === void 0) return;
|
|
@@ -4464,46 +5600,46 @@ function validateLuaExtensions(g, caps = WORKFLOW_CAPS_DEFAULT, opts = {
|
|
|
4464
5600
|
err("task-class-without-model", `taskClass '${String(node.taskClass)}' needs a \`model\` on a pushed definition \u2014 write a class (model: 'class/fast' | 'class/balanced' | 'class/strong') or an approved provider/model code; nothing maps a task class to a model at dispatch, so a step with neither would run on the agent\u2019s own model`, `${path}.taskClass`, singleId(node));
|
|
4465
5601
|
}, "checkTaskClass");
|
|
4466
5602
|
const checkWorkspace = /* @__PURE__ */ __name4((node, path) => {
|
|
4467
|
-
const
|
|
5603
|
+
const id2 = singleId(node);
|
|
4468
5604
|
const ws = workspaceOf(node);
|
|
4469
5605
|
if (isJobTier(node) && opts.policy && opts.policy.jobTier !== true) {
|
|
4470
|
-
err("job-tier-disabled", `"${
|
|
5606
|
+
err("job-tier-disabled", `"${id2}" runs on the Job tier but the org's workflowPolicy.jobTier is off \u2014 an org admin enables it (lua features workflows.caps.jobTier true)`, `${path}.tier`, id2);
|
|
4471
5607
|
}
|
|
4472
5608
|
const tools = jobToolsOf(node);
|
|
4473
5609
|
if (tools !== void 0) {
|
|
4474
5610
|
if (!isJobTier(node)) {
|
|
4475
|
-
err("job-tools-require-job-tier", "`jobTools` needs tier:'job'", `${path}.jobTools`,
|
|
5611
|
+
err("job-tools-require-job-tier", "`jobTools` needs tier:'job'", `${path}.jobTools`, id2);
|
|
4476
5612
|
}
|
|
4477
5613
|
const unknown = (Array.isArray(tools) ? tools : [
|
|
4478
5614
|
tools
|
|
4479
5615
|
]).filter((t) => !WORKFLOW_JOB_TOOLS.includes(t));
|
|
4480
5616
|
if (unknown.length > 0) {
|
|
4481
|
-
err("job-tools-unknown", `jobTools ${JSON.stringify(unknown)} outside WORKFLOW_JOB_TOOLS [${WORKFLOW_JOB_TOOLS.join(", ")}]`, `${path}.jobTools`,
|
|
5617
|
+
err("job-tools-unknown", `jobTools ${JSON.stringify(unknown)} outside WORKFLOW_JOB_TOOLS [${WORKFLOW_JOB_TOOLS.join(", ")}]`, `${path}.jobTools`, id2);
|
|
4482
5618
|
}
|
|
4483
5619
|
if (node.type === "agent" && (Array.isArray(tools) ? tools : [
|
|
4484
5620
|
tools
|
|
4485
5621
|
]).includes("gh")) {
|
|
4486
|
-
warn("gh-on-coding-turn", `"${
|
|
5622
|
+
warn("gh-on-coding-turn", `"${id2}" grants the gh tool on a coding turn \u2014 the pod can open/merge PRs on the workspace repo (purpose:'gh' token, pull_requests:write + contents:write)`, `${path}.jobTools`, id2);
|
|
4487
5623
|
}
|
|
4488
5624
|
}
|
|
4489
5625
|
if (node.type === "agent" && ws && ws !== "inherit" && ws.mount === "ro" && Array.isArray(tools) && effectiveJobTools(tools, true).length === 0) {
|
|
4490
|
-
warn("ro-step-has-no-tools", `"${
|
|
5626
|
+
warn("ro-step-has-no-tools", `"${id2}" mounts the workspace read-only and every jobTool it declares (${JSON.stringify(tools)}) is one the ro mount drops [${WORKFLOW_JOB_READ_ONLY_DROPPED.join(", ")}] \u2014 the coding turn would run with no tools at all; keep a read-only tool (read/glob/grep, gh) or mount rw`, `${path}.jobTools`, id2);
|
|
4491
5627
|
}
|
|
4492
5628
|
if (ws && ws !== "inherit") {
|
|
4493
5629
|
if (!envelopeWorkspace && !opts.mayInherit) {
|
|
4494
|
-
err("workspace-not-declared", `"${
|
|
5630
|
+
err("workspace-not-declared", `"${id2}" mounts a workspace but the workflow declares none \u2014 add workspace:{kind, \u2026} on createWorkflow`, `${path}.workspace`, id2);
|
|
4495
5631
|
}
|
|
4496
5632
|
if (ws.isolation === "worktree" && envelopeWorkspace?.kind === "empty") {
|
|
4497
|
-
err("worktree-requires-git-workspace", `"${
|
|
5633
|
+
err("worktree-requires-git-workspace", `"${id2}": isolation:'worktree' needs a kind:'git' workspace (the envelope declares kind:'empty')`, `${path}.workspace.isolation`, id2);
|
|
4498
5634
|
}
|
|
4499
5635
|
}
|
|
4500
5636
|
if (node.type === "workflow" && ws === "inherit") {
|
|
4501
5637
|
if (!envelopeWorkspace) {
|
|
4502
|
-
err("workspace-inherit-without-parent-workspace", `"${
|
|
5638
|
+
err("workspace-inherit-without-parent-workspace", `"${id2}": workspace:'inherit' but the parent workflow declares no workspace \u2014 there is nothing to inherit`, `${path}.workspace`, id2);
|
|
4503
5639
|
}
|
|
4504
5640
|
const child = opts.resolveWorkflow?.(node.workflowId);
|
|
4505
5641
|
if (child?.workspace) {
|
|
4506
|
-
err("workspace-inherit-conflict", `"${
|
|
5642
|
+
err("workspace-inherit-conflict", `"${id2}": workspace:'inherit' on "${node.workflowId}", which declares its own workspace`, `${path}.workspace`, id2);
|
|
4507
5643
|
}
|
|
4508
5644
|
}
|
|
4509
5645
|
}, "checkWorkspace");
|
|
@@ -4512,20 +5648,20 @@ function validateLuaExtensions(g, caps = WORKFLOW_CAPS_DEFAULT, opts = {
|
|
|
4512
5648
|
const schema = node.type === "step" ? node.step.outputSchema : node.type === "agent" ? node.outputSchema : void 0;
|
|
4513
5649
|
if (schema !== void 0) outputSchemas.set(singleId(node), schema);
|
|
4514
5650
|
}, "recordOutputSchema");
|
|
4515
|
-
const checkMapMembers = /* @__PURE__ */ __name4((cfg, basePath,
|
|
5651
|
+
const checkMapMembers = /* @__PURE__ */ __name4((cfg, basePath, id2) => {
|
|
4516
5652
|
for (const m of malformedMapMembers(cfg)) {
|
|
4517
|
-
warn(MAP_MEMBER_MALFORMED_CODE, mapMemberMalformedMessage(
|
|
5653
|
+
warn(MAP_MEMBER_MALFORMED_CODE, mapMemberMalformedMessage(id2, m), `${basePath}.${m.member}`, id2);
|
|
4518
5654
|
}
|
|
4519
5655
|
}, "checkMapMembers");
|
|
4520
5656
|
const checkInputShape = /* @__PURE__ */ __name4((node, path) => {
|
|
4521
5657
|
const input = node.input;
|
|
4522
5658
|
if (input === void 0) return;
|
|
4523
|
-
const
|
|
5659
|
+
const id2 = singleId(node);
|
|
4524
5660
|
if (input !== null && typeof input === "object" && !Array.isArray(input)) {
|
|
4525
|
-
checkMapMembers(input, `${path}.input`,
|
|
5661
|
+
checkMapMembers(input, `${path}.input`, id2);
|
|
4526
5662
|
return;
|
|
4527
5663
|
}
|
|
4528
|
-
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)})`, `${path}.input`,
|
|
5664
|
+
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)})`, `${path}.input`, id2);
|
|
4529
5665
|
}, "checkInputShape");
|
|
4530
5666
|
const checkBodyInput = /* @__PURE__ */ __name4((body, path, container) => {
|
|
4531
5667
|
if (body.type === "workflow" || body.input === void 0) return;
|
|
@@ -4816,7 +5952,7 @@ function validateLuaExtensions(g, caps = WORKFLOW_CAPS_DEFAULT, opts = {
|
|
|
4816
5952
|
default:
|
|
4817
5953
|
err("invalid-envelope", `unknown entry type "${entry.type}"`, path);
|
|
4818
5954
|
}
|
|
4819
|
-
for (const
|
|
5955
|
+
for (const id2 of declared) upstream.add(id2);
|
|
4820
5956
|
});
|
|
4821
5957
|
if (nodeCount > caps.maxNodes) {
|
|
4822
5958
|
err("cap-exceeded", `${nodeCount} nodes exceeds the static cap of ${caps.maxNodes}`, "definition.graph");
|
|
@@ -4941,19 +6077,19 @@ var containerIdOf = /* @__PURE__ */ __name4((type, entryIndex) => `${type}@${ent
|
|
|
4941
6077
|
function compilePlan(g) {
|
|
4942
6078
|
const steps = {};
|
|
4943
6079
|
const order = [];
|
|
4944
|
-
const addNode = /* @__PURE__ */ __name4((
|
|
4945
|
-
if (
|
|
4946
|
-
throw new WorkflowPlanError("duplicate-step-id", `Duplicate step id "${
|
|
6080
|
+
const addNode = /* @__PURE__ */ __name4((id2, node) => {
|
|
6081
|
+
if (id2 in steps) {
|
|
6082
|
+
throw new WorkflowPlanError("duplicate-step-id", `Duplicate step id "${id2}" in definition.graph`);
|
|
4947
6083
|
}
|
|
4948
|
-
steps[
|
|
4949
|
-
order.push(
|
|
6084
|
+
steps[id2] = node;
|
|
6085
|
+
order.push(id2);
|
|
4950
6086
|
}, "addNode");
|
|
4951
6087
|
let prevTails = [];
|
|
4952
6088
|
const foreachJoinToEntry = /* @__PURE__ */ new Map();
|
|
4953
6089
|
g.definition.graph.forEach((entry, entryIndex) => {
|
|
4954
6090
|
if (isArmStep(entry)) {
|
|
4955
|
-
const
|
|
4956
|
-
addNode(
|
|
6091
|
+
const id2 = armStepId(entry);
|
|
6092
|
+
addNode(id2, {
|
|
4957
6093
|
kind: armStepKind(entry),
|
|
4958
6094
|
dependsOn: prevTails,
|
|
4959
6095
|
downstream: [],
|
|
@@ -4961,7 +6097,7 @@ function compilePlan(g) {
|
|
|
4961
6097
|
entry
|
|
4962
6098
|
});
|
|
4963
6099
|
prevTails = [
|
|
4964
|
-
|
|
6100
|
+
id2
|
|
4965
6101
|
];
|
|
4966
6102
|
return;
|
|
4967
6103
|
}
|
|
@@ -5100,10 +6236,10 @@ function compilePlan(g) {
|
|
|
5100
6236
|
throw new WorkflowPlanError("unknown-entry-type", `Unknown graph entry type "${entry.type}" at definition.graph[${entryIndex}]`);
|
|
5101
6237
|
}
|
|
5102
6238
|
});
|
|
5103
|
-
for (const
|
|
5104
|
-
for (const dep of steps[
|
|
6239
|
+
for (const id2 of order) {
|
|
6240
|
+
for (const dep of steps[id2].dependsOn) {
|
|
5105
6241
|
const target = steps[dep] ?? (foreachJoinToEntry.has(dep) ? steps[foreachJoinToEntry.get(dep)] : void 0);
|
|
5106
|
-
target?.downstream.push(
|
|
6242
|
+
target?.downstream.push(id2);
|
|
5107
6243
|
}
|
|
5108
6244
|
}
|
|
5109
6245
|
return {
|
|
@@ -5292,17 +6428,17 @@ __name(renderRef, "renderRef");
|
|
|
5292
6428
|
__name4(renderRef, "renderRef");
|
|
5293
6429
|
var stepIdOf = /* @__PURE__ */ __name4((s) => typeof s === "string" ? s : s.id, "stepIdOf");
|
|
5294
6430
|
function step(s) {
|
|
5295
|
-
const
|
|
6431
|
+
const id2 = stepIdOf(s);
|
|
5296
6432
|
return {
|
|
5297
6433
|
path: /* @__PURE__ */ __name4((p) => ({
|
|
5298
|
-
path: p === "" ? `stepResults.${
|
|
6434
|
+
path: p === "" ? `stepResults.${id2}` : `stepResults.${id2}.${p}`
|
|
5299
6435
|
}), "path")
|
|
5300
6436
|
};
|
|
5301
6437
|
}
|
|
5302
6438
|
__name(step, "step");
|
|
5303
6439
|
__name4(step, "step");
|
|
5304
|
-
function stepOf(
|
|
5305
|
-
return step(
|
|
6440
|
+
function stepOf(id2) {
|
|
6441
|
+
return step(id2);
|
|
5306
6442
|
}
|
|
5307
6443
|
__name(stepOf, "stepOf");
|
|
5308
6444
|
__name4(stepOf, "stepOf");
|
|
@@ -5508,18 +6644,18 @@ function resolvePlacements(calls) {
|
|
|
5508
6644
|
const declared = /* @__PURE__ */ new Map();
|
|
5509
6645
|
const placedBy = /* @__PURE__ */ new Map();
|
|
5510
6646
|
const allIds = /* @__PURE__ */ new Map();
|
|
5511
|
-
const claimId = /* @__PURE__ */ __name4((
|
|
5512
|
-
const first = allIds.get(
|
|
6647
|
+
const claimId = /* @__PURE__ */ __name4((id2, callIndex) => {
|
|
6648
|
+
const first = allIds.get(id2);
|
|
5513
6649
|
if (first !== void 0 && first !== callIndex) {
|
|
5514
6650
|
issues.push({
|
|
5515
6651
|
code: "duplicate-step-id",
|
|
5516
|
-
message: `step id "${
|
|
6652
|
+
message: `step id "${id2}" is declared more than once (calls #${first} and #${callIndex})`,
|
|
5517
6653
|
callIndex,
|
|
5518
|
-
stepId:
|
|
6654
|
+
stepId: id2
|
|
5519
6655
|
});
|
|
5520
6656
|
return;
|
|
5521
6657
|
}
|
|
5522
|
-
allIds.set(
|
|
6658
|
+
allIds.set(id2, callIndex);
|
|
5523
6659
|
}, "claimId");
|
|
5524
6660
|
calls.forEach((call, i) => {
|
|
5525
6661
|
switch (call.kind) {
|
|
@@ -5531,7 +6667,7 @@ function resolvePlacements(calls) {
|
|
|
5531
6667
|
});
|
|
5532
6668
|
break;
|
|
5533
6669
|
case "entry":
|
|
5534
|
-
for (const
|
|
6670
|
+
for (const id2 of entryIds(call.entry)) claimId(id2, i);
|
|
5535
6671
|
break;
|
|
5536
6672
|
case "parallel":
|
|
5537
6673
|
for (const arm of call.arms) if ("node" in arm) claimId(nodeIdOf(arm.node), i);
|
|
@@ -5550,42 +6686,42 @@ function resolvePlacements(calls) {
|
|
|
5550
6686
|
});
|
|
5551
6687
|
const armMapPlacementIssue = /* @__PURE__ */ __name4((node, ref, i, container) => {
|
|
5552
6688
|
if (!ref.armMap || node.type === "mapping" || isHitlNode2(node)) return void 0;
|
|
5553
|
-
const
|
|
6689
|
+
const id2 = nodeIdOf(node);
|
|
5554
6690
|
if ((container === "foreach" || container === "loop") && node.type !== "workflow") {
|
|
5555
6691
|
return {
|
|
5556
6692
|
code: "mapping-placement",
|
|
5557
|
-
message: container === "foreach" ? `foreach body "${
|
|
6693
|
+
message: container === "foreach" ? `foreach body "${id2}": 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 "${id2}": a [map, step] body is not supported \u2014 the body receives the previous output as its input; put the .map() before the loop instead`,
|
|
5558
6694
|
callIndex: i,
|
|
5559
|
-
stepId:
|
|
6695
|
+
stepId: id2
|
|
5560
6696
|
};
|
|
5561
6697
|
}
|
|
5562
6698
|
if (node.input !== void 0) {
|
|
5563
6699
|
return {
|
|
5564
6700
|
code: "mapping-placement",
|
|
5565
|
-
message: `"${
|
|
6701
|
+
message: `"${id2}": 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)`,
|
|
5566
6702
|
callIndex: i,
|
|
5567
|
-
stepId:
|
|
6703
|
+
stepId: id2
|
|
5568
6704
|
};
|
|
5569
6705
|
}
|
|
5570
6706
|
return void 0;
|
|
5571
6707
|
}, "armMapPlacementIssue");
|
|
5572
6708
|
const hitlPlacementIssue = /* @__PURE__ */ __name4((node, ref, i, container) => {
|
|
5573
6709
|
if (!isHitlNode2(node)) return void 0;
|
|
5574
|
-
const
|
|
6710
|
+
const id2 = node.id;
|
|
5575
6711
|
if (ref.armMap) {
|
|
5576
6712
|
return {
|
|
5577
6713
|
code: "node-type-unsupported-in-container",
|
|
5578
|
-
message: workflowHitlArmShapeMessage(node.type,
|
|
6714
|
+
message: workflowHitlArmShapeMessage(node.type, id2, "mapped-arm"),
|
|
5579
6715
|
callIndex: i,
|
|
5580
|
-
stepId:
|
|
6716
|
+
stepId: id2
|
|
5581
6717
|
};
|
|
5582
6718
|
}
|
|
5583
6719
|
if (container !== "place" && !workflowContainerRunsHitlArm(container)) {
|
|
5584
6720
|
return {
|
|
5585
6721
|
code: "node-type-unsupported-in-container",
|
|
5586
|
-
message: workflowHitlArmUnsupportedMessage(node.type,
|
|
6722
|
+
message: workflowHitlArmUnsupportedMessage(node.type, id2, container),
|
|
5587
6723
|
callIndex: i,
|
|
5588
|
-
stepId:
|
|
6724
|
+
stepId: id2
|
|
5589
6725
|
};
|
|
5590
6726
|
}
|
|
5591
6727
|
return void 0;
|
|
@@ -5691,8 +6827,8 @@ function resolvePlacements(calls) {
|
|
|
5691
6827
|
graph.push(call.entry);
|
|
5692
6828
|
return;
|
|
5693
6829
|
case "declare": {
|
|
5694
|
-
const
|
|
5695
|
-
if (placedBy.has(
|
|
6830
|
+
const id2 = nodeIdOf(call.node);
|
|
6831
|
+
if (placedBy.has(id2)) return;
|
|
5696
6832
|
graph.push(call.node);
|
|
5697
6833
|
return;
|
|
5698
6834
|
}
|
|
@@ -5843,14 +6979,14 @@ function seedLedgerFromRun(run, steps, targetPlan, opts = {}) {
|
|
|
5843
6979
|
const seeded = [];
|
|
5844
6980
|
const unseeded = [];
|
|
5845
6981
|
const known = new Set(Object.keys(targetPlan.steps));
|
|
5846
|
-
const parentOf = /* @__PURE__ */ __name4((
|
|
5847
|
-
const m = /^(.*)(\[\d+\]|#\d+)$/.exec(
|
|
6982
|
+
const parentOf = /* @__PURE__ */ __name4((id2) => {
|
|
6983
|
+
const m = /^(.*)(\[\d+\]|#\d+)$/.exec(id2);
|
|
5848
6984
|
return m ? m[1] : void 0;
|
|
5849
6985
|
}, "parentOf");
|
|
5850
|
-
const dependsOf = /* @__PURE__ */ __name4((
|
|
5851
|
-
const node = targetPlan.steps[
|
|
6986
|
+
const dependsOf = /* @__PURE__ */ __name4((id2) => {
|
|
6987
|
+
const node = targetPlan.steps[id2];
|
|
5852
6988
|
if (node) return node.dependsOn;
|
|
5853
|
-
const parent = parentOf(
|
|
6989
|
+
const parent = parentOf(id2);
|
|
5854
6990
|
return parent && targetPlan.steps[parent] ? [
|
|
5855
6991
|
parent
|
|
5856
6992
|
] : [];
|
|
@@ -5863,23 +6999,23 @@ function seedLedgerFromRun(run, steps, targetPlan, opts = {}) {
|
|
|
5863
6999
|
walk2.push(s.stepId);
|
|
5864
7000
|
}
|
|
5865
7001
|
}
|
|
5866
|
-
for (const
|
|
5867
|
-
const row = byId.get(
|
|
7002
|
+
for (const id2 of walk2) {
|
|
7003
|
+
const row = byId.get(id2);
|
|
5868
7004
|
if (!row || row.status !== "completed") continue;
|
|
5869
|
-
if (!dependsOf(
|
|
5870
|
-
unseeded.push(
|
|
7005
|
+
if (!dependsOf(id2).every((d) => seededIds.has(d))) {
|
|
7006
|
+
unseeded.push(id2);
|
|
5871
7007
|
continue;
|
|
5872
7008
|
}
|
|
5873
|
-
seededIds.add(
|
|
7009
|
+
seededIds.add(id2);
|
|
5874
7010
|
seeded.push({
|
|
5875
|
-
stepId:
|
|
7011
|
+
stepId: id2,
|
|
5876
7012
|
output: row.output,
|
|
5877
7013
|
attempt: row.attempt ?? 1,
|
|
5878
7014
|
effects: row.effects ?? {}
|
|
5879
7015
|
});
|
|
5880
7016
|
}
|
|
5881
7017
|
const dropped = steps.filter((s) => s.status === "completed" && !known.has(s.stepId) && !(parentOf(s.stepId) && known.has(parentOf(s.stepId)))).map((s) => s.stepId);
|
|
5882
|
-
const firstPending = targetPlan.order.find((
|
|
7018
|
+
const firstPending = targetPlan.order.find((id2) => !seededIds.has(id2));
|
|
5883
7019
|
const graphChanged = !!(opts.targetGraphHash && run.graphHash && opts.targetGraphHash !== run.graphHash);
|
|
5884
7020
|
return {
|
|
5885
7021
|
sourceRunId: run.id,
|
|
@@ -5952,37 +7088,37 @@ function replayLedger(g, ledger) {
|
|
|
5952
7088
|
startedAt: 0,
|
|
5953
7089
|
...ledger.requestContext
|
|
5954
7090
|
};
|
|
5955
|
-
const ctxFor = /* @__PURE__ */ __name4((
|
|
7091
|
+
const ctxFor = /* @__PURE__ */ __name4((id2) => ({
|
|
5956
7092
|
initData: ledger.initData,
|
|
5957
|
-
stepResults: ancestorResults(plan,
|
|
7093
|
+
stepResults: ancestorResults(plan, id2, rows22),
|
|
5958
7094
|
state: ledger.state ?? {},
|
|
5959
7095
|
requestContext
|
|
5960
7096
|
}), "ctxFor");
|
|
5961
7097
|
const verdicts = [];
|
|
5962
|
-
for (const
|
|
5963
|
-
const node = plan.steps[
|
|
5964
|
-
const recorded = rows22.get(
|
|
7098
|
+
for (const id2 of plan.order) {
|
|
7099
|
+
const node = plan.steps[id2];
|
|
7100
|
+
const recorded = rows22.get(id2);
|
|
5965
7101
|
if (!recorded || recorded.status === "pending" || recorded.status === "skipped") continue;
|
|
5966
7102
|
if (node.kind === "branch") {
|
|
5967
7103
|
const entry = node.entry;
|
|
5968
|
-
const taken = selectBranchArms(branchSpecFromConditional(entry), ctxFor(
|
|
7104
|
+
const taken = selectBranchArms(branchSpecFromConditional(entry), ctxFor(id2));
|
|
5969
7105
|
const recordedTaken = recorded.taken ?? inferTaken(entry, rows22);
|
|
5970
7106
|
verdicts.push({
|
|
5971
|
-
stepId:
|
|
7107
|
+
stepId: id2,
|
|
5972
7108
|
kind: "branch",
|
|
5973
7109
|
recorded: recordedTaken,
|
|
5974
7110
|
local: taken,
|
|
5975
7111
|
diverged: canonical(recordedTaken) !== canonical(taken)
|
|
5976
7112
|
});
|
|
5977
|
-
} else if (node.kind === "map" && !
|
|
7113
|
+
} else if (node.kind === "map" && !id2.endsWith(".join") && recorded.status === "completed") {
|
|
5978
7114
|
const entry = node.entry;
|
|
5979
|
-
const resolved = resolveMapping(parseMapConfig(entry.mapConfig,
|
|
7115
|
+
const resolved = resolveMapping(parseMapConfig(entry.mapConfig, id2), ctxFor(id2));
|
|
5980
7116
|
const local = "error" in resolved ? {
|
|
5981
7117
|
error: resolved.error,
|
|
5982
7118
|
key: resolved.key
|
|
5983
7119
|
} : resolved.value;
|
|
5984
7120
|
verdicts.push({
|
|
5985
|
-
stepId:
|
|
7121
|
+
stepId: id2,
|
|
5986
7122
|
kind: "map",
|
|
5987
7123
|
recorded: recorded.output,
|
|
5988
7124
|
local,
|
|
@@ -5991,11 +7127,11 @@ function replayLedger(g, ledger) {
|
|
|
5991
7127
|
} else if (node.kind === "foreach") {
|
|
5992
7128
|
const entry = node.entry;
|
|
5993
7129
|
const source = node.dependsOn[0];
|
|
5994
|
-
const items = source ? ctxFor(
|
|
7130
|
+
const items = source ? ctxFor(id2).stepResults[source] : void 0;
|
|
5995
7131
|
const local = Array.isArray(items) ? items.length : void 0;
|
|
5996
7132
|
const recordedCount = recorded.itemCount ?? countChildren(entry, rows22);
|
|
5997
7133
|
verdicts.push({
|
|
5998
|
-
stepId:
|
|
7134
|
+
stepId: id2,
|
|
5999
7135
|
kind: "foreach",
|
|
6000
7136
|
recorded: recordedCount,
|
|
6001
7137
|
local,
|
|
@@ -6004,7 +7140,7 @@ function replayLedger(g, ledger) {
|
|
|
6004
7140
|
} else if (node.kind === "subrun" && recorded.status === "completed" && recorded.child) {
|
|
6005
7141
|
const local = subrunSettledOutput(recorded.child);
|
|
6006
7142
|
verdicts.push({
|
|
6007
|
-
stepId:
|
|
7143
|
+
stepId: id2,
|
|
6008
7144
|
kind: "subrun",
|
|
6009
7145
|
recorded: recorded.output,
|
|
6010
7146
|
local,
|
|
@@ -6020,7 +7156,7 @@ function replayLedger(g, ledger) {
|
|
|
6020
7156
|
__name(replayLedger, "replayLedger");
|
|
6021
7157
|
__name4(replayLedger, "replayLedger");
|
|
6022
7158
|
var JOIN = ".join";
|
|
6023
|
-
var entryOfJoin = /* @__PURE__ */ __name4((
|
|
7159
|
+
var entryOfJoin = /* @__PURE__ */ __name4((id2) => id2.endsWith(JOIN) ? id2.slice(0, -JOIN.length) : void 0, "entryOfJoin");
|
|
6024
7160
|
function replayResultOf(row, node) {
|
|
6025
7161
|
if (!row) return void 0;
|
|
6026
7162
|
if (row.status === "completed") return {
|
|
@@ -6036,7 +7172,7 @@ function replayResultOf(row, node) {
|
|
|
6036
7172
|
}
|
|
6037
7173
|
__name(replayResultOf, "replayResultOf");
|
|
6038
7174
|
__name4(replayResultOf, "replayResultOf");
|
|
6039
|
-
function ancestorResults(plan,
|
|
7175
|
+
function ancestorResults(plan, id2, rows22) {
|
|
6040
7176
|
const out = {};
|
|
6041
7177
|
const joinAliased = /* @__PURE__ */ new Set();
|
|
6042
7178
|
const seen = /* @__PURE__ */ new Set();
|
|
@@ -6085,7 +7221,7 @@ function ancestorResults(plan, id, rows22) {
|
|
|
6085
7221
|
walk2(node.dependsOn);
|
|
6086
7222
|
}
|
|
6087
7223
|
}, "walk");
|
|
6088
|
-
walk2(plan.steps[
|
|
7224
|
+
walk2(plan.steps[id2]?.dependsOn ?? []);
|
|
6089
7225
|
return out;
|
|
6090
7226
|
}
|
|
6091
7227
|
__name(ancestorResults, "ancestorResults");
|
|
@@ -6097,8 +7233,8 @@ function inferTaken(entry, rows22) {
|
|
|
6097
7233
|
entry.otherwise
|
|
6098
7234
|
] : []
|
|
6099
7235
|
];
|
|
6100
|
-
return arms.map(branchArmId).filter((
|
|
6101
|
-
const r = rows22.get(
|
|
7236
|
+
return arms.map(branchArmId).filter((id2) => {
|
|
7237
|
+
const r = rows22.get(id2);
|
|
6102
7238
|
return r !== void 0 && r.status !== "skipped" && r.status !== "pending";
|
|
6103
7239
|
});
|
|
6104
7240
|
}
|
|
@@ -6107,7 +7243,7 @@ __name4(inferTaken, "inferTaken");
|
|
|
6107
7243
|
function countChildren(entry, rows22) {
|
|
6108
7244
|
const body = branchArmId(entry.step);
|
|
6109
7245
|
let n2 = 0;
|
|
6110
|
-
for (const
|
|
7246
|
+
for (const id2 of rows22.keys()) if (id2.startsWith(`${body}[`)) n2 += 1;
|
|
6111
7247
|
return n2;
|
|
6112
7248
|
}
|
|
6113
7249
|
__name(countChildren, "countChildren");
|
|
@@ -7553,8 +8689,8 @@ function step2(s) {
|
|
|
7553
8689
|
return step(typeof s === "string" ? s : s.id);
|
|
7554
8690
|
}
|
|
7555
8691
|
__name(step2, "step");
|
|
7556
|
-
function stepOf2(
|
|
7557
|
-
return stepOf(
|
|
8692
|
+
function stepOf2(id2) {
|
|
8693
|
+
return stepOf(id2);
|
|
7558
8694
|
}
|
|
7559
8695
|
__name(stepOf2, "stepOf");
|
|
7560
8696
|
var init2 = init;
|
|
@@ -7645,16 +8781,16 @@ var assertPredicate = /* @__PURE__ */ __name((p, where) => {
|
|
|
7645
8781
|
if (!isPredicate(p)) throw new LuaWorkflowBuildError("closure-predicate", `${where}: not a LuaPredicate`, "build predicates with eq/gt/inSet/exists/and/or/not");
|
|
7646
8782
|
return p;
|
|
7647
8783
|
}, "assertPredicate");
|
|
7648
|
-
var assertRetry = /* @__PURE__ */ __name((r,
|
|
8784
|
+
var assertRetry = /* @__PURE__ */ __name((r, id2) => {
|
|
7649
8785
|
if (!r) return;
|
|
7650
8786
|
if (!isWithinWorkflowRetryAttempts(r.maxAttempts)) {
|
|
7651
8787
|
const over = typeof r.maxAttempts === "number" && r.maxAttempts > WORKFLOW_RETRY_MAX_ATTEMPTS;
|
|
7652
|
-
throw new LuaWorkflowBuildError(over ? "cap-exceeded" : "invalid-envelope", `"${
|
|
8788
|
+
throw new LuaWorkflowBuildError(over ? "cap-exceeded" : "invalid-envelope", `"${id2}": ${workflowRetryMaxAttemptsMessage(r.maxAttempts)}`);
|
|
7653
8789
|
}
|
|
7654
|
-
if (r.backoff !== void 0 && !WORKFLOW_RETRY_BACKOFFS.includes(r.backoff)) throw new LuaWorkflowBuildError("backoff-invalid", `"${
|
|
8790
|
+
if (r.backoff !== void 0 && !WORKFLOW_RETRY_BACKOFFS.includes(r.backoff)) throw new LuaWorkflowBuildError("backoff-invalid", `"${id2}": retry.backoff must be ${WORKFLOW_RETRY_BACKOFFS.map((b) => `'${b}'`).join(" | ")}`);
|
|
7655
8791
|
if (r.maxBackoffSeconds !== void 0) {
|
|
7656
|
-
if (r.backoff !== "exponential") throw new LuaWorkflowBuildError("backoff-invalid", `"${
|
|
7657
|
-
if (r.maxBackoffSeconds <= 0 || r.backoffSeconds !== void 0 && r.maxBackoffSeconds < r.backoffSeconds) throw new LuaWorkflowBuildError("backoff-invalid", `"${
|
|
8792
|
+
if (r.backoff !== "exponential") throw new LuaWorkflowBuildError("backoff-invalid", `"${id2}": retry.maxBackoffSeconds is only meaningful with backoff:'exponential'`);
|
|
8793
|
+
if (r.maxBackoffSeconds <= 0 || r.backoffSeconds !== void 0 && r.maxBackoffSeconds < r.backoffSeconds) throw new LuaWorkflowBuildError("backoff-invalid", `"${id2}": retry.maxBackoffSeconds must be > 0 and \u2265 backoffSeconds`);
|
|
7658
8794
|
}
|
|
7659
8795
|
}, "assertRetry");
|
|
7660
8796
|
var assertTimeout = /* @__PURE__ */ __name((node) => {
|
|
@@ -7926,8 +9062,8 @@ var WorkflowBuilderImpl = class WorkflowBuilderImpl2 {
|
|
|
7926
9062
|
ref: arm
|
|
7927
9063
|
};
|
|
7928
9064
|
if (arm && typeof arm === "object" && isHitlEntry(arm)) {
|
|
7929
|
-
const
|
|
7930
|
-
throw new LuaWorkflowBuildError("invalid-step", `${where}: an approval / waitForSignal arm is placed by id \u2014 declare it with .approval(${JSON.stringify(
|
|
9065
|
+
const id2 = arm.id;
|
|
9066
|
+
throw new LuaWorkflowBuildError("invalid-step", `${where}: an approval / waitForSignal arm is placed by id \u2014 declare it with .approval(${JSON.stringify(id2 ?? "id")}, \u2026) / .waitForSignal(\u2026) and pass the id string`);
|
|
7931
9067
|
}
|
|
7932
9068
|
return {
|
|
7933
9069
|
node: this.registerStep(arm, where)
|
|
@@ -8047,14 +9183,14 @@ var WorkflowBuilderImpl = class WorkflowBuilderImpl2 {
|
|
|
8047
9183
|
assertNoClosure(mapping, "map()");
|
|
8048
9184
|
this.recordEnvRefs(mapping);
|
|
8049
9185
|
this.mapCount += 1;
|
|
8050
|
-
let
|
|
8051
|
-
if (
|
|
9186
|
+
let id2 = opts?.id;
|
|
9187
|
+
if (id2 === void 0) {
|
|
8052
9188
|
this.unnamedMaps += 1;
|
|
8053
|
-
|
|
9189
|
+
id2 = `map_${this.mapCount}`;
|
|
8054
9190
|
}
|
|
8055
9191
|
const node = {
|
|
8056
9192
|
type: "mapping",
|
|
8057
|
-
id,
|
|
9193
|
+
id: id2,
|
|
8058
9194
|
mapConfig: canonicalJson(mapping)
|
|
8059
9195
|
};
|
|
8060
9196
|
return this.push({
|
|
@@ -8065,12 +9201,12 @@ var WorkflowBuilderImpl = class WorkflowBuilderImpl2 {
|
|
|
8065
9201
|
sleep(ms, opts) {
|
|
8066
9202
|
if (typeof ms !== "number" || !Number.isFinite(ms) || ms < 0) throw new LuaWorkflowBuildError("invalid-envelope", "sleep(ms) takes a literal non-negative number");
|
|
8067
9203
|
this.sleepCount += 1;
|
|
8068
|
-
const
|
|
9204
|
+
const id2 = opts?.id ?? `sleep_${this.sleepCount}`;
|
|
8069
9205
|
return this.push({
|
|
8070
9206
|
kind: "entry",
|
|
8071
9207
|
entry: defined({
|
|
8072
9208
|
type: "sleep",
|
|
8073
|
-
id,
|
|
9209
|
+
id: id2,
|
|
8074
9210
|
duration: ms,
|
|
8075
9211
|
businessHours: opts?.businessHours
|
|
8076
9212
|
})
|
|
@@ -8078,13 +9214,13 @@ var WorkflowBuilderImpl = class WorkflowBuilderImpl2 {
|
|
|
8078
9214
|
}
|
|
8079
9215
|
sleepUntil(iso, opts) {
|
|
8080
9216
|
this.sleepCount += 1;
|
|
8081
|
-
const
|
|
9217
|
+
const id2 = opts?.id ?? `sleep_${this.sleepCount}`;
|
|
8082
9218
|
if (typeof iso === "string") {
|
|
8083
9219
|
return this.push({
|
|
8084
9220
|
kind: "entry",
|
|
8085
9221
|
entry: defined({
|
|
8086
9222
|
type: "sleepUntil",
|
|
8087
|
-
id,
|
|
9223
|
+
id: id2,
|
|
8088
9224
|
date: iso,
|
|
8089
9225
|
businessHours: opts?.businessHours,
|
|
8090
9226
|
round: opts?.round
|
|
@@ -8097,7 +9233,7 @@ var WorkflowBuilderImpl = class WorkflowBuilderImpl2 {
|
|
|
8097
9233
|
kind: "entry",
|
|
8098
9234
|
entry: {
|
|
8099
9235
|
type: "mapping",
|
|
8100
|
-
id: `${
|
|
9236
|
+
id: `${id2}_at`,
|
|
8101
9237
|
mapConfig: canonicalJson({
|
|
8102
9238
|
date: {
|
|
8103
9239
|
template: iso.template
|
|
@@ -8109,9 +9245,9 @@ var WorkflowBuilderImpl = class WorkflowBuilderImpl2 {
|
|
|
8109
9245
|
kind: "entry",
|
|
8110
9246
|
entry: defined({
|
|
8111
9247
|
type: "sleepUntil",
|
|
8112
|
-
id,
|
|
9248
|
+
id: id2,
|
|
8113
9249
|
dateFrom: {
|
|
8114
|
-
step: `${
|
|
9250
|
+
step: `${id2}_at`,
|
|
8115
9251
|
path: "date"
|
|
8116
9252
|
},
|
|
8117
9253
|
businessHours: opts?.businessHours,
|
|
@@ -8119,35 +9255,35 @@ var WorkflowBuilderImpl = class WorkflowBuilderImpl2 {
|
|
|
8119
9255
|
})
|
|
8120
9256
|
});
|
|
8121
9257
|
}
|
|
8122
|
-
agentStep(
|
|
8123
|
-
this.assertId(
|
|
9258
|
+
agentStep(id2, opts) {
|
|
9259
|
+
this.assertId(id2, "agentStep()");
|
|
8124
9260
|
if (!opts || typeof opts.agentId !== "string" && !(opts.agentId && typeof opts.agentId === "object" && "__envRef" in opts.agentId)) {
|
|
8125
|
-
throw new LuaWorkflowBuildError("invalid-envelope", `agentStep("${
|
|
9261
|
+
throw new LuaWorkflowBuildError("invalid-envelope", `agentStep("${id2}") needs an agentId`);
|
|
8126
9262
|
}
|
|
8127
9263
|
const tier = opts.tier ?? (opts.workspace ? "job" : void 0);
|
|
8128
|
-
if (opts.workspace && opts.tier !== void 0 && opts.tier !== "job") throw new LuaWorkflowBuildError("workspace-requires-job-tier", `"${
|
|
8129
|
-
if (opts.harness !== void 0 && tier !== "job") throw new LuaWorkflowBuildError("harness-requires-job-tier", `"${
|
|
8130
|
-
if (opts.toolScope?.jobTools && tier !== "job") throw new LuaWorkflowBuildError("cap-exceeded", `"${
|
|
9264
|
+
if (opts.workspace && opts.tier !== void 0 && opts.tier !== "job") throw new LuaWorkflowBuildError("workspace-requires-job-tier", `"${id2}": a step mounting a workspace must be tier:'job'`);
|
|
9265
|
+
if (opts.harness !== void 0 && tier !== "job") throw new LuaWorkflowBuildError("harness-requires-job-tier", `"${id2}": harness is only legal on a tier:'job' agent step`);
|
|
9266
|
+
if (opts.toolScope?.jobTools && tier !== "job") throw new LuaWorkflowBuildError("cap-exceeded", `"${id2}": toolScope.jobTools require tier:'job' (job-tools-require-job-tier)`);
|
|
8131
9267
|
for (const m of WORKFLOW_JOB_RANGE_MEMBERS) {
|
|
8132
9268
|
if (opts[m] === void 0) continue;
|
|
8133
|
-
if (tier !== "job") throw new LuaWorkflowBuildError("max-turns-requires-job-tier", `"${
|
|
9269
|
+
if (tier !== "job") throw new LuaWorkflowBuildError("max-turns-requires-job-tier", `"${id2}": ${m} is only legal on a tier:'job' agent step`);
|
|
8134
9270
|
if (!isWithinWorkflowJobRange(m, opts[m])) {
|
|
8135
9271
|
const { min, max } = WORKFLOW_JOB_RANGES[m];
|
|
8136
|
-
throw new LuaWorkflowBuildError("max-turns-invalid", `"${
|
|
9272
|
+
throw new LuaWorkflowBuildError("max-turns-invalid", `"${id2}": ${m} must be an integer ${min}..${max}`);
|
|
8137
9273
|
}
|
|
8138
9274
|
}
|
|
8139
9275
|
assertTimeout({
|
|
8140
|
-
id,
|
|
9276
|
+
id: id2,
|
|
8141
9277
|
timeoutSeconds: opts.timeoutSeconds,
|
|
8142
9278
|
tier,
|
|
8143
9279
|
workspace: opts.workspace,
|
|
8144
9280
|
kind: "agent"
|
|
8145
9281
|
});
|
|
8146
|
-
assertRetry(opts.retry,
|
|
9282
|
+
assertRetry(opts.retry, id2);
|
|
8147
9283
|
this.recordEnvRefs(opts.agentId, opts.prompt);
|
|
8148
9284
|
const node = defined({
|
|
8149
9285
|
type: "agent",
|
|
8150
|
-
id,
|
|
9286
|
+
id: id2,
|
|
8151
9287
|
agentId: opts.agentId,
|
|
8152
9288
|
promptTemplate: templateText(opts.prompt),
|
|
8153
9289
|
outputSchema: schemaToJson(opts.outputSchema),
|
|
@@ -8175,30 +9311,30 @@ var WorkflowBuilderImpl = class WorkflowBuilderImpl2 {
|
|
|
8175
9311
|
node
|
|
8176
9312
|
});
|
|
8177
9313
|
}
|
|
8178
|
-
specialistStep(
|
|
8179
|
-
this.assertId(
|
|
9314
|
+
specialistStep(id2, opts) {
|
|
9315
|
+
this.assertId(id2, "specialistStep()");
|
|
8180
9316
|
const role = opts?.role;
|
|
8181
|
-
if (!role || typeof role !== "object") throw new LuaWorkflowBuildError("invalid-envelope", `specialistStep("${
|
|
9317
|
+
if (!role || typeof role !== "object") throw new LuaWorkflowBuildError("invalid-envelope", `specialistStep("${id2}") needs a role`);
|
|
8182
9318
|
if (role.ref !== void 0 && (role.name !== void 0 || role.instructions !== void 0 || role.tools !== void 0)) {
|
|
8183
|
-
throw new LuaWorkflowBuildError("role-ref-and-inline", `"${
|
|
9319
|
+
throw new LuaWorkflowBuildError("role-ref-and-inline", `"${id2}": role is EITHER { ref } OR the inline { name, instructions, tools } shape`);
|
|
8184
9320
|
}
|
|
8185
9321
|
if (role.ref === void 0) {
|
|
8186
9322
|
if (typeof role.instructions !== "string" || role.instructions.length > WORKFLOW_SPECIALIST_ROLE_MAX_INSTRUCTIONS) {
|
|
8187
|
-
throw new LuaWorkflowBuildError("ephemeral-role-too-long", `"${
|
|
9323
|
+
throw new LuaWorkflowBuildError("ephemeral-role-too-long", `"${id2}": role.instructions must be \u2264 ${WORKFLOW_SPECIALIST_ROLE_MAX_INSTRUCTIONS} chars`);
|
|
8188
9324
|
}
|
|
8189
|
-
if (!Array.isArray(role.tools)) throw new LuaWorkflowBuildError("invalid-envelope", `"${
|
|
8190
|
-
if (role.tools.length > 64) throw new LuaWorkflowBuildError("cap-exceeded", `"${
|
|
9325
|
+
if (!Array.isArray(role.tools)) throw new LuaWorkflowBuildError("invalid-envelope", `"${id2}": role.tools must be an array ([] = no tools)`);
|
|
9326
|
+
if (role.tools.length > 64) throw new LuaWorkflowBuildError("cap-exceeded", `"${id2}": role.tools exceeds 64 entries`);
|
|
8191
9327
|
}
|
|
8192
9328
|
assertTimeout({
|
|
8193
|
-
id,
|
|
9329
|
+
id: id2,
|
|
8194
9330
|
timeoutSeconds: opts.timeoutSeconds,
|
|
8195
9331
|
kind: "agent"
|
|
8196
9332
|
});
|
|
8197
|
-
assertRetry(opts.retry,
|
|
9333
|
+
assertRetry(opts.retry, id2);
|
|
8198
9334
|
this.recordEnvRefs(opts.prompt);
|
|
8199
9335
|
const node = defined({
|
|
8200
9336
|
type: "agent",
|
|
8201
|
-
id,
|
|
9337
|
+
id: id2,
|
|
8202
9338
|
agentId: "$self",
|
|
8203
9339
|
role: role.ref !== void 0 ? {
|
|
8204
9340
|
ref: role.ref
|
|
@@ -8221,20 +9357,20 @@ var WorkflowBuilderImpl = class WorkflowBuilderImpl2 {
|
|
|
8221
9357
|
node
|
|
8222
9358
|
});
|
|
8223
9359
|
}
|
|
8224
|
-
toolStep(
|
|
8225
|
-
this.assertId(
|
|
8226
|
-
if (!tool || typeof tool !== "object" || typeof tool.name !== "string") throw new LuaWorkflowBuildError("invalid-envelope", `toolStep("${
|
|
8227
|
-
assertNoClosure(opts.input, `toolStep("${
|
|
9360
|
+
toolStep(id2, tool, opts = {}) {
|
|
9361
|
+
this.assertId(id2, "toolStep()");
|
|
9362
|
+
if (!tool || typeof tool !== "object" || typeof tool.name !== "string") throw new LuaWorkflowBuildError("invalid-envelope", `toolStep("${id2}") needs a LuaTool`);
|
|
9363
|
+
assertNoClosure(opts.input, `toolStep("${id2}").input`);
|
|
8228
9364
|
this.recordEnvRefs(opts.input);
|
|
8229
9365
|
assertTimeout({
|
|
8230
|
-
id,
|
|
9366
|
+
id: id2,
|
|
8231
9367
|
timeoutSeconds: opts.timeoutSeconds,
|
|
8232
9368
|
kind: "tool"
|
|
8233
9369
|
});
|
|
8234
|
-
assertRetry(opts.retry,
|
|
9370
|
+
assertRetry(opts.retry, id2);
|
|
8235
9371
|
const node = defined({
|
|
8236
9372
|
type: "tool",
|
|
8237
|
-
id,
|
|
9373
|
+
id: id2,
|
|
8238
9374
|
toolId: tool.name,
|
|
8239
9375
|
input: opts.input,
|
|
8240
9376
|
timeoutSeconds: opts.timeoutSeconds,
|
|
@@ -8248,34 +9384,34 @@ var WorkflowBuilderImpl = class WorkflowBuilderImpl2 {
|
|
|
8248
9384
|
node
|
|
8249
9385
|
});
|
|
8250
9386
|
}
|
|
8251
|
-
approval(
|
|
8252
|
-
this.assertId(
|
|
8253
|
-
if (!opts || typeof opts.title !== "string") throw new LuaWorkflowBuildError("invalid-envelope", `approval("${
|
|
9387
|
+
approval(id2, opts) {
|
|
9388
|
+
this.assertId(id2, "approval()");
|
|
9389
|
+
if (!opts || typeof opts.title !== "string") throw new LuaWorkflowBuildError("invalid-envelope", `approval("${id2}") needs a title`);
|
|
8254
9390
|
if (opts.approver === "creator" && opts.excludeInitiator === true) {
|
|
8255
|
-
throw new LuaWorkflowBuildError("approver-excludes-only-candidate", `"${
|
|
9391
|
+
throw new LuaWorkflowBuildError("approver-excludes-only-candidate", `"${id2}": approver:'creator' with excludeInitiator:true always excludes the only candidate`);
|
|
8256
9392
|
}
|
|
8257
9393
|
const editable = approvalEditable(opts);
|
|
8258
|
-
if (opts.fourEyes !== void 0 && !editable) throw new LuaWorkflowBuildError("four-eyes-requires-editable", `"${
|
|
9394
|
+
if (opts.fourEyes !== void 0 && !editable) throw new LuaWorkflowBuildError("four-eyes-requires-editable", `"${id2}": \`fourEyes\` requires editable:true`);
|
|
8259
9395
|
if (opts.editable === false && Array.isArray(opts.editablePaths) && opts.editablePaths.length > 0) {
|
|
8260
|
-
throw new LuaWorkflowBuildError("editable-path-invalid", `"${
|
|
9396
|
+
throw new LuaWorkflowBuildError("editable-path-invalid", `"${id2}": \`editablePaths\` beside editable:false is contradictory \u2014 drop the paths or set editable:true`);
|
|
8261
9397
|
} else if ((opts.editablePaths !== void 0 || opts.editedPayloadSchema !== void 0) && !editable) {
|
|
8262
|
-
throw new LuaWorkflowBuildError("editable-path-invalid", `"${
|
|
9398
|
+
throw new LuaWorkflowBuildError("editable-path-invalid", `"${id2}": \`editablePaths\` / \`editedPayloadSchema\` require editable:true (a non-empty editablePaths implies it)`);
|
|
8263
9399
|
}
|
|
8264
9400
|
for (const p of opts.editablePaths ?? []) {
|
|
8265
|
-
if (!EDITABLE_PATH_RE2.test(p)) throw new LuaWorkflowBuildError("editable-path-invalid", `"${
|
|
9401
|
+
if (!EDITABLE_PATH_RE2.test(p)) throw new LuaWorkflowBuildError("editable-path-invalid", `"${id2}": editablePaths entry "${p}" is outside the grammar seg(.seg)* with [*]/[n] selectors`);
|
|
8266
9402
|
}
|
|
8267
9403
|
if (Array.isArray(opts.onTimeout)) {
|
|
8268
9404
|
const chain = opts.onTimeout;
|
|
8269
9405
|
const hops = chain.filter((h) => typeof h === "object");
|
|
8270
|
-
if (hops.length > 3) throw new LuaWorkflowBuildError("escalation-chain-too-long", `"${
|
|
9406
|
+
if (hops.length > 3) throw new LuaWorkflowBuildError("escalation-chain-too-long", `"${id2}": an onTimeout chain carries at most 3 escalation hops`);
|
|
8271
9407
|
const last = chain[chain.length - 1];
|
|
8272
|
-
if (last === void 0 || typeof last === "object") throw new LuaWorkflowBuildError("escalation-chain-not-terminal", `"${
|
|
9408
|
+
if (last === void 0 || typeof last === "object") throw new LuaWorkflowBuildError("escalation-chain-not-terminal", `"${id2}": an onTimeout chain must end in a terminal member`);
|
|
8273
9409
|
}
|
|
8274
|
-
if (typeof opts.details === "function") throw new LuaWorkflowBuildError("closure-binding", `approval("${
|
|
9410
|
+
if (typeof opts.details === "function") throw new LuaWorkflowBuildError("closure-binding", `approval("${id2}").details must be template(...)`);
|
|
8275
9411
|
this.recordEnvRefs(opts.details, opts.timeoutHours, opts.approver);
|
|
8276
9412
|
const node = defined({
|
|
8277
9413
|
type: "approval",
|
|
8278
|
-
id,
|
|
9414
|
+
id: id2,
|
|
8279
9415
|
title: opts.title,
|
|
8280
9416
|
details: opts.details ? templateText(opts.details) : void 0,
|
|
8281
9417
|
approver: opts.approver,
|
|
@@ -8297,13 +9433,13 @@ var WorkflowBuilderImpl = class WorkflowBuilderImpl2 {
|
|
|
8297
9433
|
node
|
|
8298
9434
|
});
|
|
8299
9435
|
}
|
|
8300
|
-
waitForSignal(
|
|
8301
|
-
this.assertId(
|
|
8302
|
-
if (!opts || typeof opts.signal !== "string" || opts.signal.length === 0) throw new LuaWorkflowBuildError("invalid-envelope", `waitForSignal("${
|
|
9436
|
+
waitForSignal(id2, opts) {
|
|
9437
|
+
this.assertId(id2, "waitForSignal()");
|
|
9438
|
+
if (!opts || typeof opts.signal !== "string" || opts.signal.length === 0) throw new LuaWorkflowBuildError("invalid-envelope", `waitForSignal("${id2}") needs a signal name`);
|
|
8303
9439
|
this.recordEnvRefs(opts.timeoutHours);
|
|
8304
9440
|
const node = defined({
|
|
8305
9441
|
type: "waitForSignal",
|
|
8306
|
-
id,
|
|
9442
|
+
id: id2,
|
|
8307
9443
|
signal: opts.signal,
|
|
8308
9444
|
schema: schemaToJson(opts.schema),
|
|
8309
9445
|
timeoutHours: opts.timeoutHours,
|
|
@@ -8316,28 +9452,28 @@ var WorkflowBuilderImpl = class WorkflowBuilderImpl2 {
|
|
|
8316
9452
|
node
|
|
8317
9453
|
});
|
|
8318
9454
|
}
|
|
8319
|
-
workflow(
|
|
8320
|
-
this.assertId(
|
|
8321
|
-
assertRetry(opts?.retry,
|
|
9455
|
+
workflow(id2, ref, input, opts) {
|
|
9456
|
+
this.assertId(id2, "workflow()");
|
|
9457
|
+
assertRetry(opts?.retry, id2);
|
|
8322
9458
|
const name = typeof ref === "string" ? ref : ref instanceof LuaWorkflow ? ref.getName() : void 0;
|
|
8323
|
-
if (!name) throw new LuaWorkflowBuildError("invalid-envelope", `workflow("${
|
|
9459
|
+
if (!name) throw new LuaWorkflowBuildError("invalid-envelope", `workflow("${id2}") needs a LuaWorkflow or a workflow name`);
|
|
8324
9460
|
if (opts?.workspace === "inherit") {
|
|
8325
|
-
if (!this.config.workspace) throw new LuaWorkflowBuildError("workspace-inherit-without-parent-workspace", `"${
|
|
8326
|
-
if (ref instanceof LuaWorkflow && ref.getConfig().workspace) throw new LuaWorkflowBuildError("workspace-inherit-conflict", `"${
|
|
9461
|
+
if (!this.config.workspace) throw new LuaWorkflowBuildError("workspace-inherit-without-parent-workspace", `"${id2}": workspace:'inherit' but the parent createWorkflow declares no workspace`);
|
|
9462
|
+
if (ref instanceof LuaWorkflow && ref.getConfig().workspace) throw new LuaWorkflowBuildError("workspace-inherit-conflict", `"${id2}": workspace:'inherit' on a workflow that declares its own workspace`);
|
|
8327
9463
|
}
|
|
8328
|
-
assertNoClosure(input, `workflow("${
|
|
9464
|
+
assertNoClosure(input, `workflow("${id2}").input`);
|
|
8329
9465
|
this.recordEnvRefs(input);
|
|
8330
9466
|
this.nestedRefs.push(opts?.workspace === "inherit" ? {
|
|
8331
|
-
id,
|
|
9467
|
+
id: id2,
|
|
8332
9468
|
name,
|
|
8333
9469
|
workspace: "inherit"
|
|
8334
9470
|
} : {
|
|
8335
|
-
id,
|
|
9471
|
+
id: id2,
|
|
8336
9472
|
name
|
|
8337
9473
|
});
|
|
8338
9474
|
const node = defined({
|
|
8339
9475
|
type: "workflow",
|
|
8340
|
-
id,
|
|
9476
|
+
id: id2,
|
|
8341
9477
|
workflowId: name,
|
|
8342
9478
|
input,
|
|
8343
9479
|
workspace: opts?.workspace,
|
|
@@ -8416,8 +9552,8 @@ var WorkflowBuilderImpl = class WorkflowBuilderImpl2 {
|
|
|
8416
9552
|
});
|
|
8417
9553
|
}
|
|
8418
9554
|
}
|
|
8419
|
-
assertId(
|
|
8420
|
-
if (typeof
|
|
9555
|
+
assertId(id2, where) {
|
|
9556
|
+
if (typeof id2 !== "string" || !STEP_ID_RE.test(id2)) throw new LuaWorkflowBuildError("invalid-step-id", `${where}: id "${String(id2)}" must match ${STEP_ID_RE}`);
|
|
8421
9557
|
}
|
|
8422
9558
|
};
|
|
8423
9559
|
var EDITABLE_PATH_RE2 = /^[A-Za-z_][A-Za-z0-9_]*(\[(\*|\d+)\])?(\.[A-Za-z_][A-Za-z0-9_]*(\[(\*|\d+)\])?)*$/;
|