@whobot/cli 2.0.3 → 2.0.4

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/bin/install.mjs +36 -4
  2. package/package.json +1 -1
package/bin/install.mjs CHANGED
@@ -226,7 +226,38 @@ export async function runPostinstall(env) {
226
226
  }
227
227
  }
228
228
 
229
- export function whichCommand(name, env, ignoreRealpath = "") {
229
+ // npxLauncherIgnore names the command entries of the npx copy at root, which
230
+ // npx puts first on PATH. POSIX npm links them to run.mjs; Windows npm writes
231
+ // cmd-shim files into the same node_modules/.bin, so a realpath alone cannot
232
+ // recognize them. Outside an npx copy nothing is ignored.
233
+ export function npxLauncherIgnore(root) {
234
+ if (!isNpxPath(root)) {
235
+ return {};
236
+ }
237
+ const ignore = { realpath: realpathSync(path.join(root, "bin", "run.mjs")) };
238
+ let modules = root;
239
+ while (path.basename(modules) !== "node_modules") {
240
+ const parent = path.dirname(modules);
241
+ if (parent === modules) {
242
+ return ignore;
243
+ }
244
+ modules = parent;
245
+ }
246
+ const binDir = path.join(modules, ".bin");
247
+ try {
248
+ ignore.binDir = realpathSync(binDir);
249
+ } catch {
250
+ // No .bin directory: no PATH entry can be inside it.
251
+ ignore.binDir = binDir;
252
+ }
253
+ return ignore;
254
+ }
255
+
256
+ function samePath(a, b) {
257
+ return process.platform === "win32" ? a.toLowerCase() === b.toLowerCase() : a === b;
258
+ }
259
+
260
+ export function whichCommand(name, env, ignore = {}) {
230
261
  const pathEnv = env.PATH || env.Path || "";
231
262
  const exts = process.platform === "win32" ? [".cmd", ".exe", ".bat", ""] : [""];
232
263
  for (const dir of pathEnv.split(path.delimiter)) {
@@ -237,7 +268,8 @@ export function whichCommand(name, env, ignoreRealpath = "") {
237
268
  const candidate = path.join(dir, name + ext);
238
269
  try {
239
270
  accessSync(candidate, constants.X_OK);
240
- if (ignoreRealpath && realpathSync(candidate) === ignoreRealpath) continue;
271
+ if (ignore.realpath && realpathSync(candidate) === ignore.realpath) continue;
272
+ if (ignore.binDir && samePath(realpathSync(dir), ignore.binDir)) continue;
241
273
  return candidate;
242
274
  } catch {
243
275
  // try next
@@ -625,7 +657,7 @@ async function repairAndVerifyNative(native, version, env) {
625
657
  }
626
658
  }
627
659
 
628
- export async function verifyInstalledCLI(tools, npmEnv, prefix, version, env, ignoreLauncher = "") {
660
+ export async function verifyInstalledCLI(tools, npmEnv, prefix, version, env, ignoreLauncher = {}) {
629
661
  const registered = readGlobalPackageVersion(tools, npmEnv);
630
662
  if (registered !== version) {
631
663
  throw new InstallerError(`npm registered version ${registered} does not match ${version}`, "UPDATE_VERIFY_FAILED");
@@ -696,7 +728,7 @@ export async function runExplicitInstall(argv, env) {
696
728
  npmInstallGlobalFrom(tools, pkgRoot, npmEnv);
697
729
  }
698
730
  // Ignore this npx cache launcher only, not other stale host PATH entries.
699
- const ignoreLauncher = isNpxPath(pkgRoot) ? realpathSync(path.join(pkgRoot, "bin", "run.mjs")) : "";
731
+ const ignoreLauncher = npxLauncherIgnore(pkgRoot);
700
732
  const installed = await verifyInstalledCLI(tools, npmEnv, prefix, pkg.version, env, ignoreLauncher);
701
733
  runInstallPhase(installed.native, updateArgs, env, "verify", registered);
702
734
  await prepared.discard();
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@whobot/cli",
3
- "version": "2.0.3",
3
+ "version": "2.0.4",
4
4
  "description": "Whobot CLI: npm-managed JS launcher that runs the in-package Go binary.",
5
5
  "type": "module",
6
6
  "bin": {