reply install: keep the CLI current without the user touching npm - #14
Merged
Conversation
ArtemKosolap
enabled auto-merge
August 2, 2026 15:18
vigubikReply
approved these changes
Aug 2, 2026
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.
Adds
reply install— one command that keeps a user's CLI current without them ever recalling an npm incantation — and a quiet hint fromreply --versionwhen a newer release exists.reply updateis an accepted alias of the same command, undocumented on purpose: users learn one name, and muscle memory from other CLIs still works.npm remains the only way to install the CLI, and the README now says the Node requirement plainly, next to the install command, instead of leaving it to be discovered from an npm error.
Only a global npm install is ours to drive
Everything else is reported with the command that fits it, and nothing is spawned:
installdoesnpm install -g <pkg>@latestand reports old → newnpm install <pkg>@latest, names the projectgit pull && npm ci && npm run buildGlobal versus project-local is decided by which directory owns the
node_modulesholding us, and whether that directory is the working directory or an ancestor of it — the way node itself resolves. Asking only whether the module sits undercwdgets it backwards for a version-manager install:~/.nvm/…/node_modulesis under$HOME, so a user standing in their home directory would have had their global install called project-local and the update refused for a project that isn't there. That case has a regression test.Which package we are running as decides the channel, and the two are never crossed — sending a public-channel user to GitHub Packages would point them at a registry they cannot read.
What it compares against
The GitHub Releases API, for both channels. The tag is the version of record:
package.jsonin this repository is deliberately0.0.0-development. One code path, no token, and no npm subprocess just to ask a question. It is safe for the public channel because the publish workflow flips a release to latest only afternpm publishsucceeds, so a hit there means npm already has it; the internal channel compares against the newest release of any kind, which is exactly the pre-release stream.The check may not tax the CLI
reply --versionis the only command that can check, and only when a human is watching. It is suppressed — and no request is made at all — under--json/--pretty,--quiet, a non-TTY stderr,CIorGITHUB_ACTIONS,REPLY_NO_UPDATE_CHECK=1, and in a source checkout. The answer is cached for a day, a failure backs off for an hour, the request aborts after 1.5 s, and every error is silent. Verified by hand: with output piped, no request is made and no cache file is even created.Exit codes:
0when updated or already current,1whenever an update exists and was not applied — soreply install --dry-runworks as a CI check.Safety
npm install -g <package>@latest, and only for one of the two packages we publish — a guard inside the one function that can spawn a process, not a convention.--jsonstdout carries the report and nothing else.sudo …— or, on Windows where there is nothing to prepend, says to use an elevated terminal.--yesthat runs npm for a copy we did not verify.Verification
531 offline tests (up from 421), plus
tsc. No test performs a request, spawns npm, or touches a real config directory — fetch, the clock, env, cwd and the npm runner are all injected.Checked by hand against a staged package tree: the global path, the project-local path,
--dry-run,--json, and the permission-denied branch on both platform behaviours.Not in this change
Native binaries, bootstrap scripts, PATH wiring and a Node-less install. Node stays a requirement, stated up front. That work is written up separately and deliberately waits for real demand from users who cannot install Node.