Undermoon1412 aa7f616734
fix(composer): reserve context slash command alias (#5279)
* fix(composer): reserve context slash command alias

* fix(skills): align slash docs and formatting

Signed-off-by: Undermoon1412 <80385295+Undermoon1412@users.noreply.github.com>

* fix(skills): allow context skill outside compact alias

Signed-off-by: Undermoon1412 <80385295+Undermoon1412@users.noreply.github.com>

* docs(tui): sync context skill command policy

Signed-off-by: Undermoon1412 <80385295+Undermoon1412@users.noreply.github.com>

---------

Signed-off-by: Undermoon1412 <80385295+Undermoon1412@users.noreply.github.com>
2026-09-18 07:48:24 +08:00

75 lines
2.3 KiB
TypeScript

import { describe, expect, it } from "@rstest/core";
import type { Skill } from "@/core/skills";
import {
parseSlashSkillReference,
resolveSlashSkillDisplay,
} from "@/core/skills/slash";
function makeSkill(name: string, enabled = true): Skill {
return {
name,
description: `${name} description`,
enabled,
} as Skill;
}
describe("parseSlashSkillReference", () => {
it("parses a leading /skill and captures the remaining text", () => {
expect(parseSlashSkillReference("/data-analysis summarize this")).toEqual({
name: "data-analysis",
remainingText: "summarize this",
});
});
it("parses a bare /skill with no task text", () => {
expect(parseSlashSkillReference("/data-analysis")).toEqual({
name: "data-analysis",
remainingText: "",
});
});
it("ignores reserved control commands", () => {
expect(parseSlashSkillReference("/goal ship it")).toBeNull();
expect(parseSlashSkillReference("/help")).toBeNull();
});
it("allows a context skill except for the compact alias", () => {
expect(parseSlashSkillReference("/context compact")).toBeNull();
expect(parseSlashSkillReference("/context use this skill")).toEqual({
name: "context",
remainingText: "use this skill",
});
});
it("returns null when text is not a leading slash command", () => {
expect(parseSlashSkillReference("hello /data-analysis")).toBeNull();
expect(parseSlashSkillReference("/a/b")).toBeNull();
expect(parseSlashSkillReference("plain text")).toBeNull();
});
});
describe("resolveSlashSkillDisplay", () => {
const skills = [makeSkill("data-analysis"), makeSkill("frontend-design")];
it("resolves when the referenced skill exists and is enabled", () => {
expect(resolveSlashSkillDisplay("/data-analysis go", skills)).toEqual({
name: "data-analysis",
remainingText: "go",
});
});
it("returns null for a slash command that is not an installed skill", () => {
expect(resolveSlashSkillDisplay("/hello world", skills)).toBeNull();
expect(resolveSlashSkillDisplay("/unknown-skill do it", skills)).toBeNull();
});
it("returns null when the skill exists but is disabled", () => {
expect(
resolveSlashSkillDisplay("/legacy-skill x", [
makeSkill("legacy-skill", false),
]),
).toBeNull();
});
});