mirror of
https://github.com/Kaelio/ktx.git
synced 2026-06-10 08:05:14 +02:00
feat(cli): add channel-aware update notifier (#265)
* feat(cli): show cached update notices after commands * docs(cli): describe update notices * fix(cli): type update check environment * fix(cli): decouple update notice display from refresh and harden suppression Display a cached "update available" notice based solely on the lastNoticeAt 24h throttle, independent of checkedAt refresh freshness, matching the design's independent display/refresh decisions. Suppress the check unconditionally under --json, CI, and non-TTY before consulting output-mode preferences, so a KTX_OUTPUT=pretty override can no longer make CI/non-TTY contexts phone npm.
This commit is contained in:
parent
377f21acd7
commit
698efdcef8
14 changed files with 1153 additions and 4 deletions
|
|
@ -16,6 +16,7 @@ import { renderMissingProjectMessage } from './doctor.js';
|
|||
import { findNearestKtxProjectDir, resolveKtxProjectDir } from './project-resolver.js';
|
||||
import { profileMark, profileSpan } from './startup-profile.js';
|
||||
import type { CommandOutcome } from './telemetry/index.js';
|
||||
import { prepareUpdateCheckNotice, type PrepareUpdateCheckNoticeOptions } from './update-check/update-check.js';
|
||||
|
||||
profileMark('module:cli-program');
|
||||
|
||||
|
|
@ -39,6 +40,8 @@ interface KtxCommanderProgramOptions {
|
|||
runInit: (args: { projectDir: string; force: boolean }, io: KtxCliIo) => Promise<number>;
|
||||
}
|
||||
|
||||
type KtxCliUpdateCheckOptions = Pick<PrepareUpdateCheckNoticeOptions, 'env' | 'fetchDistTags' | 'homeDir' | 'now'>;
|
||||
|
||||
export interface BuildKtxProgramOptions {
|
||||
io: KtxCliIo;
|
||||
deps: KtxCliDeps;
|
||||
|
|
@ -47,6 +50,7 @@ export interface BuildKtxProgramOptions {
|
|||
setExitCode?: (code: number) => void;
|
||||
argv?: string[];
|
||||
setTelemetryModule?: (telemetry: typeof import('./telemetry/index.js')) => void;
|
||||
updateCheck?: KtxCliUpdateCheckOptions;
|
||||
}
|
||||
|
||||
type CommanderExitLike = { exitCode: number; code: string; message: string };
|
||||
|
|
@ -431,16 +435,29 @@ export function collectCommandFlagsPresent(command: CommandUnknownOpts): Record<
|
|||
|
||||
export function buildKtxProgram(options: BuildKtxProgramOptions): Command {
|
||||
const program = createBaseProgram(options.packageInfo, options.io);
|
||||
let pendingUpdateNotice: string | null = null;
|
||||
|
||||
program.hook('preAction', async (_thisCommand, actionCommand) => {
|
||||
// The hidden completion command must stay silent and side-effect free: skip
|
||||
// the telemetry notice, command span, and project checks entirely.
|
||||
// the telemetry notice, command span, project checks, and update checks entirely.
|
||||
if (commandPath(actionCommand as CommandPathNode).includes('__complete')) {
|
||||
return;
|
||||
}
|
||||
const commandNode = actionCommand as CommandPathNode;
|
||||
const updateCheck = await prepareUpdateCheckNotice({
|
||||
io: options.io,
|
||||
env: options.updateCheck?.env,
|
||||
fetchDistTags: options.updateCheck?.fetchDistTags,
|
||||
homeDir: options.updateCheck?.homeDir,
|
||||
installedVersion: options.packageInfo.version,
|
||||
now: options.updateCheck?.now,
|
||||
commandOptions: commandOptions(commandNode),
|
||||
});
|
||||
pendingUpdateNotice = updateCheck.notice;
|
||||
|
||||
const telemetry = await import('./telemetry/index.js');
|
||||
options.setTelemetryModule?.(telemetry);
|
||||
await telemetry.showTelemetryNoticeIfNeeded(options.io, options.packageInfo);
|
||||
const commandNode = actionCommand as CommandPathNode;
|
||||
const path = commandPath(commandNode);
|
||||
const projectDir = resolveCommandProjectDir(commandNode);
|
||||
const hasProject = ktxYamlExists(projectDir);
|
||||
|
|
@ -457,6 +474,13 @@ export function buildKtxProgram(options: BuildKtxProgramOptions): Command {
|
|||
ensureProjectAvailable(options.io, commandNode);
|
||||
});
|
||||
|
||||
program.hook('postAction', () => {
|
||||
if (pendingUpdateNotice) {
|
||||
options.io.stderr.write(pendingUpdateNotice);
|
||||
pendingUpdateNotice = null;
|
||||
}
|
||||
});
|
||||
|
||||
const context: KtxCliCommandContext = {
|
||||
io: options.io,
|
||||
deps: options.deps,
|
||||
|
|
|
|||
Loading…
Add table
Add a link
Reference in a new issue