Skip to content

Commit 01f3e2d

Browse files
committed
fix(skills): require unique case-insensitive info matches
1 parent 9b1fac1 commit 01f3e2d

3 files changed

Lines changed: 19 additions & 3 deletions

File tree

CHANGELOG.md

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -3908,6 +3908,7 @@ Docs: https://docs.openclaw.ai
39083908

39093909
### Fixes
39103910

3911+
- CLI/skills: require unique case-insensitive fallback matches in `openclaw skills info` so case-only collisions return not-found instead of showing guidance for the wrong skill. (#38713)
39113912
- Agents/Ollama: forward the configured embedded-run timeout into the global undici stream timeout tuning so slow local Ollama runs no longer inherit the default stream cutoff instead of the operator-set run timeout. (#63175) Thanks @mindcraftreader and @vincentkoc.
39123913
- Models/Codex: include `apiKey` in the codex provider catalog output so the Pi ModelRegistry validator no longer rejects the entry and silently drops all custom models from every provider in `models.json`. (#66180) Thanks @hoyyeva.
39133914
- Tools/image+pdf: normalize configured provider/model refs before media-tool registry lookup so image and PDF tool runs stop rejecting valid Ollama vision models as unknown just because the tool path skipped the usual model-ref normalization step. (#59943) Thanks @yqli2420 and @vincentkoc.

src/cli/skills-cli.format.ts

Lines changed: 6 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -123,11 +123,14 @@ function resolveSkillByName(
123123
}
124124

125125
const lower = raw.toLowerCase();
126-
const caseInsensitive = report.skills.find(
126+
const caseInsensitiveMatches = report.skills.filter(
127127
(s) => s.name.toLowerCase() === lower || s.skillKey.toLowerCase() === lower,
128128
);
129-
if (caseInsensitive) {
130-
return caseInsensitive;
129+
if (caseInsensitiveMatches.length === 1) {
130+
return caseInsensitiveMatches[0] ?? null;
131+
}
132+
if (caseInsensitiveMatches.length > 1) {
133+
return null;
131134
}
132135

133136
const normalized = normalizeSkillLookupToken(raw);

src/cli/skills-cli.test.ts

Lines changed: 12 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -206,6 +206,18 @@ describe("skills-cli", () => {
206206
expect(output).toContain("Spreadsheet helpers");
207207
});
208208

209+
it("returns not found for ambiguous case-insensitive matches", () => {
210+
const report = createMockReport([
211+
createMockSkill({ name: "First Skill", skillKey: "Excel-XLSX", description: "first" }),
212+
createMockSkill({ name: "Second Skill", skillKey: "excel-xlsx", description: "second" }),
213+
]);
214+
215+
const output = formatSkillInfo(report, "EXCEL-XLSX", {});
216+
expect(output).toContain("not found");
217+
expect(output).not.toContain("first");
218+
expect(output).not.toContain("second");
219+
});
220+
209221
it("returns not found for ambiguous normalized matches", () => {
210222
const report = createMockReport([
211223
createMockSkill({ name: "Excel/XLSX", skillKey: "excel-slash", description: "first" }),

0 commit comments

Comments
 (0)