Skip to content

isCliInstalled fails to detect CLIs in ~/.local/bin (VPS/headless environments) #586

@realproject7

Description

@realproject7

Context

On a Hetzner VPS, Claude Code is installed at /root/.local/bin/claude and works from an interactive SSH shell, but QuadWork's setup wizard shows "Claude Code (not installed)". The user had to manually ln -s /root/.local/bin/claude /usr/local/bin/claude to work around it.

Root cause

isCliInstalled() in server/index.js:48-55 uses execFileSync("which", [cmd]) to detect CLIs. Claude Code's installer adds the binary to ~/.local/bin/ and appends a PATH entry to ~/.bashrc/~/.profile. But Node's execFileSync doesn't source shell profile files — it only sees the PATH inherited at process start. In headless/VPS environments where the server is started via npx, ~/.local/bin is often missing from the inherited PATH.

// Current — fails when CLI is in ~/.local/bin
function isCliInstalled(cmd) {
  try {
    execFileSync("which", [cmd], { encoding: "utf-8", stdio: "pipe" });
    return true;
  } catch {
    return false;
  }
}

Fix

Add fallback path checks when which fails. Check common install locations:

const os = require("os");

function isCliInstalled(cmd) {
  try {
    execFileSync("which", [cmd], { encoding: "utf-8", stdio: "pipe" });
    return true;
  } catch {
    // Fallback: check common install locations that may not be in PATH
    const fallbacks = [
      path.join(os.homedir(), ".local", "bin", cmd),
      path.join(os.homedir(), ".npm-global", "bin", cmd),
      `/usr/local/bin/${cmd}`,
    ];
    return fallbacks.some((p) => fs.existsSync(p));
  }
}

Acceptance criteria

  • isCliInstalled("claude") returns true when claude is at ~/.local/bin/claude even if not in PATH
  • isCliInstalled("codex") same fallback behavior
  • No change when CLIs are already in PATH (which succeeds, fallback never runs)
  • npm run build passes

Environment

  • Hetzner VPS, Debian/Ubuntu, root user
  • Claude Code installed via official installer → ~/.local/bin/claude
  • Node 24.x, started via npx quadwork start

Metadata

Metadata

Assignees

No one assigned

    Labels

    agent/devAssigned to Dev agentbugSomething isn't working

    Projects

    No projects

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions