Update .gitignore and refactor code

- Add DevChat related files to .gitignore
- Refactor package.json and settings
- Update commandManager.ts and remove example commands
- Implement customCommand.ts for handling custom commands
- Remove commitMessageCommand.ts and example commands
- Update chatConfig.ts and chatPanel.ts for new command handling
- Add new workflows for code and commit_message
This commit is contained in:
bobo.yang 2023-05-10 14:31:17 +08:00
parent a11b38c5a3
commit 7f2a869f3f
16 changed files with 223 additions and 104 deletions

5
.gitignore vendored
View File

@ -5,3 +5,8 @@ node_modules
*.vsix *.vsix
.env .env
.chatconfig.json .chatconfig.json
# DevChat
.chat/prompts.graphml
.chat/prompts.db

View File

@ -15,6 +15,7 @@
"dist/*", "dist/*",
"bin/*", "bin/*",
"assets/*", "assets/*",
"workflows/*",
"LICENSE", "LICENSE",
"README.md" "README.md"
], ],

View File

@ -1,8 +1,14 @@
import { vs } from "react-syntax-highlighter/dist/esm/styles/hljs";
import CustomCommands from "./customCommand";
import { logger } from "../util/logger";
import * as vscode from 'vscode';
import * as path from 'path';
export interface Command { export interface Command {
name: string; name: string;
pattern: string; pattern: string;
description: string; description: string;
handler: (userInput: string) => Promise<string>; handler: (commandName: string, userInput: string) => Promise<string>;
} }
class CommandManager { class CommandManager {
@ -24,7 +30,22 @@ export interface Command {
} }
getCommandList(): Command[] { getCommandList(): Command[] {
return this.commands; // load commands from CustomCommands
let newCommands: Command[] = [...this.commands];
const customCommands = CustomCommands.getInstance();
const commands = customCommands.getCommands();
commands.forEach(command => {
const commandObj: Command = {
name: command.name,
pattern: command.pattern,
description: command.description,
handler: async (commandName: string, userInput: string) => {
return CustomCommands.getInstance().handleCommand(commandName);
}
};
newCommands.push(commandObj);
});
return newCommands;
} }
async processText(text: string): Promise<string> { async processText(text: string): Promise<string> {
@ -38,7 +59,7 @@ export interface Command {
const replacements = await Promise.all( const replacements = await Promise.all(
matches.map(async (match) => { matches.map(async (match) => {
const matchedUserInput = match[1]; const matchedUserInput = match[1];
return await commandObj.handler(matchedUserInput); return await commandObj.handler(commandObj.name, matchedUserInput);
}) })
); );
let result = text; let result = text;
@ -50,7 +71,7 @@ export interface Command {
// 处理所有命令 // 处理所有命令
let result = text; let result = text;
for (const commandObj of this.commands) { for (const commandObj of this.getCommandList()) {
result = await processCommand(commandObj, result); result = await processCommand(commandObj, result);
} }

View File

@ -1,41 +0,0 @@
import {Command} from './commandManager';
import { exec } from 'child_process';
import * as vscode from 'vscode';
import * as fs from 'fs';
import * as os from 'os';
import * as path from 'path';
import { promisify } from 'util';
import { createTempSubdirectory } from '../util/commonUtil';
import { logger } from '../util/logger';
const mkdirAsync = promisify(fs.mkdir);
const execAsync = promisify(exec);
const writeFileAsync = promisify(fs.writeFile);
async function createTempDirectory(tempDir: string): Promise<void> {
try {
await mkdirAsync(tempDir, {recursive: true});
} catch (err) {
logger.channel()?.error(`Error creating temporary directory: ${err}`);
logger.channel()?.show();
}
}
export const commitMessageCommand: Command = {
name: 'commitMessageCommand',
pattern: 'commit_meesage',
description: 'commit message for changes',
handler: async (userInput: string) => {
const tempDir = createTempSubdirectory('devchat/context');
const workspaceDir = vscode.workspace.workspaceFolders?.[0].uri.fsPath;
if (workspaceDir) {
const commitmessageInstruction = path.join(workspaceDir, '.chat', 'instructions', 'commit_message', 'instCommitMessage.txt');
return `[instruction|${commitmessageInstruction}] Write a commit message`;
}
return 'Write a commit message';
},
};

View File

@ -0,0 +1,81 @@
import fs from 'fs';
import path from 'path';
import { logger } from '../util/logger';
interface Command {
name: string;
pattern: string;
description: string;
message: string;
default: boolean;
instructions: string[];
}
class CustomCommands {
private static instance: CustomCommands | null = null;
private commands: Command[] = [];
private constructor() {
}
public static getInstance(): CustomCommands {
if (!CustomCommands.instance) {
CustomCommands.instance = new CustomCommands();
}
return CustomCommands.instance;
}
public parseCommands(workflowsDir: string): void {
this.commands = [];
const subDirs = 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');
if (fs.existsSync(settingsPath)) {
const settings = JSON.parse(fs.readFileSync(settingsPath, 'utf-8'));
const command: Command = {
name: dir,
pattern: settings.pattern,
description: settings.description,
message: settings.message,
default: settings.default,
instructions: settings.instructions
};
this.commands.push(command);
}
}
}
public getCommands(): Command[] {
return this.commands;
}
public getCommand(commandName: string): Command | null {
const foundCommand = this.commands.find(command => command.name === commandName);
return foundCommand ? foundCommand : null;
}
public handleCommand(commandName: string): string {
// 获取命令对象,这里假设您已经有一个方法或属性可以获取到命令对象
const command = this.getCommand(commandName);
if (!command) {
logger.channel()?.error(`Command ${commandName} not found!`);
logger.channel()?.show();
return '';
}
// 构建instructions列表字符串
const instructions = command!.instructions
.map((instruction: string) => `[instruction|./workflows/${command.name}/${instruction}]`)
.join(' ');
// 返回结果字符串
return `${instructions} ${command!.message}`;
}
}
export default CustomCommands;

View File

@ -1,10 +0,0 @@
import {Command} from './commandManager';
export const exampleCommand1: Command = {
name: 'exampleCommand1',
pattern: 'example: command1 {{prompt}}',
description: '这是一个示例命令1',
handler: async (userInput: string) => {
return `示例命令1处理了以下文本${userInput}`;
},
};

View File

@ -1,10 +0,0 @@
import {Command} from './commandManager';
export const exampleCommand2: Command = {
name: 'exampleCommand2',
pattern: 'example: command2 {{prompt}}',
description: '这是一个示例命令2',
handler: async (userInput: string) => {
return `示例命令2处理了以下文本${userInput}`;
},
};

View File

@ -1,11 +1,6 @@
import CommandManager from './commandManager'; import CommandManager from './commandManager';
import { exampleCommand1 } from './exampleCommand1';
import { exampleCommand2 } from './exampleCommand2';
import { commitMessageCommand } from './commitMessageCommand';
const commandManager = CommandManager.getInstance(); const commandManager = CommandManager.getInstance();
// 注册命令 // 注册命令
commandManager.registerCommand(exampleCommand1);
commandManager.registerCommand(exampleCommand2);
commandManager.registerCommand(commitMessageCommand);

View File

@ -16,7 +16,7 @@ function activate(context: vscode.ExtensionContext) {
ExtensionContextHolder.context = context; ExtensionContextHolder.context = context;
logger.init(context); logger.init(context);
// 创建 .chat 目录并复制 instructions // 创建 .chat 目录并复制 workflows
createChatDirectoryAndCopyInstructionsSync(context.extensionUri); createChatDirectoryAndCopyInstructionsSync(context.extensionUri);
registerOpenChatPanelCommand(context); registerOpenChatPanelCommand(context);

View File

@ -5,6 +5,32 @@ import * as ncp from 'ncp';
import { logger } from '../util/logger'; import { logger } from '../util/logger';
function copyFileSync(source: string, target: string) {
const data = fs.readFileSync(source);
fs.writeFileSync(target, data);
}
function copyDirSync(source: string, target: string) {
// 创建目标目录
fs.mkdirSync(target, { recursive: true });
// 遍历目录中的所有文件和子目录
const files = fs.readdirSync(source);
for (const file of files) {
const sourcePath = path.join(source, file);
const targetPath = path.join(target, file);
const stats = fs.statSync(sourcePath);
if (stats.isDirectory()) {
// 递归拷贝子目录
copyDirSync(sourcePath, targetPath);
} else {
// 拷贝文件
copyFileSync(sourcePath, targetPath);
}
}
}
export function createChatDirectoryAndCopyInstructionsSync(extensionUri: vscode.Uri) { export function createChatDirectoryAndCopyInstructionsSync(extensionUri: vscode.Uri) {
const workspaceFolders = vscode.workspace.workspaceFolders; const workspaceFolders = vscode.workspace.workspaceFolders;
@ -14,7 +40,7 @@ export function createChatDirectoryAndCopyInstructionsSync(extensionUri: vscode.
const workspaceRoot = workspaceFolders[0].uri.fsPath; const workspaceRoot = workspaceFolders[0].uri.fsPath;
const chatDirPath = path.join(workspaceRoot, '.chat'); const chatDirPath = path.join(workspaceRoot, '.chat');
const instructionsSrcPath = path.join(extensionUri.fsPath, 'instructions'); const instructionsSrcPath = path.join(extensionUri.fsPath, 'workflows');
try { try {
// 检查 .chat 目录是否存在,如果不存在,则创建它 // 检查 .chat 目录是否存在,如果不存在,则创建它
@ -24,15 +50,10 @@ export function createChatDirectoryAndCopyInstructionsSync(extensionUri: vscode.
return; return;
} }
// 将 instructions 目录复制到 .chat 目录中 // 将 workflows 目录复制到 .chat 目录中
ncp.ncp(instructionsSrcPath, path.join(chatDirPath, 'instructions'), (err) => { copyDirSync(instructionsSrcPath, path.join(chatDirPath, 'workflows'));
if (err) {
logger.channel()?.error('Error copying instructions:', err);
logger.channel()?.show();
}
});
} catch (error) { } catch (error) {
logger.channel()?.error('Error creating .chat directory and copying instructions:', error); logger.channel()?.error('Error creating .chat directory and copying workflows:', error);
logger.channel()?.show(); logger.channel()?.show();
} }
} }

View File

@ -1,11 +1,14 @@
// chatPanel.ts // chatPanel.ts
import * as vscode from 'vscode'; import * as vscode from 'vscode';
import * as path from 'path';
import '../handler/loadHandlers'; import '../handler/loadHandlers';
import handleMessage from '../handler/messageHandler'; import handleMessage from '../handler/messageHandler';
import WebviewManager from './webviewManager'; import WebviewManager from './webviewManager';
import messageHistory from '../util/messageHistory'; import messageHistory from '../util/messageHistory';
import CustomCommands from '../command/customCommand';
import CommandManager from '../command/commandManager';
export default class ChatPanel { export default class ChatPanel {
private static _instance: ChatPanel | undefined; private static _instance: ChatPanel | undefined;
@ -14,6 +17,12 @@ export default class ChatPanel {
private _disposables: vscode.Disposable[] = []; private _disposables: vscode.Disposable[] = [];
public static createOrShow(extensionUri: vscode.Uri) { public static createOrShow(extensionUri: vscode.Uri) {
const workspaceDir = vscode.workspace.workspaceFolders?.[0].uri.fsPath;
if (workspaceDir) {
const workflowsDir = path.join(workspaceDir!, '.chat', 'workflows');
CustomCommands.getInstance().parseCommands(workflowsDir);
}
if (ChatPanel._instance) { if (ChatPanel._instance) {
ChatPanel._instance._panel.reveal(); ChatPanel._instance._panel.reveal();
} else { } else {

View File

@ -0,0 +1,7 @@
{
"pattern": "code",
"description": "work for generate code",
"message": "",
"default": true,
"instructions": ["instruct.txt", "python.txt"]
}

View File

@ -0,0 +1,23 @@
As a software developer assistant, your tasks are to:
- Provide a clear and concise response to address the user's requirements.
- Write code and give advice based on given code or information in the <context> if provided.
- Follow language-specific best practices and common coding standards.
When responding:
1. Summarize and describe the requirements or provided information in your own words.
2. The summary and description should better be written in bullet points (excluding code).
3. When modifying the provided code, include the entire modified functions, but exclude any unmodified functions.
If any global statements are changed, include the full global statements; otherwise, do not include them.
4. Enclose code or changes within blocks using triple backticks (```), and include the programming language and the file path, if available. For example:
```
```python path=./path/to/file.py
print("Hello, World!")
```
```
If no file paths or folder structure are provided and you are unsure about the file path of the code, you may omit the file path.
5. Use separate code blocks for different files.
6. Utilize the previous messages, if provided in the end of this prompt, to create your response. Note that not all previous messages are necessarily relevant.
7. When providing a suggestion or instruction, begin by explaining the reason behind it.
8. If you need more information, ask for it.

View File

@ -0,0 +1 @@
When writing Python code, include type hints where appropriate and maintain compliance with PEP-8 guidelines, such as providing docstrings for modules, classes, and functions.

View File

@ -0,0 +1,7 @@
{
"pattern": "commit_message",
"description": "generate commit message",
"message": "write a commit message",
"default": false,
"instructions": ["instruct.txt"]
}

View File

@ -0,0 +1,9 @@
As a software developer assistant, your task is to provide clear and concise responses and write commit messages based on given code, requirements, or conversations. Follow these guidelines:
1. A commit message should include a title and multiple body lines.
2. Adhere to best practices, such as keeping titles under 50 characters and limiting body lines to under 72 characters.
3. Enclose messages in code blocks using triple backticks (```), and flag code type as commitmsg.
4. Utilize the <context>, if provided, to create the summary.
5. Utilize the previous messages, if provided in the end of this prompt, to create the summary. Note that not all previous messages are necessarily relevant.
If you need more information, feel free to ask.