From b2c273745209c9221ca35aeccdfb51db15b38df0 Mon Sep 17 00:00:00 2001 From: Peter Steinberger Date: Thu, 19 Feb 2026 00:17:24 +0000 Subject: [PATCH] refactor(shared): reuse runtime entry requirement evaluator --- src/agents/skills-status.ts | 34 ++++++++++++++++++---------------- src/hooks/hooks-status.ts | 25 ++++++++++++++----------- src/shared/entry-status.ts | 13 +++++++++++++ 3 files changed, 45 insertions(+), 27 deletions(-) diff --git a/src/agents/skills-status.ts b/src/agents/skills-status.ts index 7d9f2a0cde..64f38ed9fd 100644 --- a/src/agents/skills-status.ts +++ b/src/agents/skills-status.ts @@ -1,6 +1,6 @@ import path from "node:path"; import type { OpenClawConfig } from "../config/config.js"; -import { evaluateEntryMetadataRequirements } from "../shared/entry-status.js"; +import { evaluateEntryMetadataRequirementsForCurrentPlatform } from "../shared/entry-status.js"; import type { RequirementConfigCheck, Requirements } from "../shared/requirements.js"; import { CONFIG_DIR } from "../utils.js"; import { @@ -179,27 +179,29 @@ function buildSkillStatus( const allowBundled = resolveBundledAllowlist(config); const blockedByAllowlist = !isBundledSkillAllowed(entry, allowBundled); const always = entry.metadata?.always === true; + const isEnvSatisfied = (envName: string) => + Boolean( + process.env[envName] || + skillConfig?.env?.[envName] || + (skillConfig?.apiKey && entry.metadata?.primaryEnv === envName), + ); + const isConfigSatisfied = (pathStr: string) => isConfigPathTruthy(config, pathStr); const bundled = bundledNames && bundledNames.size > 0 ? bundledNames.has(entry.skill.name) : entry.skill.source === "openclaw-bundled"; + const requirementStatus = evaluateEntryMetadataRequirementsForCurrentPlatform({ + always, + metadata: entry.metadata, + frontmatter: entry.frontmatter, + hasLocalBin: hasBinary, + remote: eligibility?.remote, + isEnvSatisfied, + isConfigSatisfied, + }); const { emoji, homepage, required, missing, requirementsSatisfied, configChecks } = - evaluateEntryMetadataRequirements({ - always, - metadata: entry.metadata, - frontmatter: entry.frontmatter, - hasLocalBin: hasBinary, - localPlatform: process.platform, - remote: eligibility?.remote, - isEnvSatisfied: (envName) => - Boolean( - process.env[envName] || - skillConfig?.env?.[envName] || - (skillConfig?.apiKey && entry.metadata?.primaryEnv === envName), - ), - isConfigSatisfied: (pathStr) => isConfigPathTruthy(config, pathStr), - }); + requirementStatus; const eligible = !disabled && !blockedByAllowlist && requirementsSatisfied; return { diff --git a/src/hooks/hooks-status.ts b/src/hooks/hooks-status.ts index 2b6ca8eaf3..a65cee2487 100644 --- a/src/hooks/hooks-status.ts +++ b/src/hooks/hooks-status.ts @@ -1,6 +1,6 @@ import path from "node:path"; import type { OpenClawConfig } from "../config/config.js"; -import { evaluateEntryMetadataRequirements } from "../shared/entry-status.js"; +import { evaluateEntryMetadataRequirementsForCurrentPlatform } from "../shared/entry-status.js"; import type { RequirementConfigCheck, Requirements } from "../shared/requirements.js"; import { CONFIG_DIR } from "../utils.js"; import { hasBinary, isConfigPathTruthy, resolveHookConfig } from "./config.js"; @@ -87,18 +87,21 @@ function buildHookStatus( const disabled = managedByPlugin ? false : hookConfig?.enabled === false; const always = entry.metadata?.always === true; const events = entry.metadata?.events ?? []; + const isEnvSatisfied = (envName: string) => + Boolean(process.env[envName] || hookConfig?.env?.[envName]); + const isConfigSatisfied = (pathStr: string) => isConfigPathTruthy(config, pathStr); + const requirementStatus = evaluateEntryMetadataRequirementsForCurrentPlatform({ + always, + metadata: entry.metadata, + frontmatter: entry.frontmatter, + hasLocalBin: hasBinary, + remote: eligibility?.remote, + isEnvSatisfied, + isConfigSatisfied, + }); const { emoji, homepage, required, missing, requirementsSatisfied, configChecks } = - evaluateEntryMetadataRequirements({ - always, - metadata: entry.metadata, - frontmatter: entry.frontmatter, - hasLocalBin: hasBinary, - localPlatform: process.platform, - remote: eligibility?.remote, - isEnvSatisfied: (envName) => Boolean(process.env[envName] || hookConfig?.env?.[envName]), - isConfigSatisfied: (pathStr) => isConfigPathTruthy(config, pathStr), - }); + requirementStatus; const eligible = !disabled && requirementsSatisfied; diff --git a/src/shared/entry-status.ts b/src/shared/entry-status.ts index 886c49205a..009e90a06f 100644 --- a/src/shared/entry-status.ts +++ b/src/shared/entry-status.ts @@ -7,6 +7,10 @@ import { type RequirementsMetadata, } from "./requirements.js"; +export type EntryMetadataRequirementsParams = Parameters< + typeof evaluateEntryMetadataRequirements +>[0]; + export function evaluateEntryMetadataRequirements(params: { always: boolean; metadata?: (RequirementsMetadata & { emoji?: string; homepage?: string }) | null; @@ -51,3 +55,12 @@ export function evaluateEntryMetadataRequirements(params: { configChecks, }; } + +export function evaluateEntryMetadataRequirementsForCurrentPlatform( + params: Omit, +): ReturnType { + return evaluateEntryMetadataRequirements({ + ...params, + localPlatform: process.platform, + }); +}