feat(ui): add source indicators to slash commands (#18839)

This commit is contained in:
Emily Hedlund
2026-02-20 10:54:59 -05:00
committed by GitHub
parent c3b52b8206
commit d08b1efc72
5 changed files with 293 additions and 116 deletions

View File

@@ -37,6 +37,7 @@ import { sanitizeForDisplay } from '../ui/utils/textUtils.js';
interface CommandDirectory {
path: string;
namespace: string;
extensionName?: string;
extensionId?: string;
}
@@ -111,6 +112,7 @@ export class FileCommandLoader implements ICommandLoader {
this.parseAndAdaptFile(
path.join(dirInfo.path, file),
dirInfo.path,
dirInfo.namespace,
dirInfo.extensionName,
dirInfo.extensionId,
),
@@ -151,10 +153,16 @@ export class FileCommandLoader implements ICommandLoader {
const storage = this.config?.storage ?? new Storage(this.projectRoot);
// 1. User commands
dirs.push({ path: Storage.getUserCommandsDir() });
dirs.push({
path: Storage.getUserCommandsDir(),
namespace: 'user',
});
// 2. Project commands (override user commands)
dirs.push({ path: storage.getProjectCommandsDir() });
dirs.push({
path: storage.getProjectCommandsDir(),
namespace: 'workspace',
});
// 3. Extension commands (processed last to detect all conflicts)
if (this.config) {
@@ -165,6 +173,7 @@ export class FileCommandLoader implements ICommandLoader {
const extensionCommandDirs = activeExtensions.map((ext) => ({
path: path.join(ext.path, 'commands'),
namespace: ext.name,
extensionName: ext.name,
extensionId: ext.id,
}));
@@ -179,14 +188,16 @@ export class FileCommandLoader implements ICommandLoader {
* Parses a single .toml file and transforms it into a SlashCommand object.
* @param filePath The absolute path to the .toml file.
* @param baseDir The root command directory for name calculation.
* @param namespace The namespace of the command.
* @param extensionName Optional extension name to prefix commands with.
* @returns A promise resolving to a SlashCommand, or null if the file is invalid.
*/
private async parseAndAdaptFile(
filePath: string,
baseDir: string,
extensionName?: string,
extensionId?: string,
namespace: string,
extensionName: string | undefined,
extensionId: string | undefined,
): Promise<SlashCommand | null> {
let fileContent: string;
try {
@@ -245,16 +256,11 @@ export class FileCommandLoader implements ICommandLoader {
})
.join(':');
// Add extension name tag for extension commands
const defaultDescription = `Custom command from ${path.basename(filePath)}`;
let description = validDef.description || defaultDescription;
description = sanitizeForDisplay(description, 100);
if (extensionName) {
description = `[${extensionName}] ${description}`;
}
const processors: IPromptProcessor[] = [];
const usesArgs = validDef.prompt.includes(SHORTHAND_ARGS_PLACEHOLDER);
const usesShellInjection = validDef.prompt.includes(
@@ -285,6 +291,7 @@ export class FileCommandLoader implements ICommandLoader {
return {
name: baseCommandName,
namespace,
description,
kind: CommandKind.FILE,
extensionName,