@golproductions/check 3.2.5 → 3.2.7

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 (2) hide show
  1. package/package.json +1 -1
  2. package/src/index.js +47 -11
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@golproductions/check",
3
- "version": "3.2.5",
3
+ "version": "3.2.7",
4
4
  "description": "The anti-hallucination layer for AI coding agents. Stops hallucinated commands, packages, and URLs before they run.",
5
5
  "bin": {
6
6
  "check": "src/index.js",
package/src/index.js CHANGED
@@ -6,7 +6,7 @@ import { homedir, platform, arch } from "node:os";
6
6
  import { pipeline } from "node:stream/promises";
7
7
  import { Readable } from "node:stream";
8
8
 
9
- const VERSION = "3.2.5";
9
+ const VERSION = "3.2.7";
10
10
  const BINARY_VERSION = "3.0.0";
11
11
  const API = "https://triage.golproductions.com/preflight";
12
12
  const CDN = "https://pub-e55366a7f5994be9be04f0e205179f4a.r2.dev/releases";
@@ -744,19 +744,36 @@ const SHELL_BUILTINS = new Set([
744
744
  "done", "case", "esac", "in", "function", "select", "{", "}", "!",
745
745
  ]);
746
746
 
747
+ // Quote-aware: "./spaced name.sh" is ONE token, and connectors inside
748
+ // quotes are literal text, not separators.
747
749
  function segmentBases(command) {
750
+ const segs = [[]];
751
+ let cur = "", q = null;
752
+ for (let i = 0; i < command.length; i++) {
753
+ const ch = command[i];
754
+ if (q) { if (ch === q) q = null; else cur += ch; continue; }
755
+ if (ch === '"' || ch === "'") { q = ch; continue; }
756
+ if (ch === "|" || ch === "&" || ch === ";" || ch === "\n") {
757
+ if (cur) { segs[segs.length - 1].push(cur); cur = ""; }
758
+ if (segs[segs.length - 1].length) segs.push([]);
759
+ if ((ch === "|" || ch === "&") && command[i + 1] === ch) i++;
760
+ continue;
761
+ }
762
+ if (/\s/.test(ch)) { if (cur) { segs[segs.length - 1].push(cur); cur = ""; } continue; }
763
+ cur += ch;
764
+ }
765
+ if (cur) segs[segs.length - 1].push(cur);
766
+
748
767
  const bases = [];
749
- for (const seg of command.split(/\|\||&&|[|;\n]/)) {
750
- const words = seg.trim().split(/\s+/).filter(Boolean);
768
+ for (const words of segs) {
751
769
  let base = null;
752
770
  for (const w of words) {
753
- const bare = w.replace(/^["']+|["']+$/g, "");
754
- if (!bare) continue;
755
- if (PREFIX_WORDS.has(bare)) continue;
756
- if (/^[\d.]+[smhd]?$/.test(bare)) continue;
757
- if (bare.includes("=") && !bare.startsWith("-")) continue;
758
- if (bare.startsWith("-")) continue;
759
- base = bare;
771
+ if (!w) continue;
772
+ if (PREFIX_WORDS.has(w)) continue;
773
+ if (/^[\d.]+[smhd]?$/.test(w)) continue;
774
+ if (w.includes("=") && !w.startsWith("-")) continue;
775
+ if (w.startsWith("-")) continue;
776
+ base = w;
760
777
  break;
761
778
  }
762
779
  if (base) bases.push(base);
@@ -768,6 +785,23 @@ function segmentBases(command) {
768
785
  // on itself: builtins, keywords, functions, and PATH binaries all answer
769
786
  // through the exact resolution the shell will use at launch. A model of the
770
787
  // shell can drift from the shell; the shell cannot drift from itself.
788
+ // On Windows, bare "bash" is a trap: PATH can resolve to WSL's
789
+ // System32\bash.exe — a different operating system with a different
790
+ // filesystem. The command will actually run in Git Bash, so the probe
791
+ // must ask Git Bash, located explicitly. If it cannot be located,
792
+ // abstain — never let the wrong interpreter answer for the right one.
793
+ function bashPath() {
794
+ if (platform() !== "win32") return "bash";
795
+ const candidates = [
796
+ process.env.CLAUDE_CODE_GIT_BASH_PATH,
797
+ "C:/Program Files/Git/bin/bash.exe",
798
+ "C:/Program Files/Git/usr/bin/bash.exe",
799
+ "C:/Program Files (x86)/Git/bin/bash.exe",
800
+ ].filter(Boolean);
801
+ for (const c of candidates) { try { if (existsSync(c)) return c; } catch {} }
802
+ return null;
803
+ }
804
+
771
805
  function shellKnows(name, cwd, shell) {
772
806
  try {
773
807
  if (shell === "powershell") {
@@ -776,7 +810,9 @@ function shellKnows(name, cwd, shell) {
776
810
  { cwd, timeout: 4000, stdio: "ignore", env: { ...process.env, CHECK_PROBE: name } });
777
811
  return r.error ? null : r.status === 0;
778
812
  }
779
- const r = spawnSync("bash", ["-c", 'type -- "$1" >/dev/null 2>&1', "check", name],
813
+ const bash = bashPath();
814
+ if (!bash) return null;
815
+ const r = spawnSync(bash, ["-c", 'type -- "$1" >/dev/null 2>&1', "check", name],
780
816
  { cwd, timeout: 4000, stdio: "ignore" });
781
817
  return r.error ? null : r.status === 0;
782
818
  } catch { return null; }