Skip to content

feat: add self-update command#10

Merged
sthbryan merged 16 commits into
mainfrom
feat/update-command
Jun 4, 2026
Merged

feat: add self-update command#10
sthbryan merged 16 commits into
mainfrom
feat/update-command

Conversation

@sthbryan
Copy link
Copy Markdown
Owner

@sthbryan sthbryan commented Jun 4, 2026

Adds ftm --update and ftm --check flags

  • --check: prints current/latest version and release URL

  • --update: download and installs the new binary

  • Add TUI and Web banner

sthbryan added 5 commits June 3, 2026 22:22
- fetch latest stable release from GitHub API
- semver comparison with current version
- atomic binary replacement with rollback on failure
- platform asset name mapping (darwin->macos, amd64->x64)
- Windows self-replace unsupported (returns error with release URL)
--update downloads and replaces the running binary
--check only reports current/latest version and release URL
9 new keys: check failure, current/latest version, up-to-date,
update available, release URL, downloading, apply failure, success
Uninstall() returns error instead of calling os.Exit, letting
main handle exit code. cli.Init() loads i18n translations once
at startup so subcommands can use localized messages.
Update(checkOnly bool) returns error. Removes updater dep
from main and moves all i18n/update logic out of main.go.
Copilot AI review requested due to automatic review settings June 4, 2026 04:27
Copy link
Copy Markdown

@gemini-code-assist gemini-code-assist Bot left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Code Review

This pull request refactors the CLI commands out of main.go into a new cli package and introduces self-update capabilities by checking and applying releases from GitHub, along with new localization strings. Feedback on these changes highlights several issues: a background goroutine designed to clean up the old binary will never execute due to immediate process termination, ignoring the error from cli.Init() could lead to silent initialization failures, the custom semver parser fails to handle pre-release tags correctly (where using golang.org/x/mod/semver is recommended), and ignoring the error from http.NewRequest could cause a nil pointer dereference panic.

Important

The consumer version of Gemini Code Assist on GitHub is being sunset. Starting June 18, 2026, new organization installations will be blocked, and all code review activity will officially cease on July 17, 2026.
For more details on the timeline and next steps, please review the Help Documentation.

Comment thread internal/updater/updater.go Outdated
Comment thread cmd/ftm/main.go Outdated
Comment thread internal/updater/updater.go
Comment thread internal/updater/updater.go Outdated
Copy link
Copy Markdown

Copilot AI left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Pull request overview

Adds a self-update/check feature to the ftm CLI by introducing a new internal/updater package that queries GitHub Releases, selects the platform-specific asset, and replaces the current executable. The PR also refactors uninstall/update-related CLI logic out of cmd/ftm/main.go into a new internal/cli package and adds i18n strings for the new commands.

Changes:

  • Introduce internal/updater to fetch the latest GitHub release and apply an in-place binary update.
  • Add --check and --update flags to cmd/ftm/main.go wired through internal/cli.
  • Extend EN/ES locale files with update-related messages.

Reviewed changes

Copilot reviewed 7 out of 7 changed files in this pull request and generated 5 comments.

Show a summary per file
File Description
internal/updater/updater.go Implements GitHub release lookup, asset selection, download, and binary replacement.
internal/cli/update.go Adds Update(checkOnly bool) command wrapper around internal/updater with i18n output.
internal/cli/uninstall.go Moves uninstall logic into internal/cli.
internal/cli/cli.go Centralizes CLI initialization (i18n load).
cmd/ftm/main.go Adds --check / --update flags and delegates to internal/cli.
internal/i18n/locales/en.yaml Adds update-related translation strings.
internal/i18n/locales/es.yaml Adds update-related translation strings.

💡 Add Copilot custom instructions for smarter, more guided reviews. Learn how to get started.

Comment thread internal/updater/updater.go
Comment thread internal/updater/updater.go Outdated
Comment thread internal/updater/updater.go
Comment thread internal/updater/updater.go
Comment thread cmd/ftm/main.go
sthbryan added 5 commits June 3, 2026 22:31
Moves chmod + atomic rename + macOS xattr logic out of Apply()
into apply_unix.go. Cross-platform Apply() now resolves exec
path, downloads to temp, and delegates to applyUpdate().
Stage new binary as <name>.new, write a .bat that polls move
every 1s (Windows holds an exclusive lock on the running exe),
then spawn it detached. Caller should os.Exit immediately so
the .bat can complete the swap; next ftm launch uses the new
binary. Cross-compiles cleanly with GOOS=windows.
- async check on Init() and every 6h
- gold badge in list header when a newer release exists
- 'u' key downloads and replaces the running binary, then
  os.Exit(0); matches cli.Update behavior (no graceful shutdown
  that could hang on running tunnels/ws clients)
- update_tui_badge: '↑ Update available: v{0} — press u to install'
- update_applying: 'Downloading and installing update...'
@sthbryan sthbryan closed this Jun 4, 2026
sthbryan added 4 commits June 3, 2026 22:59
- GET /api/update returns { current, latest, tag, hasUpdate, ... }
- POST /api/update applies the update and triggers os.Exit(0)
  after 500ms grace period for the response
- updateService runs a check on Start() and every 6h
- broadcasts 'update_available' via WS on first detection
- updateApi client (get + apply)
- updateStore state container
- UpdateBanner component: gold-tinted row below the header with
  'Update now' button + 'Release notes' link, listens to WS
  'update_available' messages, surfaces apply errors
- update_web_banner: 'Update available: v{latest}'
- update_web_button: 'Update now'
- update_web_notes: 'Release notes'
Copy link
Copy Markdown

Copilot AI left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Pull request overview

Copilot reviewed 25 out of 26 changed files in this pull request and generated 6 comments.

Comment thread internal/updater/apply_unix.go
Comment thread internal/web/handlers_update.go Outdated
Comment thread internal/web/handlers_update.go
Comment thread internal/updater/updater.go
Comment thread web-svelte/src/lib/stores/update.svelte.ts Outdated
Comment thread web-svelte/src/lib/components/UpdateBanner.svelte
sthbryan added 2 commits June 3, 2026 23:35
- sync os.Remove(oldPath) instead of goroutine (os.Exit kills
  goroutines, the .old was never deleted)
- clean tmpPath on rename rollback so a failed second rename
  doesn't leave ftm-update-*.tmp behind
- handle http.NewRequest errors (fetch + download) instead of
  ignoring them and risking nil-deref on header sets
- GET /api/update now always returns the full UpdateInfo shape
  (empty strings when no info yet) so the frontend type matches
  every code path
- update.svelte.ts converted from writable to runes to align
  with the other stores (providers/settings/theme)
@sthbryan sthbryan merged commit af9f57c into main Jun 4, 2026
4 checks passed
@sthbryan sthbryan deleted the feat/update-command branch June 4, 2026 05:40
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.

2 participants