Skip to content

fix(cli): resolve optional-extra install commands and preserve extras on upgrade - #442

Merged
Jason Robert (jrob5756) merged 1 commit into
mainfrom
fix/441-fleet-tui-install-hint
Aug 14, 2026
Merged

fix(cli): resolve optional-extra install commands and preserve extras on upgrade#442
Jason Robert (jrob5756) merged 1 commit into
mainfrom
fix/441-fleet-tui-install-hint

Conversation

@jrob5756

Copy link
Copy Markdown
Collaborator

Closes#441

The problem

Every hint pointing at an optional extra hardcoded pip install 'conductor-cli[<extra>]'. That cannot work on the documented install path: install.sh / install.ps1 run uv tool install, and a uv tool venv is not pip-managed — plus conductor-cli is not published to PyPI, so pip has nothing to resolve against there.

Two related defects, both included here at Jason Robert (@jrob5756)'s request:

  1. aca had the same dead string (and so did claude-agent-sdk) — these were reachable as ProviderError.suggestion, not just docstrings.
  2. conductor update silently uninstalled your extras.uv tool install --force replaces the tool's entire requirement set, and the install scripts passed a bare git source, so upgrading dropped [tui] / [aca] without saying anything.

What this does

New conductor.install_hint — a stdlib-only leaf module (top-level, because providers/ needs it and must not import from cli/). Resolves the command from the detected install context:

SignalCommand
<prefix>/uv-receipt.tomluv tool install --force '<spec>'
direct_url.json with dir_info.editableuv sync --inexact --extra <extra>
neither<sys.executable> -m pip install '<spec>'

Four properties are load-bearing:

  • Extras already installed are carried forward.--force rewrites the requirement set and uv sync is exact unless given --inexact, so a command naming only the requested extra uninstalls the others.
  • The recorded install source is reused (the receipt's git/directory/url, else direct_url.json), so the hint never redirects a fork or a local build at upstream's released tag.
  • The pip fallback names this interpreter. A bare pip does not manage a pipx venv — there it succeeds, installing a second copy the user never runs while conductor fleet keeps printing the same error.
  • An unreadable receipt is not a bare install. Both look like "no extras", but rendering the first as the second produces a confident command that deletes the user's TUI.

Both install scripts read the same receipt and rebuild the source as conductor-cli[<extras>] @ <source>, so conductor update preserves extras. New --extras <a,b> / --no-preserve-extras (plus CONDUCTOR_INSTALL_EXTRAS / CONDUCTOR_INSTALL_NO_PRESERVE_EXTRAS).

Bugs found and fixed during review

  • --no-preserve-extras was a silent no-op on an up-to-date install — the gate compared against a variable the flag itself zeroed, so the shortcut fired and reported success.
  • PowerShell handed uv three arguments instead of oneStart-Process -ArgumentList joins elements with spaces and does not quote them, so conductor-cli[tui] @ <src> split apart and the extras were dropped. Verified broken, and fixed, against real pwsh.
  • uv exits 0 with only a warning for an unknown extra — a typo installed nothing under two green checkmarks. Extras are now validated up front and the warning is surfaced on the success path.
  • installed_extras() could raise despite documenting "never raises" — from inside a ProviderError(...) argument, which deleted the diagnosis rather than degrading the hint.
  • Plus: uv sync --extra being exact by default, PEP 503 name normalization, whole-field name = matching (so conductor-cli-plugin is not folded in), and case normalization so the two installers agree.

Verification

  • make check clean; 7150 passed / 62 skipped.
  • Every fix has a test that fails when reverted — mutation-checked the argv routing, the receipt readability guard, the artifact guard, the wrapped-receipt flatten, the --apply ordering, and the up-to-date gate.
  • Three real sandboxed uv tool install runs confirm preserve / add / drop end-to-end.
  • install.sh helpers are executed for real; install.ps1 helpers are extracted with PowerShell's own AST parser and executed under pwsh, with a parity class feeding both the same receipt, and a shared oracle asserting the shell and Python parsers agree.

Known gaps

  • Format-ProcessArgument does not escape a trailing backslash in a path — unreachable today, since the only such argument is Join-Path $tmpDir 'constraints.txt'.
  • No install_scripts-marked Windows test drives install.ps1 with extras end-to-end; AST-level helper tests and a static call-site check cover it short of a real Windows install.

@jrob5756
Jason Robert (jrob5756) marked this pull request as ready for review August 14, 2026 20:00
@jrob5756
Jason Robert (jrob5756)force-pushed the fix/441-fleet-tui-install-hint branch from d7b35e3 to 4af4171CompareAugust 14, 2026 20:08
… on upgrade
Every hint pointing at an optional extra hardcoded
`pip install 'conductor-cli[<extra>]'`, which cannot work on the documented
install path: install.sh/install.ps1 create a uv tool venv, which is not
pip-managed, and conductor-cli is not published to PyPI so pip has nothing
to resolve against there.
Add `conductor.install_hint`, a stdlib-only leaf module that resolves the
command from the detected install context -- a uv receipt, an editable
`direct_url.json`, or neither. `conductor fleet` without the `tui` extra and
the `aca` / `claude-agent-sdk` provider errors all go through it. The
rendered command reuses the install source recorded for this install (so a
fork or a local build is not redirected upstream), unions the extras already
recorded (`uv tool install --force` replaces the whole requirement set, and
`uv sync` is exact unless given `--inexact`), and names this interpreter for
the pip fallback, which otherwise succeeds against a pipx venv while
installing a second copy the user never runs.
Both install scripts now read that same receipt and rebuild the source as
`conductor-cli[<extras>] @ <source>`, so `conductor update` no longer
silently uninstalls [tui]/[aca]. Adds `--extras` / `--no-preserve-extras`
(plus env-var forms), rejects an extra the package does not declare (uv
treats an unknown one as a warning and still exits 0), and quotes the spec
into `Start-Process -ArgumentList`, which does not quote its elements and so
handed uv three arguments instead of one.
A receipt that exists but cannot be read is reported rather than treated as
"no extras" in all three readers: the hint appends an inline warning, and
the scripts warn and continue rather than either dropping the extras
silently or refusing to run the reinstall that repairs that state.
Closes#441
Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
@jrob5756
Jason Robert (jrob5756)force-pushed the fix/441-fleet-tui-install-hint branch from 4af4171 to 7d7d2b5CompareAugust 14, 2026 20:19
@jrob5756
Jason Robert (jrob5756) merged commit 967e5f7 into mainAug 14, 2026
11 checks passed
@jrob5756
Jason Robert (jrob5756) deleted the fix/441-fleet-tui-install-hint branch August 14, 2026 20:32
Sign up for freeto 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.

conductor fleet's TUI install hint prints a command that cannot work (pip, and conductor-cli isn't on PyPI)

1 participant

@jrob5756