refactor(cli): dedupe browser and hooks command handlers

This commit is contained in:
Peter Steinberger
2026-02-16 17:57:20 +00:00
parent 5a39e13c92
commit 9a29d7833b
2 changed files with 147 additions and 221 deletions

View File

@@ -152,6 +152,32 @@ function formatHookMissingSummary(hook: HookStatusEntry): string {
return missing.join("; ");
}
function exitHooksCliWithError(err: unknown): never {
defaultRuntime.error(
`${theme.error("Error:")} ${err instanceof Error ? err.message : String(err)}`,
);
process.exit(1);
}
async function runHooksCliAction(action: () => Promise<void> | void): Promise<void> {
try {
await action();
} catch (err) {
exitHooksCliWithError(err);
}
}
function createInstallLogger() {
return {
info: (msg: string) => defaultRuntime.log(msg),
warn: (msg: string) => defaultRuntime.log(theme.warn(msg)),
};
}
function logGatewayRestartHint() {
defaultRuntime.log("Restart the gateway to load hooks.");
}
async function readInstalledPackageVersion(dir: string): Promise<string | undefined> {
try {
const raw = await fsp.readFile(path.join(dir, "package.json"), "utf-8");
@@ -469,80 +495,55 @@ export function registerHooksCli(program: Command): void {
.option("--eligible", "Show only eligible hooks", false)
.option("--json", "Output as JSON", false)
.option("-v, --verbose", "Show more details including missing requirements", false)
.action(async (opts) => {
try {
.action(async (opts) =>
runHooksCliAction(async () => {
const config = loadConfig();
const report = buildHooksReport(config);
defaultRuntime.log(formatHooksList(report, opts));
} catch (err) {
defaultRuntime.error(
`${theme.error("Error:")} ${err instanceof Error ? err.message : String(err)}`,
);
process.exit(1);
}
});
}),
);
hooks
.command("info <name>")
.description("Show detailed information about a hook")
.option("--json", "Output as JSON", false)
.action(async (name, opts) => {
try {
.action(async (name, opts) =>
runHooksCliAction(async () => {
const config = loadConfig();
const report = buildHooksReport(config);
defaultRuntime.log(formatHookInfo(report, name, opts));
} catch (err) {
defaultRuntime.error(
`${theme.error("Error:")} ${err instanceof Error ? err.message : String(err)}`,
);
process.exit(1);
}
});
}),
);
hooks
.command("check")
.description("Check hooks eligibility status")
.option("--json", "Output as JSON", false)
.action(async (opts) => {
try {
.action(async (opts) =>
runHooksCliAction(async () => {
const config = loadConfig();
const report = buildHooksReport(config);
defaultRuntime.log(formatHooksCheck(report, opts));
} catch (err) {
defaultRuntime.error(
`${theme.error("Error:")} ${err instanceof Error ? err.message : String(err)}`,
);
process.exit(1);
}
});
}),
);
hooks
.command("enable <name>")
.description("Enable a hook")
.action(async (name) => {
try {
.action(async (name) =>
runHooksCliAction(async () => {
await enableHook(name);
} catch (err) {
defaultRuntime.error(
`${theme.error("Error:")} ${err instanceof Error ? err.message : String(err)}`,
);
process.exit(1);
}
});
}),
);
hooks
.command("disable <name>")
.description("Disable a hook")
.action(async (name) => {
try {
.action(async (name) =>
runHooksCliAction(async () => {
await disableHook(name);
} catch (err) {
defaultRuntime.error(
`${theme.error("Error:")} ${err instanceof Error ? err.message : String(err)}`,
);
process.exit(1);
}
});
}),
);
hooks
.command("install")
@@ -597,16 +598,13 @@ export function registerHooksCli(program: Command): void {
await writeConfigFile(next);
defaultRuntime.log(`Linked hook path: ${shortenHomePath(resolved)}`);
defaultRuntime.log(`Restart the gateway to load hooks.`);
logGatewayRestartHint();
return;
}
const result = await installHooksFromPath({
path: resolved,
logger: {
info: (msg) => defaultRuntime.log(msg),
warn: (msg) => defaultRuntime.log(theme.warn(msg)),
},
logger: createInstallLogger(),
});
if (!result.ok) {
defaultRuntime.error(result.error);
@@ -628,7 +626,7 @@ export function registerHooksCli(program: Command): void {
await writeConfigFile(next);
defaultRuntime.log(`Installed hooks: ${result.hooks.join(", ")}`);
defaultRuntime.log(`Restart the gateway to load hooks.`);
logGatewayRestartHint();
return;
}
@@ -652,10 +650,7 @@ export function registerHooksCli(program: Command): void {
const result = await installHooksFromNpmSpec({
spec: raw,
logger: {
info: (msg) => defaultRuntime.log(msg),
warn: (msg) => defaultRuntime.log(theme.warn(msg)),
},
logger: createInstallLogger(),
});
if (!result.ok) {
defaultRuntime.error(result.error);
@@ -674,7 +669,7 @@ export function registerHooksCli(program: Command): void {
});
await writeConfigFile(next);
defaultRuntime.log(`Installed hooks: ${result.hooks.join(", ")}`);
defaultRuntime.log(`Restart the gateway to load hooks.`);
logGatewayRestartHint();
});
hooks
@@ -726,10 +721,7 @@ export function registerHooksCli(program: Command): void {
mode: "update",
dryRun: true,
expectedHookPackId: hookId,
logger: {
info: (msg) => defaultRuntime.log(msg),
warn: (msg) => defaultRuntime.log(theme.warn(msg)),
},
logger: createInstallLogger(),
});
if (!probe.ok) {
defaultRuntime.log(theme.error(`Failed to check ${hookId}: ${probe.error}`));
@@ -750,10 +742,7 @@ export function registerHooksCli(program: Command): void {
spec: record.spec,
mode: "update",
expectedHookPackId: hookId,
logger: {
info: (msg) => defaultRuntime.log(msg),
warn: (msg) => defaultRuntime.log(theme.warn(msg)),
},
logger: createInstallLogger(),
});
if (!result.ok) {
defaultRuntime.log(theme.error(`Failed to update ${hookId}: ${result.error}`));
@@ -782,20 +771,15 @@ export function registerHooksCli(program: Command): void {
if (updatedCount > 0) {
await writeConfigFile(nextCfg);
defaultRuntime.log("Restart the gateway to load hooks.");
logGatewayRestartHint();
}
});
hooks.action(async () => {
try {
hooks.action(async () =>
runHooksCliAction(async () => {
const config = loadConfig();
const report = buildHooksReport(config);
defaultRuntime.log(formatHooksList(report, {}));
} catch (err) {
defaultRuntime.error(
`${theme.error("Error:")} ${err instanceof Error ? err.message : String(err)}`,
);
process.exit(1);
}
});
}),
);
}