release 0.0.1
This commit is contained in:
parent
ce4634767c
commit
5f154777f6
1
.gitignore
vendored
1
.gitignore
vendored
@ -4,3 +4,4 @@ node_modules
|
||||
.vscode-test/
|
||||
*.vsix
|
||||
.env
|
||||
.chatconfig.json
|
||||
|
69
README.md
69
README.md
@ -1,71 +1,46 @@
|
||||
# devchat README
|
||||
# DevChat
|
||||
|
||||
This is the README for your extension "devchat". After writing up a brief description, we recommend including the following sections.
|
||||
DevChat is a programming assistant that helps developers, testers, and operations staff automate many tasks.
|
||||
|
||||
## Features
|
||||
|
||||
Describe specific features of your extension including screenshots of your extension in action. Image paths are relative to this README file.
|
||||
|
||||
For example if there is an image subfolder under your extension project workspace:
|
||||
|
||||
\!\[feature X\]\(images/feature-x.png\)
|
||||
|
||||
> Tip: Many popular extensions utilize animations. This is an excellent way to show off your extension! We recommend short, focused animations that are easy to follow.
|
||||
- Generate code driven by questions
|
||||
- Create smarter commit messages
|
||||
|
||||
## Requirements
|
||||
|
||||
If you have any requirements or dependencies, add a section describing those and how to install and configure them.
|
||||
- Python package: `pip install devchat`
|
||||
- System package: `apt install dtm`
|
||||
- Set your `OPENAI_API_KEY` environment variable
|
||||
|
||||
## Extension Settings
|
||||
## Installation
|
||||
|
||||
Include if your extension adds any VS Code settings through the `contributes.configuration` extension point.
|
||||
Search for "DevChat" in the Visual Studio Code marketplace and click the "Install" button.
|
||||
|
||||
For example:
|
||||
## Usage
|
||||
|
||||
This extension contributes the following settings:
|
||||
Enter "DevChat" in the command palette to open the interactive page.
|
||||
|
||||
* `myExtension.enable`: Enable/disable this extension.
|
||||
* `myExtension.thing`: Set to `blah` to do something.
|
||||
## Settings
|
||||
|
||||
*Coming soon*
|
||||
|
||||
## Known Issues
|
||||
|
||||
Calling out known issues can help limit users opening duplicate issues against your extension.
|
||||
*Coming soon*
|
||||
|
||||
## Release Notes
|
||||
|
||||
Users appreciate release notes as you update your extension.
|
||||
*Coming soon*
|
||||
|
||||
### 1.0.0
|
||||
## Contributing
|
||||
|
||||
Initial release of ...
|
||||
*Coming soon*
|
||||
|
||||
### 1.0.1
|
||||
## License
|
||||
|
||||
Fixed issue #.
|
||||
*Specify the license here*
|
||||
|
||||
### 1.1.0
|
||||
## Contact Information
|
||||
|
||||
Added features X, Y, and Z.
|
||||
|
||||
---
|
||||
|
||||
## Following extension guidelines
|
||||
|
||||
Ensure that you've read through the extensions guidelines and follow the best practices for creating your extension.
|
||||
|
||||
* [Extension Guidelines](https://code.visualstudio.com/api/references/extension-guidelines)
|
||||
|
||||
## Working with Markdown
|
||||
|
||||
You can author your README using Visual Studio Code. Here are some useful editor keyboard shortcuts:
|
||||
|
||||
* Split the editor (`Cmd+\` on macOS or `Ctrl+\` on Windows and Linux).
|
||||
* Toggle preview (`Shift+Cmd+V` on macOS or `Shift+Ctrl+V` on Windows and Linux).
|
||||
* Press `Ctrl+Space` (Windows, Linux, macOS) to see a list of Markdown snippets.
|
||||
|
||||
## For more information
|
||||
|
||||
* [Visual Studio Code's Markdown Support](http://code.visualstudio.com/docs/languages/markdown)
|
||||
* [Markdown Syntax Reference](https://help.github.com/articles/markdown-basics/)
|
||||
|
||||
**Enjoy!**
|
||||
*Provide your contact information, such as an email address or a link to a GitHub repository*
|
||||
|
@ -47,6 +47,22 @@ pre {
|
||||
overflow: auto;
|
||||
}
|
||||
|
||||
.context-menu {
|
||||
position: absolute;
|
||||
display: none;
|
||||
background-color: white;
|
||||
border: 1px solid #ccc;
|
||||
padding: 8px;
|
||||
z-index: 10;
|
||||
}
|
||||
.context-menu-item {
|
||||
cursor: pointer;
|
||||
margin-bottom: 4px;
|
||||
}
|
||||
.context-menu-item:last-child {
|
||||
margin-bottom: 0;
|
||||
}
|
||||
|
||||
.copy-button {
|
||||
background-color: #007acc;
|
||||
color: white;
|
||||
|
@ -26,6 +26,11 @@
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<div class="context-menu" id="context-menu">
|
||||
<div class="context-menu-item" id="menu-item-1">Insert Code</div>
|
||||
<div class="context-menu-item" id="menu-item-2">Copy</div>
|
||||
</div>
|
||||
|
||||
<!-- Load the chatPanel.js file -->
|
||||
<script src="<vscode-resource:/chatUI.js>"></script>
|
||||
<script src="<vscode-resource:/resizeInput.js>"></script>
|
||||
|
@ -1,11 +1,68 @@
|
||||
// chatUI.js
|
||||
|
||||
const vscode_api = acquireVsCodeApi();
|
||||
const md = new markdownit();
|
||||
|
||||
function addMessageToUI(role, content) {
|
||||
function getLastBotMessageItem(messagesContainer) {
|
||||
const lastMessage = messagesContainer.lastElementChild;
|
||||
|
||||
if (lastMessage && lastMessage.classList.contains('message-item')) {
|
||||
const lastMessageIcon = lastMessage.querySelector('i');
|
||||
if (lastMessageIcon && lastMessageIcon.classList.contains('fa-robot')) {
|
||||
return lastMessage;
|
||||
}
|
||||
}
|
||||
|
||||
return null;
|
||||
}
|
||||
|
||||
function initButtonForCodeBlock(codeBlocks) {
|
||||
codeBlocks.forEach(block => {
|
||||
block.classList.add('code-block');
|
||||
});
|
||||
|
||||
initClipboard(codeBlocks, (patchContent) => {
|
||||
postVSCodeMessage({
|
||||
command: 'block_apply',
|
||||
content: patchContent,
|
||||
});
|
||||
}, (codeContent) => {
|
||||
postVSCodeMessage({
|
||||
command: 'code_apply',
|
||||
content: codeContent,
|
||||
});
|
||||
}, (codeContent) => {
|
||||
postVSCodeMessage({
|
||||
command: 'code_file_apply',
|
||||
content: codeContent,
|
||||
});
|
||||
});
|
||||
}
|
||||
|
||||
function addMessageToUI(role, content, partial = false) {
|
||||
// Create a MarkdownIt instance for rendering markdown content
|
||||
const messagesContainer = document.getElementById('messages-container');
|
||||
|
||||
// Create a container for the message item
|
||||
// Render the markdown content inside the message content container
|
||||
const renderedContent = md.render(content);
|
||||
|
||||
let lastBotMessage = getLastBotMessageItem(messagesContainer);
|
||||
let lastMessageContent;
|
||||
|
||||
if (role == 'bot' && lastBotMessage != null) {
|
||||
lastMessageContent = lastBotMessage.querySelector('.message-content');
|
||||
lastMessageContent.innerHTML = renderedContent;
|
||||
|
||||
if (!partial) {
|
||||
// Find any code blocks in the rendered content and add a class to style them
|
||||
const codeBlocks = lastMessageContent.querySelectorAll('pre > code');
|
||||
|
||||
// Initialize the Apply Patch functionality
|
||||
initButtonForCodeBlock(codeBlocks);
|
||||
}
|
||||
return;
|
||||
}
|
||||
|
||||
const messageItem = document.createElement('div');
|
||||
messageItem.classList.add('message-item');
|
||||
|
||||
@ -17,17 +74,13 @@ function addMessageToUI(role, content) {
|
||||
// Create a container for the message content
|
||||
const messageContent = document.createElement('div');
|
||||
messageContent.classList.add('message-content');
|
||||
|
||||
// Render the markdown content inside the message content container
|
||||
const renderedContent = md.render(content);
|
||||
messageContent.innerHTML = renderedContent;
|
||||
|
||||
// Find any code blocks in the rendered content and add a class to style them
|
||||
const codeBlocks = messageContent.querySelectorAll('pre > code');
|
||||
codeBlocks.forEach(block => {
|
||||
block.classList.add('code-block');
|
||||
});
|
||||
initClipboard(codeBlocks);
|
||||
|
||||
// Initialize the Apply Patch functionality
|
||||
initButtonForCodeBlock(codeBlocks);
|
||||
|
||||
messageItem.appendChild(senderIcon);
|
||||
messageItem.appendChild(messageContent);
|
||||
@ -121,4 +174,16 @@ function processMessage(message) {
|
||||
function processMessageUI(message) {
|
||||
addMessageToUI('user', message);
|
||||
processMessage(message);
|
||||
}
|
||||
|
||||
// Function to request history messages from the extension
|
||||
function requestHistoryMessages() {
|
||||
// Send a message to the extension with the 'historyMessages' command
|
||||
vscode_api.postMessage({
|
||||
command: 'historyMessages',
|
||||
});
|
||||
}
|
||||
|
||||
function postVSCodeMessage(message) {
|
||||
vscode_api.postMessage(message);
|
||||
}
|
@ -1,5 +1,13 @@
|
||||
function initClipboard(codeBlocks) {
|
||||
// clipboard.js
|
||||
|
||||
|
||||
function initClipboard(codeBlocks, onApplyButtonClick, onApplyCodeButtonClick, onApplyCodeFileButtonClick) {
|
||||
codeBlocks.forEach(block => {
|
||||
const contentSpan = document.createElement('span');
|
||||
contentSpan.innerHTML = block.innerHTML;
|
||||
block.innerHTML = '';
|
||||
block.appendChild(contentSpan);
|
||||
|
||||
const copyButton = document.createElement('button');
|
||||
copyButton.classList.add('copy-button');
|
||||
copyButton.innerText = 'Copy';
|
||||
@ -7,7 +15,7 @@ function initClipboard(codeBlocks) {
|
||||
|
||||
copyButton.addEventListener('click', () => {
|
||||
// Copy the message text to the clipboard
|
||||
navigator.clipboard.writeText(block.textContent);
|
||||
navigator.clipboard.writeText(contentSpan.textContent);
|
||||
|
||||
// Change the button text temporarily to show that the text has been copied
|
||||
copyButton.textContent = 'Copied!';
|
||||
@ -20,5 +28,35 @@ function initClipboard(codeBlocks) {
|
||||
copyButton.appendChild(copyIcon);
|
||||
}, 1000);
|
||||
});
|
||||
|
||||
// Add 'Apply' button
|
||||
const applyButton = document.createElement('button');
|
||||
applyButton.classList.add('apply-button');
|
||||
applyButton.innerText = 'Apply Patch';
|
||||
block.appendChild(applyButton);
|
||||
|
||||
applyButton.addEventListener('click', () => {
|
||||
onApplyButtonClick(contentSpan.textContent);
|
||||
});
|
||||
|
||||
// Add 'Apply' button
|
||||
const applyCodeButton = document.createElement('button');
|
||||
applyCodeButton.classList.add('apply-button');
|
||||
applyCodeButton.innerText = 'Insert Code';
|
||||
block.appendChild(applyCodeButton);
|
||||
|
||||
applyCodeButton.addEventListener('click', () => {
|
||||
onApplyCodeButtonClick(contentSpan.textContent);
|
||||
});
|
||||
|
||||
// Add 'Apply' button
|
||||
const applyCodeFileButton = document.createElement('button');
|
||||
applyCodeFileButton.classList.add('apply-button');
|
||||
applyCodeFileButton.innerText = 'Relace File';
|
||||
block.appendChild(applyCodeFileButton);
|
||||
|
||||
applyCodeFileButton.addEventListener('click', () => {
|
||||
onApplyCodeFileButtonClick(contentSpan.textContent);
|
||||
});
|
||||
});
|
||||
}
|
157
media/main.js
157
media/main.js
@ -1,46 +1,123 @@
|
||||
// main.js
|
||||
|
||||
(function () {
|
||||
// Get DOM elements for user interaction and message display
|
||||
const messageInput = document.getElementById('message-input');
|
||||
const sendButton = document.getElementById('send-button');
|
||||
// Get DOM elements for user interaction and message display
|
||||
const messagesContainer = document.getElementById('messages-container');
|
||||
const messageInput = document.getElementById('message-input');
|
||||
const sendButton = document.getElementById('send-button');
|
||||
const contextMenu = document.getElementById('context-menu');
|
||||
const menuItem1 = document.getElementById('menu-item-1');
|
||||
const menuItem2 = document.getElementById('menu-item-2');
|
||||
let selectedText = '';
|
||||
|
||||
// Initialize input resizing
|
||||
initInputResizing();
|
||||
|
||||
function hideContextMenu() {
|
||||
contextMenu.style.display = 'none';
|
||||
}
|
||||
|
||||
function getSelectedText() {
|
||||
const selection = window.getSelection();
|
||||
return selection.toString();
|
||||
}
|
||||
|
||||
// Initialize input resizing
|
||||
initInputResizing();
|
||||
messagesContainer.addEventListener('contextmenu', (event) => {
|
||||
event.preventDefault();
|
||||
selectedText = getSelectedText();
|
||||
contextMenu.style.display = 'block';
|
||||
contextMenu.style.left = event.pageX + 'px';
|
||||
contextMenu.style.top = event.pageY + 'px';
|
||||
});
|
||||
|
||||
// Event listener for receiving messages from the extension
|
||||
window.addEventListener('message', (event) => {
|
||||
const message = event.data;
|
||||
switch (message.command) {
|
||||
case 'receiveMessage':
|
||||
// Add the received message to the chat UI as a bot message
|
||||
addMessageToUI('bot', message.text);
|
||||
break;
|
||||
}
|
||||
document.addEventListener('click', hideContextMenu);
|
||||
|
||||
menuItem1.addEventListener('click', () => {
|
||||
postVSCodeMessage({
|
||||
command: 'code_apply',
|
||||
content: selectedText,
|
||||
});
|
||||
hideContextMenu();
|
||||
});
|
||||
|
||||
// Event listener for the send button
|
||||
sendButton.addEventListener('click', () => {
|
||||
const message = messageInput.value;
|
||||
if (message) {
|
||||
// Add the user's message to the chat UI
|
||||
addMessageToUI('user', message);
|
||||
|
||||
// Clear the input field
|
||||
messageInput.value = '';
|
||||
|
||||
// Process and send the message to the extension
|
||||
processMessage(message);
|
||||
menuItem2.addEventListener('click', () => {
|
||||
navigator.clipboard.writeText(selectedText);
|
||||
hideContextMenu();
|
||||
});
|
||||
|
||||
// Event listener for receiving messages from the extension
|
||||
window.addEventListener('message', (event) => {
|
||||
const message = event.data;
|
||||
switch (message.command) {
|
||||
case 'receiveMessage':
|
||||
// Add the received message to the chat UI as a bot message
|
||||
addMessageToUI('bot', message.text);
|
||||
break;
|
||||
case 'receiveMessagePartial':
|
||||
// Add the received message to the chat UI as a bot message
|
||||
addMessageToUI('bot', message.text, true);
|
||||
break;
|
||||
case 'loadHistoryMessages':
|
||||
loadHistoryMessages(message.entries);
|
||||
break;
|
||||
case 'file_select':
|
||||
addFileToMessageInput(message.filePath);
|
||||
break;
|
||||
case 'code_select':
|
||||
addCodeToMessageInput(message.codeBlock);
|
||||
break
|
||||
case 'ask_ai':
|
||||
message_text = message.codeBlock + "\n" + message.question;
|
||||
processMessageUI(message_text)
|
||||
break;
|
||||
}
|
||||
});
|
||||
|
||||
// Event listener for the send button
|
||||
sendButton.addEventListener('click', () => {
|
||||
const message = messageInput.value;
|
||||
if (message) {
|
||||
// Add the user's message to the chat UI
|
||||
addMessageToUI('user', message);
|
||||
|
||||
// Clear the input field
|
||||
messageInput.value = '';
|
||||
|
||||
// Process and send the message to the extension
|
||||
processMessage(message);
|
||||
}
|
||||
});
|
||||
|
||||
// Event listener for the Enter key in the message input field
|
||||
messageInput.addEventListener('keypress', function (e) {
|
||||
if (e.key === 'Enter' && !e.shiftKey) {
|
||||
e.preventDefault();
|
||||
const message = messageInput.value.trim();
|
||||
if (message !== '') {
|
||||
sendButton.click();
|
||||
}
|
||||
});
|
||||
|
||||
// Event listener for the Enter key in the message input field
|
||||
messageInput.addEventListener('keypress', function (e) {
|
||||
if (e.key === 'Enter' && !e.shiftKey) {
|
||||
e.preventDefault();
|
||||
const message = messageInput.value.trim();
|
||||
if (message !== '') {
|
||||
sendButton.click();
|
||||
}
|
||||
}
|
||||
});
|
||||
})();
|
||||
|
||||
}
|
||||
});
|
||||
|
||||
function addFileToMessageInput(filePath) {
|
||||
const formattedPath = `[context|${filePath}] `;
|
||||
messageInput.value = formattedPath + messageInput.value;
|
||||
messageInput.focus();
|
||||
}
|
||||
|
||||
function addCodeToMessageInput(codeBlock) {
|
||||
messageInput.value += "\n" + codeBlock + "\n";
|
||||
messageInput.focus();
|
||||
}
|
||||
|
||||
// Request history messages when the web view is created and shown
|
||||
requestHistoryMessages();
|
||||
})();
|
||||
|
||||
// Function to load history messages from the extension
|
||||
function loadHistoryMessages(entries) {
|
||||
entries.forEach((entry) => {
|
||||
addMessageToUI('user', entry.message);
|
||||
addMessageToUI('bot', entry.response);
|
||||
});
|
||||
}
|
||||
|
35
package-lock.json
generated
35
package-lock.json
generated
@ -13,6 +13,8 @@
|
||||
"node-fetch": "^3.3.1",
|
||||
"nonce": "^1.0.4",
|
||||
"openai": "^3.2.1",
|
||||
"quote": "^0.4.0",
|
||||
"shell-escape": "^0.2.0",
|
||||
"uuid": "^9.0.0"
|
||||
},
|
||||
"devDependencies": {
|
||||
@ -20,6 +22,7 @@
|
||||
"@types/jest": "^29.5.1",
|
||||
"@types/mocha": "^10.0.1",
|
||||
"@types/node": "16.x",
|
||||
"@types/shell-escape": "^0.2.1",
|
||||
"@types/vscode": "^1.77.0",
|
||||
"@typescript-eslint/eslint-plugin": "^5.56.0",
|
||||
"@typescript-eslint/parser": "^5.56.0",
|
||||
@ -1477,6 +1480,12 @@
|
||||
"integrity": "sha512-21cFJr9z3g5dW8B0CVI9g2O9beqaThGQ6ZFBqHfwhzLDKUxaqTIy3vnfah/UPkfOiF2pLq+tGz+W8RyCskuslw==",
|
||||
"dev": true
|
||||
},
|
||||
"node_modules/@types/shell-escape": {
|
||||
"version": "0.2.1",
|
||||
"resolved": "https://registry.npmjs.org/@types/shell-escape/-/shell-escape-0.2.1.tgz",
|
||||
"integrity": "sha512-95hZXmBvwtvsLMPefKT9xquUSAJXsVDUaipyUiYoYi3ZdLhZ3w30w230Ugs96IdoJQb5ECvj0D82Jj/op00qWQ==",
|
||||
"dev": true
|
||||
},
|
||||
"node_modules/@types/stack-utils": {
|
||||
"version": "2.0.1",
|
||||
"resolved": "https://registry.npmjs.org/@types/stack-utils/-/stack-utils-2.0.1.tgz",
|
||||
@ -5341,6 +5350,11 @@
|
||||
}
|
||||
]
|
||||
},
|
||||
"node_modules/quote": {
|
||||
"version": "0.4.0",
|
||||
"resolved": "https://registry.npmjs.org/quote/-/quote-0.4.0.tgz",
|
||||
"integrity": "sha512-KHp3y3xDjuBhRx+tYKOgzPnVHMRlgpn2rU450GcU4PL24r1H6ls/hfPrxDwX2pvYMlwODHI2l8WwgoV69x5rUQ=="
|
||||
},
|
||||
"node_modules/randombytes": {
|
||||
"version": "2.1.0",
|
||||
"resolved": "https://registry.npmjs.org/randombytes/-/randombytes-2.1.0.tgz",
|
||||
@ -5615,6 +5629,11 @@
|
||||
"node": ">=8"
|
||||
}
|
||||
},
|
||||
"node_modules/shell-escape": {
|
||||
"version": "0.2.0",
|
||||
"resolved": "https://registry.npmjs.org/shell-escape/-/shell-escape-0.2.0.tgz",
|
||||
"integrity": "sha512-uRRBT2MfEOyxuECseCZd28jC1AJ8hmqqneWQ4VWUTgCAFvb3wKU1jLqj6egC4Exrr88ogg3dp+zroH4wJuaXzw=="
|
||||
},
|
||||
"node_modules/signal-exit": {
|
||||
"version": "3.0.7",
|
||||
"resolved": "https://registry.npmjs.org/signal-exit/-/signal-exit-3.0.7.tgz",
|
||||
@ -7570,6 +7589,12 @@
|
||||
"integrity": "sha512-21cFJr9z3g5dW8B0CVI9g2O9beqaThGQ6ZFBqHfwhzLDKUxaqTIy3vnfah/UPkfOiF2pLq+tGz+W8RyCskuslw==",
|
||||
"dev": true
|
||||
},
|
||||
"@types/shell-escape": {
|
||||
"version": "0.2.1",
|
||||
"resolved": "https://registry.npmjs.org/@types/shell-escape/-/shell-escape-0.2.1.tgz",
|
||||
"integrity": "sha512-95hZXmBvwtvsLMPefKT9xquUSAJXsVDUaipyUiYoYi3ZdLhZ3w30w230Ugs96IdoJQb5ECvj0D82Jj/op00qWQ==",
|
||||
"dev": true
|
||||
},
|
||||
"@types/stack-utils": {
|
||||
"version": "2.0.1",
|
||||
"resolved": "https://registry.npmjs.org/@types/stack-utils/-/stack-utils-2.0.1.tgz",
|
||||
@ -10423,6 +10448,11 @@
|
||||
"integrity": "sha512-NuaNSa6flKT5JaSYQzJok04JzTL1CA6aGhv5rfLW3PgqA+M2ChpZQnAC8h8i4ZFkBS8X5RqkDBHA7r4hej3K9A==",
|
||||
"dev": true
|
||||
},
|
||||
"quote": {
|
||||
"version": "0.4.0",
|
||||
"resolved": "https://registry.npmjs.org/quote/-/quote-0.4.0.tgz",
|
||||
"integrity": "sha512-KHp3y3xDjuBhRx+tYKOgzPnVHMRlgpn2rU450GcU4PL24r1H6ls/hfPrxDwX2pvYMlwODHI2l8WwgoV69x5rUQ=="
|
||||
},
|
||||
"randombytes": {
|
||||
"version": "2.1.0",
|
||||
"resolved": "https://registry.npmjs.org/randombytes/-/randombytes-2.1.0.tgz",
|
||||
@ -10622,6 +10652,11 @@
|
||||
"integrity": "sha512-7++dFhtcx3353uBaq8DDR4NuxBetBzC7ZQOhmTQInHEd6bSrXdiEyzCvG07Z44UYdLShWUyXt5M/yhz8ekcb1A==",
|
||||
"dev": true
|
||||
},
|
||||
"shell-escape": {
|
||||
"version": "0.2.0",
|
||||
"resolved": "https://registry.npmjs.org/shell-escape/-/shell-escape-0.2.0.tgz",
|
||||
"integrity": "sha512-uRRBT2MfEOyxuECseCZd28jC1AJ8hmqqneWQ4VWUTgCAFvb3wKU1jLqj6egC4Exrr88ogg3dp+zroH4wJuaXzw=="
|
||||
},
|
||||
"signal-exit": {
|
||||
"version": "3.0.7",
|
||||
"resolved": "https://registry.npmjs.org/signal-exit/-/signal-exit-3.0.7.tgz",
|
||||
|
42
package.json
42
package.json
@ -23,9 +23,44 @@
|
||||
"commands": [
|
||||
{
|
||||
"command": "devchat.openChatPanel",
|
||||
"title": "Open Chat Panel"
|
||||
"title": "DevChat"
|
||||
},
|
||||
{
|
||||
"command": "devchat.addConext",
|
||||
"title": "add to DevChat"
|
||||
},
|
||||
{
|
||||
"command": "devchat.askForCode",
|
||||
"title": "add to DevChat"
|
||||
},
|
||||
{
|
||||
"command": "devchat.askForFile",
|
||||
"title": "add to DevChat"
|
||||
}
|
||||
]
|
||||
],
|
||||
"menus": {
|
||||
"explorer/context": [
|
||||
{
|
||||
"when": "resourceLangId != 'git'",
|
||||
"command": "devchat.addConext",
|
||||
"group": "navigation"
|
||||
}
|
||||
],
|
||||
"editor/context": [
|
||||
{
|
||||
"command": "devchat.askForCode",
|
||||
"when": "editorTextFocus && editorHasSelection",
|
||||
"group": "navigation",
|
||||
"title": "add to DevChat"
|
||||
},
|
||||
{
|
||||
"command": "devchat.askForFile",
|
||||
"when": "editorTextFocus && !editorHasSelection",
|
||||
"group": "navigation",
|
||||
"title": "add to DevChat"
|
||||
}
|
||||
]
|
||||
}
|
||||
},
|
||||
"scripts": {
|
||||
"vscode:prepublish": "npm run package",
|
||||
@ -43,6 +78,7 @@
|
||||
"@types/jest": "^29.5.1",
|
||||
"@types/mocha": "^10.0.1",
|
||||
"@types/node": "16.x",
|
||||
"@types/shell-escape": "^0.2.1",
|
||||
"@types/vscode": "^1.77.0",
|
||||
"@typescript-eslint/eslint-plugin": "^5.56.0",
|
||||
"@typescript-eslint/parser": "^5.56.0",
|
||||
@ -63,6 +99,8 @@
|
||||
"node-fetch": "^3.3.1",
|
||||
"nonce": "^1.0.4",
|
||||
"openai": "^3.2.1",
|
||||
"quote": "^0.4.0",
|
||||
"shell-escape": "^0.2.0",
|
||||
"uuid": "^9.0.0"
|
||||
}
|
||||
}
|
||||
|
@ -1,38 +0,0 @@
|
||||
import DevChat from "../devchat";
|
||||
|
||||
describe("DevChat", () => {
|
||||
const devChat = new DevChat();
|
||||
|
||||
test("some test", () => {
|
||||
const xx = 20;
|
||||
expect(xx)
|
||||
})
|
||||
|
||||
test("chat should return a valid response", async () => {
|
||||
const chatResponse = await devChat.chat("Help me with TypeScript");
|
||||
|
||||
expect(chatResponse).toHaveProperty("prompt-hash");
|
||||
expect(chatResponse).toHaveProperty("user");
|
||||
expect(chatResponse).toHaveProperty("date");
|
||||
expect(chatResponse).toHaveProperty("response");
|
||||
expect(chatResponse).toHaveProperty("isError");
|
||||
|
||||
expect(chatResponse.isError).toBe(false);
|
||||
expect(chatResponse.response.length).toBeGreaterThan(0);
|
||||
});
|
||||
|
||||
test("log should return an array of log entries", async () => {
|
||||
const logEntries = await devChat.log({ maxCount: 5 });
|
||||
|
||||
expect(Array.isArray(logEntries)).toBe(true);
|
||||
expect(logEntries.length).toBeLessThanOrEqual(5);
|
||||
|
||||
logEntries.forEach((entry) => {
|
||||
expect(entry).toHaveProperty("prompt-hash");
|
||||
expect(entry).toHaveProperty("user");
|
||||
expect(entry).toHaveProperty("date");
|
||||
expect(entry).toHaveProperty("message");
|
||||
expect(entry).toHaveProperty("response");
|
||||
});
|
||||
});
|
||||
});
|
46
src/applyCode.ts
Normal file
46
src/applyCode.ts
Normal file
@ -0,0 +1,46 @@
|
||||
const vscode = require('vscode');
|
||||
|
||||
|
||||
export async function applyCodeFile(text: string) {
|
||||
if (vscode.window.visibleTextEditors.length > 1) {
|
||||
vscode.window.showErrorMessage(`There are more then one visible text editors. Please close all but one and try again.`);
|
||||
return;
|
||||
}
|
||||
|
||||
const editor = vscode.window.visibleTextEditors[0];
|
||||
if (!editor) {
|
||||
return;
|
||||
}
|
||||
|
||||
const document = editor.document;
|
||||
const fullRange = new vscode.Range(
|
||||
document.positionAt(0),
|
||||
document.positionAt(document.getText().length)
|
||||
);
|
||||
|
||||
await editor.edit((editBuilder: string) => {
|
||||
editBuilder.replace(fullRange, text);
|
||||
});
|
||||
}
|
||||
|
||||
async function applyCode(text: string) {
|
||||
if (vscode.window.visibleTextEditors.length > 1) {
|
||||
vscode.window.showErrorMessage(`There are more then one visible text editors. Please close all but one and try again.`);
|
||||
return;
|
||||
}
|
||||
|
||||
const editor = vscode.window.visibleTextEditors[0];
|
||||
if (!editor) {
|
||||
return;
|
||||
}
|
||||
|
||||
const selection = editor.selection;
|
||||
const start = selection.start;
|
||||
const end = selection.end;
|
||||
|
||||
await editor.edit((editBuilder: string) => {
|
||||
editBuilder.replace(new vscode.Range(start, end), text);
|
||||
});
|
||||
}
|
||||
|
||||
export default applyCode;
|
@ -9,7 +9,6 @@ import handleMessage from './messageHandler';
|
||||
export default class ChatPanel {
|
||||
private static _instance: ChatPanel | undefined;
|
||||
private readonly _panel: vscode.WebviewPanel;
|
||||
private _messageHistory: Array<{ role: string; content: string }>;
|
||||
private _disposables: vscode.Disposable[] = [];
|
||||
|
||||
// Create or reveal the chat panel
|
||||
@ -22,6 +21,10 @@ export default class ChatPanel {
|
||||
}
|
||||
}
|
||||
|
||||
public static currentPanel(): ChatPanel | undefined {
|
||||
return ChatPanel._instance;
|
||||
}
|
||||
|
||||
// Create a new webview panel
|
||||
private static createWebviewPanel(extensionUri: vscode.Uri): vscode.WebviewPanel {
|
||||
const column = vscode.window.activeTextEditor
|
||||
@ -35,13 +38,13 @@ export default class ChatPanel {
|
||||
{
|
||||
enableScripts: true,
|
||||
localResourceRoots: [vscode.Uri.joinPath(extensionUri, 'media')],
|
||||
retainContextWhenHidden: true
|
||||
}
|
||||
);
|
||||
}
|
||||
|
||||
private constructor(panel: vscode.WebviewPanel, extensionUri: vscode.Uri) {
|
||||
this._panel = panel;
|
||||
this._messageHistory = [];
|
||||
|
||||
this.setWebviewOptions(extensionUri);
|
||||
this.setWebviewContent(extensionUri);
|
||||
@ -61,6 +64,10 @@ export default class ChatPanel {
|
||||
this._panel.webview.html = this._getHtmlContent(extensionUri);
|
||||
}
|
||||
|
||||
public panel() : vscode.WebviewPanel {
|
||||
return this._panel;
|
||||
}
|
||||
|
||||
// Register event listeners for the panel and webview
|
||||
private registerEventListeners() {
|
||||
this._panel.onDidDispose(() => this.dispose(), null, this._disposables);
|
||||
|
168
src/devchat.ts
168
src/devchat.ts
@ -1,21 +1,53 @@
|
||||
import { exec } from "child_process";
|
||||
// devchat.ts
|
||||
|
||||
import { spawn } from "child_process";
|
||||
import { promisify } from "util";
|
||||
import * as vscode from 'vscode';
|
||||
import * as dotenv from 'dotenv';
|
||||
import * as path from 'path';
|
||||
|
||||
const execAsync = promisify(exec);
|
||||
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);
|
||||
let stdout = '';
|
||||
let stderr = '';
|
||||
|
||||
interface ChatOptions {
|
||||
child.stdout.on('data', (data) => {
|
||||
const dataStr = data.toString();
|
||||
onData(dataStr);
|
||||
stdout += dataStr;
|
||||
});
|
||||
|
||||
child.stderr.on('data', (data) => {
|
||||
stderr += data;
|
||||
});
|
||||
|
||||
child.on('close', (code) => {
|
||||
if (code === 0) {
|
||||
resolve({code, stdout, stderr });
|
||||
} else {
|
||||
reject({code, stdout, stderr });
|
||||
}
|
||||
});
|
||||
});
|
||||
};
|
||||
|
||||
const envPath = path.join(__dirname, '..', '.env');
|
||||
dotenv.config({ path: envPath });
|
||||
|
||||
export interface ChatOptions {
|
||||
parent?: string;
|
||||
reference?: string[];
|
||||
header?: string[];
|
||||
context?: string[];
|
||||
}
|
||||
|
||||
interface LogOptions {
|
||||
export interface LogOptions {
|
||||
skip?: number;
|
||||
maxCount?: number;
|
||||
}
|
||||
|
||||
interface LogEntry {
|
||||
export interface LogEntry {
|
||||
"prompt-hash": string;
|
||||
user: string;
|
||||
date: string;
|
||||
@ -23,7 +55,7 @@ interface LogEntry {
|
||||
response: string;
|
||||
}
|
||||
|
||||
interface ChatResponse {
|
||||
export interface ChatResponse {
|
||||
"prompt-hash": string;
|
||||
user: string;
|
||||
date: string;
|
||||
@ -32,25 +64,47 @@ interface ChatResponse {
|
||||
}
|
||||
|
||||
class DevChat {
|
||||
async chat(content: string, options: ChatOptions = {}): Promise<ChatResponse> {
|
||||
let args = "";
|
||||
|
||||
if (options.parent) {
|
||||
args += ` -p ${options.parent}`;
|
||||
}
|
||||
if (options.reference) {
|
||||
args += ` -r ${options.reference.join(",")}`;
|
||||
}
|
||||
if (options.header) {
|
||||
args += ` -h ${options.header.join(",")}`;
|
||||
}
|
||||
if (options.context) {
|
||||
args += ` -c ${options.context.join(",")}`;
|
||||
}
|
||||
|
||||
const { stdout } = await execAsync(`devchat ${args} "${content}"`, {
|
||||
async chat(content: string, options: ChatOptions = {}, onData: (data: string) => void): Promise<ChatResponse> {
|
||||
let args = ["prompt"];
|
||||
|
||||
if (options.parent) {
|
||||
args.push("-p", options.parent);
|
||||
}
|
||||
if (options.reference) {
|
||||
args.push("-r", options.reference.join(","));
|
||||
}
|
||||
if (options.header) {
|
||||
args.push("--header", options.header.join(","));
|
||||
}
|
||||
if (options.context) {
|
||||
args.push("--context", options.context.join(","));
|
||||
}
|
||||
args.push(content)
|
||||
|
||||
const workspaceDir = vscode.workspace.workspaceFolders?.[0].uri.fsPath;
|
||||
const openaiApiKey = process.env.OPENAI_API_KEY;
|
||||
|
||||
try {
|
||||
const {code, stdout, stderr } = await spawnAsync('devchat', args, {
|
||||
maxBuffer: 10 * 1024 * 1024, // Set maxBuffer to 10 MB
|
||||
});
|
||||
cwd: workspaceDir,
|
||||
env: {
|
||||
...process.env,
|
||||
OPENAI_API_KEY: openaiApiKey,
|
||||
},
|
||||
}, onData);
|
||||
|
||||
if (stderr) {
|
||||
const errorMessage = stderr.trim().match(/Error:(.+)/)?.[1];
|
||||
return {
|
||||
"prompt-hash": "",
|
||||
user: "",
|
||||
date: "",
|
||||
response: errorMessage ? `Error: ${errorMessage}` : "Unknown error",
|
||||
isError: true,
|
||||
};
|
||||
}
|
||||
|
||||
const responseLines = stdout.trim().split("\n");
|
||||
console.log(responseLines)
|
||||
|
||||
@ -63,8 +117,17 @@ class DevChat {
|
||||
isError: true,
|
||||
};
|
||||
}
|
||||
|
||||
if (responseLines[0].startsWith("error")) {
|
||||
|
||||
let promptHashLine = "";
|
||||
for (let i = responseLines.length - 1; i >= 0; i--) {
|
||||
if (responseLines[i].startsWith("prompt")) {
|
||||
promptHashLine = responseLines[i];
|
||||
responseLines.splice(i, 1);
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
if (!promptHashLine) {
|
||||
return {
|
||||
"prompt-hash": "",
|
||||
user: "",
|
||||
@ -73,18 +136,17 @@ class DevChat {
|
||||
isError: true,
|
||||
};
|
||||
}
|
||||
|
||||
const promptHashLine = responseLines.shift()!;
|
||||
|
||||
const promptHash = promptHashLine.split(" ")[1];
|
||||
|
||||
|
||||
const userLine = responseLines.shift()!;
|
||||
const user = (userLine.match(/User: (.+)/)?.[1]) ?? "";
|
||||
|
||||
|
||||
const dateLine = responseLines.shift()!;
|
||||
const date = (dateLine.match(/Date: (.+)/)?.[1]) ?? "";
|
||||
|
||||
|
||||
const response = responseLines.join("\n");
|
||||
|
||||
|
||||
return {
|
||||
"prompt-hash": promptHash,
|
||||
user,
|
||||
@ -92,22 +154,50 @@ class DevChat {
|
||||
response,
|
||||
isError: false,
|
||||
};
|
||||
} catch (error: any) {
|
||||
return {
|
||||
"prompt-hash": "",
|
||||
user: "",
|
||||
date: "",
|
||||
response: `Error: ${error.stderr}\nExit code: ${error.code}`,
|
||||
isError: true,
|
||||
};
|
||||
}
|
||||
}
|
||||
|
||||
async log(options: LogOptions = {}): Promise<LogEntry[]> {
|
||||
let args = "log";
|
||||
let args = ["log"];
|
||||
|
||||
if (options.skip) {
|
||||
args += ` --skip ${options.skip}`;
|
||||
args.push('--skip', `${options.skip}`);
|
||||
}
|
||||
if (options.maxCount) {
|
||||
args += ` --max-count ${options.maxCount}`;
|
||||
args.push('--max-count', `${options.maxCount}`);
|
||||
}
|
||||
|
||||
const { stdout } = await execAsync(`devchat ${args}`, {
|
||||
maxBuffer: 10 * 1024 * 1024, // Set maxBuffer to 10 MB
|
||||
});
|
||||
return JSON.parse(stdout.trim());
|
||||
const workspaceDir = vscode.workspace.workspaceFolders?.[0].uri.fsPath;
|
||||
const openaiApiKey = process.env.OPENAI_API_KEY;
|
||||
|
||||
try {
|
||||
const {code, stdout, stderr } = await spawnAsync('devchat', args, {
|
||||
maxBuffer: 10 * 1024 * 1024, // Set maxBuffer to 10 MB
|
||||
cwd: workspaceDir,
|
||||
env: {
|
||||
...process.env,
|
||||
OPENAI_API_KEY: openaiApiKey,
|
||||
},
|
||||
}, (partialResponse: string) => {});
|
||||
|
||||
if (stderr) {
|
||||
console.error(stderr);
|
||||
return [];
|
||||
}
|
||||
|
||||
return JSON.parse(stdout.trim());
|
||||
} catch (error) {
|
||||
console.error(error)
|
||||
return [];
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
41
src/dtm.ts
Normal file
41
src/dtm.ts
Normal file
@ -0,0 +1,41 @@
|
||||
// dtm.ts
|
||||
|
||||
import { exec } from "child_process";
|
||||
import { promisify } from "util";
|
||||
import * as vscode from 'vscode';
|
||||
|
||||
const execAsync = promisify(exec);
|
||||
|
||||
interface DtmResponse {
|
||||
status: number;
|
||||
message: string;
|
||||
log: string;
|
||||
}
|
||||
|
||||
class DtmWrapper {
|
||||
private workspaceDir: string;
|
||||
|
||||
constructor() {
|
||||
this.workspaceDir = vscode.workspace.workspaceFolders?.[0].uri.fsPath || '.';
|
||||
}
|
||||
|
||||
async scaffold(directoryTree: string): Promise<DtmResponse> {
|
||||
const { stdout } = await execAsync(`dtm scaffold "${directoryTree}" -o json`, {
|
||||
cwd: this.workspaceDir,
|
||||
});
|
||||
return JSON.parse(stdout.trim());
|
||||
}
|
||||
|
||||
async patch(patchFilePath: string): Promise<DtmResponse> {
|
||||
try {
|
||||
const { stdout } = await execAsync(`dtm patch ${patchFilePath} -o json`, {
|
||||
cwd: this.workspaceDir,
|
||||
});
|
||||
return JSON.parse(stdout.trim());
|
||||
} catch (e) {
|
||||
return JSON.parse((e as Error & { stdout: string }).stdout.trim());
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
export default DtmWrapper;
|
@ -1,5 +1,9 @@
|
||||
const vscode = require('vscode');
|
||||
const ChatPanel = require('./chatPanel').default;
|
||||
const sendFileSelectMessage = require('./messageHandler').sendFileSelectMessage;
|
||||
const sendCodeSelectMessage = require('./messageHandler').sendCodeSelectMessage;
|
||||
const askAI = require('./messageHandler').askAI;
|
||||
|
||||
|
||||
function activate(context: { extensionUri: any; subscriptions: any[]; }) {
|
||||
let disposable = vscode.commands.registerCommand('devchat.openChatPanel', () => {
|
||||
@ -10,6 +14,56 @@ function activate(context: { extensionUri: any; subscriptions: any[]; }) {
|
||||
}
|
||||
});
|
||||
|
||||
const disposable_add_context = vscode.commands.registerCommand('devchat.addConext', (uri: { path: any; }) => {
|
||||
if (!ChatPanel.currentPanel()) {
|
||||
if (vscode.workspace.workspaceFolders) {
|
||||
ChatPanel.createOrShow(context.extensionUri);
|
||||
} else {
|
||||
vscode.window.showErrorMessage('Please open a directory before using the chat panel.');
|
||||
return
|
||||
}
|
||||
}
|
||||
|
||||
sendFileSelectMessage(ChatPanel.currentPanel().panel(), uri.path);
|
||||
});
|
||||
|
||||
const disposableCodeContext = vscode.commands.registerCommand('devchat.askForCode', async () => {
|
||||
const editor = vscode.window.activeTextEditor;
|
||||
if (editor) {
|
||||
if (!ChatPanel.currentPanel()) {
|
||||
if (vscode.workspace.workspaceFolders) {
|
||||
ChatPanel.createOrShow(context.extensionUri);
|
||||
} else {
|
||||
vscode.window.showErrorMessage('Please open a directory before using the chat panel.');
|
||||
return
|
||||
}
|
||||
}
|
||||
|
||||
const selectedText = editor.document.getText(editor.selection);
|
||||
sendCodeSelectMessage(ChatPanel.currentPanel().panel(), selectedText);
|
||||
}
|
||||
});
|
||||
|
||||
const disposableAskFile = vscode.commands.registerCommand('devchat.askForFile', async () => {
|
||||
const editor = vscode.window.activeTextEditor;
|
||||
if (editor) {
|
||||
if (!ChatPanel.currentPanel()) {
|
||||
if (vscode.workspace.workspaceFolders) {
|
||||
ChatPanel.createOrShow(context.extensionUri);
|
||||
} else {
|
||||
vscode.window.showErrorMessage('Please open a directory before using the chat panel.');
|
||||
return
|
||||
}
|
||||
}
|
||||
|
||||
const selectedText = editor.document.getText();
|
||||
sendCodeSelectMessage(ChatPanel.currentPanel().panel(), selectedText);
|
||||
}
|
||||
});
|
||||
|
||||
context.subscriptions.push(disposable);
|
||||
context.subscriptions.push(disposable_add_context);
|
||||
context.subscriptions.push(disposableCodeContext)
|
||||
context.subscriptions.push(disposableAskFile)
|
||||
}
|
||||
exports.activate = activate;
|
||||
|
@ -1,19 +1,108 @@
|
||||
// messageHandler.ts
|
||||
|
||||
import * as vscode from 'vscode';
|
||||
import DevChat from './devchat';
|
||||
import * as fs from 'fs';
|
||||
import * as path from 'path';
|
||||
import { promisify } from 'util';
|
||||
import DevChat, { LogOptions } from './devchat';
|
||||
import DtmWrapper from './dtm';
|
||||
import applyCode, {applyCodeFile} from './applyCode';
|
||||
import * as vscode3 from 'vscode';
|
||||
|
||||
const writeFileAsync = promisify(fs.writeFile);
|
||||
const unlinkAsync = promisify(fs.unlink);
|
||||
|
||||
let lastPromptHash: string | undefined;
|
||||
|
||||
async function saveTempPatchFile(content: string): Promise<string> {
|
||||
const tempPatchFilePath = path.join(vscode.workspace.workspaceFolders![0].uri.fsPath, '.temp_patch_file.patch');
|
||||
await writeFileAsync(tempPatchFilePath, content);
|
||||
return tempPatchFilePath;
|
||||
}
|
||||
|
||||
async function deleteTempPatchFile(filePath: string): Promise<void> {
|
||||
await unlinkAsync(filePath);
|
||||
}
|
||||
|
||||
export function sendFileSelectMessage(panel: vscode.WebviewPanel, filePath: string): void {
|
||||
panel.webview.postMessage({ command: 'file_select', filePath });
|
||||
}
|
||||
|
||||
export function sendCodeSelectMessage(panel: vscode.WebviewPanel, codeBlock: string): void {
|
||||
panel.webview.postMessage({ command: 'code_select', codeBlock });
|
||||
}
|
||||
|
||||
export function askAI(panel: vscode.WebviewPanel, codeBlock: string, question: string): void {
|
||||
panel.webview.postMessage({ command: 'ask_ai', codeBlock, question });
|
||||
}
|
||||
|
||||
// Add this function to messageHandler.ts
|
||||
function parseMessageForContext(message: string): { context: string[]; text: string } {
|
||||
const contextRegex = /\[context\|(.*?)\]/g;
|
||||
const contextPaths = [];
|
||||
let match;
|
||||
|
||||
while ((match = contextRegex.exec(message)) !== null) {
|
||||
contextPaths.push(match[1]);
|
||||
}
|
||||
|
||||
const text = message.replace(contextRegex, '').trim();
|
||||
return { context: contextPaths, text };
|
||||
}
|
||||
|
||||
async function handleMessage(
|
||||
message: any,
|
||||
panel: vscode.WebviewPanel
|
||||
): Promise<void> {
|
||||
const devChat = new DevChat();
|
||||
const dtmWrapper = new DtmWrapper();
|
||||
|
||||
switch (message.command) {
|
||||
case 'sendMessage':
|
||||
const devChat = new DevChat();
|
||||
const chatResponse = await devChat.chat(message.text);
|
||||
const parsedMessage = parseMessageForContext(message.text);
|
||||
const chatOptions: any = lastPromptHash ? { parent: lastPromptHash } : {};
|
||||
|
||||
if (parsedMessage.context.length > 0) {
|
||||
chatOptions.context = parsedMessage.context;
|
||||
}
|
||||
|
||||
let partialData = "";
|
||||
const onData = (partialResponse: string) => {
|
||||
partialData += partialResponse;
|
||||
panel.webview.postMessage({ command: 'receiveMessagePartial', text: partialData });
|
||||
};
|
||||
|
||||
const chatResponse = await devChat.chat(parsedMessage.text, chatOptions, onData);
|
||||
lastPromptHash = chatResponse["prompt-hash"];
|
||||
const response = chatResponse.response;
|
||||
panel.webview.postMessage({ command: 'receiveMessage', text: response });
|
||||
return;
|
||||
case 'historyMessages':
|
||||
const logOptions: LogOptions = message.options || {};
|
||||
const logEntries = await devChat.log(logOptions);
|
||||
panel.webview.postMessage({ command: 'loadHistoryMessages', entries: logEntries });
|
||||
return;
|
||||
case 'block_apply':
|
||||
const tempPatchFile = await saveTempPatchFile(message.content);
|
||||
try {
|
||||
const patchResult = await dtmWrapper.patch(tempPatchFile);
|
||||
await deleteTempPatchFile(tempPatchFile);
|
||||
if (patchResult.status === 0) {
|
||||
vscode.window.showInformationMessage('Patch applied successfully.');
|
||||
} else {
|
||||
vscode.window.showErrorMessage(`Error applying patch: ${patchResult.message} ${patchResult.log}`);
|
||||
}
|
||||
} catch (error) {
|
||||
await deleteTempPatchFile(tempPatchFile);
|
||||
vscode.window.showErrorMessage(`Error applying patch: ${error}`);
|
||||
}
|
||||
return;
|
||||
case 'code_apply':
|
||||
await applyCode(message.content);
|
||||
return;
|
||||
case 'code_file_apply':
|
||||
await applyCodeFile(message.content);
|
||||
return;
|
||||
}
|
||||
}
|
||||
|
||||
|
Loading…
x
Reference in New Issue
Block a user