(input: DetectInput)
| 93 | } |
| 94 | |
| 95 | export function detectInstallMethod(input: DetectInput): InstallMethod { |
| 96 | const exists = input.exists ?? fs.existsSync; |
| 97 | const isWin = input.platform === 'win32'; |
| 98 | // Path math keyed on the TARGET platform so detection is host-independent |
| 99 | // (a Windows layout resolves correctly even when unit-tested on macOS/Linux). |
| 100 | const P = isWin ? path.win32 : path.posix; |
| 101 | const binDir = P.dirname(input.filename); // <…>/bin |
| 102 | |
| 103 | const norm = toPosix(input.filename); |
| 104 | |
| 105 | // Path-based checks come FIRST. The npm thin-installer's per-platform |
| 106 | // package (@colbymchenry/codegraph-<platform>-<arch>) is itself a complete |
| 107 | // bundle — vendored node + bin/ launcher — living inside node_modules, so |
| 108 | // the layout sniff below would misread every npm install as a standalone |
| 109 | // bundle. `upgrade` would then curl install.sh into ~/.codegraph: a SECOND |
| 110 | // install that never wins the PATH race against npm's shim, leaving |
| 111 | // `codegraph -v` permanently on the old version (the #1071 shadow, |
| 112 | // self-inflicted). A path under node_modules is authoritative about HOW the |
| 113 | // user installed, whatever the artifact inside looks like. |
| 114 | |
| 115 | // npx cache: <…>/_npx/<hash>/node_modules/@colbymchenry/codegraph/… |
| 116 | // (checked before npm — the npx cache path also contains /node_modules/). |
| 117 | if (norm.includes('/_npx/')) { |
| 118 | return { kind: 'npx' }; |
| 119 | } |
| 120 | |
| 121 | // npm install (global or local): lives under a node_modules tree. |
| 122 | if (norm.includes('/node_modules/')) { |
| 123 | const underCwd = norm.startsWith(toPosix(P.resolve(input.cwd)) + '/'); |
| 124 | return { kind: 'npm', scope: underCwd ? 'local' : 'global' }; |
| 125 | } |
| 126 | |
| 127 | // Bundle: <root>/lib/dist/bin/codegraph.js → <root> is up 3 from bin/. |
| 128 | // A bundle has a vendored node + a launcher script as siblings of lib/. |
| 129 | const bundleRoot = P.resolve(binDir, '..', '..', '..'); |
| 130 | const vendoredNode = P.join(bundleRoot, isWin ? 'node.exe' : 'node'); |
| 131 | const launcher = P.join(bundleRoot, 'bin', isWin ? 'codegraph.cmd' : 'codegraph'); |
| 132 | if (exists(vendoredNode) && exists(launcher)) { |
| 133 | const os = isWin ? 'windows' : 'unix'; |
| 134 | return { kind: 'bundle', os, bundleRoot, installDir: deriveInstallDir(bundleRoot, os, exists) }; |
| 135 | } |
| 136 | |
| 137 | // Source checkout: running <repo>/dist/bin/codegraph.js with a sibling .git. |
| 138 | const repoRoot = P.resolve(binDir, '..', '..'); |
| 139 | if (exists(P.join(repoRoot, 'package.json')) && exists(P.join(repoRoot, '.git'))) { |
| 140 | return { kind: 'source', root: repoRoot }; |
| 141 | } |
| 142 | |
| 143 | return { kind: 'unknown', reason: `unrecognized install layout at ${input.filename}` }; |
| 144 | } |
| 145 | |
| 146 | // --------------------------------------------------------------------------- |
| 147 | // Version helpers (pure) |
no test coverage detected