Add get_commands RPC for headless clients (#995)
* Add get_commands RPC for headless clients Headless clients like Emacs can now query which commands are available. Previously they could only discover file-based prompt templates by scanning the filesystem; extension commands and skills were invisible. The response includes each command's name, description, and source (extension, template, or skill). Commands appear in the same order as the TUI's autocomplete: extension commands first, then templates, then skills. Built-in TUI commands (/settings, /fork, etc.) are excluded since they require the interactive UI. Commands like /compact have dedicated RPC equivalents instead. * Add location and path to get_commands response Clients can show where commands come from (user/project/path) and display file paths in tooltips. The data is already available on templates and skills - just exposing it.
This commit is contained in:
@@ -26,6 +26,7 @@ import type {
|
||||
RpcExtensionUIResponse,
|
||||
RpcResponse,
|
||||
RpcSessionState,
|
||||
RpcSlashCommand,
|
||||
} from "./rpc-types.js";
|
||||
|
||||
// Re-export types for consumers
|
||||
@@ -497,6 +498,48 @@ export async function runRpcMode(session: AgentSession): Promise<never> {
|
||||
return success(id, "get_messages", { messages: session.messages });
|
||||
}
|
||||
|
||||
// =================================================================
|
||||
// Commands (available for invocation via prompt)
|
||||
// =================================================================
|
||||
|
||||
case "get_commands": {
|
||||
const commands: RpcSlashCommand[] = [];
|
||||
|
||||
// Extension commands
|
||||
for (const { command, extensionPath } of session.extensionRunner?.getRegisteredCommandsWithPaths() ?? []) {
|
||||
commands.push({
|
||||
name: command.name,
|
||||
description: command.description,
|
||||
source: "extension",
|
||||
path: extensionPath,
|
||||
});
|
||||
}
|
||||
|
||||
// Prompt templates (source is always "user" | "project" | "path" in coding-agent)
|
||||
for (const template of session.promptTemplates) {
|
||||
commands.push({
|
||||
name: template.name,
|
||||
description: template.description,
|
||||
source: "template",
|
||||
location: template.source as RpcSlashCommand["location"],
|
||||
path: template.filePath,
|
||||
});
|
||||
}
|
||||
|
||||
// Skills (source is always "user" | "project" | "path" in coding-agent)
|
||||
for (const skill of session.resourceLoader.getSkills().skills) {
|
||||
commands.push({
|
||||
name: `skill:${skill.name}`,
|
||||
description: skill.description,
|
||||
source: "skill",
|
||||
location: skill.source as RpcSlashCommand["location"],
|
||||
path: skill.filePath,
|
||||
});
|
||||
}
|
||||
|
||||
return success(id, "get_commands", { commands });
|
||||
}
|
||||
|
||||
default: {
|
||||
const unknownCommand = command as { type: string };
|
||||
return error(undefined, unknownCommand.type, `Unknown command: ${unknownCommand.type}`);
|
||||
|
||||
Reference in New Issue
Block a user