Files
paseo/packages/app/src/utils/agent-command-autocomplete.test.ts
T

137 lines
3.8 KiB
TypeScript

import { describe, expect, it } from "vitest";
import {
applySlashCommandReplacement,
filterAndRankCommandAutocompleteEntries,
filterInlineSkillCommandEntries,
findActiveSlashCommand,
} from "./agent-command-autocomplete";
describe("filterAndRankCommandAutocompleteEntries", () => {
const entries = [
{ source: "provider" as const, command: { name: "paseo-committee" } },
{ source: "provider" as const, command: { name: "commit" } },
{ source: "provider" as const, command: { name: "paseo-advisor" } },
];
it("ranks command-name prefixes above later word-boundary partial matches", () => {
const result = filterAndRankCommandAutocompleteEntries(entries, "comm");
expect(result.map((entry) => entry.command.name)).toEqual(["commit", "paseo-committee"]);
});
it("matches client command aliases", () => {
const result = filterAndRankCommandAutocompleteEntries(
[
{ source: "client" as const, command: { name: "exit", aliases: ["quit", "q"] } },
{ source: "client" as const, command: { name: "clear", aliases: ["new"] } },
],
"q",
);
expect(result.map((entry) => entry.command.name)).toEqual(["exit"]);
});
});
describe("findActiveSlashCommand", () => {
it("detects a slash command token in the middle of the prompt", () => {
const text = "use /tas before implementation";
expect(
findActiveSlashCommand({
text,
cursorIndex: "use /tas".length,
}),
).toEqual({
start: 4,
end: "use /tas".length,
query: "tas",
position: "inline",
});
});
it("classifies a slash command token at the prompt start", () => {
expect(
findActiveSlashCommand({
text: "/rew",
cursorIndex: "/rew".length,
}),
).toEqual({
start: 0,
end: "/rew".length,
query: "rew",
position: "start",
});
});
it("returns null when the cursor is outside the slash token", () => {
expect(
findActiveSlashCommand({
text: "use /taste now",
cursorIndex: "use /taste now".length,
}),
).toBeNull();
});
it("returns null for slash-delimited paths", () => {
expect(
findActiveSlashCommand({
text: "read /tmp/project",
cursorIndex: "read /tmp/project".length,
}),
).toBeNull();
});
});
describe("applySlashCommandReplacement", () => {
it("replaces only the active slash token", () => {
const text = "use /tas before implementation";
expect(
applySlashCommandReplacement({
text,
command: { start: 4, end: "use /tas".length, query: "tas", position: "inline" },
commandName: "taste",
}),
).toBe("use /taste before implementation");
});
it("commits an inline slash token at the prompt tail", () => {
const text = "use /tas";
expect(
applySlashCommandReplacement({
text,
command: { start: 4, end: text.length, query: "tas", position: "inline" },
commandName: "taste",
}),
).toBe("use /taste ");
});
it("commits a start slash token at the prompt tail", () => {
const text = "/tas";
expect(
applySlashCommandReplacement({
text,
command: { start: 0, end: text.length, query: "tas", position: "start" },
commandName: "taste",
}),
).toBe("/taste ");
});
});
describe("filterInlineSkillCommandEntries", () => {
it("keeps provider skills and drops executable commands", () => {
const entries = [
{ source: "client" as const, command: { name: "clear", kind: "command" } },
{ source: "provider" as const, command: { name: "compact", kind: "command" } },
{ source: "provider" as const, command: { name: "taste", kind: "skill" } },
];
expect(filterInlineSkillCommandEntries(entries).map((entry) => entry.command.name)).toEqual([
"taste",
]);
});
});