Features
- Never blocks startup — reads a cached answer from disk and returns instantly. A stale cache (24h by default) triggers a detached,
unref'd background refresh; the fresh result appears on the next run, never the current one. - Silent on non-TTY output — returns
nullimmediately wheneverprocess.stdout.isTTYis false, so piped or redirected output (duux status --json | jq) is never touched. - Respects the ecosystem's opt-outs — stays quiet when
CIorNO_UPDATE_NOTIFIERis set, on top of its own config file. - Per-package or global opt-out —
~/.config/kud/cli.jsonsupports a globalupdateNotifierflag and per-package overrides, withdisableNotices()/enableNotices()to manage it programmatically from a CLI's own subcommand. - Real semver comparison — uses the
semverpackage to compare versions correctly, prereleases included, instead of a naive string check. - Never throws — a broken network, an unreachable registry, or a read-only home directory all degrade silently to
null/no-op. An update check can never break the CLI that calls it.
Install
@kud/cli-update hasn't been published to npm yet — this is a pre-release library (0.1.0), still under review. Once it's published, install it as a normal dependency:
npm install @kud/cli-updateUntil then, install straight from the repository:
npm install kud/cli-updateUsage
Call checkForUpdate once at CLI startup, and print the notice yourself if one comes back:
import { checkForUpdate, formatNotice } from "@kud/cli-update"
import pkg from "../package.json" with { type: "json" }
const notice = await checkForUpdate({ name: pkg.name, version: pkg.version })
if (notice) console.error(formatNotice(notice))checkForUpdate always resolves — it never rejects, and it never waits on the network. formatNotice turns the result into a single line:
Update available: @kud/duux-cli 1.2.0 -> 1.3.0. Run `npm i -g @kud/duux-cli` to upgrade.Opting out
A CLI can expose its own update --disable subcommand on top of the config file at ~/.config/kud/cli.json:
import { disableNotices, enableNotices, noticesEnabled } from "@kud/cli-update"
disableNotices()
disableNotices("@kud/duux-cli")
enableNotices("@kud/duux-cli")
noticesEnabled("@kud/duux-cli")The first call turns off notices for every @kud CLI; passing a package name scopes it to just that one, and enableNotices reverses either. noticesEnabled reads the current state.
Per-package settings win over the global one. Users can reach the same switch directly, without any CLI-specific code, by editing the config file or setting NO_UPDATE_NOTIFIER=1:
{
"updateNotifier": false,
"packages": {
"@kud/duux-cli": true
}
}API
type UpdateNotice = {
name: string
current: string
latest: string
command: string
}
checkForUpdate(options: { name: string; version: string; cacheHours?: number }): Promise<UpdateNotice | null>
formatNotice(notice: UpdateNotice): string
disableNotices(scope?: string): void
enableNotices(scope?: string): void
noticesEnabled(name: string): booleancacheHours defaults to 24 and controls how long a cached "latest version" answer is trusted before a background refresh is triggered.
Development
git clone https://github.com/kud/cli-update.git
cd cli-update
npm install
npm run buildnpm test runs the Vitest suite, npm run build:watch rebuilds on change, and npm run typecheck runs a type-only check with no emit.