refactor(cli): dedupe hook enable/disable logic

This commit is contained in:
Peter Steinberger
2026-02-15 18:14:03 +00:00
parent 65f8b46c15
commit dce3e4bd94

View File

@@ -66,6 +66,50 @@ function buildHooksReport(config: OpenClawConfig): HookStatusReport {
return buildWorkspaceHookStatus(workspaceDir, { config, entries });
}
function resolveHookForToggle(
report: HookStatusReport,
hookName: string,
opts?: { requireEligible?: boolean },
): HookStatusEntry {
const hook = report.hooks.find((h) => h.name === hookName);
if (!hook) {
throw new Error(`Hook "${hookName}" not found`);
}
if (hook.managedByPlugin) {
throw new Error(
`Hook "${hookName}" is managed by plugin "${hook.pluginId ?? "unknown"}" and cannot be enabled/disabled.`,
);
}
if (opts?.requireEligible && !hook.eligible) {
throw new Error(`Hook "${hookName}" is not eligible (missing requirements)`);
}
return hook;
}
function buildConfigWithHookEnabled(params: {
config: OpenClawConfig;
hookName: string;
enabled: boolean;
ensureHooksEnabled?: boolean;
}): OpenClawConfig {
const entries = { ...params.config.hooks?.internal?.entries };
entries[params.hookName] = { ...entries[params.hookName], enabled: params.enabled };
const internal = {
...params.config.hooks?.internal,
...(params.ensureHooksEnabled ? { enabled: true } : {}),
entries,
};
return {
...params.config,
hooks: {
...params.config.hooks,
internal,
},
};
}
function formatHookStatus(hook: HookStatusEntry): string {
if (hook.eligible) {
return theme.success("✓ ready");
@@ -384,38 +428,13 @@ export function formatHooksCheck(report: HookStatusReport, opts: HooksCheckOptio
export async function enableHook(hookName: string): Promise<void> {
const config = loadConfig();
const report = buildHooksReport(config);
const hook = report.hooks.find((h) => h.name === hookName);
if (!hook) {
throw new Error(`Hook "${hookName}" not found`);
}
if (hook.managedByPlugin) {
throw new Error(
`Hook "${hookName}" is managed by plugin "${hook.pluginId ?? "unknown"}" and cannot be enabled/disabled.`,
);
}
if (!hook.eligible) {
throw new Error(`Hook "${hookName}" is not eligible (missing requirements)`);
}
// Update config
const entries = { ...config.hooks?.internal?.entries };
entries[hookName] = { ...entries[hookName], enabled: true };
const nextConfig = {
...config,
hooks: {
...config.hooks,
internal: {
...config.hooks?.internal,
enabled: true,
entries,
},
},
};
const hook = resolveHookForToggle(buildHooksReport(config), hookName, { requireEligible: true });
const nextConfig = buildConfigWithHookEnabled({
config,
hookName,
enabled: true,
ensureHooksEnabled: true,
});
await writeConfigFile(nextConfig);
defaultRuntime.log(
@@ -425,33 +444,8 @@ export async function enableHook(hookName: string): Promise<void> {
export async function disableHook(hookName: string): Promise<void> {
const config = loadConfig();
const report = buildHooksReport(config);
const hook = report.hooks.find((h) => h.name === hookName);
if (!hook) {
throw new Error(`Hook "${hookName}" not found`);
}
if (hook.managedByPlugin) {
throw new Error(
`Hook "${hookName}" is managed by plugin "${hook.pluginId ?? "unknown"}" and cannot be enabled/disabled.`,
);
}
// Update config
const entries = { ...config.hooks?.internal?.entries };
entries[hookName] = { ...entries[hookName], enabled: false };
const nextConfig = {
...config,
hooks: {
...config.hooks,
internal: {
...config.hooks?.internal,
entries,
},
},
};
const hook = resolveHookForToggle(buildHooksReport(config), hookName);
const nextConfig = buildConfigWithHookEnabled({ config, hookName, enabled: false });
await writeConfigFile(nextConfig);
defaultRuntime.log(