Skip to content

Drive upgrade when cli.new --agents finds an out-of-date Railway CLI#886

Merged
codyde merged 1 commit into
masterfrom
cody/install-upgrade-on-stale
May 8, 2026
Merged

Drive upgrade when cli.new --agents finds an out-of-date Railway CLI#886
codyde merged 1 commit into
masterfrom
cody/install-upgrade-on-stale

Conversation

@codyde
Copy link
Copy Markdown
Collaborator

@codyde codyde commented May 8, 2026

Summary

Fixes a UX gap where curl cli.new --agents skipped install entirely whenever a railway binary was on PATH, leaving users stuck on whatever version they had — including pre-detection releases that emit no telemetry attribution. Now the install script reads the existing binary's version, compares to the latest GitHub release, and prompts to upgrade in place when older.

Behavior matrix

Existing CLI Interactive (TTY) --yes / non-interactive Homebrew
Up to date skip install, run setup skip install, run setup skip install, run setup
Out of date prompt [Y/n], upgrade in place if accepted auto-upgrade in place warn brew upgrade railway, run setup with current
Version unparseable skip install (safe default), run setup skip install (safe default), run setup warn + run setup with current
Not installed (existing fresh-install path) (existing fresh-install path) n/a

The upgrade writes back to the existing binary's directory (dirname "$(command -v railway)") so we don't shadow the user's install with a duplicate on PATH, skips the redundant Install railway X to Y? confirm, and skips the "restart your terminal" warning since PATH is already correct. Homebrew installs (/opt/homebrew/*, /usr/local/Cellar/*, and the Intel /usr/local/bin symlink to Cellar) are detected and routed to brew upgrade railway instead of being clobbered.

Helpers added

  • extract_railway_version — pulls X.Y.Z (with optional pre-release suffix) out of railway --version output. Handles railway 4.54.0, v4.54.0, 4.55.0-rc.1, plain 4.54.0, empty, and garbage input.
  • version_lt — semver major.minor.patch comparison. Pre-release suffixes are stripped so 4.55.0-rc.1 compares equal to 4.55.0 (does not trigger a "downgrade" upgrade). Returns false on any unparseable input so we never claim "outdated" when we can't tell.

Test plan

Validated locally against:

  • 7 extract_railway_version cases (plain, version-only, with-v, rc suffix, dev suffix, empty, garbage)
  • 8 version_lt cases (lt by patch / minor / major, equal, greater, rc-vs-release, empty, garbage)
  • 8 end-to-end decision scenarios (stale, current, newer, rc current vs released latest, release current vs rc latest, version unknown, garbage --version output, very old major)

All 23 cases pass. bash -n install.sh is clean.

Background

Pairs with #885 (now merged). RFC: Agentic Loop Telemetry: MCP + CLI — the bigger the share of users on ≥ the caller-detection release, the smaller the NULL bucket in fct_agentic_events. Driving upgrade through cli.new --agents is the primary way that adoption shifts week over week.

🤖 Generated with Claude Code

Previously the --agents path skipped install entirely whenever a
'railway' binary was on PATH, leaving users stuck on whatever version
they had — including pre-detection releases that emit no telemetry
attribution.

Now we read the existing binary's version, compare to the latest
GitHub release, and prompt to upgrade in place when older. With
--yes/--force or non-interactive stdin we auto-confirm. The upgrade
writes back to the existing binary's directory so we don't shadow the
user's install with a duplicate on PATH, skips the redundant
"Install railway X to Y?" confirm, and skips the "restart your
terminal" warning since PATH is already correct.

Homebrew installs (/opt/homebrew/*, /usr/local/Cellar/*, and the
Intel /usr/local/bin symlink) are detected and routed to
'brew upgrade railway' instead of being clobbered, then we fall
through to agent setup with the existing CLI so the rest of
cli.new --agents still works.

Adds two helpers — extract_railway_version (handles 'railway 4.54.0',
'v4.54.0', '4.55.0-rc.1', empty/garbage) and version_lt (semver
major.minor.patch comparison, pre-release suffixes stripped, returns
false on any unparseable input so we never claim 'outdated' when we
can't tell). Validated against 15 helper cases and 8 end-to-end
decision scenarios.

Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
@codyde codyde added release/skip Author no release release/minor Author minor release and removed release/skip Author no release labels May 8, 2026
@codyde codyde merged commit d788bee into master May 8, 2026
10 of 11 checks passed
@codyde codyde deleted the cody/install-upgrade-on-stale branch May 8, 2026 08:20
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

release/minor Author minor release

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant