mirror of
https://github.com/andrepimenta/claude-code-chat.git
synced 2026-06-02 10:35:51 +08:00
Fix new chat
This commit is contained in:
297
src/extension.ts
297
src/extension.ts
@@ -56,7 +56,6 @@ interface ConversationData {
|
|||||||
};
|
};
|
||||||
messages: Array<{ timestamp: string, messageType: string, data: any }>;
|
messages: Array<{ timestamp: string, messageType: string, data: any }>;
|
||||||
filename: string;
|
filename: string;
|
||||||
isProcessing?: boolean;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
class ClaudeChatWebviewProvider implements vscode.WebviewViewProvider {
|
class ClaudeChatWebviewProvider implements vscode.WebviewViewProvider {
|
||||||
@@ -64,7 +63,7 @@ class ClaudeChatWebviewProvider implements vscode.WebviewViewProvider {
|
|||||||
private readonly _extensionUri: vscode.Uri,
|
private readonly _extensionUri: vscode.Uri,
|
||||||
private readonly _context: vscode.ExtensionContext,
|
private readonly _context: vscode.ExtensionContext,
|
||||||
private readonly _chatProvider: ClaudeChatProvider
|
private readonly _chatProvider: ClaudeChatProvider
|
||||||
) {}
|
) { }
|
||||||
|
|
||||||
public resolveWebviewView(
|
public resolveWebviewView(
|
||||||
webviewView: vscode.WebviewView,
|
webviewView: vscode.WebviewView,
|
||||||
@@ -333,7 +332,7 @@ class ClaudeChatProvider {
|
|||||||
if (this._messageHandlerDisposable) {
|
if (this._messageHandlerDisposable) {
|
||||||
this._messageHandlerDisposable.dispose();
|
this._messageHandlerDisposable.dispose();
|
||||||
}
|
}
|
||||||
|
|
||||||
// Set up new message handler
|
// Set up new message handler
|
||||||
this._messageHandlerDisposable = webview.onDidReceiveMessage(
|
this._messageHandlerDisposable = webview.onDidReceiveMessage(
|
||||||
message => this._handleWebviewMessage(message),
|
message => this._handleWebviewMessage(message),
|
||||||
@@ -349,7 +348,7 @@ class ClaudeChatProvider {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
public showInWebview(webview: vscode.Webview, webviewView?: vscode.WebviewView) {
|
public showInWebview(webview: vscode.Webview, webviewView?: vscode.WebviewView) {
|
||||||
// Close main panel if it's open
|
// Close main panel if it's open
|
||||||
if (this._panel) {
|
if (this._panel) {
|
||||||
console.log('Closing main panel because sidebar is opening');
|
console.log('Closing main panel because sidebar is opening');
|
||||||
@@ -436,11 +435,11 @@ class ClaudeChatProvider {
|
|||||||
type: 'userInput',
|
type: 'userInput',
|
||||||
data: message
|
data: message
|
||||||
});
|
});
|
||||||
|
|
||||||
// Set processing state to true
|
// Set processing state to true
|
||||||
this._postMessage({
|
this._postMessage({
|
||||||
type: 'setProcessing',
|
type: 'setProcessing',
|
||||||
data: {isProcessing: true}
|
data: { isProcessing: true }
|
||||||
});
|
});
|
||||||
|
|
||||||
// Create backup commit before Claude makes changes
|
// Create backup commit before Claude makes changes
|
||||||
@@ -466,7 +465,7 @@ class ClaudeChatProvider {
|
|||||||
// Get configuration
|
// Get configuration
|
||||||
const config = vscode.workspace.getConfiguration('claudeCodeChat');
|
const config = vscode.workspace.getConfiguration('claudeCodeChat');
|
||||||
const yoloMode = config.get<boolean>('permissions.yoloMode', false);
|
const yoloMode = config.get<boolean>('permissions.yoloMode', false);
|
||||||
|
|
||||||
if (yoloMode) {
|
if (yoloMode) {
|
||||||
// Yolo mode: skip all permissions regardless of MCP config
|
// Yolo mode: skip all permissions regardless of MCP config
|
||||||
args.push('--dangerously-skip-permissions');
|
args.push('--dangerously-skip-permissions');
|
||||||
@@ -573,6 +572,10 @@ class ClaudeChatProvider {
|
|||||||
console.log('Claude process closed with code:', code);
|
console.log('Claude process closed with code:', code);
|
||||||
console.log('Claude stderr output:', errorOutput);
|
console.log('Claude stderr output:', errorOutput);
|
||||||
|
|
||||||
|
if (!this._currentClaudeProcess) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
// Clear process reference
|
// Clear process reference
|
||||||
this._currentClaudeProcess = undefined;
|
this._currentClaudeProcess = undefined;
|
||||||
|
|
||||||
@@ -580,10 +583,16 @@ class ClaudeChatProvider {
|
|||||||
this._postMessage({
|
this._postMessage({
|
||||||
type: 'clearLoading'
|
type: 'clearLoading'
|
||||||
});
|
});
|
||||||
|
|
||||||
// Reset processing state
|
// Reset processing state
|
||||||
this._isProcessing = false;
|
this._isProcessing = false;
|
||||||
|
|
||||||
|
// Clear processing state
|
||||||
|
this._postMessage({
|
||||||
|
type: 'setProcessing',
|
||||||
|
data: { isProcessing: false }
|
||||||
|
});
|
||||||
|
|
||||||
if (code !== 0 && errorOutput.trim()) {
|
if (code !== 0 && errorOutput.trim()) {
|
||||||
// Error with output
|
// Error with output
|
||||||
this._sendAndSaveMessage({
|
this._sendAndSaveMessage({
|
||||||
@@ -595,14 +604,26 @@ class ClaudeChatProvider {
|
|||||||
|
|
||||||
claudeProcess.on('error', (error) => {
|
claudeProcess.on('error', (error) => {
|
||||||
console.log('Claude process error:', error.message);
|
console.log('Claude process error:', error.message);
|
||||||
|
|
||||||
|
if (!this._currentClaudeProcess) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
// Clear process reference
|
// Clear process reference
|
||||||
this._currentClaudeProcess = undefined;
|
this._currentClaudeProcess = undefined;
|
||||||
|
|
||||||
this._postMessage({
|
this._postMessage({
|
||||||
type: 'clearLoading'
|
type: 'clearLoading'
|
||||||
});
|
});
|
||||||
|
|
||||||
|
this._isProcessing = false;
|
||||||
|
|
||||||
|
// Clear processing state
|
||||||
|
this._postMessage({
|
||||||
|
type: 'setProcessing',
|
||||||
|
data: { isProcessing: false }
|
||||||
|
});
|
||||||
|
|
||||||
// Check if claude command is not installed
|
// Check if claude command is not installed
|
||||||
if (error.message.includes('ENOENT') || error.message.includes('command not found')) {
|
if (error.message.includes('ENOENT') || error.message.includes('command not found')) {
|
||||||
this._sendAndSaveMessage({
|
this._sendAndSaveMessage({
|
||||||
@@ -624,6 +645,18 @@ class ClaudeChatProvider {
|
|||||||
if (jsonData.subtype === 'init') {
|
if (jsonData.subtype === 'init') {
|
||||||
// System initialization message - session ID will be captured from final result
|
// System initialization message - session ID will be captured from final result
|
||||||
console.log('System initialized');
|
console.log('System initialized');
|
||||||
|
this._currentSessionId = jsonData.session_id;
|
||||||
|
//this._sendAndSaveMessage({ type: 'init', data: { sessionId: jsonData.session_id; } })
|
||||||
|
|
||||||
|
// Show session info in UI
|
||||||
|
this._sendAndSaveMessage({
|
||||||
|
type: 'sessionInfo',
|
||||||
|
data: {
|
||||||
|
sessionId: jsonData.session_id,
|
||||||
|
tools: jsonData.tools || [],
|
||||||
|
mcpServers: jsonData.mcp_servers || []
|
||||||
|
}
|
||||||
|
});
|
||||||
}
|
}
|
||||||
break;
|
break;
|
||||||
|
|
||||||
@@ -703,16 +736,16 @@ class ClaudeChatProvider {
|
|||||||
for (const content of jsonData.message.content) {
|
for (const content of jsonData.message.content) {
|
||||||
if (content.type === 'tool_result') {
|
if (content.type === 'tool_result') {
|
||||||
let resultContent = content.content || 'Tool executed successfully';
|
let resultContent = content.content || 'Tool executed successfully';
|
||||||
|
|
||||||
// Stringify if content is an object or array
|
// Stringify if content is an object or array
|
||||||
if (typeof resultContent === 'object' && resultContent !== null) {
|
if (typeof resultContent === 'object' && resultContent !== null) {
|
||||||
resultContent = JSON.stringify(resultContent, null, 2);
|
resultContent = JSON.stringify(resultContent, null, 2);
|
||||||
}
|
}
|
||||||
|
|
||||||
const isError = content.is_error || false;
|
const isError = content.is_error || false;
|
||||||
|
|
||||||
// Find the last tool use to get the tool name
|
// Find the last tool use to get the tool name
|
||||||
const lastToolUse = this._currentConversation[this._currentConversation.length-1]
|
const lastToolUse = this._currentConversation[this._currentConversation.length - 1]
|
||||||
|
|
||||||
const toolName = lastToolUse?.data?.toolName;
|
const toolName = lastToolUse?.data?.toolName;
|
||||||
|
|
||||||
@@ -784,7 +817,7 @@ class ClaudeChatProvider {
|
|||||||
// Clear processing state
|
// Clear processing state
|
||||||
this._postMessage({
|
this._postMessage({
|
||||||
type: 'setProcessing',
|
type: 'setProcessing',
|
||||||
data: {isProcessing: false}
|
data: { isProcessing: false }
|
||||||
});
|
});
|
||||||
|
|
||||||
// Update cumulative tracking
|
// Update cumulative tracking
|
||||||
@@ -819,6 +852,22 @@ class ClaudeChatProvider {
|
|||||||
|
|
||||||
|
|
||||||
private _newSession() {
|
private _newSession() {
|
||||||
|
|
||||||
|
this._isProcessing = false
|
||||||
|
|
||||||
|
// Update UI state
|
||||||
|
this._postMessage({
|
||||||
|
type: 'setProcessing',
|
||||||
|
data: { isProcessing: false }
|
||||||
|
});
|
||||||
|
|
||||||
|
// Try graceful termination first
|
||||||
|
if (this._currentClaudeProcess) {
|
||||||
|
const processToKill = this._currentClaudeProcess;
|
||||||
|
this._currentClaudeProcess = undefined;
|
||||||
|
processToKill.kill('SIGTERM');
|
||||||
|
}
|
||||||
|
|
||||||
// Clear current session
|
// Clear current session
|
||||||
this._currentSessionId = undefined;
|
this._currentSessionId = undefined;
|
||||||
|
|
||||||
@@ -842,10 +891,10 @@ class ClaudeChatProvider {
|
|||||||
public newSessionOnConfigChange() {
|
public newSessionOnConfigChange() {
|
||||||
// Reinitialize MCP config with new WSL paths
|
// Reinitialize MCP config with new WSL paths
|
||||||
this._initializeMCPConfig();
|
this._initializeMCPConfig();
|
||||||
|
|
||||||
// Start a new session due to configuration change
|
// Start a new session due to configuration change
|
||||||
this._newSession();
|
this._newSession();
|
||||||
|
|
||||||
// Show notification to user
|
// Show notification to user
|
||||||
vscode.window.showInformationMessage(
|
vscode.window.showInformationMessage(
|
||||||
'WSL configuration changed. Started a new Claude session.',
|
'WSL configuration changed. Started a new Claude session.',
|
||||||
@@ -866,7 +915,7 @@ class ClaudeChatProvider {
|
|||||||
// Clear processing state
|
// Clear processing state
|
||||||
this._postMessage({
|
this._postMessage({
|
||||||
type: 'setProcessing',
|
type: 'setProcessing',
|
||||||
data: {isProcessing: false}
|
data: { isProcessing: false }
|
||||||
});
|
});
|
||||||
|
|
||||||
// Show login required message
|
// Show login required message
|
||||||
@@ -896,7 +945,7 @@ class ClaudeChatProvider {
|
|||||||
'OK'
|
'OK'
|
||||||
);
|
);
|
||||||
|
|
||||||
// Send message to UI about terminal
|
// Send message to UI about terminal
|
||||||
this._postMessage({
|
this._postMessage({
|
||||||
type: 'terminalOpened',
|
type: 'terminalOpened',
|
||||||
data: `Please login to Claude in the terminal, then come back to this chat to continue.`,
|
data: `Please login to Claude in the terminal, then come back to this chat to continue.`,
|
||||||
@@ -906,7 +955,7 @@ class ClaudeChatProvider {
|
|||||||
private async _initializeBackupRepo(): Promise<void> {
|
private async _initializeBackupRepo(): Promise<void> {
|
||||||
try {
|
try {
|
||||||
const workspaceFolder = vscode.workspace.workspaceFolders?.[0];
|
const workspaceFolder = vscode.workspace.workspaceFolders?.[0];
|
||||||
if (!workspaceFolder) {return;}
|
if (!workspaceFolder) { return; }
|
||||||
|
|
||||||
const storagePath = this._context.storageUri?.fsPath;
|
const storagePath = this._context.storageUri?.fsPath;
|
||||||
if (!storagePath) {
|
if (!storagePath) {
|
||||||
@@ -939,7 +988,7 @@ class ClaudeChatProvider {
|
|||||||
private async _createBackupCommit(userMessage: string): Promise<void> {
|
private async _createBackupCommit(userMessage: string): Promise<void> {
|
||||||
try {
|
try {
|
||||||
const workspaceFolder = vscode.workspace.workspaceFolders?.[0];
|
const workspaceFolder = vscode.workspace.workspaceFolders?.[0];
|
||||||
if (!workspaceFolder || !this._backupRepoPath) {return;}
|
if (!workspaceFolder || !this._backupRepoPath) { return; }
|
||||||
|
|
||||||
const workspacePath = workspaceFolder.uri.fsPath;
|
const workspacePath = workspaceFolder.uri.fsPath;
|
||||||
const now = new Date();
|
const now = new Date();
|
||||||
@@ -1048,10 +1097,10 @@ class ClaudeChatProvider {
|
|||||||
private async _initializeConversations(): Promise<void> {
|
private async _initializeConversations(): Promise<void> {
|
||||||
try {
|
try {
|
||||||
const workspaceFolder = vscode.workspace.workspaceFolders?.[0];
|
const workspaceFolder = vscode.workspace.workspaceFolders?.[0];
|
||||||
if (!workspaceFolder) {return;}
|
if (!workspaceFolder) { return; }
|
||||||
|
|
||||||
const storagePath = this._context.storageUri?.fsPath;
|
const storagePath = this._context.storageUri?.fsPath;
|
||||||
if (!storagePath) {return;}
|
if (!storagePath) { return; }
|
||||||
|
|
||||||
this._conversationsPath = path.join(storagePath, 'conversations');
|
this._conversationsPath = path.join(storagePath, 'conversations');
|
||||||
|
|
||||||
@@ -1070,7 +1119,7 @@ class ClaudeChatProvider {
|
|||||||
private async _initializeMCPConfig(): Promise<void> {
|
private async _initializeMCPConfig(): Promise<void> {
|
||||||
try {
|
try {
|
||||||
const storagePath = this._context.storageUri?.fsPath;
|
const storagePath = this._context.storageUri?.fsPath;
|
||||||
if (!storagePath) {return;}
|
if (!storagePath) { return; }
|
||||||
|
|
||||||
// Create MCP config directory
|
// Create MCP config directory
|
||||||
const mcpConfigDir = path.join(storagePath, 'mcp');
|
const mcpConfigDir = path.join(storagePath, 'mcp');
|
||||||
@@ -1085,11 +1134,11 @@ class ClaudeChatProvider {
|
|||||||
const mcpConfigPath = path.join(mcpConfigDir, 'mcp-servers.json');
|
const mcpConfigPath = path.join(mcpConfigDir, 'mcp-servers.json');
|
||||||
const mcpPermissionsPath = this.convertToWSLPath(path.join(this._extensionUri.fsPath, 'mcp-permissions.js'));
|
const mcpPermissionsPath = this.convertToWSLPath(path.join(this._extensionUri.fsPath, 'mcp-permissions.js'));
|
||||||
const permissionRequestsPath = this.convertToWSLPath(path.join(storagePath, 'permission-requests'));
|
const permissionRequestsPath = this.convertToWSLPath(path.join(storagePath, 'permission-requests'));
|
||||||
|
|
||||||
// Load existing config or create new one
|
// Load existing config or create new one
|
||||||
let mcpConfig: any = { mcpServers: {} };
|
let mcpConfig: any = { mcpServers: {} };
|
||||||
const mcpConfigUri = vscode.Uri.file(mcpConfigPath);
|
const mcpConfigUri = vscode.Uri.file(mcpConfigPath);
|
||||||
|
|
||||||
try {
|
try {
|
||||||
const existingContent = await vscode.workspace.fs.readFile(mcpConfigUri);
|
const existingContent = await vscode.workspace.fs.readFile(mcpConfigUri);
|
||||||
mcpConfig = JSON.parse(new TextDecoder().decode(existingContent));
|
mcpConfig = JSON.parse(new TextDecoder().decode(existingContent));
|
||||||
@@ -1097,12 +1146,12 @@ class ClaudeChatProvider {
|
|||||||
} catch {
|
} catch {
|
||||||
console.log('No existing MCP config found, creating new one');
|
console.log('No existing MCP config found, creating new one');
|
||||||
}
|
}
|
||||||
|
|
||||||
// Ensure mcpServers exists
|
// Ensure mcpServers exists
|
||||||
if (!mcpConfig.mcpServers) {
|
if (!mcpConfig.mcpServers) {
|
||||||
mcpConfig.mcpServers = {};
|
mcpConfig.mcpServers = {};
|
||||||
}
|
}
|
||||||
|
|
||||||
// Add or update the permissions server entry
|
// Add or update the permissions server entry
|
||||||
mcpConfig.mcpServers['claude-code-chat-permissions'] = {
|
mcpConfig.mcpServers['claude-code-chat-permissions'] = {
|
||||||
command: 'node',
|
command: 'node',
|
||||||
@@ -1114,7 +1163,7 @@ class ClaudeChatProvider {
|
|||||||
|
|
||||||
const configContent = new TextEncoder().encode(JSON.stringify(mcpConfig, null, 2));
|
const configContent = new TextEncoder().encode(JSON.stringify(mcpConfig, null, 2));
|
||||||
await vscode.workspace.fs.writeFile(mcpConfigUri, configContent);
|
await vscode.workspace.fs.writeFile(mcpConfigUri, configContent);
|
||||||
|
|
||||||
console.log(`Updated MCP config at: ${mcpConfigPath}`);
|
console.log(`Updated MCP config at: ${mcpConfigPath}`);
|
||||||
} catch (error: any) {
|
} catch (error: any) {
|
||||||
console.error('Failed to initialize MCP config:', error.message);
|
console.error('Failed to initialize MCP config:', error.message);
|
||||||
@@ -1124,13 +1173,13 @@ class ClaudeChatProvider {
|
|||||||
private async _initializePermissions(): Promise<void> {
|
private async _initializePermissions(): Promise<void> {
|
||||||
try {
|
try {
|
||||||
|
|
||||||
if(this._permissionWatcher){
|
if (this._permissionWatcher) {
|
||||||
this._permissionWatcher.dispose();
|
this._permissionWatcher.dispose();
|
||||||
this._permissionWatcher = undefined;
|
this._permissionWatcher = undefined;
|
||||||
}
|
}
|
||||||
|
|
||||||
const storagePath = this._context.storageUri?.fsPath;
|
const storagePath = this._context.storageUri?.fsPath;
|
||||||
if (!storagePath) {return;}
|
if (!storagePath) { return; }
|
||||||
|
|
||||||
// Create permission requests directory
|
// Create permission requests directory
|
||||||
this._permissionRequestsPath = path.join(path.join(storagePath, 'permission-requests'));
|
this._permissionRequestsPath = path.join(path.join(storagePath, 'permission-requests'));
|
||||||
@@ -1193,13 +1242,13 @@ class ClaudeChatProvider {
|
|||||||
|
|
||||||
private async _showPermissionDialog(request: any): Promise<boolean> {
|
private async _showPermissionDialog(request: any): Promise<boolean> {
|
||||||
const toolName = request.tool || 'Unknown Tool';
|
const toolName = request.tool || 'Unknown Tool';
|
||||||
|
|
||||||
// Generate pattern for Bash commands
|
// Generate pattern for Bash commands
|
||||||
let pattern = undefined;
|
let pattern = undefined;
|
||||||
if (toolName === 'Bash' && request.input?.command) {
|
if (toolName === 'Bash' && request.input?.command) {
|
||||||
pattern = this.getCommandPattern(request.input.command);
|
pattern = this.getCommandPattern(request.input.command);
|
||||||
}
|
}
|
||||||
|
|
||||||
// Send permission request to the UI
|
// Send permission request to the UI
|
||||||
this._postMessage({
|
this._postMessage({
|
||||||
type: 'permissionRequest',
|
type: 'permissionRequest',
|
||||||
@@ -1225,7 +1274,7 @@ class ClaudeChatProvider {
|
|||||||
if (resolver) {
|
if (resolver) {
|
||||||
resolver(approved);
|
resolver(approved);
|
||||||
this._pendingPermissionResolvers.delete(id);
|
this._pendingPermissionResolvers.delete(id);
|
||||||
|
|
||||||
// Handle always allow setting
|
// Handle always allow setting
|
||||||
if (alwaysAllow && approved) {
|
if (alwaysAllow && approved) {
|
||||||
void this._saveAlwaysAllowPermission(id);
|
void this._saveAlwaysAllowPermission(id);
|
||||||
@@ -1241,7 +1290,7 @@ class ClaudeChatProvider {
|
|||||||
if (!storagePath) return;
|
if (!storagePath) return;
|
||||||
|
|
||||||
const requestFileUri = vscode.Uri.file(path.join(storagePath, 'permission-requests', `${requestId}.request`));
|
const requestFileUri = vscode.Uri.file(path.join(storagePath, 'permission-requests', `${requestId}.request`));
|
||||||
|
|
||||||
let requestContent: Uint8Array;
|
let requestContent: Uint8Array;
|
||||||
try {
|
try {
|
||||||
requestContent = await vscode.workspace.fs.readFile(requestFileUri);
|
requestContent = await vscode.workspace.fs.readFile(requestFileUri);
|
||||||
@@ -1250,11 +1299,11 @@ class ClaudeChatProvider {
|
|||||||
}
|
}
|
||||||
|
|
||||||
const request = JSON.parse(new TextDecoder().decode(requestContent));
|
const request = JSON.parse(new TextDecoder().decode(requestContent));
|
||||||
|
|
||||||
// Load existing workspace permissions
|
// Load existing workspace permissions
|
||||||
const permissionsUri = vscode.Uri.file(path.join(storagePath, 'permission-requests', 'permissions.json'));
|
const permissionsUri = vscode.Uri.file(path.join(storagePath, 'permission-requests', 'permissions.json'));
|
||||||
let permissions: any = { alwaysAllow: {} };
|
let permissions: any = { alwaysAllow: {} };
|
||||||
|
|
||||||
try {
|
try {
|
||||||
const content = await vscode.workspace.fs.readFile(permissionsUri);
|
const content = await vscode.workspace.fs.readFile(permissionsUri);
|
||||||
permissions = JSON.parse(new TextDecoder().decode(content));
|
permissions = JSON.parse(new TextDecoder().decode(content));
|
||||||
@@ -1292,7 +1341,7 @@ class ClaudeChatProvider {
|
|||||||
// Save the permissions
|
// Save the permissions
|
||||||
const permissionsContent = new TextEncoder().encode(JSON.stringify(permissions, null, 2));
|
const permissionsContent = new TextEncoder().encode(JSON.stringify(permissions, null, 2));
|
||||||
await vscode.workspace.fs.writeFile(permissionsUri, permissionsContent);
|
await vscode.workspace.fs.writeFile(permissionsUri, permissionsContent);
|
||||||
|
|
||||||
console.log(`Saved always-allow permission for ${toolName}`);
|
console.log(`Saved always-allow permission for ${toolName}`);
|
||||||
} catch (error) {
|
} catch (error) {
|
||||||
console.error('Error saving always-allow permission:', error);
|
console.error('Error saving always-allow permission:', error);
|
||||||
@@ -1302,10 +1351,10 @@ class ClaudeChatProvider {
|
|||||||
private getCommandPattern(command: string): string {
|
private getCommandPattern(command: string): string {
|
||||||
const parts = command.trim().split(/\s+/);
|
const parts = command.trim().split(/\s+/);
|
||||||
if (parts.length === 0) return command;
|
if (parts.length === 0) return command;
|
||||||
|
|
||||||
const baseCmd = parts[0];
|
const baseCmd = parts[0];
|
||||||
const subCmd = parts.length > 1 ? parts[1] : '';
|
const subCmd = parts.length > 1 ? parts[1] : '';
|
||||||
|
|
||||||
// Common patterns that should use wildcards
|
// Common patterns that should use wildcards
|
||||||
const patterns = [
|
const patterns = [
|
||||||
// Package managers
|
// Package managers
|
||||||
@@ -1322,7 +1371,7 @@ class ClaudeChatProvider {
|
|||||||
['pnpm', 'install', 'pnpm install *'],
|
['pnpm', 'install', 'pnpm install *'],
|
||||||
['pnpm', 'add', 'pnpm add *'],
|
['pnpm', 'add', 'pnpm add *'],
|
||||||
['pnpm', 'remove', 'pnpm remove *'],
|
['pnpm', 'remove', 'pnpm remove *'],
|
||||||
|
|
||||||
// Git commands
|
// Git commands
|
||||||
['git', 'add', 'git add *'],
|
['git', 'add', 'git add *'],
|
||||||
['git', 'commit', 'git commit *'],
|
['git', 'commit', 'git commit *'],
|
||||||
@@ -1335,7 +1384,7 @@ class ClaudeChatProvider {
|
|||||||
['git', 'reset', 'git reset *'],
|
['git', 'reset', 'git reset *'],
|
||||||
['git', 'rebase', 'git rebase *'],
|
['git', 'rebase', 'git rebase *'],
|
||||||
['git', 'tag', 'git tag *'],
|
['git', 'tag', 'git tag *'],
|
||||||
|
|
||||||
// Docker commands
|
// Docker commands
|
||||||
['docker', 'run', 'docker run *'],
|
['docker', 'run', 'docker run *'],
|
||||||
['docker', 'build', 'docker build *'],
|
['docker', 'build', 'docker build *'],
|
||||||
@@ -1347,7 +1396,7 @@ class ClaudeChatProvider {
|
|||||||
['docker', 'rmi', 'docker rmi *'],
|
['docker', 'rmi', 'docker rmi *'],
|
||||||
['docker', 'pull', 'docker pull *'],
|
['docker', 'pull', 'docker pull *'],
|
||||||
['docker', 'push', 'docker push *'],
|
['docker', 'push', 'docker push *'],
|
||||||
|
|
||||||
// Build tools
|
// Build tools
|
||||||
['make', '', 'make *'],
|
['make', '', 'make *'],
|
||||||
['cargo', 'build', 'cargo build *'],
|
['cargo', 'build', 'cargo build *'],
|
||||||
@@ -1359,7 +1408,7 @@ class ClaudeChatProvider {
|
|||||||
['mvn', 'package', 'mvn package *'],
|
['mvn', 'package', 'mvn package *'],
|
||||||
['gradle', 'build', 'gradle build *'],
|
['gradle', 'build', 'gradle build *'],
|
||||||
['gradle', 'test', 'gradle test *'],
|
['gradle', 'test', 'gradle test *'],
|
||||||
|
|
||||||
// System commands
|
// System commands
|
||||||
['curl', '', 'curl *'],
|
['curl', '', 'curl *'],
|
||||||
['wget', '', 'wget *'],
|
['wget', '', 'wget *'],
|
||||||
@@ -1369,7 +1418,7 @@ class ClaudeChatProvider {
|
|||||||
['tar', '', 'tar *'],
|
['tar', '', 'tar *'],
|
||||||
['zip', '', 'zip *'],
|
['zip', '', 'zip *'],
|
||||||
['unzip', '', 'unzip *'],
|
['unzip', '', 'unzip *'],
|
||||||
|
|
||||||
// Development tools
|
// Development tools
|
||||||
['node', '', 'node *'],
|
['node', '', 'node *'],
|
||||||
['python', '', 'python *'],
|
['python', '', 'python *'],
|
||||||
@@ -1381,14 +1430,14 @@ class ClaudeChatProvider {
|
|||||||
['bundle', 'install', 'bundle install *'],
|
['bundle', 'install', 'bundle install *'],
|
||||||
['gem', 'install', 'gem install *'],
|
['gem', 'install', 'gem install *'],
|
||||||
];
|
];
|
||||||
|
|
||||||
// Find matching pattern
|
// Find matching pattern
|
||||||
for (const [cmd, sub, pattern] of patterns) {
|
for (const [cmd, sub, pattern] of patterns) {
|
||||||
if (baseCmd === cmd && (sub === '' || subCmd === sub)) {
|
if (baseCmd === cmd && (sub === '' || subCmd === sub)) {
|
||||||
return pattern;
|
return pattern;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
// Default: return exact command
|
// Default: return exact command
|
||||||
return command;
|
return command;
|
||||||
}
|
}
|
||||||
@@ -1406,7 +1455,7 @@ class ClaudeChatProvider {
|
|||||||
|
|
||||||
const permissionsUri = vscode.Uri.file(path.join(storagePath, 'permission-requests', 'permissions.json'));
|
const permissionsUri = vscode.Uri.file(path.join(storagePath, 'permission-requests', 'permissions.json'));
|
||||||
let permissions: any = { alwaysAllow: {} };
|
let permissions: any = { alwaysAllow: {} };
|
||||||
|
|
||||||
try {
|
try {
|
||||||
const content = await vscode.workspace.fs.readFile(permissionsUri);
|
const content = await vscode.workspace.fs.readFile(permissionsUri);
|
||||||
permissions = JSON.parse(new TextDecoder().decode(content));
|
permissions = JSON.parse(new TextDecoder().decode(content));
|
||||||
@@ -1434,7 +1483,7 @@ class ClaudeChatProvider {
|
|||||||
|
|
||||||
const permissionsUri = vscode.Uri.file(path.join(storagePath, 'permission-requests', 'permissions.json'));
|
const permissionsUri = vscode.Uri.file(path.join(storagePath, 'permission-requests', 'permissions.json'));
|
||||||
let permissions: any = { alwaysAllow: {} };
|
let permissions: any = { alwaysAllow: {} };
|
||||||
|
|
||||||
try {
|
try {
|
||||||
const content = await vscode.workspace.fs.readFile(permissionsUri);
|
const content = await vscode.workspace.fs.readFile(permissionsUri);
|
||||||
permissions = JSON.parse(new TextDecoder().decode(content));
|
permissions = JSON.parse(new TextDecoder().decode(content));
|
||||||
@@ -1463,10 +1512,10 @@ class ClaudeChatProvider {
|
|||||||
// Save updated permissions
|
// Save updated permissions
|
||||||
const permissionsContent = new TextEncoder().encode(JSON.stringify(permissions, null, 2));
|
const permissionsContent = new TextEncoder().encode(JSON.stringify(permissions, null, 2));
|
||||||
await vscode.workspace.fs.writeFile(permissionsUri, permissionsContent);
|
await vscode.workspace.fs.writeFile(permissionsUri, permissionsContent);
|
||||||
|
|
||||||
// Send updated permissions to UI
|
// Send updated permissions to UI
|
||||||
this._sendPermissions();
|
this._sendPermissions();
|
||||||
|
|
||||||
console.log(`Removed permission for ${toolName}${command ? ` command: ${command}` : ''}`);
|
console.log(`Removed permission for ${toolName}${command ? ` command: ${command}` : ''}`);
|
||||||
} catch (error) {
|
} catch (error) {
|
||||||
console.error('Error removing permission:', error);
|
console.error('Error removing permission:', error);
|
||||||
@@ -1480,7 +1529,7 @@ class ClaudeChatProvider {
|
|||||||
|
|
||||||
const permissionsUri = vscode.Uri.file(path.join(storagePath, 'permission-requests', 'permissions.json'));
|
const permissionsUri = vscode.Uri.file(path.join(storagePath, 'permission-requests', 'permissions.json'));
|
||||||
let permissions: any = { alwaysAllow: {} };
|
let permissions: any = { alwaysAllow: {} };
|
||||||
|
|
||||||
try {
|
try {
|
||||||
const content = await vscode.workspace.fs.readFile(permissionsUri);
|
const content = await vscode.workspace.fs.readFile(permissionsUri);
|
||||||
permissions = JSON.parse(new TextDecoder().decode(content));
|
permissions = JSON.parse(new TextDecoder().decode(content));
|
||||||
@@ -1497,19 +1546,19 @@ class ClaudeChatProvider {
|
|||||||
if (!permissions.alwaysAllow[toolName]) {
|
if (!permissions.alwaysAllow[toolName]) {
|
||||||
permissions.alwaysAllow[toolName] = [];
|
permissions.alwaysAllow[toolName] = [];
|
||||||
}
|
}
|
||||||
|
|
||||||
// Convert to array if it's currently set to true
|
// Convert to array if it's currently set to true
|
||||||
if (permissions.alwaysAllow[toolName] === true) {
|
if (permissions.alwaysAllow[toolName] === true) {
|
||||||
permissions.alwaysAllow[toolName] = [];
|
permissions.alwaysAllow[toolName] = [];
|
||||||
}
|
}
|
||||||
|
|
||||||
if (Array.isArray(permissions.alwaysAllow[toolName])) {
|
if (Array.isArray(permissions.alwaysAllow[toolName])) {
|
||||||
// For Bash commands, convert to pattern using existing logic
|
// For Bash commands, convert to pattern using existing logic
|
||||||
let commandToAdd = command;
|
let commandToAdd = command;
|
||||||
if (toolName === 'Bash') {
|
if (toolName === 'Bash') {
|
||||||
commandToAdd = this.getCommandPattern(command);
|
commandToAdd = this.getCommandPattern(command);
|
||||||
}
|
}
|
||||||
|
|
||||||
// Add if not already present
|
// Add if not already present
|
||||||
if (!permissions.alwaysAllow[toolName].includes(commandToAdd)) {
|
if (!permissions.alwaysAllow[toolName].includes(commandToAdd)) {
|
||||||
permissions.alwaysAllow[toolName].push(commandToAdd);
|
permissions.alwaysAllow[toolName].push(commandToAdd);
|
||||||
@@ -1528,10 +1577,10 @@ class ClaudeChatProvider {
|
|||||||
// Save updated permissions
|
// Save updated permissions
|
||||||
const permissionsContent = new TextEncoder().encode(JSON.stringify(permissions, null, 2));
|
const permissionsContent = new TextEncoder().encode(JSON.stringify(permissions, null, 2));
|
||||||
await vscode.workspace.fs.writeFile(permissionsUri, permissionsContent);
|
await vscode.workspace.fs.writeFile(permissionsUri, permissionsContent);
|
||||||
|
|
||||||
// Send updated permissions to UI
|
// Send updated permissions to UI
|
||||||
this._sendPermissions();
|
this._sendPermissions();
|
||||||
|
|
||||||
console.log(`Added permission for ${toolName}${command ? ` command: ${command}` : ' (all commands)'}`);
|
console.log(`Added permission for ${toolName}${command ? ` command: ${command}` : ' (all commands)'}`);
|
||||||
} catch (error) {
|
} catch (error) {
|
||||||
console.error('Error adding permission:', error);
|
console.error('Error adding permission:', error);
|
||||||
@@ -1558,10 +1607,10 @@ class ClaudeChatProvider {
|
|||||||
}
|
}
|
||||||
|
|
||||||
// Filter out internal servers before sending to UI
|
// Filter out internal servers before sending to UI
|
||||||
const filteredServers = Object.fromEntries(
|
const filteredServers = Object.fromEntries(
|
||||||
Object.entries(mcpConfig.mcpServers || {}).filter(([name]) => name !== 'claude-code-chat-permissions')
|
Object.entries(mcpConfig.mcpServers || {}).filter(([name]) => name !== 'claude-code-chat-permissions')
|
||||||
);
|
);
|
||||||
this._postMessage({ type: 'mcpServers', data: filteredServers });
|
this._postMessage({ type: 'mcpServers', data: filteredServers });
|
||||||
} catch (error) {
|
} catch (error) {
|
||||||
console.error('Error loading MCP servers:', error);
|
console.error('Error loading MCP servers:', error);
|
||||||
this._postMessage({ type: 'mcpServerError', data: { error: 'Failed to load MCP servers' } });
|
this._postMessage({ type: 'mcpServerError', data: { error: 'Failed to load MCP servers' } });
|
||||||
@@ -1657,7 +1706,7 @@ class ClaudeChatProvider {
|
|||||||
|
|
||||||
private async _sendCustomSnippets(): Promise<void> {
|
private async _sendCustomSnippets(): Promise<void> {
|
||||||
try {
|
try {
|
||||||
const customSnippets = this._context.globalState.get<{[key: string]: any}>('customPromptSnippets', {});
|
const customSnippets = this._context.globalState.get<{ [key: string]: any }>('customPromptSnippets', {});
|
||||||
this._postMessage({
|
this._postMessage({
|
||||||
type: 'customSnippetsData',
|
type: 'customSnippetsData',
|
||||||
data: customSnippets
|
data: customSnippets
|
||||||
@@ -1673,16 +1722,16 @@ class ClaudeChatProvider {
|
|||||||
|
|
||||||
private async _saveCustomSnippet(snippet: any): Promise<void> {
|
private async _saveCustomSnippet(snippet: any): Promise<void> {
|
||||||
try {
|
try {
|
||||||
const customSnippets = this._context.globalState.get<{[key: string]: any}>('customPromptSnippets', {});
|
const customSnippets = this._context.globalState.get<{ [key: string]: any }>('customPromptSnippets', {});
|
||||||
customSnippets[snippet.id] = snippet;
|
customSnippets[snippet.id] = snippet;
|
||||||
|
|
||||||
await this._context.globalState.update('customPromptSnippets', customSnippets);
|
await this._context.globalState.update('customPromptSnippets', customSnippets);
|
||||||
|
|
||||||
this._postMessage({
|
this._postMessage({
|
||||||
type: 'customSnippetSaved',
|
type: 'customSnippetSaved',
|
||||||
data: { snippet }
|
data: { snippet }
|
||||||
});
|
});
|
||||||
|
|
||||||
console.log('Saved custom snippet:', snippet.name);
|
console.log('Saved custom snippet:', snippet.name);
|
||||||
} catch (error) {
|
} catch (error) {
|
||||||
console.error('Error saving custom snippet:', error);
|
console.error('Error saving custom snippet:', error);
|
||||||
@@ -1695,17 +1744,17 @@ class ClaudeChatProvider {
|
|||||||
|
|
||||||
private async _deleteCustomSnippet(snippetId: string): Promise<void> {
|
private async _deleteCustomSnippet(snippetId: string): Promise<void> {
|
||||||
try {
|
try {
|
||||||
const customSnippets = this._context.globalState.get<{[key: string]: any}>('customPromptSnippets', {});
|
const customSnippets = this._context.globalState.get<{ [key: string]: any }>('customPromptSnippets', {});
|
||||||
|
|
||||||
if (customSnippets[snippetId]) {
|
if (customSnippets[snippetId]) {
|
||||||
delete customSnippets[snippetId];
|
delete customSnippets[snippetId];
|
||||||
await this._context.globalState.update('customPromptSnippets', customSnippets);
|
await this._context.globalState.update('customPromptSnippets', customSnippets);
|
||||||
|
|
||||||
this._postMessage({
|
this._postMessage({
|
||||||
type: 'customSnippetDeleted',
|
type: 'customSnippetDeleted',
|
||||||
data: { snippetId }
|
data: { snippetId }
|
||||||
});
|
});
|
||||||
|
|
||||||
console.log('Deleted custom snippet:', snippetId);
|
console.log('Deleted custom snippet:', snippetId);
|
||||||
} else {
|
} else {
|
||||||
this._postMessage({
|
this._postMessage({
|
||||||
@@ -1725,24 +1774,24 @@ class ClaudeChatProvider {
|
|||||||
private convertToWSLPath(windowsPath: string): string {
|
private convertToWSLPath(windowsPath: string): string {
|
||||||
const config = vscode.workspace.getConfiguration('claudeCodeChat');
|
const config = vscode.workspace.getConfiguration('claudeCodeChat');
|
||||||
const wslEnabled = config.get<boolean>('wsl.enabled', false);
|
const wslEnabled = config.get<boolean>('wsl.enabled', false);
|
||||||
|
|
||||||
if (wslEnabled && windowsPath.match(/^[a-zA-Z]:/)) {
|
if (wslEnabled && windowsPath.match(/^[a-zA-Z]:/)) {
|
||||||
// Convert C:\Users\... to /mnt/c/Users/...
|
// Convert C:\Users\... to /mnt/c/Users/...
|
||||||
return windowsPath.replace(/^([a-zA-Z]):/, '/mnt/$1').toLowerCase().replace(/\\/g, '/');
|
return windowsPath.replace(/^([a-zA-Z]):/, '/mnt/$1').toLowerCase().replace(/\\/g, '/');
|
||||||
}
|
}
|
||||||
|
|
||||||
return windowsPath;
|
return windowsPath;
|
||||||
}
|
}
|
||||||
|
|
||||||
public getMCPConfigPath(): string | undefined {
|
public getMCPConfigPath(): string | undefined {
|
||||||
const storagePath = this._context.storageUri?.fsPath;
|
const storagePath = this._context.storageUri?.fsPath;
|
||||||
if (!storagePath) {return undefined;}
|
if (!storagePath) { return undefined; }
|
||||||
|
|
||||||
const configPath = path.join(storagePath, 'mcp', 'mcp-servers.json');
|
const configPath = path.join(storagePath, 'mcp', 'mcp-servers.json');
|
||||||
return path.join(configPath);
|
return path.join(configPath);
|
||||||
}
|
}
|
||||||
|
|
||||||
private _sendAndSaveMessage(message: { type: string, data: any }, options?: { isProcessing?: boolean }): void {
|
private _sendAndSaveMessage(message: { type: string, data: any }): void {
|
||||||
|
|
||||||
// Initialize conversation if this is the first message
|
// Initialize conversation if this is the first message
|
||||||
if (this._currentConversation.length === 0) {
|
if (this._currentConversation.length === 0) {
|
||||||
@@ -1764,10 +1813,8 @@ class ClaudeChatProvider {
|
|||||||
}
|
}
|
||||||
|
|
||||||
private async _saveCurrentConversation(): Promise<void> {
|
private async _saveCurrentConversation(): Promise<void> {
|
||||||
if (!this._conversationsPath || this._currentConversation.length === 0) {return;}
|
if (!this._conversationsPath || this._currentConversation.length === 0) { return; }
|
||||||
if(!this._currentSessionId) {return;}
|
if (!this._currentSessionId) { return; }
|
||||||
|
|
||||||
console.log("IS PROCESSING", this._isProcessing)
|
|
||||||
|
|
||||||
try {
|
try {
|
||||||
// Create filename from first user message and timestamp
|
// Create filename from first user message and timestamp
|
||||||
@@ -1786,7 +1833,7 @@ class ClaudeChatProvider {
|
|||||||
const datePrefix = startTime.substring(0, 16).replace('T', '_').replace(/:/g, '-');
|
const datePrefix = startTime.substring(0, 16).replace('T', '_').replace(/:/g, '-');
|
||||||
const filename = `${datePrefix}_${cleanMessage}.json`;
|
const filename = `${datePrefix}_${cleanMessage}.json`;
|
||||||
|
|
||||||
const conversationData : ConversationData = {
|
const conversationData: ConversationData = {
|
||||||
sessionId: sessionId,
|
sessionId: sessionId,
|
||||||
startTime: this._conversationStartTime,
|
startTime: this._conversationStartTime,
|
||||||
endTime: new Date().toISOString(),
|
endTime: new Date().toISOString(),
|
||||||
@@ -1800,10 +1847,6 @@ class ClaudeChatProvider {
|
|||||||
filename
|
filename
|
||||||
};
|
};
|
||||||
|
|
||||||
if (this._isProcessing !== undefined){
|
|
||||||
conversationData.isProcessing = this._isProcessing || false
|
|
||||||
}
|
|
||||||
|
|
||||||
const filePath = path.join(this._conversationsPath, filename);
|
const filePath = path.join(this._conversationsPath, filename);
|
||||||
const content = new TextEncoder().encode(JSON.stringify(conversationData, null, 2));
|
const content = new TextEncoder().encode(JSON.stringify(conversationData, null, 2));
|
||||||
await vscode.workspace.fs.writeFile(vscode.Uri.file(filePath), content);
|
await vscode.workspace.fs.writeFile(vscode.Uri.file(filePath), content);
|
||||||
@@ -1854,11 +1897,11 @@ class ClaudeChatProvider {
|
|||||||
fileList = fileList.filter(file => {
|
fileList = fileList.filter(file => {
|
||||||
const fileName = file.name.toLowerCase();
|
const fileName = file.name.toLowerCase();
|
||||||
const filePath = file.path.toLowerCase();
|
const filePath = file.path.toLowerCase();
|
||||||
|
|
||||||
// Check if term matches filename or any part of the path
|
// Check if term matches filename or any part of the path
|
||||||
return fileName.includes(term) ||
|
return fileName.includes(term) ||
|
||||||
filePath.includes(term) ||
|
filePath.includes(term) ||
|
||||||
filePath.split('/').some(segment => segment.includes(term));
|
filePath.split('/').some(segment => segment.includes(term));
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -1892,7 +1935,7 @@ class ClaudeChatProvider {
|
|||||||
'Images': ['png', 'jpg', 'jpeg', 'gif', 'svg', 'webp', 'bmp']
|
'Images': ['png', 'jpg', 'jpeg', 'gif', 'svg', 'webp', 'bmp']
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
|
|
||||||
if (result && result.length > 0) {
|
if (result && result.length > 0) {
|
||||||
// Send the selected file paths back to webview
|
// Send the selected file paths back to webview
|
||||||
result.forEach(uri => {
|
result.forEach(uri => {
|
||||||
@@ -1902,7 +1945,7 @@ class ClaudeChatProvider {
|
|||||||
});
|
});
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
} catch (error) {
|
} catch (error) {
|
||||||
console.error('Error selecting image files:', error);
|
console.error('Error selecting image files:', error);
|
||||||
}
|
}
|
||||||
@@ -1912,19 +1955,19 @@ class ClaudeChatProvider {
|
|||||||
console.log('Stop request received');
|
console.log('Stop request received');
|
||||||
|
|
||||||
this._isProcessing = false
|
this._isProcessing = false
|
||||||
|
|
||||||
// Update UI state
|
// Update UI state
|
||||||
this._postMessage({
|
this._postMessage({
|
||||||
type: 'setProcessing',
|
type: 'setProcessing',
|
||||||
data: {isProcessing: false}
|
data: { isProcessing: false }
|
||||||
});
|
});
|
||||||
|
|
||||||
if (this._currentClaudeProcess) {
|
if (this._currentClaudeProcess) {
|
||||||
console.log('Terminating Claude process...');
|
console.log('Terminating Claude process...');
|
||||||
|
|
||||||
// Try graceful termination first
|
// Try graceful termination first
|
||||||
this._currentClaudeProcess.kill('SIGTERM');
|
this._currentClaudeProcess.kill('SIGTERM');
|
||||||
|
|
||||||
// Force kill after 2 seconds if still running
|
// Force kill after 2 seconds if still running
|
||||||
setTimeout(() => {
|
setTimeout(() => {
|
||||||
if (this._currentClaudeProcess && !this._currentClaudeProcess.killed) {
|
if (this._currentClaudeProcess && !this._currentClaudeProcess.killed) {
|
||||||
@@ -1932,20 +1975,20 @@ class ClaudeChatProvider {
|
|||||||
this._currentClaudeProcess.kill('SIGKILL');
|
this._currentClaudeProcess.kill('SIGKILL');
|
||||||
}
|
}
|
||||||
}, 2000);
|
}, 2000);
|
||||||
|
|
||||||
// Clear process reference
|
// Clear process reference
|
||||||
this._currentClaudeProcess = undefined;
|
this._currentClaudeProcess = undefined;
|
||||||
|
|
||||||
this._postMessage({
|
this._postMessage({
|
||||||
type: 'clearLoading'
|
type: 'clearLoading'
|
||||||
});
|
});
|
||||||
|
|
||||||
// Send stop confirmation message directly to UI and save
|
// Send stop confirmation message directly to UI and save
|
||||||
this._sendAndSaveMessage({
|
this._sendAndSaveMessage({
|
||||||
type: 'error',
|
type: 'error',
|
||||||
data: '⏹️ Claude code was stopped.'
|
data: '⏹️ Claude code was stopped.'
|
||||||
});
|
});
|
||||||
|
|
||||||
console.log('Claude process termination initiated');
|
console.log('Claude process termination initiated');
|
||||||
} else {
|
} else {
|
||||||
console.log('No Claude process running to stop');
|
console.log('No Claude process running to stop');
|
||||||
@@ -1991,12 +2034,12 @@ class ClaudeChatProvider {
|
|||||||
|
|
||||||
private async _loadConversationHistory(filename: string): Promise<void> {
|
private async _loadConversationHistory(filename: string): Promise<void> {
|
||||||
console.log("_loadConversationHistory");
|
console.log("_loadConversationHistory");
|
||||||
if (!this._conversationsPath) {return;}
|
if (!this._conversationsPath) { return; }
|
||||||
|
|
||||||
try {
|
try {
|
||||||
const filePath = path.join(this._conversationsPath, filename);
|
const filePath = path.join(this._conversationsPath, filename);
|
||||||
console.log("filePath", filePath);
|
console.log("filePath", filePath);
|
||||||
|
|
||||||
let conversationData: ConversationData;
|
let conversationData: ConversationData;
|
||||||
try {
|
try {
|
||||||
const fileUri = vscode.Uri.file(filePath);
|
const fileUri = vscode.Uri.file(filePath);
|
||||||
@@ -2005,8 +2048,7 @@ class ClaudeChatProvider {
|
|||||||
} catch {
|
} catch {
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
console.log("conversationData-----", conversationData);
|
|
||||||
// Load conversation into current state
|
// Load conversation into current state
|
||||||
this._currentConversation = conversationData.messages || [];
|
this._currentConversation = conversationData.messages || [];
|
||||||
this._conversationStartTime = conversationData.startTime;
|
this._conversationStartTime = conversationData.startTime;
|
||||||
@@ -2030,10 +2072,10 @@ class ClaudeChatProvider {
|
|||||||
type: message.messageType,
|
type: message.messageType,
|
||||||
data: message.data
|
data: message.data
|
||||||
});
|
});
|
||||||
if(message.messageType === 'userInput'){
|
if (message.messageType === 'userInput') {
|
||||||
try{
|
try {
|
||||||
requestStartTime = new Date(message.timestamp).getTime()
|
requestStartTime = new Date(message.timestamp).getTime()
|
||||||
}catch(e){
|
} catch (e) {
|
||||||
console.log(e)
|
console.log(e)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -2051,11 +2093,10 @@ class ClaudeChatProvider {
|
|||||||
});
|
});
|
||||||
|
|
||||||
// Restore processing state if the conversation was saved while processing
|
// Restore processing state if the conversation was saved while processing
|
||||||
if (conversationData.isProcessing) {
|
if (this._isProcessing) {
|
||||||
this._isProcessing = conversationData.isProcessing;
|
|
||||||
this._postMessage({
|
this._postMessage({
|
||||||
type: 'setProcessing',
|
type: 'setProcessing',
|
||||||
data: {isProcessing: conversationData.isProcessing, requestStartTime}
|
data: { isProcessing: this._isProcessing, requestStartTime }
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
// Send ready message after conversation is loaded
|
// Send ready message after conversation is loaded
|
||||||
@@ -2094,15 +2135,15 @@ class ClaudeChatProvider {
|
|||||||
try {
|
try {
|
||||||
// Update VS Code configuration to enable YOLO mode
|
// Update VS Code configuration to enable YOLO mode
|
||||||
const config = vscode.workspace.getConfiguration('claudeCodeChat');
|
const config = vscode.workspace.getConfiguration('claudeCodeChat');
|
||||||
|
|
||||||
// Clear any global setting and set workspace setting
|
// Clear any global setting and set workspace setting
|
||||||
await config.update('permissions.yoloMode', true, vscode.ConfigurationTarget.Workspace);
|
await config.update('permissions.yoloMode', true, vscode.ConfigurationTarget.Workspace);
|
||||||
|
|
||||||
console.log('YOLO Mode enabled - all future permissions will be skipped');
|
console.log('YOLO Mode enabled - all future permissions will be skipped');
|
||||||
|
|
||||||
// Send updated settings to UI
|
// Send updated settings to UI
|
||||||
this._sendCurrentSettings();
|
this._sendCurrentSettings();
|
||||||
|
|
||||||
} catch (error) {
|
} catch (error) {
|
||||||
console.error('Error enabling YOLO mode:', error);
|
console.error('Error enabling YOLO mode:', error);
|
||||||
}
|
}
|
||||||
@@ -2110,7 +2151,7 @@ class ClaudeChatProvider {
|
|||||||
|
|
||||||
private async _updateSettings(settings: { [key: string]: any }): Promise<void> {
|
private async _updateSettings(settings: { [key: string]: any }): Promise<void> {
|
||||||
const config = vscode.workspace.getConfiguration('claudeCodeChat');
|
const config = vscode.workspace.getConfiguration('claudeCodeChat');
|
||||||
|
|
||||||
try {
|
try {
|
||||||
for (const [key, value] of Object.entries(settings)) {
|
for (const [key, value] of Object.entries(settings)) {
|
||||||
if (key === 'permissions.yoloMode') {
|
if (key === 'permissions.yoloMode') {
|
||||||
@@ -2121,7 +2162,7 @@ class ClaudeChatProvider {
|
|||||||
await config.update(key, value, vscode.ConfigurationTarget.Global);
|
await config.update(key, value, vscode.ConfigurationTarget.Global);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
console.log('Settings updated:', settings);
|
console.log('Settings updated:', settings);
|
||||||
} catch (error) {
|
} catch (error) {
|
||||||
console.error('Failed to update settings:', error);
|
console.error('Failed to update settings:', error);
|
||||||
@@ -2147,10 +2188,10 @@ class ClaudeChatProvider {
|
|||||||
if (validModels.includes(model)) {
|
if (validModels.includes(model)) {
|
||||||
this._selectedModel = model;
|
this._selectedModel = model;
|
||||||
console.log('Model selected:', model);
|
console.log('Model selected:', model);
|
||||||
|
|
||||||
// Store the model preference in workspace state
|
// Store the model preference in workspace state
|
||||||
this._context.workspaceState.update('claude.selectedModel', model);
|
this._context.workspaceState.update('claude.selectedModel', model);
|
||||||
|
|
||||||
// Show confirmation
|
// Show confirmation
|
||||||
vscode.window.showInformationMessage(`Claude model switched to: ${model.charAt(0).toUpperCase() + model.slice(1)}`);
|
vscode.window.showInformationMessage(`Claude model switched to: ${model.charAt(0).toUpperCase() + model.slice(1)}`);
|
||||||
} else {
|
} else {
|
||||||
@@ -2168,7 +2209,7 @@ class ClaudeChatProvider {
|
|||||||
|
|
||||||
// Build command arguments
|
// Build command arguments
|
||||||
const args = ['/model'];
|
const args = ['/model'];
|
||||||
|
|
||||||
// Add session resume if we have a current session
|
// Add session resume if we have a current session
|
||||||
if (this._currentSessionId) {
|
if (this._currentSessionId) {
|
||||||
args.push('--resume', this._currentSessionId);
|
args.push('--resume', this._currentSessionId);
|
||||||
@@ -2205,7 +2246,7 @@ class ClaudeChatProvider {
|
|||||||
|
|
||||||
// Build command arguments
|
// Build command arguments
|
||||||
const args = [`/${command}`];
|
const args = [`/${command}`];
|
||||||
|
|
||||||
// Add session resume if we have a current session
|
// Add session resume if we have a current session
|
||||||
if (this._currentSessionId) {
|
if (this._currentSessionId) {
|
||||||
args.push('--resume', this._currentSessionId);
|
args.push('--resume', this._currentSessionId);
|
||||||
@@ -2236,7 +2277,7 @@ class ClaudeChatProvider {
|
|||||||
private _sendPlatformInfo() {
|
private _sendPlatformInfo() {
|
||||||
const platform = process.platform;
|
const platform = process.platform;
|
||||||
const dismissed = this._context.globalState.get<boolean>('wslAlertDismissed', false);
|
const dismissed = this._context.globalState.get<boolean>('wslAlertDismissed', false);
|
||||||
|
|
||||||
// Get WSL configuration
|
// Get WSL configuration
|
||||||
const config = vscode.workspace.getConfiguration('claudeCodeChat');
|
const config = vscode.workspace.getConfiguration('claudeCodeChat');
|
||||||
const wslEnabled = config.get<boolean>('wsl.enabled', false);
|
const wslEnabled = config.get<boolean>('wsl.enabled', false);
|
||||||
@@ -2270,23 +2311,23 @@ class ClaudeChatProvider {
|
|||||||
private async _createImageFile(imageData: string, imageType: string) {
|
private async _createImageFile(imageData: string, imageType: string) {
|
||||||
try {
|
try {
|
||||||
const workspaceFolder = vscode.workspace.workspaceFolders?.[0];
|
const workspaceFolder = vscode.workspace.workspaceFolders?.[0];
|
||||||
if (!workspaceFolder) {return;}
|
if (!workspaceFolder) { return; }
|
||||||
|
|
||||||
// Extract base64 data from data URL
|
// Extract base64 data from data URL
|
||||||
const base64Data = imageData.split(',')[1];
|
const base64Data = imageData.split(',')[1];
|
||||||
const buffer = Buffer.from(base64Data, 'base64');
|
const buffer = Buffer.from(base64Data, 'base64');
|
||||||
|
|
||||||
// Get file extension from image type
|
// Get file extension from image type
|
||||||
const extension = imageType.split('/')[1] || 'png';
|
const extension = imageType.split('/')[1] || 'png';
|
||||||
|
|
||||||
// Create unique filename with timestamp
|
// Create unique filename with timestamp
|
||||||
const timestamp = Date.now();
|
const timestamp = Date.now();
|
||||||
const imageFileName = `image_${timestamp}.${extension}`;
|
const imageFileName = `image_${timestamp}.${extension}`;
|
||||||
|
|
||||||
// Create images folder in workspace .claude directory
|
// Create images folder in workspace .claude directory
|
||||||
const imagesDir = vscode.Uri.joinPath(workspaceFolder.uri, '.claude', 'claude-code-chat-images');
|
const imagesDir = vscode.Uri.joinPath(workspaceFolder.uri, '.claude', 'claude-code-chat-images');
|
||||||
await vscode.workspace.fs.createDirectory(imagesDir);
|
await vscode.workspace.fs.createDirectory(imagesDir);
|
||||||
|
|
||||||
// Create .gitignore to ignore all images
|
// Create .gitignore to ignore all images
|
||||||
const gitignorePath = vscode.Uri.joinPath(imagesDir, '.gitignore');
|
const gitignorePath = vscode.Uri.joinPath(imagesDir, '.gitignore');
|
||||||
try {
|
try {
|
||||||
@@ -2296,11 +2337,11 @@ class ClaudeChatProvider {
|
|||||||
const gitignoreContent = new TextEncoder().encode('*\n');
|
const gitignoreContent = new TextEncoder().encode('*\n');
|
||||||
await vscode.workspace.fs.writeFile(gitignorePath, gitignoreContent);
|
await vscode.workspace.fs.writeFile(gitignorePath, gitignoreContent);
|
||||||
}
|
}
|
||||||
|
|
||||||
// Create the image file
|
// Create the image file
|
||||||
const imagePath = vscode.Uri.joinPath(imagesDir, imageFileName);
|
const imagePath = vscode.Uri.joinPath(imagesDir, imageFileName);
|
||||||
await vscode.workspace.fs.writeFile(imagePath, buffer);
|
await vscode.workspace.fs.writeFile(imagePath, buffer);
|
||||||
|
|
||||||
// Send the file path back to webview
|
// Send the file path back to webview
|
||||||
this._postMessage({
|
this._postMessage({
|
||||||
type: 'imagePath',
|
type: 'imagePath',
|
||||||
@@ -2308,7 +2349,7 @@ class ClaudeChatProvider {
|
|||||||
filePath: imagePath.fsPath
|
filePath: imagePath.fsPath
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
|
|
||||||
} catch (error) {
|
} catch (error) {
|
||||||
console.error('Error creating image file:', error);
|
console.error('Error creating image file:', error);
|
||||||
vscode.window.showErrorMessage('Failed to create image file');
|
vscode.window.showErrorMessage('Failed to create image file');
|
||||||
|
|||||||
Reference in New Issue
Block a user