Files
Ali Khokhar 2749d8e9e6 patch: let the installer decide whether fcc-update has work to do (#2445)
## Why

`fcc-update` ran a separate Python checker (`_fcc-update-check`). It
looked up the latest GitHub release, cross-checked PyPI, and handed a
pinned version to the installer. The installer already selects and pins
the release itself, so that work was done twice.

## What

- **Installer: new `--update` / `-Update` flag.** In the pinned
installer, after the release `X` is selected once, it reads the
installed FCC version from `uv tool list`. It checks uv's usual
directories without changing the PATH the installer preserves.
- Installed version equal to `X`: prints "already up to date" and exits
0.
- Installed version newer than `X`, or a local/post build of `X`: prints
"newer than the published version" and exits 0.
- Installed version older than `X`, or a dev/pre-release build of `X`:
prints "update available" and continues the normal pinned install.
  - No uv, FCC not installed, or a version it can't parse: installs.
- **Version consistency.** `X` is the same value used for
`free-claude-code==X`, so the version reported is the version installed.
A release published mid-run can't change it.
- **Without the flag:** the installer behaves as before and always
reinstalls.
- **`fcc-update` / `fcc-update.cmd`:** now just run `main`'s installer
with `--update` plus the user's options. The `.cmd` keeps the
parenthesized block because the installer overwrites the file mid-run.
- **Removed:** the `updater` package, the `_fcc-update-check` entry
point, and their tests.
- **Older installs:** an existing `fcc-update` still works. It uses the
existing `_FCC_INSTALLER_RELEASE` handoff, without `--update`, and
installs the new release.
- **Dropped the PyPI cross-check.** `publish_release.py` uploads to PyPI
before marking the GitHub release latest. The one behavior difference: a
release yanked on PyPI but still "latest" on GitHub would now be
installed.

## Tests

- `smoke/installers/test_update_wrapper.py`, rewritten for the new flow.
It installs a test wheel and runs `fcc-update`. Cases:
- Options and stdin reach the installer, and replacing the script
mid-run is survived.
- Exit codes and errors are passed through, and a failed download stops
the update.
- The real installer runs with real `uv tool list` for update-available,
current and newer-installed.
- `smoke/installers/test_installers.py`: version-decision cases for
`install.sh` and `install.ps1`: not installed, older, dev build,
pre-release, unparseable, current, newer, local build, post-release.
They also check that PATH is unchanged.
- `./scripts/ci.sh --skip playwright`: 11461 passed.
- `FCC_LIVE_SMOKE=1 uv run pytest smoke/installers` on Linux: 386
passed, 384 skipped (Windows-only).
- ⚠️ **The PowerShell paths have not been run.** The Windows installer
smoke tests must be run on Windows before merging.

---
_Generated by [Claude
Code](https://claude.ai/code/session_01FKcCaLSMqa6bZDWkzJEVtX)_

<!-- greptile_comment -->

<!-- greptile_summary -->

<h2><a
href="https://app.greptile.com/api/retrigger?id=107558445&amp;sig=4d3abfa97fc4efb26c01c26ff5ef1648643e1f9b99deaa8b6f12dda6ed28def4"><picture><source
media="(prefers-color-scheme: dark)"
srcset="https://greptile-static-assets.s3.amazonaws.com/badges/RetriggerDark.svg?v=2"><source
media="(prefers-color-scheme: light)"
srcset="https://greptile-static-assets.s3.amazonaws.com/badges/Retrigger.svg?v=2"><img
alt="Retrigger"
src="https://greptile-static-assets.s3.amazonaws.com/badges/Retrigger.svg?v=2"
align="right"></picture></a><a
href="https://app.greptile.com/-/switch-tenant?tenant=alishahryar1&amp;next=%2FAlishahryar1%2Ffree-claude-code%2Fpull%2F2445&amp;utm_source=greptile_review&amp;utm_medium=github&amp;utm_campaign=view_in_greptile"><picture><source
media="(prefers-color-scheme: dark)"
srcset="https://greptile-static-assets.s3.amazonaws.com/badges/ViewInGreptileDark.svg?v=2"><source
media="(prefers-color-scheme: light)"
srcset="https://greptile-static-assets.s3.amazonaws.com/badges/ViewInGreptile.svg?v=2"><img
alt="View in Greptile"
src="https://greptile-static-assets.s3.amazonaws.com/badges/ViewInGreptile.svg?v=2"
align="right"></picture></a>Confidence Score: 5/5</h2>

<!-- greptile-impact-verdict --> No actionable defects were found in the
changed update flow.

<details open><summary><h3>Summary</h3></summary>

`fcc-update` now lets the selected release installer decide whether an
update is needed.
- FCC updates now skip installation when the selected release is already
installed.
- The separate FCC update checker is no longer shipped.

Alishahryar1 explicitly acknowledges that dropping the PyPI cross-check
allows a yanked release to be selected when GitHub still marks it
latest. Alishahryar1 also states that the PowerShell paths have not been
run and requests Windows testing before merging.
</details>

<details open><summary><h3>Diagram</h3></summary>

```mermaid
%%{init: {'theme': 'neutral'}}%%
flowchart TD
  A[fcc-update] --> B[Download main installer]
  B --> C[Select one release]
  C --> D[Run matching installer with update flag]
  D --> E{Installed version}
  E -->|Same or newer| F[Print message and stop]
  E -->|Older or unavailable| G[Install selected release]
```
</details>

<!-- greptile_confidence_score:5 -->

<sub>Reviews (1) · Last reviewed commit: ["Let the installer decide
whether
fcc-upd..."](757fc7913f)
· [Reviewed by
Greptile](https://www.greptile.com/?utm_source=greptile_review&utm_medium=github&utm_campaign=review_public&utm_content=alishahryar1/free-claude-code)</sub>

<!-- /greptile_comment -->

Co-authored-by: Claude <noreply@anthropic.com>
2026-11-15 07:00:40 -08:00
..