refactor: reuse runtime requires evaluation

This commit is contained in:
Peter Steinberger
2026-02-17 00:44:47 +00:00
parent 5195179150
commit 7687f6cfcd
3 changed files with 87 additions and 100 deletions

View File

@@ -1,12 +1,13 @@
import type { OpenClawConfig, SkillConfig } from "../../config/config.js";
import type { SkillEligibilityContext, SkillEntry } from "./types.js";
import {
evaluateRuntimeRequires,
hasBinary,
isConfigPathTruthyWithDefaults,
resolveConfigPath,
resolveRuntimePlatform,
} from "../../shared/config-eval.js";
import { resolveSkillKey } from "./frontmatter.js";
import type { SkillEligibilityContext, SkillEntry } from "./types.js";
const DEFAULT_CONFIG_VALUES: Record<string, boolean> = {
"browser.enabled": true,
@@ -95,52 +96,17 @@ export function shouldIncludeSkill(params: {
return true;
}
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;
}
}
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;
}
}
const requiredEnv = entry.metadata?.requires?.env ?? [];
if (requiredEnv.length > 0) {
for (const envName of requiredEnv) {
if (process.env[envName]) {
continue;
}
if (skillConfig?.env?.[envName]) {
continue;
}
if (skillConfig?.apiKey && entry.metadata?.primaryEnv === envName) {
continue;
}
return false;
}
}
const requiredConfig = entry.metadata?.requires?.config ?? [];
if (requiredConfig.length > 0) {
for (const configPath of requiredConfig) {
if (!isConfigPathTruthy(config, configPath)) {
return false;
}
}
}
return true;
return evaluateRuntimeRequires({
requires: entry.metadata?.requires,
hasBin: hasBinary,
hasRemoteBin: eligibility?.remote?.hasBin,
hasAnyRemoteBin: eligibility?.remote?.hasAnyBin,
hasEnv: (envName) =>
Boolean(
process.env[envName] ||
skillConfig?.env?.[envName] ||
(skillConfig?.apiKey && entry.metadata?.primaryEnv === envName),
),
isConfigPathTruthy: (configPath) => isConfigPathTruthy(config, configPath),
});
}

View File

@@ -1,12 +1,13 @@
import type { OpenClawConfig, HookConfig } from "../config/config.js";
import type { HookEligibilityContext, HookEntry } from "./types.js";
import {
evaluateRuntimeRequires,
hasBinary,
isConfigPathTruthyWithDefaults,
resolveConfigPath,
resolveRuntimePlatform,
} from "../shared/config-eval.js";
import { resolveHookKey } from "./frontmatter.js";
import type { HookEligibilityContext, HookEntry } from "./types.js";
const DEFAULT_CONFIG_VALUES: Record<string, boolean> = {
"browser.enabled": true,
@@ -66,54 +67,12 @@ export function shouldIncludeHook(params: {
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;
return evaluateRuntimeRequires({
requires: entry.metadata?.requires,
hasBin: hasBinary,
hasRemoteBin: eligibility?.remote?.hasBin,
hasAnyRemoteBin: eligibility?.remote?.hasAnyBin,
hasEnv: (envName) => Boolean(process.env[envName] || hookConfig?.env?.[envName]),
isConfigPathTruthy: (configPath) => isConfigPathTruthy(config, configPath),
});
}

View File

@@ -41,6 +41,68 @@ export function isConfigPathTruthyWithDefaults(
return isTruthy(value);
}
export type RuntimeRequires = {
bins?: string[];
anyBins?: string[];
env?: string[];
config?: string[];
};
export function evaluateRuntimeRequires(params: {
requires?: RuntimeRequires;
hasBin: (bin: string) => boolean;
hasAnyRemoteBin?: (bins: string[]) => boolean;
hasRemoteBin?: (bin: string) => boolean;
hasEnv: (envName: string) => boolean;
isConfigPathTruthy: (pathStr: string) => boolean;
}): boolean {
const requires = params.requires;
if (!requires) {
return true;
}
const requiredBins = requires.bins ?? [];
if (requiredBins.length > 0) {
for (const bin of requiredBins) {
if (params.hasBin(bin)) {
continue;
}
if (params.hasRemoteBin?.(bin)) {
continue;
}
return false;
}
}
const requiredAnyBins = requires.anyBins ?? [];
if (requiredAnyBins.length > 0) {
const anyFound = requiredAnyBins.some((bin) => params.hasBin(bin));
if (!anyFound && !params.hasAnyRemoteBin?.(requiredAnyBins)) {
return false;
}
}
const requiredEnv = requires.env ?? [];
if (requiredEnv.length > 0) {
for (const envName of requiredEnv) {
if (!params.hasEnv(envName)) {
return false;
}
}
}
const requiredConfig = requires.config ?? [];
if (requiredConfig.length > 0) {
for (const configPath of requiredConfig) {
if (!params.isConfigPathTruthy(configPath)) {
return false;
}
}
}
return true;
}
export function resolveRuntimePlatform(): string {
return process.platform;
}