@gguf/claw
Version:
Multi-channel AI gateway with extensible messaging integrations
173 lines (170 loc) • 6.57 kB
JavaScript
import { t as __exportAll } from "./rolldown-runtime-Cbj13DAv.js";
import { U as CONFIG_DIR, o as createSubsystemLogger } from "./entry.js";
import { t as evaluateEntryMetadataRequirementsForCurrentPlatform } from "./entry-status-BQkcejku.js";
import { d as hasBinary } from "./frontmatter-D-YR-Ghi.js";
import { _ as isBundledSkillAllowed, b as resolveSkillConfig, c as resolveBundledSkillsDir, i as loadWorkspaceSkillEntries, t as resolveSkillsInstallPreferences, v as isConfigPathTruthy, y as resolveBundledAllowlist } from "./skills-DJmGZazd.js";
import path from "node:path";
import { loadSkillsFromDir } from "@mariozechner/pi-coding-agent";
//#region src/agents/skills/bundled-context.ts
const skillsLogger = createSubsystemLogger("skills");
let hasWarnedMissingBundledDir = false;
let cachedBundledContext = null;
function resolveBundledSkillsContext(opts = {}) {
const dir = resolveBundledSkillsDir(opts);
const names = /* @__PURE__ */ new Set();
if (!dir) {
if (!hasWarnedMissingBundledDir) {
hasWarnedMissingBundledDir = true;
skillsLogger.warn("Bundled skills directory could not be resolved; built-in skills may be missing.");
}
return {
dir,
names
};
}
if (cachedBundledContext?.dir === dir) return {
dir,
names: new Set(cachedBundledContext.names)
};
const result = loadSkillsFromDir({
dir,
source: "openclaw-bundled"
});
for (const skill of result.skills) if (skill.name.trim()) names.add(skill.name);
cachedBundledContext = {
dir,
names: new Set(names)
};
return {
dir,
names
};
}
//#endregion
//#region src/agents/skills-status.ts
var skills_status_exports = /* @__PURE__ */ __exportAll({ buildWorkspaceSkillStatus: () => buildWorkspaceSkillStatus });
function resolveSkillKey(entry) {
return entry.metadata?.skillKey ?? entry.skill.name;
}
function selectPreferredInstallSpec(install, prefs) {
if (install.length === 0) return;
const indexed = install.map((spec, index) => ({
spec,
index
}));
const findKind = (kind) => indexed.find((item) => item.spec.kind === kind);
const brewSpec = findKind("brew");
const nodeSpec = findKind("node");
const goSpec = findKind("go");
const uvSpec = findKind("uv");
const downloadSpec = findKind("download");
const brewAvailable = hasBinary("brew");
const pickers = [
() => prefs.preferBrew && brewAvailable ? brewSpec : void 0,
() => uvSpec,
() => nodeSpec,
() => brewAvailable ? brewSpec : void 0,
() => goSpec,
() => downloadSpec,
() => brewSpec,
() => indexed[0]
];
for (const pick of pickers) {
const selected = pick();
if (selected) return selected;
}
}
function normalizeInstallOptions(entry, prefs) {
const requiredOs = entry.metadata?.os ?? [];
if (requiredOs.length > 0 && !requiredOs.includes(process.platform)) return [];
const install = entry.metadata?.install ?? [];
if (install.length === 0) return [];
const platform = process.platform;
const filtered = install.filter((spec) => {
const osList = spec.os ?? [];
return osList.length === 0 || osList.includes(platform);
});
if (filtered.length === 0) return [];
const toOption = (spec, index) => {
const id = (spec.id ?? `${spec.kind}-${index}`).trim();
const bins = spec.bins ?? [];
let label = (spec.label ?? "").trim();
if (spec.kind === "node" && spec.package) label = `Install ${spec.package} (${prefs.nodeManager})`;
if (!label) if (spec.kind === "brew" && spec.formula) label = `Install ${spec.formula} (brew)`;
else if (spec.kind === "node" && spec.package) label = `Install ${spec.package} (${prefs.nodeManager})`;
else if (spec.kind === "go" && spec.module) label = `Install ${spec.module} (go)`;
else if (spec.kind === "uv" && spec.package) label = `Install ${spec.package} (uv)`;
else if (spec.kind === "download" && spec.url) {
const url = spec.url.trim();
const last = url.split("/").pop();
label = `Download ${last && last.length > 0 ? last : url}`;
} else label = "Run installer";
return {
id,
kind: spec.kind,
label,
bins
};
};
if (filtered.every((spec) => spec.kind === "download")) return filtered.map((spec, index) => toOption(spec, index));
const preferred = selectPreferredInstallSpec(filtered, prefs);
if (!preferred) return [];
return [toOption(preferred.spec, preferred.index)];
}
function buildSkillStatus(entry, config, prefs, eligibility, bundledNames) {
const skillKey = resolveSkillKey(entry);
const skillConfig = resolveSkillConfig(config, skillKey);
const disabled = skillConfig?.enabled === false;
const blockedByAllowlist = !isBundledSkillAllowed(entry, resolveBundledAllowlist(config));
const always = entry.metadata?.always === true;
const isEnvSatisfied = (envName) => Boolean(process.env[envName] || skillConfig?.env?.[envName] || skillConfig?.apiKey && entry.metadata?.primaryEnv === envName);
const isConfigSatisfied = (pathStr) => isConfigPathTruthy(config, pathStr);
const bundled = bundledNames && bundledNames.size > 0 ? bundledNames.has(entry.skill.name) : entry.skill.source === "openclaw-bundled";
const { emoji, homepage, required, missing, requirementsSatisfied, configChecks } = evaluateEntryMetadataRequirementsForCurrentPlatform({
always,
metadata: entry.metadata,
frontmatter: entry.frontmatter,
hasLocalBin: hasBinary,
remote: eligibility?.remote,
isEnvSatisfied,
isConfigSatisfied
});
const eligible = !disabled && !blockedByAllowlist && requirementsSatisfied;
return {
name: entry.skill.name,
description: entry.skill.description,
source: entry.skill.source,
bundled,
filePath: entry.skill.filePath,
baseDir: entry.skill.baseDir,
skillKey,
primaryEnv: entry.metadata?.primaryEnv,
emoji,
homepage,
always,
disabled,
blockedByAllowlist,
eligible,
requirements: required,
missing,
configChecks,
install: normalizeInstallOptions(entry, prefs ?? resolveSkillsInstallPreferences(config))
};
}
function buildWorkspaceSkillStatus(workspaceDir, opts) {
const managedSkillsDir = opts?.managedSkillsDir ?? path.join(CONFIG_DIR, "skills");
const bundledContext = resolveBundledSkillsContext();
const skillEntries = opts?.entries ?? loadWorkspaceSkillEntries(workspaceDir, {
config: opts?.config,
managedSkillsDir,
bundledSkillsDir: bundledContext.dir
});
const prefs = resolveSkillsInstallPreferences(opts?.config);
return {
workspaceDir,
managedSkillsDir,
skills: skillEntries.map((entry) => buildSkillStatus(entry, opts?.config, prefs, opts?.eligibility, bundledContext.names))
};
}
//#endregion
export { skills_status_exports as n, buildWorkspaceSkillStatus as t };