Show Claude skills in inline autocomplete
This commit is contained in:
@@ -999,6 +999,88 @@ describe("ClaudeAgentSession context window usage", () => {
|
|||||||
expect(persistedQueryFactory.mock.calls[0]?.[0].options.persistSession).toBe(true);
|
expect(persistedQueryFactory.mock.calls[0]?.[0].options.persistSession).toBe(true);
|
||||||
});
|
});
|
||||||
|
|
||||||
|
test("classifies Claude root-only commands separately from inline skills", async () => {
|
||||||
|
const queryFactory = vi.fn(({ prompt }: { prompt: AsyncIterable<unknown> }) => {
|
||||||
|
void prompt;
|
||||||
|
return {
|
||||||
|
next: async () => ({ done: true, value: undefined }),
|
||||||
|
interrupt: async () => undefined,
|
||||||
|
return: async () => undefined,
|
||||||
|
close: () => undefined,
|
||||||
|
setPermissionMode: async () => undefined,
|
||||||
|
setModel: async () => undefined,
|
||||||
|
supportedModels: async () => [],
|
||||||
|
supportedCommands: async () => [
|
||||||
|
{
|
||||||
|
name: "taste",
|
||||||
|
description: "Use when another skill needs the shared standard. (user)",
|
||||||
|
argumentHint: "",
|
||||||
|
},
|
||||||
|
{
|
||||||
|
name: "claude-api",
|
||||||
|
description: "Build, debug, and optimize Claude API apps with this skill.",
|
||||||
|
argumentHint: "",
|
||||||
|
},
|
||||||
|
{
|
||||||
|
name: "usage",
|
||||||
|
description: "Show the total cost and duration of the current session",
|
||||||
|
argumentHint: "",
|
||||||
|
},
|
||||||
|
{
|
||||||
|
name: "clear",
|
||||||
|
description: "Start a new session with empty context",
|
||||||
|
argumentHint: "",
|
||||||
|
},
|
||||||
|
],
|
||||||
|
rewindFiles: async () => ({ canRewind: true }),
|
||||||
|
[Symbol.asyncIterator]() {
|
||||||
|
return this;
|
||||||
|
},
|
||||||
|
};
|
||||||
|
});
|
||||||
|
const client = new ClaudeAgentClient({
|
||||||
|
logger,
|
||||||
|
queryFactory,
|
||||||
|
resolveBinary: async () => "/test/claude/bin",
|
||||||
|
});
|
||||||
|
const session = await client.createSession({ provider: "claude", cwd: process.cwd() });
|
||||||
|
|
||||||
|
const commands = await session.listCommands();
|
||||||
|
await session.close();
|
||||||
|
|
||||||
|
expect(commands).toEqual([
|
||||||
|
{
|
||||||
|
name: "claude-api",
|
||||||
|
description: "Build, debug, and optimize Claude API apps with this skill.",
|
||||||
|
argumentHint: "",
|
||||||
|
kind: "skill",
|
||||||
|
},
|
||||||
|
{
|
||||||
|
name: "clear",
|
||||||
|
description: "Start a new session with empty context",
|
||||||
|
argumentHint: "",
|
||||||
|
kind: "command",
|
||||||
|
},
|
||||||
|
{
|
||||||
|
name: "rewind",
|
||||||
|
description: "Rewind tracked files to a previous user message",
|
||||||
|
argumentHint: "[user_message_uuid]",
|
||||||
|
},
|
||||||
|
{
|
||||||
|
name: "taste",
|
||||||
|
description: "Use when another skill needs the shared standard. (user)",
|
||||||
|
argumentHint: "",
|
||||||
|
kind: "skill",
|
||||||
|
},
|
||||||
|
{
|
||||||
|
name: "usage",
|
||||||
|
description: "Show the total cost and duration of the current session",
|
||||||
|
argumentHint: "",
|
||||||
|
kind: "command",
|
||||||
|
},
|
||||||
|
]);
|
||||||
|
});
|
||||||
|
|
||||||
test("deletes the persisted session jsonl on close when persistSession=false", async () => {
|
test("deletes the persisted session jsonl on close when persistSession=false", async () => {
|
||||||
const tmpConfigDir = await fs.mkdtemp(path.join(os.tmpdir(), "paseo-claude-persist-"));
|
const tmpConfigDir = await fs.mkdtemp(path.join(os.tmpdir(), "paseo-claude-persist-"));
|
||||||
const previousConfigDir = process.env.CLAUDE_CONFIG_DIR;
|
const previousConfigDir = process.env.CLAUDE_CONFIG_DIR;
|
||||||
|
|||||||
@@ -302,6 +302,18 @@ const REWIND_COMMAND: AgentSlashCommand = {
|
|||||||
description: "Rewind tracked files to a previous user message",
|
description: "Rewind tracked files to a previous user message",
|
||||||
argumentHint: "[user_message_uuid]",
|
argumentHint: "[user_message_uuid]",
|
||||||
};
|
};
|
||||||
|
const CLAUDE_ROOT_ONLY_COMMANDS = new Set([
|
||||||
|
"clear",
|
||||||
|
"compact",
|
||||||
|
"context",
|
||||||
|
"debug",
|
||||||
|
"extra-usage",
|
||||||
|
"heapdump",
|
||||||
|
"init",
|
||||||
|
"loop",
|
||||||
|
"schedule",
|
||||||
|
"usage",
|
||||||
|
]);
|
||||||
const INTERRUPT_TOOL_USE_PLACEHOLDER = "[Request interrupted by user for tool use]";
|
const INTERRUPT_TOOL_USE_PLACEHOLDER = "[Request interrupted by user for tool use]";
|
||||||
const INTERRUPT_PLACEHOLDER_PATTERN = /^\[Request interrupted by user(?:[^\]]*)\]$/;
|
const INTERRUPT_PLACEHOLDER_PATTERN = /^\[Request interrupted by user(?:[^\]]*)\]$/;
|
||||||
const NO_RESPONSE_REQUESTED_PLACEHOLDER = "No response requested.";
|
const NO_RESPONSE_REQUESTED_PLACEHOLDER = "No response requested.";
|
||||||
@@ -313,6 +325,13 @@ interface SlashCommandInvocation {
|
|||||||
rawInput: string;
|
rawInput: string;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
function classifyClaudeSlashCommand(commandName: string): AgentSlashCommand["kind"] {
|
||||||
|
// Claude exposes commands and skills as one flat SDK list, without structured source
|
||||||
|
// metadata. Keep obvious root-only/session controls out of inline autocomplete and
|
||||||
|
// treat the rest as skills; the worst failure mode is an inert inline suggestion.
|
||||||
|
return CLAUDE_ROOT_ONLY_COMMANDS.has(commandName) ? "command" : "skill";
|
||||||
|
}
|
||||||
|
|
||||||
type ClaudeAgentConfig = AgentSessionConfig & { provider: "claude" };
|
type ClaudeAgentConfig = AgentSessionConfig & { provider: "claude" };
|
||||||
|
|
||||||
export interface ClaudeContentChunk {
|
export interface ClaudeContentChunk {
|
||||||
@@ -2137,7 +2156,7 @@ class ClaudeAgentSession implements AgentSession {
|
|||||||
name: cmd.name,
|
name: cmd.name,
|
||||||
description: cmd.description,
|
description: cmd.description,
|
||||||
argumentHint: cmd.argumentHint,
|
argumentHint: cmd.argumentHint,
|
||||||
kind: "command",
|
kind: classifyClaudeSlashCommand(cmd.name),
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
Reference in New Issue
Block a user