lua-cli 3.38.0 → 3.39.0
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 +82 -0
- package/dist/api-exports.js +917 -3
- package/dist/api-exports.js.map +1 -1
- package/dist/index.js +1726 -129
- package/dist/index.js.map +1 -1
- package/dist/workflow-builder.js +901 -2
- package/dist/workflow-builder.js.map +1 -1
- package/docs/CLI_REFERENCE.md +16 -1
- package/package.json +4 -4
- package/template/package.json +1 -1
package/dist/index.js
CHANGED
|
@@ -1181,6 +1181,155 @@ function foldRichPartsIntoMessages(messages, records, makeMessage, sameTurnGroup
|
|
|
1181
1181
|
while (next < synthetic.length) combined.push(synthetic[next++].message);
|
|
1182
1182
|
return mergeRichPartMirrorMessages(combined, sameTurnGroup);
|
|
1183
1183
|
}
|
|
1184
|
+
function utf8WidthAt(value3, index) {
|
|
1185
|
+
const code = value3.charCodeAt(index);
|
|
1186
|
+
if (code < 128) return {
|
|
1187
|
+
bytes: 1,
|
|
1188
|
+
units: 1
|
|
1189
|
+
};
|
|
1190
|
+
if (code < 2048) return {
|
|
1191
|
+
bytes: 2,
|
|
1192
|
+
units: 1
|
|
1193
|
+
};
|
|
1194
|
+
if (code >= 55296 && code <= 56319) {
|
|
1195
|
+
const next = value3.charCodeAt(index + 1);
|
|
1196
|
+
if (next >= 56320 && next <= 57343) return {
|
|
1197
|
+
bytes: 4,
|
|
1198
|
+
units: 2
|
|
1199
|
+
};
|
|
1200
|
+
}
|
|
1201
|
+
return {
|
|
1202
|
+
bytes: 3,
|
|
1203
|
+
units: 1
|
|
1204
|
+
};
|
|
1205
|
+
}
|
|
1206
|
+
function utf8ByteLength(value3) {
|
|
1207
|
+
let bytes = 0;
|
|
1208
|
+
for (let i = 0; i < value3.length; ) {
|
|
1209
|
+
const width = utf8WidthAt(value3, i);
|
|
1210
|
+
bytes += width.bytes;
|
|
1211
|
+
i += width.units;
|
|
1212
|
+
}
|
|
1213
|
+
return bytes;
|
|
1214
|
+
}
|
|
1215
|
+
function clampUtf8(value3, maxBytes) {
|
|
1216
|
+
let bytes = 0;
|
|
1217
|
+
for (let i = 0; i < value3.length; ) {
|
|
1218
|
+
const width = utf8WidthAt(value3, i);
|
|
1219
|
+
if (bytes + width.bytes > maxBytes) return value3.slice(0, i);
|
|
1220
|
+
bytes += width.bytes;
|
|
1221
|
+
i += width.units;
|
|
1222
|
+
}
|
|
1223
|
+
return value3;
|
|
1224
|
+
}
|
|
1225
|
+
function mapBytes(fields, withMark) {
|
|
1226
|
+
return utf8ByteLength(JSON.stringify(withMark ? {
|
|
1227
|
+
...fields,
|
|
1228
|
+
[LOG_FIELDS_CLAMPED_KEY]: true
|
|
1229
|
+
} : fields));
|
|
1230
|
+
}
|
|
1231
|
+
function withValueCap(fields, capBytes) {
|
|
1232
|
+
const out = {};
|
|
1233
|
+
for (const [key, value3] of Object.entries(fields)) {
|
|
1234
|
+
out[key] = typeof value3 === "string" ? clampUtf8(value3, capBytes) : value3;
|
|
1235
|
+
}
|
|
1236
|
+
return out;
|
|
1237
|
+
}
|
|
1238
|
+
function describeValue(value3) {
|
|
1239
|
+
if (value3 === null) return "null";
|
|
1240
|
+
if (value3 === void 0) return "undefined";
|
|
1241
|
+
if (Array.isArray(value3)) return "an array";
|
|
1242
|
+
return typeof value3 === "object" ? "an object" : `a ${typeof value3}`;
|
|
1243
|
+
}
|
|
1244
|
+
function assertValidLogFieldKey(key) {
|
|
1245
|
+
if (!LOG_FIELD_KEY_PATTERN.test(key)) {
|
|
1246
|
+
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)`);
|
|
1247
|
+
}
|
|
1248
|
+
if (LOG_FIELD_SECRET_SHAPED_KEY_PATTERNS.some((pattern) => pattern.test(key))) {
|
|
1249
|
+
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`);
|
|
1250
|
+
}
|
|
1251
|
+
if (key === LOG_FIELDS_CLAMPED_KEY) {
|
|
1252
|
+
throw new LuaLogFieldsError(`log fields: key \`${key}\` is reserved \u2014 the platform sets it to mark a field map it had to clamp`);
|
|
1253
|
+
}
|
|
1254
|
+
}
|
|
1255
|
+
function normalizeLogFields(fields) {
|
|
1256
|
+
if (fields === void 0 || fields === null) return void 0;
|
|
1257
|
+
if (typeof fields !== "object" || Array.isArray(fields)) {
|
|
1258
|
+
throw new LuaLogFieldsError(`log fields: expected a plain object of fields, received ${describeValue(fields)}`);
|
|
1259
|
+
}
|
|
1260
|
+
const entries = Object.entries(fields);
|
|
1261
|
+
if (entries.length > LOG_FIELDS_MAX_KEYS) {
|
|
1262
|
+
throw new LuaLogFieldsError(`log fields: ${entries.length} keys exceeds the cap of ${LOG_FIELDS_MAX_KEYS} keys per call`);
|
|
1263
|
+
}
|
|
1264
|
+
const out = {};
|
|
1265
|
+
for (const [key, value3] of entries) {
|
|
1266
|
+
assertValidLogFieldKey(key);
|
|
1267
|
+
if (typeof value3 === "string" || typeof value3 === "boolean") {
|
|
1268
|
+
out[key] = value3;
|
|
1269
|
+
continue;
|
|
1270
|
+
}
|
|
1271
|
+
if (typeof value3 === "number") {
|
|
1272
|
+
if (!Number.isFinite(value3)) {
|
|
1273
|
+
throw new LuaLogFieldsError(`log fields: \`${key}\` must be a finite number \u2014 NaN and Infinity have no JSON form`);
|
|
1274
|
+
}
|
|
1275
|
+
out[key] = value3;
|
|
1276
|
+
continue;
|
|
1277
|
+
}
|
|
1278
|
+
if (Array.isArray(value3)) {
|
|
1279
|
+
const parts = [];
|
|
1280
|
+
for (const element of value3) {
|
|
1281
|
+
if (typeof element !== "string") {
|
|
1282
|
+
throw new LuaLogFieldsError(`log fields: \`${key}\` is an array, so every element must be a string (found ${describeValue(element)})`);
|
|
1283
|
+
}
|
|
1284
|
+
if (element.includes(",")) {
|
|
1285
|
+
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`);
|
|
1286
|
+
}
|
|
1287
|
+
parts.push(element);
|
|
1288
|
+
}
|
|
1289
|
+
out[key] = parts.join(",");
|
|
1290
|
+
out[`${key}${LOG_FIELD_ARRAY_COUNT_SUFFIX}`] = parts.length;
|
|
1291
|
+
continue;
|
|
1292
|
+
}
|
|
1293
|
+
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)" : ""));
|
|
1294
|
+
}
|
|
1295
|
+
const keys = Object.keys(out);
|
|
1296
|
+
if (keys.length === 0) return void 0;
|
|
1297
|
+
if (keys.length > LOG_FIELDS_MAX_KEYS) {
|
|
1298
|
+
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`);
|
|
1299
|
+
}
|
|
1300
|
+
if (clampLogFields(out)) out[LOG_FIELDS_CLAMPED_KEY] = true;
|
|
1301
|
+
return out;
|
|
1302
|
+
}
|
|
1303
|
+
function clampLogFields(out) {
|
|
1304
|
+
let clamped = false;
|
|
1305
|
+
for (const [key, value3] of Object.entries(out)) {
|
|
1306
|
+
if (typeof value3 !== "string") continue;
|
|
1307
|
+
const capped = clampUtf8(value3, LOG_FIELD_MAX_VALUE_BYTES);
|
|
1308
|
+
if (capped !== value3) {
|
|
1309
|
+
out[key] = capped;
|
|
1310
|
+
clamped = true;
|
|
1311
|
+
}
|
|
1312
|
+
}
|
|
1313
|
+
if (mapBytes(out, clamped) <= LOG_FIELDS_MAX_BYTES) return clamped;
|
|
1314
|
+
const base = {
|
|
1315
|
+
...out
|
|
1316
|
+
};
|
|
1317
|
+
let low = 0;
|
|
1318
|
+
let high = LOG_FIELD_MAX_VALUE_BYTES;
|
|
1319
|
+
let best = 0;
|
|
1320
|
+
while (low <= high) {
|
|
1321
|
+
const mid = Math.floor((low + high) / 2);
|
|
1322
|
+
if (mapBytes(withValueCap(base, mid), true) <= LOG_FIELDS_MAX_BYTES) {
|
|
1323
|
+
best = mid;
|
|
1324
|
+
low = mid + 1;
|
|
1325
|
+
} else {
|
|
1326
|
+
high = mid - 1;
|
|
1327
|
+
}
|
|
1328
|
+
}
|
|
1329
|
+
const fitted = withValueCap(base, best);
|
|
1330
|
+
for (const key of Object.keys(out)) out[key] = fitted[key];
|
|
1331
|
+
return true;
|
|
1332
|
+
}
|
|
1184
1333
|
function isDesktopFileCommandName(value3) {
|
|
1185
1334
|
return typeof value3 === "string" && DESKTOP_FILE_COMMAND_SET.has(value3);
|
|
1186
1335
|
}
|
|
@@ -1408,6 +1557,81 @@ function buildDefaultPersona(agentName) {
|
|
|
1408
1557
|
function buildPersonalSpaceStartingPersona(agentName) {
|
|
1409
1558
|
return PERSONAL_SPACE_STARTING_PERSONA.replace(new RegExp(AGENT_NAME_TOKEN.replace(/[.*+?^${}()|[\]\\]/g, "\\$&"), "g"), () => agentName || "Your assistant");
|
|
1410
1559
|
}
|
|
1560
|
+
function utf8Bytes(value3) {
|
|
1561
|
+
let bytes = 0;
|
|
1562
|
+
for (let i = 0; i < value3.length; ) {
|
|
1563
|
+
const code = value3.charCodeAt(i);
|
|
1564
|
+
if (code < 128) {
|
|
1565
|
+
bytes += 1;
|
|
1566
|
+
i += 1;
|
|
1567
|
+
} else if (code < 2048) {
|
|
1568
|
+
bytes += 2;
|
|
1569
|
+
i += 1;
|
|
1570
|
+
} else if (code >= 55296 && code <= 56319) {
|
|
1571
|
+
const next = value3.charCodeAt(i + 1);
|
|
1572
|
+
if (next >= 56320 && next <= 57343) {
|
|
1573
|
+
bytes += 4;
|
|
1574
|
+
i += 2;
|
|
1575
|
+
} else {
|
|
1576
|
+
bytes += 3;
|
|
1577
|
+
i += 1;
|
|
1578
|
+
}
|
|
1579
|
+
} else {
|
|
1580
|
+
bytes += 3;
|
|
1581
|
+
i += 1;
|
|
1582
|
+
}
|
|
1583
|
+
}
|
|
1584
|
+
return bytes;
|
|
1585
|
+
}
|
|
1586
|
+
function isPlainFieldKey(key) {
|
|
1587
|
+
if (!LOG_FIELD_KEY_PATTERN.test(key)) return false;
|
|
1588
|
+
return !LOG_FIELD_SECRET_SHAPED_KEY_PATTERNS.some((pattern) => pattern.test(key));
|
|
1589
|
+
}
|
|
1590
|
+
function describeAgentLogFieldsViolation(value3) {
|
|
1591
|
+
if (typeof value3 !== "object" || value3 === null || Array.isArray(value3)) {
|
|
1592
|
+
return "fields must be an object";
|
|
1593
|
+
}
|
|
1594
|
+
const entries = Object.entries(value3);
|
|
1595
|
+
let userKeys = 0;
|
|
1596
|
+
for (const [key, entry] of entries) {
|
|
1597
|
+
if (key === LOG_FIELDS_CLAMPED_KEY) {
|
|
1598
|
+
if (entry !== true) return `fields.${key} must be true`;
|
|
1599
|
+
continue;
|
|
1600
|
+
}
|
|
1601
|
+
userKeys += 1;
|
|
1602
|
+
if (key.endsWith(LOG_FIELD_ARRAY_COUNT_SUFFIX)) {
|
|
1603
|
+
const base = key.slice(0, -LOG_FIELD_ARRAY_COUNT_SUFFIX.length);
|
|
1604
|
+
if (!isPlainFieldKey(base)) return `fields key \`${key}\` is not a legal field key`;
|
|
1605
|
+
if (typeof entry !== "number" || !Number.isFinite(entry)) {
|
|
1606
|
+
return `fields.${key} must be a finite number`;
|
|
1607
|
+
}
|
|
1608
|
+
continue;
|
|
1609
|
+
}
|
|
1610
|
+
if (!isPlainFieldKey(key)) return `fields key \`${key}\` is not a legal field key`;
|
|
1611
|
+
if (typeof entry === "string") {
|
|
1612
|
+
if (utf8Bytes(entry) > LOG_FIELD_MAX_VALUE_BYTES) {
|
|
1613
|
+
return `fields.${key} exceeds ${LOG_FIELD_MAX_VALUE_BYTES} bytes`;
|
|
1614
|
+
}
|
|
1615
|
+
continue;
|
|
1616
|
+
}
|
|
1617
|
+
if (typeof entry === "boolean") continue;
|
|
1618
|
+
if (typeof entry === "number") {
|
|
1619
|
+
if (!Number.isFinite(entry)) return `fields.${key} must be a finite number`;
|
|
1620
|
+
continue;
|
|
1621
|
+
}
|
|
1622
|
+
return `fields.${key} must be a string, number or boolean`;
|
|
1623
|
+
}
|
|
1624
|
+
if (userKeys > LOG_FIELDS_MAX_KEYS) {
|
|
1625
|
+
return `fields has ${userKeys} keys, over the cap of ${LOG_FIELDS_MAX_KEYS}`;
|
|
1626
|
+
}
|
|
1627
|
+
if (utf8Bytes(JSON.stringify(value3)) > LOG_FIELDS_MAX_BYTES) {
|
|
1628
|
+
return `fields exceeds ${LOG_FIELDS_MAX_BYTES} bytes`;
|
|
1629
|
+
}
|
|
1630
|
+
return void 0;
|
|
1631
|
+
}
|
|
1632
|
+
function isAgentLogFields(value3) {
|
|
1633
|
+
return describeAgentLogFieldsViolation(value3) === void 0;
|
|
1634
|
+
}
|
|
1411
1635
|
function maxDrainsForTier(tier) {
|
|
1412
1636
|
return tier === "enterprise" ? LOG_DRAIN_MAX_PER_ORG_ENTERPRISE : LOG_DRAIN_MAX_PER_ORG;
|
|
1413
1637
|
}
|
|
@@ -1416,6 +1640,148 @@ function resolvePresetEndpoint(type, site) {
|
|
|
1416
1640
|
if (!template3 || !site) return void 0;
|
|
1417
1641
|
return template3.replace("{site}", site);
|
|
1418
1642
|
}
|
|
1643
|
+
function isLogDrainBucketHostAllowed(provider, host) {
|
|
1644
|
+
const normalized = host.trim().toLowerCase().replace(/^\[|\]$/g, "");
|
|
1645
|
+
if (!normalized) return false;
|
|
1646
|
+
return (LOG_DRAIN_BUCKET_HOST_PATTERNS[provider] ?? []).some((pattern) => pattern.test(normalized));
|
|
1647
|
+
}
|
|
1648
|
+
function resolveDrainBucketEndpoint(bucket) {
|
|
1649
|
+
if (!LOG_DRAIN_BUCKET_NAME_PATTERN.test(bucket.bucket)) {
|
|
1650
|
+
throw new Error("log drain bucket name is not a valid S3 bucket label");
|
|
1651
|
+
}
|
|
1652
|
+
if (bucket.provider === "aws") {
|
|
1653
|
+
const region = bucket.region.trim().toLowerCase();
|
|
1654
|
+
if (!/^[a-z0-9-]{1,32}$/.test(region)) throw new Error("log drain bucket region is not an AWS region");
|
|
1655
|
+
return `https://${bucket.bucket}.s3.${region}.amazonaws.com`;
|
|
1656
|
+
}
|
|
1657
|
+
if (!bucket.endpoint) throw new Error(`log drain '${bucket.provider}' bucket requires an endpoint`);
|
|
1658
|
+
let url;
|
|
1659
|
+
try {
|
|
1660
|
+
url = new URL(bucket.endpoint);
|
|
1661
|
+
} catch {
|
|
1662
|
+
throw new Error(`log drain '${bucket.provider}' bucket endpoint is not an absolute URL`);
|
|
1663
|
+
}
|
|
1664
|
+
if (url.protocol !== "https:") throw new Error(`log drain '${bucket.provider}' bucket endpoint must be https`);
|
|
1665
|
+
return `https://${url.host}/${bucket.bucket}`;
|
|
1666
|
+
}
|
|
1667
|
+
function drainBucketUsesPathStyle(provider) {
|
|
1668
|
+
return provider !== "aws";
|
|
1669
|
+
}
|
|
1670
|
+
function presetIntakeHosts(type) {
|
|
1671
|
+
const template3 = LOG_DRAIN_ENDPOINT_TEMPLATES[type];
|
|
1672
|
+
const sites = LOG_DRAIN_PRESET_SITES[type];
|
|
1673
|
+
if (!template3 || !sites) return [];
|
|
1674
|
+
const hosts = [];
|
|
1675
|
+
for (const site of sites) {
|
|
1676
|
+
try {
|
|
1677
|
+
hosts.push(new URL(template3.replace("{site}", site)).hostname.toLowerCase());
|
|
1678
|
+
} catch {
|
|
1679
|
+
}
|
|
1680
|
+
}
|
|
1681
|
+
return hosts;
|
|
1682
|
+
}
|
|
1683
|
+
function presetHostAllowlist(type) {
|
|
1684
|
+
return [
|
|
1685
|
+
...presetIntakeHosts(type),
|
|
1686
|
+
...LOG_DRAIN_PRESET_HOST_SUFFIXES[type] ?? []
|
|
1687
|
+
];
|
|
1688
|
+
}
|
|
1689
|
+
function drainHostAllowlistAllows(allowlist, host) {
|
|
1690
|
+
const needle = host.toLowerCase();
|
|
1691
|
+
return allowlist.some((raw) => {
|
|
1692
|
+
const entry = raw.toLowerCase();
|
|
1693
|
+
if (entry.startsWith(".")) return needle === entry.slice(1) || needle.endsWith(entry);
|
|
1694
|
+
return entry === needle;
|
|
1695
|
+
});
|
|
1696
|
+
}
|
|
1697
|
+
function drainDestinationIsVendorPinned(type) {
|
|
1698
|
+
if (LOG_DRAIN_ENDPOINT_TEMPLATES[type]) return true;
|
|
1699
|
+
return presetHostAllowlist(type).length > 0;
|
|
1700
|
+
}
|
|
1701
|
+
function drainVerificationOwnership(input) {
|
|
1702
|
+
if (input.proved === true) return "verified";
|
|
1703
|
+
if (input.mode === "test-post" && drainDestinationIsVendorPinned(input.type)) return "verified";
|
|
1704
|
+
return "reachability-only";
|
|
1705
|
+
}
|
|
1706
|
+
function drainOwnershipOrDefault(ownership) {
|
|
1707
|
+
return ownership === "verified" ? "verified" : "reachability-only";
|
|
1708
|
+
}
|
|
1709
|
+
function assertDrainContentAck(input) {
|
|
1710
|
+
const turningOn = input.next === true && input.was !== true;
|
|
1711
|
+
if (!turningOn) return void 0;
|
|
1712
|
+
if (input.ack !== true) throw new DrainContentAckRequiredError();
|
|
1713
|
+
return {
|
|
1714
|
+
by: input.actor,
|
|
1715
|
+
source: input.source,
|
|
1716
|
+
at: input.at,
|
|
1717
|
+
...input.inheritedFrom ? {
|
|
1718
|
+
inheritedFrom: input.inheritedFrom
|
|
1719
|
+
} : {}
|
|
1720
|
+
};
|
|
1721
|
+
}
|
|
1722
|
+
function composePresetEndpoint(type, endpoint) {
|
|
1723
|
+
const rule = LOG_DRAIN_PRESET_PATHS[type];
|
|
1724
|
+
if (!rule) return void 0;
|
|
1725
|
+
let url;
|
|
1726
|
+
try {
|
|
1727
|
+
url = new URL(endpoint);
|
|
1728
|
+
} catch {
|
|
1729
|
+
return {
|
|
1730
|
+
ok: false,
|
|
1731
|
+
reason: "invalid_url"
|
|
1732
|
+
};
|
|
1733
|
+
}
|
|
1734
|
+
if (url.protocol !== "https:" || !url.hostname) return {
|
|
1735
|
+
ok: false,
|
|
1736
|
+
reason: "invalid_url"
|
|
1737
|
+
};
|
|
1738
|
+
const origin = url.origin;
|
|
1739
|
+
const path26 = url.pathname.replace(/\/+$/, "");
|
|
1740
|
+
if (!rule.segment) {
|
|
1741
|
+
const base2 = path26.endsWith(rule.path) ? path26.slice(0, path26.length - rule.path.length) : path26;
|
|
1742
|
+
return {
|
|
1743
|
+
ok: true,
|
|
1744
|
+
endpoint: `${origin}${base2}${rule.path}`
|
|
1745
|
+
};
|
|
1746
|
+
}
|
|
1747
|
+
const marker = `${rule.path}/`;
|
|
1748
|
+
const at = path26.indexOf(marker);
|
|
1749
|
+
if (at < 0) {
|
|
1750
|
+
return {
|
|
1751
|
+
ok: false,
|
|
1752
|
+
reason: rule.segment === "dataset" ? "missing_dataset" : "missing_token"
|
|
1753
|
+
};
|
|
1754
|
+
}
|
|
1755
|
+
const base = path26.slice(0, at);
|
|
1756
|
+
const afterMarker = path26.slice(at + marker.length);
|
|
1757
|
+
const rest = rule.suffix && afterMarker.endsWith(rule.suffix) ? afterMarker.slice(0, afterMarker.length - rule.suffix.length) : afterMarker;
|
|
1758
|
+
if (!rest || rest.includes("/")) {
|
|
1759
|
+
return {
|
|
1760
|
+
ok: false,
|
|
1761
|
+
reason: rule.segment === "dataset" ? "missing_dataset" : "missing_token"
|
|
1762
|
+
};
|
|
1763
|
+
}
|
|
1764
|
+
if (!PRESET_SEGMENT_RE.test(rest)) return {
|
|
1765
|
+
ok: false,
|
|
1766
|
+
reason: "bad_segment"
|
|
1767
|
+
};
|
|
1768
|
+
if (rule.segment === "dataset") {
|
|
1769
|
+
return {
|
|
1770
|
+
ok: true,
|
|
1771
|
+
endpoint: `${origin}${base}${rule.path}/${rest}${rule.suffix ?? ""}`,
|
|
1772
|
+
dataset: rest
|
|
1773
|
+
};
|
|
1774
|
+
}
|
|
1775
|
+
return {
|
|
1776
|
+
ok: true,
|
|
1777
|
+
endpoint: `${origin}${base}${rule.path}/`,
|
|
1778
|
+
token: rest
|
|
1779
|
+
};
|
|
1780
|
+
}
|
|
1781
|
+
function joinPresetEndpointToken(endpoint, token) {
|
|
1782
|
+
if (typeof token !== "string" || !PRESET_SEGMENT_RE.test(token)) return endpoint;
|
|
1783
|
+
return endpoint.endsWith("/") ? `${endpoint}${token}` : `${endpoint}/${token}`;
|
|
1784
|
+
}
|
|
1419
1785
|
function nextLogDrainQuotaResetAt(now) {
|
|
1420
1786
|
return new Date(Date.UTC(now.getUTCFullYear(), now.getUTCMonth(), now.getUTCDate() + 1)).toISOString();
|
|
1421
1787
|
}
|
|
@@ -1462,6 +1828,264 @@ function logDrainQuotaDroppedSeverities(degradation) {
|
|
|
1462
1828
|
return [];
|
|
1463
1829
|
}
|
|
1464
1830
|
}
|
|
1831
|
+
function isLogExportSource(source) {
|
|
1832
|
+
return LOG_EXPORT_SOURCES.includes(source);
|
|
1833
|
+
}
|
|
1834
|
+
function clamp(value3, max) {
|
|
1835
|
+
if (typeof value3 !== "string") return void 0;
|
|
1836
|
+
const trimmed2 = value3.trim();
|
|
1837
|
+
if (!trimmed2) return void 0;
|
|
1838
|
+
return trimmed2.length <= max ? trimmed2 : `${trimmed2.slice(0, max - 1)}\u2026`;
|
|
1839
|
+
}
|
|
1840
|
+
function numberOr(value3, fallback) {
|
|
1841
|
+
return typeof value3 === "number" && Number.isFinite(value3) ? value3 : fallback;
|
|
1842
|
+
}
|
|
1843
|
+
function isoOr(value3) {
|
|
1844
|
+
return typeof value3 === "string" && value3.length > 0 ? value3 : void 0;
|
|
1845
|
+
}
|
|
1846
|
+
function logDrainNoticeView(drain, now) {
|
|
1847
|
+
const health = drain.health ?? {};
|
|
1848
|
+
const quota = drain.quota;
|
|
1849
|
+
const view = {
|
|
1850
|
+
id: String(drain.id ?? ""),
|
|
1851
|
+
name: String(drain.name ?? ""),
|
|
1852
|
+
type: drain.type,
|
|
1853
|
+
state: drain.state,
|
|
1854
|
+
deliveredCount24h: numberOr(health.deliveredCount24h, 0),
|
|
1855
|
+
droppedCount24h: numberOr(health.droppedCount24h, 0),
|
|
1856
|
+
rejectedCount24h: numberOr(health.rejectedCount24h, 0),
|
|
1857
|
+
backlog: numberOr(health.backlog, 0),
|
|
1858
|
+
quotaRatio: quota ? logDrainQuotaRatio(quota, now) : 0
|
|
1859
|
+
};
|
|
1860
|
+
if (health.pauseReason) view.pauseReason = health.pauseReason;
|
|
1861
|
+
const lastError = clamp(health.lastError, LOG_DRAIN_NOTICE_ERROR_MAX_CHARS);
|
|
1862
|
+
if (lastError) view.lastError = lastError;
|
|
1863
|
+
if (typeof health.lastStatusCode === "number") view.lastStatusCode = health.lastStatusCode;
|
|
1864
|
+
const lastSuccessAt = isoOr(health.lastSuccessAt);
|
|
1865
|
+
if (lastSuccessAt) view.lastSuccessAt = lastSuccessAt;
|
|
1866
|
+
const lastFailureAt = isoOr(health.lastFailureAt);
|
|
1867
|
+
if (lastFailureAt) view.lastFailureAt = lastFailureAt;
|
|
1868
|
+
const resetsAt = isoOr(quota?.resetsAt);
|
|
1869
|
+
if (resetsAt) view.quotaResetsAt = resetsAt;
|
|
1870
|
+
return view;
|
|
1871
|
+
}
|
|
1872
|
+
function logDrainHealthCardPath(orgId, drainId) {
|
|
1873
|
+
return `/orgs/${encodeURIComponent(orgId)}/log-drains/${encodeURIComponent(drainId)}`;
|
|
1874
|
+
}
|
|
1875
|
+
function percent(ratio) {
|
|
1876
|
+
if (!Number.isFinite(ratio) || ratio <= 0) return "0%";
|
|
1877
|
+
return `${Math.round(ratio * 100)}%`;
|
|
1878
|
+
}
|
|
1879
|
+
function becauseClause(view) {
|
|
1880
|
+
const bits = [];
|
|
1881
|
+
if (view.lastStatusCode) bits.push(`HTTP ${view.lastStatusCode}`);
|
|
1882
|
+
if (view.lastError) bits.push(view.lastError);
|
|
1883
|
+
return bits.length ? ` Last error: ${bits.join(" \u2014 ")}.` : "";
|
|
1884
|
+
}
|
|
1885
|
+
function logDrainNoticeCopy(payload) {
|
|
1886
|
+
const view = payload.drain;
|
|
1887
|
+
const name = view.name || view.id;
|
|
1888
|
+
const backlog = view.backlog > 0 ? ` ${view.backlog.toLocaleString("en-US")} records are buffered.` : "";
|
|
1889
|
+
switch (payload.kind) {
|
|
1890
|
+
case "failing":
|
|
1891
|
+
return {
|
|
1892
|
+
title: name,
|
|
1893
|
+
subject: `Log drain "${name}" is failing`,
|
|
1894
|
+
previewLine: "Failing \u2014 15 minutes without a successful delivery",
|
|
1895
|
+
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.`,
|
|
1896
|
+
status: "failed",
|
|
1897
|
+
priority: "high"
|
|
1898
|
+
};
|
|
1899
|
+
case "paused_auto":
|
|
1900
|
+
return {
|
|
1901
|
+
title: name,
|
|
1902
|
+
subject: `Log drain "${name}" was paused`,
|
|
1903
|
+
previewLine: "Paused \u2014 24 hours without a successful delivery",
|
|
1904
|
+
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}\`.`,
|
|
1905
|
+
status: "failed",
|
|
1906
|
+
priority: "high"
|
|
1907
|
+
};
|
|
1908
|
+
case "paused_quota":
|
|
1909
|
+
return {
|
|
1910
|
+
title: name,
|
|
1911
|
+
subject: `Log drain "${name}" was paused \u2014 daily quota exhausted`,
|
|
1912
|
+
previewLine: `Paused \u2014 ${percent(view.quotaRatio)} of the daily allowance used`,
|
|
1913
|
+
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}\`.`,
|
|
1914
|
+
status: "failed",
|
|
1915
|
+
priority: "high"
|
|
1916
|
+
};
|
|
1917
|
+
case "quota_warning":
|
|
1918
|
+
return {
|
|
1919
|
+
title: name,
|
|
1920
|
+
subject: `Log drain "${name}" has used 80% of its daily allowance`,
|
|
1921
|
+
previewLine: `${percent(view.quotaRatio)} of the daily allowance used`,
|
|
1922
|
+
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"}.`,
|
|
1923
|
+
status: "failed",
|
|
1924
|
+
priority: "normal"
|
|
1925
|
+
};
|
|
1926
|
+
case "dropped": {
|
|
1927
|
+
const dropped = payload.droppedCount ?? view.droppedCount24h;
|
|
1928
|
+
return {
|
|
1929
|
+
title: name,
|
|
1930
|
+
subject: `Log drain "${name}" is dropping records`,
|
|
1931
|
+
previewLine: `${dropped.toLocaleString("en-US")} records dropped`,
|
|
1932
|
+
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.`,
|
|
1933
|
+
status: "failed",
|
|
1934
|
+
priority: "high"
|
|
1935
|
+
};
|
|
1936
|
+
}
|
|
1937
|
+
case "verification_pending":
|
|
1938
|
+
return {
|
|
1939
|
+
title: name,
|
|
1940
|
+
subject: `Log drain "${name}" is still unverified`,
|
|
1941
|
+
previewLine: "Unverified after 24 hours \u2014 nothing is being delivered",
|
|
1942
|
+
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.`,
|
|
1943
|
+
status: "failed",
|
|
1944
|
+
priority: "normal"
|
|
1945
|
+
};
|
|
1946
|
+
default: {
|
|
1947
|
+
const exhaustive = payload.kind;
|
|
1948
|
+
throw new Error(`unhandled log-drain notice kind: ${String(exhaustive)}`);
|
|
1949
|
+
}
|
|
1950
|
+
}
|
|
1951
|
+
}
|
|
1952
|
+
function logDrainNoticeLabel(kind) {
|
|
1953
|
+
switch (kind) {
|
|
1954
|
+
case "failing":
|
|
1955
|
+
return "failing";
|
|
1956
|
+
case "paused_auto":
|
|
1957
|
+
return "paused (no success for 24 h)";
|
|
1958
|
+
case "paused_quota":
|
|
1959
|
+
return "paused (daily allowance exhausted)";
|
|
1960
|
+
case "quota_warning":
|
|
1961
|
+
return "80% of the daily allowance used";
|
|
1962
|
+
case "dropped":
|
|
1963
|
+
return "dropping records";
|
|
1964
|
+
case "verification_pending":
|
|
1965
|
+
return "still unverified";
|
|
1966
|
+
default: {
|
|
1967
|
+
const exhaustive = kind;
|
|
1968
|
+
throw new Error(`unhandled log-drain notice kind: ${String(exhaustive)}`);
|
|
1969
|
+
}
|
|
1970
|
+
}
|
|
1971
|
+
}
|
|
1972
|
+
function logDrainNoticeDigestCopy(payload) {
|
|
1973
|
+
const entries = [
|
|
1974
|
+
...payload.entries ?? []
|
|
1975
|
+
].sort((a, b) => a.at < b.at ? -1 : a.at > b.at ? 1 : 0).slice(0, LOG_DRAIN_DIGEST_MAX_ENTRIES);
|
|
1976
|
+
const drains = new Set(entries.map((entry) => entry.drainId));
|
|
1977
|
+
const noun = `${entries.length} notice${entries.length === 1 ? "" : "s"}`;
|
|
1978
|
+
const across = `${drains.size} drain${drains.size === 1 ? "" : "s"}`;
|
|
1979
|
+
const lines = entries.map((entry) => `${entry.drainName || entry.drainId} \u2014 ${logDrainNoticeLabel(entry.kind)}`);
|
|
1980
|
+
return {
|
|
1981
|
+
title: "Log drains \u2014 daily summary",
|
|
1982
|
+
subject: `Log drains \u2014 ${noun} in the last day`,
|
|
1983
|
+
previewLine: `${noun} across ${across}`,
|
|
1984
|
+
summary: `${noun} across ${across} in the last day: ${lines.join("; ")}.`,
|
|
1985
|
+
status: "failed",
|
|
1986
|
+
priority: "normal"
|
|
1987
|
+
};
|
|
1988
|
+
}
|
|
1989
|
+
function finiteNonNegative(value3) {
|
|
1990
|
+
return typeof value3 === "number" && Number.isFinite(value3) && value3 >= 0 ? value3 : void 0;
|
|
1991
|
+
}
|
|
1992
|
+
function mergeLimits(base, stored) {
|
|
1993
|
+
const patch = stored ?? {};
|
|
1994
|
+
return {
|
|
1995
|
+
eventsPerDay: finiteNonNegative(patch.eventsPerDay) ?? base.eventsPerDay,
|
|
1996
|
+
bytesPerDay: finiteNonNegative(patch.bytesPerDay) ?? base.bytesPerDay
|
|
1997
|
+
};
|
|
1998
|
+
}
|
|
1999
|
+
function mergeCard(base, stored) {
|
|
2000
|
+
const patch = stored ?? {};
|
|
2001
|
+
return {
|
|
2002
|
+
includedEventsPerMonth: finiteNonNegative(patch.includedEventsPerMonth) ?? base.includedEventsPerMonth,
|
|
2003
|
+
includedBytesPerMonth: finiteNonNegative(patch.includedBytesPerMonth) ?? base.includedBytesPerMonth,
|
|
2004
|
+
usdPerMillionEvents: finiteNonNegative(patch.usdPerMillionEvents) ?? base.usdPerMillionEvents,
|
|
2005
|
+
usdPerGiB: finiteNonNegative(patch.usdPerGiB) ?? base.usdPerGiB
|
|
2006
|
+
};
|
|
2007
|
+
}
|
|
2008
|
+
function resolveStoredLogDrainPlanConfig(stored) {
|
|
2009
|
+
const values = stored;
|
|
2010
|
+
if (!values || typeof values.version !== "number" || !Number.isFinite(values.version)) {
|
|
2011
|
+
return DEFAULT_LOG_DRAIN_PLAN_CONFIG;
|
|
2012
|
+
}
|
|
2013
|
+
const tiers = {};
|
|
2014
|
+
const pricing = {};
|
|
2015
|
+
for (const tier of TIERS) {
|
|
2016
|
+
tiers[tier] = mergeLimits(DEFAULT_LOG_DRAIN_PLAN_CONFIG.tiers[tier], values.tiers?.[tier]);
|
|
2017
|
+
pricing[tier] = mergeCard(DEFAULT_LOG_DRAIN_PLAN_CONFIG.pricing[tier], values.pricing?.[tier]);
|
|
2018
|
+
}
|
|
2019
|
+
const orgs = {};
|
|
2020
|
+
for (const [orgId, override] of Object.entries(values.orgs ?? {})) {
|
|
2021
|
+
if (!orgId || !override || typeof override !== "object") continue;
|
|
2022
|
+
const row2 = {};
|
|
2023
|
+
if (override.tier && TIERS.includes(override.tier)) row2.tier = override.tier;
|
|
2024
|
+
const events = finiteNonNegative(override.eventsPerDay);
|
|
2025
|
+
const bytes = finiteNonNegative(override.bytesPerDay);
|
|
2026
|
+
if (events !== void 0) row2.eventsPerDay = events;
|
|
2027
|
+
if (bytes !== void 0) row2.bytesPerDay = bytes;
|
|
2028
|
+
if (override.pricing && typeof override.pricing === "object") row2.pricing = {
|
|
2029
|
+
...override.pricing
|
|
2030
|
+
};
|
|
2031
|
+
if (Object.keys(row2).length) orgs[orgId] = row2;
|
|
2032
|
+
}
|
|
2033
|
+
return {
|
|
2034
|
+
version: values.version,
|
|
2035
|
+
tiers,
|
|
2036
|
+
pricing,
|
|
2037
|
+
...Object.keys(orgs).length ? {
|
|
2038
|
+
orgs
|
|
2039
|
+
} : {}
|
|
2040
|
+
};
|
|
2041
|
+
}
|
|
2042
|
+
function logDrainPlanTierOverride(config, orgId) {
|
|
2043
|
+
return orgId ? config.orgs?.[orgId]?.tier : void 0;
|
|
2044
|
+
}
|
|
2045
|
+
function logDrainQuotaLimitsFor(config, orgId, tier) {
|
|
2046
|
+
const base = config.tiers[tier] ?? config.tiers.team ?? LOG_DRAIN_QUOTAS.team;
|
|
2047
|
+
const override = orgId ? config.orgs?.[orgId] : void 0;
|
|
2048
|
+
if (!override) return {
|
|
2049
|
+
...base
|
|
2050
|
+
};
|
|
2051
|
+
return {
|
|
2052
|
+
eventsPerDay: override.eventsPerDay ?? base.eventsPerDay,
|
|
2053
|
+
bytesPerDay: override.bytesPerDay ?? base.bytesPerDay
|
|
2054
|
+
};
|
|
2055
|
+
}
|
|
2056
|
+
function logDrainPriceCardFor(config, orgId, tier) {
|
|
2057
|
+
const base = config.pricing[tier] ?? config.pricing.team ?? DEFAULT_LOG_DRAIN_PLAN_CONFIG.pricing.team;
|
|
2058
|
+
const override = orgId ? config.orgs?.[orgId]?.pricing : void 0;
|
|
2059
|
+
return override ? mergeCard(base, override) : {
|
|
2060
|
+
...base
|
|
2061
|
+
};
|
|
2062
|
+
}
|
|
2063
|
+
function priceDrainUsage(totals, card, tier) {
|
|
2064
|
+
const billableRecords = Math.max(0, Math.floor(finiteNonNegative(totals?.billableRecords) ?? 0));
|
|
2065
|
+
const billableBytes = Math.max(0, Math.floor(finiteNonNegative(totals?.billableBytes) ?? 0));
|
|
2066
|
+
const includedEvents = card.includedEventsPerMonth;
|
|
2067
|
+
const includedBytes = card.includedBytesPerMonth;
|
|
2068
|
+
const overageEvents = Math.max(0, billableRecords - includedEvents);
|
|
2069
|
+
const overageBytes = Math.max(0, billableBytes - includedBytes);
|
|
2070
|
+
const eventsUsd = overageEvents / 1e6 * card.usdPerMillionEvents;
|
|
2071
|
+
const bytesUsd = overageBytes / LOG_DRAIN_BYTES_PER_GIB * card.usdPerGiB;
|
|
2072
|
+
const unpriced = card.usdPerMillionEvents === 0 && card.usdPerGiB === 0;
|
|
2073
|
+
const round = /* @__PURE__ */ __name2((usd) => Math.round(usd * 100) / 100, "round");
|
|
2074
|
+
return {
|
|
2075
|
+
lineItem: LOG_DRAIN_USAGE_LINE_ITEM,
|
|
2076
|
+
tier,
|
|
2077
|
+
billableRecords,
|
|
2078
|
+
billableBytes,
|
|
2079
|
+
includedEvents,
|
|
2080
|
+
includedBytes,
|
|
2081
|
+
overageEvents,
|
|
2082
|
+
overageBytes,
|
|
2083
|
+
eventsUsd: round(eventsUsd),
|
|
2084
|
+
bytesUsd: round(bytesUsd),
|
|
2085
|
+
usd: round(Math.max(eventsUsd, bytesUsd)),
|
|
2086
|
+
unpriced
|
|
2087
|
+
};
|
|
2088
|
+
}
|
|
1465
2089
|
function encodeLogCursor(c) {
|
|
1466
2090
|
return Buffer.from(JSON.stringify({
|
|
1467
2091
|
t: c.t,
|
|
@@ -2180,7 +2804,7 @@ function effectiveAgentFeatures(base, override, rule) {
|
|
|
2180
2804
|
if (rule === "wholesale") return override || base || void 0;
|
|
2181
2805
|
return effectiveAgentFeatureRows(base, override).rows;
|
|
2182
2806
|
}
|
|
2183
|
-
var __defProp2, __name2, PLUMBING_THREAD_CHANNELS, CHANNEL_CONVERSATION_CHANNELS, HIDDEN_THREAD_CHANNELS, REVIEWABLE_ACTION_EXECUTE_TOOL_ALLOWLIST, REVIEWABLE_STANDING_START_TOOLS, REVIEWABLE_MCP_SEND_TOOL_SUFFIX, MCP_TOOL_READ_VERB_RE, MCP_DRAFT_CREATE_VERBS, NON_INTERACTIVE_CHANNELS, RICH_PARTS_MESSAGE_ID_PREFIX, SCREENSHOT_MESSAGE_ID_PREFIX, BROWSER_COMMANDS, BROWSER_COMMAND_NAMES, DESKTOP_FILE_COMMANDS, DESKTOP_FILE_COMMAND_SET, WORKFLOW_RETRY_BACKOFFS, WORKFLOW_RETRY_MIN_ATTEMPTS, WORKFLOW_RETRY_POLICY_KEYS, WORKFLOW_RETRY_MAX_ATTEMPTS, WORKFLOW_RETRY_ENGINE_KEYS, WORKFLOW_JOB_RESOURCES, WORKFLOW_SIDE_EFFECTS, WORKFLOW_AGENT_EFFORTS, WORKFLOW_MODEL_CLASSES, WORKFLOW_TASK_CLASSES, WORKFLOW_MODEL_TRAITS, WORKFLOW_MODEL_REASON_MAX_LENGTH, WORKFLOW_MODELS_COMPOSE_MODES, WORKFLOW_MODELS_PIN_MODES, WORKFLOW_MODELS_FALLBACK_MODES, WORKFLOW_MODELS_CONSENT_ACTIONS_MIN, WORKFLOW_DEFAULT_TASK_CLASS_MAP, WORKFLOW_MODELS_MAX_CLASS_DEFAULT, WORKFLOW_AUTONOMY_FORMS, WORKFLOW_AUTONOMY_NUMERIC_KEYS, WORKFLOW_AUTONOMY_ENVELOPE_KEYS, WORKFLOW_AUTONOMY_ENABLED_DEFAULT, WORKFLOW_AUTONOMY_DEFAULTS, WORKFLOW_AUTONOMY_CEILINGS, WORKFLOW_AUTONOMY_MAX_RUNS_PER_HOUR_ENV, WORKFLOW_AUTONOMY_MAX_RUNS_PER_HOUR_CEILING, WORKFLOW_AUTONOMY_FORMS_DEFAULT, WORKFLOW_AUTONOMY_MIN_VALUE, WORKFLOW_JOB_RANGES, WORKFLOW_JOB_RANGE_MEMBERS, WORKFLOW_SINGLE_STEP_TYPES, WORKFLOW_HITL_ENTRY_TYPES, WORKFLOW_ARM_ENTRY_TYPES, WORKFLOW_HITL_ARM_CONTAINERS, WORKFLOW_GRAPH_ENTRY_STEP_KINDS, WORKFLOW_ARM_ENTRY_STEP_KINDS, WORKFLOW_BUDGET_MAX_DURATION_SECONDS, MODEL_ID_BYOK_PROVIDERS, MODEL_CLASS_REF_PREFIX, MODEL_SNAPSHOT_SUFFIX, REASONING_EFFORT_VALUES, IMPLICIT_MODEL_SELECTION_SOURCES, PLATFORM_FALLBACK_MODEL_SOURCE, AGENT_NAME_TOKEN, DEFAULT_PERSONA_GUIDE, PERSONAL_SPACE_STARTING_PERSONA, AGENT_LOG_SOURCES, AGENT_LOG_ENVIRONMENTS, LOG_DRAIN_TYPES_PHASE1, LOG_DRAIN_FORMATS, LOG_DRAIN_SEVERITIES, LOG_DRAIN_SOURCES, LOG_DRAIN_CONTENT_SOURCES, LOG_DRAIN_DEFAULT_SOURCES, LOG_DRAIN_MAX_PER_ORG, LOG_DRAIN_MAX_PER_ORG_ENTERPRISE, LOG_DRAIN_DATADOG_SITES, LOG_DRAIN_ENDPOINT_TEMPLATES, LOG_DRAIN_QUOTAS, LOG_DRAIN_QUOTA_WARN_RATIO, LOG_DRAIN_QUOTA_DROP_DEBUG_RATIO, LOG_DRAIN_QUOTA_DROP_INFO_RATIO, LOG_DRAIN_QUOTA_PAUSE_RATIO, LOG_CURSOR_MAX_LENGTH, LOG_CURSOR_MAX_ID_LENGTH, LOG_RELATIVE_TIME_PATTERN, LOG_ISO_TIME_PATTERN, RELATIVE_UNIT_MS, CORE_DRAINING_CODE, CORE_DRAINING_DEFAULT_RETRY_MS, CORE_DRAINING_MAX_RETRY_MS, VoiceNameSchema, PluginProviderSchema, RealtimeProviderSchema, PluginClassSchema, ModelDescriptorSchema, InferenceModelSchema, PluginModelSchema, RealtimeModelSchema, LuaVoiceModelSchema, TurnDetectionSchema, InterruptionSchema, BuiltinAudioClipSchema, AudioConfigSchema, BackgroundAudioEntrySchema, BackgroundAudioSchema, LuaVoiceConfigInnerSchema, LuaVoiceConfigSchema, LuaVoiceRefSchema, EventType, LUA_JOB_DEFAULT_TIMEOUT_SECONDS, LUA_JOB_MIN_TIMEOUT_SECONDS, LUA_JOB_MAX_TIMEOUT_SECONDS, KEYS, MAX_BODY_BYTES, MAX_ID_LENGTH, UTC_ISO, TEMPLATE_TRIGGER_URL_ENV_PREFIX, TEMPLATE_INSTALL_POLICY_PER_WORKSPACE_VALUES, SUBJECT_TYPES, SubjectTypeSchema, CREDENTIAL_TYPES, CredentialTypeSchema, DEVICE_OPERATIONS, DeviceOperationSchema, DEVICE_SCOPE_BY_OPERATION, DeviceBindingSchema, TYPED_API_KEY, IdSchema, SESSION_AUTH_TIME_MAX_S, PrincipalDescriptorSchema, ActorDescriptorSchema, PrincipalOwnerSchema, CredentialLifecycleSchema, GeneralCredentialDescriptorSchema, DeviceCredentialDescriptorSchema, GeneralPrincipalContextSchema, DeviceCredentialPrincipalContextSchema, RawPrincipalContextSchema, PrincipalContextSchema, DeviceCredentialClaimSchema, LUA_CLIENT_HEADER, LUA_CLIENT_APPS, SEMVER_PATTERN, WEB_RELEASE_PATTERN, CLIENT_HEADER_PATTERN, LUA_SESSION_ID_CLAIM, SESSION_REVOKED_CODE, AUTHZ_PROJECTION_VERSION, ProjectedScopeSchema, DisplayRoleSchema, AuthorizationPrincipalSchema, CredentialContextSchema, ProjectionAnomalySchema, ProjectedOrgSchema, ProjectedResourceSchema, CapabilityProfilesSchema, RoleCatalogSchema, EffectiveAuthorizationSchema, ResourcePageSchema, SYSTEM_USER_PREFIX, WORKFLOW_RUN_IN_FLIGHT, WORKFLOW_RUN_IDLE, WORKFLOW_RUN_TERMINAL, WORKFLOW_RUN_STATUSES, WORKFLOW_RUN_GATE_KINDS, WORKFLOW_STEP_STATUSES, WORKFLOW_STEP_IN_FLIGHT, WORKFLOW_SIGNAL_EVENT_SITES, ARCHIVE_WINDOW_MARGIN_DAYS, WORKFLOW_ORG_PURGING_TTL_S, WORKFLOW_ORG_PURGE_FORCE_AFTER_MS, IDEMPOTENCY_HOLDING_STATUSES, WORKFLOW_SCHEDULED_RUN_ID_PREFIX, CLOUD_TASK_RUN_ID_PREFIX, WORKFLOW_SCHEDULE_KEY_MAX, WORKFLOW_SCHEDULE_IDEMPOTENCY_KEY_PREFIX, WORKFLOW_OPERATION_ID_PREFIX, WORKFLOW_JOURNAL_PROTOCOL_VERSION, WORKFLOW_CONNECTION_KEY_RE, WORKFLOW_JOB_MODEL_SOURCE_LABELS, WORKFLOW_SUSPEND_KINDS, WORKFLOW_RUN_NOTIFICATION_SUSPENDED_KINDS, WORKFLOW_SIGNAL_PAYLOAD_MAX_BYTES, WORKFLOW_RESOLVE_OUTPUT_MAX_BYTES, WORKFLOW_GOAL_JUDGE_SELF, REDACTED_PLACEHOLDER, PROVIDER_MESSAGE_MAX_CHARS, ERROR_MESSAGE_MAX_CHARS, SECRET_LITERAL_PATTERNS, SECRET_NAME, SECRET_PAIR_PATTERNS, GROUP_COUNT, WORKFLOW_SECRET_KEY_RE, WORKFLOW_RESERVED_SECRET_KEYS, SCRUB_INPUT_MAX_CHARS, SCRUB_CUT_BACKOFF_CHARS, WORKFLOW_AUDIT_EVENTS, WORKFLOW_AUDIT_METADATA_MAX_BYTES, INDENT, WRAP_WIDTH, NOUNS, GET_TOOL_NAMES, PREAMBLE, WORKFLOW_APPROVAL_OUTPUT_DECISIONS, WORKFLOW_APPROVAL_OUTPUT_SCHEMA, JSON_FENCE_RE, DEFAULT_ON_AGENT_FEATURES, SUBAGENT_PER_KEY_FLAG_ENV, PER_KEY_FLAG_VALUES;
|
|
2807
|
+
var __defProp2, __name2, PLUMBING_THREAD_CHANNELS, CHANNEL_CONVERSATION_CHANNELS, HIDDEN_THREAD_CHANNELS, REVIEWABLE_ACTION_EXECUTE_TOOL_ALLOWLIST, REVIEWABLE_STANDING_START_TOOLS, REVIEWABLE_MCP_SEND_TOOL_SUFFIX, MCP_TOOL_READ_VERB_RE, MCP_DRAFT_CREATE_VERBS, NON_INTERACTIVE_CHANNELS, RICH_PARTS_MESSAGE_ID_PREFIX, SCREENSHOT_MESSAGE_ID_PREFIX, BROWSER_COMMANDS, BROWSER_COMMAND_NAMES, LOG_FIELDS_MAX_KEYS, LOG_FIELD_MAX_VALUE_BYTES, LOG_FIELDS_MAX_BYTES, LOG_FIELD_KEY_PATTERN, LOG_FIELD_SECRET_SHAPED_KEY_PATTERNS, LOG_FIELDS_CLAMPED_KEY, LOG_FIELD_ARRAY_COUNT_SUFFIX, LuaLogFieldsError, DESKTOP_FILE_COMMANDS, DESKTOP_FILE_COMMAND_SET, WORKFLOW_RETRY_BACKOFFS, WORKFLOW_RETRY_MIN_ATTEMPTS, WORKFLOW_RETRY_POLICY_KEYS, WORKFLOW_RETRY_MAX_ATTEMPTS, WORKFLOW_RETRY_ENGINE_KEYS, WORKFLOW_JOB_RESOURCES, WORKFLOW_SIDE_EFFECTS, WORKFLOW_AGENT_EFFORTS, WORKFLOW_MODEL_CLASSES, WORKFLOW_TASK_CLASSES, WORKFLOW_MODEL_TRAITS, WORKFLOW_MODEL_REASON_MAX_LENGTH, WORKFLOW_MODELS_COMPOSE_MODES, WORKFLOW_MODELS_PIN_MODES, WORKFLOW_MODELS_FALLBACK_MODES, WORKFLOW_MODELS_CONSENT_ACTIONS_MIN, WORKFLOW_DEFAULT_TASK_CLASS_MAP, WORKFLOW_MODELS_MAX_CLASS_DEFAULT, WORKFLOW_AUTONOMY_FORMS, WORKFLOW_AUTONOMY_NUMERIC_KEYS, WORKFLOW_AUTONOMY_ENVELOPE_KEYS, WORKFLOW_AUTONOMY_ENABLED_DEFAULT, WORKFLOW_AUTONOMY_DEFAULTS, WORKFLOW_AUTONOMY_CEILINGS, WORKFLOW_AUTONOMY_MAX_RUNS_PER_HOUR_ENV, WORKFLOW_AUTONOMY_MAX_RUNS_PER_HOUR_CEILING, WORKFLOW_AUTONOMY_FORMS_DEFAULT, WORKFLOW_AUTONOMY_MIN_VALUE, WORKFLOW_JOB_RANGES, WORKFLOW_JOB_RANGE_MEMBERS, WORKFLOW_SINGLE_STEP_TYPES, WORKFLOW_HITL_ENTRY_TYPES, WORKFLOW_ARM_ENTRY_TYPES, WORKFLOW_HITL_ARM_CONTAINERS, WORKFLOW_GRAPH_ENTRY_STEP_KINDS, WORKFLOW_ARM_ENTRY_STEP_KINDS, WORKFLOW_BUDGET_MAX_DURATION_SECONDS, MODEL_ID_BYOK_PROVIDERS, MODEL_CLASS_REF_PREFIX, MODEL_SNAPSHOT_SUFFIX, REASONING_EFFORT_VALUES, IMPLICIT_MODEL_SELECTION_SOURCES, PLATFORM_FALLBACK_MODEL_SOURCE, AGENT_NAME_TOKEN, DEFAULT_PERSONA_GUIDE, PERSONAL_SPACE_STARTING_PERSONA, AGENT_LOG_SOURCES, AGENT_LOG_ENVIRONMENTS, AGENT_LOG_FIELDS_MAX_WIRE_KEYS, LOG_DRAIN_TYPES_PHASE1, LOG_DRAIN_TYPES_PHASE2, LOG_DRAIN_TYPES_IMPLEMENTED, LOG_DRAIN_FORMATS, LOG_DRAIN_SEVERITIES, LOG_DRAIN_SOURCES, LOG_DRAIN_CONTENT_SOURCES, LOG_DRAIN_DEFAULT_SOURCES, LOG_DRAIN_MAX_PER_ORG, LOG_DRAIN_MAX_PER_ORG_ENTERPRISE, LOG_DRAIN_DATADOG_SITES, LOG_DRAIN_NEWRELIC_SITES, LOG_DRAIN_ENDPOINT_TEMPLATES, LOG_DRAIN_PRESET_SITES, LOG_DRAIN_BUCKET_NAME_PATTERN, LOG_DRAIN_BUCKET_HOST_PATTERNS, LOG_DRAIN_PRESET_HOST_SUFFIXES, DRAIN_CONTENT_ACK_ERROR_CODE, DRAIN_CONTENT_ACK_FIELD, DrainContentAckRequiredError, LOG_DRAIN_PRESET_PATHS, PRESET_SEGMENT_RE, LOG_DRAIN_QUOTAS, LOG_DRAIN_QUOTA_WARN_RATIO, LOG_DRAIN_QUOTA_DROP_DEBUG_RATIO, LOG_DRAIN_QUOTA_DROP_INFO_RATIO, LOG_DRAIN_QUOTA_PAUSE_RATIO, LOG_EXPORT_SOURCES, LOG_EXPORT_MAX_WINDOW_DAYS, LOG_EXPORT_MAX_WINDOW_MS, LOG_EXPORT_URL_TTL_SECONDS, LOG_EXPORT_FILE_RETENTION_DAYS, LOG_EXPORT_FILE_RETENTION_MS, LOG_EXPORT_PART_MAX_BYTES, LOG_DRAIN_NOTICE_RATE_LIMIT_MS, LOG_DRAIN_VERIFICATION_STALE_MS, LOG_DRAIN_DIGEST_INTERVAL_MS, LOG_DRAIN_DIGEST_MAX_ENTRIES, LOG_DRAIN_NOTICE_ERROR_MAX_CHARS, LOG_DRAIN_USAGE_LINE_ITEM, LOG_DRAIN_BYTES_PER_GIB, DEFAULT_LOG_DRAIN_PLAN_CONFIG, TIERS, LOG_CURSOR_MAX_LENGTH, LOG_CURSOR_MAX_ID_LENGTH, LOG_RELATIVE_TIME_PATTERN, LOG_ISO_TIME_PATTERN, RELATIVE_UNIT_MS, CORE_DRAINING_CODE, CORE_DRAINING_DEFAULT_RETRY_MS, CORE_DRAINING_MAX_RETRY_MS, VoiceNameSchema, PluginProviderSchema, RealtimeProviderSchema, PluginClassSchema, ModelDescriptorSchema, InferenceModelSchema, PluginModelSchema, RealtimeModelSchema, LuaVoiceModelSchema, TurnDetectionSchema, InterruptionSchema, BuiltinAudioClipSchema, AudioConfigSchema, BackgroundAudioEntrySchema, BackgroundAudioSchema, LuaVoiceConfigInnerSchema, LuaVoiceConfigSchema, LuaVoiceRefSchema, EventType, LUA_JOB_DEFAULT_TIMEOUT_SECONDS, LUA_JOB_MIN_TIMEOUT_SECONDS, LUA_JOB_MAX_TIMEOUT_SECONDS, KEYS, MAX_BODY_BYTES, MAX_ID_LENGTH, UTC_ISO, TEMPLATE_TRIGGER_URL_ENV_PREFIX, TEMPLATE_INSTALL_POLICY_PER_WORKSPACE_VALUES, SUBJECT_TYPES, SubjectTypeSchema, CREDENTIAL_TYPES, CredentialTypeSchema, DEVICE_OPERATIONS, DeviceOperationSchema, DEVICE_SCOPE_BY_OPERATION, DeviceBindingSchema, TYPED_API_KEY, IdSchema, SESSION_AUTH_TIME_MAX_S, PrincipalDescriptorSchema, ActorDescriptorSchema, PrincipalOwnerSchema, CredentialLifecycleSchema, GeneralCredentialDescriptorSchema, DeviceCredentialDescriptorSchema, GeneralPrincipalContextSchema, DeviceCredentialPrincipalContextSchema, RawPrincipalContextSchema, PrincipalContextSchema, DeviceCredentialClaimSchema, LUA_CLIENT_HEADER, LUA_CLIENT_APPS, SEMVER_PATTERN, WEB_RELEASE_PATTERN, CLIENT_HEADER_PATTERN, LUA_SESSION_ID_CLAIM, SESSION_REVOKED_CODE, AUTHZ_PROJECTION_VERSION, ProjectedScopeSchema, DisplayRoleSchema, AuthorizationPrincipalSchema, CredentialContextSchema, ProjectionAnomalySchema, ProjectedOrgSchema, ProjectedResourceSchema, CapabilityProfilesSchema, RoleCatalogSchema, EffectiveAuthorizationSchema, ResourcePageSchema, SYSTEM_USER_PREFIX, WORKFLOW_RUN_IN_FLIGHT, WORKFLOW_RUN_IDLE, WORKFLOW_RUN_TERMINAL, WORKFLOW_RUN_STATUSES, WORKFLOW_RUN_GATE_KINDS, WORKFLOW_STEP_STATUSES, WORKFLOW_STEP_IN_FLIGHT, WORKFLOW_SIGNAL_EVENT_SITES, ARCHIVE_WINDOW_MARGIN_DAYS, WORKFLOW_ORG_PURGING_TTL_S, WORKFLOW_ORG_PURGE_FORCE_AFTER_MS, IDEMPOTENCY_HOLDING_STATUSES, WORKFLOW_SCHEDULED_RUN_ID_PREFIX, CLOUD_TASK_RUN_ID_PREFIX, WORKFLOW_SCHEDULE_KEY_MAX, WORKFLOW_SCHEDULE_IDEMPOTENCY_KEY_PREFIX, WORKFLOW_OPERATION_ID_PREFIX, WORKFLOW_JOURNAL_PROTOCOL_VERSION, WORKFLOW_CONNECTION_KEY_RE, WORKFLOW_JOB_MODEL_SOURCE_LABELS, WORKFLOW_SUSPEND_KINDS, WORKFLOW_RUN_NOTIFICATION_SUSPENDED_KINDS, WORKFLOW_SIGNAL_PAYLOAD_MAX_BYTES, WORKFLOW_RESOLVE_OUTPUT_MAX_BYTES, WORKFLOW_GOAL_JUDGE_SELF, REDACTED_PLACEHOLDER, PROVIDER_MESSAGE_MAX_CHARS, ERROR_MESSAGE_MAX_CHARS, SECRET_LITERAL_PATTERNS, SECRET_NAME, SECRET_PAIR_PATTERNS, GROUP_COUNT, WORKFLOW_SECRET_KEY_RE, WORKFLOW_RESERVED_SECRET_KEYS, SCRUB_INPUT_MAX_CHARS, SCRUB_CUT_BACKOFF_CHARS, WORKFLOW_AUDIT_EVENTS, WORKFLOW_AUDIT_METADATA_MAX_BYTES, INDENT, WRAP_WIDTH, NOUNS, GET_TOOL_NAMES, PREAMBLE, WORKFLOW_APPROVAL_OUTPUT_DECISIONS, WORKFLOW_APPROVAL_OUTPUT_SCHEMA, JSON_FENCE_RE, DEFAULT_ON_AGENT_FEATURES, SUBAGENT_PER_KEY_FLAG_ENV, PER_KEY_FLAG_VALUES;
|
|
2184
2808
|
var init_dist = __esm({
|
|
2185
2809
|
"../shared-types/dist/index.mjs"() {
|
|
2186
2810
|
"use strict";
|
|
@@ -2499,6 +3123,50 @@ var init_dist = __esm({
|
|
|
2499
3123
|
}
|
|
2500
3124
|
];
|
|
2501
3125
|
BROWSER_COMMAND_NAMES = BROWSER_COMMANDS.map((c) => c.name);
|
|
3126
|
+
LOG_FIELDS_MAX_KEYS = 32;
|
|
3127
|
+
LOG_FIELD_MAX_VALUE_BYTES = 1024;
|
|
3128
|
+
LOG_FIELDS_MAX_BYTES = 8192;
|
|
3129
|
+
LOG_FIELD_KEY_PATTERN = /^[a-z][a-z0-9_]{0,63}$/;
|
|
3130
|
+
LOG_FIELD_SECRET_SHAPED_KEY_PATTERNS = Object.freeze([
|
|
3131
|
+
/^api_[0-9a-f]{24,}$/,
|
|
3132
|
+
/^gh[pousr]_[a-z0-9]{36}$/,
|
|
3133
|
+
/^(?:sk|rk|pk)_(?:live|test)_[a-z0-9]{16,}$/,
|
|
3134
|
+
/^lua_hc_[a-z0-9]{20,}/,
|
|
3135
|
+
/^lua_sk_[a-z0-9]{20,}/
|
|
3136
|
+
]);
|
|
3137
|
+
LOG_FIELDS_CLAMPED_KEY = "lua_fields_clamped";
|
|
3138
|
+
LOG_FIELD_ARRAY_COUNT_SUFFIX = ".count";
|
|
3139
|
+
LuaLogFieldsError = class _LuaLogFieldsError extends Error {
|
|
3140
|
+
static {
|
|
3141
|
+
__name(this, "_LuaLogFieldsError");
|
|
3142
|
+
}
|
|
3143
|
+
static {
|
|
3144
|
+
__name2(this, "LuaLogFieldsError");
|
|
3145
|
+
}
|
|
3146
|
+
constructor(message) {
|
|
3147
|
+
super(message);
|
|
3148
|
+
this.name = "LuaLogFieldsError";
|
|
3149
|
+
Object.setPrototypeOf(this, _LuaLogFieldsError.prototype);
|
|
3150
|
+
}
|
|
3151
|
+
};
|
|
3152
|
+
__name(utf8WidthAt, "utf8WidthAt");
|
|
3153
|
+
__name2(utf8WidthAt, "utf8WidthAt");
|
|
3154
|
+
__name(utf8ByteLength, "utf8ByteLength");
|
|
3155
|
+
__name2(utf8ByteLength, "utf8ByteLength");
|
|
3156
|
+
__name(clampUtf8, "clampUtf8");
|
|
3157
|
+
__name2(clampUtf8, "clampUtf8");
|
|
3158
|
+
__name(mapBytes, "mapBytes");
|
|
3159
|
+
__name2(mapBytes, "mapBytes");
|
|
3160
|
+
__name(withValueCap, "withValueCap");
|
|
3161
|
+
__name2(withValueCap, "withValueCap");
|
|
3162
|
+
__name(describeValue, "describeValue");
|
|
3163
|
+
__name2(describeValue, "describeValue");
|
|
3164
|
+
__name(assertValidLogFieldKey, "assertValidLogFieldKey");
|
|
3165
|
+
__name2(assertValidLogFieldKey, "assertValidLogFieldKey");
|
|
3166
|
+
__name(normalizeLogFields, "normalizeLogFields");
|
|
3167
|
+
__name2(normalizeLogFields, "normalizeLogFields");
|
|
3168
|
+
__name(clampLogFields, "clampLogFields");
|
|
3169
|
+
__name2(clampLogFields, "clampLogFields");
|
|
2502
3170
|
DESKTOP_FILE_COMMANDS = [
|
|
2503
3171
|
"files_roots",
|
|
2504
3172
|
"files_stat",
|
|
@@ -2888,12 +3556,37 @@ This text is who you are for this person. As you learn them, their name, their w
|
|
|
2888
3556
|
"production",
|
|
2889
3557
|
"sandbox"
|
|
2890
3558
|
];
|
|
3559
|
+
AGENT_LOG_FIELDS_MAX_WIRE_KEYS = LOG_FIELDS_MAX_KEYS + 1;
|
|
3560
|
+
__name(utf8Bytes, "utf8Bytes");
|
|
3561
|
+
__name2(utf8Bytes, "utf8Bytes");
|
|
3562
|
+
__name(isPlainFieldKey, "isPlainFieldKey");
|
|
3563
|
+
__name2(isPlainFieldKey, "isPlainFieldKey");
|
|
3564
|
+
__name(describeAgentLogFieldsViolation, "describeAgentLogFieldsViolation");
|
|
3565
|
+
__name2(describeAgentLogFieldsViolation, "describeAgentLogFieldsViolation");
|
|
3566
|
+
__name(isAgentLogFields, "isAgentLogFields");
|
|
3567
|
+
__name2(isAgentLogFields, "isAgentLogFields");
|
|
2891
3568
|
LOG_DRAIN_TYPES_PHASE1 = [
|
|
2892
3569
|
"http",
|
|
2893
3570
|
"otlp",
|
|
2894
3571
|
"datadog",
|
|
2895
3572
|
"betterstack"
|
|
2896
3573
|
];
|
|
3574
|
+
LOG_DRAIN_TYPES_PHASE2 = [
|
|
3575
|
+
"splunk",
|
|
3576
|
+
"loki",
|
|
3577
|
+
"axiom",
|
|
3578
|
+
"newrelic",
|
|
3579
|
+
"sumologic"
|
|
3580
|
+
];
|
|
3581
|
+
LOG_DRAIN_TYPES_IMPLEMENTED = [
|
|
3582
|
+
...LOG_DRAIN_TYPES_PHASE1,
|
|
3583
|
+
...LOG_DRAIN_TYPES_PHASE2,
|
|
3584
|
+
// RECONCILE-4 (W4-4). `s3` is implemented (H4 / PRO-1887) but is NOT in
|
|
3585
|
+
// `LOG_DRAIN_TYPES_PHASE2`, because its own flag opens it and `*` must not. It
|
|
3586
|
+
// belongs here all the same: this list is what a CLIENT may offer, and the server
|
|
3587
|
+
// remains the authority that answers 422 with the live list.
|
|
3588
|
+
"s3"
|
|
3589
|
+
];
|
|
2897
3590
|
LOG_DRAIN_FORMATS = [
|
|
2898
3591
|
"json",
|
|
2899
3592
|
"ndjson"
|
|
@@ -2912,7 +3605,10 @@ This text is who you are for this person. As you learn them, their name, their w
|
|
|
2912
3605
|
"trigger-execution",
|
|
2913
3606
|
"job-execution",
|
|
2914
3607
|
"workflow-run",
|
|
2915
|
-
"workflow-audit"
|
|
3608
|
+
"workflow-audit",
|
|
3609
|
+
// PRO-1884 (H2). Appended AFTER 'workflow-audit' so the enum stays additive and
|
|
3610
|
+
// no existing member changes position.
|
|
3611
|
+
"voice-call"
|
|
2916
3612
|
];
|
|
2917
3613
|
LOG_DRAIN_CONTENT_SOURCES = [
|
|
2918
3614
|
"user_message",
|
|
@@ -2935,7 +3631,22 @@ This text is who you are for this person. As you learn them, their name, their w
|
|
|
2935
3631
|
"mcp",
|
|
2936
3632
|
"rag",
|
|
2937
3633
|
"execution",
|
|
2938
|
-
"agent_error"
|
|
3634
|
+
"agent_error",
|
|
3635
|
+
// ── phase 2 ──
|
|
3636
|
+
// PRO-1882 / H1. `delivery` carries one record per applied status transition of an
|
|
3637
|
+
// outbound message. It is on by default because a send that failed at the vendor is
|
|
3638
|
+
// operational truth a customer's own on-call needs, and nothing in it is content:
|
|
3639
|
+
// the recipient is masked to its last four characters unless the drain selects
|
|
3640
|
+
// `includeContent`.
|
|
3641
|
+
"delivery",
|
|
3642
|
+
// PRO-1884 / H2. The three adjacent execution ledgers. ON for a NEW drain: they are
|
|
3643
|
+
// the platform's own record of a dispatch, a run and a job outcome — the same class
|
|
3644
|
+
// of operational line the phase-1 defaults already carry, and none of them is
|
|
3645
|
+
// content-bearing without `includeContent`. A drain created before this shipped keeps
|
|
3646
|
+
// the source set it was created with; nothing is added to an existing drain.
|
|
3647
|
+
"trigger-execution",
|
|
3648
|
+
"job-execution",
|
|
3649
|
+
"workflow-run"
|
|
2939
3650
|
];
|
|
2940
3651
|
LOG_DRAIN_MAX_PER_ORG = 5;
|
|
2941
3652
|
LOG_DRAIN_MAX_PER_ORG_ENTERPRISE = 10;
|
|
@@ -2949,11 +3660,106 @@ This text is who you are for this person. As you learn them, their name, their w
|
|
|
2949
3660
|
"ap1.datadoghq.com",
|
|
2950
3661
|
"ddog-gov.com"
|
|
2951
3662
|
];
|
|
3663
|
+
LOG_DRAIN_NEWRELIC_SITES = [
|
|
3664
|
+
"log-api.newrelic.com",
|
|
3665
|
+
"log-api.eu.newrelic.com",
|
|
3666
|
+
"log-api.jp.newrelic.com"
|
|
3667
|
+
];
|
|
2952
3668
|
LOG_DRAIN_ENDPOINT_TEMPLATES = {
|
|
2953
|
-
datadog: "https://http-intake.logs.{site}/api/v2/logs"
|
|
3669
|
+
datadog: "https://http-intake.logs.{site}/api/v2/logs",
|
|
3670
|
+
newrelic: "https://{site}/log/v1"
|
|
3671
|
+
};
|
|
3672
|
+
LOG_DRAIN_PRESET_SITES = {
|
|
3673
|
+
datadog: LOG_DRAIN_DATADOG_SITES,
|
|
3674
|
+
newrelic: LOG_DRAIN_NEWRELIC_SITES
|
|
2954
3675
|
};
|
|
2955
3676
|
__name(resolvePresetEndpoint, "resolvePresetEndpoint");
|
|
2956
3677
|
__name2(resolvePresetEndpoint, "resolvePresetEndpoint");
|
|
3678
|
+
LOG_DRAIN_BUCKET_NAME_PATTERN = /^[a-z0-9][a-z0-9-]{1,61}[a-z0-9]$/;
|
|
3679
|
+
LOG_DRAIN_BUCKET_HOST_PATTERNS = Object.freeze({
|
|
3680
|
+
aws: [
|
|
3681
|
+
// virtual-host style, regional and legacy global
|
|
3682
|
+
/^[a-z0-9][a-z0-9-]{1,61}[a-z0-9]\.s3(\.dualstack)?(\.[a-z0-9-]+)?\.amazonaws\.com$/,
|
|
3683
|
+
// path style
|
|
3684
|
+
/^s3(\.dualstack)?(\.[a-z0-9-]+)?\.amazonaws\.com$/
|
|
3685
|
+
],
|
|
3686
|
+
r2: [
|
|
3687
|
+
/^[a-f0-9]{32}\.r2\.cloudflarestorage\.com$/
|
|
3688
|
+
],
|
|
3689
|
+
gcs: [
|
|
3690
|
+
/^storage\.googleapis\.com$/
|
|
3691
|
+
]
|
|
3692
|
+
});
|
|
3693
|
+
__name(isLogDrainBucketHostAllowed, "isLogDrainBucketHostAllowed");
|
|
3694
|
+
__name2(isLogDrainBucketHostAllowed, "isLogDrainBucketHostAllowed");
|
|
3695
|
+
__name(resolveDrainBucketEndpoint, "resolveDrainBucketEndpoint");
|
|
3696
|
+
__name2(resolveDrainBucketEndpoint, "resolveDrainBucketEndpoint");
|
|
3697
|
+
__name(drainBucketUsesPathStyle, "drainBucketUsesPathStyle");
|
|
3698
|
+
__name2(drainBucketUsesPathStyle, "drainBucketUsesPathStyle");
|
|
3699
|
+
__name(presetIntakeHosts, "presetIntakeHosts");
|
|
3700
|
+
__name2(presetIntakeHosts, "presetIntakeHosts");
|
|
3701
|
+
LOG_DRAIN_PRESET_HOST_SUFFIXES = {
|
|
3702
|
+
axiom: [
|
|
3703
|
+
".axiom.co"
|
|
3704
|
+
],
|
|
3705
|
+
sumologic: [
|
|
3706
|
+
".sumologic.com"
|
|
3707
|
+
]
|
|
3708
|
+
};
|
|
3709
|
+
__name(presetHostAllowlist, "presetHostAllowlist");
|
|
3710
|
+
__name2(presetHostAllowlist, "presetHostAllowlist");
|
|
3711
|
+
__name(drainHostAllowlistAllows, "drainHostAllowlistAllows");
|
|
3712
|
+
__name2(drainHostAllowlistAllows, "drainHostAllowlistAllows");
|
|
3713
|
+
__name(drainDestinationIsVendorPinned, "drainDestinationIsVendorPinned");
|
|
3714
|
+
__name2(drainDestinationIsVendorPinned, "drainDestinationIsVendorPinned");
|
|
3715
|
+
__name(drainVerificationOwnership, "drainVerificationOwnership");
|
|
3716
|
+
__name2(drainVerificationOwnership, "drainVerificationOwnership");
|
|
3717
|
+
__name(drainOwnershipOrDefault, "drainOwnershipOrDefault");
|
|
3718
|
+
__name2(drainOwnershipOrDefault, "drainOwnershipOrDefault");
|
|
3719
|
+
DRAIN_CONTENT_ACK_ERROR_CODE = "DRAIN_CONTENT_ACK_REQUIRED";
|
|
3720
|
+
DRAIN_CONTENT_ACK_FIELD = "includeContentAck";
|
|
3721
|
+
DrainContentAckRequiredError = class extends Error {
|
|
3722
|
+
static {
|
|
3723
|
+
__name(this, "DrainContentAckRequiredError");
|
|
3724
|
+
}
|
|
3725
|
+
static {
|
|
3726
|
+
__name2(this, "DrainContentAckRequiredError");
|
|
3727
|
+
}
|
|
3728
|
+
code = DRAIN_CONTENT_ACK_ERROR_CODE;
|
|
3729
|
+
field = DRAIN_CONTENT_ACK_FIELD;
|
|
3730
|
+
constructor() {
|
|
3731
|
+
super("includeContent ships end-user message content to a third party; set includeContentAck: true to confirm.");
|
|
3732
|
+
this.name = "DrainContentAckRequiredError";
|
|
3733
|
+
}
|
|
3734
|
+
};
|
|
3735
|
+
__name(assertDrainContentAck, "assertDrainContentAck");
|
|
3736
|
+
__name2(assertDrainContentAck, "assertDrainContentAck");
|
|
3737
|
+
LOG_DRAIN_PRESET_PATHS = {
|
|
3738
|
+
// https://docs.splunk.com/Documentation/Splunk/latest/Data/HECExamples
|
|
3739
|
+
splunk: {
|
|
3740
|
+
path: "/services/collector/event"
|
|
3741
|
+
},
|
|
3742
|
+
// https://grafana.com/docs/loki/latest/reference/loki-http-api/#ingest-logs
|
|
3743
|
+
loki: {
|
|
3744
|
+
path: "/loki/api/v1/push"
|
|
3745
|
+
},
|
|
3746
|
+
// https://axiom.co/docs/restapi/endpoints/ingestIntoDataset
|
|
3747
|
+
axiom: {
|
|
3748
|
+
path: "/v1/datasets",
|
|
3749
|
+
segment: "dataset",
|
|
3750
|
+
suffix: "/ingest"
|
|
3751
|
+
},
|
|
3752
|
+
// https://help.sumologic.com/docs/send-data/hosted-collectors/http-source/logs-metrics/upload-logs/
|
|
3753
|
+
sumologic: {
|
|
3754
|
+
path: "/receiver/v1/http",
|
|
3755
|
+
segment: "token"
|
|
3756
|
+
}
|
|
3757
|
+
};
|
|
3758
|
+
PRESET_SEGMENT_RE = /^[A-Za-z0-9._~%=+-]{1,512}$/;
|
|
3759
|
+
__name(composePresetEndpoint, "composePresetEndpoint");
|
|
3760
|
+
__name2(composePresetEndpoint, "composePresetEndpoint");
|
|
3761
|
+
__name(joinPresetEndpointToken, "joinPresetEndpointToken");
|
|
3762
|
+
__name2(joinPresetEndpointToken, "joinPresetEndpointToken");
|
|
2957
3763
|
LOG_DRAIN_QUOTAS = {
|
|
2958
3764
|
team: {
|
|
2959
3765
|
eventsPerDay: 1e6,
|
|
@@ -2986,6 +3792,100 @@ This text is who you are for this person. As you learn them, their name, their w
|
|
|
2986
3792
|
__name2(logDrainQuotaWarned, "logDrainQuotaWarned");
|
|
2987
3793
|
__name(logDrainQuotaDroppedSeverities, "logDrainQuotaDroppedSeverities");
|
|
2988
3794
|
__name2(logDrainQuotaDroppedSeverities, "logDrainQuotaDroppedSeverities");
|
|
3795
|
+
LOG_EXPORT_SOURCES = [
|
|
3796
|
+
...AGENT_LOG_SOURCES,
|
|
3797
|
+
"execution"
|
|
3798
|
+
];
|
|
3799
|
+
LOG_EXPORT_MAX_WINDOW_DAYS = 31;
|
|
3800
|
+
LOG_EXPORT_MAX_WINDOW_MS = LOG_EXPORT_MAX_WINDOW_DAYS * 24 * 60 * 60 * 1e3;
|
|
3801
|
+
LOG_EXPORT_URL_TTL_SECONDS = 24 * 60 * 60;
|
|
3802
|
+
LOG_EXPORT_FILE_RETENTION_DAYS = 7;
|
|
3803
|
+
LOG_EXPORT_FILE_RETENTION_MS = LOG_EXPORT_FILE_RETENTION_DAYS * 24 * 60 * 60 * 1e3;
|
|
3804
|
+
LOG_EXPORT_PART_MAX_BYTES = 256 * 1024 * 1024;
|
|
3805
|
+
__name(isLogExportSource, "isLogExportSource");
|
|
3806
|
+
__name2(isLogExportSource, "isLogExportSource");
|
|
3807
|
+
LOG_DRAIN_NOTICE_RATE_LIMIT_MS = 60 * 6e4;
|
|
3808
|
+
LOG_DRAIN_VERIFICATION_STALE_MS = 24 * 60 * 6e4;
|
|
3809
|
+
LOG_DRAIN_DIGEST_INTERVAL_MS = 24 * 60 * 6e4;
|
|
3810
|
+
LOG_DRAIN_DIGEST_MAX_ENTRIES = 50;
|
|
3811
|
+
LOG_DRAIN_NOTICE_ERROR_MAX_CHARS = 200;
|
|
3812
|
+
__name(clamp, "clamp");
|
|
3813
|
+
__name2(clamp, "clamp");
|
|
3814
|
+
__name(numberOr, "numberOr");
|
|
3815
|
+
__name2(numberOr, "numberOr");
|
|
3816
|
+
__name(isoOr, "isoOr");
|
|
3817
|
+
__name2(isoOr, "isoOr");
|
|
3818
|
+
__name(logDrainNoticeView, "logDrainNoticeView");
|
|
3819
|
+
__name2(logDrainNoticeView, "logDrainNoticeView");
|
|
3820
|
+
__name(logDrainHealthCardPath, "logDrainHealthCardPath");
|
|
3821
|
+
__name2(logDrainHealthCardPath, "logDrainHealthCardPath");
|
|
3822
|
+
__name(percent, "percent");
|
|
3823
|
+
__name2(percent, "percent");
|
|
3824
|
+
__name(becauseClause, "becauseClause");
|
|
3825
|
+
__name2(becauseClause, "becauseClause");
|
|
3826
|
+
__name(logDrainNoticeCopy, "logDrainNoticeCopy");
|
|
3827
|
+
__name2(logDrainNoticeCopy, "logDrainNoticeCopy");
|
|
3828
|
+
__name(logDrainNoticeLabel, "logDrainNoticeLabel");
|
|
3829
|
+
__name2(logDrainNoticeLabel, "logDrainNoticeLabel");
|
|
3830
|
+
__name(logDrainNoticeDigestCopy, "logDrainNoticeDigestCopy");
|
|
3831
|
+
__name2(logDrainNoticeDigestCopy, "logDrainNoticeDigestCopy");
|
|
3832
|
+
LOG_DRAIN_USAGE_LINE_ITEM = "log_drain_events";
|
|
3833
|
+
LOG_DRAIN_BYTES_PER_GIB = 1024 ** 3;
|
|
3834
|
+
DEFAULT_LOG_DRAIN_PLAN_CONFIG = {
|
|
3835
|
+
version: 1,
|
|
3836
|
+
tiers: {
|
|
3837
|
+
team: {
|
|
3838
|
+
...LOG_DRAIN_QUOTAS.team
|
|
3839
|
+
},
|
|
3840
|
+
business: {
|
|
3841
|
+
...LOG_DRAIN_QUOTAS.business
|
|
3842
|
+
},
|
|
3843
|
+
enterprise: {
|
|
3844
|
+
...LOG_DRAIN_QUOTAS.enterprise
|
|
3845
|
+
}
|
|
3846
|
+
},
|
|
3847
|
+
pricing: {
|
|
3848
|
+
team: {
|
|
3849
|
+
includedEventsPerMonth: 0,
|
|
3850
|
+
includedBytesPerMonth: 0,
|
|
3851
|
+
usdPerMillionEvents: 0,
|
|
3852
|
+
usdPerGiB: 0
|
|
3853
|
+
},
|
|
3854
|
+
business: {
|
|
3855
|
+
includedEventsPerMonth: 0,
|
|
3856
|
+
includedBytesPerMonth: 0,
|
|
3857
|
+
usdPerMillionEvents: 0,
|
|
3858
|
+
usdPerGiB: 0
|
|
3859
|
+
},
|
|
3860
|
+
enterprise: {
|
|
3861
|
+
includedEventsPerMonth: 0,
|
|
3862
|
+
includedBytesPerMonth: 0,
|
|
3863
|
+
usdPerMillionEvents: 0,
|
|
3864
|
+
usdPerGiB: 0
|
|
3865
|
+
}
|
|
3866
|
+
}
|
|
3867
|
+
};
|
|
3868
|
+
TIERS = [
|
|
3869
|
+
"team",
|
|
3870
|
+
"business",
|
|
3871
|
+
"enterprise"
|
|
3872
|
+
];
|
|
3873
|
+
__name(finiteNonNegative, "finiteNonNegative");
|
|
3874
|
+
__name2(finiteNonNegative, "finiteNonNegative");
|
|
3875
|
+
__name(mergeLimits, "mergeLimits");
|
|
3876
|
+
__name2(mergeLimits, "mergeLimits");
|
|
3877
|
+
__name(mergeCard, "mergeCard");
|
|
3878
|
+
__name2(mergeCard, "mergeCard");
|
|
3879
|
+
__name(resolveStoredLogDrainPlanConfig, "resolveStoredLogDrainPlanConfig");
|
|
3880
|
+
__name2(resolveStoredLogDrainPlanConfig, "resolveStoredLogDrainPlanConfig");
|
|
3881
|
+
__name(logDrainPlanTierOverride, "logDrainPlanTierOverride");
|
|
3882
|
+
__name2(logDrainPlanTierOverride, "logDrainPlanTierOverride");
|
|
3883
|
+
__name(logDrainQuotaLimitsFor, "logDrainQuotaLimitsFor");
|
|
3884
|
+
__name2(logDrainQuotaLimitsFor, "logDrainQuotaLimitsFor");
|
|
3885
|
+
__name(logDrainPriceCardFor, "logDrainPriceCardFor");
|
|
3886
|
+
__name2(logDrainPriceCardFor, "logDrainPriceCardFor");
|
|
3887
|
+
__name(priceDrainUsage, "priceDrainUsage");
|
|
3888
|
+
__name2(priceDrainUsage, "priceDrainUsage");
|
|
2989
3889
|
LOG_CURSOR_MAX_LENGTH = 512;
|
|
2990
3890
|
LOG_CURSOR_MAX_ID_LENGTH = 128;
|
|
2991
3891
|
LOG_RELATIVE_TIME_PATTERN = /^(\d{1,9})([smhd])$/;
|
|
@@ -5218,15 +6118,15 @@ function validateApproverBlock(node, opts = {
|
|
|
5218
6118
|
const users = spec?.users;
|
|
5219
6119
|
if (Array.isArray(users) && users.length > APPROVER_SPEC_MAX_USERS) push("cap-exceeded", path26, `at most ${APPROVER_SPEC_MAX_USERS} users`);
|
|
5220
6120
|
else {
|
|
5221
|
-
const
|
|
6121
|
+
const refusal2 = describeApproverSpecRefusal(spec);
|
|
5222
6122
|
issues.push({
|
|
5223
6123
|
code: "approver-invalid",
|
|
5224
6124
|
path: path26,
|
|
5225
6125
|
severity: "error",
|
|
5226
|
-
message:
|
|
6126
|
+
message: refusal2.message,
|
|
5227
6127
|
repair: {
|
|
5228
|
-
approver:
|
|
5229
|
-
written:
|
|
6128
|
+
approver: refusal2.approver,
|
|
6129
|
+
written: refusal2.written
|
|
5230
6130
|
}
|
|
5231
6131
|
});
|
|
5232
6132
|
}
|
|
@@ -13765,7 +14665,26 @@ var init_ast_helpers = __esm({
|
|
|
13765
14665
|
});
|
|
13766
14666
|
|
|
13767
14667
|
// src/compiler/utils/class-hierarchy.ts
|
|
14668
|
+
import path3 from "path";
|
|
13768
14669
|
import { Node as Node2 } from "ts-morph";
|
|
14670
|
+
function normalizePath(filePath) {
|
|
14671
|
+
return path3.resolve(filePath).split(path3.sep).join("/");
|
|
14672
|
+
}
|
|
14673
|
+
function sdkDistDir() {
|
|
14674
|
+
if (sdkDistDirCache !== void 0) return sdkDistDirCache;
|
|
14675
|
+
try {
|
|
14676
|
+
sdkDistDirCache = `${normalizePath(getPackageRoot())}/dist`;
|
|
14677
|
+
} catch {
|
|
14678
|
+
sdkDistDirCache = null;
|
|
14679
|
+
}
|
|
14680
|
+
return sdkDistDirCache;
|
|
14681
|
+
}
|
|
14682
|
+
function isSdkDeclaration(classDecl) {
|
|
14683
|
+
const filePath = normalizePath(classDecl.getSourceFile().getFilePath());
|
|
14684
|
+
if (filePath.includes(SDK_NODE_MODULES_SEGMENT)) return true;
|
|
14685
|
+
const distDir = sdkDistDir();
|
|
14686
|
+
return distDir !== null && filePath.startsWith(`${distDir}/`);
|
|
14687
|
+
}
|
|
13769
14688
|
function getClassHierarchy(classDecl, maxDepth = DEFAULT_MAX_DEPTH) {
|
|
13770
14689
|
const chain = [
|
|
13771
14690
|
classDecl
|
|
@@ -13794,9 +14713,10 @@ function extendsAny(classDecl, baseNames) {
|
|
|
13794
14713
|
}
|
|
13795
14714
|
return false;
|
|
13796
14715
|
}
|
|
13797
|
-
function findClassMember(classDecl, memberName, kind = "either") {
|
|
14716
|
+
function findClassMember(classDecl, memberName, kind = "either", options = {}) {
|
|
13798
14717
|
const chain = getClassHierarchy(classDecl);
|
|
13799
14718
|
for (const cls of chain) {
|
|
14719
|
+
if (!options.includeSdkDeclarations && isSdkDeclaration(cls)) break;
|
|
13800
14720
|
if (kind === "property" || kind === "either") {
|
|
13801
14721
|
const prop = cls.getProperty(memberName);
|
|
13802
14722
|
if (prop && Node2.isPropertyDeclaration(prop)) {
|
|
@@ -13837,11 +14757,16 @@ function safeGetBaseClass(classDecl) {
|
|
|
13837
14757
|
function classKey(c) {
|
|
13838
14758
|
return `${c.getSourceFile().getFilePath()}#${c.getName() ?? "<anonymous>"}#${c.getStartLineNumber()}`;
|
|
13839
14759
|
}
|
|
13840
|
-
var DEFAULT_MAX_DEPTH;
|
|
14760
|
+
var DEFAULT_MAX_DEPTH, SDK_NODE_MODULES_SEGMENT, sdkDistDirCache;
|
|
13841
14761
|
var init_class_hierarchy = __esm({
|
|
13842
14762
|
"src/compiler/utils/class-hierarchy.ts"() {
|
|
13843
14763
|
"use strict";
|
|
14764
|
+
init_package_root();
|
|
13844
14765
|
DEFAULT_MAX_DEPTH = 10;
|
|
14766
|
+
SDK_NODE_MODULES_SEGMENT = "/node_modules/lua-cli/";
|
|
14767
|
+
__name(normalizePath, "normalizePath");
|
|
14768
|
+
__name(sdkDistDir, "sdkDistDir");
|
|
14769
|
+
__name(isSdkDeclaration, "isSdkDeclaration");
|
|
13845
14770
|
__name(getClassHierarchy, "getClassHierarchy");
|
|
13846
14771
|
__name(extendsAny, "extendsAny");
|
|
13847
14772
|
__name(findClassMember, "findClassMember");
|
|
@@ -14858,9 +15783,8 @@ var init_job_plugin = __esm({
|
|
|
14858
15783
|
});
|
|
14859
15784
|
|
|
14860
15785
|
// src/compiler/plugins/webhook.plugin.ts
|
|
14861
|
-
import path3 from "path";
|
|
14862
15786
|
import { Node as Node6 } from "ts-morph";
|
|
14863
|
-
var
|
|
15787
|
+
var WebhookPlugin;
|
|
14864
15788
|
var init_webhook_plugin = __esm({
|
|
14865
15789
|
"src/compiler/plugins/webhook.plugin.ts"() {
|
|
14866
15790
|
"use strict";
|
|
@@ -14868,8 +15792,6 @@ var init_webhook_plugin = __esm({
|
|
|
14868
15792
|
init_ast_helpers();
|
|
14869
15793
|
init_class_hierarchy();
|
|
14870
15794
|
init_schema_converter();
|
|
14871
|
-
init_package_root();
|
|
14872
|
-
LUA_CLI_DECLARATION_PATH = path3.join(getPackageRoot(), "dist", "api-exports.d.ts");
|
|
14873
15795
|
WebhookPlugin = class extends BasePlugin {
|
|
14874
15796
|
static {
|
|
14875
15797
|
__name(this, "WebhookPlugin");
|
|
@@ -14896,8 +15818,7 @@ var init_webhook_plugin = __esm({
|
|
|
14896
15818
|
const exportName = isDefaultExport ? "default" : className;
|
|
14897
15819
|
const name = readStringMember(classDecl, "name") ?? deriveNameFromClassName(className);
|
|
14898
15820
|
const description = readStringMember(classDecl, "description") ?? "";
|
|
14899
|
-
const
|
|
14900
|
-
const hasSecret = secretMember !== void 0 && !(secretMember.owner.getName() === "LuaWebhook" && path3.resolve(secretMember.owner.getSourceFile().getFilePath()) === path3.resolve(LUA_CLI_DECLARATION_PATH));
|
|
15821
|
+
const hasSecret = findClassMember(classDecl, "secret", "property") !== void 0;
|
|
14901
15822
|
return {
|
|
14902
15823
|
kind: this.kind,
|
|
14903
15824
|
name,
|
|
@@ -18692,13 +19613,15 @@ var init_voice_plugin = __esm({
|
|
|
18692
19613
|
|
|
18693
19614
|
// ../shared-sandbox/dist/index.mjs
|
|
18694
19615
|
import vm from "vm";
|
|
18695
|
-
import { createRequire } from "module";
|
|
19616
|
+
import { builtinModules, createRequire } from "module";
|
|
18696
19617
|
import path6 from "path";
|
|
18697
19618
|
import dns from "dns";
|
|
18698
19619
|
import net2 from "net";
|
|
18699
19620
|
import { promisify } from "util";
|
|
18700
19621
|
import * as net from "net";
|
|
18701
19622
|
import { Agent as UndiciAgent } from "undici";
|
|
19623
|
+
import { isIP } from "net";
|
|
19624
|
+
import { Agent } from "undici";
|
|
18702
19625
|
import vm2 from "vm";
|
|
18703
19626
|
function buildSandboxProcess(opts) {
|
|
18704
19627
|
const hrtimeFn = /* @__PURE__ */ __name6((time) => process.hrtime(time), "hrtimeFn");
|
|
@@ -18841,10 +19764,13 @@ function buildSandboxGlobals() {
|
|
|
18841
19764
|
undefined: void 0
|
|
18842
19765
|
};
|
|
18843
19766
|
}
|
|
19767
|
+
function isRequireBlocklisted(id) {
|
|
19768
|
+
return REQUIRE_BLOCKLIST.has(id) || BLOCKLISTED_PACKAGES.some((name) => id.startsWith(`${name}/`));
|
|
19769
|
+
}
|
|
18844
19770
|
function buildSandboxRequire(opts) {
|
|
18845
19771
|
const realRequire = createRequire(path6.join(opts.cwd, "package.json"));
|
|
18846
19772
|
const wrapped = /* @__PURE__ */ __name6((id) => {
|
|
18847
|
-
if (
|
|
19773
|
+
if (isRequireBlocklisted(id)) {
|
|
18848
19774
|
const evt = {
|
|
18849
19775
|
event: "sandbox_require_blocklisted",
|
|
18850
19776
|
module: id,
|
|
@@ -19586,6 +20512,67 @@ function resolveExtraAllowedHostnames() {
|
|
|
19586
20512
|
if (!csv) return [];
|
|
19587
20513
|
return csv.split(",").map((s) => s.trim()).filter(Boolean);
|
|
19588
20514
|
}
|
|
20515
|
+
function pinnedLookup(addresses) {
|
|
20516
|
+
const rows3 = addresses.map((address) => ({
|
|
20517
|
+
address,
|
|
20518
|
+
family: isIP(address) === 6 ? 6 : 4
|
|
20519
|
+
}));
|
|
20520
|
+
return (hostname, optionsOrCb, maybeCb) => {
|
|
20521
|
+
const options = typeof optionsOrCb === "function" ? {} : optionsOrCb ?? {};
|
|
20522
|
+
const cb = typeof optionsOrCb === "function" ? optionsOrCb : maybeCb;
|
|
20523
|
+
const family = options.family === 4 || options.family === 6 ? options.family : void 0;
|
|
20524
|
+
const matching = family ? rows3.filter((row2) => row2.family === family) : rows3;
|
|
20525
|
+
if (matching.length === 0) {
|
|
20526
|
+
const error = new Error(`pinned lookup has no address for ${hostname}`);
|
|
20527
|
+
error.code = "ENOTFOUND";
|
|
20528
|
+
error.syscall = "getaddrinfo";
|
|
20529
|
+
error.hostname = hostname;
|
|
20530
|
+
cb(error);
|
|
20531
|
+
return;
|
|
20532
|
+
}
|
|
20533
|
+
if (options.all) {
|
|
20534
|
+
cb(null, matching);
|
|
20535
|
+
return;
|
|
20536
|
+
}
|
|
20537
|
+
cb(null, matching[0].address, matching[0].family);
|
|
20538
|
+
};
|
|
20539
|
+
}
|
|
20540
|
+
function pinnedDispatcherFor(addresses) {
|
|
20541
|
+
if (!addresses || addresses.length === 0) return void 0;
|
|
20542
|
+
const pinned = [
|
|
20543
|
+
...addresses
|
|
20544
|
+
];
|
|
20545
|
+
const dispatcher = new Agent({
|
|
20546
|
+
connect: {
|
|
20547
|
+
// undici forwards `connect.lookup` to `net.createConnection`, so this is the
|
|
20548
|
+
// hook that runs at TCP-connection time — the same hook the sandbox guard uses.
|
|
20549
|
+
// eslint-disable-next-line @typescript-eslint/no-explicit-any
|
|
20550
|
+
lookup: pinnedLookup(pinned)
|
|
20551
|
+
}
|
|
20552
|
+
});
|
|
20553
|
+
dispatcher[PINNED_ADDRESSES] = pinned;
|
|
20554
|
+
return {
|
|
20555
|
+
dispatcher,
|
|
20556
|
+
addresses: pinned,
|
|
20557
|
+
// `destroy`, not `close`: close waits for in-flight requests, and this is called
|
|
20558
|
+
// once the body has been read or cancelled, where waiting can only hang.
|
|
20559
|
+
close: /* @__PURE__ */ __name6(async () => {
|
|
20560
|
+
try {
|
|
20561
|
+
await dispatcher.destroy();
|
|
20562
|
+
} catch {
|
|
20563
|
+
}
|
|
20564
|
+
}, "close")
|
|
20565
|
+
};
|
|
20566
|
+
}
|
|
20567
|
+
function pinnedAddressesOf(dispatcher) {
|
|
20568
|
+
return dispatcher?.[PINNED_ADDRESSES];
|
|
20569
|
+
}
|
|
20570
|
+
function withPinnedDispatcher(init3, pin) {
|
|
20571
|
+
return pin ? {
|
|
20572
|
+
...init3,
|
|
20573
|
+
dispatcher: pin.dispatcher
|
|
20574
|
+
} : init3;
|
|
20575
|
+
}
|
|
19589
20576
|
function wrapBundleAsCjsModule(source) {
|
|
19590
20577
|
return "(function(module, exports, require) {\n" + source + "\n})(module, module.exports, require);";
|
|
19591
20578
|
}
|
|
@@ -19690,7 +20677,7 @@ function logUserCodeOrError(logger, message, error, context = {}) {
|
|
|
19690
20677
|
logger.error(message, error, context);
|
|
19691
20678
|
}
|
|
19692
20679
|
}
|
|
19693
|
-
var __defProp6, __name6, REQUIRE_BLOCKLIST, SANDBOX_FAKE_DIRNAME, SANDBOX_FAKE_FILENAME, EGRESS_DENIED_CODE, EGRESS_PROBE_DEFAULT_MS, PRIVATE_RANGES, dnsLookup, DEFAULT_BLOCK_CIDRS, HOSTNAME_NON_OVERRIDABLE_CIDRS, WorkflowDeterminismError, WORKFLOW_SCRIPT_REMOVED_GLOBALS, WORKFLOW_SCRIPT_TRAPPED_GLOBALS, WORKFLOW_SCRIPT_FORBIDDEN_PLATFORM_KEYS, USER_CODE_ERROR_CODE, PLATFORM_VM_ERROR_CODE, UserCodeError, DEFAULT_MAX_CAUSE_DEPTH, MissingPrimitiveCodeError;
|
|
20680
|
+
var __defProp6, __name6, REQUIRE_BLOCKLIST, SANDBOX_FAKE_DIRNAME, SANDBOX_FAKE_FILENAME, BLOCKLISTED_PACKAGES, EGRESS_DENIED_CODE, EGRESS_PROBE_DEFAULT_MS, PRIVATE_RANGES, dnsLookup, DEFAULT_BLOCK_CIDRS, HOSTNAME_NON_OVERRIDABLE_CIDRS, PINNED_ADDRESSES, WorkflowDeterminismError, WORKFLOW_SCRIPT_REMOVED_GLOBALS, WORKFLOW_SCRIPT_TRAPPED_GLOBALS, WORKFLOW_SCRIPT_FORBIDDEN_PLATFORM_KEYS, USER_CODE_ERROR_CODE, PLATFORM_VM_ERROR_CODE, UserCodeError, DEFAULT_MAX_CAUSE_DEPTH, MissingPrimitiveCodeError;
|
|
19694
20681
|
var init_dist4 = __esm({
|
|
19695
20682
|
"../shared-sandbox/dist/index.mjs"() {
|
|
19696
20683
|
"use strict";
|
|
@@ -19734,6 +20721,11 @@ var init_dist4 = __esm({
|
|
|
19734
20721
|
]);
|
|
19735
20722
|
SANDBOX_FAKE_DIRNAME = "/";
|
|
19736
20723
|
SANDBOX_FAKE_FILENAME = "/index.ts";
|
|
20724
|
+
BLOCKLISTED_PACKAGES = [
|
|
20725
|
+
...REQUIRE_BLOCKLIST
|
|
20726
|
+
].filter((id) => !id.startsWith("node:") && !builtinModules.includes(id));
|
|
20727
|
+
__name(isRequireBlocklisted, "isRequireBlocklisted");
|
|
20728
|
+
__name6(isRequireBlocklisted, "isRequireBlocklisted");
|
|
19737
20729
|
__name(buildSandboxRequire, "buildSandboxRequire");
|
|
19738
20730
|
__name6(buildSandboxRequire, "buildSandboxRequire");
|
|
19739
20731
|
EGRESS_DENIED_CODE = "EGRESS_DENIED";
|
|
@@ -19849,6 +20841,15 @@ var init_dist4 = __esm({
|
|
|
19849
20841
|
__name6(resolveExtraAllowedCidrs, "resolveExtraAllowedCidrs");
|
|
19850
20842
|
__name(resolveExtraAllowedHostnames, "resolveExtraAllowedHostnames");
|
|
19851
20843
|
__name6(resolveExtraAllowedHostnames, "resolveExtraAllowedHostnames");
|
|
20844
|
+
PINNED_ADDRESSES = /* @__PURE__ */ Symbol.for("lua.pinnedDispatch.addresses");
|
|
20845
|
+
__name(pinnedLookup, "pinnedLookup");
|
|
20846
|
+
__name6(pinnedLookup, "pinnedLookup");
|
|
20847
|
+
__name(pinnedDispatcherFor, "pinnedDispatcherFor");
|
|
20848
|
+
__name6(pinnedDispatcherFor, "pinnedDispatcherFor");
|
|
20849
|
+
__name(pinnedAddressesOf, "pinnedAddressesOf");
|
|
20850
|
+
__name6(pinnedAddressesOf, "pinnedAddressesOf");
|
|
20851
|
+
__name(withPinnedDispatcher, "withPinnedDispatcher");
|
|
20852
|
+
__name6(withPinnedDispatcher, "withPinnedDispatcher");
|
|
19852
20853
|
__name(wrapBundleAsCjsModule, "wrapBundleAsCjsModule");
|
|
19853
20854
|
__name6(wrapBundleAsCjsModule, "wrapBundleAsCjsModule");
|
|
19854
20855
|
__name(runBundleInContext, "runBundleInContext");
|
|
@@ -20481,6 +21482,12 @@ function safeDate() {
|
|
|
20481
21482
|
SafeDate.UTC = Date.UTC;
|
|
20482
21483
|
return SafeDate;
|
|
20483
21484
|
}
|
|
21485
|
+
function safeMath() {
|
|
21486
|
+
const math = {};
|
|
21487
|
+
for (const key of Reflect.ownKeys(Math)) math[key] = Math[key];
|
|
21488
|
+
math.random = notStaticStub("Math.random");
|
|
21489
|
+
return Object.freeze(math);
|
|
21490
|
+
}
|
|
20484
21491
|
function createSerializationContext() {
|
|
20485
21492
|
const moduleRef = {
|
|
20486
21493
|
exports: {}
|
|
@@ -20536,10 +21543,7 @@ function createSerializationContext() {
|
|
|
20536
21543
|
setImmediate: notStaticStub("setImmediate"),
|
|
20537
21544
|
queueMicrotask: notStaticStub("queueMicrotask"),
|
|
20538
21545
|
Date: safeDate(),
|
|
20539
|
-
Math:
|
|
20540
|
-
...Math,
|
|
20541
|
-
random: notStaticStub("Math.random")
|
|
20542
|
-
}),
|
|
21546
|
+
Math: safeMath(),
|
|
20543
21547
|
process: {
|
|
20544
21548
|
env: new Proxy({}, {
|
|
20545
21549
|
get: /* @__PURE__ */ __name((_t, prop) => typeof prop === "symbol" ? void 0 : notStaticStub(`process.env.${String(prop)}`)(), "get")
|
|
@@ -21131,6 +22135,7 @@ var init_graph_serializer = __esm({
|
|
|
21131
22135
|
"Workflows"
|
|
21132
22136
|
];
|
|
21133
22137
|
__name(safeDate, "safeDate");
|
|
22138
|
+
__name(safeMath, "safeMath");
|
|
21134
22139
|
__name(createSerializationContext, "createSerializationContext");
|
|
21135
22140
|
__name(serializeViaVm, "serializeViaVm");
|
|
21136
22141
|
__name(locateWorkflowExpression, "locateWorkflowExpression");
|
|
@@ -34856,7 +35861,7 @@ async function runWorkflowLocallyInner(rawOpts) {
|
|
|
34856
35861
|
]
|
|
34857
35862
|
]));
|
|
34858
35863
|
let seq = 0;
|
|
34859
|
-
const
|
|
35864
|
+
const emit3 = /* @__PURE__ */ __name((type, stepId, payload) => {
|
|
34860
35865
|
seq += 1;
|
|
34861
35866
|
ledger.events.push({
|
|
34862
35867
|
seq,
|
|
@@ -34939,7 +35944,7 @@ async function runWorkflowLocallyInner(rawOpts) {
|
|
|
34939
35944
|
completedAt: clock
|
|
34940
35945
|
});
|
|
34941
35946
|
if (status === "completed") stepResults[row2.stepId] = row2.output;
|
|
34942
|
-
|
|
35947
|
+
emit3(`step.${status}`, row2.stepId, row2.error ? {
|
|
34943
35948
|
error: row2.error
|
|
34944
35949
|
} : void 0);
|
|
34945
35950
|
say(`[${stamp()}] ${row2.stepId} \xB7 ${status}${row2.error ? ` \xB7 ${row2.error.code}: ${row2.error.message}` : ""}`);
|
|
@@ -35113,7 +36118,7 @@ async function runWorkflowLocallyInner(rawOpts) {
|
|
|
35113
36118
|
throw new BailRunSignal(output2);
|
|
35114
36119
|
}, "bailRun"),
|
|
35115
36120
|
log: /* @__PURE__ */ __name((message) => {
|
|
35116
|
-
|
|
36121
|
+
emit3("step.progress", row2.stepId, {
|
|
35117
36122
|
message
|
|
35118
36123
|
});
|
|
35119
36124
|
say(`[${stamp()}] ${row2.stepId} \xB7 log \xB7 ${message}`);
|
|
@@ -35182,7 +36187,7 @@ async function runWorkflowLocallyInner(rawOpts) {
|
|
|
35182
36187
|
clock += wallS * 1e3;
|
|
35183
36188
|
const requeued = s < segments;
|
|
35184
36189
|
const nextSession = `session-${id}-s${s}`;
|
|
35185
|
-
|
|
36190
|
+
emit3("step.checkpointed", id, {
|
|
35186
36191
|
segment: s,
|
|
35187
36192
|
segmentsMax: segments,
|
|
35188
36193
|
headSha: `local${s}`,
|
|
@@ -35239,7 +36244,7 @@ async function runWorkflowLocallyInner(rawOpts) {
|
|
|
35239
36244
|
} catch (e) {
|
|
35240
36245
|
if (e instanceof SuspendSignal) {
|
|
35241
36246
|
row2.status = "suspended";
|
|
35242
|
-
|
|
36247
|
+
emit3("step.suspended", id, {
|
|
35243
36248
|
kind: "input"
|
|
35244
36249
|
});
|
|
35245
36250
|
say(`[${stamp()}] ${id} \xB7 suspended \xB7 awaiting resumeData`);
|
|
@@ -35304,7 +36309,7 @@ async function runWorkflowLocallyInner(rawOpts) {
|
|
|
35304
36309
|
}
|
|
35305
36310
|
for (; ; ) {
|
|
35306
36311
|
say(`[park:${row2.stepId}] ${code} \u2014 retry/skip/complete/fail?`);
|
|
35307
|
-
|
|
36312
|
+
emit3("step.parked", row2.stepId, {
|
|
35308
36313
|
code
|
|
35309
36314
|
});
|
|
35310
36315
|
const answer = await opts.prompt("park", row2.stepId, {
|
|
@@ -35356,7 +36361,7 @@ async function runWorkflowLocallyInner(rawOpts) {
|
|
|
35356
36361
|
const maxAttempts = retryOf(single);
|
|
35357
36362
|
row2.status = "running";
|
|
35358
36363
|
row2.startedAt = clock;
|
|
35359
|
-
|
|
36364
|
+
emit3("step.started", row2.stepId);
|
|
35360
36365
|
const parkBaseId = row2.stepId.replace(/(\[\d+\]|#\d+)$/, "");
|
|
35361
36366
|
if (opts.park?.includes(row2.stepId) || opts.park?.includes(parkBaseId)) {
|
|
35362
36367
|
row2.attempt = Math.max(1, row2.attempt);
|
|
@@ -35830,7 +36835,7 @@ async function runWorkflowLocallyInner(rawOpts) {
|
|
|
35830
36835
|
}
|
|
35831
36836
|
}, "runRow");
|
|
35832
36837
|
const throttleAt = /* @__PURE__ */ new Map();
|
|
35833
|
-
|
|
36838
|
+
emit3("run.started");
|
|
35834
36839
|
say(`[${stamp()}] run ${runId} \xB7 ${plan.order.length} planned step(s)`);
|
|
35835
36840
|
try {
|
|
35836
36841
|
for (; ; ) {
|
|
@@ -35898,7 +36903,7 @@ async function runWorkflowLocallyInner(rawOpts) {
|
|
|
35898
36903
|
ledger.status = "completed";
|
|
35899
36904
|
ledger.output = bailed.output;
|
|
35900
36905
|
ledger.bailedFromStepId = bailed.stepId;
|
|
35901
|
-
|
|
36906
|
+
emit3("run.completed", void 0, {
|
|
35902
36907
|
bailed: true,
|
|
35903
36908
|
bailedFromStepId: bailed.stepId
|
|
35904
36909
|
});
|
|
@@ -35915,7 +36920,7 @@ async function runWorkflowLocallyInner(rawOpts) {
|
|
|
35915
36920
|
if (runFailure) {
|
|
35916
36921
|
for (const r of rows3.values()) skipRow(r, "run_failed");
|
|
35917
36922
|
ledger.status = "failed";
|
|
35918
|
-
|
|
36923
|
+
emit3("run.failed", runFailure.stepId, {
|
|
35919
36924
|
code: runFailure.code
|
|
35920
36925
|
});
|
|
35921
36926
|
say(`[${stamp()}] run \xB7 failed \xB7 ${runFailure.code}: ${runFailure.message}`);
|
|
@@ -35972,7 +36977,7 @@ async function runWorkflowLocallyInner(rawOpts) {
|
|
|
35972
36977
|
}
|
|
35973
36978
|
ledger.status = "completed";
|
|
35974
36979
|
ledger.output = output;
|
|
35975
|
-
|
|
36980
|
+
emit3("run.completed");
|
|
35976
36981
|
say(`[${stamp()}] run \xB7 completed`);
|
|
35977
36982
|
finalizeLedger();
|
|
35978
36983
|
return {
|
|
@@ -36068,6 +37073,23 @@ function parseJsonOrFile(raw, what) {
|
|
|
36068
37073
|
__name(parseJsonOrFile, "parseJsonOrFile");
|
|
36069
37074
|
|
|
36070
37075
|
// src/utils/sandbox.ts
|
|
37076
|
+
init_dist();
|
|
37077
|
+
function createSandboxLog(consoleObj) {
|
|
37078
|
+
const emit3 = /* @__PURE__ */ __name((level, message, fields) => {
|
|
37079
|
+
const normalized = normalizeLogFields(fields);
|
|
37080
|
+
const text = typeof message === "object" && message !== null ? JSON.stringify(message) : String(message);
|
|
37081
|
+
const write = level === "error" ? consoleObj.error : level === "warn" ? consoleObj.warn : level === "info" ? consoleObj.info : consoleObj.log;
|
|
37082
|
+
if (normalized) write.call(consoleObj, text, JSON.stringify(normalized));
|
|
37083
|
+
else write.call(consoleObj, text);
|
|
37084
|
+
}, "emit");
|
|
37085
|
+
return Object.freeze({
|
|
37086
|
+
debug: /* @__PURE__ */ __name((message, fields) => emit3("debug", message, fields), "debug"),
|
|
37087
|
+
info: /* @__PURE__ */ __name((message, fields) => emit3("info", message, fields), "info"),
|
|
37088
|
+
warn: /* @__PURE__ */ __name((message, fields) => emit3("warn", message, fields), "warn"),
|
|
37089
|
+
error: /* @__PURE__ */ __name((message, fields) => emit3("error", message, fields), "error")
|
|
37090
|
+
});
|
|
37091
|
+
}
|
|
37092
|
+
__name(createSandboxLog, "createSandboxLog");
|
|
36071
37093
|
function resolveRequireMode() {
|
|
36072
37094
|
return process.env.LUA_SANDBOX_REQUIRE_MODE === "enforce" ? "enforce" : "log";
|
|
36073
37095
|
}
|
|
@@ -36211,6 +37233,13 @@ function createSandbox(options) {
|
|
|
36211
37233
|
__envRef: key
|
|
36212
37234
|
}), "template")
|
|
36213
37235
|
}),
|
|
37236
|
+
// K1a (PRO-2142) — the `log` global, so `lua test` runs the same code
|
|
37237
|
+
// production runs. There is no `VmLogSink` here, so the line goes to the
|
|
37238
|
+
// developer's console with its fields rendered beside it; the VALIDATION is
|
|
37239
|
+
// the identical `normalizeLogFields` the production VM calls, which is the
|
|
37240
|
+
// half that has to agree — a field map `lua test` accepts is one production
|
|
37241
|
+
// accepts, and one it refuses is refused here with the same message.
|
|
37242
|
+
log: createSandboxLog(consoleObj),
|
|
36214
37243
|
BasketStatus,
|
|
36215
37244
|
OrderStatus,
|
|
36216
37245
|
AI: {
|
|
@@ -36341,10 +37370,7 @@ async function executeTool(options) {
|
|
|
36341
37370
|
return await primitive.execute(inputs);
|
|
36342
37371
|
} catch (e) {
|
|
36343
37372
|
console.error(e);
|
|
36344
|
-
|
|
36345
|
-
status: "error",
|
|
36346
|
-
error: e.message
|
|
36347
|
-
};
|
|
37373
|
+
throw e;
|
|
36348
37374
|
}
|
|
36349
37375
|
} else {
|
|
36350
37376
|
const commonJsWrapper = `
|
|
@@ -36355,7 +37381,7 @@ module.exports = async (input) => {
|
|
|
36355
37381
|
return await executeFunction(input);
|
|
36356
37382
|
} catch(e) {
|
|
36357
37383
|
console.error(e);
|
|
36358
|
-
|
|
37384
|
+
throw e;
|
|
36359
37385
|
}
|
|
36360
37386
|
};
|
|
36361
37387
|
`;
|
|
@@ -36391,10 +37417,7 @@ async function executeWebhook(options) {
|
|
|
36391
37417
|
return await primitive.execute(event);
|
|
36392
37418
|
} catch (e) {
|
|
36393
37419
|
console.error(e);
|
|
36394
|
-
|
|
36395
|
-
status: "error",
|
|
36396
|
-
error: e.message
|
|
36397
|
-
};
|
|
37420
|
+
throw e;
|
|
36398
37421
|
}
|
|
36399
37422
|
} else {
|
|
36400
37423
|
const commonJsWrapper = `
|
|
@@ -36405,7 +37428,7 @@ module.exports = async (event) => {
|
|
|
36405
37428
|
return await executeFunction(event);
|
|
36406
37429
|
} catch(e) {
|
|
36407
37430
|
console.error(e);
|
|
36408
|
-
|
|
37431
|
+
throw e;
|
|
36409
37432
|
}
|
|
36410
37433
|
};
|
|
36411
37434
|
`;
|
|
@@ -36457,10 +37480,7 @@ async function executeJob(options) {
|
|
|
36457
37480
|
return await primitive.execute(jobInstance);
|
|
36458
37481
|
} catch (e) {
|
|
36459
37482
|
console.error(e);
|
|
36460
|
-
|
|
36461
|
-
status: "error",
|
|
36462
|
-
error: e.message
|
|
36463
|
-
};
|
|
37483
|
+
throw e;
|
|
36464
37484
|
}
|
|
36465
37485
|
} else {
|
|
36466
37486
|
const commonJsWrapper = `
|
|
@@ -36471,7 +37491,7 @@ module.exports = async (job) => {
|
|
|
36471
37491
|
return await executeFunction(job);
|
|
36472
37492
|
} catch(e) {
|
|
36473
37493
|
console.error(e);
|
|
36474
|
-
|
|
37494
|
+
throw e;
|
|
36475
37495
|
}
|
|
36476
37496
|
};
|
|
36477
37497
|
`;
|
|
@@ -36557,10 +37577,7 @@ async function executePreProcessor(options) {
|
|
|
36557
37577
|
return await primitive.execute(userInstance, messages, channel);
|
|
36558
37578
|
} catch (e) {
|
|
36559
37579
|
console.error(e);
|
|
36560
|
-
|
|
36561
|
-
status: "error",
|
|
36562
|
-
error: e.message
|
|
36563
|
-
};
|
|
37580
|
+
throw e;
|
|
36564
37581
|
}
|
|
36565
37582
|
} else {
|
|
36566
37583
|
const commonJsWrapper = `
|
|
@@ -36571,7 +37588,7 @@ module.exports = async (input) => {
|
|
|
36571
37588
|
return await executeFunction(input.user, input.messages, input.channel);
|
|
36572
37589
|
} catch(e) {
|
|
36573
37590
|
console.error(e);
|
|
36574
|
-
|
|
37591
|
+
throw e;
|
|
36575
37592
|
}
|
|
36576
37593
|
};
|
|
36577
37594
|
`;
|
|
@@ -37419,8 +38436,13 @@ var ALIAS_MAP = {
|
|
|
37419
38436
|
"delete",
|
|
37420
38437
|
"test",
|
|
37421
38438
|
"verify",
|
|
38439
|
+
// H4 / PRO-1887: the second half of a BUCKET verification, for the write-only
|
|
38440
|
+
// role that cannot read its own challenge object back.
|
|
38441
|
+
"confirm",
|
|
37422
38442
|
"pause",
|
|
37423
38443
|
"resume",
|
|
38444
|
+
// PRO-2126: re-enqueue one batch's records after a terminal refusal.
|
|
38445
|
+
"replay",
|
|
37424
38446
|
"rotate-secret"
|
|
37425
38447
|
],
|
|
37426
38448
|
aliases: lowerKeys({
|
|
@@ -39562,13 +40584,18 @@ async function compileQuietly(asJson) {
|
|
|
39562
40584
|
}
|
|
39563
40585
|
}
|
|
39564
40586
|
__name(compileQuietly, "compileQuietly");
|
|
39565
|
-
function handleExecutionError(error, entityType) {
|
|
39566
|
-
|
|
40587
|
+
function handleExecutionError(error, entityType, asJson = false) {
|
|
40588
|
+
if (asJson) {
|
|
40589
|
+
console.log(JSON.stringify(cliErrorEnvelope(error), null, 2));
|
|
40590
|
+
} else {
|
|
40591
|
+
console.error(`
|
|
39567
40592
|
\u274C ${entityType} execution failed:`);
|
|
39568
|
-
|
|
39569
|
-
|
|
39570
|
-
|
|
40593
|
+
console.error(error.message);
|
|
40594
|
+
if (error.stack) {
|
|
40595
|
+
console.error(error.stack);
|
|
40596
|
+
}
|
|
39571
40597
|
}
|
|
40598
|
+
process.exitCode = classifyCliError(error).exitCode;
|
|
39572
40599
|
}
|
|
39573
40600
|
__name(handleExecutionError, "handleExecutionError");
|
|
39574
40601
|
function extractToolsFromManifest(manifest) {
|
|
@@ -39744,7 +40771,7 @@ async function testSkill(entityName, inputJson, asJson = false) {
|
|
|
39744
40771
|
});
|
|
39745
40772
|
}
|
|
39746
40773
|
} catch (error) {
|
|
39747
|
-
handleExecutionError(error, "Tool");
|
|
40774
|
+
handleExecutionError(error, "Tool", asJson);
|
|
39748
40775
|
if (!asJson) {
|
|
39749
40776
|
writeHintBlock({
|
|
39750
40777
|
headline: "Tool ran locally \u2014 no server logs exist for this execution.",
|
|
@@ -39863,7 +40890,7 @@ async function testWebhook(entityName, inputJson, asJson = false) {
|
|
|
39863
40890
|
});
|
|
39864
40891
|
}
|
|
39865
40892
|
} catch (error) {
|
|
39866
|
-
handleExecutionError(error, "Webhook");
|
|
40893
|
+
handleExecutionError(error, "Webhook", asJson);
|
|
39867
40894
|
if (!asJson) {
|
|
39868
40895
|
writeHintBlock({
|
|
39869
40896
|
headline: "Webhook ran locally \u2014 no server logs exist for this execution.",
|
|
@@ -39955,7 +40982,7 @@ async function testJob(entityName, asJson = false) {
|
|
|
39955
40982
|
});
|
|
39956
40983
|
}
|
|
39957
40984
|
} catch (error) {
|
|
39958
|
-
handleExecutionError(error, "Job");
|
|
40985
|
+
handleExecutionError(error, "Job", asJson);
|
|
39959
40986
|
if (!asJson) {
|
|
39960
40987
|
writeHintBlock({
|
|
39961
40988
|
headline: "Job ran locally \u2014 no server logs exist for this execution.",
|
|
@@ -40107,7 +41134,7 @@ Raw result:`);
|
|
|
40107
41134
|
});
|
|
40108
41135
|
}
|
|
40109
41136
|
} catch (error) {
|
|
40110
|
-
handleExecutionError(error, "PreProcessor");
|
|
41137
|
+
handleExecutionError(error, "PreProcessor", asJson);
|
|
40111
41138
|
if (!asJson) {
|
|
40112
41139
|
writeHintBlock({
|
|
40113
41140
|
headline: "Preprocessor ran locally \u2014 no server logs exist for this execution.",
|
|
@@ -40236,7 +41263,7 @@ async function testPostProcessor(entityName, inputJson, asJson = false) {
|
|
|
40236
41263
|
});
|
|
40237
41264
|
}
|
|
40238
41265
|
} catch (error) {
|
|
40239
|
-
handleExecutionError(error, "PostProcessor");
|
|
41266
|
+
handleExecutionError(error, "PostProcessor", asJson);
|
|
40240
41267
|
if (!asJson) {
|
|
40241
41268
|
writeHintBlock({
|
|
40242
41269
|
headline: "Postprocessor ran locally \u2014 no server logs exist for this execution.",
|
|
@@ -41194,6 +42221,10 @@ function pickPushAllNextStepVariant(opts) {
|
|
|
41194
42221
|
return null;
|
|
41195
42222
|
}
|
|
41196
42223
|
__name(pickPushAllNextStepVariant, "pickPushAllNextStepVariant");
|
|
42224
|
+
function pushAllExitCode(variant) {
|
|
42225
|
+
return variant === "partial" || variant === "error" ? CLI_EXIT.ERROR : void 0;
|
|
42226
|
+
}
|
|
42227
|
+
__name(pushAllExitCode, "pushAllExitCode");
|
|
41197
42228
|
function formatPushFailureSummary(failedItems) {
|
|
41198
42229
|
if (failedItems.length === 0) return "";
|
|
41199
42230
|
const lines = [];
|
|
@@ -42331,6 +43362,7 @@ Until the backup catches up, \`lua init\` for this agent will restore an older s
|
|
|
42331
43362
|
pushedSomething,
|
|
42332
43363
|
failedCount: failedItems.length + deployFailedCount
|
|
42333
43364
|
});
|
|
43365
|
+
process.exitCode = pushAllExitCode(variant);
|
|
42334
43366
|
if (variant === "success") {
|
|
42335
43367
|
console.log("");
|
|
42336
43368
|
if (!options.suppressVersionCreateHint) {
|
|
@@ -42380,6 +43412,7 @@ init_command_utils();
|
|
|
42380
43412
|
|
|
42381
43413
|
// src/utils/deploy-helpers.ts
|
|
42382
43414
|
init_cli();
|
|
43415
|
+
init_cli_error();
|
|
42383
43416
|
import inquirer8 from "inquirer";
|
|
42384
43417
|
function formatVersionChoice(version) {
|
|
42385
43418
|
const currentIndicator = version.isCurrent ? " (CURRENT)" : "";
|
|
@@ -42428,6 +43461,10 @@ function formatDeploySuccess(params) {
|
|
|
42428
43461
|
return `\u2705 ${label2} "${name}" v${version} deployed successfully`;
|
|
42429
43462
|
}
|
|
42430
43463
|
__name(formatDeploySuccess, "formatDeploySuccess");
|
|
43464
|
+
function deployAllExitCode(failedCount) {
|
|
43465
|
+
return failedCount > 0 ? CLI_EXIT.ERROR : void 0;
|
|
43466
|
+
}
|
|
43467
|
+
__name(deployAllExitCode, "deployAllExitCode");
|
|
42431
43468
|
|
|
42432
43469
|
// src/commands/deploy.ts
|
|
42433
43470
|
init_constants();
|
|
@@ -42869,6 +43906,12 @@ async function deployAllCommand(_options) {
|
|
|
42869
43906
|
const versions = await deployConfig.getVersions(apiKey, agentId, entityId);
|
|
42870
43907
|
if (!versions || versions.length === 0) {
|
|
42871
43908
|
writeInfo(` \u2139\uFE0F No versions for ${deployConfig.label} "${entity.name}", skipping`);
|
|
43909
|
+
failedItems.push({
|
|
43910
|
+
kind: deployConfig.type,
|
|
43911
|
+
name: entity.name,
|
|
43912
|
+
error: `No versions found on the server for ${deployConfig.idField} "${entityId}" \u2014 push it first, or remove the stale id from lua.skill.yaml if it was deleted server-side`
|
|
43913
|
+
});
|
|
43914
|
+
failedCount++;
|
|
42872
43915
|
continue;
|
|
42873
43916
|
}
|
|
42874
43917
|
const latestVersion = sortVersionsByDate(versions)[0].version;
|
|
@@ -42985,6 +44028,7 @@ async function deployAllCommand(_options) {
|
|
|
42985
44028
|
when: "partial"
|
|
42986
44029
|
});
|
|
42987
44030
|
}
|
|
44031
|
+
process.exitCode = deployAllExitCode(failedCount);
|
|
42988
44032
|
}
|
|
42989
44033
|
__name(deployAllCommand, "deployAllCommand");
|
|
42990
44034
|
|
|
@@ -43816,6 +44860,7 @@ var LogsApi = class extends HttpClient {
|
|
|
43816
44860
|
if (filters.toolName) queryParams.append("toolName", filters.toolName);
|
|
43817
44861
|
if (filters.logType) queryParams.append("logType", filters.logType);
|
|
43818
44862
|
if (filters.userId) queryParams.append("userId", filters.userId);
|
|
44863
|
+
if (filters.channel) queryParams.append("channel", filters.channel);
|
|
43819
44864
|
if (filters.since) queryParams.append("since", filters.since);
|
|
43820
44865
|
if (filters.until) queryParams.append("until", filters.until);
|
|
43821
44866
|
if (filters.environment) queryParams.append("environment", filters.environment);
|
|
@@ -43881,6 +44926,14 @@ async function probeAgentErrorsSince(apiKey, agentId, sinceISO) {
|
|
|
43881
44926
|
}
|
|
43882
44927
|
__name(probeAgentErrorsSince, "probeAgentErrorsSince");
|
|
43883
44928
|
|
|
44929
|
+
// src/commands/chat-log-environment.ts
|
|
44930
|
+
function declaredLogEnvironment(session) {
|
|
44931
|
+
if (session.type !== "production") return void 0;
|
|
44932
|
+
if (session.previewVersion != null) return void 0;
|
|
44933
|
+
return "production";
|
|
44934
|
+
}
|
|
44935
|
+
__name(declaredLogEnvironment, "declaredLogEnvironment");
|
|
44936
|
+
|
|
43884
44937
|
// src/commands/chat.ts
|
|
43885
44938
|
init_cli_error();
|
|
43886
44939
|
async function runChatProbe(chatEnv, window) {
|
|
@@ -44323,6 +45376,10 @@ async function sendProductionMessageStream(chatEnv, messages, callbacks) {
|
|
|
44323
45376
|
if (chatEnv.previewVersion != null) {
|
|
44324
45377
|
chatRequest.version = chatEnv.previewVersion;
|
|
44325
45378
|
}
|
|
45379
|
+
const declared = declaredLogEnvironment(chatEnv);
|
|
45380
|
+
if (declared) {
|
|
45381
|
+
chatRequest.environment = declared;
|
|
45382
|
+
}
|
|
44326
45383
|
const chatApi = new ChatApi(BASE_URLS.CHAT, chatEnv.apiKey);
|
|
44327
45384
|
await chatApi.sendMessageStream(chatEnv.agentId, chatRequest, callbacks.onChunk, callbacks.onPostprocessComplete, callbacks.onPreprocessorBlocked, callbacks.onBatchAbort, callbacks.onBatchHandled);
|
|
44328
45385
|
}
|
|
@@ -47920,6 +48977,7 @@ async function logsCommand(cmdObj) {
|
|
|
47920
48977
|
pageGiven,
|
|
47921
48978
|
json: cmdObj?.json || false,
|
|
47922
48979
|
userId: cmdObj?.userId || null,
|
|
48980
|
+
channel: cmdObj?.channel || null,
|
|
47923
48981
|
agentId: cmdObj?.agentId || null,
|
|
47924
48982
|
direction: cmdObj?.direction || null,
|
|
47925
48983
|
status: cmdObj?.status || null,
|
|
@@ -47945,7 +49003,7 @@ async function logsCommand(cmdObj) {
|
|
|
47945
49003
|
return;
|
|
47946
49004
|
}
|
|
47947
49005
|
const logsApi = new LogsApi(BASE_URLS.API, apiKey);
|
|
47948
|
-
const hasNonInteractiveFlags = Boolean(options.type || options.name || options.json || options.userId || options.since || options.until || options.environment || options.follow);
|
|
49006
|
+
const hasNonInteractiveFlags = Boolean(options.type || options.name || options.json || options.userId || options.channel || options.since || options.until || options.environment || options.follow);
|
|
47949
49007
|
trackEvent("cli_logs_action", {
|
|
47950
49008
|
filter_type: options.type || null,
|
|
47951
49009
|
json_output: options.json || false,
|
|
@@ -48010,6 +49068,12 @@ async function listCallLogs(agentId, apiKey, options) {
|
|
|
48010
49068
|
}
|
|
48011
49069
|
}
|
|
48012
49070
|
__name(listCallLogs, "listCallLogs");
|
|
49071
|
+
function formatLogFields(fields) {
|
|
49072
|
+
if (!fields || typeof fields !== "object" || Array.isArray(fields)) return void 0;
|
|
49073
|
+
const pairs = Object.keys(fields).sort().map((key) => `${key}=${String(fields[key])}`);
|
|
49074
|
+
return pairs.length > 0 ? pairs.join(" ") : void 0;
|
|
49075
|
+
}
|
|
49076
|
+
__name(formatLogFields, "formatLogFields");
|
|
48013
49077
|
function renderLogEntry(log, isLast) {
|
|
48014
49078
|
const timestamp = new Date(log.timestamp).toLocaleString();
|
|
48015
49079
|
const logSource = log.metadata?.logSource;
|
|
@@ -48048,6 +49112,10 @@ function renderLogEntry(log, isLast) {
|
|
|
48048
49112
|
console.log(chalk2.gray(` Duration: ${log.duration}ms`));
|
|
48049
49113
|
}
|
|
48050
49114
|
console.log(` ${log.message}`);
|
|
49115
|
+
const fieldsLine = formatLogFields(log.metadata?.fields);
|
|
49116
|
+
if (fieldsLine) {
|
|
49117
|
+
console.log(chalk2.gray(` ${fieldsLine}`));
|
|
49118
|
+
}
|
|
48051
49119
|
if (!isLast) {
|
|
48052
49120
|
console.log(chalk2.gray(` ${"-".repeat(78)}`));
|
|
48053
49121
|
}
|
|
@@ -48289,6 +49357,9 @@ async function nonInteractiveLogs(logsApi, agentId, apiKey, options) {
|
|
|
48289
49357
|
if (options.userId) {
|
|
48290
49358
|
filters.userId = options.userId;
|
|
48291
49359
|
}
|
|
49360
|
+
if (options.channel) {
|
|
49361
|
+
filters.channel = options.channel;
|
|
49362
|
+
}
|
|
48292
49363
|
if (options.since) filters.since = options.since;
|
|
48293
49364
|
if (options.until) filters.until = options.until;
|
|
48294
49365
|
if (options.environment) filters.environment = options.environment;
|
|
@@ -48661,6 +49732,38 @@ function getLogColor(subType, logSource) {
|
|
|
48661
49732
|
}
|
|
48662
49733
|
__name(getLogColor, "getLogColor");
|
|
48663
49734
|
|
|
49735
|
+
// src/commands/logs.export.ts
|
|
49736
|
+
init_cli();
|
|
49737
|
+
init_cli_error();
|
|
49738
|
+
init_analytics();
|
|
49739
|
+
import { basename } from "path";
|
|
49740
|
+
import { existsSync as existsSync9, mkdirSync as mkdirSync8, writeFileSync as writeFileSync10 } from "fs";
|
|
49741
|
+
import { join as join9, resolve as resolvePath2 } from "path";
|
|
49742
|
+
init_constants();
|
|
49743
|
+
init_lua_fetch();
|
|
49744
|
+
|
|
49745
|
+
// src/api/log-export.api.service.ts
|
|
49746
|
+
init_http_client();
|
|
49747
|
+
var LogExportApi = class extends HttpClient {
|
|
49748
|
+
static {
|
|
49749
|
+
__name(this, "LogExportApi");
|
|
49750
|
+
}
|
|
49751
|
+
orgId;
|
|
49752
|
+
constructor(baseUrl, credential, orgId) {
|
|
49753
|
+
super(baseUrl, credential), this.orgId = orgId;
|
|
49754
|
+
}
|
|
49755
|
+
/** RELATIVE to `baseUrl` — every `HttpClient` verb prepends it itself. */
|
|
49756
|
+
base() {
|
|
49757
|
+
return `/admin/orgs/${encodeURIComponent(this.orgId)}/logs/export`;
|
|
49758
|
+
}
|
|
49759
|
+
async startExport(input) {
|
|
49760
|
+
return this.httpPost(this.base(), input);
|
|
49761
|
+
}
|
|
49762
|
+
async getExport(jobId) {
|
|
49763
|
+
return this.httpGet(`${this.base()}/${encodeURIComponent(jobId)}`);
|
|
49764
|
+
}
|
|
49765
|
+
};
|
|
49766
|
+
|
|
48664
49767
|
// src/commands/drains.ts
|
|
48665
49768
|
init_cli();
|
|
48666
49769
|
init_command_utils();
|
|
@@ -48715,6 +49818,15 @@ var DrainsApi = class extends HttpClient {
|
|
|
48715
49818
|
async verifyDrain(drainId) {
|
|
48716
49819
|
return this.httpPost(this.drainPath(drainId, "/verify"));
|
|
48717
49820
|
}
|
|
49821
|
+
/**
|
|
49822
|
+
* Settle a bucket ownership challenge (H4). Not `httpPostOnce`: confirming is
|
|
49823
|
+
* idempotent and answers the same `verifiedAt`, so a retried request is safe.
|
|
49824
|
+
*/
|
|
49825
|
+
async confirmChallenge(drainId, token) {
|
|
49826
|
+
return this.httpPost(this.drainPath(drainId, "/challenge/confirm"), {
|
|
49827
|
+
token
|
|
49828
|
+
});
|
|
49829
|
+
}
|
|
48718
49830
|
async pauseDrain(drainId, reason) {
|
|
48719
49831
|
return this.httpPost(this.drainPath(drainId, "/pause"), reason ? {
|
|
48720
49832
|
reason
|
|
@@ -48731,6 +49843,17 @@ var DrainsApi = class extends HttpClient {
|
|
|
48731
49843
|
const path26 = this.drainPath(drainId, `/rotate-secret${finalize ? "?finalize=true" : ""}`);
|
|
48732
49844
|
return finalize ? this.httpPost(path26, {}) : this.httpPostOnce(path26, {});
|
|
48733
49845
|
}
|
|
49846
|
+
/**
|
|
49847
|
+
* Re-enqueue one batch's records (PRO-2126).
|
|
49848
|
+
*
|
|
49849
|
+
* `httpPost`, not `httpPostOnce`: a replay is idempotent in the way that matters —
|
|
49850
|
+
* the second call finds the rows already `pending`, matches nothing and answers 409
|
|
49851
|
+
* — so a retried request cannot double-deliver. It DOES spend a second slot of the
|
|
49852
|
+
* per-drain budget, which is the price of a retry and not a correctness problem.
|
|
49853
|
+
*/
|
|
49854
|
+
async replayBatch(drainId, batchId) {
|
|
49855
|
+
return this.httpPost(this.drainPath(drainId, `/deliveries/${encodeURIComponent(batchId)}/replay`));
|
|
49856
|
+
}
|
|
48734
49857
|
async listDeliveries(drainId, opts = {}) {
|
|
48735
49858
|
const query = new URLSearchParams();
|
|
48736
49859
|
if (opts.limit !== void 0) query.set("limit", String(opts.limit));
|
|
@@ -48752,19 +49875,30 @@ var HEADER_NAME_PATTERN = /^[A-Za-z0-9-]{1,64}$/;
|
|
|
48752
49875
|
var ENDPOINT_TYPES = [
|
|
48753
49876
|
"http",
|
|
48754
49877
|
"otlp",
|
|
48755
|
-
"betterstack"
|
|
49878
|
+
"betterstack",
|
|
49879
|
+
"splunk",
|
|
49880
|
+
"loki",
|
|
49881
|
+
"axiom",
|
|
49882
|
+
"sumologic"
|
|
48756
49883
|
];
|
|
48757
49884
|
var SITE_TYPES = [
|
|
48758
|
-
"datadog"
|
|
48759
|
-
|
|
48760
|
-
var PHASE2_SOURCES = [
|
|
48761
|
-
"delivery",
|
|
48762
|
-
"trigger-execution",
|
|
48763
|
-
"job-execution",
|
|
48764
|
-
"workflow-run",
|
|
48765
|
-
"workflow-audit"
|
|
49885
|
+
"datadog",
|
|
49886
|
+
"newrelic"
|
|
48766
49887
|
];
|
|
48767
|
-
|
|
49888
|
+
function sitesFor(type) {
|
|
49889
|
+
return LOG_DRAIN_PRESET_SITES[type] ?? LOG_DRAIN_DATADOG_SITES;
|
|
49890
|
+
}
|
|
49891
|
+
__name(sitesFor, "sitesFor");
|
|
49892
|
+
function endpointHint(type) {
|
|
49893
|
+
const rule = LOG_DRAIN_PRESET_PATHS[type];
|
|
49894
|
+
if (!rule) return void 0;
|
|
49895
|
+
if (rule.segment === "dataset") return `the full ingest URL, ending in ${rule.path}/<dataset>${rule.suffix ?? ""}`;
|
|
49896
|
+
if (rule.segment === "token") return `the full HTTP Source URL, ending in ${rule.path}/<collector code>`;
|
|
49897
|
+
return `your host \u2014 ${rule.path} is appended for you`;
|
|
49898
|
+
}
|
|
49899
|
+
__name(endpointHint, "endpointHint");
|
|
49900
|
+
var UNAVAILABLE_SOURCES = [];
|
|
49901
|
+
var SELECTABLE_SOURCES = LOG_DRAIN_SOURCES.filter((source) => !UNAVAILABLE_SOURCES.includes(source));
|
|
48768
49902
|
var NON_CONTENT_SOURCES = SELECTABLE_SOURCES.filter((source) => !LOG_DRAIN_CONTENT_SOURCES.includes(source));
|
|
48769
49903
|
var TOKEN_ECHO_TYPES = [
|
|
48770
49904
|
"http"
|
|
@@ -48809,8 +49943,8 @@ __name(trimmed, "trimmed");
|
|
|
48809
49943
|
function parseType(raw) {
|
|
48810
49944
|
const value3 = trimmed(raw)?.toLowerCase();
|
|
48811
49945
|
if (!value3) return void 0;
|
|
48812
|
-
if (!
|
|
48813
|
-
throw CliError.usage(`--type "${raw}" is not
|
|
49946
|
+
if (!LOG_DRAIN_TYPES_IMPLEMENTED.includes(value3)) {
|
|
49947
|
+
throw CliError.usage(`--type "${raw}" is not a destination lua-cli knows how to address.`, listHint("Destinations", LOG_DRAIN_TYPES_IMPLEMENTED));
|
|
48814
49948
|
}
|
|
48815
49949
|
return value3;
|
|
48816
49950
|
}
|
|
@@ -49073,12 +50207,13 @@ async function resolveDestination(type, options) {
|
|
|
49073
50207
|
const endpoint = trimmed(options.endpoint);
|
|
49074
50208
|
const site = trimmed(options.site);
|
|
49075
50209
|
if (SITE_TYPES.includes(type)) {
|
|
50210
|
+
const sites = sitesFor(type);
|
|
49076
50211
|
if (endpoint) {
|
|
49077
|
-
throw CliError.usage(`--endpoint is not accepted for ${type}: its URL is derived from --site.`, listHint("Sites",
|
|
50212
|
+
throw CliError.usage(`--endpoint is not accepted for ${type}: its URL is derived from --site.`, listHint("Sites", sites));
|
|
49078
50213
|
}
|
|
49079
|
-
const chosen = site ?? await promptChoice("Which site?",
|
|
49080
|
-
if (!
|
|
49081
|
-
throw CliError.usage(`--site "${chosen}" is not a ${type} site.`, listHint("Sites",
|
|
50214
|
+
const chosen = site ?? await promptChoice("Which site?", sites, "--site", `${type}`);
|
|
50215
|
+
if (!sites.includes(chosen)) {
|
|
50216
|
+
throw CliError.usage(`--site "${chosen}" is not a ${type} site.`, listHint("Sites", sites));
|
|
49082
50217
|
}
|
|
49083
50218
|
return {
|
|
49084
50219
|
site: chosen
|
|
@@ -49090,12 +50225,108 @@ async function resolveDestination(type, options) {
|
|
|
49090
50225
|
if (site) {
|
|
49091
50226
|
throw CliError.usage(`--site is not accepted for ${type}: give the destination URL with --endpoint.`);
|
|
49092
50227
|
}
|
|
49093
|
-
const
|
|
50228
|
+
const hint = endpointHint(type);
|
|
50229
|
+
const url = endpoint ?? await promptText(type === "otlp" ? "OTLP logs endpoint (the full /v1/logs URL):" : "Destination URL:", "--endpoint", hint ?? `${type} sends to your own URL`);
|
|
49094
50230
|
return {
|
|
49095
50231
|
endpoint: url
|
|
49096
50232
|
};
|
|
49097
50233
|
}
|
|
49098
50234
|
__name(resolveDestination, "resolveDestination");
|
|
50235
|
+
var BUCKET_PROVIDERS = [
|
|
50236
|
+
"aws",
|
|
50237
|
+
"r2",
|
|
50238
|
+
"gcs"
|
|
50239
|
+
];
|
|
50240
|
+
function parseProvider(raw) {
|
|
50241
|
+
const value3 = trimmed(raw)?.toLowerCase() ?? "aws";
|
|
50242
|
+
if (!BUCKET_PROVIDERS.includes(value3)) {
|
|
50243
|
+
throw CliError.usage(`--provider "${raw}" is not an object store.`, listHint("Valid values", BUCKET_PROVIDERS));
|
|
50244
|
+
}
|
|
50245
|
+
return value3;
|
|
50246
|
+
}
|
|
50247
|
+
__name(parseProvider, "parseProvider");
|
|
50248
|
+
function resolveBucketCredentials(options) {
|
|
50249
|
+
const roleArn = trimmed(options.roleArn);
|
|
50250
|
+
const spec = trimmed(options.credentialsFromEnv);
|
|
50251
|
+
if (roleArn && spec) {
|
|
50252
|
+
throw CliError.usage("Give either --role-arn or --credentials-from-env, not both.", "A role is assumed at send time; a key pair is stored. One drain uses one of them.");
|
|
50253
|
+
}
|
|
50254
|
+
if (roleArn) {
|
|
50255
|
+
return {
|
|
50256
|
+
roleArn,
|
|
50257
|
+
...trimmed(options.externalId) ? {
|
|
50258
|
+
externalId: trimmed(options.externalId)
|
|
50259
|
+
} : {}
|
|
50260
|
+
};
|
|
50261
|
+
}
|
|
50262
|
+
if (!spec) return void 0;
|
|
50263
|
+
const eq3 = spec.indexOf("=");
|
|
50264
|
+
if (eq3 === -1) {
|
|
50265
|
+
throw CliError.usage(`--credentials-from-env "${spec}" must read <KEY_ID_VAR>=<SECRET_VAR>.`, "Both values stay in the environment \u2014 e.g. --credentials-from-env AWS_KEY_ID=AWS_SECRET");
|
|
50266
|
+
}
|
|
50267
|
+
const keyVar = spec.slice(0, eq3).trim();
|
|
50268
|
+
const secretVar = spec.slice(eq3 + 1).trim();
|
|
50269
|
+
if (!keyVar || !secretVar) {
|
|
50270
|
+
throw CliError.usage(`--credentials-from-env "${spec}" must name two environment variables.`);
|
|
50271
|
+
}
|
|
50272
|
+
const accessKeyId = process.env[keyVar];
|
|
50273
|
+
const secretAccessKey = process.env[secretVar];
|
|
50274
|
+
for (const [variable, value3] of [
|
|
50275
|
+
[
|
|
50276
|
+
keyVar,
|
|
50277
|
+
accessKeyId
|
|
50278
|
+
],
|
|
50279
|
+
[
|
|
50280
|
+
secretVar,
|
|
50281
|
+
secretAccessKey
|
|
50282
|
+
]
|
|
50283
|
+
]) {
|
|
50284
|
+
if (!value3) {
|
|
50285
|
+
throw CliError.usage(`--credentials-from-env ${keyVar}=${secretVar}: the environment variable ${variable} is unset or empty.`, "Export it in the shell or the CI job that runs this command");
|
|
50286
|
+
}
|
|
50287
|
+
}
|
|
50288
|
+
return {
|
|
50289
|
+
accessKeyId,
|
|
50290
|
+
secretAccessKey
|
|
50291
|
+
};
|
|
50292
|
+
}
|
|
50293
|
+
__name(resolveBucketCredentials, "resolveBucketCredentials");
|
|
50294
|
+
async function resolveBucket(options) {
|
|
50295
|
+
const provider = parseProvider(options.provider);
|
|
50296
|
+
const endpoint = trimmed(options.endpoint);
|
|
50297
|
+
if (provider === "aws" && endpoint) {
|
|
50298
|
+
throw CliError.usage("--endpoint is not accepted for an aws bucket: its URL is derived from --bucket and --region.", "Use --endpoint only for --provider r2 or gcs");
|
|
50299
|
+
}
|
|
50300
|
+
const bucket = trimmed(options.bucket) ?? await promptText("Bucket name:", "--bucket", "the bucket to write to");
|
|
50301
|
+
const region = trimmed(options.region) ?? await promptText("Region:", "--region", provider === "r2" ? "R2 uses 'auto'" : "the bucket's region");
|
|
50302
|
+
const host = provider === "aws" ? void 0 : endpoint ?? await promptText("S3-compatible endpoint:", "--endpoint", provider === "r2" ? "https://<account>.r2.cloudflarestorage.com" : "https://storage.googleapis.com");
|
|
50303
|
+
return {
|
|
50304
|
+
provider,
|
|
50305
|
+
bucket,
|
|
50306
|
+
region,
|
|
50307
|
+
...trimmed(options.prefix) ? {
|
|
50308
|
+
prefix: trimmed(options.prefix)
|
|
50309
|
+
} : {},
|
|
50310
|
+
...host ? {
|
|
50311
|
+
endpoint: host
|
|
50312
|
+
} : {},
|
|
50313
|
+
...resolveBucketCredentials(options) ? {
|
|
50314
|
+
credentials: resolveBucketCredentials(options)
|
|
50315
|
+
} : {}
|
|
50316
|
+
};
|
|
50317
|
+
}
|
|
50318
|
+
__name(resolveBucket, "resolveBucket");
|
|
50319
|
+
async function confirmChallengeCore(context, drainId, options) {
|
|
50320
|
+
const token = trimmed(options.token) ?? await promptText("Token from the _lua-verify-<token> object in your bucket:", "--token", "list your prefix for _lua-verify-* to find it");
|
|
50321
|
+
const result = await drainsCall(() => drainsApiFor(context).confirmChallenge(drainId, token));
|
|
50322
|
+
if (options.json) {
|
|
50323
|
+
printJson(result);
|
|
50324
|
+
return;
|
|
50325
|
+
}
|
|
50326
|
+
writeSuccess(`\u2705 Ownership confirmed for ${drainId}`);
|
|
50327
|
+
writeInfo(` verified at ${result.verifiedAt}`);
|
|
50328
|
+
}
|
|
50329
|
+
__name(confirmChallengeCore, "confirmChallengeCore");
|
|
49099
50330
|
function verificationCurl(type, endpoint, headers) {
|
|
49100
50331
|
const target = endpoint ?? "<your endpoint>";
|
|
49101
50332
|
const headerArgs = headers.map((header) => header.fromEnv ? ` -H "${header.name}: $${header.fromEnv}" \\` : ` -H '${header.name}: <the value you entered>' \\`);
|
|
@@ -49116,11 +50347,37 @@ function verificationCurl(type, endpoint, headers) {
|
|
|
49116
50347
|
];
|
|
49117
50348
|
}
|
|
49118
50349
|
__name(verificationCurl, "verificationCurl");
|
|
50350
|
+
function bucketVerificationInstructions(drain, json) {
|
|
50351
|
+
const prefix = drain.bucket?.prefix;
|
|
50352
|
+
const where = prefix ? `${prefix}/_lua-verify-*` : "_lua-verify-*";
|
|
50353
|
+
const bucket = drain.bucket?.bucket ?? "<your bucket>";
|
|
50354
|
+
const endpointArg = drain.bucket?.endpoint ? ` --endpoint-url '${drain.bucket.endpoint}'` : "";
|
|
50355
|
+
emitAside("Lua writes a challenge object into the bucket itself \u2014 nothing is POSTed to a URL.", json);
|
|
50356
|
+
emitAside("Check the credentials can write under the prefix first:", json);
|
|
50357
|
+
emitAside("", json);
|
|
50358
|
+
emitAside(` aws s3 cp - 's3://${bucket}/${prefix ? `${prefix}/` : ""}_lua-write-check'${endpointArg} </dev/null`, json);
|
|
50359
|
+
emitAside("", json);
|
|
50360
|
+
emitAside(" (a zero-byte object, yours to delete \u2014 a write-only role cannot remove it itself)", json);
|
|
50361
|
+
emitAside("", json);
|
|
50362
|
+
emitAside(`Then: lua drains verify ${drain.id}`, json);
|
|
50363
|
+
emitAside("", json);
|
|
50364
|
+
emitAside("That is what mints the challenge, and how it settles depends on the role:", json);
|
|
50365
|
+
emitAside(" \xB7 with s3:GetObject, Lua reads the object back and 'verify' finishes on its own;", json);
|
|
50366
|
+
emitAside(" \xB7 write-only \u2014 the grant we recommend \u2014 leaves the claim open. List the prefix", json);
|
|
50367
|
+
emitAside(` for ${where}, take the <token> off the object name, and run:`, json);
|
|
50368
|
+
emitAside("", json);
|
|
50369
|
+
emitAside(` lua drains confirm ${drain.id} --token <token>`, json);
|
|
50370
|
+
}
|
|
50371
|
+
__name(bucketVerificationInstructions, "bucketVerificationInstructions");
|
|
49119
50372
|
function verificationInstructions(drain, headers, options) {
|
|
49120
50373
|
const type = drain.type;
|
|
49121
50374
|
const json = options.json;
|
|
49122
50375
|
emitAside("", json);
|
|
49123
50376
|
emitAside("Before anything is delivered, Lua has to confirm you own this destination.", json);
|
|
50377
|
+
if (type === "s3") {
|
|
50378
|
+
bucketVerificationInstructions(drain, json);
|
|
50379
|
+
return;
|
|
50380
|
+
}
|
|
49124
50381
|
if (TOKEN_ECHO_TYPES.includes(type)) {
|
|
49125
50382
|
emitAside("Lua POSTs one record carrying an X-Lua-Verify header; your receiver must answer 2xx AND", json);
|
|
49126
50383
|
emitAside("repeat that header back on the response. Check yours first:", json);
|
|
@@ -49136,8 +50393,9 @@ function verificationInstructions(drain, headers, options) {
|
|
|
49136
50393
|
__name(verificationInstructions, "verificationInstructions");
|
|
49137
50394
|
async function createDrainCore(context, options) {
|
|
49138
50395
|
const name = trimmed(options.name) ?? await promptText("Drain name:", "--name", "1\u201364 chars, unique per org");
|
|
49139
|
-
const type = parseType(options.type) ?? await promptChoice("Where should the logs go?",
|
|
49140
|
-
const
|
|
50396
|
+
const type = parseType(options.type) ?? await promptChoice("Where should the logs go?", LOG_DRAIN_TYPES_IMPLEMENTED, "--type", "the destination kind");
|
|
50397
|
+
const bucket = type === "s3" ? await resolveBucket(options) : void 0;
|
|
50398
|
+
const destination = bucket ? {} : await resolveDestination(type, options);
|
|
49141
50399
|
const format = parseFormat(options.format);
|
|
49142
50400
|
const headers = await resolveHeaders(options);
|
|
49143
50401
|
const flagSources = parseSources(options.sources);
|
|
@@ -49159,6 +50417,9 @@ async function createDrainCore(context, options) {
|
|
|
49159
50417
|
...destination.site ? {
|
|
49160
50418
|
site: destination.site
|
|
49161
50419
|
} : {},
|
|
50420
|
+
...bucket ? {
|
|
50421
|
+
bucket
|
|
50422
|
+
} : {},
|
|
49162
50423
|
...format ? {
|
|
49163
50424
|
format
|
|
49164
50425
|
} : {},
|
|
@@ -49211,6 +50472,14 @@ async function createDrainCore(context, options) {
|
|
|
49211
50472
|
label: "Verify",
|
|
49212
50473
|
command: `lua drains verify ${drain.id}`
|
|
49213
50474
|
},
|
|
50475
|
+
// W4-D3: on a bucket drain the step after `verify` is `confirm`, not `test` —
|
|
50476
|
+
// a write-only role (the recommended grant) cannot settle its own claim.
|
|
50477
|
+
...drain.type === "s3" ? [
|
|
50478
|
+
{
|
|
50479
|
+
label: "Settle the challenge",
|
|
50480
|
+
command: `lua drains confirm ${drain.id} --token <token>`
|
|
50481
|
+
}
|
|
50482
|
+
] : [],
|
|
49214
50483
|
{
|
|
49215
50484
|
label: "Send one record",
|
|
49216
50485
|
command: `lua drains test ${drain.id}`
|
|
@@ -49526,6 +50795,30 @@ async function rotateSecretCore(context, drainId, options) {
|
|
|
49526
50795
|
});
|
|
49527
50796
|
}
|
|
49528
50797
|
__name(rotateSecretCore, "rotateSecretCore");
|
|
50798
|
+
async function replayDrainCore(context, drainId, batchId, options) {
|
|
50799
|
+
const replayed = await drainsCall(() => drainsApiFor(context).replayBatch(drainId, batchId));
|
|
50800
|
+
if (options.json) {
|
|
50801
|
+
printJson({
|
|
50802
|
+
replayOf: replayed.replayOf,
|
|
50803
|
+
records: replayed.records,
|
|
50804
|
+
enqueuedAt: replayed.enqueuedAt
|
|
50805
|
+
});
|
|
50806
|
+
return;
|
|
50807
|
+
}
|
|
50808
|
+
const records = replayed.records === 1 ? "1 record" : `${replayed.records} records`;
|
|
50809
|
+
writeSuccess(`\u2705 Re-enqueued ${records} from batch ${replayed.replayOf}`);
|
|
50810
|
+
writeInfo(" They go out in a NEW batch with a new id; delivery is asynchronous.");
|
|
50811
|
+
writeHintBlock({
|
|
50812
|
+
headline: "Watch for it:",
|
|
50813
|
+
lines: [
|
|
50814
|
+
{
|
|
50815
|
+
label: "Attempts",
|
|
50816
|
+
command: `lua drains deliveries ${drainId} --kind batch`
|
|
50817
|
+
}
|
|
50818
|
+
]
|
|
50819
|
+
});
|
|
50820
|
+
}
|
|
50821
|
+
__name(replayDrainCore, "replayDrainCore");
|
|
49529
50822
|
|
|
49530
50823
|
// src/commands/drains.ts
|
|
49531
50824
|
var DRAIN_ACTIONS = [
|
|
@@ -49537,8 +50830,10 @@ var DRAIN_ACTIONS = [
|
|
|
49537
50830
|
"delete",
|
|
49538
50831
|
"test",
|
|
49539
50832
|
"verify",
|
|
50833
|
+
"confirm",
|
|
49540
50834
|
"pause",
|
|
49541
50835
|
"resume",
|
|
50836
|
+
"replay",
|
|
49542
50837
|
"rotate-secret"
|
|
49543
50838
|
];
|
|
49544
50839
|
var MISSING_SCOPE_MESSAGE = "Missing scope: logs:manage. Create a key with that scope (lua auth key) or ask an org admin.";
|
|
@@ -49554,6 +50849,8 @@ var DELIVERY_KINDS = [
|
|
|
49554
50849
|
var DEFAULT_DELIVERY_LIMIT = 20;
|
|
49555
50850
|
var MAX_DELIVERY_LIMIT = 100;
|
|
49556
50851
|
var MAX_TABLE_WIDTH = 100;
|
|
50852
|
+
var DRAIN_ID_PREFIX = "drn_";
|
|
50853
|
+
var MAX_LISTED_DRAINS = 10;
|
|
49557
50854
|
async function resolveDrainsContext(options) {
|
|
49558
50855
|
const apiKey = await requireAuth();
|
|
49559
50856
|
const flagOrg = typeof options.org === "string" ? options.org.trim() : "";
|
|
@@ -49611,6 +50908,25 @@ async function drainsCall(call) {
|
|
|
49611
50908
|
throw CliError.fromStatus(response.error?.statusCode, drainRefusalMessage(response.error), void 0, apiErrorDetail(response.error));
|
|
49612
50909
|
}
|
|
49613
50910
|
__name(drainsCall, "drainsCall");
|
|
50911
|
+
function identify(drain) {
|
|
50912
|
+
return `${drain.id} \u2014 ${drain.name}`;
|
|
50913
|
+
}
|
|
50914
|
+
__name(identify, "identify");
|
|
50915
|
+
async function resolveDrainRef(context, ref, options = {}) {
|
|
50916
|
+
const wanted = `${ref ?? ""}`.trim();
|
|
50917
|
+
if (wanted.startsWith(DRAIN_ID_PREFIX)) return wanted;
|
|
50918
|
+
const drains = (await drainsCall(() => drainsApiFor(context).listDrains())).drains ?? [];
|
|
50919
|
+
const matches = drains.filter((drain) => drain.name === wanted);
|
|
50920
|
+
if (matches.length === 1) {
|
|
50921
|
+
if (!options.json) writeInfo(`\u{1F6B0} ${wanted} \u2192 ${matches[0].id}`);
|
|
50922
|
+
return matches[0].id;
|
|
50923
|
+
}
|
|
50924
|
+
if (matches.length > 1) {
|
|
50925
|
+
throw CliError.usage(`${matches.length} log drains in ${context.orgId} are named "${wanted}" \u2014 address one by id.`, listHint("Matching drains", matches.map(identify)));
|
|
50926
|
+
}
|
|
50927
|
+
throw CliError.usage(`No log drain named "${wanted}" in ${context.orgId}.`, joinHint(`A drain is addressed by its id (${DRAIN_ID_PREFIX}\u2026) or by its exact name`, drains.length > 0 ? listHint("Drains", drains.slice(0, MAX_LISTED_DRAINS).map(identify)) : void 0, drains.length > MAX_LISTED_DRAINS && "Run lua drains list for the rest", drains.length === 0 && "This organization has no log drains \u2014 lua drains create"));
|
|
50928
|
+
}
|
|
50929
|
+
__name(resolveDrainRef, "resolveDrainRef");
|
|
49614
50930
|
function printJson2(payload) {
|
|
49615
50931
|
console.log(JSON.stringify(payload, null, 2));
|
|
49616
50932
|
}
|
|
@@ -49730,8 +51046,8 @@ function quotaRatio(drain) {
|
|
|
49730
51046
|
const quota = drain.quota;
|
|
49731
51047
|
if (!quota || !quota.eventsPerDay) return "\u2014";
|
|
49732
51048
|
const ratio = quota.eventsPerDay > 0 ? (quota.usedEvents ?? 0) / quota.eventsPerDay : 0;
|
|
49733
|
-
const
|
|
49734
|
-
return quota.degradation && quota.degradation !== "none" ? `${
|
|
51049
|
+
const percent2 = Math.round(ratio * 1e3) / 10;
|
|
51050
|
+
return quota.degradation && quota.degradation !== "none" ? `${percent2}% ${quota.degradation}` : `${percent2}%`;
|
|
49735
51051
|
}
|
|
49736
51052
|
__name(quotaRatio, "quotaRatio");
|
|
49737
51053
|
function printDrainDetail(drain) {
|
|
@@ -49778,6 +51094,13 @@ function printDrainDetail(drain) {
|
|
|
49778
51094
|
"verifiedAt",
|
|
49779
51095
|
shortIso2(drain.verifiedAt)
|
|
49780
51096
|
],
|
|
51097
|
+
// PRO-2120 (G5-04). `verifiedAt` alone says WHEN, never WHAT — and for a vendor
|
|
51098
|
+
// preset on a host the customer supplied, what was proved is reachability, not
|
|
51099
|
+
// ownership. Absent (every drain verified before this shipped) reads the same way.
|
|
51100
|
+
[
|
|
51101
|
+
"ownership",
|
|
51102
|
+
drain.verification?.ownership ?? "reachability-only"
|
|
51103
|
+
],
|
|
49781
51104
|
[
|
|
49782
51105
|
"lastSuccessAt",
|
|
49783
51106
|
shortIso2(health.lastSuccessAt)
|
|
@@ -49937,7 +51260,9 @@ async function listDrainsCore(context, options) {
|
|
|
49937
51260
|
});
|
|
49938
51261
|
}
|
|
49939
51262
|
__name(listDrainsCore, "listDrainsCore");
|
|
49940
|
-
async function statusDrainsCore(context,
|
|
51263
|
+
async function statusDrainsCore(context, drainRef, options) {
|
|
51264
|
+
const wanted = `${drainRef ?? ""}`.trim();
|
|
51265
|
+
const drainId = wanted ? await resolveDrainRef(context, wanted, options) : void 0;
|
|
49941
51266
|
const api = drainsApiFor(context);
|
|
49942
51267
|
const drains = drainId ? [
|
|
49943
51268
|
await drainsCall(() => api.getDrain(drainId))
|
|
@@ -49972,9 +51297,10 @@ async function statusDrainsCore(context, drainId, options) {
|
|
|
49972
51297
|
}
|
|
49973
51298
|
}
|
|
49974
51299
|
__name(statusDrainsCore, "statusDrainsCore");
|
|
49975
|
-
async function deliveriesCore(context,
|
|
51300
|
+
async function deliveriesCore(context, drainRef, options) {
|
|
49976
51301
|
const limit = parseLimit(options.limit);
|
|
49977
51302
|
const kind = parseKind(options.kind);
|
|
51303
|
+
const drainId = await resolveDrainRef(context, drainRef, options);
|
|
49978
51304
|
const page = await drainsCall(() => drainsApiFor(context).listDeliveries(drainId, {
|
|
49979
51305
|
limit,
|
|
49980
51306
|
...kind ? {
|
|
@@ -50014,17 +51340,25 @@ function parseKind(raw) {
|
|
|
50014
51340
|
return kind;
|
|
50015
51341
|
}
|
|
50016
51342
|
__name(parseKind, "parseKind");
|
|
50017
|
-
async function drainsCommand(action, drainId, cmdObj) {
|
|
51343
|
+
async function drainsCommand(action, drainId, batchIdOrOptions, cmdObj) {
|
|
51344
|
+
const batchId = typeof batchIdOrOptions === "string" ? batchIdOrOptions : void 0;
|
|
51345
|
+
const resolvedOptions = batchIdOrOptions && typeof batchIdOrOptions === "object" ? batchIdOrOptions : cmdObj;
|
|
50018
51346
|
return withErrorHandling(
|
|
50019
51347
|
async () => {
|
|
50020
|
-
const options =
|
|
51348
|
+
const options = resolvedOptions ?? {};
|
|
50021
51349
|
const verb = action ? validateOrSuggest("drains.action", action) : "list";
|
|
50022
|
-
const needsId = /* @__PURE__ */ __name((v) => v === "deliveries" || v === "update" || v === "delete" || v === "test" || v === "verify" || v === "pause" || v === "resume" || v === "rotate-secret", "needsId");
|
|
51350
|
+
const needsId = /* @__PURE__ */ __name((v) => v === "deliveries" || v === "update" || v === "delete" || v === "test" || v === "verify" || v === "confirm" || v === "pause" || v === "resume" || v === "replay" || v === "rotate-secret", "needsId");
|
|
50023
51351
|
if (needsId(verb) && !drainId) {
|
|
50024
|
-
|
|
51352
|
+
const takesName = verb === "deliveries";
|
|
51353
|
+
throw CliError.usage(`lua drains ${verb} needs a drain id${takesName ? " or name" : ""}.`, listHint("Run", [
|
|
50025
51354
|
"lua drains list"
|
|
50026
51355
|
]));
|
|
50027
51356
|
}
|
|
51357
|
+
if (verb === "replay" && !batchId) {
|
|
51358
|
+
throw CliError.usage("lua drains replay needs a drain id and a batch id.", listHint("Find one", [
|
|
51359
|
+
`lua drains deliveries ${drainId ?? "<drain id>"} --kind batch`
|
|
51360
|
+
]));
|
|
51361
|
+
}
|
|
50028
51362
|
const context = await resolveDrainsContext(options);
|
|
50029
51363
|
switch (verb) {
|
|
50030
51364
|
case "list":
|
|
@@ -50051,12 +51385,18 @@ async function drainsCommand(action, drainId, cmdObj) {
|
|
|
50051
51385
|
case "verify":
|
|
50052
51386
|
await verifyDrainCore(context, drainId, options);
|
|
50053
51387
|
break;
|
|
51388
|
+
case "confirm":
|
|
51389
|
+
await confirmChallengeCore(context, drainId, options);
|
|
51390
|
+
break;
|
|
50054
51391
|
case "pause":
|
|
50055
51392
|
await pauseDrainCore(context, drainId, options);
|
|
50056
51393
|
break;
|
|
50057
51394
|
case "resume":
|
|
50058
51395
|
await resumeDrainCore(context, drainId, options);
|
|
50059
51396
|
break;
|
|
51397
|
+
case "replay":
|
|
51398
|
+
await replayDrainCore(context, drainId, batchId, options);
|
|
51399
|
+
break;
|
|
50060
51400
|
case "rotate-secret":
|
|
50061
51401
|
await rotateSecretCore(context, drainId, options);
|
|
50062
51402
|
break;
|
|
@@ -50078,6 +51418,207 @@ async function drainsCommand(action, drainId, cmdObj) {
|
|
|
50078
51418
|
}
|
|
50079
51419
|
__name(drainsCommand, "drainsCommand");
|
|
50080
51420
|
|
|
51421
|
+
// src/commands/logs.export.ts
|
|
51422
|
+
var LOG_EXPORT_POLL = {
|
|
51423
|
+
/** First delay; doubles to `maxIntervalMs`. */
|
|
51424
|
+
intervalMs: 2e3,
|
|
51425
|
+
maxIntervalMs: 15e3,
|
|
51426
|
+
/** Polls before the command gives up and prints how to resume. */
|
|
51427
|
+
maxAttempts: 240,
|
|
51428
|
+
sleep: /* @__PURE__ */ __name((ms) => new Promise((resolve7) => setTimeout(resolve7, ms)), "sleep")
|
|
51429
|
+
};
|
|
51430
|
+
var LOG_EXPORT_DOWNLOAD = {
|
|
51431
|
+
fetchBytes: /* @__PURE__ */ __name(async (url) => {
|
|
51432
|
+
const res = await luaFetch(url);
|
|
51433
|
+
if (!res.ok) throw new Error(`download failed: HTTP ${res.status}`);
|
|
51434
|
+
return Buffer.from(await res.arrayBuffer());
|
|
51435
|
+
}, "fetchBytes")
|
|
51436
|
+
};
|
|
51437
|
+
var ALREADY_RUNNING = "EXPORT_ALREADY_RUNNING";
|
|
51438
|
+
var MISSING_EXPORT_SCOPE_MESSAGE = "Missing scope: logs:read. Create a key with that scope (lua auth key) or ask an org admin.";
|
|
51439
|
+
var TERMINAL2 = /* @__PURE__ */ new Set([
|
|
51440
|
+
"succeeded",
|
|
51441
|
+
"failed",
|
|
51442
|
+
"expired"
|
|
51443
|
+
]);
|
|
51444
|
+
async function logsExportCommand(cmdObj) {
|
|
51445
|
+
return withErrorHandling(
|
|
51446
|
+
async () => {
|
|
51447
|
+
const options = cmdObj ?? {};
|
|
51448
|
+
const since = options.since ? parseWindowBound("--since", String(options.since)) : void 0;
|
|
51449
|
+
const until = options.until ? parseWindowBound("--until", String(options.until)) : void 0;
|
|
51450
|
+
if (!since) {
|
|
51451
|
+
throw CliError.usage("logs export: --since <when> is required", "An ISO 8601 instant, or a relative form such as 24h or 7d");
|
|
51452
|
+
}
|
|
51453
|
+
const sources = parseTypeFlag(options.type);
|
|
51454
|
+
const outDir = options.out ? resolveOutDir(String(options.out)) : void 0;
|
|
51455
|
+
const context = await resolveDrainsContext(options);
|
|
51456
|
+
const api = new LogExportApi(BASE_URLS.API, context.apiKey, context.orgId);
|
|
51457
|
+
const say = /* @__PURE__ */ __name((line) => {
|
|
51458
|
+
if (!options.json) writeProgress(line);
|
|
51459
|
+
}, "say");
|
|
51460
|
+
const jobId = await startOrAttach(api, {
|
|
51461
|
+
from: since,
|
|
51462
|
+
to: until ?? (/* @__PURE__ */ new Date()).toISOString(),
|
|
51463
|
+
sources
|
|
51464
|
+
}, say);
|
|
51465
|
+
if (options.noWait || options.wait === false) {
|
|
51466
|
+
emit2(options, {
|
|
51467
|
+
jobId,
|
|
51468
|
+
state: "queued",
|
|
51469
|
+
files: []
|
|
51470
|
+
});
|
|
51471
|
+
trackEvent("cli_logs_export", {
|
|
51472
|
+
waited: false,
|
|
51473
|
+
json_output: !!options.json,
|
|
51474
|
+
downloaded: 0
|
|
51475
|
+
});
|
|
51476
|
+
return;
|
|
51477
|
+
}
|
|
51478
|
+
const job = await pollToTerminal(api, jobId, say);
|
|
51479
|
+
if (job.state === "failed") {
|
|
51480
|
+
throw CliError.fromStatus(500, `The export failed: ${job.error ?? "no reason recorded"}`);
|
|
51481
|
+
}
|
|
51482
|
+
if (job.state === "expired") {
|
|
51483
|
+
throw CliError.fromStatus(410, "The export expired before it could be downloaded.");
|
|
51484
|
+
}
|
|
51485
|
+
const written = outDir ? await downloadParts(job, outDir, say) : [];
|
|
51486
|
+
emit2(options, {
|
|
51487
|
+
jobId,
|
|
51488
|
+
state: job.state,
|
|
51489
|
+
files: job.files,
|
|
51490
|
+
written,
|
|
51491
|
+
truncated: job.truncated
|
|
51492
|
+
});
|
|
51493
|
+
if (!options.json) {
|
|
51494
|
+
writeInfo(`Export ${jobId}: ${job.counts.rows} record(s) in ${job.files.length} file(s)` + (job.truncated ? " (TRUNCATED \u2014 the row cap was reached; narrow the window)" : ""));
|
|
51495
|
+
if (!outDir && job.files.length) {
|
|
51496
|
+
writeHintBlock({
|
|
51497
|
+
headline: `${job.files.length} part(s) are ready for 24 h`,
|
|
51498
|
+
lines: [
|
|
51499
|
+
{
|
|
51500
|
+
label: "Download them",
|
|
51501
|
+
command: `lua logs export --since ${options.since} --out ./export`
|
|
51502
|
+
},
|
|
51503
|
+
{
|
|
51504
|
+
label: "Read the signed URLs",
|
|
51505
|
+
command: `lua logs export --since ${options.since} --json`
|
|
51506
|
+
}
|
|
51507
|
+
]
|
|
51508
|
+
});
|
|
51509
|
+
}
|
|
51510
|
+
}
|
|
51511
|
+
trackEvent("cli_logs_export", {
|
|
51512
|
+
waited: true,
|
|
51513
|
+
json_output: !!options.json,
|
|
51514
|
+
downloaded: written.length,
|
|
51515
|
+
truncated: !!job.truncated
|
|
51516
|
+
});
|
|
51517
|
+
},
|
|
51518
|
+
"logs export",
|
|
51519
|
+
// LUA-803: a refusal that escapes under `--json` is the typed envelope on stdout.
|
|
51520
|
+
{
|
|
51521
|
+
json: /* @__PURE__ */ __name(() => !!cmdObj?.json, "json")
|
|
51522
|
+
}
|
|
51523
|
+
);
|
|
51524
|
+
}
|
|
51525
|
+
__name(logsExportCommand, "logsExportCommand");
|
|
51526
|
+
function parseTypeFlag(raw) {
|
|
51527
|
+
const value3 = typeof raw === "string" ? raw.trim() : "";
|
|
51528
|
+
if (!value3 || value3 === "all") return void 0;
|
|
51529
|
+
return value3.split(",").map((one) => one.trim()).filter(Boolean).map((one) => validateOrSuggest("logs.type", one));
|
|
51530
|
+
}
|
|
51531
|
+
__name(parseTypeFlag, "parseTypeFlag");
|
|
51532
|
+
function resolveOutDir(raw) {
|
|
51533
|
+
if (/^[a-z][a-z0-9+.-]*:\/\//i.test(raw)) {
|
|
51534
|
+
throw CliError.usage(`logs export: --out must be a local directory, not ${raw}`);
|
|
51535
|
+
}
|
|
51536
|
+
const dir = resolvePath2(raw);
|
|
51537
|
+
if (!existsSync9(dir)) mkdirSync8(dir, {
|
|
51538
|
+
recursive: true
|
|
51539
|
+
});
|
|
51540
|
+
return dir;
|
|
51541
|
+
}
|
|
51542
|
+
__name(resolveOutDir, "resolveOutDir");
|
|
51543
|
+
async function startOrAttach(api, input, say) {
|
|
51544
|
+
const body = {
|
|
51545
|
+
from: input.from,
|
|
51546
|
+
to: input.to,
|
|
51547
|
+
...input.sources ? {
|
|
51548
|
+
sources: input.sources
|
|
51549
|
+
} : {}
|
|
51550
|
+
};
|
|
51551
|
+
const started = await callExport(() => api.startExport(body));
|
|
51552
|
+
if (started.success && started.data?.jobId) {
|
|
51553
|
+
say(`Export ${started.data.jobId} queued`);
|
|
51554
|
+
return started.data.jobId;
|
|
51555
|
+
}
|
|
51556
|
+
if (started.error?.code === ALREADY_RUNNING) {
|
|
51557
|
+
const running = /\b(lex_[0-9a-f]{24})\b/.exec(started.error.message ?? "")?.[1];
|
|
51558
|
+
if (running) {
|
|
51559
|
+
say(`This organization already has export ${running} running \u2014 following it`);
|
|
51560
|
+
return running;
|
|
51561
|
+
}
|
|
51562
|
+
}
|
|
51563
|
+
throw refusal(started);
|
|
51564
|
+
}
|
|
51565
|
+
__name(startOrAttach, "startOrAttach");
|
|
51566
|
+
async function pollToTerminal(api, jobId, say) {
|
|
51567
|
+
let delay = LOG_EXPORT_POLL.intervalMs;
|
|
51568
|
+
let last;
|
|
51569
|
+
for (let attempt = 0; attempt < LOG_EXPORT_POLL.maxAttempts; attempt++) {
|
|
51570
|
+
if (attempt > 0) {
|
|
51571
|
+
await LOG_EXPORT_POLL.sleep(delay);
|
|
51572
|
+
delay = Math.min(LOG_EXPORT_POLL.maxIntervalMs, delay * 2);
|
|
51573
|
+
}
|
|
51574
|
+
const res = await callExport(() => api.getExport(jobId));
|
|
51575
|
+
if (!res.success || !res.data) throw refusal(res);
|
|
51576
|
+
last = res.data;
|
|
51577
|
+
if (TERMINAL2.has(last.state)) return last;
|
|
51578
|
+
say(`Export ${jobId}: ${last.state} \u2014 ${last.counts.rows} record(s) so far`);
|
|
51579
|
+
}
|
|
51580
|
+
throw CliError.fromStatus(504, `The export ${jobId} is still running after ${LOG_EXPORT_POLL.maxAttempts} polls.`, `Check it later with: lua logs export --since ${last?.window.from ?? "24h"} --no-wait`);
|
|
51581
|
+
}
|
|
51582
|
+
__name(pollToTerminal, "pollToTerminal");
|
|
51583
|
+
async function downloadParts(job, outDir, say) {
|
|
51584
|
+
const written = [];
|
|
51585
|
+
for (const file of job.files) {
|
|
51586
|
+
if (!file.url) {
|
|
51587
|
+
throw CliError.fromStatus(410, `Part ${file.seq} of ${job.id} no longer has a download URL (it expires 24 h after the export finishes).`);
|
|
51588
|
+
}
|
|
51589
|
+
const target = join9(outDir, basename(String(file.name)));
|
|
51590
|
+
say(`Downloading ${basename(target)} (${file.rows} record(s))`);
|
|
51591
|
+
const bytes = await LOG_EXPORT_DOWNLOAD.fetchBytes(file.url);
|
|
51592
|
+
writeFileSync10(target, bytes);
|
|
51593
|
+
written.push(target);
|
|
51594
|
+
}
|
|
51595
|
+
return written;
|
|
51596
|
+
}
|
|
51597
|
+
__name(downloadParts, "downloadParts");
|
|
51598
|
+
async function callExport(call) {
|
|
51599
|
+
try {
|
|
51600
|
+
return await call();
|
|
51601
|
+
} catch (error) {
|
|
51602
|
+
if (CliError.isCliError(error) && error.statusCode === 403) {
|
|
51603
|
+
throw CliError.forbidden(MISSING_EXPORT_SCOPE_MESSAGE);
|
|
51604
|
+
}
|
|
51605
|
+
throw error;
|
|
51606
|
+
}
|
|
51607
|
+
}
|
|
51608
|
+
__name(callExport, "callExport");
|
|
51609
|
+
function emit2(options, payload) {
|
|
51610
|
+
if (options.json) console.log(JSON.stringify(payload, null, 2));
|
|
51611
|
+
}
|
|
51612
|
+
__name(emit2, "emit");
|
|
51613
|
+
function refusal(response) {
|
|
51614
|
+
const error = response.error;
|
|
51615
|
+
if (error?.statusCode === 403) return CliError.forbidden(MISSING_EXPORT_SCOPE_MESSAGE);
|
|
51616
|
+
const message = error?.message || "The log export API refused the request.";
|
|
51617
|
+
const line = error?.code ? `${error.code}: ${message}` : message;
|
|
51618
|
+
return CliError.fromStatus(error?.statusCode, line, void 0, apiErrorDetail(error));
|
|
51619
|
+
}
|
|
51620
|
+
__name(refusal, "refusal");
|
|
51621
|
+
|
|
50081
51622
|
// src/commands/completion.ts
|
|
50082
51623
|
init_cli();
|
|
50083
51624
|
init_analytics();
|
|
@@ -50985,8 +52526,8 @@ init_credential_operational_context();
|
|
|
50985
52526
|
init_files();
|
|
50986
52527
|
init_artifact_loader();
|
|
50987
52528
|
import chalk3 from "chalk";
|
|
50988
|
-
import { existsSync as
|
|
50989
|
-
import { join as
|
|
52529
|
+
import { existsSync as existsSync10, readFileSync as readFileSync13 } from "fs";
|
|
52530
|
+
import { join as join10 } from "path";
|
|
50990
52531
|
import { performance } from "perf_hooks";
|
|
50991
52532
|
import * as os from "os";
|
|
50992
52533
|
init_semver();
|
|
@@ -51176,7 +52717,7 @@ function gatherProject(config) {
|
|
|
51176
52717
|
};
|
|
51177
52718
|
}
|
|
51178
52719
|
const rootDir = process.cwd();
|
|
51179
|
-
const configPath =
|
|
52720
|
+
const configPath = join10(rootDir, COMPILE_FILES.LUA_SKILL_YAML);
|
|
51180
52721
|
const agentId = config.agent?.agentId != null ? String(config.agent.agentId) : null;
|
|
51181
52722
|
let agentName = null;
|
|
51182
52723
|
let manifestFound = false;
|
|
@@ -51358,7 +52899,7 @@ function gatherTelemetry() {
|
|
|
51358
52899
|
].includes(envVal.toLowerCase());
|
|
51359
52900
|
} else {
|
|
51360
52901
|
try {
|
|
51361
|
-
if (
|
|
52902
|
+
if (existsSync10(TELEMETRY_FILE)) {
|
|
51362
52903
|
const raw = readFileSync13(TELEMETRY_FILE, "utf8");
|
|
51363
52904
|
const cfg = JSON.parse(raw);
|
|
51364
52905
|
if (typeof cfg.enabled === "boolean") enabled = cfg.enabled;
|
|
@@ -54404,7 +55945,7 @@ var TERMINAL_CANCELLED = /* @__PURE__ */ new Set([
|
|
|
54404
55945
|
"cancelled",
|
|
54405
55946
|
"abandoned"
|
|
54406
55947
|
]);
|
|
54407
|
-
var
|
|
55948
|
+
var TERMINAL3 = /* @__PURE__ */ new Set([
|
|
54408
55949
|
...TERMINAL_FAILED,
|
|
54409
55950
|
...TERMINAL_CANCELLED,
|
|
54410
55951
|
"completed"
|
|
@@ -55648,14 +57189,14 @@ function frameSeq(frame, ev) {
|
|
|
55648
57189
|
return typeof ev.seq === "number" ? ev.seq : void 0;
|
|
55649
57190
|
}
|
|
55650
57191
|
__name(frameSeq, "frameSeq");
|
|
55651
|
-
async function watchBoundary(ctx, runId, state3, seq, line, code,
|
|
57192
|
+
async function watchBoundary(ctx, runId, state3, seq, line, code, emit3) {
|
|
55652
57193
|
if (state3.truth === void 0 || state3.truth !== null && state3.truth.watermark === void 0) {
|
|
55653
57194
|
state3.truth = await readWatchTruth(ctx, runId);
|
|
55654
57195
|
}
|
|
55655
57196
|
const truth = state3.truth;
|
|
55656
|
-
if (truth === null) return
|
|
55657
|
-
if (truth.watermark === void 0 || seq === void 0) return truth.parked ?
|
|
55658
|
-
if (seq > truth.watermark) return
|
|
57197
|
+
if (truth === null) return emit3(line, code);
|
|
57198
|
+
if (truth.watermark === void 0 || seq === void 0) return truth.parked ? emit3(line, code) : void 0;
|
|
57199
|
+
if (seq > truth.watermark) return emit3(line, code);
|
|
55659
57200
|
if (!truth.parked) return void 0;
|
|
55660
57201
|
state3.pending = {
|
|
55661
57202
|
line,
|
|
@@ -55788,7 +57329,7 @@ async function cancelCore(ctx, runId, o) {
|
|
|
55788
57329
|
emitJson(ctx, res);
|
|
55789
57330
|
if (!ctx.json) {
|
|
55790
57331
|
const v = res.data;
|
|
55791
|
-
const alreadyTerminal = v.transitioned !== true && (v.state === "terminal" || v.state === "abandoned" ||
|
|
57332
|
+
const alreadyTerminal = v.transitioned !== true && (v.state === "terminal" || v.state === "abandoned" || TERMINAL3.has(v.status));
|
|
55792
57333
|
if (alreadyTerminal) {
|
|
55793
57334
|
writeInfo(`\u2139\uFE0F run ${runId} was already ${v.status} \u2014 nothing to cancel`);
|
|
55794
57335
|
return WORKFLOW_EXIT.OK;
|
|
@@ -56725,7 +58266,7 @@ async function exportCore(ctx, name, o) {
|
|
|
56725
58266
|
} : {},
|
|
56726
58267
|
message: w.message
|
|
56727
58268
|
}));
|
|
56728
|
-
const
|
|
58269
|
+
const refusal2 = issues.length === 0 ? void 0 : checkIssues.length === 0 ? new CliError("export_not_expressible", `"${wf.name}" v${d.version} has ${inexpressible.length} node${inexpressible.length === 1 ? "" : "s"} the export codegen has no SDK spelling for \u2014 the file compiles WITHOUT ${inexpressible.length === 1 ? "it" : "them"} and cannot round-trip`, {
|
|
56729
58270
|
issues,
|
|
56730
58271
|
hint: "The file is written for review \u2014 add the node by hand, or keep the version dynamic (the chat composer edits it in place)."
|
|
56731
58272
|
}) : new CliError("export_not_compilable", `"${wf.name}" v${d.version} exported to a file \`lua compile\` refuses \u2014 ${checkIssues.length} error${checkIssues.length === 1 ? "" : "s"} (the export codegen could not produce a file the SDK builder accepts)`, {
|
|
@@ -56737,12 +58278,12 @@ async function exportCore(ctx, name, o) {
|
|
|
56737
58278
|
...d,
|
|
56738
58279
|
warnings
|
|
56739
58280
|
};
|
|
56740
|
-
if (
|
|
58281
|
+
if (refusal2) {
|
|
56741
58282
|
console.log(JSON.stringify({
|
|
56742
|
-
...cliErrorEnvelope(
|
|
58283
|
+
...cliErrorEnvelope(refusal2),
|
|
56743
58284
|
data
|
|
56744
58285
|
}, null, 2));
|
|
56745
|
-
return
|
|
58286
|
+
return refusal2.exitCode;
|
|
56746
58287
|
}
|
|
56747
58288
|
console.log(JSON.stringify({
|
|
56748
58289
|
...res,
|
|
@@ -56764,14 +58305,14 @@ async function exportCore(ctx, name, o) {
|
|
|
56764
58305
|
console.log(` ${f.path}`);
|
|
56765
58306
|
}
|
|
56766
58307
|
const written = `exported "${wf.name}" v${d.version} (${d.form} form) \u2014 ${d.files.length} file(s) under ${outDir}`;
|
|
56767
|
-
if (
|
|
58308
|
+
if (refusal2) {
|
|
56768
58309
|
console.error(`\u274C ${written}, but ${check && !check.ok ? "the file does not compile as written" : "the file cannot round-trip"}`);
|
|
56769
58310
|
} else {
|
|
56770
58311
|
const verdict = check ? ` \xB7 compiles as written${check.workflows[0]?.graphHash ? ` (${check.workflows[0].graphHash})` : ""}` : ` \xB7 dry compile skipped \u2014 the file compiles once the TODO tool import${todoTools.length === 1 ? "" : "s"} ${todoTools.length === 1 ? "is" : "are"} resolved`;
|
|
56771
58312
|
writeSuccess(`\u2705 ${written}${verdict}`);
|
|
56772
58313
|
}
|
|
56773
58314
|
for (const w of warnings) console.warn(`\u26A0\uFE0F ${w.code}${w.path ? ` at ${w.path}` : ""}: ${w.message}`);
|
|
56774
|
-
if (
|
|
58315
|
+
if (refusal2) throw refusal2;
|
|
56775
58316
|
if (warnings.length) writeInfo("\u{1F4A1} Review the TODOs the warnings name; `lua push workflow` then mints a static version from the file.");
|
|
56776
58317
|
return WORKFLOW_EXIT.OK;
|
|
56777
58318
|
}
|
|
@@ -56789,7 +58330,7 @@ function parseSinceFlag(raw, now = Date.now()) {
|
|
|
56789
58330
|
__name(parseSinceFlag, "parseSinceFlag");
|
|
56790
58331
|
var ARCHIVE_EXPORT_TTL_DAYS = 7;
|
|
56791
58332
|
var ARCHIVE_TERMINAL_STATUS_FILTER = [
|
|
56792
|
-
...
|
|
58333
|
+
...TERMINAL3
|
|
56793
58334
|
].join(",");
|
|
56794
58335
|
var ARCHIVE_DEFAULT_RETENTION_DAYS = 90;
|
|
56795
58336
|
var archiveDownload = {
|
|
@@ -57204,7 +58745,7 @@ async function jobLogsCore(ctx, runId, stepId, o) {
|
|
|
57204
58745
|
}
|
|
57205
58746
|
for (const line of v.logs.slice(printed)) console.log(` ${line}`);
|
|
57206
58747
|
printed = Math.max(printed, v.logs.length);
|
|
57207
|
-
const terminal =
|
|
58748
|
+
const terminal = TERMINAL3.has(v.status) || /^(completed|failed|cancelled|skipped|reaped|deleted)$/.test(v.status);
|
|
57208
58749
|
if (!o.follow || terminal || v.attemptFinished || v.phase === "deleted") {
|
|
57209
58750
|
if (o.follow && !ctx.json) writeInfo(` \u2014 ${v.status} (${v.phase})`);
|
|
57210
58751
|
return WORKFLOW_EXIT.OK;
|
|
@@ -67000,8 +68541,8 @@ __name(telemetryCommand, "telemetryCommand");
|
|
|
67000
68541
|
init_cli();
|
|
67001
68542
|
init_command_utils();
|
|
67002
68543
|
init_analytics();
|
|
67003
|
-
import { writeFileSync as
|
|
67004
|
-
import { resolve as resolve5, join as
|
|
68544
|
+
import { writeFileSync as writeFileSync11, existsSync as existsSync11, unlinkSync as unlinkSync3 } from "fs";
|
|
68545
|
+
import { resolve as resolve5, join as join11 } from "path";
|
|
67005
68546
|
init_artifact_loader();
|
|
67006
68547
|
init_types();
|
|
67007
68548
|
function getProjectToolNames() {
|
|
@@ -67024,9 +68565,9 @@ async function governanceCommand(action) {
|
|
|
67024
68565
|
return;
|
|
67025
68566
|
}
|
|
67026
68567
|
const srcDir = resolve5(process.cwd(), "src");
|
|
67027
|
-
const targetDir =
|
|
67028
|
-
const filePath =
|
|
67029
|
-
if (
|
|
68568
|
+
const targetDir = existsSync11(srcDir) ? srcDir : process.cwd();
|
|
68569
|
+
const filePath = join11(targetDir, "governance.ts");
|
|
68570
|
+
if (existsSync11(filePath)) {
|
|
67030
68571
|
const { overwrite } = await safePrompt([
|
|
67031
68572
|
{
|
|
67032
68573
|
type: "confirm",
|
|
@@ -67117,7 +68658,7 @@ async function governanceCommand(action) {
|
|
|
67117
68658
|
}
|
|
67118
68659
|
}
|
|
67119
68660
|
const content = generateGovernanceFile(setup);
|
|
67120
|
-
|
|
68661
|
+
writeFileSync11(filePath, content, "utf-8");
|
|
67121
68662
|
const relativePath = filePath.replace(process.cwd() + "/", "");
|
|
67122
68663
|
writeSuccess(`Created ${relativePath}`);
|
|
67123
68664
|
console.log("");
|
|
@@ -67155,9 +68696,9 @@ async function governanceCommand(action) {
|
|
|
67155
68696
|
__name(governanceCommand, "governanceCommand");
|
|
67156
68697
|
async function governanceRemove() {
|
|
67157
68698
|
const srcDir = resolve5(process.cwd(), "src");
|
|
67158
|
-
const targetDir =
|
|
67159
|
-
const filePath =
|
|
67160
|
-
const hasLocal =
|
|
68699
|
+
const targetDir = existsSync11(srcDir) ? srcDir : process.cwd();
|
|
68700
|
+
const filePath = join11(targetDir, "governance.ts");
|
|
68701
|
+
const hasLocal = existsSync11(filePath);
|
|
67161
68702
|
const { confirm } = await safePrompt([
|
|
67162
68703
|
{
|
|
67163
68704
|
type: "confirm",
|
|
@@ -67508,8 +69049,8 @@ init_command_utils();
|
|
|
67508
69049
|
init_artifact_loader();
|
|
67509
69050
|
init_types();
|
|
67510
69051
|
import { spawn as spawn3 } from "child_process";
|
|
67511
|
-
import { existsSync as
|
|
67512
|
-
import { join as
|
|
69052
|
+
import { existsSync as existsSync12, readdirSync as readdirSync4, statSync as statSync6 } from "fs";
|
|
69053
|
+
import { join as join12, relative as relative2, resolve as resolve6 } from "path";
|
|
67513
69054
|
init_voice_api_service();
|
|
67514
69055
|
init_constants();
|
|
67515
69056
|
|
|
@@ -68097,8 +69638,8 @@ function escapeRegex(s) {
|
|
|
68097
69638
|
}
|
|
68098
69639
|
__name(escapeRegex, "escapeRegex");
|
|
68099
69640
|
function detectRunner(cwd) {
|
|
68100
|
-
const pkgPath =
|
|
68101
|
-
if (!
|
|
69641
|
+
const pkgPath = join12(cwd, "package.json");
|
|
69642
|
+
if (!existsSync12(pkgPath)) return null;
|
|
68102
69643
|
try {
|
|
68103
69644
|
const pkg2 = JSON.parse(__require("fs").readFileSync(pkgPath, "utf8"));
|
|
68104
69645
|
const deps = {
|
|
@@ -68470,7 +70011,7 @@ function findVoiceTestFiles(root) {
|
|
|
68470
70011
|
return;
|
|
68471
70012
|
}
|
|
68472
70013
|
for (const entry of entries) {
|
|
68473
|
-
const full =
|
|
70014
|
+
const full = join12(dir, entry);
|
|
68474
70015
|
let s;
|
|
68475
70016
|
try {
|
|
68476
70017
|
s = statSync6(full);
|
|
@@ -69512,6 +71053,22 @@ function collect(value3, previous) {
|
|
|
69512
71053
|
];
|
|
69513
71054
|
}
|
|
69514
71055
|
__name(collect, "collect");
|
|
71056
|
+
function withGroupOptions(options, command) {
|
|
71057
|
+
const parent = command.parent;
|
|
71058
|
+
if (!parent) return options;
|
|
71059
|
+
const merged = {
|
|
71060
|
+
...options
|
|
71061
|
+
};
|
|
71062
|
+
for (const option of command.options) {
|
|
71063
|
+
const key = option.attributeName();
|
|
71064
|
+
if (merged[key] !== void 0) continue;
|
|
71065
|
+
if (!parent.options.some((parentOption) => parentOption.attributeName() === key)) continue;
|
|
71066
|
+
if (parent.getOptionValueSource(key) !== "cli") continue;
|
|
71067
|
+
merged[key] = parent.getOptionValue(key);
|
|
71068
|
+
}
|
|
71069
|
+
return merged;
|
|
71070
|
+
}
|
|
71071
|
+
__name(withGroupOptions, "withGroupOptions");
|
|
69515
71072
|
function setupAuthCommands(program2) {
|
|
69516
71073
|
const authCommand = program2.command("auth").description("\u{1F510} Authentication management").addHelpText("after", `
|
|
69517
71074
|
Examples:
|
|
@@ -69828,11 +71385,12 @@ Examples:
|
|
|
69828
71385
|
$ lua channels Interactive management
|
|
69829
71386
|
$ lua channels list List all channels
|
|
69830
71387
|
`).action(channelsCommand);
|
|
69831
|
-
program2.command("logs").description("\u{1F4CA} View agent and skill logs").option("--type <type>", "Filter by type: all, calls, or any of the 18 log sources (skill, job, webhook, trigger, preprocessor, postprocessor, user_message, agent_response, agent_error, runtime, mcp, rag, device, device-trigger, model-resolver, workflow-step, workflow-script, workflow)").option("--name <name>", "Entity name to filter (requires --type)").option("--user-id <userId>", "Filter logs by user ID").option("--agent-id <agentId>", "View logs for a specific agent ID (admin access required)").option("--limit <n>", "Number of logs to show (default: 20)").option("--page <n>", "Page number for pagination").option("--json", "Output as JSON (for scripting)").option("--direction <direction>", "Filter calls by direction (inbound | outbound) \u2014 only with --type calls").option("--status <status>", "Filter calls by status \u2014 only with --type calls").option("--since <when>", "Only logs at or after this time: an ISO 8601 instant, or 15m | 2h | 7d").option("--until <when>", "Only logs at or before this time; same formats (ends a --follow)").option("--environment <env>", "production | sandbox (a row with no environment reads as production)").option("--follow", "Stream new logs as they arrive (Ctrl-C to stop); not valid with --page").addHelpText("after", `
|
|
71388
|
+
const logsGroup = program2.command("logs").description("\u{1F4CA} View agent and skill logs").option("--type <type>", "Filter by type: all, calls, or any of the 18 log sources (skill, job, webhook, trigger, preprocessor, postprocessor, user_message, agent_response, agent_error, runtime, mcp, rag, device, device-trigger, model-resolver, workflow-step, workflow-script, workflow)").option("--name <name>", "Entity name to filter (requires --type)").option("--user-id <userId>", "Filter logs by user ID").option("--channel <channel>", "Filter logs by messaging channel (e.g. whatsapp, slack, integration:<type>)").option("--agent-id <agentId>", "View logs for a specific agent ID (admin access required)").option("--limit <n>", "Number of logs to show (default: 20)").option("--page <n>", "Page number for pagination").option("--json", "Output as JSON (for scripting)").option("--direction <direction>", "Filter calls by direction (inbound | outbound) \u2014 only with --type calls").option("--status <status>", "Filter calls by status \u2014 only with --type calls").option("--since <when>", "Only logs at or after this time: an ISO 8601 instant, or 15m | 2h | 7d").option("--until <when>", "Only logs at or before this time; same formats (ends a --follow)").option("--environment <env>", "production | sandbox (a row with no environment reads as production)").option("--follow", "Stream new logs as they arrive (Ctrl-C to stop); not valid with --page").addHelpText("after", `
|
|
69832
71389
|
Options:
|
|
69833
71390
|
--type <type> Filter by type: all, calls, or any of the 18 log sources (skill, job, webhook, trigger, preprocessor, postprocessor, user_message, agent_response, agent_error, runtime, mcp, rag, device, device-trigger, model-resolver, workflow-step, workflow-script, workflow)
|
|
69834
71391
|
--name <name> Entity name to filter (requires --type, not for message types)
|
|
69835
71392
|
--user-id <userId> Filter logs by user ID
|
|
71393
|
+
--channel <channel> Filter logs by messaging channel (e.g. whatsapp, slack, integration:<type>)
|
|
69836
71394
|
--agent-id <agentId> View logs for a specific agent ID (admin access required, overrides the agent in lua.config.yaml)
|
|
69837
71395
|
--limit <n> Number of logs to show (default: 20)
|
|
69838
71396
|
--page <n> Page number for pagination
|
|
@@ -69853,6 +71411,7 @@ Examples:
|
|
|
69853
71411
|
$ lua logs --type mcp View MCP tool execution logs
|
|
69854
71412
|
$ lua logs --user-id user-123 View all logs for a user
|
|
69855
71413
|
$ lua logs --user-id user-123 --json > user-logs.json Export user logs
|
|
71414
|
+
$ lua logs --channel integration:lua_crm Isolate one integration's wake-up turns
|
|
69856
71415
|
$ lua logs --agent-id agent-abc123 Logs for a different agent you admin
|
|
69857
71416
|
$ lua logs --type calls Recent voice calls (renders as table)
|
|
69858
71417
|
$ lua logs --type calls --direction outbound Outbound calls only
|
|
@@ -69868,6 +71427,28 @@ Notes:
|
|
|
69868
71427
|
shift the window. --type calls reads voice calls and ignores --since/--until/--environment
|
|
69869
71428
|
/--follow. --since is INCLUSIVE; the boundary row is de-duplicated by id while following.
|
|
69870
71429
|
`).action(logsCommand);
|
|
71430
|
+
logsGroup.command("export").description("\u{1F4E6} Export this organization's logs as gzip NDJSON (asynchronous job)").option("--since <when>", "Inclusive lower bound (REQUIRED): an ISO 8601 instant, or 24h | 7d").option("--until <when>", "Inclusive upper bound; same formats (default: now)").option("--type <type>", "Comma-separated log sources, or all (default: all)").option("--out <dir>", "Download the parts into this directory (created if missing)").option("--org <id>", "The organization to export (default: the project, or the key when it reaches one org)").option("--no-wait", "Start the export and print the job id without polling it").option("--json", "Output as JSON").addHelpText("after", `
|
|
71431
|
+
Options:
|
|
71432
|
+
--since <when> REQUIRED. Inclusive lower bound: an ISO 8601 instant, or 24h | 7d
|
|
71433
|
+
--until <when> Inclusive upper bound, same formats (default: now)
|
|
71434
|
+
--type <type> Comma-separated log sources, or all (default: all)
|
|
71435
|
+
--out <dir> Download every part into this local directory
|
|
71436
|
+
--org <id> The organization, when the key reaches more than one
|
|
71437
|
+
--no-wait Start it and print the job id; poll later
|
|
71438
|
+
--json Output as JSON for scripting
|
|
71439
|
+
|
|
71440
|
+
Examples:
|
|
71441
|
+
$ lua logs export --since 7d --out ./export A week, downloaded
|
|
71442
|
+
$ lua logs export --since 30d --type skill,job A month, two sources
|
|
71443
|
+
$ lua logs export --since 24h --no-wait --json Start it and return
|
|
71444
|
+
|
|
71445
|
+
Notes:
|
|
71446
|
+
The window is at most 31 days and the job at most 10 000 000 records; narrow the window
|
|
71447
|
+
or the sources rather than raising either. One export runs per organization at a time \u2014
|
|
71448
|
+
a second invocation FOLLOWS the running one instead of refusing. Download links expire
|
|
71449
|
+
24 h after the export finishes and the files are removed after 7 days. Message bodies
|
|
71450
|
+
are excluded unless the export was started with the logs:manage scope.
|
|
71451
|
+
`).action((options, command) => logsExportCommand(withGroupOptions(options ?? {}, command)));
|
|
69871
71452
|
program2.command("skills [actionOrEnv] [action]").description("\u2699\uFE0F Manage and view skills").option("--skill-name <name>", "Skill name").option("--skill-version <version>", "Version for deploy action (or 'latest')").addHelpText("after", `
|
|
69872
71453
|
Arguments:
|
|
69873
71454
|
actionOrEnv Optional: environment ('sandbox', 'production') or action ('view', 'versions', 'deploy', 'delete')
|
|
@@ -69909,18 +71490,25 @@ Examples:
|
|
|
69909
71490
|
$ lua webhooks subscribe --webhook-name myWebhook --event message.delivered Subscribe to event
|
|
69910
71491
|
$ lua webhooks unsubscribe --webhook-name myWebhook --event message.delivered Unsubscribe from event
|
|
69911
71492
|
`).action(webhooksCommand);
|
|
69912
|
-
program2.command("drains [action] [id]").description("\u{1F6B0} Manage log drains (stream this organization's logs to your own destination)").option("--json", "Output as JSON").option("--yes", "Skip confirmation prompts (required with --include-content in CI)").option("--org <id>", "The organization to act on (default: the project, or the key when it reaches one org)").option("--name <name>", "Drain name (1-64 chars, unique per org)").option("--type <type>", "http | otlp | datadog | betterstack").option("--endpoint <url>", "Destination URL (http
|
|
71493
|
+
program2.command("drains [action] [id] [batchId]").description("\u{1F6B0} Manage log drains (stream this organization's logs to your own destination)").option("--json", "Output as JSON").option("--yes", "Skip confirmation prompts (required with --include-content in CI)").option("--org <id>", "The organization to act on (default: the project, or the key when it reaches one org)").option("--name <name>", "Drain name (1-64 chars, unique per org)").option("--type <type>", "http | otlp | datadog | betterstack | splunk | loki | axiom | newrelic | sumologic | s3").option("--endpoint <url>", "Destination URL (http/otlp), or the S3-compatible endpoint for --type s3 on R2/GCS").option("--site <site>", "Preset site/region, e.g. datadoghq.eu").option("--provider <name>", "s3: aws | r2 | gcs (default aws)").option("--bucket <name>", "s3: the bucket name").option("--region <code>", "s3: the bucket's region (use 'auto' for R2)").option("--prefix <key>", "s3: key prefix under which objects are written").option("--credentials-from-env <KEY_ID_VAR=SECRET_VAR>", "s3: read the access key pair from two environment variables").option("--role-arn <arn>", "s3 (aws): assume this role instead of holding a key pair").option("--external-id <id>", "s3 (aws): the sts:ExternalId the role trust policy requires").option("--token <token>", "confirm: the token from the _lua-verify-<token> object in your bucket").option("--format <format>", "json | ndjson").option("--header <name>", "Custom header NAME (the value is prompted)", collect, []).option("--header-from-env <name=ENV_VAR>", "Custom header, value read from an env var (CI form)", collect, []).option("--sources <list>", "Comma-separated source selectors (default: the recommended set)").option("--min-severity <level>", "debug | info | warn | error (default info)").option("--agents <list>", "'all' or a comma-separated list of agent ids").option("--environments <list>", "production,sandbox (default production)").option("--sampling <spec>", "Head sampling, e.g. debug=0.1").option("--include-content", "Include user messages and agent responses (prints an acknowledgement)").option("--no-include-content", "update: stop sending message bodies (the drain keeps its sources)").option("--limit <n>", "deliveries: rows to return (max 100)").option("--kind <kind>", "deliveries: batch | test | verify | heartbeat | dropped | truncated").option("--reason <text>", "pause: why").option("--finalize", "rotate-secret: close an open rotation window early").addHelpText("after", `
|
|
69913
71494
|
Arguments:
|
|
69914
71495
|
action Optional: list (default), status, deliveries, create, update, delete,
|
|
69915
|
-
test, verify, pause, resume, rotate-secret
|
|
69916
|
-
id The drain id, for every action but list
|
|
71496
|
+
test, verify, confirm, pause, resume, replay, rotate-secret
|
|
71497
|
+
id The drain id, for every action but list and create. The READ verbs
|
|
71498
|
+
(status, deliveries) also accept a drain's exact name (PRO-2124);
|
|
71499
|
+
the mutating verbs, replay included, stay id-only
|
|
71500
|
+
batchId replay only: the batch id from a delivery row
|
|
69917
71501
|
|
|
69918
71502
|
Examples:
|
|
69919
71503
|
$ lua drains List this org's drains
|
|
69920
71504
|
$ lua drains status --json Health + quota (exit 2 if any is failing)
|
|
71505
|
+
$ lua drains deliveries prod-siem By name \u2014 read verbs resolve it to an id
|
|
69921
71506
|
$ lua drains create --name prod-siem --type http --endpoint https://logs.example.com/lua
|
|
71507
|
+
$ lua drains create --name archive --type s3 --bucket acme-logs --region eu-west-1 --prefix lua/logs --credentials-from-env AWS_KEY_ID=AWS_SECRET Object storage (S3/R2/GCS)
|
|
69922
71508
|
$ lua drains verify drn_... Prove you own the endpoint
|
|
71509
|
+
$ lua drains confirm drn_... --token <token> Settle a bucket ownership challenge
|
|
69923
71510
|
$ lua drains deliveries drn_... --limit 20 --kind batch Recent delivery attempts
|
|
71511
|
+
$ lua drains replay drn_... 01J... Re-enqueue that batch's records
|
|
69924
71512
|
$ lua drains rotate-secret drn_... New signing secret (shown once)
|
|
69925
71513
|
$ lua drains rotate-secret drn_... --finalize Close the rotation window
|
|
69926
71514
|
$ lua drains pause drn_... --reason "noisy vendor" Stop delivering (buffering continues)
|
|
@@ -69929,7 +71517,16 @@ Examples:
|
|
|
69929
71517
|
Notes:
|
|
69930
71518
|
Secrets are never flags. --header takes a NAME and prompts for the value; in --ci mode use
|
|
69931
71519
|
--header-from-env DD_API_KEY=DATADOG_KEY. The HMAC signing secret is minted by the server and
|
|
69932
|
-
printed exactly once, at create and at rotate-secret.
|
|
71520
|
+
printed exactly once, at create and at rotate-secret. An object-storage drain's secret access
|
|
71521
|
+
key is the same: --credentials-from-env KEY_ID_VAR=SECRET_VAR, never a value on the command line.
|
|
71522
|
+
|
|
71523
|
+
A terminal refusal (a 4xx that is not 408/429) drops the whole batch. 'lua drains replay <id>
|
|
71524
|
+
<batchId>' puts its records back in the queue, for as long as they are inside the six-hour
|
|
71525
|
+
delivery horizon \u2014 after that they are gone and the command says so.
|
|
71526
|
+
|
|
71527
|
+
A bucket drain proves ownership by writing _lua-verify-<token> under its prefix. If the role can
|
|
71528
|
+
read it back, 'lua drains verify' finishes on its own; if it is write-only \u2014 the grant we
|
|
71529
|
+
recommend \u2014 list your prefix, find the object, and run 'lua drains confirm <id> --token <token>'.
|
|
69933
71530
|
`).action(drainsCommand);
|
|
69934
71531
|
program2.command("devices [action]").description("\u{1F4E1} Manage connected devices").option("--device-name <name>", "Device name").option("--group <group>", "Filter by device group").option("--payload <json>", "JSON payload for test/test-trigger", "{}").option("--timeout <ms>", "Timeout in milliseconds", "30000").option("--force", "Skip confirmation prompts").addHelpText("after", `
|
|
69935
71532
|
Arguments:
|