Problem
Today wheels upgrade is check-only. The bare verb prints usage, wheels upgrade check scans the app for breaking changes (read-only, #2941/#2963/#2967 added exit-code gating, --strict, and --format=json), and the actual framework swap is left to the user: the upgrade guides document downloading a zip and manually replacing vendor/wheels/, and the CLI's own hint — brew upgrade wheels — only upgrades the CLI binary, never the app's vendored framework copy. There is no supported one-command path from "CLI updated" to "app framework updated".
Proposal (PR1 — this issue)
Give wheels upgrade an apply mode that swaps the app's vendor/wheels/ with the framework bundled inside the installed CLI:
- Bare
wheels upgrade applies the swap. Source = the CLI's bundled vendor/wheels/ (resolved via WHEELS_FRAMEWORK_PATH override first, else walking up from the module's own install location — mirroring resolveFrameworkSource(), minus the project-root candidate, which is the swap target).
- Backup first. The existing
vendor/wheels/ is renamed to vendor/wheels.bak-<yyyymmdd>-<HHmmss> (collision counter on rapid re-runs) via an atomic Java renameTo, with a hard error if the rename fails — recovery is a single mv. --nobackup opts out.
- Safety rails before any destructive step: both source and target must sniff as a Wheels framework dir (
wheels.json/box.json present); refuse when run outside a Wheels app (no vendor/wheels/); refuse when source and target resolve to the same directory (e.g. running inside the wheels repo checkout itself); --to=<version> must exactly match the bundled framework version or the command hard-errors.
- Report old → new version and the backup path on success.
wheels upgrade check keeps its current read-only behavior unchanged, including --strict, --format=json, and the Wheels.UpgradeCheckFailed exit-code contract.
This unlocks the bleeding-edge flow: brew uninstall wheels && brew install wheels-be && wheels upgrade puts the BE framework into an existing app, with the stable copy parked in vendor/wheels.bak-*.
Follow-up (PR2 — not in scope here)
Network download of arbitrary --to=<version> targets (resolved via ReleaseChannel), so apply mode can install versions the CLI doesn't bundle.
🤖 Generated with Claude Code
Problem
Today
wheels upgradeis check-only. The bare verb prints usage,wheels upgrade checkscans the app for breaking changes (read-only, #2941/#2963/#2967 added exit-code gating,--strict, and--format=json), and the actual framework swap is left to the user: the upgrade guides document downloading a zip and manually replacingvendor/wheels/, and the CLI's own hint —brew upgrade wheels— only upgrades the CLI binary, never the app's vendored framework copy. There is no supported one-command path from "CLI updated" to "app framework updated".Proposal (PR1 — this issue)
Give
wheels upgradean apply mode that swaps the app'svendor/wheels/with the framework bundled inside the installed CLI:wheels upgradeapplies the swap. Source = the CLI's bundledvendor/wheels/(resolved viaWHEELS_FRAMEWORK_PATHoverride first, else walking up from the module's own install location — mirroringresolveFrameworkSource(), minus the project-root candidate, which is the swap target).vendor/wheels/is renamed tovendor/wheels.bak-<yyyymmdd>-<HHmmss>(collision counter on rapid re-runs) via an atomic JavarenameTo, with a hard error if the rename fails — recovery is a singlemv.--nobackupopts out.wheels.json/box.jsonpresent); refuse when run outside a Wheels app (novendor/wheels/); refuse when source and target resolve to the same directory (e.g. running inside the wheels repo checkout itself);--to=<version>must exactly match the bundled framework version or the command hard-errors.wheels upgrade checkkeeps its current read-only behavior unchanged, including--strict,--format=json, and theWheels.UpgradeCheckFailedexit-code contract.This unlocks the bleeding-edge flow:
brew uninstall wheels && brew install wheels-be && wheels upgradeputs the BE framework into an existing app, with the stable copy parked invendor/wheels.bak-*.Follow-up (PR2 — not in scope here)
Network download of arbitrary
--to=<version>targets (resolved viaReleaseChannel), so apply mode can install versions the CLI doesn't bundle.🤖 Generated with Claude Code