feat: Add Shell Command Execution to Custom Commands (#4917)

This commit is contained in:
Abhi
2025-07-27 02:00:26 -04:00
committed by GitHub
parent 9e61b3510c
commit 576cebc928
16 changed files with 1604 additions and 653 deletions

View File

@@ -19,7 +19,7 @@ import {
CommandContext,
CommandKind,
SlashCommand,
SubmitPromptActionReturn,
SlashCommandActionReturn,
} from '../ui/commands/types.js';
import {
DefaultArgumentProcessor,
@@ -28,7 +28,12 @@ import {
import {
IPromptProcessor,
SHORTHAND_ARGS_PLACEHOLDER,
SHELL_INJECTION_TRIGGER,
} from './prompt-processors/types.js';
import {
ConfirmationRequiredError,
ShellProcessor,
} from './prompt-processors/shellProcessor.js';
/**
* Defines the Zod schema for a command definition file. This serves as the
@@ -172,6 +177,11 @@ export class FileCommandLoader implements ICommandLoader {
const processors: IPromptProcessor[] = [];
// Add the Shell Processor if needed.
if (validDef.prompt.includes(SHELL_INJECTION_TRIGGER)) {
processors.push(new ShellProcessor(commandName));
}
// The presence of '{{args}}' is the switch that determines the behavior.
if (validDef.prompt.includes(SHORTHAND_ARGS_PLACEHOLDER)) {
processors.push(new ShorthandArgumentProcessor());
@@ -188,7 +198,7 @@ export class FileCommandLoader implements ICommandLoader {
action: async (
context: CommandContext,
_args: string,
): Promise<SubmitPromptActionReturn> => {
): Promise<SlashCommandActionReturn> => {
if (!context.invocation) {
console.error(
`[FileCommandLoader] Critical error: Command '${commandName}' was executed without invocation context.`,
@@ -199,15 +209,31 @@ export class FileCommandLoader implements ICommandLoader {
};
}
let processedPrompt = validDef.prompt;
for (const processor of processors) {
processedPrompt = await processor.process(processedPrompt, context);
}
try {
let processedPrompt = validDef.prompt;
for (const processor of processors) {
processedPrompt = await processor.process(processedPrompt, context);
}
return {
type: 'submit_prompt',
content: processedPrompt,
};
return {
type: 'submit_prompt',
content: processedPrompt,
};
} catch (e) {
// Check if it's our specific error type
if (e instanceof ConfirmationRequiredError) {
// Halt and request confirmation from the UI layer.
return {
type: 'confirm_shell_commands',
commandsToConfirm: e.commandsToConfirm,
originalInvocation: {
raw: context.invocation.raw,
},
};
}
// Re-throw other errors to be handled by the global error handler.
throw e;
}
},
};
}