refactor(cli): share npm install metadata helpers

This commit is contained in:
Peter Steinberger
2026-02-21 21:56:05 +00:00
parent d6ad647f56
commit 2d4e4e2288
6 changed files with 316 additions and 79 deletions

View File

@@ -26,6 +26,11 @@ import { renderTable } from "../terminal/table.js";
import { theme } from "../terminal/theme.js";
import { resolveUserPath, shortenHomePath } from "../utils.js";
import { formatCliCommand } from "./command-format.js";
import {
buildNpmInstallRecordFields,
logPinnedNpmSpecMessages,
resolvePinnedNpmSpec,
} from "./npm-resolution.js";
import { promptYesNo } from "./prompt.js";
export type HooksListOptions = {
@@ -179,6 +184,25 @@ function logGatewayRestartHint() {
defaultRuntime.log("Restart the gateway to load hooks.");
}
function logIntegrityDriftWarning(
hookId: string,
drift: {
resolution: { resolvedSpec?: string };
spec: string;
expectedIntegrity: string;
actualIntegrity: string;
},
) {
const specLabel = drift.resolution.resolvedSpec ?? drift.spec;
defaultRuntime.log(
theme.warn(
`Integrity drift detected for "${hookId}" (${specLabel})` +
`\nExpected: ${drift.expectedIntegrity}` +
`\nActual: ${drift.actualIntegrity}`,
),
);
}
async function readInstalledPackageVersion(dir: string): Promise<string | undefined> {
try {
const raw = await fsp.readFile(path.join(dir, "package.json"), "utf-8");
@@ -660,29 +684,25 @@ export function registerHooksCli(program: Command): void {
}
let next = enableInternalHookEntries(cfg, result.hooks);
const resolvedSpec = result.npmResolution?.resolvedSpec;
const recordSpec = opts.pin && resolvedSpec ? resolvedSpec : raw;
if (opts.pin && !resolvedSpec) {
defaultRuntime.log(
theme.warn("Could not resolve exact npm version for --pin; storing original npm spec."),
);
}
if (opts.pin && resolvedSpec) {
defaultRuntime.log(`Pinned npm install record to ${resolvedSpec}.`);
}
const pinInfo = resolvePinnedNpmSpec({
rawSpec: raw,
pin: Boolean(opts.pin),
resolvedSpec: result.npmResolution?.resolvedSpec,
});
logPinnedNpmSpecMessages(
pinInfo,
(message) => defaultRuntime.log(message),
(message) => defaultRuntime.log(theme.warn(message)),
);
next = recordHookInstall(next, {
hookId: result.hookPackId,
source: "npm",
spec: recordSpec,
installPath: result.targetDir,
version: result.version,
resolvedName: result.npmResolution?.name,
resolvedVersion: result.npmResolution?.version,
resolvedSpec: result.npmResolution?.resolvedSpec,
integrity: result.npmResolution?.integrity,
shasum: result.npmResolution?.shasum,
resolvedAt: result.npmResolution?.resolvedAt,
...buildNpmInstallRecordFields({
spec: pinInfo.recordSpec,
installPath: result.targetDir,
version: result.version,
resolution: result.npmResolution,
}),
hooks: result.hooks,
});
await writeConfigFile(next);
@@ -741,14 +761,7 @@ export function registerHooksCli(program: Command): void {
expectedHookPackId: hookId,
expectedIntegrity: record.integrity,
onIntegrityDrift: async (drift) => {
const specLabel = drift.resolution.resolvedSpec ?? drift.spec;
defaultRuntime.log(
theme.warn(
`Integrity drift detected for "${hookId}" (${specLabel})` +
`\nExpected: ${drift.expectedIntegrity}` +
`\nActual: ${drift.actualIntegrity}`,
),
);
logIntegrityDriftWarning(hookId, drift);
return true;
},
logger: createInstallLogger(),
@@ -774,14 +787,7 @@ export function registerHooksCli(program: Command): void {
expectedHookPackId: hookId,
expectedIntegrity: record.integrity,
onIntegrityDrift: async (drift) => {
const specLabel = drift.resolution.resolvedSpec ?? drift.spec;
defaultRuntime.log(
theme.warn(
`Integrity drift detected for "${hookId}" (${specLabel})` +
`\nExpected: ${drift.expectedIntegrity}` +
`\nActual: ${drift.actualIntegrity}`,
),
);
logIntegrityDriftWarning(hookId, drift);
return await promptYesNo(`Continue updating "${hookId}" with this artifact?`);
},
logger: createInstallLogger(),
@@ -794,16 +800,12 @@ export function registerHooksCli(program: Command): void {
const nextVersion = result.version ?? (await readInstalledPackageVersion(result.targetDir));
nextCfg = recordHookInstall(nextCfg, {
hookId,
source: "npm",
spec: record.spec,
installPath: result.targetDir,
version: nextVersion,
resolvedName: result.npmResolution?.name,
resolvedVersion: result.npmResolution?.version,
resolvedSpec: result.npmResolution?.resolvedSpec,
integrity: result.npmResolution?.integrity,
shasum: result.npmResolution?.shasum,
resolvedAt: result.npmResolution?.resolvedAt,
...buildNpmInstallRecordFields({
spec: record.spec,
installPath: result.targetDir,
version: nextVersion,
resolution: result.npmResolution,
}),
hooks: result.hooks,
});
updatedCount += 1;