Skip to content

fix: handle root-owned Claude binaries on Linux#28

Closed
othavioquiliao wants to merge 4 commits into
cpaczek:mainfrom
othavioquiliao:fix/resolve-shell-wrapper-binary
Closed

fix: handle root-owned Claude binaries on Linux#28
othavioquiliao wants to merge 4 commits into
cpaczek:mainfrom
othavioquiliao:fix/resolve-shell-wrapper-binary

Conversation

@othavioquiliao
Copy link
Copy Markdown

@othavioquiliao othavioquiliao commented Apr 3, 2026

Context

If you install Claude Code as a system package (like on Arch with omarchy), /usr/bin/claude is actually a tiny shell wrapper that does exec /opt/claude-code/bin/claude. The binary finder didn't know how to follow that, so it'd see a 77-byte file and bail.

On top of that, the real binary is root-owned, so patching needs sudo. And when you re-run with sudo, the environment gets wiped — bun disappears from PATH (mine is managed by mise, but same thing happens with asdf, volta, etc.), and $HOME points to /root so none of the config files are found.

What this does

Shell wrappers: Added resolveShellWrapper() that reads the script, finds the exec target, and follows it to the actual binary. Also added /opt/claude-code/bin/claude to the candidate list.

Sudo re-exec: If the binary dir isn't writable, we now re-run under sudo automatically (early, before the TUI starts — otherwise it freezes). The trick is resolving bun, the claude binary, and HOME before escalating, while PATH is still intact, then passing them through as env vars with execFileSync('sudo', ['env', ...]). No shell interpolation, no injection issues.

The sudo escalation logic lives in its own helper (src/patcher/sudo.ts) instead of being copy-pasted between commands.

Why not just sudo --preserve-env=PATH? Tried that first, but secure_path in sudoers silently overrides it on most distros. Resolving to absolute paths before sudo and forwarding them is more reliable.

Testing

  • 7 new tests for resolveShellWrapper, all 210 passing
  • Build/lint/typecheck clean
  • Tested manually on Arch with root-owned /opt/claude-code/bin/claude + bun via mise

O binary-finder não resolvia shell wrappers Unix (ex: /usr/bin/claude
com `exec /opt/claude-code/bin/claude`). Adiciona resolveShellWrapper()
para parsear `exec` em scripts com shebang, e /opt/claude-code/bin/claude
como fallback para instalações via pacote do sistema.
…o patch

Três correções para instalações via pacote do sistema (ex: omarchy):

1. Preflight detecta falta de write permission no diretório do binário
   e re-executa via sudo automaticamente antes do TUI iniciar.
2. patchBinary() verifica write permission com erro claro (safety net).
3. confirm_patch handler no apply TUI agora captura erros em vez de
   congelar silenciosamente.
4. isClaudeRunning() usa pgrep -x (match exato) em vez de -f para
   eliminar falsos positivos.
sudo sanitiza o ambiente, fazendo homedir() retornar /root e bun não
ser encontrado em ~/.bun/bin/. Preserva HOME com --preserve-env=HOME
e adiciona fallback no findBunBinary() usando SUDO_USER para localizar
bun no home do usuário original.
@othavioquiliao othavioquiliao changed the title fix: resolve Unix shell script wrappers in binary finder fix: handle root-owned Claude binaries on Linux Apr 3, 2026
…ção sudo

Extrai lógica duplicada de sudo re-exec para helper compartilhado,
troca execSync com template literal por execFileSync com array de args
(elimina shell injection), e propaga bunPath no PreflightResult para
evitar chamada redundante a findBunBinary().
@cpaczek
Copy link
Copy Markdown
Owner

cpaczek commented Apr 3, 2026

Haven't fully reviewed but thank you for pr @othavioquiliao can you look into windows CI test failing we prob need to flag this so sudo stuff is only on Linux or Mac

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

2 participants