feat(shell): add blocking update gate on startup#1826
Conversation
Add a blocking update prompt before interactive shell startup when a newer version is cached locally. Users can press Enter to upgrade, q to skip, or s to permanently skip that version. Replaces the repeating toast notification. Respects KIMI_CLI_NO_AUTO_UPDATE. Update docs and changelog accordingly.
Signed-off-by: Kai <me@kaiyi.cool>
There was a problem hiding this comment.
Pull request overview
Adds a startup “update gate” for the interactive shell that blocks on launch when a newer version is already cached locally, replacing the prior repeating update toast behavior and integrating “skip this version” suppression across UI surfaces.
Changes:
- Introduce a blocking update gate (
check_update_gate/_run_update_gate) driven by cachedlatest_version.txtplus a newskipped_version.txt. - Remove the repeating “update available” toast loop; keep the “updated, restart” toast only when an update actually happened.
- Suppress the welcome panel “New version available” hint when the user has skipped that specific version and when
KIMI_CLI_NO_AUTO_UPDATEis set; update docs/changelogs accordingly.
Reviewed changes
Copilot reviewed 11 out of 11 changed files in this pull request and generated 4 comments.
Show a summary per file
| File | Description |
|---|---|
src/kimi_cli/ui/shell/update.py |
Implements update gate UI + skip tracking + gate decision logic based on cached version files. |
src/kimi_cli/app.py |
Invokes the update gate before starting the interactive shell (when no command is provided). |
src/kimi_cli/ui/shell/__init__.py |
Removes the repeating update-available toast; suppresses welcome panel update hint when skipped/disabled. |
tests/ui/test_update_gate.py |
Adds unit tests for gate triggering/skipping behavior, skip persistence, and toast suppression. |
CHANGELOG.md |
Documents the new startup update gate behavior. |
docs/en/release-notes/changelog.md |
Documents the new startup update gate behavior (EN). |
docs/zh/release-notes/changelog.md |
Documents the new startup update gate behavior (ZH). |
docs/en/faq.md |
Clarifies that KIMI_CLI_NO_AUTO_UPDATE disables reminders/prompts, not just background checks. |
docs/zh/faq.md |
Same clarification as EN (ZH). |
docs/en/configuration/env-vars.md |
Updates env var description to “disable all update-related features” (EN). |
docs/zh/configuration/env-vars.md |
Updates env var description to “disable all update-related features” (ZH). |
💡 Add Copilot custom instructions for smarter, more guided reviews. Learn how to get started.
src/kimi_cli/ui/shell/update.py
Outdated
| def _read_key() -> str: | ||
| """Read a single character from stdin in raw terminal mode.""" | ||
| import sys | ||
| import termios | ||
| import tty | ||
|
|
||
| fd = sys.stdin.fileno() | ||
| old = termios.tcgetattr(fd) | ||
| try: | ||
| tty.setraw(fd) | ||
| return sys.stdin.read(1) | ||
| finally: | ||
| termios.tcsetattr(fd, termios.TCSADRAIN, old) |
| if key in ("\r", "\n"): | ||
| console.print(f"[grey50]Running: {UPGRADE_COMMAND}[/grey50]\n") | ||
| result = subprocess.run(UPGRADE_COMMAND.split()) | ||
| console.print() |
src/kimi_cli/ui/shell/update.py
Outdated
| SKIPPED_VERSION_FILE.write_text(latest_version, encoding="utf-8") | ||
| console.print(f"[grey50]Reminders skipped for version {latest_version}.[/grey50]\n") |
src/kimi_cli/ui/shell/update.py
Outdated
|
|
||
| if get_env_bool("KIMI_CLI_NO_AUTO_UPDATE"): | ||
| return | ||
| if not sys.stdin.isatty(): |
There was a problem hiding this comment.
💡 Codex Review
Here are some automated review suggestions for this pull request.
Reviewed commit: d113e9ee22
ℹ️ About Codex in GitHub
Your team has set up Codex to review pull requests in this repo. Reviews are triggered when you
- Open a pull request for review
- Mark a draft as ready
- Comment "@codex review".
If Codex has suggestions, it will comment; otherwise it will react with 👍.
Codex can also answer questions or update the PR. Try commenting "@codex address that feedback".
src/kimi_cli/ui/shell/update.py
Outdated
|
|
||
| if key in ("\r", "\n"): | ||
| console.print(f"[grey50]Running: {UPGRADE_COMMAND}[/grey50]\n") | ||
| result = subprocess.run(UPGRADE_COMMAND.split()) |
There was a problem hiding this comment.
Handle missing upgrader binary gracefully
When the user presses Enter, _run_update_gate executes subprocess.run(UPGRADE_COMMAND.split()) without catching OSError. If the configured upgrader command is not available on PATH (for example, a non-uv installation or a wrapper override typo), this raises FileNotFoundError and aborts startup with a traceback instead of showing the existing manual-upgrade fallback message. Please catch process-launch errors and route them through the same user-facing failure path.
Useful? React with 👍 / 👎.
- Support Windows in _read_key() via msvcrt - Use shlex.split for subprocess command - Handle OSError on skip file write and subprocess execution - Check both stdin and stdout isatty in update gate
There was a problem hiding this comment.
💡 Codex Review
Here are some automated review suggestions for this pull request.
Reviewed commit: 7e1c1aa2c3
ℹ️ About Codex in GitHub
Your team has set up Codex to review pull requests in this repo. Reviews are triggered when you
- Open a pull request for review
- Mark a draft as ready
- Comment "@codex review".
If Codex has suggestions, it will comment; otherwise it will react with 👍.
Codex can also answer questions or update the PR. Try commenting "@codex address that feedback".
| with contextlib.suppress(OSError): | ||
| SKIPPED_VERSION_FILE.write_text(latest_version, encoding="utf-8") | ||
| console.print(f"[grey50]Reminders skipped for version {latest_version}.[/grey50]\n") |
There was a problem hiding this comment.
Handle skip-file write failures before confirming skip
If writing skipped_version.txt fails (for example, $KIMI_SHARE_DIR is read-only or has wrong permissions), the code suppresses OSError but still prints Reminders skipped.... In that scenario the skip is not persisted, so users are told the reminder is disabled and then get blocked by the same gate again on next startup. Please only show the success message when the write succeeds, and show a failure fallback when it does not.
Useful? React with 👍 / 👎.
Summary
[Enter]— runuv tool upgrade kimi-cliimmediately and exit[q]— continue without upgrading (will be prompted again next startup)[s]— skip reminders for this specific versionKIMI_CLI_NO_AUTO_UPDATEin both the gate and the welcome panel noticeDetails
The gate reads from the already-existing
~/.kimi/latest_version.txtcache file (written by the background update checker). No new network calls at startup. A new~/.kimi/skipped_version.txtfile tracks versions the user has explicitly chosen to skip.Skipping a version silences all update notices for that version — both the startup gate and the welcome panel hint — until a newer version is available.
Test plan
uv run pytest tests/ui/test_update_gate.py -v— 30 tests, all passmake check— ruff and pyright cleanlatest_version.txtpointing to a newer version, verify gate appears and each key works correctly