@node9/proxy 2.21.0 → 2.22.1

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (3) hide show
  1. package/dist/cli.js +37 -13
  2. package/dist/cli.mjs +37 -13
  3. package/package.json +1 -1
package/dist/cli.js CHANGED
@@ -59232,11 +59232,29 @@ function suspiciousZeroWidth(text) {
59232
59232
  }
59233
59233
  var stripZeroWidth = (t) => t.replace(/[​⁠]/g, "");
59234
59234
  var INSTRUCTION_FILE_RE = /(^|\/)(CLAUDE|AGENTS|GEMINI)\.md$|(^|\/)\.cursorrules$|(^|\/)\.(windsurf|cline)rules$|(^|\/)copilot-instructions\.md$|(^|\/)SKILL\.md$|(^|\/)\.claude\/agents\/[^/]+\.md$|(^|\/)\.claude\/commands\/.+\.md$/;
59235
+ function skillDirsOf(paths) {
59236
+ const dirs = /* @__PURE__ */ new Set();
59237
+ for (const p of paths) {
59238
+ const m = /^(.+)\/SKILL\.md$/.exec(p);
59239
+ if (m) dirs.add(m[1]);
59240
+ }
59241
+ return dirs;
59242
+ }
59243
+ function isSkillSupportFile(path79, skillDirs) {
59244
+ if (!path79.endsWith(".md") || /(^|\/)SKILL\.md$/.test(path79)) return false;
59245
+ for (let d = path79.lastIndexOf("/"); d > 0; d = path79.lastIndexOf("/", d - 1)) {
59246
+ if (skillDirs.has(path79.slice(0, d))) return true;
59247
+ }
59248
+ return false;
59249
+ }
59250
+ function isInstructionFile(path79, skillDirs) {
59251
+ return INSTRUCTION_FILE_RE.test(path79) || isSkillSupportFile(path79, skillDirs);
59252
+ }
59235
59253
  var OVERRIDE_RE = /ignore\s+(all\s+)?(previous|prior|the\s+above)\s+(instructions|prompts?|rules)|disregard\s+(the\s+|your\s+)?(system\s+)?(prompt|instructions|rules)|forget\s+(everything|all\s+(previous|prior))|you\s+are\s+now\s+(a|an|the)\b|<\/?system>/i;
59236
59254
  var FETCH_OBEY_RE = /\b(curl|wget|iwr|invoke-webrequest)\b[^\n|]*\|\s*(bash|sh|zsh|python3?(?!\s+-m\s+json\.tool\b)|node|iex)\b|\b(curl|wget)\b[^\n]*&&[^\n]*\b(bash|sh)\b/i;
59237
59255
  var SECRET_PATH_RE = /~\/\.aws\/credentials|~\/\.ssh\/id_[a-z]+|~\/\.config\/gh\/hosts|read\s+the\s+(token|secret|api[_ ]?key|password)\s+(in|from)\s+[.`'"]?\.?env/i;
59238
59256
  var EXFIL_RE = /\b(post|send|upload|exfiltrate|forward)\b(?!\s+(the\s+|your\s+)?(users?|them|him|her|people|visitors?|customers?|readers?)\b)[^\n]{0,40}\b(to|at)\b[^\n]{0,50}(https?:\/\/|webhook|hook\.[a-z])/i;
59239
- var HUMAN_SECTION_RE = /^#+\s.*\b(install(ation|ers?|ing|s)?|setup|set ?up|getting started|quick ?start|contributing|contribution|development|dev setup|build|prerequisites|requirements|usage)\b/i;
59257
+ var HUMAN_SECTION_RE = /^#+\s.*\b((?:re-?|un)?install(ation|ers?|ing|s)?|setup|set ?up|getting started|quick ?start|contributing|contribution|development|dev setup|build|prerequisites|requirements|usage)\b/i;
59240
59258
  var NEGATION_RE = /\b(never|do not|don'?t|avoid|must not|should not|no need to|refuse to)\b/i;
59241
59259
  function isNegated(text, idx) {
59242
59260
  return NEGATION_RE.test(text.slice(Math.max(0, idx - 40), idx));
@@ -59431,13 +59449,17 @@ var SURFACE_FILES = [
59431
59449
  ];
59432
59450
  var WORKFLOW_DIR = ".github/workflows";
59433
59451
  var CONFIG_FILE_RE = /(^|\/)\.claude\/settings(\.local)?\.json$|(^|\/)\.mcp\.json$|(^|\/)\.cursor\/mcp\.json$|(^|\/)\.codex\/config\.toml$/;
59434
- var SURFACE_BASENAME = new RegExp(`${INSTRUCTION_FILE_RE.source}|${CONFIG_FILE_RE.source}`);
59452
+ function selectSurface(paths) {
59453
+ const skillDirs = skillDirsOf(paths);
59454
+ const isSupport = (p) => isSkillSupportFile(p, skillDirs);
59455
+ return paths.filter((p) => isInstructionFile(p, skillDirs) || CONFIG_FILE_RE.test(p)).sort((a, b) => Number(isSupport(a)) - Number(isSupport(b)));
59456
+ }
59435
59457
  var IGNORE_HARD = /(^|\/)(node_modules|vendor|\.git|\.next|\.venv|site-packages)\//;
59436
59458
  var IGNORE_SOFT = /(^|\/)(dist|build|out|target)\//;
59437
59459
  var isIgnoredDir = (relSlash) => IGNORE_HARD.test(relSlash) || IGNORE_SOFT.test(relSlash);
59438
59460
  var MAX_SURFACE_FILES = 200;
59439
59461
  function pickSurfacePaths(paths, truncated, notes) {
59440
- const surface = paths.filter((p) => SURFACE_BASENAME.test(p) && !IGNORE_HARD.test(p));
59462
+ const surface = selectSurface(paths.filter((p) => !IGNORE_HARD.test(p)));
59441
59463
  const matched = surface.filter((p) => !IGNORE_SOFT.test(p));
59442
59464
  const softSkipped = surface.filter((p) => IGNORE_SOFT.test(p));
59443
59465
  const capped = matched.slice(0, MAX_SURFACE_FILES);
@@ -59609,11 +59631,11 @@ function readLocalTree(dir) {
59609
59631
  add(rel);
59610
59632
  };
59611
59633
  for (const p of SURFACE_FILES) collect(p);
59612
- const matches = [];
59634
+ const all = [];
59613
59635
  const MAX_DIRS = 5e3;
59614
59636
  let dirsVisited = 0;
59615
59637
  const walk = (relDir) => {
59616
- if (matches.length >= MAX_SURFACE_FILES || dirsVisited >= MAX_DIRS) return;
59638
+ if (dirsVisited >= MAX_DIRS) return;
59617
59639
  dirsVisited++;
59618
59640
  let entries;
59619
59641
  try {
@@ -59622,22 +59644,23 @@ function readLocalTree(dir) {
59622
59644
  return;
59623
59645
  }
59624
59646
  for (const e of entries) {
59625
- if (matches.length >= MAX_SURFACE_FILES || dirsVisited >= MAX_DIRS) return;
59647
+ if (dirsVisited >= MAX_DIRS) return;
59626
59648
  const rel = relDir ? `${relDir}/${e.name}` : e.name;
59627
59649
  if (e.isDirectory()) {
59628
59650
  if (isIgnoredDir(`${rel}/`)) continue;
59629
59651
  walk(rel);
59630
- } else if (e.isFile() && SURFACE_BASENAME.test(rel)) {
59631
- matches.push(rel);
59652
+ } else if (e.isFile()) {
59653
+ all.push(rel);
59632
59654
  }
59633
59655
  }
59634
59656
  };
59635
59657
  walk("");
59636
- if (matches.length >= MAX_SURFACE_FILES || dirsVisited >= MAX_DIRS)
59658
+ const matches = selectSurface(all);
59659
+ if (matches.length > MAX_SURFACE_FILES || dirsVisited >= MAX_DIRS)
59637
59660
  notes.push(
59638
59661
  `repo is large \u2014 some agent-surface files may be INCOMPLETE (capped at ${MAX_SURFACE_FILES} files / ${MAX_DIRS} dirs).`
59639
59662
  );
59640
- for (const rel of matches) collect(rel);
59663
+ for (const rel of matches.slice(0, MAX_SURFACE_FILES)) collect(rel);
59641
59664
  const wfDir = import_path61.default.join(root, WORKFLOW_DIR);
59642
59665
  try {
59643
59666
  if (import_fs66.default.existsSync(wfDir)) {
@@ -59680,7 +59703,7 @@ function readGitRefTree(dir, ref) {
59680
59703
  if (content !== null) files.push({ path: rel, content });
59681
59704
  };
59682
59705
  for (const rel of SURFACE_FILES) add(rel);
59683
- const nested = all.filter((rel) => SURFACE_BASENAME.test(rel) && !isIgnoredDir(rel));
59706
+ const nested = selectSurface(all.filter((rel) => !isIgnoredDir(rel)));
59684
59707
  if (nested.length > MAX_SURFACE_FILES) {
59685
59708
  notes.push(
59686
59709
  `repo is large \u2014 some agent-surface files may be INCOMPLETE (capped at ${MAX_SURFACE_FILES} files).`
@@ -60475,6 +60498,7 @@ function scanTree(tree) {
60475
60498
  const findings = [];
60476
60499
  const inspected = [];
60477
60500
  const notes = [...tree.notes];
60501
+ const skillDirs = skillDirsOf(tree.files.map((f) => f.path));
60478
60502
  for (const file of tree.files) {
60479
60503
  inspected.push(file.path);
60480
60504
  try {
@@ -60489,7 +60513,7 @@ function scanTree(tree) {
60489
60513
  findings.push(...analyzeMcp(file.path, file.content));
60490
60514
  } else if (/(^|\/)\.codex\/config\.toml$/.test(file.path)) {
60491
60515
  findings.push(...analyzeCodexConfig(file.path, file.content));
60492
- } else if (INSTRUCTION_FILE_RE.test(file.path)) {
60516
+ } else if (isInstructionFile(file.path, skillDirs)) {
60493
60517
  findings.push(...analyzeInstructionFile(file.path, file.content));
60494
60518
  }
60495
60519
  } catch (err2) {
@@ -60522,7 +60546,7 @@ var COLOR = {
60522
60546
  medium: import_chalk32.default.yellow,
60523
60547
  advisory: import_chalk32.default.gray
60524
60548
  };
60525
- var ACTION_URL = "https://github.com/marketplace/actions/node9-agent-security-check?ref=cli_scan_repo";
60549
+ var ACTION_URL = "https://github.com/marketplace/actions/node9-agent-security?ref=cli_scan_repo";
60526
60550
  function renderCta(res) {
60527
60551
  const L = [];
60528
60552
  L.push(import_chalk32.default.dim(" " + "\u2500".repeat(63)));
package/dist/cli.mjs CHANGED
@@ -59221,11 +59221,29 @@ function suspiciousZeroWidth(text) {
59221
59221
  }
59222
59222
  var stripZeroWidth = (t) => t.replace(/[​⁠]/g, "");
59223
59223
  var INSTRUCTION_FILE_RE = /(^|\/)(CLAUDE|AGENTS|GEMINI)\.md$|(^|\/)\.cursorrules$|(^|\/)\.(windsurf|cline)rules$|(^|\/)copilot-instructions\.md$|(^|\/)SKILL\.md$|(^|\/)\.claude\/agents\/[^/]+\.md$|(^|\/)\.claude\/commands\/.+\.md$/;
59224
+ function skillDirsOf(paths) {
59225
+ const dirs = /* @__PURE__ */ new Set();
59226
+ for (const p of paths) {
59227
+ const m = /^(.+)\/SKILL\.md$/.exec(p);
59228
+ if (m) dirs.add(m[1]);
59229
+ }
59230
+ return dirs;
59231
+ }
59232
+ function isSkillSupportFile(path79, skillDirs) {
59233
+ if (!path79.endsWith(".md") || /(^|\/)SKILL\.md$/.test(path79)) return false;
59234
+ for (let d = path79.lastIndexOf("/"); d > 0; d = path79.lastIndexOf("/", d - 1)) {
59235
+ if (skillDirs.has(path79.slice(0, d))) return true;
59236
+ }
59237
+ return false;
59238
+ }
59239
+ function isInstructionFile(path79, skillDirs) {
59240
+ return INSTRUCTION_FILE_RE.test(path79) || isSkillSupportFile(path79, skillDirs);
59241
+ }
59224
59242
  var OVERRIDE_RE = /ignore\s+(all\s+)?(previous|prior|the\s+above)\s+(instructions|prompts?|rules)|disregard\s+(the\s+|your\s+)?(system\s+)?(prompt|instructions|rules)|forget\s+(everything|all\s+(previous|prior))|you\s+are\s+now\s+(a|an|the)\b|<\/?system>/i;
59225
59243
  var FETCH_OBEY_RE = /\b(curl|wget|iwr|invoke-webrequest)\b[^\n|]*\|\s*(bash|sh|zsh|python3?(?!\s+-m\s+json\.tool\b)|node|iex)\b|\b(curl|wget)\b[^\n]*&&[^\n]*\b(bash|sh)\b/i;
59226
59244
  var SECRET_PATH_RE = /~\/\.aws\/credentials|~\/\.ssh\/id_[a-z]+|~\/\.config\/gh\/hosts|read\s+the\s+(token|secret|api[_ ]?key|password)\s+(in|from)\s+[.`'"]?\.?env/i;
59227
59245
  var EXFIL_RE = /\b(post|send|upload|exfiltrate|forward)\b(?!\s+(the\s+|your\s+)?(users?|them|him|her|people|visitors?|customers?|readers?)\b)[^\n]{0,40}\b(to|at)\b[^\n]{0,50}(https?:\/\/|webhook|hook\.[a-z])/i;
59228
- var HUMAN_SECTION_RE = /^#+\s.*\b(install(ation|ers?|ing|s)?|setup|set ?up|getting started|quick ?start|contributing|contribution|development|dev setup|build|prerequisites|requirements|usage)\b/i;
59246
+ var HUMAN_SECTION_RE = /^#+\s.*\b((?:re-?|un)?install(ation|ers?|ing|s)?|setup|set ?up|getting started|quick ?start|contributing|contribution|development|dev setup|build|prerequisites|requirements|usage)\b/i;
59229
59247
  var NEGATION_RE = /\b(never|do not|don'?t|avoid|must not|should not|no need to|refuse to)\b/i;
59230
59248
  function isNegated(text, idx) {
59231
59249
  return NEGATION_RE.test(text.slice(Math.max(0, idx - 40), idx));
@@ -59420,13 +59438,17 @@ var SURFACE_FILES = [
59420
59438
  ];
59421
59439
  var WORKFLOW_DIR = ".github/workflows";
59422
59440
  var CONFIG_FILE_RE = /(^|\/)\.claude\/settings(\.local)?\.json$|(^|\/)\.mcp\.json$|(^|\/)\.cursor\/mcp\.json$|(^|\/)\.codex\/config\.toml$/;
59423
- var SURFACE_BASENAME = new RegExp(`${INSTRUCTION_FILE_RE.source}|${CONFIG_FILE_RE.source}`);
59441
+ function selectSurface(paths) {
59442
+ const skillDirs = skillDirsOf(paths);
59443
+ const isSupport = (p) => isSkillSupportFile(p, skillDirs);
59444
+ return paths.filter((p) => isInstructionFile(p, skillDirs) || CONFIG_FILE_RE.test(p)).sort((a, b) => Number(isSupport(a)) - Number(isSupport(b)));
59445
+ }
59424
59446
  var IGNORE_HARD = /(^|\/)(node_modules|vendor|\.git|\.next|\.venv|site-packages)\//;
59425
59447
  var IGNORE_SOFT = /(^|\/)(dist|build|out|target)\//;
59426
59448
  var isIgnoredDir = (relSlash) => IGNORE_HARD.test(relSlash) || IGNORE_SOFT.test(relSlash);
59427
59449
  var MAX_SURFACE_FILES = 200;
59428
59450
  function pickSurfacePaths(paths, truncated, notes) {
59429
- const surface = paths.filter((p) => SURFACE_BASENAME.test(p) && !IGNORE_HARD.test(p));
59451
+ const surface = selectSurface(paths.filter((p) => !IGNORE_HARD.test(p)));
59430
59452
  const matched = surface.filter((p) => !IGNORE_SOFT.test(p));
59431
59453
  const softSkipped = surface.filter((p) => IGNORE_SOFT.test(p));
59432
59454
  const capped = matched.slice(0, MAX_SURFACE_FILES);
@@ -59598,11 +59620,11 @@ function readLocalTree(dir) {
59598
59620
  add(rel);
59599
59621
  };
59600
59622
  for (const p of SURFACE_FILES) collect(p);
59601
- const matches = [];
59623
+ const all = [];
59602
59624
  const MAX_DIRS = 5e3;
59603
59625
  let dirsVisited = 0;
59604
59626
  const walk = (relDir) => {
59605
- if (matches.length >= MAX_SURFACE_FILES || dirsVisited >= MAX_DIRS) return;
59627
+ if (dirsVisited >= MAX_DIRS) return;
59606
59628
  dirsVisited++;
59607
59629
  let entries;
59608
59630
  try {
@@ -59611,22 +59633,23 @@ function readLocalTree(dir) {
59611
59633
  return;
59612
59634
  }
59613
59635
  for (const e of entries) {
59614
- if (matches.length >= MAX_SURFACE_FILES || dirsVisited >= MAX_DIRS) return;
59636
+ if (dirsVisited >= MAX_DIRS) return;
59615
59637
  const rel = relDir ? `${relDir}/${e.name}` : e.name;
59616
59638
  if (e.isDirectory()) {
59617
59639
  if (isIgnoredDir(`${rel}/`)) continue;
59618
59640
  walk(rel);
59619
- } else if (e.isFile() && SURFACE_BASENAME.test(rel)) {
59620
- matches.push(rel);
59641
+ } else if (e.isFile()) {
59642
+ all.push(rel);
59621
59643
  }
59622
59644
  }
59623
59645
  };
59624
59646
  walk("");
59625
- if (matches.length >= MAX_SURFACE_FILES || dirsVisited >= MAX_DIRS)
59647
+ const matches = selectSurface(all);
59648
+ if (matches.length > MAX_SURFACE_FILES || dirsVisited >= MAX_DIRS)
59626
59649
  notes.push(
59627
59650
  `repo is large \u2014 some agent-surface files may be INCOMPLETE (capped at ${MAX_SURFACE_FILES} files / ${MAX_DIRS} dirs).`
59628
59651
  );
59629
- for (const rel of matches) collect(rel);
59652
+ for (const rel of matches.slice(0, MAX_SURFACE_FILES)) collect(rel);
59630
59653
  const wfDir = path65.join(root, WORKFLOW_DIR);
59631
59654
  try {
59632
59655
  if (fs70.existsSync(wfDir)) {
@@ -59669,7 +59692,7 @@ function readGitRefTree(dir, ref) {
59669
59692
  if (content !== null) files.push({ path: rel, content });
59670
59693
  };
59671
59694
  for (const rel of SURFACE_FILES) add(rel);
59672
- const nested = all.filter((rel) => SURFACE_BASENAME.test(rel) && !isIgnoredDir(rel));
59695
+ const nested = selectSurface(all.filter((rel) => !isIgnoredDir(rel)));
59673
59696
  if (nested.length > MAX_SURFACE_FILES) {
59674
59697
  notes.push(
59675
59698
  `repo is large \u2014 some agent-surface files may be INCOMPLETE (capped at ${MAX_SURFACE_FILES} files).`
@@ -60464,6 +60487,7 @@ function scanTree(tree) {
60464
60487
  const findings = [];
60465
60488
  const inspected = [];
60466
60489
  const notes = [...tree.notes];
60490
+ const skillDirs = skillDirsOf(tree.files.map((f) => f.path));
60467
60491
  for (const file of tree.files) {
60468
60492
  inspected.push(file.path);
60469
60493
  try {
@@ -60478,7 +60502,7 @@ function scanTree(tree) {
60478
60502
  findings.push(...analyzeMcp(file.path, file.content));
60479
60503
  } else if (/(^|\/)\.codex\/config\.toml$/.test(file.path)) {
60480
60504
  findings.push(...analyzeCodexConfig(file.path, file.content));
60481
- } else if (INSTRUCTION_FILE_RE.test(file.path)) {
60505
+ } else if (isInstructionFile(file.path, skillDirs)) {
60482
60506
  findings.push(...analyzeInstructionFile(file.path, file.content));
60483
60507
  }
60484
60508
  } catch (err2) {
@@ -60511,7 +60535,7 @@ var COLOR = {
60511
60535
  medium: chalk32.yellow,
60512
60536
  advisory: chalk32.gray
60513
60537
  };
60514
- var ACTION_URL = "https://github.com/marketplace/actions/node9-agent-security-check?ref=cli_scan_repo";
60538
+ var ACTION_URL = "https://github.com/marketplace/actions/node9-agent-security?ref=cli_scan_repo";
60515
60539
  function renderCta(res) {
60516
60540
  const L = [];
60517
60541
  L.push(chalk32.dim(" " + "\u2500".repeat(63)));
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@node9/proxy",
3
- "version": "2.21.0",
3
+ "version": "2.22.1",
4
4
  "description": "IAM for your AI agents. Set what Claude Code, Codex, Gemini, Cursor and any MCP server are allowed to do, review risky actions before they run, and keep every action on the record.",
5
5
  "main": "./dist/index.js",
6
6
  "module": "./dist/index.mjs",