Support env var and prompt input for command
This commit is contained in:
parent
e06e35f8f9
commit
b2ba9e148d
@ -36,7 +36,7 @@ export interface Command {
|
||||
pattern: command.pattern,
|
||||
description: command.description,
|
||||
handler: async (commandName: string, userInput: string) => {
|
||||
return CustomCommands.getInstance().handleCommand(commandName);
|
||||
return CustomCommands.getInstance().handleCommand(commandName, userInput);
|
||||
}
|
||||
};
|
||||
if (command.show || includeHide) {
|
||||
@ -52,14 +52,14 @@ export interface Command {
|
||||
// 转义特殊字符
|
||||
const escapedPattern = commandObj.pattern.replace(/[-\/\\^$*+?.()|[\]{}]/g, '\\$&');
|
||||
const commandPattern = new RegExp(
|
||||
`\\/(${escapedPattern.replace('{{prompt}}', '(.+?)')})`,
|
||||
`\\/(${escapedPattern.replace('\\{\\{prompt\\}\\}', '\\{\\{(.+?)\\}\\}')})`,
|
||||
'g'
|
||||
);
|
||||
|
||||
const matches = Array.from(text.matchAll(commandPattern));
|
||||
const replacements = await Promise.all(
|
||||
matches.map(async (match) => {
|
||||
const matchedUserInput = match[1];
|
||||
const matchedUserInput = match[2];
|
||||
return await commandObj.handler(commandObj.name, matchedUserInput);
|
||||
})
|
||||
);
|
||||
|
@ -30,26 +30,35 @@ class CustomCommands {
|
||||
this.commands = [];
|
||||
|
||||
try {
|
||||
const subDirs = fs.readdirSync(workflowsDir, { withFileTypes: true })
|
||||
const extensionDirs = fs.readdirSync(workflowsDir, { withFileTypes: true })
|
||||
.filter(dirent => dirent.isDirectory())
|
||||
.map(dirent => dirent.name);
|
||||
|
||||
for (const dir of subDirs) {
|
||||
const settingsPath = path.join(workflowsDir, dir, '_setting_.json');
|
||||
for (const extensionDir of extensionDirs) {
|
||||
const commandDir = path.join(workflowsDir, extensionDir, 'command');
|
||||
if (fs.existsSync(commandDir)) {
|
||||
const commandSubDirs = fs.readdirSync(commandDir, { withFileTypes: true })
|
||||
.filter(dirent => dirent.isDirectory())
|
||||
.map(dirent => dirent.name);
|
||||
|
||||
for (const commandSubDir of commandSubDirs) {
|
||||
const settingsPath = path.join(commandDir, commandSubDir, '_setting_.json');
|
||||
if (fs.existsSync(settingsPath)) {
|
||||
const settings = JSON.parse(fs.readFileSync(settingsPath, 'utf-8'));
|
||||
const command: Command = {
|
||||
name: dir,
|
||||
name: commandSubDir,
|
||||
pattern: settings.pattern,
|
||||
description: settings.description,
|
||||
message: settings.message,
|
||||
default: settings.default,
|
||||
show: settings.show === undefined ? "true" : settings.show,
|
||||
instructions: settings.instructions
|
||||
instructions: settings.instructions.map((instruction: string) => path.join(commandDir, commandSubDir, instruction))
|
||||
};
|
||||
this.commands.push(command);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
} catch (error) {
|
||||
// 显示错误消息
|
||||
logger.channel()?.error(`Failed to parse commands: ${error}`);
|
||||
@ -71,7 +80,7 @@ class CustomCommands {
|
||||
}
|
||||
|
||||
|
||||
public handleCommand(commandName: string): string {
|
||||
public handleCommand(commandName: string, userInput: string): string {
|
||||
// 获取命令对象,这里假设您已经有一个方法或属性可以获取到命令对象
|
||||
const command = this.getCommand(commandName);
|
||||
if (!command) {
|
||||
@ -80,13 +89,39 @@ class CustomCommands {
|
||||
return '';
|
||||
}
|
||||
|
||||
// 构建instructions列表字符串
|
||||
let commandMessage = command.message;
|
||||
if (userInput && userInput.length > 0) {
|
||||
// userInput is "['aa', 'bb]" like string
|
||||
// parse userInput to array
|
||||
// handle eval exception
|
||||
|
||||
try {
|
||||
const userInputArray = eval(userInput);
|
||||
|
||||
// replace command message $1 with userInputArray[0], $2 with userInputArray[1] and so on
|
||||
for (let i = 0; i < userInputArray.length; i++) {
|
||||
commandMessage = commandMessage.replace(`$${i + 1}`, userInputArray[i]);
|
||||
}
|
||||
} catch (error) {
|
||||
logger.channel()?.error(`Failed to parse user input: ${userInput} error: ${error}`);
|
||||
logger.channel()?.show();
|
||||
return '';
|
||||
}
|
||||
}
|
||||
|
||||
// replace ${Name} with enviroment var Name
|
||||
const envVarRegex = /\${(\w+)}/g;
|
||||
commandMessage = commandMessage.replace(envVarRegex, (match, p1) => {
|
||||
return process.env[p1] || '';
|
||||
});
|
||||
|
||||
// build instrctions
|
||||
const instructions = command!.instructions
|
||||
.map((instruction: string) => `[instruction|./.chat/workflows/${command.name}/${instruction}]`)
|
||||
.map((instruction: string) => `[instruction|${instruction}]`)
|
||||
.join(' ');
|
||||
|
||||
// 返回结果字符串
|
||||
return `${instructions} ${command!.message}`;
|
||||
return `${instructions} ${commandMessage}`;
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -23,6 +23,8 @@ describe('CustomCommands', () => {
|
||||
// Mock the file system with two directories, one with _setting_.json and one without
|
||||
mockFs({
|
||||
'workflows': {
|
||||
"some": {
|
||||
"command": {
|
||||
'command1': {
|
||||
'_setting_.json': JSON.stringify({
|
||||
pattern: 'command1',
|
||||
@ -36,7 +38,9 @@ describe('CustomCommands', () => {
|
||||
'command2': {
|
||||
// No _setting_.json file
|
||||
},
|
||||
},
|
||||
}
|
||||
}
|
||||
}
|
||||
});
|
||||
|
||||
const workflowsDir = path.join(process.cwd(), 'workflows');
|
||||
@ -54,6 +58,7 @@ describe('CustomCommands', () => {
|
||||
},
|
||||
];
|
||||
|
||||
expectedResult[0].instructions = [path.join(workflowsDir, 'some', 'command', 'command1', 'instruction1'), path.join(workflowsDir, 'some', 'command', 'command1', 'instruction2')];
|
||||
expect(customCommands['commands']).to.deep.equal(expectedResult);
|
||||
});
|
||||
|
||||
@ -100,7 +105,23 @@ describe('CustomCommands', () => {
|
||||
};
|
||||
|
||||
customCommands.regCommand(command);
|
||||
const result = customCommands.handleCommand('test');
|
||||
expect(result).to.equal('[instruction|./.chat/workflows/test/instruction1] [instruction|./.chat/workflows/test/instruction2] Test message');
|
||||
const result = customCommands.handleCommand('test', '');
|
||||
expect(result).to.equal('[instruction|instruction1] [instruction|instruction2] Test message');
|
||||
});
|
||||
|
||||
it('should handle a custom command with args', () => {
|
||||
const command: Command = {
|
||||
name: 'test',
|
||||
pattern: 'test {{prompt}}',
|
||||
description: 'Test command',
|
||||
message: 'Test message "$1","$2"',
|
||||
default: false,
|
||||
show: true,
|
||||
instructions: ['instruction1', 'instruction2'],
|
||||
};
|
||||
|
||||
customCommands.regCommand(command);
|
||||
const result = customCommands.handleCommand('test', '["v1", "v2"]');
|
||||
expect(result).to.equal('[instruction|instruction1] [instruction|instruction2] Test message "v1","v2"');
|
||||
});
|
||||
});
|
Loading…
x
Reference in New Issue
Block a user