Merge 749928c35487d55100477496ba05ffc40b09be2d into 598f1826d8b2bc969aace2c6459824737667218c
This commit is contained in:
commit
0f45e42fd5
@ -94,6 +94,52 @@ function formatSkillMissingSummary(skill: SkillStatusEntry): string {
|
||||
return missing.join("; ");
|
||||
}
|
||||
|
||||
function normalizeSkillLookupToken(value: string): string {
|
||||
return value
|
||||
.trim()
|
||||
.toLowerCase()
|
||||
.replace(/[\s_/]+/g, "-")
|
||||
.replace(/[^a-z0-9-]+/g, "")
|
||||
.replace(/-+/g, "-")
|
||||
.replace(/^-+|-+$/g, "");
|
||||
}
|
||||
|
||||
function resolveSkillByName(
|
||||
report: SkillStatusReport,
|
||||
requestedName: string,
|
||||
): SkillStatusEntry | null {
|
||||
const raw = requestedName.trim();
|
||||
if (!raw) {
|
||||
return null;
|
||||
}
|
||||
|
||||
const direct = report.skills.find((s) => s.name === raw || s.skillKey === raw);
|
||||
if (direct) {
|
||||
return direct;
|
||||
}
|
||||
|
||||
const lower = raw.toLowerCase();
|
||||
const caseInsensitive = report.skills.find(
|
||||
(s) => s.name.toLowerCase() === lower || s.skillKey.toLowerCase() === lower,
|
||||
);
|
||||
if (caseInsensitive) {
|
||||
return caseInsensitive;
|
||||
}
|
||||
|
||||
const normalized = normalizeSkillLookupToken(raw);
|
||||
if (!normalized) {
|
||||
return null;
|
||||
}
|
||||
|
||||
return (
|
||||
report.skills.find(
|
||||
(s) =>
|
||||
normalizeSkillLookupToken(s.name) === normalized ||
|
||||
normalizeSkillLookupToken(s.skillKey) === normalized,
|
||||
) ?? null
|
||||
);
|
||||
}
|
||||
|
||||
export function formatSkillsList(report: SkillStatusReport, opts: SkillsListOptions): string {
|
||||
const skills = opts.eligible ? report.skills.filter((s) => s.eligible) : report.skills;
|
||||
|
||||
@ -168,14 +214,15 @@ export function formatSkillInfo(
|
||||
skillName: string,
|
||||
opts: SkillInfoOptions,
|
||||
): string {
|
||||
const skill = report.skills.find((s) => s.name === skillName || s.skillKey === skillName);
|
||||
const requestedName = skillName.trim();
|
||||
const skill = resolveSkillByName(report, requestedName);
|
||||
|
||||
if (!skill) {
|
||||
if (opts.json) {
|
||||
return JSON.stringify({ error: "not found", skill: skillName }, null, 2);
|
||||
return JSON.stringify({ error: "not found", skill: requestedName }, null, 2);
|
||||
}
|
||||
return appendClawHubHint(
|
||||
`Skill "${skillName}" not found. Run \`${formatCliCommand("openclaw skills list")}\` to see available skills.`,
|
||||
`Skill "${requestedName}" not found. Run \`${formatCliCommand("openclaw skills list")}\` to see available skills.`,
|
||||
opts.json,
|
||||
);
|
||||
}
|
||||
|
||||
@ -149,16 +149,30 @@ describe("skills-cli", () => {
|
||||
expect(output).toContain("API_KEY");
|
||||
});
|
||||
|
||||
it("normalizes text-presentation emoji selectors in info output", () => {
|
||||
it("resolves skill info case-insensitively", () => {
|
||||
const report = createMockReport([
|
||||
createMockSkill({
|
||||
name: "info-emoji",
|
||||
emoji: "🎛\uFE0E",
|
||||
name: "Excel XLSX",
|
||||
skillKey: "Excel-XLSX",
|
||||
description: "Spreadsheet helpers",
|
||||
}),
|
||||
]);
|
||||
|
||||
const output = formatSkillInfo(report, "info-emoji", {});
|
||||
expect(output).toContain("🎛️");
|
||||
const output = formatSkillInfo(report, "excel-xlsx", {});
|
||||
expect(output).toContain("Spreadsheet helpers");
|
||||
});
|
||||
|
||||
it("resolves skill info across separator variants", () => {
|
||||
const report = createMockReport([
|
||||
createMockSkill({
|
||||
name: "Excel XLSX",
|
||||
skillKey: "excel_xlsx",
|
||||
description: "Spreadsheet helpers",
|
||||
}),
|
||||
]);
|
||||
|
||||
const output = formatSkillInfo(report, "excel-xlsx", {});
|
||||
expect(output).toContain("Spreadsheet helpers");
|
||||
});
|
||||
});
|
||||
|
||||
|
||||
Loading…
x
Reference in New Issue
Block a user