Merge branch 'main' of https://github.com/covespace/devchat-vscode into input-multiline
This commit is contained in:
commit
d7622abe28
@ -8,7 +8,7 @@ import * as os from 'os';
|
||||
import * as path from 'path';
|
||||
import { promisify } from 'util';
|
||||
import { createTempSubdirectory } from '../util/commonUtil';
|
||||
import ExtensionContextHolder from '../util/extensionContext';
|
||||
import { logger } from '../util/logger';
|
||||
|
||||
const mkdirAsync = promisify(fs.mkdir);
|
||||
const execAsync = promisify(exec);
|
||||
@ -19,26 +19,8 @@ async function createTempDirectory(tempDir: string): Promise<void> {
|
||||
try {
|
||||
await mkdirAsync(tempDir, {recursive: true});
|
||||
} catch (err) {
|
||||
console.error(`Error creating temporary directory: ${err}`);
|
||||
}
|
||||
}
|
||||
|
||||
async function writeDiffFile(diff_file: string) {
|
||||
try {
|
||||
const workspaceDir = vscode.workspace.workspaceFolders?.[0].uri.fsPath;
|
||||
|
||||
const { stdout, stderr } = await execAsync('git diff --cached', {
|
||||
cwd: workspaceDir
|
||||
});
|
||||
if (stderr) {
|
||||
console.error(`Error output from git diff --cached: ${stderr}`);
|
||||
return;
|
||||
}
|
||||
// 将结果写入到临时文件中
|
||||
const tempFilePath = diff_file;
|
||||
await writeFileAsync(tempFilePath, stdout);
|
||||
} catch (err) {
|
||||
console.error(`Error executing git diff --cached: ${err}`);
|
||||
logger.channel()?.error(`Error creating temporary directory: ${err}`);
|
||||
logger.channel()?.show();
|
||||
}
|
||||
}
|
||||
|
||||
@ -49,12 +31,6 @@ export const commitMessageCommand: Command = {
|
||||
handler: async (userInput: string) => {
|
||||
const tempDir = createTempSubdirectory('devchat/context');
|
||||
|
||||
// // 创建临时目录
|
||||
// const diff_file = path.join(tempDir, 'diff_output.txt');
|
||||
// await writeDiffFile(diff_file);
|
||||
|
||||
// return `[context|${diff_file}] Write a commit message`;
|
||||
|
||||
const workspaceDir = vscode.workspace.workspaceFolders?.[0].uri.fsPath;
|
||||
if (workspaceDir) {
|
||||
const commitmessageInstruction = path.join(workspaceDir, '.chat', 'instructions', 'commit_message', 'instCommitMessage.txt');
|
||||
|
@ -2,6 +2,7 @@ import * as path from 'path';
|
||||
import * as vscode from 'vscode';
|
||||
import { ChatContext } from './contextManager';
|
||||
import { createTempSubdirectory, runCommandStringAndWriteOutput } from '../util/commonUtil';
|
||||
import { logger } from '../util/logger';
|
||||
|
||||
export const customCommandContext: ChatContext = {
|
||||
name: '<custom command>',
|
||||
@ -17,10 +18,13 @@ export const customCommandContext: ChatContext = {
|
||||
if (customCommand) {
|
||||
const tempDir = await createTempSubdirectory('devchat/context');
|
||||
const diff_file = path.join(tempDir, 'custom.txt');
|
||||
|
||||
logger.channel()?.info(`custom command: ${customCommand}`);
|
||||
const result = await runCommandStringAndWriteOutput(customCommand, diff_file);
|
||||
console.log(result.exitCode);
|
||||
console.log(result.stdout);
|
||||
console.log(result.stderr);
|
||||
logger.channel()?.info(`custom command: ${customCommand} exit code:`, result.exitCode);
|
||||
|
||||
logger.channel()?.debug(`custom command: ${customCommand} stdout:`, result.stdout);
|
||||
logger.channel()?.debug(`custom command: ${customCommand} stderr:`, result.stderr);
|
||||
return `[context|${diff_file}]`;
|
||||
}
|
||||
return '';
|
||||
|
@ -2,16 +2,22 @@ import * as path from 'path';
|
||||
import { ChatContext } from './contextManager';
|
||||
import { createTempSubdirectory, runCommandStringAndWriteOutput } from '../util/commonUtil';
|
||||
|
||||
import { logger } from '../util/logger';
|
||||
|
||||
|
||||
export const gitDiffContext: ChatContext = {
|
||||
name: 'git diff',
|
||||
description: 'diff for all changes',
|
||||
handler: async () => {
|
||||
const tempDir = await createTempSubdirectory('devchat/context');
|
||||
const diff_file = path.join(tempDir, 'diff_all.txt');
|
||||
|
||||
logger.channel()?.info(`git diff`);
|
||||
const result = await runCommandStringAndWriteOutput('git diff', diff_file);
|
||||
console.log(result.exitCode);
|
||||
console.log(result.stdout);
|
||||
console.log(result.stderr);
|
||||
logger.channel()?.info(`git diff exit code:`, result.exitCode);
|
||||
|
||||
logger.channel()?.debug(`git diff stdout:`, result.stdout);
|
||||
logger.channel()?.debug(`git diff stderr:`, result.stderr);
|
||||
return `[context|${diff_file}]`;
|
||||
},
|
||||
};
|
||||
|
@ -2,16 +2,22 @@ import * as path from 'path';
|
||||
import { ChatContext } from './contextManager';
|
||||
import { createTempSubdirectory, runCommandStringAndWriteOutput } from '../util/commonUtil';
|
||||
|
||||
import { logger } from '../util/logger';
|
||||
|
||||
|
||||
export const gitDiffCachedContext: ChatContext = {
|
||||
name: 'git diff cached',
|
||||
description: 'diff for cached changes',
|
||||
handler: async () => {
|
||||
const tempDir = await createTempSubdirectory('devchat/context');
|
||||
const diff_file = path.join(tempDir, 'diff_cached.txt');
|
||||
|
||||
logger.channel()?.info(`git diff --cached`);
|
||||
const result = await runCommandStringAndWriteOutput('git diff --cached', diff_file);
|
||||
console.log(result.exitCode);
|
||||
console.log(result.stdout);
|
||||
console.log(result.stderr);
|
||||
logger.channel()?.info(`git diff --cached exit code:`, result.exitCode);
|
||||
|
||||
logger.channel()?.debug(`git diff --cached stdout:`, result.stdout);
|
||||
logger.channel()?.debug(`git diff --cached stderr:`, result.stderr);
|
||||
return `[context|${diff_file}]`;
|
||||
},
|
||||
};
|
||||
|
@ -2,15 +2,20 @@
|
||||
import * as vscode from 'vscode';
|
||||
import * as path from 'path';
|
||||
import { createTempSubdirectory, runCommandStringAndWriteOutput } from '../util/commonUtil';
|
||||
import { logger } from '../util/logger';
|
||||
|
||||
|
||||
export async function handleRefCommand(ref_command: string) {
|
||||
if (ref_command) {
|
||||
const tempDir = await createTempSubdirectory('devchat/context');
|
||||
const diff_file = path.join(tempDir, 'custom.txt');
|
||||
|
||||
logger.channel()?.info(`custom command: ${ref_command}`);
|
||||
const result = await runCommandStringAndWriteOutput(ref_command, diff_file);
|
||||
console.log(result.exitCode);
|
||||
console.log(result.stdout);
|
||||
console.log(result.stderr);
|
||||
logger.channel()?.info(`custom command: ${ref_command} exit code:`, result.exitCode);
|
||||
|
||||
logger.channel()?.debug(`custom command: ${ref_command} stdout:`, result.stdout);
|
||||
logger.channel()?.debug(`custom command: ${ref_command} stderr:`, result.stderr);
|
||||
return `[context|${diff_file}]`;
|
||||
}
|
||||
|
||||
|
@ -2,13 +2,14 @@ import * as vscode from 'vscode';
|
||||
|
||||
import { handleCodeSelected } from '../context/contextCodeSelected';
|
||||
import { handleFileSelected } from '../context/contextFileSelected';
|
||||
import { MessageHandler } from '../handler/messageHandler';
|
||||
|
||||
export async function sendFileSelectMessage(panel: vscode.WebviewPanel, filePath: string): Promise<void> {
|
||||
const codeContext = await handleFileSelected(filePath);
|
||||
panel.webview.postMessage({ command: 'appendContext', context: codeContext });
|
||||
MessageHandler.sendMessage(panel, { command: 'appendContext', context: codeContext });
|
||||
}
|
||||
|
||||
export async function sendCodeSelectMessage(panel: vscode.WebviewPanel, filePath: string, codeBlock: string): Promise<void> {
|
||||
const codeContext = await handleCodeSelected(filePath, codeBlock);
|
||||
panel.webview.postMessage({ command: 'appendContext', context: codeContext });
|
||||
MessageHandler.sendMessage(panel, { command: 'appendContext', context: codeContext });
|
||||
}
|
@ -9,10 +9,12 @@ import {
|
||||
} from './contributes/commands';
|
||||
|
||||
import ExtensionContextHolder from './util/extensionContext';
|
||||
import { logger } from './util/logger';
|
||||
|
||||
|
||||
function activate(context: vscode.ExtensionContext) {
|
||||
ExtensionContextHolder.context = context;
|
||||
logger.init(context);
|
||||
|
||||
// 创建 .chat 目录并复制 instructions
|
||||
createChatDirectoryAndCopyInstructionsSync(context.extensionUri);
|
||||
|
@ -1,9 +1,11 @@
|
||||
import * as vscode from 'vscode';
|
||||
import ChatContextManager from '../context/contextManager';
|
||||
|
||||
import { MessageHandler } from './messageHandler';
|
||||
|
||||
export async function addConext(message: any, panel: vscode.WebviewPanel): Promise<void> {
|
||||
const contextStr = await ChatContextManager.getInstance().processText(message.selected);
|
||||
panel.webview.postMessage({ command: 'appendContext', context: contextStr });
|
||||
MessageHandler.sendMessage(panel, { command: 'appendContext', context: contextStr });
|
||||
return;
|
||||
}
|
||||
|
||||
|
@ -1,10 +1,11 @@
|
||||
import * as vscode from 'vscode';
|
||||
import { handleRefCommand } from '../context/contextRef';
|
||||
import { MessageHandler } from './messageHandler';
|
||||
|
||||
// message: { command: 'addRefCommandContext', refCommand: string }
|
||||
// User input: /ref ls . then "ls ." will be passed to refCommand
|
||||
export async function addRefCommandContext(message: any, panel: vscode.WebviewPanel): Promise<void> {
|
||||
const contextStr = await handleRefCommand(message.refCommand);
|
||||
panel.webview.postMessage({ command: 'appendContext', context: contextStr });
|
||||
MessageHandler.sendMessage(panel, { command: 'appendContext', context: contextStr });
|
||||
return;
|
||||
}
|
||||
|
@ -1,12 +1,12 @@
|
||||
import * as vscode from 'vscode';
|
||||
import * as fs from 'fs';
|
||||
import { handleRefCommand } from '../context/contextRef';
|
||||
import { MessageHandler } from './messageHandler';
|
||||
|
||||
// message: { command: 'contextDetail', file: string }
|
||||
// read detail context information from file
|
||||
// return json string
|
||||
export async function contextDetail(message: any, panel: vscode.WebviewPanel): Promise<void> {
|
||||
const fileContent = fs.readFileSync(message.file, 'utf-8');
|
||||
panel.webview.postMessage({ command: 'contextDetailResponse', 'file':message.file, result: fileContent });
|
||||
MessageHandler.sendMessage(panel, { command: 'contextDetailResponse', 'file':message.file, result: fileContent });
|
||||
return;
|
||||
}
|
||||
|
@ -1,10 +1,10 @@
|
||||
import * as vscode from 'vscode';
|
||||
import CommandManager from '../command/commandManager';
|
||||
|
||||
import { MessageHandler } from './messageHandler';
|
||||
|
||||
export async function convertCommand(message: any, panel: vscode.WebviewPanel): Promise<void> {
|
||||
const newText = await CommandManager.getInstance().processText(message.text);
|
||||
panel.webview.postMessage({ command: 'convertCommand', result: newText });
|
||||
MessageHandler.sendMessage(panel, { command: 'convertCommand', result: newText });
|
||||
return;
|
||||
}
|
||||
|
||||
|
@ -1,13 +1,13 @@
|
||||
import * as vscode from 'vscode';
|
||||
import DevChat, { LogOptions } from '../toolwrapper/devchat';
|
||||
|
||||
import { MessageHandler } from './messageHandler';
|
||||
|
||||
export async function historyMessages(message: any, panel: vscode.WebviewPanel): Promise<void> {
|
||||
const devChat = new DevChat();
|
||||
|
||||
const logOptions: LogOptions = message.options || {};
|
||||
const logEntries = await devChat.log(logOptions);
|
||||
panel.webview.postMessage({ command: 'loadHistoryMessages', entries: logEntries });
|
||||
MessageHandler.sendMessage(panel, { command: 'loadHistoryMessages', entries: logEntries });
|
||||
return;
|
||||
}
|
||||
|
||||
|
@ -4,9 +4,10 @@ import * as vscode from 'vscode';
|
||||
|
||||
import '../command/loadCommands';
|
||||
import '../context/loadContexts'
|
||||
import { logger } from '../util/logger';
|
||||
|
||||
|
||||
class MessageHandler {
|
||||
export class MessageHandler {
|
||||
private handlers: { [command: string]: (message: any, panel: vscode.WebviewPanel) => Promise<void> } = {};
|
||||
|
||||
constructor() {
|
||||
@ -19,14 +20,20 @@ class MessageHandler {
|
||||
async handleMessage(message: any, panel: vscode.WebviewPanel): Promise<void> {
|
||||
const handler = this.handlers[message.command];
|
||||
if (handler) {
|
||||
logger.channel()?.info(`Handling command "${message.command}"`);
|
||||
await handler(message, panel);
|
||||
logger.channel()?.info(`Handling command "${message.command}" done`);
|
||||
} else {
|
||||
console.error(`No handler found for command "${message.command}"`);
|
||||
logger.channel()?.error(`No handler found for command "${message.command}"`);
|
||||
logger.channel()?.show();
|
||||
}
|
||||
}
|
||||
|
||||
sendMessage(panel: vscode.WebviewPanel, command: string, data: any): void {
|
||||
panel.webview.postMessage({ command, ...data });
|
||||
public static sendMessage(panel: vscode.WebviewPanel, message: object, log: boolean = true): void {
|
||||
if (log) {
|
||||
logger.channel()?.info(`Sending message "${JSON.stringify(message)}"`);
|
||||
}
|
||||
panel.webview.postMessage(message);
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -1,10 +1,10 @@
|
||||
import * as vscode from 'vscode';
|
||||
import CommandManager from '../command/commandManager';
|
||||
|
||||
import { MessageHandler } from './messageHandler';
|
||||
|
||||
export async function regCommandList(message: any, panel: vscode.WebviewPanel): Promise<void> {
|
||||
const commandList = CommandManager.getInstance().getCommandList();
|
||||
panel.webview.postMessage({ command: 'regCommandList', result: commandList });
|
||||
MessageHandler.sendMessage(panel, { command: 'regCommandList', result: commandList });
|
||||
return;
|
||||
}
|
||||
|
||||
|
@ -1,10 +1,10 @@
|
||||
import * as vscode from 'vscode';
|
||||
import ChatContextManager from '../context/contextManager';
|
||||
|
||||
import { MessageHandler } from './messageHandler';
|
||||
|
||||
export async function regContextList(message: any, panel: vscode.WebviewPanel): Promise<void> {
|
||||
const contextList = ChatContextManager.getInstance().getContextList();
|
||||
panel.webview.postMessage({ command: 'regContextList', result: contextList });
|
||||
MessageHandler.sendMessage(panel, { command: 'regContextList', result: contextList });
|
||||
return;
|
||||
}
|
||||
|
||||
|
@ -4,6 +4,8 @@ import * as fs from 'fs';
|
||||
import * as path from 'path';
|
||||
import DevChat from '../toolwrapper/devchat';
|
||||
import CommandManager from '../command/commandManager';
|
||||
import { logger } from '../util/logger';
|
||||
import { MessageHandler } from './messageHandler';
|
||||
|
||||
|
||||
// Add this function to messageHandler.ts
|
||||
@ -60,7 +62,8 @@ function getInstructionFiles(): string[] {
|
||||
}
|
||||
}
|
||||
} catch (error) {
|
||||
console.error('Error reading instruction files:', error);
|
||||
logger.channel()?.error(`Error reading instruction files: ${error}`);
|
||||
logger.channel()?.show();
|
||||
}
|
||||
}
|
||||
return instructionFiles;
|
||||
@ -73,8 +76,6 @@ export async function sendMessage(message: any, panel: vscode.WebviewPanel): Pro
|
||||
const devChat = new DevChat();
|
||||
|
||||
const newText2 = await CommandManager.getInstance().processText(message.text);
|
||||
panel.webview.postMessage({ command: 'convertCommand', result: newText2 });
|
||||
|
||||
const parsedMessage = parseMessage(newText2);
|
||||
const chatOptions: any = lastPromptHash ? { parent: lastPromptHash } : {};
|
||||
|
||||
@ -94,7 +95,7 @@ export async function sendMessage(message: any, panel: vscode.WebviewPanel): Pro
|
||||
let partialData = "";
|
||||
const onData = (partialResponse: string) => {
|
||||
partialData += partialResponse;
|
||||
panel.webview.postMessage({ command: 'receiveMessagePartial', text: partialData });
|
||||
MessageHandler.sendMessage(panel, { command: 'receiveMessagePartial', text: partialData }, false);
|
||||
};
|
||||
|
||||
const chatResponse = await devChat.chat(parsedMessage.text, chatOptions, onData);
|
||||
@ -109,7 +110,7 @@ export async function sendMessage(message: any, panel: vscode.WebviewPanel): Pro
|
||||
}
|
||||
}
|
||||
const response = chatResponse.response;
|
||||
panel.webview.postMessage({ command: 'receiveMessage', text: response });
|
||||
MessageHandler.sendMessage(panel, { command: 'receiveMessage', text: response });
|
||||
return;
|
||||
}
|
||||
|
||||
|
@ -3,6 +3,8 @@ import * as fs from 'fs';
|
||||
import * as path from 'path';
|
||||
import * as ncp from 'ncp';
|
||||
|
||||
import { logger } from '../util/logger';
|
||||
|
||||
export function createChatDirectoryAndCopyInstructionsSync(extensionUri: vscode.Uri) {
|
||||
|
||||
const workspaceFolders = vscode.workspace.workspaceFolders;
|
||||
@ -25,10 +27,12 @@ export function createChatDirectoryAndCopyInstructionsSync(extensionUri: vscode.
|
||||
// 将 instructions 目录复制到 .chat 目录中
|
||||
ncp.ncp(instructionsSrcPath, path.join(chatDirPath, 'instructions'), (err) => {
|
||||
if (err) {
|
||||
console.error('Error copying instructions:', err);
|
||||
logger.channel()?.error('Error copying instructions:', err);
|
||||
logger.channel()?.show();
|
||||
}
|
||||
});
|
||||
} catch (error) {
|
||||
console.error('Error creating .chat directory and copying instructions:', error);
|
||||
logger.channel()?.error('Error creating .chat directory and copying instructions:', error);
|
||||
logger.channel()?.show();
|
||||
}
|
||||
}
|
@ -7,6 +7,8 @@ import * as dotenv from 'dotenv';
|
||||
import * as path from 'path';
|
||||
import * as fs from 'fs';
|
||||
|
||||
import { logger } from '../util/logger';
|
||||
|
||||
const spawnAsync = async (command: string, args: string[], options: any, onData: (data: string) => void): Promise<{ code: number, stdout: string; stderr: string }> => {
|
||||
return new Promise((resolve, reject) => {
|
||||
const child = spawn(command, args, options);
|
||||
@ -121,6 +123,7 @@ class DevChat {
|
||||
fs.writeFileSync(configPath, configJson);
|
||||
|
||||
try {
|
||||
logger.channel()?.info(`Running devchat with args: ${args.join(" ")}`);
|
||||
const { code, stdout, stderr } = await spawnAsync('devchat', args, {
|
||||
maxBuffer: 10 * 1024 * 1024, // Set maxBuffer to 10 MB
|
||||
cwd: workspaceDir,
|
||||
@ -142,7 +145,6 @@ class DevChat {
|
||||
}
|
||||
|
||||
const responseLines = stdout.trim().split("\n");
|
||||
console.log(responseLines)
|
||||
|
||||
if (responseLines.length === 0) {
|
||||
return {
|
||||
@ -215,6 +217,7 @@ class DevChat {
|
||||
const openaiApiKey = process.env.OPENAI_API_KEY;
|
||||
|
||||
try {
|
||||
logger.channel()?.info(`Running devchat with args: ${args.join(" ")}`);
|
||||
const { code, stdout, stderr } = await spawnAsync('devchat', args, {
|
||||
maxBuffer: 10 * 1024 * 1024, // Set maxBuffer to 10 MB
|
||||
cwd: workspaceDir,
|
||||
@ -225,13 +228,15 @@ class DevChat {
|
||||
}, (partialResponse: string) => { });
|
||||
|
||||
if (stderr) {
|
||||
console.error(stderr);
|
||||
logger.channel()?.error(`Error getting log: ${stderr}`);
|
||||
logger.channel()?.show();
|
||||
return [];
|
||||
}
|
||||
|
||||
return JSON.parse(stdout.trim());
|
||||
} catch (error) {
|
||||
console.error(error)
|
||||
logger.channel()?.error(`Error getting log: ${error}`);
|
||||
logger.channel()?.show();
|
||||
return [];
|
||||
}
|
||||
}
|
||||
|
@ -1,6 +1,8 @@
|
||||
import { spawn } from "child_process";
|
||||
import * as vscode from 'vscode';
|
||||
|
||||
import { logger } from "../util/logger";
|
||||
|
||||
interface DtmResponse {
|
||||
status: number;
|
||||
message: string;
|
||||
@ -16,6 +18,7 @@ class DtmWrapper {
|
||||
|
||||
private async runCommand(command: string, args: string[]): Promise<DtmResponse> {
|
||||
return new Promise((resolve, reject) => {
|
||||
logger.channel()?.info(`Running command: ${command} ${args.join(' ')}`);
|
||||
const child = spawn(command, args, { cwd: this.workspaceDir });
|
||||
let stdout = '';
|
||||
let stderr = '';
|
||||
@ -58,7 +61,8 @@ class DtmWrapper {
|
||||
return await this.runCommand('dtm', ['commit', '-m', commitMsg, '-o', 'json']);
|
||||
} catch (error) {
|
||||
// 处理 runCommand 中的 reject 错误
|
||||
console.error('Error in commit:', error);
|
||||
logger.channel()?.error(`Error in commit: ${error}`);
|
||||
logger.channel()?.show();
|
||||
return error as DtmResponse;
|
||||
}
|
||||
}
|
||||
|
13
src/util/logger.ts
Normal file
13
src/util/logger.ts
Normal file
@ -0,0 +1,13 @@
|
||||
import * as vscode from 'vscode'
|
||||
|
||||
export class logger {
|
||||
private static _channel: vscode.LogOutputChannel | undefined;
|
||||
public static init(context: vscode.ExtensionContext): void {
|
||||
this._channel = vscode.window.createOutputChannel('DevChat', { log: true });
|
||||
}
|
||||
|
||||
public static channel(): vscode.LogOutputChannel | undefined {
|
||||
return this._channel;
|
||||
}
|
||||
}
|
||||
|
Loading…
x
Reference in New Issue
Block a user