Merge pull request #4 from covespace/replace_gpt_with_devchat
Replace gpt with devchat
This commit is contained in:
commit
523b0fb35c
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*
|
||||
|
5
jest.config.js
Normal file
5
jest.config.js
Normal file
@ -0,0 +1,5 @@
|
||||
module.exports = {
|
||||
preset: "ts-jest",
|
||||
testEnvironment: "node",
|
||||
testMatch: ["<rootDir>/src/__test__/**/*.test.ts"],
|
||||
};
|
@ -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,71 @@
|
||||
// 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
|
||||
let renderedContent = md.render(content);
|
||||
if (role == "user") {
|
||||
renderedContent = md.render("\`\`\`\n" + 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,18 +77,16 @@ 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
|
||||
if (role != "user") {
|
||||
initButtonForCodeBlock(codeBlocks);
|
||||
}
|
||||
|
||||
messageItem.appendChild(senderIcon);
|
||||
messageItem.appendChild(messageContent);
|
||||
|
||||
@ -121,4 +179,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);
|
||||
});
|
||||
}
|
||||
|
4961
package-lock.json
generated
4961
package-lock.json
generated
File diff suppressed because it is too large
Load Diff
45
package.json
45
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",
|
||||
@ -40,15 +75,19 @@
|
||||
},
|
||||
"devDependencies": {
|
||||
"@types/glob": "^8.1.0",
|
||||
"@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",
|
||||
"@vscode/test-electron": "^2.3.0",
|
||||
"eslint": "^8.36.0",
|
||||
"glob": "^8.1.0",
|
||||
"jest": "^29.5.0",
|
||||
"mocha": "^10.2.0",
|
||||
"ts-jest": "^29.1.0",
|
||||
"ts-loader": "^9.4.2",
|
||||
"typescript": "^4.9.5",
|
||||
"webpack": "^5.76.3",
|
||||
@ -60,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"
|
||||
}
|
||||
}
|
||||
|
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;
|
102
src/chatPanel.ts
102
src/chatPanel.ts
@ -1,106 +1,100 @@
|
||||
// chatPanel.ts
|
||||
|
||||
import * as vscode from 'vscode';
|
||||
import * as path from 'path';
|
||||
import * as fs from 'fs';
|
||||
import { v4 as uuidv4 } from 'uuid';
|
||||
import { chatWithGPT } from './openaiClient';
|
||||
import DevChat from './devchat';
|
||||
import handleMessage from './messageHandler';
|
||||
|
||||
export default class ChatPanel {
|
||||
public static currentPanel: ChatPanel | undefined;
|
||||
private static _instance: ChatPanel | undefined;
|
||||
private readonly _panel: vscode.WebviewPanel;
|
||||
private _session_id: string;
|
||||
private _sessionName: string;
|
||||
private _messageHistory: Array<{ role: string; content: string }>;
|
||||
private _disposables: vscode.Disposable[] = [];
|
||||
private static _sessions: { [sessionName: string]: ChatPanel } = {};
|
||||
|
||||
|
||||
public static createOrShow(extensionUri: vscode.Uri, sessionName: string) {
|
||||
const session = ChatPanel._sessions[sessionName];
|
||||
|
||||
if (session) {
|
||||
// If a session with the given name exists, reveal the existing panel
|
||||
session._panel.reveal();
|
||||
return
|
||||
// Create or reveal the chat panel
|
||||
public static createOrShow(extensionUri: vscode.Uri) {
|
||||
if (ChatPanel._instance) {
|
||||
ChatPanel._instance._panel.reveal();
|
||||
} else {
|
||||
const panel = ChatPanel.createWebviewPanel(extensionUri);
|
||||
ChatPanel._instance = new ChatPanel(panel, extensionUri);
|
||||
}
|
||||
}
|
||||
|
||||
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
|
||||
? vscode.window.activeTextEditor.viewColumn
|
||||
: undefined;
|
||||
|
||||
// Create a new webview panel
|
||||
const panel = vscode.window.createWebviewPanel(
|
||||
return vscode.window.createWebviewPanel(
|
||||
'chatPanel',
|
||||
sessionName,
|
||||
'Chat',
|
||||
column || vscode.ViewColumn.One,
|
||||
{
|
||||
enableScripts: true,
|
||||
localResourceRoots: [vscode.Uri.joinPath(extensionUri, 'media')]
|
||||
localResourceRoots: [vscode.Uri.joinPath(extensionUri, 'media')],
|
||||
retainContextWhenHidden: true
|
||||
}
|
||||
);
|
||||
|
||||
// Set the webview's initial HTML content
|
||||
const chatPanel = new ChatPanel(panel, extensionUri, uuidv4(), sessionName);
|
||||
ChatPanel._sessions[sessionName] = chatPanel;
|
||||
}
|
||||
|
||||
public static sessions() {
|
||||
return ChatPanel._sessions;
|
||||
}
|
||||
|
||||
private constructor(panel: vscode.WebviewPanel, extensionUri: vscode.Uri, session_id: string, sessionName: string) {
|
||||
// ... initialize the chat panel ...
|
||||
private constructor(panel: vscode.WebviewPanel, extensionUri: vscode.Uri) {
|
||||
this._panel = panel;
|
||||
this._sessionName = sessionName;
|
||||
this._session_id = session_id;
|
||||
this._messageHistory = [];
|
||||
|
||||
// Set the webview options
|
||||
this.setWebviewOptions(extensionUri);
|
||||
this.setWebviewContent(extensionUri);
|
||||
this.registerEventListeners();
|
||||
}
|
||||
|
||||
// Set webview options
|
||||
private setWebviewOptions(extensionUri: vscode.Uri) {
|
||||
this._panel.webview.options = {
|
||||
enableScripts: true,
|
||||
localResourceRoots: [vscode.Uri.joinPath(extensionUri, 'media')]
|
||||
localResourceRoots: [vscode.Uri.joinPath(extensionUri, 'media')],
|
||||
};
|
||||
}
|
||||
|
||||
// Set the webview content
|
||||
// Set webview content
|
||||
private setWebviewContent(extensionUri: vscode.Uri) {
|
||||
this._panel.webview.html = this._getHtmlContent(extensionUri);
|
||||
}
|
||||
|
||||
// Handle webview events and dispose of the panel when closed
|
||||
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);
|
||||
|
||||
this._panel.webview.onDidReceiveMessage(
|
||||
async (message) => {
|
||||
switch (message.command) {
|
||||
case 'sendMessage':
|
||||
const [status, response] = await chatWithGPT(message.text, this._session_id, this._messageHistory);
|
||||
if (status == 0) {
|
||||
this._messageHistory.push({ role: 'user', content: message.text });
|
||||
this._messageHistory.push({ role: 'assistant', content: response });
|
||||
}
|
||||
this._panel.webview.postMessage({ command: 'receiveMessage', text: response });
|
||||
return;
|
||||
}
|
||||
handleMessage(message, this._panel);
|
||||
},
|
||||
null,
|
||||
this._disposables
|
||||
);
|
||||
}
|
||||
|
||||
// Get the HTML content for the panel
|
||||
private _getHtmlContent(extensionUri: vscode.Uri): string {
|
||||
const htmlPath = vscode.Uri.joinPath(extensionUri, 'media', 'chatPanel.html');
|
||||
const htmlContent = fs.readFileSync(htmlPath.fsPath, 'utf8');
|
||||
|
||||
// Replace the resource placeholder with the correct resource URI
|
||||
return htmlContent.replace(/<vscode-resource:(\/.+?)>/g, (_, resourcePath) => {
|
||||
const resourceUri = vscode.Uri.joinPath(extensionUri, 'media', resourcePath);
|
||||
return this._panel.webview.asWebviewUri(resourceUri).toString();
|
||||
});
|
||||
}
|
||||
|
||||
// Dispose the panel and clean up resources
|
||||
public dispose() {
|
||||
// ... dispose the panel and clean up resources ...
|
||||
// Remove the ChatPanel instance from the _sessions object
|
||||
delete ChatPanel._sessions[this._sessionName];
|
||||
|
||||
// Dispose of the WebviewPanel and other resources
|
||||
ChatPanel._instance = undefined;
|
||||
this._panel.dispose();
|
||||
while (this._disposables.length) {
|
||||
const disposable = this._disposables.pop();
|
||||
@ -109,6 +103,4 @@ export default class ChatPanel {
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// ... other helper methods ...
|
||||
}
|
||||
}
|
||||
|
204
src/devchat.ts
Normal file
204
src/devchat.ts
Normal file
@ -0,0 +1,204 @@
|
||||
// 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 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 = '';
|
||||
|
||||
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[];
|
||||
}
|
||||
|
||||
export interface LogOptions {
|
||||
skip?: number;
|
||||
maxCount?: number;
|
||||
}
|
||||
|
||||
export interface LogEntry {
|
||||
"prompt-hash": string;
|
||||
user: string;
|
||||
date: string;
|
||||
message: string;
|
||||
response: string;
|
||||
}
|
||||
|
||||
export interface ChatResponse {
|
||||
"prompt-hash": string;
|
||||
user: string;
|
||||
date: string;
|
||||
response: string;
|
||||
isError: boolean;
|
||||
}
|
||||
|
||||
class DevChat {
|
||||
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)
|
||||
|
||||
if (responseLines.length === 0) {
|
||||
return {
|
||||
"prompt-hash": "",
|
||||
user: "",
|
||||
date: "",
|
||||
response: "",
|
||||
isError: true,
|
||||
};
|
||||
}
|
||||
|
||||
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: "",
|
||||
date: "",
|
||||
response: responseLines.join("\n"),
|
||||
isError: true,
|
||||
};
|
||||
}
|
||||
|
||||
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,
|
||||
date,
|
||||
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"];
|
||||
|
||||
if (options.skip) {
|
||||
args.push('--skip', `${options.skip}`);
|
||||
}
|
||||
if (options.maxCount) {
|
||||
args.push('--max-count', `${options.maxCount}`);
|
||||
}
|
||||
|
||||
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 [];
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
export default DevChat;
|
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,39 +1,69 @@
|
||||
// The module 'vscode' contains the VS Code extensibility API
|
||||
// Import the module and reference it with the alias vscode in your code below
|
||||
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', async () => {
|
||||
const sessionNames = Object.keys(ChatPanel.sessions());
|
||||
let disposable = vscode.commands.registerCommand('devchat.openChatPanel', () => {
|
||||
if (vscode.workspace.workspaceFolders) {
|
||||
ChatPanel.createOrShow(context.extensionUri);
|
||||
} else {
|
||||
vscode.window.showErrorMessage('Please open a directory before using the chat panel.');
|
||||
}
|
||||
});
|
||||
|
||||
const createNewSessionOption = 'Create new session';
|
||||
const options = [...sessionNames, createNewSessionOption];
|
||||
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
|
||||
}
|
||||
}
|
||||
|
||||
const selectedOption = await vscode.window.showQuickPick(options, {
|
||||
placeHolder: 'Select a session or create a new one',
|
||||
});
|
||||
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);
|
||||
}
|
||||
});
|
||||
|
||||
if (!selectedOption) {
|
||||
return;
|
||||
}
|
||||
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);
|
||||
}
|
||||
});
|
||||
|
||||
let sessionName = selectedOption;
|
||||
|
||||
if (selectedOption === createNewSessionOption) {
|
||||
sessionName = await vscode.window.showInputBox({
|
||||
prompt: 'Enter a new session name',
|
||||
placeHolder: 'Session Name',
|
||||
});
|
||||
|
||||
if (!sessionName) {
|
||||
return;
|
||||
}
|
||||
}
|
||||
|
||||
ChatPanel.createOrShow(context.extensionUri, sessionName);
|
||||
});
|
||||
|
||||
context.subscriptions.push(disposable);
|
||||
context.subscriptions.push(disposable);
|
||||
context.subscriptions.push(disposable_add_context);
|
||||
context.subscriptions.push(disposableCodeContext)
|
||||
context.subscriptions.push(disposableAskFile)
|
||||
}
|
||||
exports.activate = activate;
|
||||
|
109
src/messageHandler.ts
Normal file
109
src/messageHandler.ts
Normal file
@ -0,0 +1,109 @@
|
||||
// messageHandler.ts
|
||||
|
||||
import * as vscode from 'vscode';
|
||||
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 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;
|
||||
}
|
||||
}
|
||||
|
||||
export default handleMessage;
|
@ -1,50 +0,0 @@
|
||||
|
||||
const { Configuration, OpenAIApi } = require("openai");
|
||||
import * as dotenv from 'dotenv';
|
||||
import * as path from 'path';
|
||||
|
||||
const extensionDir = path.resolve(__dirname, '..');
|
||||
const envFilePath = path.join(extensionDir, '.env');
|
||||
const dotenvOutput = dotenv.config({ path: envFilePath });
|
||||
console.log('dotenv output:', dotenvOutput);
|
||||
|
||||
const configuration = new Configuration({
|
||||
apiKey: process.env.OPENAI_API_KEY,
|
||||
});
|
||||
|
||||
// Set up proxy settings
|
||||
const openai = new OpenAIApi(configuration);
|
||||
|
||||
const HttpsProxyAgent = require('https-proxy-agent')
|
||||
const HttpProxyAgent = require('http-proxy-agent');
|
||||
|
||||
export async function chatWithGPT(prompt: string, session_id: string, messageList: Array<{ role: string; content: string }>): Promise<any[]> {
|
||||
const fullConversation = [
|
||||
...messageList,
|
||||
{
|
||||
role: 'user',
|
||||
content: prompt,
|
||||
},
|
||||
];
|
||||
|
||||
try {
|
||||
let completion = await openai.createChatCompletion({
|
||||
model: "gpt-3.5-turbo",
|
||||
messages: fullConversation,
|
||||
temperature: 0.9,
|
||||
max_tokens: 2048,
|
||||
top_p: 1,
|
||||
frequency_penalty: 0.0,
|
||||
presence_penalty: 0.6,
|
||||
stop: null,
|
||||
},
|
||||
{
|
||||
}
|
||||
);
|
||||
|
||||
return [0, completion.data.choices[0].message.content]
|
||||
} catch (e) {
|
||||
console.log("Error:", e.message)
|
||||
return [-1, "Error while connecting to the GPT model."];
|
||||
}
|
||||
}
|
@ -1,22 +0,0 @@
|
||||
"use strict";
|
||||
Object.defineProperty(exports, "__esModule", { value: true });
|
||||
const path = require("path");
|
||||
const test_electron_1 = require("@vscode/test-electron");
|
||||
async function main() {
|
||||
try {
|
||||
// The folder containing the Extension Manifest package.json
|
||||
// Passed to `--extensionDevelopmentPath`
|
||||
const extensionDevelopmentPath = path.resolve(__dirname, '../../');
|
||||
// The path to test runner
|
||||
// Passed to --extensionTestsPath
|
||||
const extensionTestsPath = path.resolve(__dirname, './suite/index');
|
||||
// Download VS Code, unzip it and run the integration test
|
||||
await (0, test_electron_1.runTests)({ extensionDevelopmentPath, extensionTestsPath });
|
||||
}
|
||||
catch (err) {
|
||||
console.error('Failed to run tests', err);
|
||||
process.exit(1);
|
||||
}
|
||||
}
|
||||
main();
|
||||
//# sourceMappingURL=runTest.js.map
|
@ -1 +0,0 @@
|
||||
{"version":3,"file":"runTest.js","sourceRoot":"","sources":["runTest.ts"],"names":[],"mappings":";;AAAA,6BAA6B;AAE7B,yDAAiD;AAEjD,KAAK,UAAU,IAAI;IAClB,IAAI;QACH,4DAA4D;QAC5D,yCAAyC;QACzC,MAAM,wBAAwB,GAAG,IAAI,CAAC,OAAO,CAAC,SAAS,EAAE,QAAQ,CAAC,CAAC;QAEnE,0BAA0B;QAC1B,iCAAiC;QACjC,MAAM,kBAAkB,GAAG,IAAI,CAAC,OAAO,CAAC,SAAS,EAAE,eAAe,CAAC,CAAC;QAEpE,0DAA0D;QAC1D,MAAM,IAAA,wBAAQ,EAAC,EAAE,wBAAwB,EAAE,kBAAkB,EAAE,CAAC,CAAC;KACjE;IAAC,OAAO,GAAG,EAAE;QACb,OAAO,CAAC,KAAK,CAAC,qBAAqB,EAAE,GAAG,CAAC,CAAC;QAC1C,OAAO,CAAC,IAAI,CAAC,CAAC,CAAC,CAAC;KAChB;AACF,CAAC;AAED,IAAI,EAAE,CAAC"}
|
@ -1,23 +0,0 @@
|
||||
import * as path from 'path';
|
||||
|
||||
import { runTests } from '@vscode/test-electron';
|
||||
|
||||
async function main() {
|
||||
try {
|
||||
// The folder containing the Extension Manifest package.json
|
||||
// Passed to `--extensionDevelopmentPath`
|
||||
const extensionDevelopmentPath = path.resolve(__dirname, '../../');
|
||||
|
||||
// The path to test runner
|
||||
// Passed to --extensionTestsPath
|
||||
const extensionTestsPath = path.resolve(__dirname, './suite/index');
|
||||
|
||||
// Download VS Code, unzip it and run the integration test
|
||||
await runTests({ extensionDevelopmentPath, extensionTestsPath });
|
||||
} catch (err) {
|
||||
console.error('Failed to run tests', err);
|
||||
process.exit(1);
|
||||
}
|
||||
}
|
||||
|
||||
main();
|
@ -1,15 +0,0 @@
|
||||
"use strict";
|
||||
Object.defineProperty(exports, "__esModule", { value: true });
|
||||
const assert = require("assert");
|
||||
// You can import and use all API from the 'vscode' module
|
||||
// as well as import your extension to test it
|
||||
const vscode = require("vscode");
|
||||
// import * as myExtension from '../../extension';
|
||||
suite('Extension Test Suite', () => {
|
||||
vscode.window.showInformationMessage('Start all tests.');
|
||||
test('Sample test', () => {
|
||||
assert.strictEqual(-1, [1, 2, 3].indexOf(5));
|
||||
assert.strictEqual(-1, [1, 2, 3].indexOf(0));
|
||||
});
|
||||
});
|
||||
//# sourceMappingURL=extension.test.js.map
|
@ -1 +0,0 @@
|
||||
{"version":3,"file":"extension.test.js","sourceRoot":"","sources":["extension.test.ts"],"names":[],"mappings":";;AAAA,iCAAiC;AAEjC,0DAA0D;AAC1D,8CAA8C;AAC9C,iCAAiC;AACjC,kDAAkD;AAElD,KAAK,CAAC,sBAAsB,EAAE,GAAG,EAAE;IAClC,MAAM,CAAC,MAAM,CAAC,sBAAsB,CAAC,kBAAkB,CAAC,CAAC;IAEzD,IAAI,CAAC,aAAa,EAAE,GAAG,EAAE;QACxB,MAAM,CAAC,WAAW,CAAC,CAAC,CAAC,EAAE,CAAC,CAAC,EAAE,CAAC,EAAE,CAAC,CAAC,CAAC,OAAO,CAAC,CAAC,CAAC,CAAC,CAAC;QAC7C,MAAM,CAAC,WAAW,CAAC,CAAC,CAAC,EAAE,CAAC,CAAC,EAAE,CAAC,EAAE,CAAC,CAAC,CAAC,OAAO,CAAC,CAAC,CAAC,CAAC,CAAC;IAC9C,CAAC,CAAC,CAAC;AACJ,CAAC,CAAC,CAAC"}
|
@ -1,15 +0,0 @@
|
||||
import * as assert from 'assert';
|
||||
|
||||
// You can import and use all API from the 'vscode' module
|
||||
// as well as import your extension to test it
|
||||
import * as vscode from 'vscode';
|
||||
// import * as myExtension from '../../extension';
|
||||
|
||||
suite('Extension Test Suite', () => {
|
||||
vscode.window.showInformationMessage('Start all tests.');
|
||||
|
||||
test('Sample test', () => {
|
||||
assert.strictEqual(-1, [1, 2, 3].indexOf(5));
|
||||
assert.strictEqual(-1, [1, 2, 3].indexOf(0));
|
||||
});
|
||||
});
|
@ -1,40 +0,0 @@
|
||||
"use strict";
|
||||
Object.defineProperty(exports, "__esModule", { value: true });
|
||||
exports.run = void 0;
|
||||
const path = require("path");
|
||||
const Mocha = require("mocha");
|
||||
const glob = require("glob");
|
||||
function run() {
|
||||
// Create the mocha test
|
||||
const mocha = new Mocha({
|
||||
ui: 'tdd',
|
||||
color: true
|
||||
});
|
||||
const testsRoot = path.resolve(__dirname, '..');
|
||||
return new Promise((c, e) => {
|
||||
glob('**/**.test.js', { cwd: testsRoot }, (err, files) => {
|
||||
if (err) {
|
||||
return e(err);
|
||||
}
|
||||
// Add files to the test suite
|
||||
files.forEach(f => mocha.addFile(path.resolve(testsRoot, f)));
|
||||
try {
|
||||
// Run the mocha test
|
||||
mocha.run(failures => {
|
||||
if (failures > 0) {
|
||||
e(new Error(`${failures} tests failed.`));
|
||||
}
|
||||
else {
|
||||
c();
|
||||
}
|
||||
});
|
||||
}
|
||||
catch (err) {
|
||||
console.error(err);
|
||||
e(err);
|
||||
}
|
||||
});
|
||||
});
|
||||
}
|
||||
exports.run = run;
|
||||
//# sourceMappingURL=index.js.map
|
@ -1 +0,0 @@
|
||||
{"version":3,"file":"index.js","sourceRoot":"","sources":["index.ts"],"names":[],"mappings":";;;AAAA,6BAA6B;AAC7B,+BAA+B;AAC/B,6BAA6B;AAE7B,SAAgB,GAAG;IAClB,wBAAwB;IACxB,MAAM,KAAK,GAAG,IAAI,KAAK,CAAC;QACvB,EAAE,EAAE,KAAK;QACT,KAAK,EAAE,IAAI;KACX,CAAC,CAAC;IAEH,MAAM,SAAS,GAAG,IAAI,CAAC,OAAO,CAAC,SAAS,EAAE,IAAI,CAAC,CAAC;IAEhD,OAAO,IAAI,OAAO,CAAC,CAAC,CAAC,EAAE,CAAC,EAAE,EAAE;QAC3B,IAAI,CAAC,eAAe,EAAE,EAAE,GAAG,EAAE,SAAS,EAAE,EAAE,CAAC,GAAG,EAAE,KAAK,EAAE,EAAE;YACxD,IAAI,GAAG,EAAE;gBACR,OAAO,CAAC,CAAC,GAAG,CAAC,CAAC;aACd;YAED,8BAA8B;YAC9B,KAAK,CAAC,OAAO,CAAC,CAAC,CAAC,EAAE,CAAC,KAAK,CAAC,OAAO,CAAC,IAAI,CAAC,OAAO,CAAC,SAAS,EAAE,CAAC,CAAC,CAAC,CAAC,CAAC;YAE9D,IAAI;gBACH,qBAAqB;gBACrB,KAAK,CAAC,GAAG,CAAC,QAAQ,CAAC,EAAE;oBACpB,IAAI,QAAQ,GAAG,CAAC,EAAE;wBACjB,CAAC,CAAC,IAAI,KAAK,CAAC,GAAG,QAAQ,gBAAgB,CAAC,CAAC,CAAC;qBAC1C;yBAAM;wBACN,CAAC,EAAE,CAAC;qBACJ;gBACF,CAAC,CAAC,CAAC;aACH;YAAC,OAAO,GAAG,EAAE;gBACb,OAAO,CAAC,KAAK,CAAC,GAAG,CAAC,CAAC;gBACnB,CAAC,CAAC,GAAG,CAAC,CAAC;aACP;QACF,CAAC,CAAC,CAAC;IACJ,CAAC,CAAC,CAAC;AACJ,CAAC;AAjCD,kBAiCC"}
|
@ -1,38 +0,0 @@
|
||||
import * as path from 'path';
|
||||
import * as Mocha from 'mocha';
|
||||
import * as glob from 'glob';
|
||||
|
||||
export function run(): Promise<void> {
|
||||
// Create the mocha test
|
||||
const mocha = new Mocha({
|
||||
ui: 'tdd',
|
||||
color: true
|
||||
});
|
||||
|
||||
const testsRoot = path.resolve(__dirname, '..');
|
||||
|
||||
return new Promise((c, e) => {
|
||||
glob('**/**.test.js', { cwd: testsRoot }, (err, files) => {
|
||||
if (err) {
|
||||
return e(err);
|
||||
}
|
||||
|
||||
// Add files to the test suite
|
||||
files.forEach(f => mocha.addFile(path.resolve(testsRoot, f)));
|
||||
|
||||
try {
|
||||
// Run the mocha test
|
||||
mocha.run(failures => {
|
||||
if (failures > 0) {
|
||||
e(new Error(`${failures} tests failed.`));
|
||||
} else {
|
||||
c();
|
||||
}
|
||||
});
|
||||
} catch (err) {
|
||||
console.error(err);
|
||||
e(err);
|
||||
}
|
||||
});
|
||||
});
|
||||
}
|
@ -15,3 +15,4 @@
|
||||
// "noUnusedParameters": true, /* Report errors on unused parameters. */
|
||||
}
|
||||
}
|
||||
|
||||
|
Loading…
x
Reference in New Issue
Block a user