cli: expose capabilities in skills subcommands

This commit is contained in:
Vincent Koc
2026-02-27 08:56:32 -08:00
parent e5e97ca11a
commit 5ceb39098c

View File

@@ -1,6 +1,9 @@
import type { Command } from "commander";
import { resolveAgentWorkspaceDir, resolveDefaultAgentId } from "../agents/agent-scope.js";
import type { SkillStatusReport } from "../agents/skills-status.js";
import { loadConfig } from "../config/config.js";
import { loggingState } from "../logging/state.js";
import { createSubsystemLogger } from "../logging/subsystem.js";
import { defaultRuntime } from "../runtime.js";
import { formatDocsLink } from "../terminal/links.js";
import { theme } from "../terminal/theme.js";
@@ -13,9 +16,28 @@ export type {
} from "./skills-cli.format.js";
export { formatSkillInfo, formatSkillsCheck, formatSkillsList } from "./skills-cli.format.js";
type SkillStatusReport = Awaited<
ReturnType<(typeof import("../agents/skills-status.js"))["buildWorkspaceSkillStatus"]>
>;
const log = createSubsystemLogger("skills/cli");
/** Build a structured summary of the skills report for JSON file logging. */
function buildStructuredReport(report: SkillStatusReport) {
const eligible = report.skills.filter((s) => s.eligible);
const blocked = report.skills.filter((s) => s.scanResult?.severity === "critical");
const disabled = report.skills.filter((s) => s.disabled);
return {
total: report.skills.length,
eligible: eligible.length,
blocked: blocked.length,
disabled: disabled.length,
missing: report.skills.length - eligible.length - blocked.length - disabled.length,
skills: report.skills.map((s) => ({
name: s.name,
source: s.source,
eligible: s.eligible,
scanSeverity: s.scanResult?.severity ?? "clean",
capabilities: s.capabilities,
})),
};
}
async function loadSkillsStatusReport(): Promise<SkillStatusReport> {
const config = loadConfig();
@@ -24,10 +46,19 @@ async function loadSkillsStatusReport(): Promise<SkillStatusReport> {
return buildWorkspaceSkillStatus(workspaceDir, { config });
}
async function runSkillsAction(render: (report: SkillStatusReport) => string): Promise<void> {
async function runSkillsAction(
render: (report: SkillStatusReport) => string,
command: string,
): Promise<void> {
try {
const report = await loadSkillsStatusReport();
defaultRuntime.log(render(report));
const formatted = render(report);
const rawLog = loggingState.rawConsole?.log ?? defaultRuntime.log;
rawLog(formatted);
log.info(`${command} completed`, {
command,
...buildStructuredReport(report),
});
} catch (err) {
defaultRuntime.error(String(err));
defaultRuntime.exit(1);
@@ -54,7 +85,7 @@ export function registerSkillsCli(program: Command) {
.option("--eligible", "Show only eligible (ready to use) skills", false)
.option("-v, --verbose", "Show more details including missing requirements", false)
.action(async (opts) => {
await runSkillsAction((report) => formatSkillsList(report, opts));
await runSkillsAction((report) => formatSkillsList(report, opts), "skills list");
});
skills
@@ -63,7 +94,7 @@ export function registerSkillsCli(program: Command) {
.argument("<name>", "Skill name")
.option("--json", "Output as JSON", false)
.action(async (name, opts) => {
await runSkillsAction((report) => formatSkillInfo(report, name, opts));
await runSkillsAction((report) => formatSkillInfo(report, name, opts), `skills info ${name}`);
});
skills
@@ -71,11 +102,11 @@ export function registerSkillsCli(program: Command) {
.description("Check which skills are ready vs missing requirements")
.option("--json", "Output as JSON", false)
.action(async (opts) => {
await runSkillsAction((report) => formatSkillsCheck(report, opts));
await runSkillsAction((report) => formatSkillsCheck(report, opts), "skills check");
});
// Default action (no subcommand) - show list
skills.action(async () => {
await runSkillsAction((report) => formatSkillsList(report, {}));
await runSkillsAction((report) => formatSkillsList(report, {}), "skills list");
});
}