Repository navigation
fix(tui): hold install and update screens until their action finishes - #676
Open
eric-engberg wants to merge 3 commits into
Open
eric-engberg wants to merge 3 commits into
eric-engberg wants to merge 3 commits into
Conversation
Confirming an install, uninstall or global update started its async action and left the Yes/No dialog live. A second Enter started the same action again, so `npm install -g` ran twice at once and both runs went on to write Claude's settings.json. ESC returned to the previous menu while the action kept running, and when it finished it jumped the TUI to the main menu (or the Install Complete notice) from wherever the user had gone. The pinned version mismatch screen's "Update npm global install" item had the same problem. App now runs these actions one at a time. While one runs, the confirm dialog and the mismatch screen show a working line in place of their options and ignore ESC; a ref blocks a second start even before that screen re-renders. When the action settles, its own navigation takes over as before, including the failure paths.
Move the scratch config, probe stubs and Ink rendering used by the App tests into helpers/render-app.ts, next to wait-for-ink.ts, so other tests that drive the whole TUI can use the same setup.
The App sets chalk's global color level from the settings it loads, and the whole-App test helper didn't restore it. Test files that run later in the same process then rendered at that level instead of their own: a No Color check could see 256-color codes. The sandbox now restores the level along with the mocks and the config path.
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.
What
After you confirm an install, uninstall or global update, the confirm dialog now replaces Yes/No with
Working... This may take a moment.and ignores Enter and ESC until the action finishes. The pinned version mismatch screen does the same while its "Update npm global install to v…" item runs: it showsUpdating npm global install to v2.2.30... This may take a moment.in place of its options.Why
These actions run a package manager and then write Claude's
settings.json, which takes seconds. Until now the dialog stayed live the whole time, with no sign anything was happening:npmstub onPATHrecords two concurrent installs one second apart, and both go on to write Claude's settings:settings.jsonand pulled the TUI from wherever the user had gone to the Install Complete notice.npm install -gruns, and ESC exited the TUI while npm was still running.How
Appruns these actions through one helper that allows a single action at a time. A ref blocks a second start synchronously, before the busy screen has re-rendered, and a state flag drives what's shown. While an action runs:ConfirmDialogtakes a new optionalbusyprop. It keeps the message (so you can still see which command is running), replaces Yes/No with the working line, and ignores ESC. Other dialogs don't pass it, so they behave as before.updatingprop and does the same in place of its Update/Exit list.When the action settles, its own navigation runs unchanged: success, failure, the "not resolvable on PATH" notice, and the partial-uninstall message all land where they did before. Sync confirm actions (Star on GitHub, the invalid-settings save guard) settle immediately, so nothing changes for them. Ctrl+S was already off on the confirm screen. Ctrl+C still quits.
Demo
No GIF: recording this flow would run a real
npm install -g. These are tmux captures of the built CLI under Node with a stubnpmthat sleeps 8 s. The render mode doesn't affect this screen.Before: after Yes, the dialog looks unchanged and still takes Enter and ESC.
After: after Yes, then Enter and ESC while npm runs:
Testing
src/tui/__tests__/App.test.tsrender the wholeAppwith stubbed package-manager and Claude settings calls. The setup lives insrc/tui/__tests__/helpers/render-app.ts(second commit), so other whole-TUI tests can reuse it. One confirms an install, the other runs the pinned mismatch update; each presses Enter and ESC while the action is pending. Onmainboth fail withrunGlobalPackageInstallcalled 2 times. On this branch both pass, and each asserts one run, the working line, no navigation, and the normal result afterwards. Each passed 10 of 10 runs under Bun and under Node.bun test: 2784 pass, 0 fail.bun run lintpasses.App.test.tsunder Node (Vitest): 21 pass (19 existing, 2 new).mainpasses the same 19.HOMEandCLAUDE_CONFIG_DIRand stubnpmandclaude:mainran npm twice and ESC showed the install menu. This branch ran it once, stayed on the working line, then showed Install Complete.mainran npm twice. This branch ran it once, showed the updating line, then went to the main menu with✓ Global package updatedandinstalledVersion: 2.2.30saved.