Skip to content

fix(desktop): make doctor installs retryable with per-runtime progress and auth status#1765

Merged
wpfleger96 merged 1 commit into
mainfrom
wpfleger96/doctor-install-reliability
Jul 12, 2026
Merged

fix(desktop): make doctor installs retryable with per-runtime progress and auth status#1765
wpfleger96 merged 1 commit into
mainfrom
wpfleger96/doctor-install-reliability

Conversation

@wpfleger96

@wpfleger96 wpfleger96 commented Jul 12, 2026

Copy link
Copy Markdown
Collaborator

Stack: this PR → #1767

Fixes the Doctor (harness install) failures hit on a fresh Mac with no dev tools (OSS desktop build):

  • Installs are retryable without restarting the app. The login-shell PATH was cached in a OnceLock for the app's lifetime, so installing Node.js after a failed install could never help until relaunch. The cache is now a refreshable three-state LoginShellPath enum — every install/retry and Doctor Re-run re-fetches it (refresh_login_shell_path()), the login shell spawns outside the cache lock so a concurrent agent spawn never blocks on it, and failed install rows show a Retry button with the error kept visible until retried.
  • nvm-managed Node.js is found, with alias content validated. nvm initializes in ~/.zshrc (interactive shells only), so login shells never see it and codex-acp-style #!/usr/bin/env node shims failed at launch with env: node: No such file or directory. Command resolution, CLI probes, and the agent-spawn PATH now include nvm's default version bin dir (find_nvm_default_bin: reads alias/default with one alias hop, falling back to the highest installed version under ~/.nvm/versions/node/). Alias tags are validated before any path join (is_safe_nvm_tag rejects absolute paths, .. traversal, and non-nvm characters) — PathBuf::join replaces its base when handed an absolute path, so an unvalidated ~/.nvm/alias/default could otherwise steer the agent-spawn PATH to arbitrary binaries.
  • Missing Node.js is surfaced up front. When an adapter needs npm install -g but neither node nor npm resolves, the runtime row hides the Install button and shows a "Node.js is required" callout linking to nodejs.org (a shared NodeRequiredOrInstall component backs both the adapter_missing and not_installed states), instead of failing mid-install with zsh:1: command not found: npm.
  • Concurrent installs each keep their own spinner. Install progress was derived from the shared mutation's last variables, so starting a second install stopped the first's spinner (backend installs already ran concurrently). Progress is now tracked per runtime id.
  • Doctor shows CLI auth status. Available claude/codex runtimes are probed (claude auth status / codex login status, declared per runtime via auth_probe_args on KnownAcpRuntime) and render "Authenticated", "Not authenticated" with a login hint, or "Config error: ". Probes run in parallel with a 10-second process-level timeout that kills the probe child on expiry, so a hung CLI cannot accumulate orphaned processes across Re-runs. Every discovery probes fresh — there is no result cache. Runtimes without a login step (goose, buzz-agent) show nothing.

The Doctor states (auth badges, node-required callout, retry flow) are covered by a Playwright screenshot spec (doctor-states.spec.ts) driving them through configurable bridge mocks, including a fail-then-succeed install sequence that exercises Retry end to end.

@wpfleger96 wpfleger96 requested a review from a team as a code owner July 12, 2026 04:59
wpfleger96 added a commit that referenced this pull request Jul 12, 2026
wpfleger96 added a commit that referenced this pull request Jul 12, 2026
@wpfleger96

Copy link
Copy Markdown
Collaborator Author

🤖 Updated Doctor state screenshots from the current branch:

Authenticated

01-auth-logged-in

Not authenticated, with login hint

02-auth-logged-out

Config error diagnostic

03-auth-config-error

Node.js required callout

04-node-required

Failed install with Retry

05-retry-after-failure

Retry succeeds

Clicking Retry re-runs the install; the error clears and the success banner renders.
05-retry-success

…s and auth status

Fresh-install failures on stock Macs had four root causes: the login-shell
PATH was cached for the app's entire lifetime via OnceLock (installing
Node.js mid-session had no effect until restart); nvm-managed node/npm was
invisible to the command resolver and agent spawn PATH because nvm only
initializes in interactive shells; a single shared React mutation overwrote
the in-flight indicator when two runtimes installed concurrently; and the
Doctor panel never verified that CLI-based agents (claude, codex) were
actually authenticated.

Review-round hardening: probe_auth_status's inner-thread timeout leaked a
blocked thread and a live CLI child on expiry — replaced with a
process-level timeout (spawn → drain threads → kill-on-expiry) mirroring
run_install_command. The login-shell cache now uses double-checked locking
with a named LoginShellPath enum so the shell spawn happens outside the
lock. nvm alias tags are validated (is_safe_nvm_tag) before path joins so
an attacker-writable alias file cannot steer agent spawn to arbitrary
binaries; both the default tag and one-hop alias are checked.
auth_probe_args moved onto KnownAcpRuntime (removing the probe_args_for
side registry), and the never-hitting 60s auth-probe TTL cache was removed.

A five-state Doctor screenshots spec (logged-in/logged-out/config-error
badges, node-required callout, install-failure Retry) doubles as a
regression guard for the new UI logic.

Rebased over #1750 (codex-acp 1.x swap): its adapter_outdated Doctor branch
now passes the required hasError prop, its make_codex_runtime test helper
gained the auth_probe_args/login_hint fields, and the AdapterOutdated
version-gate is composed into the two-phase discover_acp_runtimes.
@wpfleger96 wpfleger96 force-pushed the wpfleger96/doctor-install-reliability branch from d16bf95 to ea82454 Compare July 12, 2026 21:29
@wpfleger96 wpfleger96 merged commit 25bb714 into main Jul 12, 2026
25 checks passed
@wpfleger96 wpfleger96 deleted the wpfleger96/doctor-install-reliability branch July 12, 2026 21:42
wpfleger96 pushed a commit that referenced this pull request Jul 12, 2026
* origin/main:
  fix(desktop): correct provider and model handling in agent config dialogs (#1764)
  fix(desktop): cascade persona deletes and restart agents on global config save (#1766)
  fix(desktop): make doctor installs retryable with per-runtime progress and auth status (#1765)
  fix(codex): swap to @agentclientprotocol/codex-acp 1.x + detect outdated adapter (#1750)
  Fix oversized mobile Manage channel sheet (#1774)
  fix(desktop): show thread replies loader (#1773)
  fix(build): allow vendored opus to configure under CMake 4 (#1763)
  fix(desktop): restore multi-image mosaic galleries (#1769)
  Group channel membership events (#1713)
  Fix desktop launch motion and reaction spacing (#1717)
  fix(desktop): align sidebar search across themes (#1712)
  fix(desktop): Buzz theme flicker, white bar & accent-picker motion (#1681)
  fix(mobile): highlight full multi-word mentions (#1762)
  [BOT-1264] fix(mobile): #channel tags not tappable (#1695)
  feat(desktop): surface Team Instructions as distinct observer section (#1759)

# Conflicts:
#	desktop/playwright.config.ts
wpfleger96 pushed a commit that referenced this pull request Jul 12, 2026
* origin/main:
  fix(desktop): correct provider and model handling in agent config dialogs (#1764)
  fix(desktop): cascade persona deletes and restart agents on global config save (#1766)
  fix(desktop): make doctor installs retryable with per-runtime progress and auth status (#1765)
  fix(codex): swap to @agentclientprotocol/codex-acp 1.x + detect outdated adapter (#1750)
  Fix oversized mobile Manage channel sheet (#1774)
  fix(desktop): show thread replies loader (#1773)
  fix(build): allow vendored opus to configure under CMake 4 (#1763)
  fix(desktop): restore multi-image mosaic galleries (#1769)
  Group channel membership events (#1713)
  Fix desktop launch motion and reaction spacing (#1717)
  fix(desktop): align sidebar search across themes (#1712)
  fix(desktop): Buzz theme flicker, white bar & accent-picker motion (#1681)
  fix(mobile): highlight full multi-word mentions (#1762)
  [BOT-1264] fix(mobile): #channel tags not tappable (#1695)
  feat(desktop): surface Team Instructions as distinct observer section (#1759)

Co-authored-by: Will Pfleger <pfleger.will@gmail.com>
Signed-off-by: Will Pfleger <pfleger.will@gmail.com>

# Conflicts:
#	desktop/playwright.config.ts
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.

1 participant