290 lines
12 KiB
JavaScript
290 lines
12 KiB
JavaScript
import "./paths-BDd7_JUB.js";
|
|
import { c as resolveDefaultAgentId, s as resolveAgentWorkspaceDir } from "./agent-scope-CrgUOY3f.js";
|
|
import { R as theme, c as defaultRuntime } from "./subsystem-46MXi6Ip.js";
|
|
import { _ as shortenHomePath } from "./utils-Dg0Xbl6w.js";
|
|
import "./exec-CTo4hK94.js";
|
|
import "./model-selection-Cp1maz7B.js";
|
|
import "./github-copilot-token-VZsS4013.js";
|
|
import { t as formatCliCommand } from "./command-format-BQK1OIvH.js";
|
|
import "./boolean-CE7i9tBR.js";
|
|
import "./env-DOcCob95.js";
|
|
import { r as loadConfig } from "./config-BAN8QfW5.js";
|
|
import "./manifest-registry-BFpLJJDB.js";
|
|
import "./skills-C4b1FA1e.js";
|
|
import { t as formatDocsLink } from "./links-C9fyAH-V.js";
|
|
import { t as renderTable } from "./table-DuNe7Qes.js";
|
|
import { t as buildWorkspaceSkillStatus } from "./skills-status-CSCMqNZP.js";
|
|
|
|
//#region src/cli/skills-cli.ts
|
|
function appendClawHubHint(output, json) {
|
|
if (json) return output;
|
|
return `${output}\n\nTip: use \`npx clawhub\` to search, install, and sync skills.`;
|
|
}
|
|
function formatSkillStatus(skill) {
|
|
if (skill.eligible) return theme.success("✓ ready");
|
|
if (skill.disabled) return theme.warn("⏸ disabled");
|
|
if (skill.blockedByAllowlist) return theme.warn("🚫 blocked");
|
|
return theme.error("✗ missing");
|
|
}
|
|
function formatSkillName(skill) {
|
|
return `${skill.emoji ?? "📦"} ${theme.command(skill.name)}`;
|
|
}
|
|
function formatSkillMissingSummary(skill) {
|
|
const missing = [];
|
|
if (skill.missing.bins.length > 0) missing.push(`bins: ${skill.missing.bins.join(", ")}`);
|
|
if (skill.missing.anyBins.length > 0) missing.push(`anyBins: ${skill.missing.anyBins.join(", ")}`);
|
|
if (skill.missing.env.length > 0) missing.push(`env: ${skill.missing.env.join(", ")}`);
|
|
if (skill.missing.config.length > 0) missing.push(`config: ${skill.missing.config.join(", ")}`);
|
|
if (skill.missing.os.length > 0) missing.push(`os: ${skill.missing.os.join(", ")}`);
|
|
return missing.join("; ");
|
|
}
|
|
/**
|
|
* Format the skills list output
|
|
*/
|
|
function formatSkillsList(report, opts) {
|
|
const skills = opts.eligible ? report.skills.filter((s) => s.eligible) : report.skills;
|
|
if (opts.json) {
|
|
const jsonReport = {
|
|
workspaceDir: report.workspaceDir,
|
|
managedSkillsDir: report.managedSkillsDir,
|
|
skills: skills.map((s) => ({
|
|
name: s.name,
|
|
description: s.description,
|
|
emoji: s.emoji,
|
|
eligible: s.eligible,
|
|
disabled: s.disabled,
|
|
blockedByAllowlist: s.blockedByAllowlist,
|
|
source: s.source,
|
|
bundled: s.bundled,
|
|
primaryEnv: s.primaryEnv,
|
|
homepage: s.homepage,
|
|
missing: s.missing
|
|
}))
|
|
};
|
|
return JSON.stringify(jsonReport, null, 2);
|
|
}
|
|
if (skills.length === 0) return appendClawHubHint(opts.eligible ? `No eligible skills found. Run \`${formatCliCommand("openclaw skills list")}\` to see all skills.` : "No skills found.", opts.json);
|
|
const eligible = skills.filter((s) => s.eligible);
|
|
const tableWidth = Math.max(60, (process.stdout.columns ?? 120) - 1);
|
|
const rows = skills.map((skill) => {
|
|
const missing = formatSkillMissingSummary(skill);
|
|
return {
|
|
Status: formatSkillStatus(skill),
|
|
Skill: formatSkillName(skill),
|
|
Description: theme.muted(skill.description),
|
|
Source: skill.source ?? "",
|
|
Missing: missing ? theme.warn(missing) : ""
|
|
};
|
|
});
|
|
const columns = [
|
|
{
|
|
key: "Status",
|
|
header: "Status",
|
|
minWidth: 10
|
|
},
|
|
{
|
|
key: "Skill",
|
|
header: "Skill",
|
|
minWidth: 18,
|
|
flex: true
|
|
},
|
|
{
|
|
key: "Description",
|
|
header: "Description",
|
|
minWidth: 24,
|
|
flex: true
|
|
},
|
|
{
|
|
key: "Source",
|
|
header: "Source",
|
|
minWidth: 10
|
|
}
|
|
];
|
|
if (opts.verbose) columns.push({
|
|
key: "Missing",
|
|
header: "Missing",
|
|
minWidth: 18,
|
|
flex: true
|
|
});
|
|
const lines = [];
|
|
lines.push(`${theme.heading("Skills")} ${theme.muted(`(${eligible.length}/${skills.length} ready)`)}`);
|
|
lines.push(renderTable({
|
|
width: tableWidth,
|
|
columns,
|
|
rows
|
|
}).trimEnd());
|
|
return appendClawHubHint(lines.join("\n"), opts.json);
|
|
}
|
|
/**
|
|
* Format detailed info for a single skill
|
|
*/
|
|
function formatSkillInfo(report, skillName, opts) {
|
|
const skill = report.skills.find((s) => s.name === skillName || s.skillKey === skillName);
|
|
if (!skill) {
|
|
if (opts.json) return JSON.stringify({
|
|
error: "not found",
|
|
skill: skillName
|
|
}, null, 2);
|
|
return appendClawHubHint(`Skill "${skillName}" not found. Run \`${formatCliCommand("openclaw skills list")}\` to see available skills.`, opts.json);
|
|
}
|
|
if (opts.json) return JSON.stringify(skill, null, 2);
|
|
const lines = [];
|
|
const emoji = skill.emoji ?? "📦";
|
|
const status = skill.eligible ? theme.success("✓ Ready") : skill.disabled ? theme.warn("⏸ Disabled") : skill.blockedByAllowlist ? theme.warn("🚫 Blocked by allowlist") : theme.error("✗ Missing requirements");
|
|
lines.push(`${emoji} ${theme.heading(skill.name)} ${status}`);
|
|
lines.push("");
|
|
lines.push(skill.description);
|
|
lines.push("");
|
|
lines.push(theme.heading("Details:"));
|
|
lines.push(`${theme.muted(" Source:")} ${skill.source}`);
|
|
lines.push(`${theme.muted(" Path:")} ${shortenHomePath(skill.filePath)}`);
|
|
if (skill.homepage) lines.push(`${theme.muted(" Homepage:")} ${skill.homepage}`);
|
|
if (skill.primaryEnv) lines.push(`${theme.muted(" Primary env:")} ${skill.primaryEnv}`);
|
|
if (skill.requirements.bins.length > 0 || skill.requirements.anyBins.length > 0 || skill.requirements.env.length > 0 || skill.requirements.config.length > 0 || skill.requirements.os.length > 0) {
|
|
lines.push("");
|
|
lines.push(theme.heading("Requirements:"));
|
|
if (skill.requirements.bins.length > 0) {
|
|
const binsStatus = skill.requirements.bins.map((bin) => {
|
|
return skill.missing.bins.includes(bin) ? theme.error(`✗ ${bin}`) : theme.success(`✓ ${bin}`);
|
|
});
|
|
lines.push(`${theme.muted(" Binaries:")} ${binsStatus.join(", ")}`);
|
|
}
|
|
if (skill.requirements.anyBins.length > 0) {
|
|
const anyBinsMissing = skill.missing.anyBins.length > 0;
|
|
const anyBinsStatus = skill.requirements.anyBins.map((bin) => {
|
|
return anyBinsMissing ? theme.error(`✗ ${bin}`) : theme.success(`✓ ${bin}`);
|
|
});
|
|
lines.push(`${theme.muted(" Any binaries:")} ${anyBinsStatus.join(", ")}`);
|
|
}
|
|
if (skill.requirements.env.length > 0) {
|
|
const envStatus = skill.requirements.env.map((env) => {
|
|
return skill.missing.env.includes(env) ? theme.error(`✗ ${env}`) : theme.success(`✓ ${env}`);
|
|
});
|
|
lines.push(`${theme.muted(" Environment:")} ${envStatus.join(", ")}`);
|
|
}
|
|
if (skill.requirements.config.length > 0) {
|
|
const configStatus = skill.requirements.config.map((cfg) => {
|
|
return skill.missing.config.includes(cfg) ? theme.error(`✗ ${cfg}`) : theme.success(`✓ ${cfg}`);
|
|
});
|
|
lines.push(`${theme.muted(" Config:")} ${configStatus.join(", ")}`);
|
|
}
|
|
if (skill.requirements.os.length > 0) {
|
|
const osStatus = skill.requirements.os.map((osName) => {
|
|
return skill.missing.os.includes(osName) ? theme.error(`✗ ${osName}`) : theme.success(`✓ ${osName}`);
|
|
});
|
|
lines.push(`${theme.muted(" OS:")} ${osStatus.join(", ")}`);
|
|
}
|
|
}
|
|
if (skill.install.length > 0 && !skill.eligible) {
|
|
lines.push("");
|
|
lines.push(theme.heading("Install options:"));
|
|
for (const inst of skill.install) lines.push(` ${theme.warn("→")} ${inst.label}`);
|
|
}
|
|
return appendClawHubHint(lines.join("\n"), opts.json);
|
|
}
|
|
/**
|
|
* Format a check/summary of all skills status
|
|
*/
|
|
function formatSkillsCheck(report, opts) {
|
|
const eligible = report.skills.filter((s) => s.eligible);
|
|
const disabled = report.skills.filter((s) => s.disabled);
|
|
const blocked = report.skills.filter((s) => s.blockedByAllowlist && !s.disabled);
|
|
const missingReqs = report.skills.filter((s) => !s.eligible && !s.disabled && !s.blockedByAllowlist);
|
|
if (opts.json) return JSON.stringify({
|
|
summary: {
|
|
total: report.skills.length,
|
|
eligible: eligible.length,
|
|
disabled: disabled.length,
|
|
blocked: blocked.length,
|
|
missingRequirements: missingReqs.length
|
|
},
|
|
eligible: eligible.map((s) => s.name),
|
|
disabled: disabled.map((s) => s.name),
|
|
blocked: blocked.map((s) => s.name),
|
|
missingRequirements: missingReqs.map((s) => ({
|
|
name: s.name,
|
|
missing: s.missing,
|
|
install: s.install
|
|
}))
|
|
}, null, 2);
|
|
const lines = [];
|
|
lines.push(theme.heading("Skills Status Check"));
|
|
lines.push("");
|
|
lines.push(`${theme.muted("Total:")} ${report.skills.length}`);
|
|
lines.push(`${theme.success("✓")} ${theme.muted("Eligible:")} ${eligible.length}`);
|
|
lines.push(`${theme.warn("⏸")} ${theme.muted("Disabled:")} ${disabled.length}`);
|
|
lines.push(`${theme.warn("🚫")} ${theme.muted("Blocked by allowlist:")} ${blocked.length}`);
|
|
lines.push(`${theme.error("✗")} ${theme.muted("Missing requirements:")} ${missingReqs.length}`);
|
|
if (eligible.length > 0) {
|
|
lines.push("");
|
|
lines.push(theme.heading("Ready to use:"));
|
|
for (const skill of eligible) {
|
|
const emoji = skill.emoji ?? "📦";
|
|
lines.push(` ${emoji} ${skill.name}`);
|
|
}
|
|
}
|
|
if (missingReqs.length > 0) {
|
|
lines.push("");
|
|
lines.push(theme.heading("Missing requirements:"));
|
|
for (const skill of missingReqs) {
|
|
const emoji = skill.emoji ?? "📦";
|
|
const missing = [];
|
|
if (skill.missing.bins.length > 0) missing.push(`bins: ${skill.missing.bins.join(", ")}`);
|
|
if (skill.missing.anyBins.length > 0) missing.push(`anyBins: ${skill.missing.anyBins.join(", ")}`);
|
|
if (skill.missing.env.length > 0) missing.push(`env: ${skill.missing.env.join(", ")}`);
|
|
if (skill.missing.config.length > 0) missing.push(`config: ${skill.missing.config.join(", ")}`);
|
|
if (skill.missing.os.length > 0) missing.push(`os: ${skill.missing.os.join(", ")}`);
|
|
lines.push(` ${emoji} ${skill.name} ${theme.muted(`(${missing.join("; ")})`)}`);
|
|
}
|
|
}
|
|
return appendClawHubHint(lines.join("\n"), opts.json);
|
|
}
|
|
/**
|
|
* Register the skills CLI commands
|
|
*/
|
|
function registerSkillsCli(program) {
|
|
const skills = program.command("skills").description("List and inspect available skills").addHelpText("after", () => `\n${theme.muted("Docs:")} ${formatDocsLink("/cli/skills", "docs.openclaw.ai/cli/skills")}\n`);
|
|
skills.command("list").description("List all available skills").option("--json", "Output as JSON", false).option("--eligible", "Show only eligible (ready to use) skills", false).option("-v, --verbose", "Show more details including missing requirements", false).action(async (opts) => {
|
|
try {
|
|
const config = loadConfig();
|
|
const report = buildWorkspaceSkillStatus(resolveAgentWorkspaceDir(config, resolveDefaultAgentId(config)), { config });
|
|
defaultRuntime.log(formatSkillsList(report, opts));
|
|
} catch (err) {
|
|
defaultRuntime.error(String(err));
|
|
defaultRuntime.exit(1);
|
|
}
|
|
});
|
|
skills.command("info").description("Show detailed information about a skill").argument("<name>", "Skill name").option("--json", "Output as JSON", false).action(async (name, opts) => {
|
|
try {
|
|
const config = loadConfig();
|
|
const report = buildWorkspaceSkillStatus(resolveAgentWorkspaceDir(config, resolveDefaultAgentId(config)), { config });
|
|
defaultRuntime.log(formatSkillInfo(report, name, opts));
|
|
} catch (err) {
|
|
defaultRuntime.error(String(err));
|
|
defaultRuntime.exit(1);
|
|
}
|
|
});
|
|
skills.command("check").description("Check which skills are ready vs missing requirements").option("--json", "Output as JSON", false).action(async (opts) => {
|
|
try {
|
|
const config = loadConfig();
|
|
const report = buildWorkspaceSkillStatus(resolveAgentWorkspaceDir(config, resolveDefaultAgentId(config)), { config });
|
|
defaultRuntime.log(formatSkillsCheck(report, opts));
|
|
} catch (err) {
|
|
defaultRuntime.error(String(err));
|
|
defaultRuntime.exit(1);
|
|
}
|
|
});
|
|
skills.action(async () => {
|
|
try {
|
|
const config = loadConfig();
|
|
const report = buildWorkspaceSkillStatus(resolveAgentWorkspaceDir(config, resolveDefaultAgentId(config)), { config });
|
|
defaultRuntime.log(formatSkillsList(report, {}));
|
|
} catch (err) {
|
|
defaultRuntime.error(String(err));
|
|
defaultRuntime.exit(1);
|
|
}
|
|
});
|
|
}
|
|
|
|
//#endregion
|
|
export { registerSkillsCli }; |