nearly-cli 0.1.2 → 0.1.3

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/scripts/attach.mjs +24 -8
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "nearly-cli",
3
- "version": "0.1.2",
3
+ "version": "0.1.3",
4
4
  "description": "A pull request tells you what changed. Nearly tells you what nearly happened: the commands a human refused, the pushes policy blocked, the turns rolled back.",
5
5
  "type": "module",
6
6
  "bin": {
@@ -16,7 +16,7 @@
16
16
  // it, and if it cannot start, Claude Code falls back to its own prompts and
17
17
  // nothing breaks.
18
18
 
19
- import { readFileSync, writeFileSync, mkdirSync, existsSync } from 'node:fs';
19
+ import { readFileSync, writeFileSync, mkdirSync, existsSync, realpathSync } from 'node:fs';
20
20
  import { join, resolve, dirname, basename } from 'node:path';
21
21
  import { fileURLToPath } from 'node:url';
22
22
  import { execFileSync, spawnSync } from 'node:child_process';
@@ -40,15 +40,31 @@ function pkgVersion() {
40
40
  catch { return 'latest'; }
41
41
  }
42
42
 
43
- // Only trust a `nearly` on PATH if it really is this tool.
43
+ // Only trust a `nearly` on PATH if it really is this tool and it will still be
44
+ // there tomorrow.
45
+ //
46
+ // npx puts its own temporary bin first on PATH for the life of the process, so
47
+ // during `npx nearly-cli` a naive lookup finds a `nearly` that ceases to exist
48
+ // the moment npx exits. Believing it meant writing hooks that call a command
49
+ // nobody has, which fail on every tool call, which means no gate at all.
44
50
  function onPath() {
51
+ const args = process.platform === 'win32' ? ['nearly'] : ['-a', 'nearly'];
52
+ let found = [];
45
53
  try {
46
- const p = execFileSync(process.platform === 'win32' ? 'where' : 'which', ['nearly'],
47
- { encoding: 'utf8', stdio: ['ignore', 'pipe', 'ignore'] }).trim().split('\n')[0];
48
- if (!p) return null;
49
- const out = execFileSync(p, ['--which'], { encoding: 'utf8', stdio: ['ignore', 'pipe', 'ignore'] }).trim();
50
- return out ? p : null;
54
+ found = execFileSync(process.platform === 'win32' ? 'where' : 'which', args,
55
+ { encoding: 'utf8', stdio: ['ignore', 'pipe', 'ignore'] }).trim().split('\n').filter(Boolean);
51
56
  } catch { return null; }
57
+
58
+ for (const p of found) {
59
+ let resolved = p;
60
+ try { resolved = realpathSync(p); } catch { /* keep the literal path */ }
61
+ if (/[\\/]_npx[\\/]/.test(p) || /[\\/]_npx[\\/]/.test(resolved)) continue; // vanishes when npx exits
62
+ try {
63
+ const out = execFileSync(p, ['--which'], { encoding: 'utf8', stdio: ['ignore', 'pipe', 'ignore'] }).trim();
64
+ if (out) return p;
65
+ } catch { /* not our command; try the next one */ }
66
+ }
67
+ return null;
52
68
  }
53
69
 
54
70
  const fromPackage = /[\\/]node_modules[\\/]/.test(root) || /[\\/]_npx[\\/]/.test(root);
@@ -72,7 +88,7 @@ function installGlobally() {
72
88
  }
73
89
  let installed = onPath();
74
90
  const hookCmd = (ev) => installed
75
- ? `nearly hook ${ev}`
91
+ ? `nearly hook ${ev}` // verified above to survive this process
76
92
  : fromPackage
77
93
  ? `npx -y nearly-cli@${pkgVersion()} hook ${ev}`
78
94
  : `node ${JSON.stringify(HOOK)} ${ev}`;