@node9/proxy 2.45.0 → 2.47.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.
@@ -106,22 +106,16 @@ var init_forecast_context = __esm({
106
106
  });
107
107
 
108
108
  // packages/policy-engine/dist/index.mjs
109
- import mvdanSh3 from "mvdan-sh";
110
109
  import picomatch from "picomatch";
111
110
  import safeRegex from "safe-regex2";
112
111
  import pm from "picomatch";
113
- import mvdanSh from "mvdan-sh";
114
112
  import mvdanSh2 from "mvdan-sh";
113
+ import mvdanSh from "mvdan-sh";
114
+ import mvdanSh3 from "mvdan-sh";
115
115
  import safeRegex2 from "safe-regex2";
116
116
  import { createHash as createHash2 } from "crypto";
117
117
  import { createHash as createHash22 } from "crypto";
118
- import mvdanSh4 from "mvdan-sh";
119
- import mvdanSh5 from "mvdan-sh";
120
- import mvdanSh6 from "mvdan-sh";
121
- import mvdanSh8 from "mvdan-sh";
122
- import mvdanSh7 from "mvdan-sh";
123
118
  import { createHash as createHash3 } from "crypto";
124
- import mvdanSh9 from "mvdan-sh";
125
119
  import crypto from "crypto";
126
120
  function validateRegex(pattern) {
127
121
  if (!pattern) return "Pattern is required";
@@ -703,6 +697,62 @@ function resolveCheckMap(settings) {
703
697
  for (const c of CHECKS) out[c.id] = checkValue(settings, c.id);
704
698
  return out;
705
699
  }
700
+ function isGoNode(v) {
701
+ return v !== null && typeof v === "object" && typeof v.Pos === "function";
702
+ }
703
+ function toPlainTree(goNode) {
704
+ const kind = syntax.NodeType(goNode);
705
+ const out = { kind, pos: goNode.Pos().Offset(), end: goNode.End().Offset() };
706
+ const spec = KINDS[kind];
707
+ if (!spec) {
708
+ unknownKinds.add(kind);
709
+ return out;
710
+ }
711
+ convertFields(goNode, spec, out, kind);
712
+ return out;
713
+ }
714
+ function convertFields(goNode, spec, out, kind) {
715
+ for (const f of spec.scalars ?? []) out[f] = goNode[f];
716
+ for (const f of spec.nodes ?? []) {
717
+ const v = goNode[f];
718
+ if (v === void 0 || v === null) {
719
+ out[f] = null;
720
+ } else if (Array.isArray(v)) {
721
+ out[f] = v.map((c) => isGoNode(c) ? toPlainTree(c) : c);
722
+ } else if (isGoNode(v)) {
723
+ out[f] = toPlainTree(v);
724
+ } else if (typeof v === "object" && STRUCTS[`${kind}.${f}`]) {
725
+ const sub = { struct: `${kind}.${f}` };
726
+ convertFields(v, STRUCTS[`${kind}.${f}`], sub, `${kind}.${f}`);
727
+ out[f] = sub;
728
+ } else {
729
+ out[f] = v;
730
+ }
731
+ }
732
+ }
733
+ function childrenOf(n) {
734
+ const spec = n.kind ? KINDS[n.kind] : STRUCTS[n.struct];
735
+ if (!spec?.nodes) return [];
736
+ const out = [];
737
+ for (const f of spec.nodes) {
738
+ if (spec.notWalked?.includes(f)) continue;
739
+ const v = n[f];
740
+ if (!v) continue;
741
+ if (Array.isArray(v)) {
742
+ for (const c of v) if (c) out.push(c);
743
+ } else if (v.kind) {
744
+ out.push(v);
745
+ } else if (v.struct) {
746
+ out.push(...childrenOf(v));
747
+ }
748
+ }
749
+ return out;
750
+ }
751
+ function walk(root, fn) {
752
+ if (!root) return;
753
+ if (!fn(root)) return;
754
+ for (const c of childrenOf(root)) walk(c, fn);
755
+ }
706
756
  function isInvisibleChar(char) {
707
757
  return INVISIBLE_ONE.test(char);
708
758
  }
@@ -858,7 +908,7 @@ function judgeInlineCode(language, code, isProtected) {
858
908
  }
859
909
  function isCatHeredocOrLit(part) {
860
910
  if (!part) return false;
861
- const t = syntax.NodeType(part);
911
+ const t = part.kind;
862
912
  if (t === "Lit") return true;
863
913
  if (t !== "CmdSubst") return false;
864
914
  const stmts = part.Stmts || [];
@@ -868,9 +918,9 @@ function isCatHeredocOrLit(part) {
868
918
  const hasHeredoc = redirs.some((r) => r && r.Hdoc);
869
919
  if (!hasHeredoc) return false;
870
920
  const cmd = stmt.Cmd;
871
- if (!cmd || syntax.NodeType(cmd) !== "CallExpr") return false;
921
+ if (!cmd || cmd.kind !== "CallExpr") return false;
872
922
  const firstArg = cmd.Args?.[0]?.Parts || [];
873
- if (firstArg.length !== 1 || syntax.NodeType(firstArg[0]) !== "Lit") return false;
923
+ if (firstArg.length !== 1 || firstArg[0].kind !== "Lit") return false;
874
924
  return (firstArg[0].Value || "").toLowerCase() === "cat";
875
925
  }
876
926
  function parseShared(command) {
@@ -882,7 +932,7 @@ function parseShared(command) {
882
932
  }
883
933
  let parsed;
884
934
  try {
885
- parsed = sharedParser.Parse(command, "cmd");
935
+ parsed = toPlainTree(sharedParser.Parse(command, "cmd"));
886
936
  } catch {
887
937
  parsed = PARSE_FAIL;
888
938
  }
@@ -943,10 +993,10 @@ function fileAccessViewImpl(command) {
943
993
  const at = (byteOffset) => toCharIndex === null ? byteOffset : toCharIndex(byteOffset);
944
994
  const edits = [];
945
995
  try {
946
- syntax.Walk(f, (node) => {
996
+ walk(f, (node) => {
947
997
  if (!node) return false;
948
998
  const n = node;
949
- if (syntax.NodeType(n) !== "CallExpr") return true;
999
+ if (n.kind !== "CallExpr") return true;
950
1000
  const args = n.Args || [];
951
1001
  const words = args.map((a) => resolveWordLiteral(a));
952
1002
  const head = unwrapCommandHead(words);
@@ -958,8 +1008,8 @@ function fileAccessViewImpl(command) {
958
1008
  if (!PROGRAM_DIR.test(word)) continue;
959
1009
  const name = word.split(/[\\/]/).pop() ?? "";
960
1010
  if (!name) continue;
961
- const s = at(args[i].Pos().Offset());
962
- const e = at(args[i].End().Offset());
1011
+ const s = at(args[i].pos);
1012
+ const e = at(args[i].end);
963
1013
  if (s < 0 || e < 0) continue;
964
1014
  edits.push([s, e, name]);
965
1015
  }
@@ -987,10 +1037,10 @@ function literalPayloadsOf(command, depth) {
987
1037
  if (f === PARSE_FAIL) return [];
988
1038
  const out = [];
989
1039
  try {
990
- syntax.Walk(f, (node) => {
1040
+ walk(f, (node) => {
991
1041
  if (!node || out.length >= MAX_READING_PAYLOADS) return false;
992
1042
  const n = node;
993
- if (syntax.NodeType(n) !== "CallExpr") return true;
1043
+ if (n.kind !== "CallExpr") return true;
994
1044
  const words = (n.Args || []).map((a) => resolveWordLiteral(a));
995
1045
  if (words.length === 0) return true;
996
1046
  const payload = literalShellPayload(words, baseWord(words[0]));
@@ -1010,23 +1060,23 @@ function foldCommandWords(reading) {
1010
1060
  const at = (byteOffset) => toCharIndex === null ? byteOffset : toCharIndex(byteOffset);
1011
1061
  const edits = [];
1012
1062
  try {
1013
- syntax.Walk(f, (node) => {
1063
+ walk(f, (node) => {
1014
1064
  if (!node) return false;
1015
1065
  const n = node;
1016
- if (syntax.NodeType(n) !== "CallExpr") return true;
1066
+ if (n.kind !== "CallExpr") return true;
1017
1067
  const args = n.Args || [];
1018
1068
  const words = args.map((a) => resolveWordLiteral(a));
1019
1069
  const folded = words.map((w) => w === null ? null : foldHomoglyphs(w));
1020
1070
  const head = unwrapCommandHead(folded);
1021
1071
  for (let i = 0; i <= head && i < args.length; i++) {
1022
1072
  const parts = args[i].Parts || [];
1023
- if (parts.length !== 1 || syntax.NodeType(parts[0]) !== "Lit") continue;
1073
+ if (parts.length !== 1 || parts[0].kind !== "Lit") continue;
1024
1074
  const value = parts[0].Value ?? "";
1025
1075
  const word = folded[i];
1026
1076
  if (word === null || word === value || !/[^\x00-\x7f]/.test(value)) continue;
1027
1077
  if (!/^[A-Za-z0-9._/-]+$/.test(word)) continue;
1028
- const s = at(args[i].Pos().Offset());
1029
- const e = at(args[i].End().Offset());
1078
+ const s = at(args[i].pos);
1079
+ const e = at(args[i].end);
1030
1080
  if (s < 0 || e < 0) continue;
1031
1081
  edits.push([s, e, word]);
1032
1082
  }
@@ -1063,10 +1113,10 @@ function interpreterHeredocSpans(f, at) {
1063
1113
  const stmts = f?.Stmts || [];
1064
1114
  const candidates = [];
1065
1115
  let unsafe = false;
1066
- syntax.Walk(f, (node) => {
1116
+ walk(f, (node) => {
1067
1117
  if (!node || unsafe) return false;
1068
1118
  const n = node;
1069
- const t = syntax.NodeType(n);
1119
+ const t = n.kind;
1070
1120
  if (t === "FuncDecl") {
1071
1121
  unsafe = true;
1072
1122
  return false;
@@ -1086,7 +1136,7 @@ function interpreterHeredocSpans(f, at) {
1086
1136
  });
1087
1137
  if (unsafe) return [];
1088
1138
  for (const st of stmts) {
1089
- if (!st?.Cmd || syntax.NodeType(st.Cmd) !== "CallExpr") continue;
1139
+ if (!st?.Cmd || st.Cmd.kind !== "CallExpr") continue;
1090
1140
  const words = (st.Cmd.Args || []).map((a) => resolveWordLiteral(a));
1091
1141
  const name = (words[0] ?? "").toLowerCase();
1092
1142
  if (!STDIN_CODE_INTERPRETERS.test(name)) continue;
@@ -1101,8 +1151,8 @@ function interpreterHeredocSpans(f, at) {
1101
1151
  if (stdin.length !== 1 || others > 0) continue;
1102
1152
  const r = stdin[0];
1103
1153
  if (heredocText(r.Hdoc) === null) continue;
1104
- const hs = at(r.Hdoc.Pos().Offset());
1105
- const he = at(r.Hdoc.End().Offset());
1154
+ const hs = at(r.Hdoc.pos);
1155
+ const he = at(r.Hdoc.end);
1106
1156
  if (hs < 0 || he < 0 || he <= hs) continue;
1107
1157
  spans.push([hs, he]);
1108
1158
  }
@@ -1122,24 +1172,24 @@ function normalizeCommandForPolicyImpl(command, codeBodies) {
1122
1172
  strips.push([hs, he]);
1123
1173
  msgSpans.add(`${hs}:${he}`);
1124
1174
  }
1125
- syntax.Walk(f, (node) => {
1175
+ walk(f, (node) => {
1126
1176
  if (!node) return false;
1127
1177
  const n = node;
1128
- if (syntax.NodeType(n) !== "CallExpr") return true;
1178
+ if (n.kind !== "CallExpr") return true;
1129
1179
  const args = n.Args || [];
1130
1180
  for (let i = 0; i < args.length - 1; i++) {
1131
1181
  const argParts = args[i].Parts || [];
1132
- if (argParts.length !== 1 || syntax.NodeType(argParts[0]) !== "Lit") continue;
1182
+ if (argParts.length !== 1 || argParts[0].kind !== "Lit") continue;
1133
1183
  const flagVal = argParts[0].Value || "";
1134
1184
  if (!MESSAGE_FLAGS.has(flagVal.toLowerCase())) continue;
1135
1185
  const next = args[i + 1];
1136
1186
  const nextParts = next.Parts || [];
1137
1187
  if (nextParts.length !== 1) continue;
1138
1188
  const quotedNode = nextParts[0];
1139
- const nt = syntax.NodeType(quotedNode);
1189
+ const nt = quotedNode.kind;
1140
1190
  const markStrip = () => {
1141
- const s = at(next.Pos().Offset());
1142
- const e = at(next.End().Offset());
1191
+ const s = at(next.pos);
1192
+ const e = at(next.end);
1143
1193
  if (s < 0 || e < 0) return;
1144
1194
  strips.push([s, e]);
1145
1195
  msgSpans.add(`${s}:${e}`);
@@ -1148,7 +1198,7 @@ function normalizeCommandForPolicyImpl(command, codeBodies) {
1148
1198
  markStrip();
1149
1199
  } else if (nt === "DblQuoted") {
1150
1200
  const innerParts = quotedNode.Parts || [];
1151
- const allLit = innerParts.length === 0 || innerParts.every((p) => syntax.NodeType(p) === "Lit");
1201
+ const allLit = innerParts.length === 0 || innerParts.every((p) => p.kind === "Lit");
1152
1202
  if (allLit) {
1153
1203
  markStrip();
1154
1204
  } else if (innerParts.every((p) => isCatHeredocOrLit(p))) {
@@ -1157,8 +1207,8 @@ function normalizeCommandForPolicyImpl(command, codeBodies) {
1157
1207
  }
1158
1208
  }
1159
1209
  for (const arg of args) {
1160
- const s = at(arg.Pos().Offset());
1161
- const e = at(arg.End().Offset());
1210
+ const s = at(arg.pos);
1211
+ const e = at(arg.end);
1162
1212
  if (s < 0 || e < 0) continue;
1163
1213
  if (msgSpans.has(`${s}:${e}`)) continue;
1164
1214
  const resolved = resolveWordLiteral(arg);
@@ -1198,10 +1248,10 @@ function scanArgsForDynamicExec(args, startIdx) {
1198
1248
  let hasParamExp = false;
1199
1249
  let hasCurl = false;
1200
1250
  for (let i = startIdx; i < args.length; i++) {
1201
- syntax.Walk(args[i], (inner) => {
1251
+ walk(args[i], (inner) => {
1202
1252
  if (!inner) return false;
1203
1253
  const inn = inner;
1204
- const it = syntax.NodeType(inn);
1254
+ const it = inn.kind;
1205
1255
  if (it === "CmdSubst") hasCmdSubst = true;
1206
1256
  if (it === "ParamExp") hasParamExp = true;
1207
1257
  if (it === "Lit" && DOWNLOAD_CMDS.has(inn.Value?.toLowerCase())) hasCurl = true;
@@ -1214,15 +1264,16 @@ function scanArgsForDynamicExec(args, startIdx) {
1214
1264
  }
1215
1265
  function detectDangerousShellExec(command) {
1216
1266
  try {
1217
- const f = sharedParser.Parse(command, "cmd");
1267
+ const f = parseShared(command);
1268
+ if (f === PARSE_FAIL) return null;
1218
1269
  let result = null;
1219
1270
  const assigned = assignedNames(f);
1220
- syntax.Walk(f, (node) => {
1271
+ walk(f, (node) => {
1221
1272
  if (!node || result === "block") return false;
1222
1273
  const n = node;
1223
- if (syntax.NodeType(n) === "BinaryCmd" && n.Y && !listOps().has(n.Op)) {
1274
+ if (n.kind === "BinaryCmd" && n.Y && !listOps().has(n.Op)) {
1224
1275
  const call = n.Y.Cmd;
1225
- if (call && syntax.NodeType(call) === "CallExpr") {
1276
+ if (call && call.kind === "CallExpr") {
1226
1277
  const words = (call.Args || []).map((a) => resolveWordLiteral(a));
1227
1278
  const head2 = unwrapCommandHead(words);
1228
1279
  const name = (words[head2] ?? "").split("/").pop() ?? "";
@@ -1235,7 +1286,7 @@ function detectDangerousShellExec(command) {
1235
1286
  result = "review";
1236
1287
  }
1237
1288
  }
1238
- if (syntax.NodeType(n) !== "CallExpr") return true;
1289
+ if (n.kind !== "CallExpr") return true;
1239
1290
  const args = n.Args || [];
1240
1291
  if (args.length === 0) return true;
1241
1292
  const headWords = args.map(
@@ -1246,7 +1297,7 @@ function detectDangerousShellExec(command) {
1246
1297
  if (!lookup && (opaqueExecutable(args[0], assigned) || opaqueExecutable(args[head], assigned)))
1247
1298
  result = "review";
1248
1299
  const firstParts = args[0].Parts || [];
1249
- if (firstParts.length !== 1 || syntax.NodeType(firstParts[0]) !== "Lit") return true;
1300
+ if (firstParts.length !== 1 || firstParts[0].kind !== "Lit") return true;
1250
1301
  const cmdName = firstParts[0].Value?.toLowerCase() ?? "";
1251
1302
  if (cmdName === "eval") {
1252
1303
  const v = scanArgsForDynamicExec(args, 1);
@@ -1254,7 +1305,7 @@ function detectDangerousShellExec(command) {
1254
1305
  } else if (SHELL_INTERPRETERS.has(cmdName)) {
1255
1306
  for (let i = 1; i < args.length - 1; i++) {
1256
1307
  const flagParts = args[i].Parts || [];
1257
- if (flagParts.length !== 1 || syntax.NodeType(flagParts[0]) !== "Lit" || flagParts[0].Value !== "-c")
1308
+ if (flagParts.length !== 1 || flagParts[0].kind !== "Lit" || flagParts[0].Value !== "-c")
1258
1309
  continue;
1259
1310
  const v = scanArgsForDynamicExec(args, i + 1);
1260
1311
  if (v === "block" || v === "review" && result === null) result = v;
@@ -1278,8 +1329,7 @@ function isDefaultExpansion(part) {
1278
1329
  }
1279
1330
  function lookupSubstitution(part) {
1280
1331
  const stmts = part.Stmts ?? [];
1281
- if (stmts.length !== 1 || !stmts[0].Cmd || syntax.NodeType(stmts[0].Cmd) !== "CallExpr")
1282
- return null;
1332
+ if (stmts.length !== 1 || !stmts[0].Cmd || stmts[0].Cmd.kind !== "CallExpr") return null;
1283
1333
  const words = (stmts[0].Cmd.Args ?? []).map((a) => resolveWordLiteral(a));
1284
1334
  if (words.some((w) => w === null)) return null;
1285
1335
  if (words.length === 2 && words[0] === "which") return words[1];
@@ -1289,9 +1339,9 @@ function lookupSubstitution(part) {
1289
1339
  }
1290
1340
  function assignedNames(f) {
1291
1341
  const names = /* @__PURE__ */ new Set();
1292
- syntax.Walk(f, (node) => {
1342
+ walk(f, (node) => {
1293
1343
  if (!node) return false;
1294
- const kind = syntax.NodeType(node);
1344
+ const kind = node.kind;
1295
1345
  if (kind === "Assign" && node.Name?.Value) names.add(node.Name.Value);
1296
1346
  if (kind === "ForClause" && node.Loop?.Name?.Value) names.add(node.Loop.Name.Value);
1297
1347
  if (kind === "CallExpr") {
@@ -1306,7 +1356,7 @@ function assignedNames(f) {
1306
1356
  }
1307
1357
  function executableParts(word, assigned, quoted = false) {
1308
1358
  return (word?.Parts ?? []).flatMap((part) => {
1309
- const kind = syntax.NodeType(part);
1359
+ const kind = part.kind;
1310
1360
  if (kind === "DblQuoted") return executableParts(part, assigned, true);
1311
1361
  if (kind === "Lit") return [{ kind: "Lit", value: part.Value ?? "", quoted }];
1312
1362
  if (kind === "SglQuoted")
@@ -1374,10 +1424,10 @@ function chmodHasOpenPermMode(command) {
1374
1424
  if (f === PARSE_FAIL) return false;
1375
1425
  let found = false;
1376
1426
  try {
1377
- syntax.Walk(f, (node) => {
1427
+ walk(f, (node) => {
1378
1428
  if (!node || found) return false;
1379
1429
  const n = node;
1380
- if (syntax.NodeType(n) !== "CallExpr") return true;
1430
+ if (n.kind !== "CallExpr") return true;
1381
1431
  const words = (n.Args || []).map((a) => resolveWordLiteral(a));
1382
1432
  if (words.length === 0) return true;
1383
1433
  const name = (words[0] ?? "").toLowerCase();
@@ -1430,11 +1480,11 @@ function redirStdinOps() {
1430
1480
  }
1431
1481
  function deriveBinaryOp(sample) {
1432
1482
  try {
1433
- const f = sharedParser.Parse(sample, "cmd");
1483
+ const f = toPlainTree(sharedParser.Parse(sample, "cmd"));
1434
1484
  let op = -1;
1435
- syntax.Walk(f, (node) => {
1485
+ walk(f, (node) => {
1436
1486
  const n = node;
1437
- if (n && syntax.NodeType(n) === "BinaryCmd" && op < 0) op = n.Op;
1487
+ if (n && n.kind === "BinaryCmd" && op < 0) op = n.Op;
1438
1488
  return true;
1439
1489
  });
1440
1490
  return op;
@@ -1508,7 +1558,7 @@ function heredocText(word) {
1508
1558
  const parts = word?.Parts ?? [];
1509
1559
  let out = "";
1510
1560
  for (const p of parts) {
1511
- if (syntax.NodeType(p) !== "Lit") return null;
1561
+ if (p.kind !== "Lit") return null;
1512
1562
  out += p.Value ?? "";
1513
1563
  }
1514
1564
  return out;
@@ -1544,7 +1594,7 @@ function attachedCode(interp, flag) {
1544
1594
  }
1545
1595
  function inlineExecCall(stmt, pipeFed) {
1546
1596
  const cmd = stmt?.Cmd;
1547
- if (!cmd || syntax.NodeType(cmd) !== "CallExpr") return null;
1597
+ if (!cmd || cmd.kind !== "CallExpr") return null;
1548
1598
  const words = (cmd.Args || []).map((a) => resolveWordLiteral(a));
1549
1599
  if (words.length === 0) return null;
1550
1600
  const headIdx = unwrapCommandHead(words);
@@ -1625,10 +1675,10 @@ function shellPayloadNeedsReview(payload) {
1625
1675
  let review = false;
1626
1676
  payloadNesting++;
1627
1677
  try {
1628
- syntax.Walk(f, (node) => {
1678
+ walk(f, (node) => {
1629
1679
  if (!node || review) return false;
1630
1680
  const n = node;
1631
- if (syntax.NodeType(n) !== "CallExpr") return true;
1681
+ if (n.kind !== "CallExpr") return true;
1632
1682
  const words = (n.Args || []).map((a) => resolveWordLiteral(a));
1633
1683
  if (words.length === 0) return true;
1634
1684
  const h = unwrapCommandHead(words);
@@ -1662,10 +1712,10 @@ function inlineExecCalls(command) {
1662
1712
  if (f === PARSE_FAIL) return PARSE_FAIL;
1663
1713
  const calls = [];
1664
1714
  try {
1665
- syntax.Walk(f, (node) => {
1715
+ walk(f, (node) => {
1666
1716
  if (!node || calls.length >= MAX_INLINE_CALLS) return false;
1667
1717
  const n = node;
1668
- const t = syntax.NodeType(n);
1718
+ const t = n.kind;
1669
1719
  if (t === "BinaryCmd" && n.Y && !listOps().has(n.Op)) {
1670
1720
  const call = inlineExecCall(n.Y, true);
1671
1721
  if (call) calls.push(call);
@@ -1800,7 +1850,7 @@ function shellScriptOperands(command) {
1800
1850
  walkWithCalls(f, (node) => {
1801
1851
  if (!node) return false;
1802
1852
  const n = node;
1803
- if (syntax.NodeType(n) !== "CallExpr") return true;
1853
+ if (n.kind !== "CallExpr") return true;
1804
1854
  const callArgs = n.Args || [];
1805
1855
  if (callArgs.length === 0) return true;
1806
1856
  const words = callArgs.map((a) => resolveWordLiteral(a));
@@ -1836,7 +1886,7 @@ function shellScriptOperands(command) {
1836
1886
  }
1837
1887
  function windowsDrivePathSpelling(word) {
1838
1888
  const parts = word?.Parts || [];
1839
- if (parts.length === 0 || !parts.every((p) => syntax.NodeType(p) === "Lit")) return null;
1889
+ if (parts.length === 0 || !parts.every((p) => p.kind === "Lit")) return null;
1840
1890
  const raw = parts.map((p) => p.Value ?? "").join("");
1841
1891
  return /^[A-Za-z]:\\[^\s'"$`]*$/.test(raw) ? raw : null;
1842
1892
  }
@@ -1874,15 +1924,15 @@ function recordTopLevelAssignments(f) {
1874
1924
  }
1875
1925
  function probeBinOp(src) {
1876
1926
  try {
1877
- const cmd = syntax.NewParser().Parse(src, "probe")?.Stmts?.[0]?.Cmd;
1878
- if (cmd && syntax.NodeType(cmd) === "BinaryCmd") return cmd.Op;
1927
+ const cmd = toPlainTree(syntax2.NewParser().Parse(src, "probe"))?.Stmts?.[0]?.Cmd;
1928
+ if (cmd && cmd.kind === "BinaryCmd") return cmd.Op;
1879
1929
  } catch {
1880
1930
  }
1881
1931
  return null;
1882
1932
  }
1883
1933
  function recordTopLevelStmt(stmt) {
1884
1934
  if (!stmt || !stmt.Cmd) return false;
1885
- const t = syntax.NodeType(stmt.Cmd);
1935
+ const t = stmt.Cmd.kind;
1886
1936
  if (t === "BinaryCmd") {
1887
1937
  if (!AND_OR_OPS.has(stmt.Cmd.Op)) return false;
1888
1938
  if (!recordTopLevelStmt(stmt.Cmd.X)) return false;
@@ -1892,7 +1942,7 @@ function recordTopLevelStmt(stmt) {
1892
1942
  if (t !== "CallExpr" && t !== "DeclClause") return false;
1893
1943
  let at = 0;
1894
1944
  try {
1895
- at = stmt.Pos().Offset();
1945
+ at = stmt.pos;
1896
1946
  } catch {
1897
1947
  at = 0;
1898
1948
  }
@@ -1903,14 +1953,14 @@ function recordTopLevelStmt(stmt) {
1903
1953
  }
1904
1954
  function recordAssignments(n, at) {
1905
1955
  if (!assignmentTable) return;
1906
- const t = syntax.NodeType(n);
1956
+ const t = n.kind;
1907
1957
  let assigns = [];
1908
1958
  if (t === "CallExpr") {
1909
1959
  if ((n.Args || []).length > 0) return;
1910
1960
  assigns = n.Assigns || [];
1911
1961
  } else if (t === "DeclClause") {
1912
1962
  if (!ASSIGNMENT_HEADS.has(n.Variant?.Value ?? "")) return;
1913
- assigns = (n.Args || []).filter((a) => syntax.NodeType(a) === "Assign");
1963
+ assigns = (n.Args || []).filter((a) => a.kind === "Assign");
1914
1964
  } else return;
1915
1965
  for (const a of assigns) {
1916
1966
  const name = a?.Name?.Value;
@@ -1919,13 +1969,13 @@ function recordAssignments(n, at) {
1919
1969
  }
1920
1970
  }
1921
1971
  function resolveTrivialSubst(part) {
1922
- if (syntax.NodeType(part) !== "CmdSubst") return void 0;
1972
+ if (part.kind !== "CmdSubst") return void 0;
1923
1973
  const stmts = part.Stmts || [];
1924
1974
  if (stmts.length !== 1) return void 0;
1925
1975
  const st = stmts[0];
1926
1976
  if ((st.Redirs || []).length > 0 || st.Negated || st.Background) return void 0;
1927
1977
  const cmd = st.Cmd;
1928
- if (!cmd || syntax.NodeType(cmd) !== "CallExpr") return void 0;
1978
+ if (!cmd || cmd.kind !== "CallExpr") return void 0;
1929
1979
  if ((cmd.Assigns || []).length > 0) return void 0;
1930
1980
  const words = (cmd.Args || []).map((a) => resolveWordLiteral(a));
1931
1981
  if (words.length === 0 || words.some((w) => w === null)) return void 0;
@@ -1950,7 +2000,7 @@ function recordedExpansion(name) {
1950
2000
  return rec.value;
1951
2001
  }
1952
2002
  function isPlainParam(p) {
1953
- if (syntax.NodeType(p) !== "ParamExp") return false;
2003
+ if (p.kind !== "ParamExp") return false;
1954
2004
  return !(p.Excl || p.Length || p.Width || p.Index || p.Slice || p.Repl || p.Exp);
1955
2005
  }
1956
2006
  function expandPlainParam(p) {
@@ -1962,9 +2012,9 @@ function expandPlainParam(p) {
1962
2012
  }
1963
2013
  function functionBodies(f) {
1964
2014
  const out = /* @__PURE__ */ new Map();
1965
- syntax.Walk(f, (node) => {
2015
+ walk(f, (node) => {
1966
2016
  const n = node;
1967
- if (n && syntax.NodeType(n) === "FuncDecl" && n.Name?.Value && n.Body) {
2017
+ if (n && n.kind === "FuncDecl" && n.Name?.Value && n.Body) {
1968
2018
  const list = out.get(n.Name.Value) ?? [];
1969
2019
  list.push(n.Body);
1970
2020
  out.set(n.Name.Value, list);
@@ -1975,10 +2025,10 @@ function functionBodies(f) {
1975
2025
  }
1976
2026
  function rebindsPositionals(body) {
1977
2027
  let found = false;
1978
- syntax.Walk(body, (node) => {
2028
+ walk(body, (node) => {
1979
2029
  const n = node;
1980
2030
  if (found || !n) return false;
1981
- if (syntax.NodeType(n) === "CallExpr") {
2031
+ if (n.kind === "CallExpr") {
1982
2032
  const words = (n.Args || []).map((a) => resolveWordLiteral(a));
1983
2033
  if (words[0] === "shift") found = true;
1984
2034
  else if (words[0] === "set" && words.slice(1).some((w) => w === null || w === "--" || !/^[-+]/.test(w)))
@@ -1998,7 +2048,7 @@ function tableBindings() {
1998
2048
  function walkWithCalls(f, visit) {
1999
2049
  const bodies = functionBodies(f);
2000
2050
  if (bodies.size === 0) {
2001
- syntax.Walk(f, visit);
2051
+ walk(f, visit);
2002
2052
  return;
2003
2053
  }
2004
2054
  const seenCalls = /* @__PURE__ */ new Set();
@@ -2032,8 +2082,8 @@ function walkWithCalls(f, visit) {
2032
2082
  currentStmtOffset = Number.MAX_SAFE_INTEGER;
2033
2083
  callDepth++;
2034
2084
  try {
2035
- if (body.Cmd && syntax.NodeType(body.Cmd) === "Block") recordTopLevelAssignments(body.Cmd);
2036
- syntax.Walk(body, step);
2085
+ if (body.Cmd && body.Cmd.kind === "Block") recordTopLevelAssignments(body.Cmd);
2086
+ walk(body, step);
2037
2087
  } finally {
2038
2088
  callDepth--;
2039
2089
  assignmentTable = outerTable;
@@ -2044,10 +2094,10 @@ function walkWithCalls(f, visit) {
2044
2094
  const step = (node) => {
2045
2095
  if (!node) return false;
2046
2096
  const go = visit(node);
2047
- if (go !== false && syntax.NodeType(node) === "CallExpr") inline(node);
2097
+ if (go !== false && node.kind === "CallExpr") inline(node);
2048
2098
  return go;
2049
2099
  };
2050
- syntax.Walk(f, step);
2100
+ walk(f, step);
2051
2101
  }
2052
2102
  function withAssignments(f, body) {
2053
2103
  const outerTable = assignmentTable;
@@ -2072,7 +2122,7 @@ function walkCommandScope(command, visit) {
2072
2122
  if (f === PARSE_FAIL) return "parse-fail";
2073
2123
  withAssignments(f, () => {
2074
2124
  walkWithCalls(f, (node) => {
2075
- if (node && syntax.NodeType(node) === "Stmt") trackStatement(node);
2125
+ if (node && node.kind === "Stmt") trackStatement(node);
2076
2126
  return visit(node);
2077
2127
  });
2078
2128
  });
@@ -2080,7 +2130,7 @@ function walkCommandScope(command, visit) {
2080
2130
  }
2081
2131
  function trackStatement(n) {
2082
2132
  try {
2083
- currentStmtOffset = n.Pos().Offset();
2133
+ currentStmtOffset = n.pos;
2084
2134
  } catch {
2085
2135
  currentStmtOffset = Number.MAX_SAFE_INTEGER;
2086
2136
  }
@@ -2096,11 +2146,11 @@ function resolveWordLiteral(w) {
2096
2146
  return s;
2097
2147
  }
2098
2148
  function resolveWordPrefix(w) {
2099
- const walk2 = (parts) => {
2149
+ const walk3 = (parts) => {
2100
2150
  let s = "";
2101
2151
  for (const p of parts) {
2102
2152
  if (p && typeof p === "object" && Array.isArray(p.Parts) && p.Dollar !== void 0) {
2103
- const inner = walk2(p.Parts);
2153
+ const inner = walk3(p.Parts);
2104
2154
  s += inner.prefix;
2105
2155
  if (inner.dynamic) return { prefix: s, dynamic: true };
2106
2156
  continue;
@@ -2111,10 +2161,10 @@ function resolveWordPrefix(w) {
2111
2161
  }
2112
2162
  return { prefix: s, dynamic: false };
2113
2163
  };
2114
- return walk2(w?.Parts || []);
2164
+ return walk3(w?.Parts || []);
2115
2165
  }
2116
2166
  function resolvePart(p, inQuotes) {
2117
- const t = syntax.NodeType(p);
2167
+ const t = p.kind;
2118
2168
  if (t === "Lit") {
2119
2169
  const raw = p.Value ?? "";
2120
2170
  if (!inQuotes) return raw.replace(/\\(.)/g, "$1");
@@ -2210,7 +2260,7 @@ function extractShellDestinations(command) {
2210
2260
  () => walkWithCalls(f, (node) => {
2211
2261
  if (!node) return false;
2212
2262
  const n = node;
2213
- if (syntax.NodeType(n) === "Stmt") {
2263
+ if (n.kind === "Stmt") {
2214
2264
  trackStatement(n);
2215
2265
  for (const raw of redirectWords(n)) {
2216
2266
  const host2 = devNetRedirectHost(raw);
@@ -2222,7 +2272,7 @@ function extractShellDestinations(command) {
2222
2272
  out.push({ host: host2, binary, raw });
2223
2273
  }
2224
2274
  }
2225
- if (syntax.NodeType(n) !== "CallExpr") return true;
2275
+ if (n.kind !== "CallExpr") return true;
2226
2276
  const callArgs = n.Args || [];
2227
2277
  if (callArgs.length === 0) return true;
2228
2278
  const words = callArgs.map((a) => resolveWordLiteral(a));
@@ -2257,7 +2307,7 @@ function extractShellDestTokens(command) {
2257
2307
  () => walkWithCalls(f, (node) => {
2258
2308
  if (!node) return false;
2259
2309
  const n = node;
2260
- if (syntax.NodeType(n) === "Stmt") {
2310
+ if (n.kind === "Stmt") {
2261
2311
  trackStatement(n);
2262
2312
  for (const raw of redirectWords(n)) {
2263
2313
  const host2 = devNetRedirectHost(raw);
@@ -2269,7 +2319,7 @@ function extractShellDestTokens(command) {
2269
2319
  out.push({ token: host2, binary });
2270
2320
  }
2271
2321
  }
2272
- if (syntax.NodeType(n) !== "CallExpr") return true;
2322
+ if (n.kind !== "CallExpr") return true;
2273
2323
  const callArgs = n.Args || [];
2274
2324
  if (callArgs.length === 0) return true;
2275
2325
  const words = callArgs.map((a) => resolveWordLiteral(a));
@@ -2337,11 +2387,11 @@ function isWaivableCleanupTarget(p) {
2337
2387
  }
2338
2388
  function deriveRedirOp(sample) {
2339
2389
  try {
2340
- const f = sharedParser.Parse(sample, "cmd");
2390
+ const f = toPlainTree(sharedParser.Parse(sample, "cmd"));
2341
2391
  let op = -1;
2342
- syntax.Walk(f, (node) => {
2392
+ walk(f, (node) => {
2343
2393
  const n = node;
2344
- if (n && syntax.NodeType(n) === "Redirect" && op < 0) op = n.Op;
2394
+ if (n && n.kind === "Redirect" && op < 0) op = n.Op;
2345
2395
  return true;
2346
2396
  });
2347
2397
  return op;
@@ -2354,7 +2404,7 @@ function collectSameCommandCreations(f) {
2354
2404
  try {
2355
2405
  const stmts = Array.isArray(f?.Stmts) ? f.Stmts : [];
2356
2406
  for (const stmt of stmts) {
2357
- if (!stmt || !stmt.Cmd || syntax.NodeType(stmt.Cmd) !== "CallExpr") continue;
2407
+ if (!stmt || !stmt.Cmd || stmt.Cmd.kind !== "CallExpr") continue;
2358
2408
  const redirs = stmt.Redirs || [];
2359
2409
  if (!redirs.some((r) => r && REDIR_HEREDOC_OPS.has(r.Op))) continue;
2360
2410
  for (const r of redirs) {
@@ -2378,10 +2428,10 @@ function isRmCreatedInCommandCleanup(command) {
2378
2428
  let sawRm = false;
2379
2429
  let ok = true;
2380
2430
  try {
2381
- syntax.Walk(f, (node) => {
2431
+ walk(f, (node) => {
2382
2432
  if (!node || !ok) return false;
2383
2433
  const n = node;
2384
- if (syntax.NodeType(n) !== "CallExpr") return true;
2434
+ if (n.kind !== "CallExpr") return true;
2385
2435
  const args = n.Args || [];
2386
2436
  const name = (resolveWordLiteral(args[0]) ?? "").toLowerCase();
2387
2437
  if (name !== "rm") return true;
@@ -2431,10 +2481,10 @@ function analyzeFsOperationImpl(command, depth = 0) {
2431
2481
  walkWithCalls(f, (node) => {
2432
2482
  if (!node || result?.verdict === "block") return false;
2433
2483
  const n = node;
2434
- const nodeType = syntax.NodeType(n);
2484
+ const nodeType = n.kind;
2435
2485
  if (nodeType === "Stmt") {
2436
2486
  try {
2437
- currentStmtOffset = n.Pos().Offset();
2487
+ currentStmtOffset = n.pos;
2438
2488
  } catch {
2439
2489
  currentStmtOffset = Number.MAX_SAFE_INTEGER;
2440
2490
  }
@@ -2947,11 +2997,12 @@ function analyzeShellCommand(command) {
2947
2997
  if (lower2.startsWith("-")) allTokens.push(lower2.replace(/^-+/, ""));
2948
2998
  };
2949
2999
  try {
2950
- const f = sharedParser.Parse(command, "cmd");
2951
- syntax.Walk(f, (node) => {
3000
+ const f = parseShared(command);
3001
+ if (f === PARSE_FAIL) throw new Error("parse failed");
3002
+ walk(f, (node) => {
2952
3003
  if (!node) return false;
2953
3004
  const n = node;
2954
- if (syntax.NodeType(n) !== "CallExpr") return true;
3005
+ if (n.kind !== "CallExpr") return true;
2955
3006
  const wordValues2 = (n.Args || []).map((arg) => {
2956
3007
  return (arg.Parts || []).map((p) => (p.Value ?? "").replace(/\\(.)/g, "$1")).join("");
2957
3008
  }).filter((s) => s.length > 0);
@@ -3223,7 +3274,7 @@ function runnablePrefix(command) {
3223
3274
  let text = command;
3224
3275
  for (let attempt = 0; attempt < 32; attempt++) {
3225
3276
  try {
3226
- return syntax2.NewParser().Parse(text, "");
3277
+ return toPlainTree(syntax3.NewParser().Parse(text, ""));
3227
3278
  } catch (error) {
3228
3279
  const message = String(typeof error?.Error === "function" ? error.Error() : error?.message);
3229
3280
  const line = Number(/^(\d+):/.exec(message)?.[1]);
@@ -3291,7 +3342,7 @@ function wordValues(word, state) {
3291
3342
  out2 = next.slice(0, MAX_ALTERNATIVES);
3292
3343
  };
3293
3344
  for (const node of nodes) {
3294
- const kind = syntax2.NodeType(node);
3345
+ const kind = node.kind;
3295
3346
  let pieces;
3296
3347
  if (kind === "ParamExp") pieces = paramValues(node, quoted);
3297
3348
  else if (kind === "DblQuoted") {
@@ -3359,9 +3410,9 @@ function collectShellFileAccesses(command, context = {}) {
3359
3410
  }
3360
3411
  function substitutions(word, state, depth) {
3361
3412
  if (!word) return;
3362
- syntax2.Walk(word, (node) => {
3413
+ walk(word, (node) => {
3363
3414
  if (!node) return false;
3364
- if (["CmdSubst", "ProcSubst"].includes(syntax2.NodeType(node))) {
3415
+ if (["CmdSubst", "ProcSubst"].includes(node.kind)) {
3365
3416
  statements(node.Stmts ?? [], clone(state), depth + 1);
3366
3417
  return false;
3367
3418
  }
@@ -3785,7 +3836,7 @@ function collectShellFileAccesses(command, context = {}) {
3785
3836
  }
3786
3837
  function readsScriptFromStdin(stmt) {
3787
3838
  const cmd = stmt?.Cmd;
3788
- if (!cmd || syntax2.NodeType(cmd) !== "CallExpr") return false;
3839
+ if (!cmd || cmd.kind !== "CallExpr") return false;
3789
3840
  const words = (cmd.Args ?? []).map((a) => resolveWordLiteral(a));
3790
3841
  const head = unwrapCommandHead(words);
3791
3842
  return SHELL_INTERPRETERS.has(base(words[head])) && shellConsumesPipe(words.slice(head + 1));
@@ -3799,7 +3850,7 @@ function collectShellFileAccesses(command, context = {}) {
3799
3850
  }
3800
3851
  function producedText(stmt) {
3801
3852
  const cmd = stmt?.Cmd;
3802
- if (!cmd || syntax2.NodeType(cmd) !== "CallExpr") return null;
3853
+ if (!cmd || cmd.kind !== "CallExpr") return null;
3803
3854
  const words = (cmd.Args ?? []).map((a) => resolveWordLiteral(a));
3804
3855
  if (words.some((w) => w === null)) return null;
3805
3856
  const head = unwrapCommandHead(words);
@@ -3818,7 +3869,7 @@ function collectShellFileAccesses(command, context = {}) {
3818
3869
  if (!stmt || depth > MAX_DEPTH) return;
3819
3870
  state.onSuccess = void 0;
3820
3871
  if (stmt.Background) state = clone(state);
3821
- const headWord = stmt.Cmd && syntax2.NodeType(stmt.Cmd) === "CallExpr" ? base(resolveWordLiteral(stmt.Cmd.Args?.[0])) : "";
3872
+ const headWord = stmt.Cmd && stmt.Cmd.kind === "CallExpr" ? base(resolveWordLiteral(stmt.Cmd.Args?.[0])) : "";
3822
3873
  const sends = SENDING_STDIN.has(headWord);
3823
3874
  for (const redir of stmt.Redirs ?? []) {
3824
3875
  substitutions(redir.Word, state, depth);
@@ -3834,7 +3885,7 @@ function collectShellFileAccesses(command, context = {}) {
3834
3885
  const cmd = stmt.Cmd;
3835
3886
  if (!cmd) return;
3836
3887
  stdinScript(stmt, state, depth);
3837
- switch (syntax2.NodeType(cmd)) {
3888
+ switch (cmd.kind) {
3838
3889
  case "CallExpr":
3839
3890
  call(cmd, state, depth);
3840
3891
  break;
@@ -3848,7 +3899,7 @@ function collectShellFileAccesses(command, context = {}) {
3848
3899
  for (; ; ) {
3849
3900
  segments2.unshift({ op: node.Op, part: node.Y });
3850
3901
  const left = node.X;
3851
- if (left?.Cmd && syntax2.NodeType(left.Cmd) === "BinaryCmd" && !left.Redirs?.length && !left.Negated && !left.Background)
3902
+ if (left?.Cmd && left.Cmd.kind === "BinaryCmd" && !left.Redirs?.length && !left.Negated && !left.Background)
3852
3903
  node = left.Cmd;
3853
3904
  else {
3854
3905
  segments2.unshift({ op: node.Op, part: left });
@@ -5218,11 +5269,10 @@ function shellWriteUnseen(command, target) {
5218
5269
  let unseen = false;
5219
5270
  let seen = false;
5220
5271
  try {
5221
- syntax4.Walk(f, (node) => {
5272
+ walk(f, (node) => {
5222
5273
  if (!node || unseen) return false;
5223
5274
  const n = node;
5224
- if (syntax4.NodeType(n) !== "Stmt" || !n.Cmd || syntax4.NodeType(n.Cmd) !== "CallExpr")
5225
- return true;
5275
+ if (n.kind !== "Stmt" || !n.Cmd || n.Cmd.kind !== "CallExpr") return true;
5226
5276
  const words = (n.Cmd.Args || []).map(
5227
5277
  (a) => resolveWordLiteral(a)
5228
5278
  );
@@ -5277,14 +5327,14 @@ function analyzeGitImpl(command) {
5277
5327
  seen.add(key);
5278
5328
  findings.push(f);
5279
5329
  };
5280
- const walk2 = new GitWalk((inv) => classify(inv).forEach(found), found);
5281
- const parsed = walk2.run(command, 0);
5330
+ const walk3 = new GitWalk((inv) => classify(inv).forEach(found), found);
5331
+ const parsed = walk3.run(command, 0);
5282
5332
  return { parsed, findings };
5283
5333
  }
5284
5334
  function isPositionalParam(word) {
5285
5335
  let parts = word?.Parts || [];
5286
- if (parts.length === 1 && syntax5.NodeType(parts[0]) === "DblQuoted") parts = parts[0].Parts || [];
5287
- if (parts.length !== 1 || syntax5.NodeType(parts[0]) !== "ParamExp") return false;
5336
+ if (parts.length === 1 && parts[0].kind === "DblQuoted") parts = parts[0].Parts || [];
5337
+ if (parts.length !== 1 || parts[0].kind !== "ParamExp") return false;
5288
5338
  return /^(\d+|@|\*)$/.test(parts[0].Param?.Value ?? "");
5289
5339
  }
5290
5340
  function boundPositionals() {
@@ -5298,11 +5348,11 @@ function boundPositionals() {
5298
5348
  function plainParamName(word) {
5299
5349
  let parts = word?.Parts || [];
5300
5350
  let quoted = false;
5301
- if (parts.length === 1 && syntax5.NodeType(parts[0]) === "DblQuoted") {
5351
+ if (parts.length === 1 && parts[0].kind === "DblQuoted") {
5302
5352
  parts = parts[0].Parts || [];
5303
5353
  quoted = true;
5304
5354
  }
5305
- if (parts.length !== 1 || syntax5.NodeType(parts[0]) !== "ParamExp") return null;
5355
+ if (parts.length !== 1 || parts[0].kind !== "ParamExp") return null;
5306
5356
  const p = parts[0];
5307
5357
  if (p.Excl || p.Length || p.Width || p.Index || p.Slice || p.Repl || p.Exp) return null;
5308
5358
  const name = p.Param?.Value;
@@ -5327,7 +5377,7 @@ function resolveGitWords(word) {
5327
5377
  }
5328
5378
  const parts = word?.Parts || [];
5329
5379
  const expansion = parts.some((p) => {
5330
- const t = syntax5.NodeType(p);
5380
+ const t = p.kind;
5331
5381
  return t === "ParamExp" || t === "CmdSubst";
5332
5382
  });
5333
5383
  return expansion ? splitFields(value) : [value];
@@ -5728,14 +5778,14 @@ function hookCommands(text) {
5728
5778
  const root = parsed?.hooks;
5729
5779
  if (!root || typeof root !== "object") return null;
5730
5780
  const out = [];
5731
- const walk2 = (v, depth) => {
5781
+ const walk3 = (v, depth) => {
5732
5782
  if (depth > 8 || !v || typeof v !== "object") return;
5733
5783
  for (const [k, x] of Object.entries(v)) {
5734
5784
  if (k === "command" && typeof x === "string") out.push(x);
5735
- else walk2(x, depth + 1);
5785
+ else walk3(x, depth + 1);
5736
5786
  }
5737
5787
  };
5738
- walk2(root, 0);
5788
+ walk3(root, 0);
5739
5789
  return out;
5740
5790
  }
5741
5791
  function hooksDisarmed(text) {
@@ -5902,9 +5952,9 @@ function isDupInOp(op) {
5902
5952
  if (dupInOp === null) {
5903
5953
  let found = -1;
5904
5954
  try {
5905
- syntax6.Walk(parseShared("cat <&3"), (node) => {
5955
+ walk(parseShared("cat <&3"), (node) => {
5906
5956
  const n = node;
5907
- if (found === -1 && n && syntax6.NodeType(n) === "Stmt" && n.Redirs?.[0]) {
5957
+ if (found === -1 && n && n.kind === "Stmt" && n.Redirs?.[0]) {
5908
5958
  found = n.Redirs[0].Op;
5909
5959
  }
5910
5960
  return true;
@@ -5925,10 +5975,10 @@ function analyzeOutbound(command) {
5925
5975
  return hit;
5926
5976
  }
5927
5977
  const findings = [];
5928
- const walk2 = new OutboundWalk(findings);
5929
- const parsed = walk2.run(command, 0);
5978
+ const walk3 = new OutboundWalk(findings);
5979
+ const parsed = walk3.run(command, 0);
5930
5980
  const envOut = findings.find((f) => f.checkId === "data.env-exfil");
5931
- if (envOut) envOut.destinations = walk2.envDestinations();
5981
+ if (envOut) envOut.destinations = walk3.envDestinations();
5932
5982
  const computed = { parsed, findings };
5933
5983
  if (cache2.size >= CACHE_MAX2) {
5934
5984
  const oldest = cache2.keys().next().value;
@@ -5944,7 +5994,7 @@ function wordShape(word) {
5944
5994
  const parts = word?.Parts || [];
5945
5995
  let out = "";
5946
5996
  for (const p of parts) {
5947
- const t = syntax6.NodeType(p);
5997
+ const t = p.kind;
5948
5998
  if (t === "Lit" || t === "SglQuoted") out += p.Value ?? "";
5949
5999
  else if (t === "DblQuoted") out += wordShape(p);
5950
6000
  else out += "X";
@@ -6079,16 +6129,16 @@ function declDumpsEnv(decl) {
6079
6129
  }
6080
6130
  function paramName(word) {
6081
6131
  let parts = word?.Parts || [];
6082
- if (parts.length === 1 && syntax6.NodeType(parts[0]) === "DblQuoted") parts = parts[0].Parts || [];
6083
- if (parts.length !== 1 || syntax6.NodeType(parts[0]) !== "ParamExp") return null;
6132
+ if (parts.length === 1 && parts[0].kind === "DblQuoted") parts = parts[0].Parts || [];
6133
+ if (parts.length !== 1 || parts[0].kind !== "ParamExp") return null;
6084
6134
  return parts[0].Param?.Value ?? null;
6085
6135
  }
6086
6136
  function refersTo(word, names) {
6087
6137
  let hit = false;
6088
- syntax6.Walk(word, (node) => {
6138
+ walk(word, (node) => {
6089
6139
  if (hit || !node) return false;
6090
6140
  const n = node;
6091
- if (syntax6.NodeType(n) === "ParamExp" && names.has(n.Param?.Value)) hit = true;
6141
+ if (n.kind === "ParamExp" && names.has(n.Param?.Value)) hit = true;
6092
6142
  return !hit;
6093
6143
  });
6094
6144
  return hit;
@@ -6096,10 +6146,10 @@ function refersTo(word, names) {
6096
6146
  function runsCommandsIn(stmt) {
6097
6147
  const readVars = /* @__PURE__ */ new Set();
6098
6148
  let hit = false;
6099
- syntax6.Walk(stmt, (node) => {
6149
+ walk(stmt, (node) => {
6100
6150
  if (hit || !node) return false;
6101
6151
  const n = node;
6102
- if (syntax6.NodeType(n) !== "CallExpr") return true;
6152
+ if (n.kind !== "CallExpr") return true;
6103
6153
  const words = wordsOf(n);
6104
6154
  if (words.length === 0) return true;
6105
6155
  const { head, at } = headOf(words);
@@ -6676,7 +6726,7 @@ function localContexts(file2) {
6676
6726
  if (depth > 64) return null;
6677
6727
  if (!stmt || stmt.Background || stmt.Negated || stmt.Redirs?.length) return null;
6678
6728
  const cmd = stmt.Cmd;
6679
- const kind = syntax7.NodeType(cmd);
6729
+ const kind = cmd.kind;
6680
6730
  if (kind === "BinaryCmd" && cmd.Op === andOp) {
6681
6731
  const next = visit(cmd.X, steps, depth + 1);
6682
6732
  return next === null ? null : visit(cmd.Y, next, depth + 1);
@@ -6692,7 +6742,7 @@ function localContexts(file2) {
6692
6742
  )
6693
6743
  ))
6694
6744
  return null;
6695
- contexts.set(cmd.Pos().Offset(), steps);
6745
+ contexts.set(cmd.pos, steps);
6696
6746
  return null;
6697
6747
  }
6698
6748
  if (file2.Stmts?.length === 1) visit(file2.Stmts[0], []);
@@ -6703,12 +6753,12 @@ function collect(command, out, depth) {
6703
6753
  const f = parseShared(command);
6704
6754
  if (typeof f === "symbol") return;
6705
6755
  const contexts = depth === 0 ? localContexts(f) : /* @__PURE__ */ new Map();
6706
- syntax7.Walk(f, (node) => {
6707
- if (node && syntax7.NodeType(node) === "CallExpr") {
6756
+ walk(f, (node) => {
6757
+ if (node && node.kind === "CallExpr") {
6708
6758
  const words = (node.Args || []).map((a) => resolveWordLiteral(a));
6709
6759
  const start = out.length;
6710
6760
  if (words.length > 0) fromCall(words, out, depth);
6711
- const steps = contexts.get(node.Pos().Offset());
6761
+ const steps = contexts.get(node.pos);
6712
6762
  for (let i = start; i < out.length; i++) {
6713
6763
  if (["npx", "bunx", "npm exec"].includes(out[i].manager)) {
6714
6764
  if (!steps) out[i].localCwd = null;
@@ -6755,7 +6805,7 @@ function collect2(command, out, depth) {
6755
6805
  try {
6756
6806
  walkCommandScope(command, (node) => {
6757
6807
  const n = node;
6758
- if (!n || syntax8.NodeType(n) !== "CallExpr") return true;
6808
+ if (!n || n.kind !== "CallExpr") return true;
6759
6809
  const words = (n.Args || []).map((a) => resolveWordLiteral(a));
6760
6810
  if (words.length === 0) return true;
6761
6811
  const prefix = (n.Assigns || []).filter((a) => a?.Name?.Value).map(
@@ -8140,12 +8190,12 @@ function extractContentDestinations(text) {
8140
8190
  function extractArgDestinations(args) {
8141
8191
  const out = /* @__PURE__ */ new Set();
8142
8192
  try {
8143
- walk(args, void 0, out, 0);
8193
+ walk2(args, void 0, out, 0);
8144
8194
  } catch {
8145
8195
  }
8146
8196
  return [...out];
8147
8197
  }
8148
- function walk(value, key, out, depth) {
8198
+ function walk2(value, key, out, depth) {
8149
8199
  if (out.size >= MAX_DESTINATIONS || depth > 12) return;
8150
8200
  if (typeof value === "string") {
8151
8201
  const s = value.length > MAX_SCAN_CHARS ? value.slice(0, MAX_SCAN_CHARS) : value;
@@ -8164,12 +8214,12 @@ function walk(value, key, out, depth) {
8164
8214
  return;
8165
8215
  }
8166
8216
  if (Array.isArray(value)) {
8167
- for (const v of value) walk(v, key, out, depth + 1);
8217
+ for (const v of value) walk2(v, key, out, depth + 1);
8168
8218
  return;
8169
8219
  }
8170
8220
  if (value && typeof value === "object") {
8171
8221
  for (const [k, v] of Object.entries(value))
8172
- walk(v, k, out, depth + 1);
8222
+ walk2(v, k, out, depth + 1);
8173
8223
  }
8174
8224
  }
8175
8225
  function destinationDomain(dest) {
@@ -8821,9 +8871,9 @@ function classifyCall(head, args, prefixes, env, state, out) {
8821
8871
  function walkCalls(command, out, depth, state) {
8822
8872
  const f = parseShared(command);
8823
8873
  if (typeof f === "symbol" || !f) return;
8824
- syntax9.Walk(f, (node) => {
8874
+ walk(f, (node) => {
8825
8875
  if (!node) return false;
8826
- const type = syntax9.NodeType(node);
8876
+ const type = node.kind;
8827
8877
  if (type === "DeclClause") {
8828
8878
  for (const a of node.Args || []) if (a?.Name?.Value) state.env.add(a.Name.Value);
8829
8879
  return true;
@@ -8975,7 +9025,7 @@ function matchCanaryArgs(args, values) {
8975
9025
  if (values.length === 0) return null;
8976
9026
  const needles = prepare(values);
8977
9027
  if (needles.length === 0) return null;
8978
- const walk2 = (v, depth, fieldPath) => {
9028
+ const walk3 = (v, depth, fieldPath) => {
8979
9029
  if (depth > MAX_DEPTH4) return null;
8980
9030
  if (typeof v === "string") {
8981
9031
  const hit = matchPrepared(v, needles);
@@ -8984,31 +9034,31 @@ function matchCanaryArgs(args, values) {
8984
9034
  const trimmed = v.trim();
8985
9035
  if (trimmed.startsWith("{") || trimmed.startsWith("[")) {
8986
9036
  try {
8987
- return walk2(JSON.parse(v), depth + 1, fieldPath);
9037
+ return walk3(JSON.parse(v), depth + 1, fieldPath);
8988
9038
  } catch {
8989
9039
  }
8990
9040
  }
8991
9041
  }
8992
9042
  return null;
8993
9043
  }
8994
- if (typeof v === "number" && Number.isFinite(v)) return walk2(String(v), depth, fieldPath);
9044
+ if (typeof v === "number" && Number.isFinite(v)) return walk3(String(v), depth, fieldPath);
8995
9045
  if (Array.isArray(v)) {
8996
9046
  for (let i = 0; i < v.length; i++) {
8997
- const h = walk2(v[i], depth + 1, `${fieldPath}[${i}]`);
9047
+ const h = walk3(v[i], depth + 1, `${fieldPath}[${i}]`);
8998
9048
  if (h) return h;
8999
9049
  }
9000
9050
  return null;
9001
9051
  }
9002
9052
  if (v && typeof v === "object") {
9003
9053
  for (const [k, child] of Object.entries(v)) {
9004
- const h = walk2(child, depth + 1, fieldPath ? `${fieldPath}.${k}` : k);
9054
+ const h = walk3(child, depth + 1, fieldPath ? `${fieldPath}.${k}` : k);
9005
9055
  if (h) return h;
9006
9056
  }
9007
9057
  }
9008
9058
  return null;
9009
9059
  };
9010
9060
  try {
9011
- return walk2(args, 0, "");
9061
+ return walk3(args, 0, "");
9012
9062
  } catch (e) {
9013
9063
  console.error(
9014
9064
  "[node9 engine] canary args walk failed:",
@@ -9017,7 +9067,7 @@ function matchCanaryArgs(args, values) {
9017
9067
  return null;
9018
9068
  }
9019
9069
  }
9020
- var MAX_REGEX_LENGTH, REGEX_CACHE_MAX, regexCache, aws_default, bash_safe_default, docker_default, filesystem_default, github_default, k8s_default, mongodb_default, postgres_default, project_jail_default, redis_default, finance_default, identity_default, publishing_default, settings_default, branches_default, ACTION_TEMPLATES, ACTION_CHECKS, GAP, prog, httpTo, httpWrite, HTTP_WRITE, HTTP_WRITE_ANY, NOT_STRIPE_TEST, postTo, STRIPE_OBJECTS, APP_SHIELD_SPECS, APP_SHIELDS, APP_SHIELD_NAMES, APP_SERVER_GLOB, GENERAL_ACTION_RULES, BUILTIN_SHIELDS, SSRF_MAX_HOST, METADATA_ADDRESSES, STRICT_TIERS, METADATA_HOSTNAMES, v4Octets, TIER_REASON, CHECK_TEXT, LEVELS, MODE_VALUES, SOFT, STRICT, BLOCK_ALL, LEVEL_CHECKS, VERDICTS, CHECK_VERDICT_RANK, ALL, BUILTIN_DANGEROUS_WORDS, PRODUCT_CHECKS, SHIELD_RULE_NAME, SHIELD_RULES_FOLDED_INTO_PRODUCT, CHECKS, CHECK_BY_ID, LEGACY_TO_ID, PROJECT_JAIL_BLOCK_READ, OVERRIDE_PREFIX, LABEL_WRAPPERS, LEGACY_READERS, INVISIBLE_RE, INVISIBLE_ONE, HOMOGLYPHS, HOMOGLYPH_RE, MAX_BLOBS, MIN_DECODED, BASE64_RUN_RE, HEX_RUN_RE, HEX_ESCAPE_RUN_RE, SYSTEM_AUTH_FILES, SYSTEM_AUTH_DIRS, PASSWORD_HASH_FILES, STARTUP_NAMES, SYSTEM_DIRS, SYSTEM_DIRS_EXEMPT, UPLOAD_SYSTEM_DIRS, AGENT_INSTRUCTION_FILES, AGENT_INSTRUCTION_DIRS, LEGACY_SYSTEM_PATH_RE, MAX_INLINE_CODE, WHAT, OUTSIDE, pyImport, either, PYTHON, NODE, PERL, RUBY, PHP, TABLES, STRING_LITERAL, syntax, sharedParser, MESSAGE_FLAGS, SHELL_INTERPRETERS, DOWNLOAD_CMDS, NORMALIZE_CACHE_MAX, normalizeCache, codeBodiesCache, AST_CACHE_MAX, astCache, PARSE_FAIL, INTERPRETER_LINE, PROGRAM_DIR, ACCESS_VIEW_CACHE_MAX, accessViewCache, MAX_READING_PAYLOADS, STDIN_CODE_INTERPRETERS, RUNS_TEXT_ELSEWHERE, defaultExpansionOps, VARIABLE_READERS, FS_READ_TOOLS, GREP_SHAPE, PATTERN_VERBS, PATTERN_VERB_NAMES, GREP_FILE_OPERANDS, READER_VALUE_LETTERS, FILE_OPERAND_FLAGS, SCP_VALUE_FLAGS, CURL_SOURCE_FLAGS, CURL_VALUE_LETTERS, WGET_VALUE_LETTERS, TAR_VALUE_LETTERS, ZIP_VALUE_LETTERS, RSYNC_VALUE_LETTERS, RSYNC_SKIP, CP_VALUE_LETTERS, INSTALL_VALUE_LETTERS, COPY_VERBS, TAR_MODE_WORD, COPY_VERB_HEADS, FS_OP_PRESCREEN_RE, HOME_CACHE_ALLOWLIST, SENSITIVE_PATH_RULES, AST_FS_REGEX_RULES, SQL_DB_CLIS, SQL_DDL_RE, CHMOD_OPEN_PERM_TOKENS, COMMAND_WRAPPERS, INLINE_INTERPRETER, RUNNER_WRAPPERS, _redirStdinOps, _listOps, WRAPPER_TAKES_TARGET, FIND_EXEC_FLAGS, FS_MUTATION_TOOLS, INTERP_LEADING_TARGET, MAX_PAYLOAD_NESTING, payloadNesting, MAX_INLINE_CALLS, INLINE_EXEC_FALLBACK, UNREADABLE_SOURCE, SCRIPT_RUNNERS, SCRIPT_RUNNER_VALUE_FLAGS, MAX_SCRIPT_OPERANDS, NET_BINARIES, VALUE_FLAGS, HOME_VARIABLES, assignmentTable, currentStmtOffset, PAYLOAD_BUDGET, payloadBudget, seenPayloads, UNANALYSABLE_NESTING, ASSIGNMENT_HEADS, AND_OP, OR_OP, AND_OR_OPS, MAX_CALL_DEPTH, MAX_CALL_WALKS, callDepth, callWalks, FS_OP_CACHE_MAX, fsOpCache, stripDotSlash, REDIR_TRUNCATE_OPS, REDIR_FILE_IN_OPS, REDIR_HEREDOC_OPS, FIND_OPTIONS, COPY_RULE_OF, isReaderWord, positionalAfter, NONE, UNKNOWN, FORBIDDEN_PATH_SEGMENTS, BASH_TOOL_NAMES, MCP_EXECUTORS, BUILTIN_FIELDS, ARGV_FIELDS, BARE_WORD, MAX_ARGV_CHARACTERS, syntax2, MAX_ALTERNATIVES, MAX_CALL_DEPTH2, MAX_CALL_WALKS2, POSITIONAL, MAX_DEPTH, MAX_PAYLOAD_DEPTH, unique, clone, SENDING_STDIN, DOWNLOAD_SHORT_VALUE, DOWNLOAD_LONG_VALUE, DOWNLOAD_OUTPUT_FLAGS, DOWNLOAD_DIR_FLAGS, base, quoteGlob, asWord, WRITES, APPENDS, READS, DUP_OUT, HERE_STRING, AND, OR, DEFAULT_OPS, exempt, RANK, syntax3, SEQUENCE_OPS, BIP39_ENGLISH, BIP39_PUBLIC_VECTORS, indices, lengths, hash, MAX_MNEMONIC_HASHES, SECRET_VIEW_LIMITS, IBAN_LENGTH, IBAN_BBAN_SHAPE, B58, B58_INDEX, XPRV_VERSIONS, B62, CRC32_TABLE, GITHUB_TOKEN_RE, B64URL, B64URL_INDEX, CASK_TWO_ZERO_SUFFIX, CASK_FOUR_ZERO_SUFFIX, CF_ODD, CF_EVEN, SPANISH_LETTERS, HETU_CHARS, VERHOEFF_D, VERHOEFF_P, MAX, UNTRUSTED_TOOLS, INJECTION_SIGNALS, MENTION_QUOTE_RE, MENTION_WORD_RE, ASSIGNMENT_CONTEXT_RE, DLP_STOPWORDS, REFERENCE_VALUE_RE, IDENTIFIER_VALUE_RE, PATH_VALUE_RE, DOTTED_REFERENCE_RE, CONCATENATION_RE, EMAIL_VALUE_RE, FIXTURE_NAME_RE, DERIVATIVE_NAME_RE, QUERY_CREDENTIAL_VALUE_RE, OTP_SECRET_RE, OTP_DOC_SECRETS, ASSIGNED_SECRET_VALUE_RE, ASSIGNED_SECRET_NAME_RE, NAME_KEYWORD_RE, ARN_CONTEXT_RE, CIPHER_KEY_NAME_RE, CIPHER_NAME_PARTS, CIPHER_KEY_VALUE_RE, LARAVEL_KEY_VALUE_RE, SQL_PASSWORD_VALUE_RE, GRAFANA_KEY_VALUE_RE, BASIC_VALUE_RE, BASIC_PAIR_RE, BASIC_HEADER_RE, BASIC_HEADER_PAIR_RE, BASIC_PLACEHOLDER_RE, BASIC_TEMPLATE_MARKERS, DROPBOX_SECRET_RE, OTP_CAPTURE_RE, DB_URL_PASSWORD_RE, DLP_PATTERNS, DLP_PATTERNS_GLOBAL, SENSITIVE_PATH_PATTERNS, SENSITIVE_PATH_REGEXES, MAX_DEPTH2, MAX_STRING_BYTES, MAX_JSON_PARSE_BYTES, BATCH_SEPARATOR, ENCODED_RUN_RE, IMPERATIVE, SECRET_TARGET, GUARD, SIGNALS, DESTINATION_RE, REUSED_SIGNALS, NEVER_NEGATED, NEGATION_BEFORE, syntax4, RDR_IN, COPY_VERBS2, LITERAL_VERBS, syntax5, GIT_PRESCREEN_RE, MAX_PAYLOAD_DEPTH2, MAX_ALIAS_DEPTH, CACHE_MAX, cache, PAYLOAD_SHELLS, CONFIG_SCOPE_FLAGS, CONFIG_VALUE_FLAGS, GLOBAL_VALUE_OPTIONS, GLOBAL_FLAG_OPTIONS, MAX_LOOP_ITEMS, GitWalk, POSITIONAL2, FORCE_PUSH, DESTRUCTIVE, UNREADABLE, PUSH_LONG_VALUE, BRANCH_LONG_VALUE, TAG_LONG_VALUE, CLEAN_LONG_VALUE, HOOKS_BYPASS, NO_VERIFY_SUBS, HOOK_KILL_SWITCHES, COMMIT_LONG_VALUE, CHMOD_OPTION_RE, STAGE_ALL, ADD_LONG_VALUE, CHECK_ID, RULE_NAME, INERT_LINE_RE, CHECK_ID2, INSTRUCTION_NAMES, SETTINGS_RE, HOOK_WORDS_RE, syntax6, SHELLS, NETCATS, NET_CLIENTS, SENDERS, NETCAT_EXEC_LONG, DECL_DUMPS, PROC_ENVIRON_RE, DEV_NET_RE, SOCAT_PROGRAM_RE, SOCAT_NET_RE, PRESCREEN_RE, MAX_PAYLOAD_DEPTH3, CACHE_MAX2, cache2, dupInOp, REVERSE_SHELL_DESCRIPTION, ENV_EXFIL_DESCRIPTION, DYNAMIC_WORD, MULTICALL, SHELL_VALUE_OPTIONS, INTERPRETERS, OutboundWalk, syntax7, NPM_INSTALL_VERBS, NPM_EXEC_VERBS, PNPM_INSTALL_VERBS, YARN_INSTALL_VERBS, BUN_INSTALL_VERBS, DLX_VERBS, NON_REGISTRY_RE, NPM_NAME_RE, EXACT_SEMVER_RE, NPM_VALUE_FLAGS, PNPM_VALUE_FLAGS, YARN_VALUE_FLAGS, BUN_VALUE_FLAGS, PIP_VALUE_FLAGS, UV_VALUE_FLAGS, POETRY_VALUE_FLAGS, PIPENV_VALUE_FLAGS, PIPX_VALUE_FLAGS, PY_SPEC_RE, PY_EXACT_RE, EXACT_VERSION_RE, GEM_NAME_RE, GEM_VALUE_FLAGS, BUNDLE_VALUE_FLAGS, CRATE_NAME_RE, CARGO_ADD_VALUE_FLAGS, CARGO_INSTALL_VALUE_FLAGS, GO_VALUE_FLAGS, GO_PATH_RE, NUGET_NAME_RE, DOTNET_ADD_VALUE_FLAGS, DOTNET_TOOL_VALUE_FLAGS, NUGET_VALUE_FLAGS, MAVEN_COORD_RE, COMPOSER_NAME_RE, COMPOSER_VALUE_FLAGS, EDITOR_HEADS, EXTENSION_ID_RE, MANAGER_HEADS, SHELLS2, MAX_NESTING, SHELL_VALUE_FLAGS, syntax8, NPM_FAMILY, PIP_FAMILY, NPM_FETCH_VERBS, PIP_FETCH_VERBS, NPM_FLAGS, PIP_FLAGS, NPM_VARS, PIP_VARS, PRESCREEN_RE2, PIP_ATTACHED_RE, MAX_PAYLOAD_DEPTH4, PUBLIC_REGISTRY_HOSTS, TUNING_FIELDS, MAP_GOVERNED, KNOB_GOVERNED, CONFIGURABLE_CHECK_IDS, DEFAULT_EGRESS_ALLOWLIST, PRIVATE_HOST_SUFFIXES, SOURCE_COMMANDS, SINK_COMMANDS, OBFUSCATORS, SENSITIVE_PATTERNS, FLAGS_WITH_VALUES, DESTINATION_ARGS, MCP_DESTINATION_KEYS, ARGUMENT_SCAN_LIMITS, RUN_CHAR, runChar, VERDICT_RANK, SQL_DML_KEYWORDS, MAX_DESTINATIONS, MAX_SCAN_CHARS, EMAIL_RE, URL_RE, IBAN_RE, RECIPIENT_KEYS, DESTRUCTIVE_VERB_RE, PII_EMAIL_RE, PII_SSN_RE, PII_PHONE_RE, PII_CC16_RE, PII_CC15_RE, PII_CC14_RE, PII_CC13_RE, PII_CC19_RE, CARD_PATTERNS, PII_ROUTING_RE, ROUTING_LABEL_RE, ROUTING_LABEL_WINDOW, NATIONAL_ID_SHAPES, NATIONAL_ID_LABEL_RE, NATIONAL_ID_LABEL_CS_RE, idLabelIn, NATIONAL_ID_LABEL_WINDOW, NATIONAL_ID_GUARD_RE, PII_IBAN_RE, REALTIME_PII_PATTERNS, MAX_PII_SCAN_BYTES, IBAN_DESTINATION_KEYS, WHOLE_IBAN_RE, JSON_ESCAPE_RE, JSON_ESCAPES, MASKED_KINDS, ENTRY_RE, IBAN_TEXT_RE, EMAIL_TEXT_RE, ACCOUNT_KEY_RE, ACCOUNT_VALUE_RE, MAX_MASK_DEPTH, syntax9, EMPTY, CURL_SEND_FLAGS, WGET_SEND_FLAGS, IWR_SEND_FLAGS, WRITE_METHODS, GH_READ, GH_WRITE, GH_HOSTNAME_FLAGS, GH_REPO_VALUE_FLAGS, GH_API_VALUE_FLAGS, GIT_FETCH, PUBLISH, SHELLS3, OWN_HEADS, MAX_DEPTH3, CWD_CHANGERS, TERMINAL_ESCAPE_RE, LOOP_MAX_RECORDS, CANARY_MIN_LENGTH, MAX_TEXT, MAX_DEPTH4, MAX_JSON_PARSE, URL_DEPTH, B64_DEPTH, MIN_SEGMENT, SEPARATORS, stripSeparators, looksText, CANARY_DECODERS, VIEWS, LONG_OUTPUT_THRESHOLD_BYTES, CANONICAL_EXTRACTOR_VERSION;
9070
+ var MAX_REGEX_LENGTH, REGEX_CACHE_MAX, regexCache, aws_default, bash_safe_default, docker_default, filesystem_default, github_default, k8s_default, mongodb_default, postgres_default, project_jail_default, redis_default, finance_default, identity_default, publishing_default, settings_default, branches_default, ACTION_TEMPLATES, ACTION_CHECKS, GAP, prog, httpTo, httpWrite, HTTP_WRITE, HTTP_WRITE_ANY, NOT_STRIPE_TEST, postTo, STRIPE_OBJECTS, APP_SHIELD_SPECS, APP_SHIELDS, APP_SHIELD_NAMES, APP_SERVER_GLOB, GENERAL_ACTION_RULES, BUILTIN_SHIELDS, SSRF_MAX_HOST, METADATA_ADDRESSES, STRICT_TIERS, METADATA_HOSTNAMES, v4Octets, TIER_REASON, CHECK_TEXT, LEVELS, MODE_VALUES, SOFT, STRICT, BLOCK_ALL, LEVEL_CHECKS, VERDICTS, CHECK_VERDICT_RANK, ALL, BUILTIN_DANGEROUS_WORDS, PRODUCT_CHECKS, SHIELD_RULE_NAME, SHIELD_RULES_FOLDED_INTO_PRODUCT, CHECKS, CHECK_BY_ID, LEGACY_TO_ID, PROJECT_JAIL_BLOCK_READ, OVERRIDE_PREFIX, LABEL_WRAPPERS, LEGACY_READERS, syntax, KINDS, STRUCTS, unknownKinds, INVISIBLE_RE, INVISIBLE_ONE, HOMOGLYPHS, HOMOGLYPH_RE, MAX_BLOBS, MIN_DECODED, BASE64_RUN_RE, HEX_RUN_RE, HEX_ESCAPE_RUN_RE, SYSTEM_AUTH_FILES, SYSTEM_AUTH_DIRS, PASSWORD_HASH_FILES, STARTUP_NAMES, SYSTEM_DIRS, SYSTEM_DIRS_EXEMPT, UPLOAD_SYSTEM_DIRS, AGENT_INSTRUCTION_FILES, AGENT_INSTRUCTION_DIRS, LEGACY_SYSTEM_PATH_RE, MAX_INLINE_CODE, WHAT, OUTSIDE, pyImport, either, PYTHON, NODE, PERL, RUBY, PHP, TABLES, STRING_LITERAL, syntax2, sharedParser, MESSAGE_FLAGS, SHELL_INTERPRETERS, DOWNLOAD_CMDS, NORMALIZE_CACHE_MAX, normalizeCache, codeBodiesCache, AST_CACHE_MAX, astCache, PARSE_FAIL, INTERPRETER_LINE, PROGRAM_DIR, ACCESS_VIEW_CACHE_MAX, accessViewCache, MAX_READING_PAYLOADS, STDIN_CODE_INTERPRETERS, RUNS_TEXT_ELSEWHERE, defaultExpansionOps, VARIABLE_READERS, FS_READ_TOOLS, GREP_SHAPE, PATTERN_VERBS, PATTERN_VERB_NAMES, GREP_FILE_OPERANDS, READER_VALUE_LETTERS, FILE_OPERAND_FLAGS, SCP_VALUE_FLAGS, CURL_SOURCE_FLAGS, CURL_VALUE_LETTERS, WGET_VALUE_LETTERS, TAR_VALUE_LETTERS, ZIP_VALUE_LETTERS, RSYNC_VALUE_LETTERS, RSYNC_SKIP, CP_VALUE_LETTERS, INSTALL_VALUE_LETTERS, COPY_VERBS, TAR_MODE_WORD, COPY_VERB_HEADS, FS_OP_PRESCREEN_RE, HOME_CACHE_ALLOWLIST, SENSITIVE_PATH_RULES, AST_FS_REGEX_RULES, SQL_DB_CLIS, SQL_DDL_RE, CHMOD_OPEN_PERM_TOKENS, COMMAND_WRAPPERS, INLINE_INTERPRETER, RUNNER_WRAPPERS, _redirStdinOps, _listOps, WRAPPER_TAKES_TARGET, FIND_EXEC_FLAGS, FS_MUTATION_TOOLS, INTERP_LEADING_TARGET, MAX_PAYLOAD_NESTING, payloadNesting, MAX_INLINE_CALLS, INLINE_EXEC_FALLBACK, UNREADABLE_SOURCE, SCRIPT_RUNNERS, SCRIPT_RUNNER_VALUE_FLAGS, MAX_SCRIPT_OPERANDS, NET_BINARIES, VALUE_FLAGS, HOME_VARIABLES, assignmentTable, currentStmtOffset, PAYLOAD_BUDGET, payloadBudget, seenPayloads, UNANALYSABLE_NESTING, ASSIGNMENT_HEADS, AND_OP, OR_OP, AND_OR_OPS, MAX_CALL_DEPTH, MAX_CALL_WALKS, callDepth, callWalks, FS_OP_CACHE_MAX, fsOpCache, stripDotSlash, REDIR_TRUNCATE_OPS, REDIR_FILE_IN_OPS, REDIR_HEREDOC_OPS, FIND_OPTIONS, COPY_RULE_OF, isReaderWord, positionalAfter, NONE, UNKNOWN, FORBIDDEN_PATH_SEGMENTS, BASH_TOOL_NAMES, MCP_EXECUTORS, BUILTIN_FIELDS, ARGV_FIELDS, BARE_WORD, MAX_ARGV_CHARACTERS, syntax3, MAX_ALTERNATIVES, MAX_CALL_DEPTH2, MAX_CALL_WALKS2, POSITIONAL, MAX_DEPTH, MAX_PAYLOAD_DEPTH, unique, clone, SENDING_STDIN, DOWNLOAD_SHORT_VALUE, DOWNLOAD_LONG_VALUE, DOWNLOAD_OUTPUT_FLAGS, DOWNLOAD_DIR_FLAGS, base, quoteGlob, asWord, WRITES, APPENDS, READS, DUP_OUT, HERE_STRING, AND, OR, DEFAULT_OPS, exempt, RANK, SEQUENCE_OPS, BIP39_ENGLISH, BIP39_PUBLIC_VECTORS, indices, lengths, hash, MAX_MNEMONIC_HASHES, SECRET_VIEW_LIMITS, IBAN_LENGTH, IBAN_BBAN_SHAPE, B58, B58_INDEX, XPRV_VERSIONS, B62, CRC32_TABLE, GITHUB_TOKEN_RE, B64URL, B64URL_INDEX, CASK_TWO_ZERO_SUFFIX, CASK_FOUR_ZERO_SUFFIX, CF_ODD, CF_EVEN, SPANISH_LETTERS, HETU_CHARS, VERHOEFF_D, VERHOEFF_P, MAX, UNTRUSTED_TOOLS, INJECTION_SIGNALS, MENTION_QUOTE_RE, MENTION_WORD_RE, ASSIGNMENT_CONTEXT_RE, DLP_STOPWORDS, REFERENCE_VALUE_RE, IDENTIFIER_VALUE_RE, PATH_VALUE_RE, DOTTED_REFERENCE_RE, CONCATENATION_RE, EMAIL_VALUE_RE, FIXTURE_NAME_RE, DERIVATIVE_NAME_RE, QUERY_CREDENTIAL_VALUE_RE, OTP_SECRET_RE, OTP_DOC_SECRETS, ASSIGNED_SECRET_VALUE_RE, ASSIGNED_SECRET_NAME_RE, NAME_KEYWORD_RE, ARN_CONTEXT_RE, CIPHER_KEY_NAME_RE, CIPHER_NAME_PARTS, CIPHER_KEY_VALUE_RE, LARAVEL_KEY_VALUE_RE, SQL_PASSWORD_VALUE_RE, GRAFANA_KEY_VALUE_RE, BASIC_VALUE_RE, BASIC_PAIR_RE, BASIC_HEADER_RE, BASIC_HEADER_PAIR_RE, BASIC_PLACEHOLDER_RE, BASIC_TEMPLATE_MARKERS, DROPBOX_SECRET_RE, OTP_CAPTURE_RE, DB_URL_PASSWORD_RE, DLP_PATTERNS, DLP_PATTERNS_GLOBAL, SENSITIVE_PATH_PATTERNS, SENSITIVE_PATH_REGEXES, MAX_DEPTH2, MAX_STRING_BYTES, MAX_JSON_PARSE_BYTES, BATCH_SEPARATOR, ENCODED_RUN_RE, IMPERATIVE, SECRET_TARGET, GUARD, SIGNALS, DESTINATION_RE, REUSED_SIGNALS, NEVER_NEGATED, NEGATION_BEFORE, RDR_IN, COPY_VERBS2, LITERAL_VERBS, GIT_PRESCREEN_RE, MAX_PAYLOAD_DEPTH2, MAX_ALIAS_DEPTH, CACHE_MAX, cache, PAYLOAD_SHELLS, CONFIG_SCOPE_FLAGS, CONFIG_VALUE_FLAGS, GLOBAL_VALUE_OPTIONS, GLOBAL_FLAG_OPTIONS, MAX_LOOP_ITEMS, GitWalk, POSITIONAL2, FORCE_PUSH, DESTRUCTIVE, UNREADABLE, PUSH_LONG_VALUE, BRANCH_LONG_VALUE, TAG_LONG_VALUE, CLEAN_LONG_VALUE, HOOKS_BYPASS, NO_VERIFY_SUBS, HOOK_KILL_SWITCHES, COMMIT_LONG_VALUE, CHMOD_OPTION_RE, STAGE_ALL, ADD_LONG_VALUE, CHECK_ID, RULE_NAME, INERT_LINE_RE, CHECK_ID2, INSTRUCTION_NAMES, SETTINGS_RE, HOOK_WORDS_RE, SHELLS, NETCATS, NET_CLIENTS, SENDERS, NETCAT_EXEC_LONG, DECL_DUMPS, PROC_ENVIRON_RE, DEV_NET_RE, SOCAT_PROGRAM_RE, SOCAT_NET_RE, PRESCREEN_RE, MAX_PAYLOAD_DEPTH3, CACHE_MAX2, cache2, dupInOp, REVERSE_SHELL_DESCRIPTION, ENV_EXFIL_DESCRIPTION, DYNAMIC_WORD, MULTICALL, SHELL_VALUE_OPTIONS, INTERPRETERS, OutboundWalk, NPM_INSTALL_VERBS, NPM_EXEC_VERBS, PNPM_INSTALL_VERBS, YARN_INSTALL_VERBS, BUN_INSTALL_VERBS, DLX_VERBS, NON_REGISTRY_RE, NPM_NAME_RE, EXACT_SEMVER_RE, NPM_VALUE_FLAGS, PNPM_VALUE_FLAGS, YARN_VALUE_FLAGS, BUN_VALUE_FLAGS, PIP_VALUE_FLAGS, UV_VALUE_FLAGS, POETRY_VALUE_FLAGS, PIPENV_VALUE_FLAGS, PIPX_VALUE_FLAGS, PY_SPEC_RE, PY_EXACT_RE, EXACT_VERSION_RE, GEM_NAME_RE, GEM_VALUE_FLAGS, BUNDLE_VALUE_FLAGS, CRATE_NAME_RE, CARGO_ADD_VALUE_FLAGS, CARGO_INSTALL_VALUE_FLAGS, GO_VALUE_FLAGS, GO_PATH_RE, NUGET_NAME_RE, DOTNET_ADD_VALUE_FLAGS, DOTNET_TOOL_VALUE_FLAGS, NUGET_VALUE_FLAGS, MAVEN_COORD_RE, COMPOSER_NAME_RE, COMPOSER_VALUE_FLAGS, EDITOR_HEADS, EXTENSION_ID_RE, MANAGER_HEADS, SHELLS2, MAX_NESTING, SHELL_VALUE_FLAGS, NPM_FAMILY, PIP_FAMILY, NPM_FETCH_VERBS, PIP_FETCH_VERBS, NPM_FLAGS, PIP_FLAGS, NPM_VARS, PIP_VARS, PRESCREEN_RE2, PIP_ATTACHED_RE, MAX_PAYLOAD_DEPTH4, PUBLIC_REGISTRY_HOSTS, TUNING_FIELDS, MAP_GOVERNED, KNOB_GOVERNED, CONFIGURABLE_CHECK_IDS, DEFAULT_EGRESS_ALLOWLIST, PRIVATE_HOST_SUFFIXES, SOURCE_COMMANDS, SINK_COMMANDS, OBFUSCATORS, SENSITIVE_PATTERNS, FLAGS_WITH_VALUES, DESTINATION_ARGS, MCP_DESTINATION_KEYS, ARGUMENT_SCAN_LIMITS, RUN_CHAR, runChar, VERDICT_RANK, SQL_DML_KEYWORDS, MAX_DESTINATIONS, MAX_SCAN_CHARS, EMAIL_RE, URL_RE, IBAN_RE, RECIPIENT_KEYS, DESTRUCTIVE_VERB_RE, PII_EMAIL_RE, PII_SSN_RE, PII_PHONE_RE, PII_CC16_RE, PII_CC15_RE, PII_CC14_RE, PII_CC13_RE, PII_CC19_RE, CARD_PATTERNS, PII_ROUTING_RE, ROUTING_LABEL_RE, ROUTING_LABEL_WINDOW, NATIONAL_ID_SHAPES, NATIONAL_ID_LABEL_RE, NATIONAL_ID_LABEL_CS_RE, idLabelIn, NATIONAL_ID_LABEL_WINDOW, NATIONAL_ID_GUARD_RE, PII_IBAN_RE, REALTIME_PII_PATTERNS, MAX_PII_SCAN_BYTES, IBAN_DESTINATION_KEYS, WHOLE_IBAN_RE, JSON_ESCAPE_RE, JSON_ESCAPES, MASKED_KINDS, ENTRY_RE, IBAN_TEXT_RE, EMAIL_TEXT_RE, ACCOUNT_KEY_RE, ACCOUNT_VALUE_RE, MAX_MASK_DEPTH, EMPTY, CURL_SEND_FLAGS, WGET_SEND_FLAGS, IWR_SEND_FLAGS, WRITE_METHODS, GH_READ, GH_WRITE, GH_HOSTNAME_FLAGS, GH_REPO_VALUE_FLAGS, GH_API_VALUE_FLAGS, GIT_FETCH, PUBLISH, SHELLS3, OWN_HEADS, MAX_DEPTH3, CWD_CHANGERS, TERMINAL_ESCAPE_RE, LOOP_MAX_RECORDS, CANARY_MIN_LENGTH, MAX_TEXT, MAX_DEPTH4, MAX_JSON_PARSE, URL_DEPTH, B64_DEPTH, MIN_SEGMENT, SEPARATORS, stripSeparators, looksText, CANARY_DECODERS, VIEWS, LONG_OUTPUT_THRESHOLD_BYTES, CANONICAL_EXTRACTOR_VERSION;
9021
9071
  var init_dist = __esm({
9022
9072
  "packages/policy-engine/dist/index.mjs"() {
9023
9073
  "use strict";
@@ -11665,6 +11715,61 @@ var init_dist = __esm({
11665
11715
  return s.untrustedContent.afterExposure === "log-only" ? "log" : "review";
11666
11716
  }
11667
11717
  };
11718
+ ({ syntax } = mvdanSh);
11719
+ KINDS = {
11720
+ File: { nodes: ["Stmts"] },
11721
+ Stmt: { nodes: ["Cmd", "Redirs"], scalars: ["Negated", "Background", "Coprocess"] },
11722
+ CallExpr: { nodes: ["Assigns", "Args"] },
11723
+ Assign: { nodes: ["Name", "Value", "Index", "Array"], scalars: ["Append", "Naked"] },
11724
+ Word: { nodes: ["Parts"] },
11725
+ Lit: { scalars: ["Value"] },
11726
+ SglQuoted: { scalars: ["Value", "Dollar"] },
11727
+ DblQuoted: { nodes: ["Parts"], scalars: ["Dollar"] },
11728
+ ParamExp: {
11729
+ nodes: ["Param", "Index", "Slice", "Repl", "Exp"],
11730
+ scalars: ["Short", "Excl", "Length", "Width"]
11731
+ },
11732
+ CmdSubst: { nodes: ["Stmts"], scalars: ["Backquotes", "TempFile", "ReplyVar"] },
11733
+ ArithmExp: { nodes: ["X"], scalars: ["Bracket", "Unsigned"] },
11734
+ ArithmCmd: { nodes: ["X"], scalars: ["Unsigned"] },
11735
+ ProcSubst: { nodes: ["Stmts"], scalars: ["Op"] },
11736
+ ExtGlob: { nodes: ["Pattern"], scalars: ["Op"] },
11737
+ BraceExp: { nodes: ["Elems"], scalars: ["Sequence"] },
11738
+ // only with SplitBraces, unused here
11739
+ BinaryCmd: { nodes: ["X", "Y"], scalars: ["Op"] },
11740
+ BinaryArithm: { nodes: ["X", "Y"], scalars: ["Op"] },
11741
+ UnaryArithm: { nodes: ["X"], scalars: ["Op", "Post"] },
11742
+ ParenArithm: { nodes: ["X"] },
11743
+ BinaryTest: { nodes: ["X", "Y"], scalars: ["Op"] },
11744
+ UnaryTest: { nodes: ["X"], scalars: ["Op"] },
11745
+ ParenTest: { nodes: ["X"] },
11746
+ Redirect: { nodes: ["N", "Word", "Hdoc"], scalars: ["Op"] },
11747
+ Block: { nodes: ["Stmts"] },
11748
+ Subshell: { nodes: ["Stmts"] },
11749
+ IfClause: { nodes: ["Cond", "Then", "Else"] },
11750
+ WhileClause: { nodes: ["Cond", "Do"], scalars: ["Until"] },
11751
+ ForClause: { nodes: ["Loop", "Do"], scalars: ["Select"] },
11752
+ WordIter: { nodes: ["Name", "Items"] },
11753
+ CStyleLoop: { nodes: ["Init", "Cond", "Post"] },
11754
+ CaseClause: { nodes: ["Word", "Items"] },
11755
+ CaseItem: { nodes: ["Patterns", "Stmts"], scalars: ["Op"] },
11756
+ FuncDecl: { nodes: ["Name", "Body"], scalars: ["RsrvWord"] },
11757
+ DeclClause: { nodes: ["Variant", "Args"], notWalked: ["Variant"] },
11758
+ LetClause: { nodes: ["Exprs"] },
11759
+ TimeClause: { nodes: ["Stmt"], scalars: ["PosixFormat"] },
11760
+ CoprocClause: { nodes: ["Name", "Stmt"] },
11761
+ TestClause: { nodes: ["X"] },
11762
+ TestDecl: { nodes: ["Description", "Body"] },
11763
+ ArrayExpr: { nodes: ["Elems"] },
11764
+ ArrayElem: { nodes: ["Index", "Value"] },
11765
+ Comment: { scalars: ["Text"] }
11766
+ };
11767
+ STRUCTS = {
11768
+ "ParamExp.Slice": { nodes: ["Offset", "Length"], notWalked: ["Offset", "Length"] },
11769
+ "ParamExp.Repl": { nodes: ["Orig", "With"], scalars: ["All"] },
11770
+ "ParamExp.Exp": { nodes: ["Word"], scalars: ["Op"] }
11771
+ };
11772
+ unknownKinds = /* @__PURE__ */ new Set();
11668
11773
  INVISIBLE_RE = /[­͏؜᠎​-‏‪-‮⁠-⁤-︀-️]|[\u{E0000}-\u{E007F}]/gu;
11669
11774
  INVISIBLE_ONE = new RegExp(`^(?:${INVISIBLE_RE.source.split("|")[0]})$`, "u");
11670
11775
  HOMOGLYPHS = {
@@ -11950,8 +12055,8 @@ var init_dist = __esm({
11950
12055
  php: PHP
11951
12056
  };
11952
12057
  STRING_LITERAL = /(['"`])((?:\\.|(?!\1)[^\\\n]){1,4096})\1/g;
11953
- ({ syntax } = mvdanSh);
11954
- sharedParser = syntax.NewParser();
12058
+ ({ syntax: syntax2 } = mvdanSh2);
12059
+ sharedParser = syntax2.NewParser();
11955
12060
  MESSAGE_FLAGS = /* @__PURE__ */ new Set([
11956
12061
  "-m",
11957
12062
  "--message",
@@ -11985,7 +12090,7 @@ var init_dist = __esm({
11985
12090
  NORMALIZE_CACHE_MAX = 5e3;
11986
12091
  normalizeCache = /* @__PURE__ */ new Map();
11987
12092
  codeBodiesCache = /* @__PURE__ */ new Map();
11988
- AST_CACHE_MAX = 5e3;
12093
+ AST_CACHE_MAX = 256;
11989
12094
  astCache = /* @__PURE__ */ new Map();
11990
12095
  PARSE_FAIL = /* @__PURE__ */ Symbol("parse-fail");
11991
12096
  INTERPRETER_LINE = /^#![ \t]*[\w./+-]+(?:[ \t]+[\w./+=:-]+)*[ \t]*\r?(?=\n|$)/;
@@ -12970,7 +13075,7 @@ var init_dist = __esm({
12970
13075
  ARGV_FIELDS = ["args", "argv"];
12971
13076
  BARE_WORD = /^[A-Za-z0-9_./+:@%,-]+$/;
12972
13077
  MAX_ARGV_CHARACTERS = 262144;
12973
- ({ syntax: syntax2 } = mvdanSh2);
13078
+ ({ syntax: syntax3 } = mvdanSh3);
12974
13079
  MAX_ALTERNATIVES = 64;
12975
13080
  MAX_CALL_DEPTH2 = 4;
12976
13081
  MAX_CALL_WALKS2 = 256;
@@ -13062,7 +13167,6 @@ var init_dist = __esm({
13062
13167
  );
13063
13168
  exempt = (p) => SYSTEM_DIRS_EXEMPT.some((d) => within(p, d));
13064
13169
  RANK = { allow: 0, review: 1, block: 2 };
13065
- ({ syntax: syntax3 } = mvdanSh3);
13066
13170
  SEQUENCE_OPS = (() => {
13067
13171
  const ops = /* @__PURE__ */ new Set();
13068
13172
  for (const text of ["x && y", "x || y"]) {
@@ -16224,7 +16328,6 @@ zoo`.split("\n");
16224
16328
  );
16225
16329
  NEVER_NEGATED = /* @__PURE__ */ new Set([SIGNALS[1].any[0]]);
16226
16330
  NEGATION_BEFORE = /\b(never|do not|don'?t|must not|mustn'?t|should not|shouldn'?t|not allowed to|forbidden to|avoid|without|no|not)\b[^.!?;:\n]{0,24}$/i;
16227
- ({ syntax: syntax4 } = mvdanSh4);
16228
16331
  RDR_IN = (() => {
16229
16332
  try {
16230
16333
  return parseShared("x <y").Stmts[0].Redirs[0].Op;
@@ -16253,7 +16356,6 @@ zoo`.split("\n");
16253
16356
  "tar"
16254
16357
  ]);
16255
16358
  LITERAL_VERBS = /* @__PURE__ */ new Set(["echo", "printf", ":", "true", "touch", "sed"]);
16256
- ({ syntax: syntax5 } = mvdanSh5);
16257
16359
  GIT_PRESCREEN_RE = /git|husky/i;
16258
16360
  MAX_PAYLOAD_DEPTH2 = 8;
16259
16361
  MAX_ALIAS_DEPTH = 5;
@@ -16322,7 +16424,7 @@ zoo`.split("\n");
16322
16424
  visit(node, depth) {
16323
16425
  if (!node) return false;
16324
16426
  const n = node;
16325
- const type = syntax5.NodeType(n);
16427
+ const type = n.kind;
16326
16428
  if (type === "Stmt") {
16327
16429
  this.visitHeredocShell(n, depth);
16328
16430
  return true;
@@ -16330,7 +16432,7 @@ zoo`.split("\n");
16330
16432
  if (type === "ForClause") {
16331
16433
  const loop = n.Loop;
16332
16434
  const name = loop?.Name?.Value;
16333
- if (name && syntax5.NodeType(loop) === "WordIter") {
16435
+ if (name && loop.kind === "WordIter") {
16334
16436
  const items = (loop.Items || []).map((w) => resolveWordLiteral(w));
16335
16437
  const literal = items.length > 0 && items.every((v) => v !== null);
16336
16438
  this.loopVars.set(name, literal ? items.slice(0, MAX_LOOP_ITEMS) : null);
@@ -16397,7 +16499,7 @@ zoo`.split("\n");
16397
16499
  // eslint-disable-next-line @typescript-eslint/no-explicit-any
16398
16500
  visitHeredocShell(stmt, depth) {
16399
16501
  const cmd = stmt.Cmd;
16400
- if (!cmd || syntax5.NodeType(cmd) !== "CallExpr" || depth >= MAX_PAYLOAD_DEPTH2) return;
16502
+ if (!cmd || cmd.kind !== "CallExpr" || depth >= MAX_PAYLOAD_DEPTH2) return;
16401
16503
  const redirs = stmt.Redirs || [];
16402
16504
  const hdoc = redirs.find((r) => r?.Hdoc && (r.N == null || r.N.Value === "0"));
16403
16505
  if (!hdoc) return;
@@ -16651,7 +16753,6 @@ zoo`.split("\n");
16651
16753
  ]);
16652
16754
  SETTINGS_RE = /\/(?:\.claude\/settings(?:\.local)?\.json|\.gemini\/settings\.json|\.codex\/hooks\.json|\.cursor\/hooks\.json)$/i;
16653
16755
  HOOK_WORDS_RE = /"hooks"|\b(PreToolUse|PostToolUse|UserPromptSubmit|Notification|Stop|SubagentStop|SessionStart|SessionEnd|PreCompact|BeforeTool|AfterTool)\b|"command"\s*:/;
16654
- ({ syntax: syntax6 } = mvdanSh6);
16655
16756
  SHELLS = /* @__PURE__ */ new Set([...SHELL_INTERPRETERS, "mksh", "ash", "csh", "tcsh"]);
16656
16757
  NETCATS = /* @__PURE__ */ new Set(["nc", "ncat", "netcat", "nc.traditional", "nc.openbsd"]);
16657
16758
  NET_CLIENTS = /* @__PURE__ */ new Set([...NETCATS, "telnet", "socat"]);
@@ -16709,7 +16810,7 @@ zoo`.split("\n");
16709
16810
  const f = parseShared(command);
16710
16811
  if (!f || typeof f !== "object" || !f.Stmts) return false;
16711
16812
  try {
16712
- syntax6.Walk(f, (node) => this.visit(node, depth));
16813
+ walk(f, (node) => this.visit(node, depth));
16713
16814
  } catch {
16714
16815
  return false;
16715
16816
  }
@@ -16748,7 +16849,7 @@ zoo`.split("\n");
16748
16849
  }
16749
16850
  visit(n, depth) {
16750
16851
  if (!n) return false;
16751
- const type = syntax6.NodeType(n);
16852
+ const type = n.kind;
16752
16853
  if (type === "Stmt") {
16753
16854
  this.visitStmt(n, depth);
16754
16855
  return true;
@@ -16768,7 +16869,7 @@ zoo`.split("\n");
16768
16869
  const redirs = redirectWords(stmt);
16769
16870
  const toSocket = redirs.some((w) => w !== null && DEV_NET_RE.test(w));
16770
16871
  if (!cmd) return;
16771
- const type = syntax6.NodeType(cmd);
16872
+ const type = cmd.kind;
16772
16873
  if (type !== "CallExpr" || wordsOf(cmd).length > 0) {
16773
16874
  if (this.readsNetFd(stmt) && runsCommandsIn(stmt)) {
16774
16875
  this.reverseShell("commands are read from a network socket opened with exec");
@@ -16854,7 +16955,7 @@ zoo`.split("\n");
16854
16955
  const stages = [];
16855
16956
  const flatten = (s) => {
16856
16957
  const c = s?.Cmd;
16857
- if (c && syntax6.NodeType(c) === "BinaryCmd" && isPipeOp(c.Op)) {
16958
+ if (c && c.kind === "BinaryCmd" && isPipeOp(c.Op)) {
16858
16959
  flatten(c.X);
16859
16960
  flatten(c.Y);
16860
16961
  } else stages.push(s);
@@ -16876,8 +16977,8 @@ zoo`.split("\n");
16876
16977
  sinks.set(i, socketHosts(st));
16877
16978
  }
16878
16979
  if (!c) return;
16879
- if (syntax6.NodeType(c) === "DeclClause" && declDumpsEnv(c) && dump < 0) dump = i;
16880
- if (syntax6.NodeType(c) !== "CallExpr") {
16980
+ if (c.kind === "DeclClause" && declDumpsEnv(c) && dump < 0) dump = i;
16981
+ if (c.kind !== "CallExpr") {
16881
16982
  if (runsCommandsIn(st)) shell = i;
16882
16983
  return;
16883
16984
  }
@@ -16918,10 +17019,10 @@ zoo`.split("\n");
16918
17019
  /** A word (or assignment value) whose text includes an env dump's output. */
16919
17020
  carriesEnv(word) {
16920
17021
  let hit = false;
16921
- syntax6.Walk(word, (node) => {
17022
+ walk(word, (node) => {
16922
17023
  if (hit || !node) return false;
16923
17024
  const n = node;
16924
- const t = syntax6.NodeType(n);
17025
+ const t = n.kind;
16925
17026
  if (t === "ParamExp" && n.Param?.Value && this.envVars.has(n.Param.Value)) {
16926
17027
  hit = true;
16927
17028
  return false;
@@ -16938,11 +17039,11 @@ zoo`.split("\n");
16938
17039
  stmtsDumpEnv(stmts) {
16939
17040
  let hit = false;
16940
17041
  for (const s of stmts) {
16941
- syntax6.Walk(s, (node) => {
17042
+ walk(s, (node) => {
16942
17043
  if (hit || !node) return false;
16943
17044
  const n = node;
16944
- const t = syntax6.NodeType(n);
16945
- if (t === "Stmt" && n.Cmd && syntax6.NodeType(n.Cmd) === "CallExpr") {
17045
+ const t = n.kind;
17046
+ if (t === "Stmt" && n.Cmd && n.Cmd.kind === "CallExpr") {
16946
17047
  const words = wordsOf(n.Cmd);
16947
17048
  if (words.length > 0 && dumpsEnv(words, n)) hit = true;
16948
17049
  }
@@ -16959,7 +17060,6 @@ zoo`.split("\n");
16959
17060
  this.run(payload, depth + 1);
16960
17061
  }
16961
17062
  };
16962
- ({ syntax: syntax7 } = mvdanSh7);
16963
17063
  NPM_INSTALL_VERBS = /* @__PURE__ */ new Set([
16964
17064
  "install",
16965
17065
  "i",
@@ -17341,7 +17441,6 @@ zoo`.split("\n");
17341
17441
  SHELLS2 = /* @__PURE__ */ new Set(["sh", "bash", "zsh", "dash", "ksh", "ash"]);
17342
17442
  MAX_NESTING = 3;
17343
17443
  SHELL_VALUE_FLAGS = /* @__PURE__ */ new Set(["--rcfile", "--init-file", "-O", "+O", "-o", "+o"]);
17344
- ({ syntax: syntax8 } = mvdanSh8);
17345
17444
  NPM_FAMILY = /* @__PURE__ */ new Set(["npm", "pnpm", "yarn", "bun", "npx", "pnpx", "bunx"]);
17346
17445
  PIP_FAMILY = /* @__PURE__ */ new Set(["pip", "pip3", "uv", "uvx", "pipx", "pipenv"]);
17347
17446
  NPM_FETCH_VERBS = /* @__PURE__ */ new Set([
@@ -17873,7 +17972,6 @@ zoo`.split("\n");
17873
17972
  ACCOUNT_KEY_RE = /("(?:iban|account|account_number|accountNumber)"\s*:\s*")([A-Za-z0-9 .-]{6,40})(")/g;
17874
17973
  ACCOUNT_VALUE_RE = /"([A-Z]{2}\d{2}[A-Z0-9]{11,30})"/g;
17875
17974
  MAX_MASK_DEPTH = 64;
17876
- ({ syntax: syntax9 } = mvdanSh9);
17877
17975
  EMPTY = {
17878
17976
  fetches: false,
17879
17977
  sends: false,
@@ -18520,18 +18618,18 @@ function statAndFirstLine(file2) {
18520
18618
  }
18521
18619
  function listCodexSessionFiles(base2 = codexSessionsDir()) {
18522
18620
  const files = [];
18523
- const walk2 = (dir2) => {
18621
+ const walk3 = (dir2) => {
18524
18622
  try {
18525
18623
  for (const entry of fs3.readdirSync(dir2, { withFileTypes: true })) {
18526
18624
  const file2 = path3.join(dir2, entry.name);
18527
- if (entry.isDirectory()) walk2(file2);
18625
+ if (entry.isDirectory()) walk3(file2);
18528
18626
  else if (entry.isFile() && entry.name.endsWith(".jsonl")) files.push(file2);
18529
18627
  }
18530
18628
  } catch {
18531
18629
  }
18532
18630
  };
18533
- walk2(base2);
18534
- if (path3.basename(base2) === "sessions") walk2(path3.join(path3.dirname(base2), "archived_sessions"));
18631
+ walk3(base2);
18632
+ if (path3.basename(base2) === "sessions") walk3(path3.join(path3.dirname(base2), "archived_sessions"));
18535
18633
  const sessions = /* @__PURE__ */ new Map();
18536
18634
  for (const file2 of files.sort()) {
18537
18635
  try {
@@ -18747,79 +18845,6 @@ var init_credential_files = __esm({
18747
18845
  }
18748
18846
  });
18749
18847
 
18750
- // src/cli/commands/blast.ts
18751
- import chalk from "chalk";
18752
- import fs5 from "fs";
18753
- import path6 from "path";
18754
- import os4 from "os";
18755
- function buildSensitivePaths(home, cwd) {
18756
- const homeFiles = homeCredentialFiles(home).map(({ full, label: label2, description, score }) => ({
18757
- full,
18758
- label: label2,
18759
- description,
18760
- score
18761
- }));
18762
- return [
18763
- ...homeFiles,
18764
- {
18765
- full: path6.join(cwd, ".env"),
18766
- label: ".env (current folder)",
18767
- description: "App secrets: database passwords, API keys",
18768
- score: 20
18769
- },
18770
- {
18771
- full: path6.join(cwd, ".env.local"),
18772
- label: ".env.local (current folder)",
18773
- description: "Local overrides: often contains real credentials",
18774
- score: 15
18775
- },
18776
- {
18777
- full: path6.join(cwd, ".env.production"),
18778
- label: ".env.production (current folder)",
18779
- description: "Production secrets",
18780
- score: 20
18781
- }
18782
- ];
18783
- }
18784
- function isReadable(filePath) {
18785
- try {
18786
- fs5.accessSync(filePath, fs5.constants.R_OK);
18787
- return true;
18788
- } catch {
18789
- return false;
18790
- }
18791
- }
18792
- function runBlast() {
18793
- const home = os4.homedir();
18794
- const cwd = process.cwd();
18795
- const paths = buildSensitivePaths(home, cwd);
18796
- let scoreDeduction = 0;
18797
- const reachable = [];
18798
- for (const p of paths) {
18799
- if (fs5.existsSync(p.full) && isReadable(p.full)) {
18800
- reachable.push(p);
18801
- scoreDeduction += p.score;
18802
- }
18803
- }
18804
- const envFindings = [];
18805
- for (const [key, value] of Object.entries(process.env)) {
18806
- if (!value) continue;
18807
- const match = scanArgs({ [key]: value });
18808
- if (match) {
18809
- envFindings.push({ key, patternName: match.patternName });
18810
- scoreDeduction += 10;
18811
- }
18812
- }
18813
- return { reachable, envFindings, score: Math.max(0, 100 - scoreDeduction) };
18814
- }
18815
- var init_blast = __esm({
18816
- "src/cli/commands/blast.ts"() {
18817
- "use strict";
18818
- init_dlp();
18819
- init_credential_files();
18820
- }
18821
- });
18822
-
18823
18848
  // src/mcp-cmd.ts
18824
18849
  var init_mcp_cmd = __esm({
18825
18850
  "src/mcp-cmd.ts"() {
@@ -18872,14 +18897,14 @@ var init_codex_trust = __esm({
18872
18897
  });
18873
18898
 
18874
18899
  // src/daemon/hook-baseline.ts
18875
- import path7 from "path";
18876
- import os5 from "os";
18900
+ import path6 from "path";
18901
+ import os4 from "os";
18877
18902
  var BASELINE_FILE, NOTIFIED_FILE;
18878
18903
  var init_hook_baseline = __esm({
18879
18904
  "src/daemon/hook-baseline.ts"() {
18880
18905
  "use strict";
18881
- BASELINE_FILE = path7.join(os5.homedir(), ".node9", "hooks-baseline.json");
18882
- NOTIFIED_FILE = path7.join(os5.homedir(), ".node9", "hook-heal-notified.json");
18906
+ BASELINE_FILE = path6.join(os4.homedir(), ".node9", "hooks-baseline.json");
18907
+ NOTIFIED_FILE = path6.join(os4.homedir(), ".node9", "hook-heal-notified.json");
18883
18908
  }
18884
18909
  });
18885
18910
 
@@ -18898,27 +18923,27 @@ var init_setup_pi_shim = __esm({
18898
18923
  });
18899
18924
 
18900
18925
  // src/utils/atomic-write.ts
18901
- import fs6 from "fs";
18902
- import path8 from "path";
18926
+ import fs5 from "fs";
18927
+ import path7 from "path";
18903
18928
  import { randomUUID } from "crypto";
18904
18929
  function atomicWriteSync(filePath, data, options) {
18905
- const dir2 = path8.dirname(filePath);
18906
- if (!fs6.existsSync(dir2)) fs6.mkdirSync(dir2, { recursive: true });
18930
+ const dir2 = path7.dirname(filePath);
18931
+ if (!fs5.existsSync(dir2)) fs5.mkdirSync(dir2, { recursive: true });
18907
18932
  const tmpPath = `${filePath}.${randomUUID()}.tmp`;
18908
18933
  try {
18909
- fs6.writeFileSync(tmpPath, data, options);
18934
+ fs5.writeFileSync(tmpPath, data, options);
18910
18935
  } catch (err) {
18911
18936
  try {
18912
- fs6.unlinkSync(tmpPath);
18937
+ fs5.unlinkSync(tmpPath);
18913
18938
  } catch {
18914
18939
  }
18915
18940
  throw err;
18916
18941
  }
18917
18942
  try {
18918
- fs6.renameSync(tmpPath, filePath);
18943
+ fs5.renameSync(tmpPath, filePath);
18919
18944
  } catch (err) {
18920
18945
  try {
18921
- fs6.unlinkSync(tmpPath);
18946
+ fs5.unlinkSync(tmpPath);
18922
18947
  } catch {
18923
18948
  }
18924
18949
  throw err;
@@ -18931,10 +18956,10 @@ var init_atomic_write = __esm({
18931
18956
  });
18932
18957
 
18933
18958
  // src/setup.ts
18934
- import fs7 from "fs";
18935
- import path9 from "path";
18936
- import os6 from "os";
18937
- import chalk2 from "chalk";
18959
+ import fs6 from "fs";
18960
+ import path8 from "path";
18961
+ import os5 from "os";
18962
+ import chalk from "chalk";
18938
18963
  import { confirm as rawConfirm } from "@inquirer/prompts";
18939
18964
  import { parse as parseToml4, stringify as stringifyToml2 } from "smol-toml";
18940
18965
  import * as yaml from "yaml";
@@ -18946,9 +18971,9 @@ function isNode9Hook(cmd) {
18946
18971
  // fell into after #185.
18947
18972
  /[/\\]\.node9[/\\]bin[/\\]hook"? (?:check|log)/.test(cmd);
18948
18973
  }
18949
- function claudeDesktopConfigPath(homeDir = os6.homedir()) {
18974
+ function claudeDesktopConfigPath(homeDir = os5.homedir()) {
18950
18975
  if (process.platform === "darwin") {
18951
- return path9.join(
18976
+ return path8.join(
18952
18977
  homeDir,
18953
18978
  "Library",
18954
18979
  "Application Support",
@@ -18957,47 +18982,47 @@ function claudeDesktopConfigPath(homeDir = os6.homedir()) {
18957
18982
  );
18958
18983
  }
18959
18984
  if (process.platform === "linux") {
18960
- return path9.join(homeDir, ".config", "Claude", "claude_desktop_config.json");
18985
+ return path8.join(homeDir, ".config", "Claude", "claude_desktop_config.json");
18961
18986
  }
18962
18987
  if (process.platform === "win32") {
18963
- const appData = process.env.APPDATA || path9.join(homeDir, "AppData", "Roaming");
18964
- return path9.join(appData, "Claude", "claude_desktop_config.json");
18988
+ const appData = process.env.APPDATA || path8.join(homeDir, "AppData", "Roaming");
18989
+ return path8.join(appData, "Claude", "claude_desktop_config.json");
18965
18990
  }
18966
18991
  return null;
18967
18992
  }
18968
- function opencodeConfigDir(home = os6.homedir()) {
18993
+ function opencodeConfigDir(home = os5.homedir()) {
18969
18994
  const xdg = process.env.XDG_CONFIG_HOME;
18970
- const base2 = xdg && path9.isAbsolute(xdg) ? xdg : path9.join(home, ".config");
18971
- return path9.join(base2, "opencode");
18995
+ const base2 = xdg && path8.isAbsolute(xdg) ? xdg : path8.join(home, ".config");
18996
+ return path8.join(base2, "opencode");
18972
18997
  }
18973
18998
  function commonBinDirs(home) {
18974
18999
  return [
18975
- path9.join(home, ".local", "bin"),
18976
- path9.join(home, ".bun", "bin"),
18977
- path9.join(home, ".npm-global", "bin"),
19000
+ path8.join(home, ".local", "bin"),
19001
+ path8.join(home, ".bun", "bin"),
19002
+ path8.join(home, ".npm-global", "bin"),
18978
19003
  "/usr/local/bin",
18979
19004
  "/opt/homebrew/bin"
18980
19005
  ];
18981
19006
  }
18982
- function binaryInPath(binary, home = os6.homedir()) {
19007
+ function binaryInPath(binary, home = os5.homedir()) {
18983
19008
  const pathEnv = process.env.PATH ?? "";
18984
- const dirs = [...pathEnv.split(path9.delimiter), ...commonBinDirs(home)];
19009
+ const dirs = [...pathEnv.split(path8.delimiter), ...commonBinDirs(home)];
18985
19010
  const seen = /* @__PURE__ */ new Set();
18986
19011
  for (const dir2 of dirs) {
18987
19012
  if (!dir2 || seen.has(dir2)) continue;
18988
19013
  seen.add(dir2);
18989
19014
  try {
18990
- fs7.accessSync(path9.join(dir2, binary), fs7.constants.X_OK);
19015
+ fs6.accessSync(path8.join(dir2, binary), fs6.constants.X_OK);
18991
19016
  return true;
18992
19017
  } catch {
18993
19018
  }
18994
19019
  }
18995
19020
  return false;
18996
19021
  }
18997
- function detectAgents(homeDir = os6.homedir()) {
19022
+ function detectAgents(homeDir = os5.homedir()) {
18998
19023
  const exists2 = (p) => {
18999
19024
  try {
19000
- return fs7.existsSync(p);
19025
+ return fs6.existsSync(p);
19001
19026
  } catch (err) {
19002
19027
  const code = err.code;
19003
19028
  if (code !== "ENOENT") {
@@ -19009,7 +19034,7 @@ function detectAgents(homeDir = os6.homedir()) {
19009
19034
  };
19010
19035
  const desktopPath = claudeDesktopConfigPath(homeDir);
19011
19036
  return {
19012
- claude: exists2(path9.join(homeDir, ".claude")) || exists2(path9.join(homeDir, ".claude.json")),
19037
+ claude: exists2(path8.join(homeDir, ".claude")) || exists2(path8.join(homeDir, ".claude.json")),
19013
19038
  // Antigravity (agy) shares the ~/.gemini root, so a bare
19014
19039
  // `exists(~/.gemini)` would report the (EOL'd) Gemini CLI as
19015
19040
  // installed on every agy machine — and `node9 init` would then
@@ -19019,19 +19044,19 @@ function detectAgents(homeDir = os6.homedir()) {
19019
19044
  // creates ~/.gemini/settings.json on first run; agy does not touch
19020
19045
  // it (it uses antigravity-cli/settings.json) — that file is the
19021
19046
  // legacy-CLI discriminator.
19022
- gemini: exists2(path9.join(homeDir, ".gemini", "settings.json")) || binaryInPath("gemini", homeDir),
19047
+ gemini: exists2(path8.join(homeDir, ".gemini", "settings.json")) || binaryInPath("gemini", homeDir),
19023
19048
  // agy creates ~/.gemini/antigravity-cli/ on first launch; the IDE
19024
19049
  // creates antigravity-ide/. PATH fallback covers installed-but-
19025
19050
  // never-launched (same class as opencode #186).
19026
- antigravity: exists2(path9.join(homeDir, ".gemini", "antigravity-cli")) || exists2(path9.join(homeDir, ".gemini", "antigravity-ide")) || binaryInPath("agy", homeDir),
19051
+ antigravity: exists2(path8.join(homeDir, ".gemini", "antigravity-cli")) || exists2(path8.join(homeDir, ".gemini", "antigravity-ide")) || binaryInPath("agy", homeDir),
19027
19052
  // GitHub Copilot CLI creates ~/.copilot on first launch; PATH
19028
19053
  // fallback covers installed-but-never-launched (same as opencode #186).
19029
- copilot: exists2(path9.join(homeDir, ".copilot")) || binaryInPath("copilot", homeDir),
19030
- cursor: exists2(path9.join(homeDir, ".cursor")),
19031
- codex: exists2(path9.join(homeDir, ".codex")),
19032
- windsurf: exists2(path9.join(homeDir, ".codeium", "windsurf")),
19033
- vscode: exists2(path9.join(homeDir, ".vscode")),
19034
- claudeDesktop: desktopPath !== null && exists2(path9.dirname(desktopPath)),
19054
+ copilot: exists2(path8.join(homeDir, ".copilot")) || binaryInPath("copilot", homeDir),
19055
+ cursor: exists2(path8.join(homeDir, ".cursor")),
19056
+ codex: exists2(path8.join(homeDir, ".codex")),
19057
+ windsurf: exists2(path8.join(homeDir, ".codeium", "windsurf")),
19058
+ vscode: exists2(path8.join(homeDir, ".vscode")),
19059
+ claudeDesktop: desktopPath !== null && exists2(path8.dirname(desktopPath)),
19035
19060
  // Opencode creates its config dir lazily on first launch — fall back to a
19036
19061
  // PATH lookup so installed-but-never-launched CLIs are still wired. Config
19037
19062
  // dir honors $XDG_CONFIG_HOME via opencodeConfigDir (#186, custom-XDG).
@@ -19042,7 +19067,7 @@ function detectAgents(homeDir = os6.homedir()) {
19042
19067
  // dir lazily on first launch — same class of bug as opencode's #186
19043
19068
  // (design R6) — so fall back to PATH lookup for installed-but-never-
19044
19069
  // launched pi.
19045
- pi: exists2(path9.join(homeDir, ".pi", "agent")) || binaryInPath("pi", homeDir),
19070
+ pi: exists2(path8.join(homeDir, ".pi", "agent")) || binaryInPath("pi", homeDir),
19046
19071
  // Hermes Agent (https://github.com/NousResearch/hermes-agent): home dir
19047
19072
  // is $HERMES_HOME (default ~/.hermes) per hermes_constants.py:30. config.yaml
19048
19073
  // appears after `hermes setup` has run; the directory alone exists from
@@ -19051,13 +19076,13 @@ function detectAgents(homeDir = os6.homedir()) {
19051
19076
  hermes: exists2(hermesHomeDir(homeDir)) || binaryInPath("hermes", homeDir)
19052
19077
  };
19053
19078
  }
19054
- function hermesHomeDir(homeDir = os6.homedir()) {
19079
+ function hermesHomeDir(homeDir = os5.homedir()) {
19055
19080
  const env = process.env.HERMES_HOME?.trim();
19056
- if (env && path9.isAbsolute(env)) return env;
19057
- return path9.join(homeDir, ".hermes");
19081
+ if (env && path8.isAbsolute(env)) return env;
19082
+ return path8.join(homeDir, ".hermes");
19058
19083
  }
19059
- function hermesConfigPath(homeDir = os6.homedir()) {
19060
- return path9.join(hermesHomeDir(homeDir), HERMES_CONFIG_FILENAME);
19084
+ function hermesConfigPath(homeDir = os5.homedir()) {
19085
+ return path8.join(hermesHomeDir(homeDir), HERMES_CONFIG_FILENAME);
19061
19086
  }
19062
19087
  var HERMES_CONFIG_FILENAME;
19063
19088
  var init_setup = __esm({
@@ -19076,15 +19101,15 @@ var init_setup = __esm({
19076
19101
  });
19077
19102
 
19078
19103
  // src/agent-wiring.ts
19079
- import fs8 from "fs";
19080
- import path10 from "path";
19081
- import os7 from "os";
19104
+ import fs7 from "fs";
19105
+ import path9 from "path";
19106
+ import os6 from "os";
19082
19107
  import * as yaml2 from "yaml";
19083
19108
  import { parse as parseToml5 } from "smol-toml";
19084
19109
  function readJson(filePath) {
19085
- if (!fs8.existsSync(filePath)) return null;
19110
+ if (!fs7.existsSync(filePath)) return null;
19086
19111
  try {
19087
- return JSON.parse(fs8.readFileSync(filePath, "utf-8"));
19112
+ return JSON.parse(fs7.readFileSync(filePath, "utf-8"));
19088
19113
  } catch {
19089
19114
  return "invalid";
19090
19115
  }
@@ -19096,10 +19121,10 @@ function flatHaveNode9Hook(entries) {
19096
19121
  return (Array.isArray(entries) ? entries : []).some((h) => isNode9Hook(h.command));
19097
19122
  }
19098
19123
  function readHookRoot(filePath, format) {
19099
- if (!fs8.existsSync(filePath)) return "absent";
19124
+ if (!fs7.existsSync(filePath)) return "absent";
19100
19125
  let raw;
19101
19126
  try {
19102
- raw = fs8.readFileSync(filePath, "utf-8");
19127
+ raw = fs7.readFileSync(filePath, "utf-8");
19103
19128
  } catch {
19104
19129
  return "absent";
19105
19130
  }
@@ -19122,20 +19147,20 @@ function detectMcp(servers) {
19122
19147
  return { wrapped, present };
19123
19148
  }
19124
19149
  function readMcp(filePath, format) {
19125
- if (!fs8.existsSync(filePath)) return { wrapped: [], present: false };
19150
+ if (!fs7.existsSync(filePath)) return { wrapped: [], present: false };
19126
19151
  try {
19127
19152
  if (format === "toml") {
19128
- const parsed2 = parseToml5(fs8.readFileSync(filePath, "utf-8"));
19153
+ const parsed2 = parseToml5(fs7.readFileSync(filePath, "utf-8"));
19129
19154
  return detectMcp(parsed2?.mcp_servers);
19130
19155
  }
19131
19156
  const parsed = readJson(filePath);
19132
19157
  if (parsed === null || parsed === "invalid") return { wrapped: [], present: false };
19133
- return detectMcp(parsed.mcpServers);
19158
+ return detectMcp(format === "vscode" ? parsed.servers : parsed.mcpServers);
19134
19159
  } catch {
19135
19160
  return { wrapped: [], present: false };
19136
19161
  }
19137
19162
  }
19138
- function getAgentWiring(home = os7.homedir()) {
19163
+ function getAgentWiring(home = os6.homedir()) {
19139
19164
  const detected = detectAgents(home);
19140
19165
  return AGENT_SPECS.map((spec) => {
19141
19166
  const present = spec.present(home);
@@ -19179,7 +19204,8 @@ function getAgentWiring(home = os7.homedir()) {
19179
19204
  configFormat: spec.hookFormat === "yaml" ? "YAML" : "JSON",
19180
19205
  mcpServers: mcp ? mcp.wrapped : null,
19181
19206
  mcpProtected: mcp ? mcp.present : false,
19182
- isProtected: anyHookWired || (mcp?.present ?? false)
19207
+ isProtected: anyHookWired || (mcp?.present ?? false),
19208
+ protection: spec.hookEvents.length > 0 || spec.shimFile ? "hooks" : "mcp"
19183
19209
  };
19184
19210
  });
19185
19211
  }
@@ -19190,7 +19216,7 @@ var init_agent_wiring = __esm({
19190
19216
  init_setup();
19191
19217
  exists = (p) => {
19192
19218
  try {
19193
- return fs8.existsSync(p);
19219
+ return fs7.existsSync(p);
19194
19220
  } catch {
19195
19221
  return false;
19196
19222
  }
@@ -19204,55 +19230,55 @@ var init_agent_wiring = __esm({
19204
19230
  id: "claude",
19205
19231
  label: "Claude Code",
19206
19232
  setupCommand: "node9 agents add claude",
19207
- hookFile: (h) => path10.join(h, ".claude", "settings.json"),
19233
+ hookFile: (h) => path9.join(h, ".claude", "settings.json"),
19208
19234
  hookFormat: "matcher",
19209
19235
  // UserPromptSubmit is prompt DLP. setup.ts has written it for Claude since
19210
19236
  // that shipped; the spec must name it too, or status/doctor never show the
19211
19237
  // row and heal (which repairs via setupAgent) has no signal it is missing.
19212
19238
  hookEvents: [ck("PreToolUse"), lg("PostToolUse"), ck("UserPromptSubmit")],
19213
- mcpFile: (h) => path10.join(h, ".claude.json"),
19214
- present: (h) => exists(path10.join(h, ".claude", "settings.json")) || exists(path10.join(h, ".claude.json"))
19239
+ mcpFile: (h) => path9.join(h, ".claude.json"),
19240
+ present: (h) => exists(path9.join(h, ".claude", "settings.json")) || exists(path9.join(h, ".claude.json"))
19215
19241
  },
19216
19242
  {
19217
19243
  id: "gemini",
19218
19244
  label: "Gemini CLI",
19219
19245
  setupCommand: "node9 agents add gemini",
19220
- hookFile: (h) => path10.join(h, ".gemini", "settings.json"),
19246
+ hookFile: (h) => path9.join(h, ".gemini", "settings.json"),
19221
19247
  hookFormat: "matcher",
19222
19248
  hookEvents: [ck("BeforeTool"), lg("AfterTool")],
19223
- mcpFile: (h) => path10.join(h, ".gemini", "settings.json"),
19224
- present: (h) => exists(path10.join(h, ".gemini", "settings.json"))
19249
+ mcpFile: (h) => path9.join(h, ".gemini", "settings.json"),
19250
+ present: (h) => exists(path9.join(h, ".gemini", "settings.json"))
19225
19251
  },
19226
19252
  {
19227
19253
  id: "codex",
19228
19254
  label: "Codex",
19229
19255
  setupCommand: "node9 agents add codex",
19230
- hookFile: (h) => path10.join(h, ".codex", "hooks.json"),
19256
+ hookFile: (h) => path9.join(h, ".codex", "hooks.json"),
19231
19257
  hookFormat: "matcher",
19232
19258
  hookEvents: [ck("PreToolUse"), ck("UserPromptSubmit")],
19233
- mcpFile: (h) => path10.join(h, ".codex", "config.toml"),
19259
+ mcpFile: (h) => path9.join(h, ".codex", "config.toml"),
19234
19260
  mcpFormat: "toml",
19235
- present: (h) => exists(path10.join(h, ".codex"))
19261
+ present: (h) => exists(path9.join(h, ".codex"))
19236
19262
  },
19237
19263
  {
19238
19264
  id: "antigravity",
19239
19265
  label: "Antigravity",
19240
19266
  setupCommand: "node9 agents add antigravity",
19241
- hookFile: (h) => path10.join(h, ".gemini", "config", "hooks.json"),
19267
+ hookFile: (h) => path9.join(h, ".gemini", "config", "hooks.json"),
19242
19268
  hookFormat: "matcher",
19243
19269
  hookEvents: [ck("PreToolUse"), lg("PostToolUse")],
19244
- mcpFile: (h) => path10.join(h, ".gemini", "config", "mcp_config.json"),
19245
- present: (h) => exists(path10.join(h, ".gemini", "config", "hooks.json")) || exists(path10.join(h, ".gemini", "antigravity-cli")) || exists(path10.join(h, ".gemini", "antigravity-ide"))
19270
+ mcpFile: (h) => path9.join(h, ".gemini", "config", "mcp_config.json"),
19271
+ present: (h) => exists(path9.join(h, ".gemini", "config", "hooks.json")) || exists(path9.join(h, ".gemini", "antigravity-cli")) || exists(path9.join(h, ".gemini", "antigravity-ide"))
19246
19272
  },
19247
19273
  {
19248
19274
  id: "copilot",
19249
19275
  label: "GitHub Copilot",
19250
19276
  setupCommand: "node9 agents add copilot",
19251
- hookFile: (h) => path10.join(h, ".copilot", "hooks", "node9.json"),
19277
+ hookFile: (h) => path9.join(h, ".copilot", "hooks", "node9.json"),
19252
19278
  hookFormat: "flat",
19253
19279
  hookEvents: [ck("PreToolUse"), lg("PostToolUse"), ck("UserPromptSubmit")],
19254
- mcpFile: (h) => path10.join(h, ".copilot", "mcp-config.json"),
19255
- present: (h) => exists(path10.join(h, ".copilot"))
19280
+ mcpFile: (h) => path9.join(h, ".copilot", "mcp-config.json"),
19281
+ present: (h) => exists(path9.join(h, ".copilot"))
19256
19282
  },
19257
19283
  {
19258
19284
  id: "cursor",
@@ -19261,8 +19287,45 @@ var init_agent_wiring = __esm({
19261
19287
  // MCP-only — no hook file (see note above).
19262
19288
  hookFormat: "flat",
19263
19289
  hookEvents: [],
19264
- mcpFile: (h) => path10.join(h, ".cursor", "mcp.json"),
19265
- present: (h) => exists(path10.join(h, ".cursor", "mcp.json"))
19290
+ mcpFile: (h) => path9.join(h, ".cursor", "mcp.json"),
19291
+ present: (h) => exists(path9.join(h, ".cursor", "mcp.json"))
19292
+ },
19293
+ // The three MCP-only agents below came over from `getAgentsStatus` (fw#421
19294
+ // P3), so one registry answers every "is it wired" question.
19295
+ {
19296
+ id: "windsurf",
19297
+ label: "Windsurf",
19298
+ setupCommand: "node9 agents add windsurf",
19299
+ hookFormat: "flat",
19300
+ hookEvents: [],
19301
+ mcpFile: (h) => path9.join(h, ".codeium", "windsurf", "mcp_config.json"),
19302
+ mcpInventory: false,
19303
+ present: (h) => exists(path9.join(h, ".codeium", "windsurf"))
19304
+ },
19305
+ {
19306
+ id: "vscode",
19307
+ label: "VSCode",
19308
+ setupCommand: "node9 agents add vscode",
19309
+ hookFormat: "flat",
19310
+ hookEvents: [],
19311
+ mcpFile: (h) => path9.join(h, ".vscode", "mcp.json"),
19312
+ mcpFormat: "vscode",
19313
+ mcpInventory: false,
19314
+ present: (h) => exists(path9.join(h, ".vscode"))
19315
+ },
19316
+ {
19317
+ id: "claudeDesktop",
19318
+ label: "Claude Desktop",
19319
+ setupCommand: "node9 agents add claudeDesktop",
19320
+ hookFormat: "flat",
19321
+ hookEvents: [],
19322
+ // The per-platform config path; its parent directory is the footprint.
19323
+ mcpFile: (h) => claudeDesktopConfigPath(h) ?? path9.join(h, ".config", "Claude", "claude_desktop_config.json"),
19324
+ mcpInventory: false,
19325
+ present: (h) => {
19326
+ const p = claudeDesktopConfigPath(h);
19327
+ return p !== null && exists(path9.dirname(p));
19328
+ }
19266
19329
  },
19267
19330
  {
19268
19331
  id: "hermes",
@@ -19283,8 +19346,8 @@ var init_agent_wiring = __esm({
19283
19346
  setupCommand: "node9 agents add opencode",
19284
19347
  hookFormat: "flat",
19285
19348
  hookEvents: [],
19286
- shimFile: (h) => path10.join(opencodeConfigDir(h), "plugins", "node9.js"),
19287
- present: (h) => exists(opencodeConfigDir(h)) || exists(path10.join(opencodeConfigDir(h), "plugins", "node9.js"))
19349
+ shimFile: (h) => path9.join(opencodeConfigDir(h), "plugins", "node9.js"),
19350
+ present: (h) => exists(opencodeConfigDir(h)) || exists(path9.join(opencodeConfigDir(h), "plugins", "node9.js"))
19288
19351
  },
19289
19352
  {
19290
19353
  id: "pi",
@@ -19292,8 +19355,8 @@ var init_agent_wiring = __esm({
19292
19355
  setupCommand: "node9 agents add pi",
19293
19356
  hookFormat: "flat",
19294
19357
  hookEvents: [],
19295
- shimFile: (h) => path10.join(h, ".pi", "agent", "extensions", "node9.js"),
19296
- present: (h) => exists(path10.join(h, ".pi", "agent")) || exists(path10.join(h, ".pi", "agent", "extensions", "node9.js"))
19358
+ shimFile: (h) => path9.join(h, ".pi", "agent", "extensions", "node9.js"),
19359
+ present: (h) => exists(path9.join(h, ".pi", "agent")) || exists(path9.join(h, ".pi", "agent", "extensions", "node9.js"))
19297
19360
  }
19298
19361
  ];
19299
19362
  }
@@ -19383,14 +19446,14 @@ var init_build = __esm({
19383
19446
  });
19384
19447
 
19385
19448
  // src/shields.ts
19386
- import fs9 from "fs";
19387
- import path11 from "path";
19388
- import os8 from "os";
19449
+ import fs8 from "fs";
19450
+ import path10 from "path";
19451
+ import os7 from "os";
19389
19452
  function loadUserShields() {
19390
19453
  const result = {};
19391
19454
  let entries;
19392
19455
  try {
19393
- entries = fs9.readdirSync(USER_SHIELDS_DIR).filter((f) => f.endsWith(".json"));
19456
+ entries = fs8.readdirSync(USER_SHIELDS_DIR).filter((f) => f.endsWith(".json"));
19394
19457
  } catch (err) {
19395
19458
  if (err.code !== "ENOENT") {
19396
19459
  process.stderr.write(
@@ -19401,9 +19464,9 @@ function loadUserShields() {
19401
19464
  return result;
19402
19465
  }
19403
19466
  for (const file2 of entries) {
19404
- const filePath = path11.join(USER_SHIELDS_DIR, file2);
19467
+ const filePath = path10.join(USER_SHIELDS_DIR, file2);
19405
19468
  try {
19406
- const raw = JSON.parse(fs9.readFileSync(filePath, "utf-8"));
19469
+ const raw = JSON.parse(fs8.readFileSync(filePath, "utf-8"));
19407
19470
  const v = validateShieldDefinition(raw);
19408
19471
  if ("error" in v) {
19409
19472
  process.stderr.write(`[node9] ${v.error}: ${filePath}
@@ -19435,7 +19498,7 @@ function getShield(name) {
19435
19498
  }
19436
19499
  function readShieldsFile() {
19437
19500
  try {
19438
- const raw = fs9.readFileSync(SHIELDS_STATE_FILE, "utf-8");
19501
+ const raw = fs8.readFileSync(SHIELDS_STATE_FILE, "utf-8");
19439
19502
  if (!raw.trim()) return { active: [] };
19440
19503
  const parsed = JSON.parse(raw);
19441
19504
  const active = Array.isArray(parsed.active) ? parsed.active.filter(
@@ -19468,23 +19531,23 @@ var init_shields = __esm({
19468
19531
  init_dist();
19469
19532
  init_build();
19470
19533
  init_dist();
19471
- USER_SHIELDS_DIR = path11.join(os8.homedir(), ".node9", "shields");
19534
+ USER_SHIELDS_DIR = path10.join(os7.homedir(), ".node9", "shields");
19472
19535
  SHIELDS = buildSHIELDS();
19473
- SHIELDS_STATE_FILE = path11.join(os8.homedir(), ".node9", "shields.json");
19536
+ SHIELDS_STATE_FILE = path10.join(os7.homedir(), ".node9", "shields.json");
19474
19537
  }
19475
19538
  });
19476
19539
 
19477
19540
  // src/shields/jail.ts
19478
- import fs10 from "fs";
19479
- import os9 from "os";
19480
- import path12 from "path";
19541
+ import fs9 from "fs";
19542
+ import os8 from "os";
19543
+ import path11 from "path";
19481
19544
  function jailStorePath() {
19482
- return path12.join(os9.homedir(), ".node9", "jail-paths.json");
19545
+ return path11.join(os8.homedir(), ".node9", "jail-paths.json");
19483
19546
  }
19484
19547
  function readJailPaths() {
19485
19548
  let text;
19486
19549
  try {
19487
- text = fs10.readFileSync(jailStorePath(), "utf8");
19550
+ text = fs9.readFileSync(jailStorePath(), "utf8");
19488
19551
  } catch (err) {
19489
19552
  if (err.code === "ENOENT") return [];
19490
19553
  throw err;
@@ -19522,11 +19585,11 @@ var init_jail = __esm({
19522
19585
  });
19523
19586
 
19524
19587
  // src/canary/registry.ts
19525
- import fs11 from "fs";
19526
- import os10 from "os";
19527
- import path13 from "path";
19588
+ import fs10 from "fs";
19589
+ import os9 from "os";
19590
+ import path12 from "path";
19528
19591
  function canaryStorePath() {
19529
- return path13.join(os10.homedir(), ".node9", "canaries.json");
19592
+ return path12.join(os9.homedir(), ".node9", "canaries.json");
19530
19593
  }
19531
19594
  function isRecord(x) {
19532
19595
  if (!x || typeof x !== "object") return false;
@@ -19537,7 +19600,7 @@ function loadCanaries(opts) {
19537
19600
  const p = canaryStorePath();
19538
19601
  let raw;
19539
19602
  try {
19540
- raw = fs11.readFileSync(p, "utf-8");
19603
+ raw = fs10.readFileSync(p, "utf-8");
19541
19604
  } catch (e) {
19542
19605
  if (e.code === "ENOENT") return [];
19543
19606
  throw e;
@@ -19576,23 +19639,23 @@ var init_registry = __esm({
19576
19639
  });
19577
19640
 
19578
19641
  // src/utils/read-capped.ts
19579
- import fs12 from "fs";
19642
+ import fs11 from "fs";
19580
19643
  function readCapped(file2, maxBytes, openFlags = "r") {
19581
19644
  if (maxBytes < 0) return null;
19582
19645
  let fd;
19583
19646
  try {
19584
- fd = fs12.openSync(file2, openFlags);
19647
+ fd = fs11.openSync(file2, openFlags);
19585
19648
  } catch {
19586
19649
  return null;
19587
19650
  }
19588
19651
  try {
19589
- const st = fs12.fstatSync(fd);
19652
+ const st = fs11.fstatSync(fd);
19590
19653
  if (!st.isFile()) return null;
19591
19654
  const want = Math.min(st.size, maxBytes + 1);
19592
19655
  const buf = Buffer.alloc(want);
19593
19656
  let read2 = 0;
19594
19657
  while (read2 < want) {
19595
- const n = fs12.readSync(fd, buf, read2, want - read2, read2);
19658
+ const n = fs11.readSync(fd, buf, read2, want - read2, read2);
19596
19659
  if (n <= 0) break;
19597
19660
  read2 += n;
19598
19661
  }
@@ -19604,7 +19667,7 @@ function readCapped(file2, maxBytes, openFlags = "r") {
19604
19667
  return null;
19605
19668
  } finally {
19606
19669
  try {
19607
- fs12.closeSync(fd);
19670
+ fs11.closeSync(fd);
19608
19671
  } catch {
19609
19672
  }
19610
19673
  }
@@ -19620,13 +19683,13 @@ var init_read_capped = __esm({
19620
19683
  });
19621
19684
 
19622
19685
  // src/posture/secrets.ts
19623
- import fs13 from "fs";
19624
- import path14 from "path";
19625
- import os11 from "os";
19686
+ import fs12 from "fs";
19687
+ import path13 from "path";
19688
+ import os10 from "os";
19626
19689
  function displayPath(p, home) {
19627
19690
  if (p === home) return "~";
19628
- const prefix = home.endsWith(path14.sep) ? home : home + path14.sep;
19629
- if (p.startsWith(prefix)) return "~" + path14.sep + p.slice(prefix.length);
19691
+ const prefix = home.endsWith(path13.sep) ? home : home + path13.sep;
19692
+ if (p.startsWith(prefix)) return "~" + path13.sep + p.slice(prefix.length);
19630
19693
  return p;
19631
19694
  }
19632
19695
  function safeRead(file2) {
@@ -19637,8 +19700,8 @@ function safeRead(file2) {
19637
19700
  function candidateFiles(home, cwd) {
19638
19701
  const files = /* @__PURE__ */ new Set();
19639
19702
  try {
19640
- for (const name of fs13.readdirSync(cwd)) {
19641
- if (name === ".env" || name.startsWith(".env.")) files.add(path14.join(cwd, name));
19703
+ for (const name of fs12.readdirSync(cwd)) {
19704
+ if (name === ".env" || name.startsWith(".env.")) files.add(path13.join(cwd, name));
19642
19705
  }
19643
19706
  } catch {
19644
19707
  }
@@ -19646,7 +19709,7 @@ function candidateFiles(home, cwd) {
19646
19709
  if (spec.hookFile) files.add(spec.hookFile(home));
19647
19710
  if (spec.mcpFile) files.add(spec.mcpFile(home));
19648
19711
  }
19649
- files.add(path14.join(home, ".env"));
19712
+ files.add(path13.join(home, ".env"));
19650
19713
  return [...files];
19651
19714
  }
19652
19715
  function credentialMaterial(home) {
@@ -19660,7 +19723,7 @@ function plantedDecoyPaths() {
19660
19723
  }
19661
19724
  }
19662
19725
  function checkSecrets(ctx) {
19663
- const home = ctx.home || os11.homedir();
19726
+ const home = ctx.home || os10.homedir();
19664
19727
  const findings = [];
19665
19728
  const planted = plantedDecoyPaths();
19666
19729
  const plaintext = [];
@@ -19696,7 +19759,7 @@ function checkSecrets(ctx) {
19696
19759
  for (const file2 of credentialMaterial(home)) {
19697
19760
  if (planted.has(file2)) continue;
19698
19761
  try {
19699
- if (fs13.statSync(file2).isFile()) {
19762
+ if (fs12.statSync(file2).isFile()) {
19700
19763
  creds.push(displayPath(file2, home));
19701
19764
  credPaths.push(file2);
19702
19765
  }
@@ -19717,6 +19780,25 @@ function checkSecrets(ctx) {
19717
19780
  coverageProbe: { kind: "fileRead", paths: credPaths }
19718
19781
  });
19719
19782
  }
19783
+ const envSecrets = [];
19784
+ for (const [key, value] of Object.entries(ctx.env ?? process.env)) {
19785
+ if (!value) continue;
19786
+ const match = scanArgs({ [key]: value });
19787
+ if (match) envSecrets.push(`${key} (${match.patternName})`);
19788
+ }
19789
+ if (envSecrets.length > 0) {
19790
+ findings.push({
19791
+ category: "Secrets",
19792
+ severity: "high",
19793
+ title: `${envSecrets.length} secret environment variable${envSecrets.length === 1 ? "" : "s"} visible to the agent`,
19794
+ what: "A key or token is exported in the shell the agent runs from.",
19795
+ why: "Every program the agent starts inherits the environment, so the value is one `env` away.",
19796
+ who: "A tricked agent can read it and send it anywhere a command can reach.",
19797
+ detail: envSecrets,
19798
+ fix: "Unset it in the shell that starts the agent, or pass it to the one command that needs it (`env KEY=... cmd`) or a secrets manager.",
19799
+ owner: "os"
19800
+ });
19801
+ }
19720
19802
  if (planted.size > 0) {
19721
19803
  findings.push({
19722
19804
  category: "Secrets",
@@ -19739,6 +19821,7 @@ var init_secrets = __esm({
19739
19821
  init_registry();
19740
19822
  init_read_capped();
19741
19823
  init_credential_files();
19824
+ init_dlp();
19742
19825
  MAX_FILE_BYTES = 256 * 1024;
19743
19826
  }
19744
19827
  });
@@ -20149,15 +20232,15 @@ var init_managed = __esm({
20149
20232
  });
20150
20233
 
20151
20234
  // src/auth/trusted-hosts.ts
20152
- import fs14 from "fs";
20153
- import path15 from "path";
20154
- import os12 from "os";
20235
+ import fs13 from "fs";
20236
+ import path14 from "path";
20237
+ import os11 from "os";
20155
20238
  function getTrustedHostsPath() {
20156
- return path15.join(os12.homedir(), ".node9", "trusted-hosts.json");
20239
+ return path14.join(os11.homedir(), ".node9", "trusted-hosts.json");
20157
20240
  }
20158
20241
  function readTrustedHosts() {
20159
20242
  try {
20160
- const raw = fs14.readFileSync(getTrustedHostsPath(), "utf8");
20243
+ const raw = fs13.readFileSync(getTrustedHostsPath(), "utf8");
20161
20244
  const parsed = JSON.parse(raw);
20162
20245
  return Array.isArray(parsed.hosts) ? parsed.hosts : [];
20163
20246
  } catch {
@@ -20166,7 +20249,7 @@ function readTrustedHosts() {
20166
20249
  }
20167
20250
  function getFileMtime() {
20168
20251
  try {
20169
- return fs14.statSync(getTrustedHostsPath()).mtimeMs;
20252
+ return fs13.statSync(getTrustedHostsPath()).mtimeMs;
20170
20253
  } catch {
20171
20254
  return 0;
20172
20255
  }
@@ -20385,9 +20468,9 @@ var init_api_url = __esm({
20385
20468
  });
20386
20469
 
20387
20470
  // src/config/index.ts
20388
- import fs15 from "fs";
20389
- import path16 from "path";
20390
- import os13 from "os";
20471
+ import fs14 from "fs";
20472
+ import path15 from "path";
20473
+ import os12 from "os";
20391
20474
  function sanitizeSsrfAllow(entries, source) {
20392
20475
  const kept = [];
20393
20476
  for (const entry of entries) {
@@ -20409,8 +20492,8 @@ function noteRejectedApiUrl(raw) {
20409
20492
  if (rejectedApiUrlsSeen.has(key)) return;
20410
20493
  rejectedApiUrlsSeen.add(key);
20411
20494
  try {
20412
- fs15.appendFileSync(
20413
- path16.join(os13.homedir(), ".node9", "hook-debug.log"),
20495
+ fs14.appendFileSync(
20496
+ path15.join(os12.homedir(), ".node9", "hook-debug.log"),
20414
20497
  `[${(/* @__PURE__ */ new Date()).toISOString()}] REFUSED apiUrl, using the default instead: ${String(raw).slice(0, 200).replace(/[\r\n]+/g, " ")}
20415
20498
  `
20416
20499
  );
@@ -20427,9 +20510,9 @@ function getCredentials() {
20427
20510
  };
20428
20511
  }
20429
20512
  try {
20430
- const credPath = path16.join(os13.homedir(), ".node9", "credentials.json");
20431
- if (fs15.existsSync(credPath)) {
20432
- const creds = JSON.parse(fs15.readFileSync(credPath, "utf-8"));
20513
+ const credPath = path15.join(os12.homedir(), ".node9", "credentials.json");
20514
+ if (fs14.existsSync(credPath)) {
20515
+ const creds = JSON.parse(fs14.readFileSync(credPath, "utf-8"));
20433
20516
  const profileName = process.env.NODE9_PROFILE || "default";
20434
20517
  const profile = creds[profileName];
20435
20518
  if (typeof profile?.apiKey === "string" && profile.apiKey.length > 0) {
@@ -20461,7 +20544,7 @@ function readRulesCacheResilient(cacheFile) {
20461
20544
  for (let attempt = 0; attempt < 3; attempt++) {
20462
20545
  let content;
20463
20546
  try {
20464
- content = fs15.readFileSync(cacheFile, "utf-8");
20547
+ content = fs14.readFileSync(cacheFile, "utf-8");
20465
20548
  existed = true;
20466
20549
  } catch (err) {
20467
20550
  if (err.code === "ENOENT") return {};
@@ -20476,10 +20559,10 @@ function readRulesCacheResilient(cacheFile) {
20476
20559
  }
20477
20560
  }
20478
20561
  if (existed || sawReadError) {
20479
- const backup = path16.join(path16.dirname(cacheFile), "rules-cache.last-good.json");
20562
+ const backup = path15.join(path15.dirname(cacheFile), "rules-cache.last-good.json");
20480
20563
  if (backup !== cacheFile) {
20481
20564
  try {
20482
- const raw = JSON.parse(fs15.readFileSync(backup, "utf-8"));
20565
+ const raw = JSON.parse(fs14.readFileSync(backup, "utf-8"));
20483
20566
  logCacheReadIssue(cacheFile, "RULES_CACHE_CORRUPT_USED_BACKUP");
20484
20567
  lastParsedRulesCache = raw;
20485
20568
  return raw;
@@ -20499,8 +20582,8 @@ function logCacheReadIssue(cacheFile, kind) {
20499
20582
  if (now - cacheReadLastLoggedAt < CACHE_LOG_REARM_MS) return;
20500
20583
  cacheReadLastLoggedAt = now;
20501
20584
  try {
20502
- fs15.appendFileSync(
20503
- path16.join(os13.homedir(), ".node9", "hook-debug.log"),
20585
+ fs14.appendFileSync(
20586
+ path15.join(os12.homedir(), ".node9", "hook-debug.log"),
20504
20587
  `[${(/* @__PURE__ */ new Date()).toISOString()}] ${kind} ${cacheFile}
20505
20588
  `
20506
20589
  );
@@ -20517,8 +20600,8 @@ function catalogSettingsFrom(settings, policy) {
20517
20600
  }
20518
20601
  function getConfig(cwd) {
20519
20602
  if (!cwd && cachedConfig) return cachedConfig;
20520
- const globalPath = path16.join(os13.homedir(), ".node9", "config.json");
20521
- const projectPath = path16.join(cwd ?? process.cwd(), "node9.config.json");
20603
+ const globalPath = path15.join(os12.homedir(), ".node9", "config.json");
20604
+ const projectPath = path15.join(cwd ?? process.cwd(), "node9.config.json");
20522
20605
  const globalConfig = tryLoadConfig(globalPath);
20523
20606
  const projectConfig = tryLoadConfig(projectPath, { project: true });
20524
20607
  const mergedSettings = {
@@ -20763,7 +20846,7 @@ function getConfig(cwd) {
20763
20846
  let cloudMandatesEnforcement = false;
20764
20847
  let cloudMandatesAppPerm = false;
20765
20848
  {
20766
- const cacheFile = path16.join(os13.homedir(), ".node9", "rules-cache.json");
20849
+ const cacheFile = path15.join(os12.homedir(), ".node9", "rules-cache.json");
20767
20850
  try {
20768
20851
  const raw = readRulesCacheResilient(cacheFile);
20769
20852
  if (Array.isArray(raw.rules) && raw.rules.length > 0) {
@@ -21195,10 +21278,10 @@ function getConfig(cwd) {
21195
21278
  }
21196
21279
  function tryLoadConfig(filePath, options = {}) {
21197
21280
  v2ChecksByPath.delete(filePath);
21198
- if (!fs15.existsSync(filePath)) return null;
21281
+ if (!fs14.existsSync(filePath)) return null;
21199
21282
  let raw;
21200
21283
  try {
21201
- raw = JSON.parse(fs15.readFileSync(filePath, "utf-8"));
21284
+ raw = JSON.parse(fs14.readFileSync(filePath, "utf-8"));
21202
21285
  } catch (err) {
21203
21286
  const msg = err instanceof Error ? err.message : String(err);
21204
21287
  process.stderr.write(
@@ -21661,10 +21744,10 @@ var init_templates = __esm({
21661
21744
  });
21662
21745
 
21663
21746
  // src/posture/egress.ts
21664
- import fs16 from "fs";
21747
+ import fs15 from "fs";
21665
21748
  function sandboxEgressWallActive() {
21666
21749
  try {
21667
- return fs16.existsSync(ALLOWED_DOMAINS_PATH);
21750
+ return fs15.existsSync(ALLOWED_DOMAINS_PATH);
21668
21751
  } catch {
21669
21752
  return false;
21670
21753
  }
@@ -22011,29 +22094,29 @@ var init_gate_order = __esm({
22011
22094
  });
22012
22095
 
22013
22096
  // src/policy/file-access.ts
22014
- import fs17 from "fs";
22015
- import os14 from "os";
22016
- import path17 from "path";
22097
+ import fs16 from "fs";
22098
+ import os13 from "os";
22099
+ import path16 from "path";
22017
22100
  function absoluteSpelling(p, cwd, home) {
22018
22101
  if (p === "~" || p.startsWith("~/")) p = home + p.slice(1);
22019
- return path17.isAbsolute(p) ? p : `${cwd}/${p}`;
22102
+ return path16.isAbsolute(p) ? p : `${cwd}/${p}`;
22020
22103
  }
22021
22104
  function physical(p, followFinal, links = 0) {
22022
22105
  if (links > 40) throw new Error("Too many symbolic links");
22023
22106
  if (!followFinal) {
22024
- const parent = physical(path17.dirname(p), true, links);
22025
- return { path: `${parent.path}/${path17.basename(p)}`, missing: parent.missing };
22107
+ const parent = physical(path16.dirname(p), true, links);
22108
+ return { path: `${parent.path}/${path16.basename(p)}`, missing: parent.missing };
22026
22109
  }
22027
22110
  try {
22028
- return { path: fs17.realpathSync.native(p), missing: false };
22111
+ return { path: fs16.realpathSync.native(p), missing: false };
22029
22112
  } catch (error) {
22030
22113
  const code = error.code;
22031
22114
  if (!["ENOENT", "ENOTDIR"].includes(code ?? "")) throw error;
22032
22115
  try {
22033
- if (fs17.lstatSync(p).isSymbolicLink()) {
22034
- const target = fs17.readlinkSync(p);
22116
+ if (fs16.lstatSync(p).isSymbolicLink()) {
22117
+ const target = fs16.readlinkSync(p);
22035
22118
  return physical(
22036
- path17.isAbsolute(target) ? target : `${path17.dirname(p)}/${target}`,
22119
+ path16.isAbsolute(target) ? target : `${path16.dirname(p)}/${target}`,
22037
22120
  true,
22038
22121
  links + 1
22039
22122
  );
@@ -22042,13 +22125,13 @@ function physical(p, followFinal, links = 0) {
22042
22125
  if (!["ENOENT", "ENOTDIR"].includes(linkError.code ?? ""))
22043
22126
  throw linkError;
22044
22127
  }
22045
- const parent = path17.dirname(p);
22128
+ const parent = path16.dirname(p);
22046
22129
  if (parent === p) return { path: p, missing: true };
22047
22130
  const resolved = physical(parent, true, links);
22048
- return { path: `${resolved.path}/${path17.basename(p)}`, missing: true };
22131
+ return { path: `${resolved.path}/${path16.basename(p)}`, missing: true };
22049
22132
  }
22050
22133
  }
22051
- function prepareFileAccesses(tool, args, cwd = process.cwd(), inspection = {}, home = os14.homedir()) {
22134
+ function prepareFileAccesses(tool, args, cwd = process.cwd(), inspection = {}, home = os13.homedir()) {
22052
22135
  const context = { cwd, homeDirs: [home, "/root"] };
22053
22136
  const accesses = collectFileAccesses(tool, args, context, inspection);
22054
22137
  const handledPaths = /* @__PURE__ */ new Set();
@@ -22071,14 +22154,14 @@ function prepareFileAccesses(tool, args, cwd = process.cwd(), inspection = {}, h
22071
22154
  const raw = absoluteSpelling(access.path, access.cwd ?? cwd, home);
22072
22155
  if (access.directoryTarget) {
22073
22156
  try {
22074
- if (!fs17.statSync(absoluteSpelling(access.directoryTarget, access.cwd ?? cwd, home)).isDirectory())
22157
+ if (!fs16.statSync(absoluteSpelling(access.directoryTarget, access.cwd ?? cwd, home)).isDirectory())
22075
22158
  continue;
22076
22159
  } catch {
22077
22160
  }
22078
22161
  }
22079
22162
  if (access.operation === "create") {
22080
22163
  try {
22081
- fs17.statSync(raw);
22164
+ fs16.statSync(raw);
22082
22165
  continue;
22083
22166
  } catch {
22084
22167
  }
@@ -22133,15 +22216,15 @@ var init_file_access = __esm({
22133
22216
  });
22134
22217
 
22135
22218
  // src/supply-chain/osv-index.ts
22136
- import fs18 from "fs";
22137
- import os15 from "os";
22138
- import path18 from "path";
22219
+ import fs17 from "fs";
22220
+ import os14 from "os";
22221
+ import path17 from "path";
22139
22222
  import { createHash as createHash4 } from "crypto";
22140
22223
  function osvRoot() {
22141
- return path18.join(os15.homedir(), ".node9", "osv");
22224
+ return path17.join(os14.homedir(), ".node9", "osv");
22142
22225
  }
22143
22226
  function ecoDir(eco) {
22144
- return path18.join(osvRoot(), eco);
22227
+ return path17.join(osvRoot(), eco);
22145
22228
  }
22146
22229
  function indexKey(eco, name) {
22147
22230
  switch (eco) {
@@ -22160,11 +22243,11 @@ function shardOf(key) {
22160
22243
  return createHash4("sha1").update(key).digest("hex").slice(0, 2);
22161
22244
  }
22162
22245
  function shardPath(eco, shard) {
22163
- return path18.join(ecoDir(eco), "shards", `${shard}.json`);
22246
+ return path17.join(ecoDir(eco), "shards", `${shard}.json`);
22164
22247
  }
22165
22248
  function readMeta(eco) {
22166
22249
  try {
22167
- const m = JSON.parse(fs18.readFileSync(path18.join(ecoDir(eco), "meta.json"), "utf8"));
22250
+ const m = JSON.parse(fs17.readFileSync(path17.join(ecoDir(eco), "meta.json"), "utf8"));
22168
22251
  if (typeof m?.syncedAt !== "string" || typeof m?.lastModifiedMs !== "number") return null;
22169
22252
  return m;
22170
22253
  } catch {
@@ -22173,7 +22256,7 @@ function readMeta(eco) {
22173
22256
  }
22174
22257
  function readShard(eco, shard) {
22175
22258
  try {
22176
- const s = JSON.parse(fs18.readFileSync(shardPath(eco, shard), "utf8"));
22259
+ const s = JSON.parse(fs17.readFileSync(shardPath(eco, shard), "utf8"));
22177
22260
  return s && typeof s === "object" && !Array.isArray(s) ? s : {};
22178
22261
  } catch {
22179
22262
  return {};
@@ -22555,17 +22638,17 @@ var init_registry2 = __esm({
22555
22638
  });
22556
22639
 
22557
22640
  // src/supply-chain/local-resolve.ts
22558
- import fs19 from "fs";
22559
- import path19 from "path";
22641
+ import fs18 from "fs";
22642
+ import path18 from "path";
22560
22643
  function resolveInstalled(name, cwd) {
22561
- if (!cwd || !path19.isAbsolute(cwd)) return null;
22644
+ if (!cwd || !path18.isAbsolute(cwd)) return null;
22562
22645
  if (!/^(?:@[^/\\]+\/)?[^/\\]+$/.test(name)) return null;
22563
- let dir2 = path19.resolve(cwd);
22646
+ let dir2 = path18.resolve(cwd);
22564
22647
  for (let i = 0; i < MAX_LEVELS; i++) {
22565
- const pkgDir = path19.join(dir2, "node_modules", ...name.split("/"));
22566
- const manifest = path19.join(pkgDir, "package.json");
22648
+ const pkgDir = path18.join(dir2, "node_modules", ...name.split("/"));
22649
+ const manifest = path18.join(pkgDir, "package.json");
22567
22650
  try {
22568
- const raw = fs19.readFileSync(manifest, "utf8");
22651
+ const raw = fs18.readFileSync(manifest, "utf8");
22569
22652
  const parsed = JSON.parse(raw);
22570
22653
  if (typeof parsed.version === "string" && parsed.version.length > 0) {
22571
22654
  return { version: parsed.version, dir: pkgDir };
@@ -22573,7 +22656,7 @@ function resolveInstalled(name, cwd) {
22573
22656
  return null;
22574
22657
  } catch {
22575
22658
  }
22576
- const parent = path19.dirname(dir2);
22659
+ const parent = path18.dirname(dir2);
22577
22660
  if (parent === dir2) break;
22578
22661
  dir2 = parent;
22579
22662
  }
@@ -22590,7 +22673,7 @@ var init_local_resolve = __esm({
22590
22673
 
22591
22674
  // src/supply-chain/check.ts
22592
22675
  import picomatch2 from "picomatch";
22593
- import path20 from "path";
22676
+ import path19 from "path";
22594
22677
  function commandOf(toolName, args) {
22595
22678
  if (!isBashTool(toolName) || !args || typeof args !== "object") return null;
22596
22679
  const a = args;
@@ -22692,7 +22775,7 @@ function checkInstalled(p, version, misses) {
22692
22775
  }
22693
22776
  async function checkOne(p, cfg, misses, networkCapped, cwd) {
22694
22777
  if (p.ecosystem === "npm" && LOCAL_FIRST_MANAGERS.has(p.manager) && p.localCwd !== null && (p.raw === p.name || p.version)) {
22695
- const localCwd = cwd && path20.isAbsolute(cwd) ? (p.localCwd ?? []).reduce((dir2, step) => path20.resolve(dir2, step), cwd) : void 0;
22778
+ const localCwd = cwd && path19.isAbsolute(cwd) ? (p.localCwd ?? []).reduce((dir2, step) => path19.resolve(dir2, step), cwd) : void 0;
22696
22779
  const installed = resolveInstalled(p.name, localCwd);
22697
22780
  if (installed && (!p.version || p.version === installed.version))
22698
22781
  return checkInstalled(p, installed.version, misses);
@@ -22861,33 +22944,33 @@ var init_check = __esm({
22861
22944
  });
22862
22945
 
22863
22946
  // src/supply-chain/registries.ts
22864
- import os16 from "os";
22865
- import path21 from "path";
22866
- import fs20 from "fs";
22947
+ import os15 from "os";
22948
+ import path20 from "path";
22949
+ import fs19 from "fs";
22867
22950
  function userFiles(home, env) {
22868
- const xdg = env.XDG_CONFIG_HOME || path21.join(home, ".config");
22951
+ const xdg = env.XDG_CONFIG_HOME || path20.join(home, ".config");
22869
22952
  return [
22870
- env.NPM_CONFIG_USERCONFIG || env.npm_config_userconfig || path21.join(home, ".npmrc"),
22871
- path21.join(home, ".yarnrc"),
22872
- path21.join(home, ".yarnrc.yml"),
22873
- path21.join(home, ".bunfig.toml"),
22953
+ env.NPM_CONFIG_USERCONFIG || env.npm_config_userconfig || path20.join(home, ".npmrc"),
22954
+ path20.join(home, ".yarnrc"),
22955
+ path20.join(home, ".yarnrc.yml"),
22956
+ path20.join(home, ".bunfig.toml"),
22874
22957
  env.PIP_CONFIG_FILE || "",
22875
- path21.join(xdg, "pip", "pip.conf"),
22876
- path21.join(home, ".pip", "pip.conf"),
22958
+ path20.join(xdg, "pip", "pip.conf"),
22959
+ path20.join(home, ".pip", "pip.conf"),
22877
22960
  "/etc/pip.conf",
22878
- env.VIRTUAL_ENV ? path21.join(env.VIRTUAL_ENV, "pip.conf") : "",
22961
+ env.VIRTUAL_ENV ? path20.join(env.VIRTUAL_ENV, "pip.conf") : "",
22879
22962
  env.UV_CONFIG_FILE || "",
22880
- path21.join(xdg, "uv", "uv.toml"),
22963
+ path20.join(xdg, "uv", "uv.toml"),
22881
22964
  "/etc/uv/uv.toml"
22882
22965
  ].filter(Boolean);
22883
22966
  }
22884
22967
  function projectFiles(cwd) {
22885
- if (!cwd || !path21.isAbsolute(cwd)) return [];
22968
+ if (!cwd || !path20.isAbsolute(cwd)) return [];
22886
22969
  const out = [];
22887
22970
  let dir2 = cwd;
22888
22971
  for (let i = 0; i < MAX_PARENT_DIRS; i++) {
22889
- for (const f of PROJECT_FILES) out.push(path21.join(dir2, f));
22890
- const parent = path21.dirname(dir2);
22972
+ for (const f of PROJECT_FILES) out.push(path20.join(dir2, f));
22973
+ const parent = path20.dirname(dir2);
22891
22974
  if (parent === dir2) break;
22892
22975
  dir2 = parent;
22893
22976
  }
@@ -22926,7 +23009,7 @@ function hostsInText(text, out) {
22926
23009
  }
22927
23010
  }
22928
23011
  }
22929
- function configuredRegistryHosts(cwd, env = process.env, home = os16.homedir()) {
23012
+ function configuredRegistryHosts(cwd, env = process.env, home = os15.homedir()) {
22930
23013
  const key = [
22931
23014
  cwd ?? "",
22932
23015
  home,
@@ -22948,7 +23031,7 @@ function configuredRegistryHosts(cwd, env = process.env, home = os16.homedir())
22948
23031
  const r = readCappedText(
22949
23032
  file2,
22950
23033
  MAX_CONFIG_BYTES,
22951
- fs20.constants.O_RDONLY | (fs20.constants.O_NONBLOCK ?? 0)
23034
+ fs19.constants.O_RDONLY | (fs19.constants.O_NONBLOCK ?? 0)
22952
23035
  );
22953
23036
  if (r) hostsInText(r.text, hosts);
22954
23037
  }
@@ -23005,17 +23088,17 @@ var init_registries = __esm({
23005
23088
  });
23006
23089
 
23007
23090
  // src/utils/provenance.ts
23008
- import fs21 from "fs";
23009
- import path22 from "path";
23010
- import os17 from "os";
23091
+ import fs20 from "fs";
23092
+ import path21 from "path";
23093
+ import os16 from "os";
23011
23094
  function findInPath(cmd) {
23012
- if (path22.posix.isAbsolute(cmd)) return cmd;
23095
+ if (path21.posix.isAbsolute(cmd)) return cmd;
23013
23096
  const pathEnv = process.env.PATH ?? "";
23014
- for (const dir2 of pathEnv.split(path22.delimiter)) {
23097
+ for (const dir2 of pathEnv.split(path21.delimiter)) {
23015
23098
  if (!dir2) continue;
23016
- const full = path22.join(dir2, cmd);
23099
+ const full = path21.join(dir2, cmd);
23017
23100
  try {
23018
- fs21.accessSync(full, fs21.constants.X_OK);
23101
+ fs20.accessSync(full, fs20.constants.X_OK);
23019
23102
  return full;
23020
23103
  } catch {
23021
23104
  }
@@ -23026,7 +23109,7 @@ function _classifyPath(resolved, cwd) {
23026
23109
  if (cwd && resolved.startsWith(cwd + "/")) {
23027
23110
  return { trustLevel: "user", reason: "binary in project directory" };
23028
23111
  }
23029
- const osTmp = os17.tmpdir();
23112
+ const osTmp = os16.tmpdir();
23030
23113
  const allSuspect = osTmp ? [...SUSPECT_PREFIXES, osTmp] : SUSPECT_PREFIXES;
23031
23114
  if (allSuspect.some((p) => resolved === p || resolved.startsWith(p + "/"))) {
23032
23115
  return { trustLevel: "suspect", reason: `binary in temp directory: ${resolved}` };
@@ -23044,7 +23127,7 @@ function _classifyPath(resolved, cwd) {
23044
23127
  }
23045
23128
  function checkProvenance(cmd, cwd) {
23046
23129
  const bare = cmd.startsWith("./") ? cmd.slice(2) : cmd;
23047
- if (path22.posix.isAbsolute(bare)) {
23130
+ if (path21.posix.isAbsolute(bare)) {
23048
23131
  const early = _classifyPath(bare, cwd);
23049
23132
  if (early.trustLevel === "suspect") {
23050
23133
  return { resolvedPath: bare, ...early };
@@ -23060,7 +23143,7 @@ function checkProvenance(cmd, cwd) {
23060
23143
  reason: "binary not found in PATH"
23061
23144
  };
23062
23145
  }
23063
- resolved = fs21.realpathSync(found);
23146
+ resolved = fs20.realpathSync(found);
23064
23147
  } catch {
23065
23148
  return {
23066
23149
  resolvedPath: cmd,
@@ -23069,7 +23152,7 @@ function checkProvenance(cmd, cwd) {
23069
23152
  };
23070
23153
  }
23071
23154
  try {
23072
- const stat = fs21.statSync(resolved);
23155
+ const stat = fs20.statSync(resolved);
23073
23156
  if (stat.mode & 2) {
23074
23157
  return {
23075
23158
  resolvedPath: resolved,
@@ -23094,19 +23177,19 @@ var init_provenance2 = __esm({
23094
23177
  SYSTEM_PREFIXES = ["/usr/bin", "/usr/sbin", "/bin", "/sbin"];
23095
23178
  MANAGED_PREFIXES = ["/usr/local/bin", "/opt/homebrew", "/home/linuxbrew", "/nix/store"];
23096
23179
  USER_PREFIXES = [
23097
- path22.join(os17.homedir(), "bin"),
23098
- path22.join(os17.homedir(), ".local", "bin"),
23099
- path22.join(os17.homedir(), ".cargo", "bin"),
23100
- path22.join(os17.homedir(), ".npm-global", "bin"),
23101
- path22.join(os17.homedir(), ".volta", "bin")
23180
+ path21.join(os16.homedir(), "bin"),
23181
+ path21.join(os16.homedir(), ".local", "bin"),
23182
+ path21.join(os16.homedir(), ".cargo", "bin"),
23183
+ path21.join(os16.homedir(), ".npm-global", "bin"),
23184
+ path21.join(os16.homedir(), ".volta", "bin")
23102
23185
  ];
23103
23186
  SUSPECT_PREFIXES = ["/tmp", "/var/tmp", "/dev/shm"];
23104
23187
  }
23105
23188
  });
23106
23189
 
23107
23190
  // src/policy/index.ts
23108
- import fs22 from "fs";
23109
- import path23 from "path";
23191
+ import fs21 from "fs";
23192
+ import path22 from "path";
23110
23193
  async function evaluatePolicy2(toolName, args, agent, cwd, opts) {
23111
23194
  const config = opts?.config ?? getConfig(cwd);
23112
23195
  const prepared = opts?.fileAccess ?? prepareFileAccesses(toolName, args, cwd, inspectionLayers(config.policy));
@@ -23138,9 +23221,9 @@ async function evaluatePolicy2(toolName, args, agent, cwd, opts) {
23138
23221
  );
23139
23222
  }
23140
23223
  function isGitWorkTreeTop(dir2, cwd) {
23141
- if (!path23.isAbsolute(cwd)) return true;
23224
+ if (!path22.isAbsolute(cwd)) return true;
23142
23225
  try {
23143
- return fs22.existsSync(path23.join(path23.resolve(cwd, dir2), ".git"));
23226
+ return fs21.existsSync(path22.join(path22.resolve(cwd, dir2), ".git"));
23144
23227
  } catch {
23145
23228
  return true;
23146
23229
  }
@@ -23149,7 +23232,7 @@ function readAgentSettings(absPath) {
23149
23232
  const r = readCappedText(
23150
23233
  absPath,
23151
23234
  MAX_AGENT_SETTINGS_BYTES,
23152
- fs22.constants.O_RDONLY | (fs22.constants.O_NONBLOCK ?? 0)
23235
+ fs21.constants.O_RDONLY | (fs21.constants.O_NONBLOCK ?? 0)
23153
23236
  );
23154
23237
  return r && !r.truncated ? r.text : null;
23155
23238
  }
@@ -23218,14 +23301,14 @@ var init_gate = __esm({
23218
23301
  });
23219
23302
 
23220
23303
  // src/posture/supply-chain.ts
23221
- import os18 from "os";
23222
- import path24 from "path";
23304
+ import os17 from "os";
23305
+ import path23 from "path";
23223
23306
  import { parse as parseToml6 } from "smol-toml";
23224
23307
  function isNode9Managed(command, args = []) {
23225
23308
  if (!command) return false;
23226
- if (path24.basename(command).toLowerCase() === "node9") return true;
23227
- if (PACKAGE_RUNNERS.has(path24.basename(command).toLowerCase())) {
23228
- return args.some((a) => a === "node9" || path24.basename(a).toLowerCase() === "node9");
23309
+ if (path23.basename(command).toLowerCase() === "node9") return true;
23310
+ if (PACKAGE_RUNNERS.has(path23.basename(command).toLowerCase())) {
23311
+ return args.some((a) => a === "node9" || path23.basename(a).toLowerCase() === "node9");
23229
23312
  }
23230
23313
  return false;
23231
23314
  }
@@ -23247,10 +23330,10 @@ function readServers(file2, format, agent) {
23247
23330
  }
23248
23331
  }
23249
23332
  function checkSupplyChain(ctx) {
23250
- const home = ctx.home || os18.homedir();
23333
+ const home = ctx.home || os17.homedir();
23251
23334
  const servers = [];
23252
23335
  for (const spec of AGENT_SPECS) {
23253
- if (!spec.mcpFile) continue;
23336
+ if (!spec.mcpFile || spec.mcpInventory === false) continue;
23254
23337
  servers.push(...readServers(spec.mcpFile(home), spec.mcpFormat ?? "json", spec.label));
23255
23338
  }
23256
23339
  if (servers.length === 0) return [];
@@ -23346,11 +23429,11 @@ var init_privilege = __esm({
23346
23429
  });
23347
23430
 
23348
23431
  // src/posture/containment.ts
23349
- import fs23 from "fs";
23432
+ import fs22 from "fs";
23350
23433
  function inContainer() {
23351
- if (fs23.existsSync("/.dockerenv") || fs23.existsSync("/run/.containerenv")) return true;
23434
+ if (fs22.existsSync("/.dockerenv") || fs22.existsSync("/run/.containerenv")) return true;
23352
23435
  try {
23353
- const cgroup = fs23.readFileSync("/proc/1/cgroup", "utf8");
23436
+ const cgroup = fs22.readFileSync("/proc/1/cgroup", "utf8");
23354
23437
  if (/docker|kubepods|containerd|lxc|libpod/.test(cgroup)) return true;
23355
23438
  } catch {
23356
23439
  }
@@ -23396,7 +23479,7 @@ var init_containment = __esm({
23396
23479
  });
23397
23480
 
23398
23481
  // src/posture/inbound.ts
23399
- import fs24 from "fs";
23482
+ import fs23 from "fs";
23400
23483
  function buildNetworkFix(labels) {
23401
23484
  const shielded = [
23402
23485
  ...new Map(
@@ -23454,7 +23537,7 @@ function collectListeners() {
23454
23537
  const byPort = /* @__PURE__ */ new Map();
23455
23538
  for (const file2 of ["/proc/net/tcp", "/proc/net/tcp6"]) {
23456
23539
  try {
23457
- for (const l of parseListeners(fs24.readFileSync(file2, "utf8"))) {
23540
+ for (const l of parseListeners(fs23.readFileSync(file2, "utf8"))) {
23458
23541
  if (!byPort.has(l.port)) byPort.set(l.port, l);
23459
23542
  }
23460
23543
  } catch {
@@ -23466,11 +23549,11 @@ function readProc(pid) {
23466
23549
  let comm = "unknown";
23467
23550
  let cmdline = "";
23468
23551
  try {
23469
- comm = fs24.readFileSync(`/proc/${pid}/comm`, "utf8").trim().replace(/-MainThread$/, "") || "unknown";
23552
+ comm = fs23.readFileSync(`/proc/${pid}/comm`, "utf8").trim().replace(/-MainThread$/, "") || "unknown";
23470
23553
  } catch {
23471
23554
  }
23472
23555
  try {
23473
- cmdline = fs24.readFileSync(`/proc/${pid}/cmdline`).toString().replace(/\0/g, " ").trim();
23556
+ cmdline = fs23.readFileSync(`/proc/${pid}/cmdline`).toString().replace(/\0/g, " ").trim();
23474
23557
  } catch {
23475
23558
  }
23476
23559
  return { comm, cmdline };
@@ -23480,21 +23563,21 @@ function resolveProcesses(inodes) {
23480
23563
  if (inodes.size === 0) return map;
23481
23564
  let pids;
23482
23565
  try {
23483
- pids = fs24.readdirSync("/proc").filter((d) => /^\d+$/.test(d));
23566
+ pids = fs23.readdirSync("/proc").filter((d) => /^\d+$/.test(d));
23484
23567
  } catch {
23485
23568
  return map;
23486
23569
  }
23487
23570
  for (const pid of pids) {
23488
23571
  let fds;
23489
23572
  try {
23490
- fds = fs24.readdirSync(`/proc/${pid}/fd`);
23573
+ fds = fs23.readdirSync(`/proc/${pid}/fd`);
23491
23574
  } catch {
23492
23575
  continue;
23493
23576
  }
23494
23577
  for (const fd of fds) {
23495
23578
  let link;
23496
23579
  try {
23497
- link = fs24.readlinkSync(`/proc/${pid}/fd/${fd}`);
23580
+ link = fs23.readlinkSync(`/proc/${pid}/fd/${fd}`);
23498
23581
  } catch {
23499
23582
  continue;
23500
23583
  }
@@ -23599,9 +23682,9 @@ var init_inbound = __esm({
23599
23682
  });
23600
23683
 
23601
23684
  // src/posture/coverage.ts
23602
- import os19 from "os";
23685
+ import os18 from "os";
23603
23686
  function checkCoverage(ctx) {
23604
- const home = ctx.home || os19.homedir();
23687
+ const home = ctx.home || os18.homedir();
23605
23688
  const findings = [];
23606
23689
  const protectedAgents = getAgentWiring(home).filter((r) => r.isProtected);
23607
23690
  if (protectedAgents.length === 0) {
@@ -23645,7 +23728,7 @@ var init_coverage = __esm({
23645
23728
  });
23646
23729
 
23647
23730
  // src/posture/governance.ts
23648
- import path25 from "path";
23731
+ import path24 from "path";
23649
23732
  function checkData(ctx) {
23650
23733
  const dlp = getConfig(ctx.cwd).policy.dlp;
23651
23734
  if (!dlp?.enabled) {
@@ -23789,7 +23872,7 @@ var init_governance = __esm({
23789
23872
  "src/posture/governance.ts"() {
23790
23873
  "use strict";
23791
23874
  init_config();
23792
- jailProbePath = (home) => path25.join(home, ".aws", "credentials");
23875
+ jailProbePath = (home) => path24.join(home, ".aws", "credentials");
23793
23876
  }
23794
23877
  });
23795
23878
 
@@ -23968,7 +24051,7 @@ var init_enforcement = __esm({
23968
24051
  });
23969
24052
 
23970
24053
  // src/posture/index.ts
23971
- import os20 from "os";
24054
+ import os19 from "os";
23972
24055
  function dropEnforcementRedundant(findings) {
23973
24056
  const coveragePresent = findings.some((f) => f.category === "Coverage");
23974
24057
  if (!coveragePresent) return findings;
@@ -23994,9 +24077,10 @@ async function runChecks(checks, ctx) {
23994
24077
  }
23995
24078
  async function runPosture(opts = {}) {
23996
24079
  const ctx = {
23997
- home: opts.home ?? os20.homedir(),
24080
+ home: opts.home ?? os19.homedir(),
23998
24081
  cwd: opts.cwd ?? process.cwd(),
23999
- agent: opts.agent
24082
+ agent: opts.agent,
24083
+ env: opts.env
24000
24084
  };
24001
24085
  const {
24002
24086
  findings: rawFindings,
@@ -24055,6 +24139,102 @@ var init_posture = __esm({
24055
24139
  }
24056
24140
  });
24057
24141
 
24142
+ // src/posture/render.ts
24143
+ import chalk2 from "chalk";
24144
+ var ICON, TIER_LABEL;
24145
+ var init_render = __esm({
24146
+ "src/posture/render.ts"() {
24147
+ "use strict";
24148
+ init_score();
24149
+ ICON = {
24150
+ critical: chalk2.red("\u274C"),
24151
+ high: chalk2.red("\u274C"),
24152
+ medium: chalk2.yellow("\u26A0\uFE0F "),
24153
+ advisory: chalk2.gray("\u26A0\uFE0F ")
24154
+ };
24155
+ TIER_LABEL = {
24156
+ good: chalk2.green("Good"),
24157
+ "at-risk": chalk2.yellow("At risk"),
24158
+ critical: chalk2.red("Critical")
24159
+ };
24160
+ }
24161
+ });
24162
+
24163
+ // src/cli/commands/blast.ts
24164
+ import chalk3 from "chalk";
24165
+ import fs24 from "fs";
24166
+ import path25 from "path";
24167
+ import os20 from "os";
24168
+ function buildSensitivePaths(home, cwd) {
24169
+ const homeFiles = homeCredentialFiles(home).map(({ full, label: label2, description, score }) => ({
24170
+ full,
24171
+ label: label2,
24172
+ description,
24173
+ score
24174
+ }));
24175
+ return [
24176
+ ...homeFiles,
24177
+ {
24178
+ full: path25.join(cwd, ".env"),
24179
+ label: ".env (current folder)",
24180
+ description: "App secrets: database passwords, API keys",
24181
+ score: 20
24182
+ },
24183
+ {
24184
+ full: path25.join(cwd, ".env.local"),
24185
+ label: ".env.local (current folder)",
24186
+ description: "Local overrides: often contains real credentials",
24187
+ score: 15
24188
+ },
24189
+ {
24190
+ full: path25.join(cwd, ".env.production"),
24191
+ label: ".env.production (current folder)",
24192
+ description: "Production secrets",
24193
+ score: 20
24194
+ }
24195
+ ];
24196
+ }
24197
+ function isReadable(filePath) {
24198
+ try {
24199
+ fs24.accessSync(filePath, fs24.constants.R_OK);
24200
+ return true;
24201
+ } catch {
24202
+ return false;
24203
+ }
24204
+ }
24205
+ function runBlast() {
24206
+ const home = os20.homedir();
24207
+ const cwd = process.cwd();
24208
+ const paths = buildSensitivePaths(home, cwd);
24209
+ let scoreDeduction = 0;
24210
+ const reachable = [];
24211
+ for (const p of paths) {
24212
+ if (fs24.existsSync(p.full) && isReadable(p.full)) {
24213
+ reachable.push(p);
24214
+ scoreDeduction += p.score;
24215
+ }
24216
+ }
24217
+ const envFindings = [];
24218
+ for (const [key, value] of Object.entries(process.env)) {
24219
+ if (!value) continue;
24220
+ const match = scanArgs({ [key]: value });
24221
+ if (match) {
24222
+ envFindings.push({ key, patternName: match.patternName });
24223
+ scoreDeduction += 10;
24224
+ }
24225
+ }
24226
+ return { reachable, envFindings, score: Math.max(0, 100 - scoreDeduction) };
24227
+ }
24228
+ var init_blast = __esm({
24229
+ "src/cli/commands/blast.ts"() {
24230
+ "use strict";
24231
+ init_dlp();
24232
+ init_credential_files();
24233
+ init_posture();
24234
+ init_render();
24235
+ }
24236
+ });
24237
+
24058
24238
  // src/auth/decision-record.ts
24059
24239
  function personRecord(channel, decision, extra = {}, now = Date.now()) {
24060
24240
  return {
@@ -24714,7 +24894,7 @@ import * as fs26 from "fs";
24714
24894
  import * as path27 from "path";
24715
24895
  function listSessionFiles(dir2, maxDepth = 6) {
24716
24896
  const out = [];
24717
- const walk2 = (d, rel, depth) => {
24897
+ const walk3 = (d, rel, depth) => {
24718
24898
  if (depth > maxDepth) return;
24719
24899
  let entries;
24720
24900
  try {
@@ -24724,11 +24904,11 @@ function listSessionFiles(dir2, maxDepth = 6) {
24724
24904
  }
24725
24905
  for (const e of entries) {
24726
24906
  const childRel = rel ? path27.join(rel, e.name) : e.name;
24727
- if (e.isDirectory()) walk2(path27.join(d, e.name), childRel, depth + 1);
24907
+ if (e.isDirectory()) walk3(path27.join(d, e.name), childRel, depth + 1);
24728
24908
  else if (e.name.endsWith(".jsonl")) out.push(childRel);
24729
24909
  }
24730
24910
  };
24731
- walk2(dir2, "", 0);
24911
+ walk3(dir2, "", 0);
24732
24912
  return out;
24733
24913
  }
24734
24914
  function sessionIdOf(relPath) {
@@ -25535,7 +25715,7 @@ var init_report_audit = __esm({
25535
25715
  });
25536
25716
 
25537
25717
  // src/config/keyed-guard.ts
25538
- import chalk3 from "chalk";
25718
+ import chalk4 from "chalk";
25539
25719
  function isKeyedForPolicy() {
25540
25720
  try {
25541
25721
  return getConfig().policySource === "workspace";
@@ -29344,7 +29524,7 @@ var init_scan_summary = __esm({
29344
29524
  });
29345
29525
 
29346
29526
  // src/cli/render/scan-derive.ts
29347
- import chalk4 from "chalk";
29527
+ import chalk5 from "chalk";
29348
29528
  import stringWidth from "string-width";
29349
29529
  var init_scan_derive = __esm({
29350
29530
  "src/cli/render/scan-derive.ts"() {
@@ -29363,7 +29543,6 @@ var init_protection = __esm({
29363
29543
  var init_scan_json = __esm({
29364
29544
  "src/cli/render/scan-json.ts"() {
29365
29545
  "use strict";
29366
- init_scan_derive();
29367
29546
  }
29368
29547
  });
29369
29548
 
@@ -29376,7 +29555,7 @@ var init_scan_history = __esm({
29376
29555
  });
29377
29556
 
29378
29557
  // src/cli/commands/scan.ts
29379
- import chalk5 from "chalk";
29558
+ import chalk6 from "chalk";
29380
29559
  import fs43 from "fs";
29381
29560
  import path46 from "path";
29382
29561
  import os35 from "os";
@@ -29522,19 +29701,19 @@ function scrubDecoys(subject, values) {
29522
29701
  for (const v of values) if (v) out = out.split(v).join("[node9-decoy]");
29523
29702
  return out;
29524
29703
  };
29525
- const walk2 = (v, depth) => {
29704
+ const walk3 = (v, depth) => {
29526
29705
  if (depth > 6) return v;
29527
29706
  if (typeof v === "string") return scrubText(v);
29528
- if (Array.isArray(v)) return v.map((x) => walk2(x, depth + 1));
29707
+ if (Array.isArray(v)) return v.map((x) => walk3(x, depth + 1));
29529
29708
  if (v && typeof v === "object") {
29530
29709
  const out = {};
29531
29710
  for (const [k, child] of Object.entries(v))
29532
- out[k] = walk2(child, depth + 1);
29711
+ out[k] = walk3(child, depth + 1);
29533
29712
  return out;
29534
29713
  }
29535
29714
  return v;
29536
29715
  };
29537
- return walk2(subject, 0);
29716
+ return walk3(subject, 0);
29538
29717
  }
29539
29718
  function detectLoops(calls, project, sessionId, agent) {
29540
29719
  const counts = /* @__PURE__ */ new Map();
@@ -30721,7 +30900,7 @@ var init_scan = __esm({
30721
30900
  init_hook_payload();
30722
30901
  init_dist();
30723
30902
  init_scan_summary();
30724
- init_setup();
30903
+ init_agent_wiring();
30725
30904
  init_blast();
30726
30905
  init_scan_derive();
30727
30906
  init_protection();