refactor(shared): share entry requirements evaluation

This commit is contained in:
Peter Steinberger
2026-02-15 18:39:29 +00:00
committed by Shadow
parent a5b87338e5
commit 137079fc21
3 changed files with 85 additions and 45 deletions

View File

@@ -1,7 +1,6 @@
import path from "node:path"; import path from "node:path";
import type { OpenClawConfig } from "../config/config.js"; import type { OpenClawConfig } from "../config/config.js";
import { resolveEmojiAndHomepage } from "../shared/entry-metadata.js"; import { evaluateEntryMetadataRequirements } from "../shared/entry-status.js";
import { evaluateRequirementsFromMetadataWithRemote } from "../shared/requirements.js";
import { CONFIG_DIR } from "../utils.js"; import { CONFIG_DIR } from "../utils.js";
import { import {
hasBinary, hasBinary,
@@ -184,23 +183,16 @@ function buildSkillStatus(
const allowBundled = resolveBundledAllowlist(config); const allowBundled = resolveBundledAllowlist(config);
const blockedByAllowlist = !isBundledSkillAllowed(entry, allowBundled); const blockedByAllowlist = !isBundledSkillAllowed(entry, allowBundled);
const always = entry.metadata?.always === true; const always = entry.metadata?.always === true;
const { emoji, homepage } = resolveEmojiAndHomepage({
metadata: entry.metadata,
frontmatter: entry.frontmatter,
});
const bundled = const bundled =
bundledNames && bundledNames.size > 0 bundledNames && bundledNames.size > 0
? bundledNames.has(entry.skill.name) ? bundledNames.has(entry.skill.name)
: entry.skill.source === "openclaw-bundled"; : entry.skill.source === "openclaw-bundled";
const { const { emoji, homepage, required, missing, requirementsSatisfied, configChecks } =
required, evaluateEntryMetadataRequirements({
missing,
eligible: requirementsSatisfied,
configChecks,
} = evaluateRequirementsFromMetadataWithRemote({
always, always,
metadata: entry.metadata, metadata: entry.metadata,
frontmatter: entry.frontmatter,
hasLocalBin: hasBinary, hasLocalBin: hasBinary,
localPlatform: process.platform, localPlatform: process.platform,
remote: eligibility?.remote, remote: eligibility?.remote,

View File

@@ -1,8 +1,7 @@
import path from "node:path"; import path from "node:path";
import type { OpenClawConfig } from "../config/config.js"; import type { OpenClawConfig } from "../config/config.js";
import type { HookEligibilityContext, HookEntry, HookInstallSpec } from "./types.js"; import type { HookEligibilityContext, HookEntry, HookInstallSpec } from "./types.js";
import { resolveEmojiAndHomepage } from "../shared/entry-metadata.js"; import { evaluateEntryMetadataRequirements } from "../shared/entry-status.js";
import { evaluateRequirementsFromMetadataWithRemote } from "../shared/requirements.js";
import { CONFIG_DIR } from "../utils.js"; import { CONFIG_DIR } from "../utils.js";
import { hasBinary, isConfigPathTruthy, resolveHookConfig } from "./config.js"; import { hasBinary, isConfigPathTruthy, resolveHookConfig } from "./config.js";
import { loadWorkspaceHookEntries } from "./workspace.js"; import { loadWorkspaceHookEntries } from "./workspace.js";
@@ -101,20 +100,13 @@ function buildHookStatus(
const managedByPlugin = entry.hook.source === "openclaw-plugin"; const managedByPlugin = entry.hook.source === "openclaw-plugin";
const disabled = managedByPlugin ? false : hookConfig?.enabled === false; const disabled = managedByPlugin ? false : hookConfig?.enabled === false;
const always = entry.metadata?.always === true; const always = entry.metadata?.always === true;
const { emoji, homepage } = resolveEmojiAndHomepage({
metadata: entry.metadata,
frontmatter: entry.frontmatter,
});
const events = entry.metadata?.events ?? []; const events = entry.metadata?.events ?? [];
const { const { emoji, homepage, required, missing, requirementsSatisfied, configChecks } =
required, evaluateEntryMetadataRequirements({
missing,
eligible: requirementsSatisfied,
configChecks,
} = evaluateRequirementsFromMetadataWithRemote({
always, always,
metadata: entry.metadata, metadata: entry.metadata,
frontmatter: entry.frontmatter,
hasLocalBin: hasBinary, hasLocalBin: hasBinary,
localPlatform: process.platform, localPlatform: process.platform,
remote: eligibility?.remote, remote: eligibility?.remote,

View File

@@ -0,0 +1,56 @@
import { resolveEmojiAndHomepage } from "./entry-metadata.js";
import {
evaluateRequirementsFromMetadataWithRemote,
type RequirementConfigCheck,
type Requirements,
type RequirementsMetadata,
} from "./requirements.js";
export function evaluateEntryMetadataRequirements(params: {
always: boolean;
metadata?: (RequirementsMetadata & { emoji?: string; homepage?: string }) | null;
frontmatter?: {
emoji?: string;
homepage?: string;
website?: string;
url?: string;
} | null;
hasLocalBin: (bin: string) => boolean;
localPlatform: string;
remote?: {
hasBin?: (bin: string) => boolean;
hasAnyBin?: (bins: string[]) => boolean;
platforms?: string[];
};
isEnvSatisfied: (envName: string) => boolean;
isConfigSatisfied: (pathStr: string) => boolean;
}): {
emoji?: string;
homepage?: string;
required: Requirements;
missing: Requirements;
requirementsSatisfied: boolean;
configChecks: RequirementConfigCheck[];
} {
const { emoji, homepage } = resolveEmojiAndHomepage({
metadata: params.metadata,
frontmatter: params.frontmatter,
});
const { required, missing, eligible, configChecks } = evaluateRequirementsFromMetadataWithRemote({
always: params.always,
metadata: params.metadata ?? undefined,
hasLocalBin: params.hasLocalBin,
localPlatform: params.localPlatform,
remote: params.remote,
isEnvSatisfied: params.isEnvSatisfied,
isConfigSatisfied: params.isConfigSatisfied,
});
return {
...(emoji ? { emoji } : {}),
...(homepage ? { homepage } : {}),
required,
missing,
requirementsSatisfied: eligible,
configChecks,
};
}