mirror of
https://github.com/rowboatlabs/rowboat.git
synced 2026-06-30 20:39:46 +02:00
fix(code-mode): resolve claude/codex installed via version managers
commonInstallPaths only checked ~/.nvm/versions/node/<binary>, never descending into nvm's versioned vX.Y.Z/bin subdirs, so an nvm-installed codex/claude showed "not installed" in Settings and failed code-mode chat with "CLI not found" on GUI launches (where the login-shell PATH isn't inherited). Enumerate each installed Node version's bin dir for nvm/fnm/asdf, and add pnpm global (PNPM_HOME / platform default) and Claude Code's legacy ~/.claude/local install location. Shared by both the Settings status check and the chat/tab binary resolvers, so it covers all code-mode entry points. Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
This commit is contained in:
parent
5332ebcb06
commit
0d50373576
1 changed files with 42 additions and 4 deletions
|
|
@ -3,7 +3,7 @@ import { promisify } from 'util';
|
|||
import os from 'os';
|
||||
import path from 'path';
|
||||
import fs from 'fs/promises';
|
||||
import { existsSync } from 'fs';
|
||||
import { existsSync, readdirSync } from 'fs';
|
||||
import { CodeModeAgentStatus } from './types.js';
|
||||
|
||||
const execAsync = promisify(exec);
|
||||
|
|
@ -28,16 +28,54 @@ export function commonInstallPaths(binary: string): string[] {
|
|||
path.join(home, '.volta', 'bin', `${binary}.cmd`),
|
||||
];
|
||||
}
|
||||
return [
|
||||
const dirs = [
|
||||
'/usr/local/bin',
|
||||
'/opt/homebrew/bin', // Apple Silicon Homebrew
|
||||
'/usr/bin',
|
||||
path.join(home, '.npm-global', 'bin'),
|
||||
path.join(home, '.local', 'bin'),
|
||||
path.join(home, '.volta', 'bin'),
|
||||
path.join(home, '.nvm', 'versions', 'node'), // partial; nvm has versioned subdirs
|
||||
path.join(home, 'bin'),
|
||||
].map(dir => path.join(dir, binary));
|
||||
// Claude Code's legacy local installer / `claude migrate-installer` target.
|
||||
path.join(home, '.claude', 'local'),
|
||||
// pnpm global bin: PNPM_HOME if set, else the platform default
|
||||
// (~/Library/pnpm on macOS, ~/.local/share/pnpm on Linux).
|
||||
process.env.PNPM_HOME ||
|
||||
(process.platform === 'darwin'
|
||||
? path.join(home, 'Library', 'pnpm')
|
||||
: path.join(home, '.local', 'share', 'pnpm')),
|
||||
// Node version managers install into versioned subdirs (e.g.
|
||||
// ~/.nvm/versions/node/v24.16.0/bin) — enumerate each version's bin dir.
|
||||
...versionManagerBinDirs(home),
|
||||
];
|
||||
return dirs.map(dir => path.join(dir, binary));
|
||||
}
|
||||
|
||||
// nvm/fnm/asdf keep a `bin` dir per installed Node version. A static path can't
|
||||
// match (the version segment is unknown), so list the version dirs and append
|
||||
// `bin`. Returns [] when a manager isn't present — readdir failures are ignored.
|
||||
function versionManagerBinDirs(home: string): string[] {
|
||||
const versionRoots = [
|
||||
path.join(home, '.nvm', 'versions', 'node'), // nvm
|
||||
path.join(home, '.local', 'share', 'fnm', 'node-versions'), // fnm (Linux)
|
||||
path.join(home, 'Library', 'Application Support', 'fnm', 'node-versions'),// fnm (macOS)
|
||||
path.join(home, '.asdf', 'installs', 'nodejs'), // asdf
|
||||
];
|
||||
const dirs: string[] = [];
|
||||
for (const root of versionRoots) {
|
||||
let versions: string[];
|
||||
try {
|
||||
versions = readdirSync(root);
|
||||
} catch {
|
||||
continue; // manager not installed
|
||||
}
|
||||
for (const version of versions) {
|
||||
// fnm nests another `installation` dir; nvm/asdf put bin directly under the version.
|
||||
dirs.push(path.join(root, version, 'bin'));
|
||||
dirs.push(path.join(root, version, 'installation', 'bin'));
|
||||
}
|
||||
}
|
||||
return dirs;
|
||||
}
|
||||
|
||||
async function probeShell(binary: string): Promise<boolean> {
|
||||
|
|
|
|||
Loading…
Add table
Add a link
Reference in a new issue