mirror of
https://github.com/openclaw/openclaw.git
synced 2026-05-07 20:41:24 +00:00
120 lines
3.3 KiB
TypeScript
120 lines
3.3 KiB
TypeScript
import type { OpenClawConfig, HookConfig } from "../config/config.js";
|
|
import type { HookEligibilityContext, HookEntry } from "./types.js";
|
|
import {
|
|
hasBinary,
|
|
isConfigPathTruthyWithDefaults,
|
|
resolveConfigPath,
|
|
resolveRuntimePlatform,
|
|
} from "../shared/config-eval.js";
|
|
import { resolveHookKey } from "./frontmatter.js";
|
|
|
|
const DEFAULT_CONFIG_VALUES: Record<string, boolean> = {
|
|
"browser.enabled": true,
|
|
"browser.evaluateEnabled": true,
|
|
"workspace.dir": true,
|
|
};
|
|
|
|
export { hasBinary, resolveConfigPath, resolveRuntimePlatform };
|
|
|
|
export function isConfigPathTruthy(config: OpenClawConfig | undefined, pathStr: string): boolean {
|
|
return isConfigPathTruthyWithDefaults(config, pathStr, DEFAULT_CONFIG_VALUES);
|
|
}
|
|
|
|
export function resolveHookConfig(
|
|
config: OpenClawConfig | undefined,
|
|
hookKey: string,
|
|
): HookConfig | undefined {
|
|
const hooks = config?.hooks?.internal?.entries;
|
|
if (!hooks || typeof hooks !== "object") {
|
|
return undefined;
|
|
}
|
|
const entry = (hooks as Record<string, HookConfig | undefined>)[hookKey];
|
|
if (!entry || typeof entry !== "object") {
|
|
return undefined;
|
|
}
|
|
return entry;
|
|
}
|
|
|
|
export function shouldIncludeHook(params: {
|
|
entry: HookEntry;
|
|
config?: OpenClawConfig;
|
|
eligibility?: HookEligibilityContext;
|
|
}): boolean {
|
|
const { entry, config, eligibility } = params;
|
|
const hookKey = resolveHookKey(entry.hook.name, entry);
|
|
const hookConfig = resolveHookConfig(config, hookKey);
|
|
const pluginManaged = entry.hook.source === "openclaw-plugin";
|
|
const osList = entry.metadata?.os ?? [];
|
|
const remotePlatforms = eligibility?.remote?.platforms ?? [];
|
|
|
|
// Check if explicitly disabled
|
|
if (!pluginManaged && hookConfig?.enabled === false) {
|
|
return false;
|
|
}
|
|
|
|
// Check OS requirement
|
|
if (
|
|
osList.length > 0 &&
|
|
!osList.includes(resolveRuntimePlatform()) &&
|
|
!remotePlatforms.some((platform) => osList.includes(platform))
|
|
) {
|
|
return false;
|
|
}
|
|
|
|
// If marked as 'always', bypass all other checks
|
|
if (entry.metadata?.always === true) {
|
|
return true;
|
|
}
|
|
|
|
// Check required binaries (all must be present)
|
|
const requiredBins = entry.metadata?.requires?.bins ?? [];
|
|
if (requiredBins.length > 0) {
|
|
for (const bin of requiredBins) {
|
|
if (hasBinary(bin)) {
|
|
continue;
|
|
}
|
|
if (eligibility?.remote?.hasBin?.(bin)) {
|
|
continue;
|
|
}
|
|
return false;
|
|
}
|
|
}
|
|
|
|
// Check anyBins (at least one must be present)
|
|
const requiredAnyBins = entry.metadata?.requires?.anyBins ?? [];
|
|
if (requiredAnyBins.length > 0) {
|
|
const anyFound =
|
|
requiredAnyBins.some((bin) => hasBinary(bin)) ||
|
|
eligibility?.remote?.hasAnyBin?.(requiredAnyBins);
|
|
if (!anyFound) {
|
|
return false;
|
|
}
|
|
}
|
|
|
|
// Check required environment variables
|
|
const requiredEnv = entry.metadata?.requires?.env ?? [];
|
|
if (requiredEnv.length > 0) {
|
|
for (const envName of requiredEnv) {
|
|
if (process.env[envName]) {
|
|
continue;
|
|
}
|
|
if (hookConfig?.env?.[envName]) {
|
|
continue;
|
|
}
|
|
return false;
|
|
}
|
|
}
|
|
|
|
// Check required config paths
|
|
const requiredConfig = entry.metadata?.requires?.config ?? [];
|
|
if (requiredConfig.length > 0) {
|
|
for (const configPath of requiredConfig) {
|
|
if (!isConfigPathTruthy(config, configPath)) {
|
|
return false;
|
|
}
|
|
}
|
|
}
|
|
|
|
return true;
|
|
}
|