diff --git a/.eslintrc.json b/.eslintrc.json new file mode 100644 index 0000000..47ef7b3 --- /dev/null +++ b/.eslintrc.json @@ -0,0 +1,21 @@ +{ + "root": true, + "parser": "@typescript-eslint/parser", + "parserOptions": { + "ecmaVersion": 2020, + "sourceType": "module" + }, + "plugins": ["@typescript-eslint"], + "extends": [ + "eslint:recommended", + "plugin:@typescript-eslint/recommended" + ], + "rules": { + "@typescript-eslint/no-unused-vars": "warn", + "@typescript-eslint/no-explicit-any": "warn" + }, + "env": { + "node": true, + "es6": true + } +} diff --git a/.gitignore b/.gitignore index 1170717..2443eec 100644 --- a/.gitignore +++ b/.gitignore @@ -89,7 +89,8 @@ out # Nuxt.js build / generate output .nuxt -dist +# dist - commented out for VS Code extension, we need dist/ for the bundled extension +# dist # Gatsby files .cache/ diff --git a/.prettierrc.json b/.prettierrc.json new file mode 100644 index 0000000..29b9d1f --- /dev/null +++ b/.prettierrc.json @@ -0,0 +1,8 @@ +{ + "semi": true, + "trailingComma": "es5", + "singleQuote": true, + "printWidth": 100, + "tabWidth": 2, + "useTabs": false +} diff --git a/.vscodeignore b/.vscodeignore new file mode 100644 index 0000000..db2dc0f --- /dev/null +++ b/.vscodeignore @@ -0,0 +1,14 @@ +.vscode/** +.vscode-test/** +src/** +.gitignore +.yarnrc +webpack.config.js +**/tsconfig.json +**/.eslintrc.json +**/*.map +**/*.ts +node_modules/** +out/** +.eslintcache +.prettierrc.json diff --git a/EXTENSION_README.md b/EXTENSION_README.md new file mode 100644 index 0000000..131bcea --- /dev/null +++ b/EXTENSION_README.md @@ -0,0 +1,223 @@ +# Deep Assistant - VS Code Extension + +A powerful AI assistant extension for Visual Studio Code with full support for web-based editors like github.dev and vscode.dev. + +## Features + +- **Multiple AI Models**: Support for GPT-4o, Claude, DeepSeek, and more +- **Web Compatible**: Works seamlessly on github.dev and vscode.dev +- **Chat Interface**: Beautiful integrated chat panel in VS Code sidebar +- **Token Management**: Track your API usage with energy-based billing +- **Model Selection**: Easily switch between different AI models +- **Conversation History**: Maintains context across multiple messages + +## Supported Models + +- GPT-4o / GPT-4o-mini +- Claude 3.7 Sonnet / Claude 3.5 Sonnet / Claude Sonnet 4 +- DeepSeek Chat / DeepSeek Reasoner +- o1-preview / o1-mini / o3-mini + +## Installation + +### From VS Code Marketplace (Coming Soon) + +1. Open VS Code +2. Go to Extensions (Ctrl+Shift+X / Cmd+Shift+X) +3. Search for "Deep Assistant" +4. Click Install + +### Manual Installation + +1. Clone this repository +2. Install dependencies: `npm install` +3. Build the extension: `npm run package` +4. Install the `.vsix` file in VS Code + +### Using on github.dev + +The extension is fully compatible with github.dev! Simply: + +1. Navigate to any GitHub repository +2. Press `.` to open github.dev +3. Install the Deep Assistant extension +4. Configure your API token in settings +5. Start chatting with AI! + +## Configuration + +After installation, configure the extension in VS Code settings: + +1. **API Token** (`deepAssistant.apiToken`): Your Deep Assistant API token +2. **API Base URL** (`deepAssistant.apiBaseUrl`): Default: `https://api.deep-assistant.com` +3. **Default Model** (`deepAssistant.defaultModel`): Choose your preferred AI model +4. **System Message** (`deepAssistant.systemMessage`): Customize the AI's behavior +5. **Show Token Usage** (`deepAssistant.showTokenUsage`): Display energy/token usage + +### Getting an API Token + +To use the Deep Assistant extension, you need an API token: + +1. Visit the Deep Assistant website (link coming soon) +2. Sign up or log in to your account +3. Generate an API token +4. Copy the token to VS Code settings + +## Usage + +### Opening the Chat Panel + +- Click the Deep Assistant icon in the Activity Bar +- Or use Command Palette (Ctrl+Shift+P / Cmd+Shift+P): `Deep Assistant: Start Chat` + +### Sending Messages + +1. Type your message in the input field at the bottom of the chat panel +2. Press Enter or click Send +3. Wait for the AI response + +### Available Commands + +- **Deep Assistant: Start Chat** - Open the chat panel +- **Deep Assistant: Clear Chat History** - Clear conversation history +- **Deep Assistant: Select Model** - Choose a different AI model +- **Deep Assistant: Settings** - Open extension settings + +### Keyboard Shortcuts + +- `Enter` - Send message +- `Shift+Enter` - New line in message + +## Architecture + +This extension is built with: + +- **TypeScript** - Type-safe code +- **Webpack** - Bundling for both desktop and web +- **VS Code API** - Native VS Code integration +- **Fetch API** - Web-compatible HTTP requests + +### Project Structure + +``` +├── src/ +│ ├── extension.ts # Desktop extension entry point +│ ├── web/ +│ │ └── extension.ts # Web extension entry point +│ ├── apiClient.ts # API integration layer +│ └── chatViewProvider.ts # Chat UI implementation +├── dist/ +│ ├── extension.js # Compiled desktop extension +│ └── web/ +│ └── extension.js # Compiled web extension +├── package.json # Extension manifest +├── webpack.config.js # Build configuration +└── tsconfig.json # TypeScript configuration +``` + +## Development + +### Prerequisites + +- Node.js 18+ +- npm or yarn +- VS Code + +### Setup + +```bash +# Install dependencies +npm install + +# Compile extension +npm run compile + +# Compile web extension +npm run compile-web + +# Watch mode (auto-compile on changes) +npm run watch +# or for web extension +npm run watch-web +``` + +### Testing Locally + +1. Open this project in VS Code +2. Press F5 to launch Extension Development Host +3. Test your changes in the new VS Code window + +### Testing on Web + +```bash +# Build web extension +npm run compile-web + +# Test in browser (requires @vscode/test-web) +npx @vscode/test-web --browserType=chromium --extensionDevelopmentPath=. +``` + +### Building for Production + +```bash +# Build both desktop and web extensions +npm run package + +# This creates optimized bundles in dist/ +``` + +## API Integration + +This extension integrates with the Deep Assistant API Gateway, which provides: + +- OpenAI-compatible API endpoints +- Multi-provider failover (OpenAI, DeepSeek, OpenRouter, etc.) +- Token-based authentication +- Energy-based billing system +- Conversation history management + +For API documentation, see the [api-gateway ARCHITECTURE.md](https://github.com/deep-assistant/api-gateway/blob/main/ARCHITECTURE.md). + +## Roadmap + +- [ ] Streaming responses support +- [ ] Code snippet insertion +- [ ] File context sharing +- [ ] Multi-turn conversations with history +- [ ] Voice input/output +- [ ] Image generation +- [ ] Code review assistance +- [ ] Custom system prompts per workspace + +## Contributing + +Contributions are welcome! Please: + +1. Fork the repository +2. Create a feature branch +3. Make your changes +4. Submit a pull request + +## Support + +- Report issues: [GitHub Issues](https://github.com/deep-assistant/master-plan/issues) +- Discussions: [GitHub Discussions](https://github.com/deep-assistant/master-plan/discussions) + +## License + +This project is released under the Unlicense (public domain). See LICENSE file for details. + +## Privacy + +- All API requests are sent to the configured API endpoint +- No data is stored locally except for configuration +- Conversation history is managed server-side +- See our Privacy Policy for more details + +## Credits + +Developed by the Deep Assistant team as part of the mission to create a personal AI assistant available on any device. + +--- + +**Enjoy using Deep Assistant!** diff --git a/README.md b/README.md index f2900fe..c849a97 100644 --- a/README.md +++ b/README.md @@ -2,7 +2,30 @@ The repository to host: * [issues](https://github.com/deep-assistant/master-plan/issues) that related to entire organization; -* [community discussions](https://github.com/deep-assistant/master-plan/discussions). +* [community discussions](https://github.com/deep-assistant/master-plan/discussions); +* **VS Code Extension** - Deep Assistant extension with full support for Visual Studio Code web (github.dev, vscode.dev). + +## VS Code Extension + +**Deep Assistant** is now available as a VS Code extension with full support for web-based editors! + +### Features + +- Works on **github.dev** and **vscode.dev** in your browser +- Integrated chat interface in VS Code sidebar +- Support for multiple AI models (GPT-4o, Claude, DeepSeek, etc.) +- Token-based billing with energy tracking +- Real-time conversation with AI assistance + +### Quick Start + +1. Navigate to any GitHub repository +2. Press `.` to open github.dev +3. Install the Deep Assistant extension +4. Configure your API token in settings +5. Start chatting with AI! + +See [EXTENSION_README.md](./EXTENSION_README.md) for detailed documentation. ## Architecture Documentation diff --git a/package.json b/package.json new file mode 100644 index 0000000..5eb386c --- /dev/null +++ b/package.json @@ -0,0 +1,143 @@ +{ + "name": "deep-assistant", + "displayName": "Deep Assistant", + "description": "Personal AI assistant for VS Code with support for Visual Studio Code web (github.dev, vscode.dev)", + "version": "0.1.0", + "publisher": "deep-assistant", + "license": "Unlicense", + "engines": { + "vscode": "^1.80.0" + }, + "categories": [ + "AI", + "Chat", + "Other" + ], + "keywords": [ + "ai", + "assistant", + "chat", + "gpt", + "openai", + "claude", + "deepseek" + ], + "activationEvents": [ + "onStartupFinished" + ], + "main": "./dist/extension.js", + "browser": "./dist/web/extension.js", + "contributes": { + "commands": [ + { + "command": "deepAssistant.chat", + "title": "Deep Assistant: Start Chat" + }, + { + "command": "deepAssistant.clearChat", + "title": "Deep Assistant: Clear Chat History" + }, + { + "command": "deepAssistant.selectModel", + "title": "Deep Assistant: Select Model" + }, + { + "command": "deepAssistant.showSettings", + "title": "Deep Assistant: Settings" + } + ], + "configuration": { + "title": "Deep Assistant", + "properties": { + "deepAssistant.apiBaseUrl": { + "type": "string", + "default": "https://api.deep-assistant.com", + "description": "API Gateway base URL" + }, + "deepAssistant.apiToken": { + "type": "string", + "default": "", + "description": "Your API token for authentication" + }, + "deepAssistant.defaultModel": { + "type": "string", + "default": "gpt-4o-mini", + "enum": [ + "gpt-4o", + "gpt-4o-mini", + "claude-3-7-sonnet", + "claude-3-5-sonnet", + "claude-sonnet-4", + "deepseek-chat", + "deepseek-reasoner", + "o1-preview", + "o1-mini", + "o3-mini" + ], + "description": "Default AI model to use" + }, + "deepAssistant.systemMessage": { + "type": "string", + "default": "You are a helpful AI assistant integrated into VS Code.", + "description": "System message for the AI assistant" + }, + "deepAssistant.showTokenUsage": { + "type": "boolean", + "default": true, + "description": "Show token usage in chat responses" + } + } + }, + "viewsContainers": { + "activitybar": [ + { + "id": "deep-assistant", + "title": "Deep Assistant", + "icon": "resources/icon.svg" + } + ] + }, + "views": { + "deep-assistant": [ + { + "type": "webview", + "id": "deepAssistant.chatView", + "name": "Chat" + } + ] + } + }, + "scripts": { + "vscode:prepublish": "npm run package", + "compile": "webpack", + "compile-web": "webpack --config-name web", + "watch": "webpack --watch", + "watch-web": "webpack --watch --config-name web", + "package": "webpack --mode production --devtool hidden-source-map", + "package-web": "webpack --mode production --devtool hidden-source-map --config-name web", + "test": "node ./out/test/runTest.js", + "lint": "eslint src --ext ts", + "format": "prettier --write \"src/**/*.ts\"" + }, + "devDependencies": { + "@types/node": "^20.0.0", + "@types/vscode": "^1.80.0", + "@typescript-eslint/eslint-plugin": "^6.0.0", + "@typescript-eslint/parser": "^6.0.0", + "eslint": "^8.50.0", + "prettier": "^3.0.0", + "ts-loader": "^9.5.0", + "typescript": "^5.2.0", + "webpack": "^5.88.0", + "webpack-cli": "^5.1.4" + }, + "dependencies": {}, + "repository": { + "type": "git", + "url": "https://github.com/deep-assistant/vscode-extension.git" + }, + "bugs": { + "url": "https://github.com/deep-assistant/master-plan/issues" + }, + "homepage": "https://github.com/deep-assistant/master-plan#readme" +} diff --git a/resources/icon.svg b/resources/icon.svg new file mode 100644 index 0000000..88fa04d --- /dev/null +++ b/resources/icon.svg @@ -0,0 +1,9 @@ + + + + + + + + + diff --git a/src/apiClient.ts b/src/apiClient.ts new file mode 100644 index 0000000..68cc6ae --- /dev/null +++ b/src/apiClient.ts @@ -0,0 +1,147 @@ +import * as vscode from 'vscode'; + +export interface ChatMessage { + role: 'user' | 'assistant' | 'system'; + content: string; +} + +export interface CompletionResponse { + id: string; + object: string; + created: number; + model: string; + choices: Array<{ + index: number; + message: { + role: string; + content: string; + }; + finish_reason: string; + }>; + usage?: { + prompt_tokens: number; + completion_tokens: number; + total_tokens: number; + energy?: number; + }; +} + +export class ApiClient { + private getConfig() { + return vscode.workspace.getConfiguration('deepAssistant'); + } + + private getApiBaseUrl(): string { + return this.getConfig().get('apiBaseUrl', 'https://api.deep-assistant.com'); + } + + private getApiToken(): string { + const token = this.getConfig().get('apiToken', ''); + if (!token) { + vscode.window.showErrorMessage( + 'Deep Assistant: API token is not configured. Please set it in settings.' + ); + return ''; + } + return token as string; + } + + private getDefaultModel(): string { + return this.getConfig().get('defaultModel', 'gpt-4o-mini'); + } + + private getSystemMessage(): string { + return this.getConfig().get( + 'systemMessage', + 'You are a helpful AI assistant integrated into VS Code.' + ); + } + + async sendMessage(userMessage: string): Promise { + const apiToken = this.getApiToken(); + if (!apiToken) { + return 'Error: API token not configured'; + } + + const apiBaseUrl = this.getApiBaseUrl(); + const model = this.getDefaultModel(); + const systemMessage = this.getSystemMessage(); + + try { + const messages: ChatMessage[] = [ + { role: 'system', content: systemMessage }, + { role: 'user', content: userMessage }, + ]; + + const response = await fetch(`${apiBaseUrl}/v1/chat/completions`, { + method: 'POST', + headers: { + 'Content-Type': 'application/json', + Authorization: `Bearer ${apiToken}`, + }, + body: JSON.stringify({ + model, + messages, + stream: false, + }), + }); + + if (!response.ok) { + const errorText = await response.text(); + console.error('API error response:', errorText); + + if (response.status === 401) { + return 'Error: Invalid API token. Please check your settings.'; + } else if (response.status === 429) { + return 'Error: Insufficient balance. Please top up your account.'; + } + + return `Error: API request failed with status ${response.status}`; + } + + const data: CompletionResponse = await response.json(); + + if (data.choices && data.choices.length > 0) { + let result = data.choices[0].message.content; + + // Optionally show token usage + if (this.getConfig().get('showTokenUsage', true) && data.usage) { + const energy = data.usage.energy || 0; + result += `\n\n_Token usage: ${data.usage.total_tokens} tokens (${energy.toFixed(2)} energy)_`; + } + + return result; + } + + return 'Error: No response from AI'; + } catch (error) { + console.error('API client error:', error); + return `Error: ${error instanceof Error ? error.message : 'Unknown error occurred'}`; + } + } + + async clearDialog(): Promise { + const apiToken = this.getApiToken(); + if (!apiToken) { + return; + } + + const apiBaseUrl = this.getApiBaseUrl(); + + try { + // Get user ID from token (for now, we'll use a placeholder) + // In production, this should be derived from the token or user profile + const userId = 'vscode-user'; + + const response = await fetch(`${apiBaseUrl}/dialog?masterToken=${apiToken}&userId=${userId}`, { + method: 'DELETE', + }); + + if (!response.ok) { + console.error('Failed to clear dialog:', response.statusText); + } + } catch (error) { + console.error('Error clearing dialog:', error); + } + } +} diff --git a/src/chatViewProvider.ts b/src/chatViewProvider.ts new file mode 100644 index 0000000..d0418e7 --- /dev/null +++ b/src/chatViewProvider.ts @@ -0,0 +1,299 @@ +import * as vscode from 'vscode'; +import { ApiClient } from './apiClient'; + +export class ChatViewProvider implements vscode.WebviewViewProvider { + public static readonly viewType = 'deepAssistant.chatView'; + + private _view?: vscode.WebviewView; + + constructor( + private readonly _extensionUri: vscode.Uri, + private readonly _apiClient: ApiClient + ) {} + + public resolveWebviewView( + webviewView: vscode.WebviewView, + context: vscode.WebviewViewResolveContext, + _token: vscode.CancellationToken + ) { + this._view = webviewView; + + webviewView.webview.options = { + enableScripts: true, + localResourceRoots: [this._extensionUri], + }; + + webviewView.webview.html = this._getHtmlForWebview(webviewView.webview); + + // Handle messages from the webview + webviewView.webview.onDidReceiveMessage(async (data) => { + switch (data.type) { + case 'sendMessage': { + const userMessage = data.message; + // Send typing indicator + webviewView.webview.postMessage({ + type: 'typingStart', + }); + + try { + const response = await this._apiClient.sendMessage(userMessage); + webviewView.webview.postMessage({ + type: 'receiveMessage', + message: response, + }); + } catch (error) { + webviewView.webview.postMessage({ + type: 'receiveMessage', + message: `Error: ${error instanceof Error ? error.message : 'Unknown error'}`, + }); + } finally { + webviewView.webview.postMessage({ + type: 'typingStop', + }); + } + break; + } + } + }); + } + + public focusView() { + if (this._view) { + this._view.show?.(true); + } + } + + public clearChat() { + if (this._view) { + this._view.webview.postMessage({ + type: 'clearChat', + }); + } + } + + private _getHtmlForWebview(webview: vscode.Webview) { + return ` + + + + + Deep Assistant Chat + + + +
+
+
+ + +
+
+ + + +`; + } +} diff --git a/src/extension.ts b/src/extension.ts new file mode 100644 index 0000000..8629f4b --- /dev/null +++ b/src/extension.ts @@ -0,0 +1,78 @@ +import * as vscode from 'vscode'; +import { ChatViewProvider } from './chatViewProvider'; +import { ApiClient } from './apiClient'; + +let chatViewProvider: ChatViewProvider; +let apiClient: ApiClient; + +export function activate(context: vscode.ExtensionContext) { + console.log('Deep Assistant extension is now active'); + + // Initialize API client + apiClient = new ApiClient(); + + // Register chat view provider + chatViewProvider = new ChatViewProvider(context.extensionUri, apiClient); + context.subscriptions.push( + vscode.window.registerWebviewViewProvider(ChatViewProvider.viewType, chatViewProvider) + ); + + // Register commands + context.subscriptions.push( + vscode.commands.registerCommand('deepAssistant.chat', () => { + chatViewProvider.focusView(); + }) + ); + + context.subscriptions.push( + vscode.commands.registerCommand('deepAssistant.clearChat', async () => { + const confirmed = await vscode.window.showWarningMessage( + 'Are you sure you want to clear chat history?', + 'Yes', + 'No' + ); + if (confirmed === 'Yes') { + await apiClient.clearDialog(); + chatViewProvider.clearChat(); + vscode.window.showInformationMessage('Chat history cleared'); + } + }) + ); + + context.subscriptions.push( + vscode.commands.registerCommand('deepAssistant.selectModel', async () => { + const models = [ + 'gpt-4o', + 'gpt-4o-mini', + 'claude-3-7-sonnet', + 'claude-3-5-sonnet', + 'claude-sonnet-4', + 'deepseek-chat', + 'deepseek-reasoner', + 'o1-preview', + 'o1-mini', + 'o3-mini', + ]; + + const selected = await vscode.window.showQuickPick(models, { + placeHolder: 'Select an AI model', + }); + + if (selected) { + const config = vscode.workspace.getConfiguration('deepAssistant'); + await config.update('defaultModel', selected, vscode.ConfigurationTarget.Global); + vscode.window.showInformationMessage(`Model changed to ${selected}`); + } + }) + ); + + context.subscriptions.push( + vscode.commands.registerCommand('deepAssistant.showSettings', () => { + vscode.commands.executeCommand('workbench.action.openSettings', 'deepAssistant'); + }) + ); +} + +export function deactivate() { + console.log('Deep Assistant extension is now deactivated'); +} diff --git a/src/web/extension.ts b/src/web/extension.ts new file mode 100644 index 0000000..6a6fc22 --- /dev/null +++ b/src/web/extension.ts @@ -0,0 +1,83 @@ +import * as vscode from 'vscode'; +import { ChatViewProvider } from '../chatViewProvider'; +import { ApiClient } from '../apiClient'; + +let chatViewProvider: ChatViewProvider; +let apiClient: ApiClient; + +export function activate(context: vscode.ExtensionContext) { + console.log('Deep Assistant web extension is now active (running in browser)'); + + // Initialize API client + apiClient = new ApiClient(); + + // Register chat view provider + chatViewProvider = new ChatViewProvider(context.extensionUri, apiClient); + context.subscriptions.push( + vscode.window.registerWebviewViewProvider(ChatViewProvider.viewType, chatViewProvider) + ); + + // Register commands + context.subscriptions.push( + vscode.commands.registerCommand('deepAssistant.chat', () => { + chatViewProvider.focusView(); + }) + ); + + context.subscriptions.push( + vscode.commands.registerCommand('deepAssistant.clearChat', async () => { + const confirmed = await vscode.window.showWarningMessage( + 'Are you sure you want to clear chat history?', + 'Yes', + 'No' + ); + if (confirmed === 'Yes') { + await apiClient.clearDialog(); + chatViewProvider.clearChat(); + vscode.window.showInformationMessage('Chat history cleared'); + } + }) + ); + + context.subscriptions.push( + vscode.commands.registerCommand('deepAssistant.selectModel', async () => { + const models = [ + 'gpt-4o', + 'gpt-4o-mini', + 'claude-3-7-sonnet', + 'claude-3-5-sonnet', + 'claude-sonnet-4', + 'deepseek-chat', + 'deepseek-reasoner', + 'o1-preview', + 'o1-mini', + 'o3-mini', + ]; + + const selected = await vscode.window.showQuickPick(models, { + placeHolder: 'Select an AI model', + }); + + if (selected) { + const config = vscode.workspace.getConfiguration('deepAssistant'); + await config.update('defaultModel', selected, vscode.ConfigurationTarget.Global); + vscode.window.showInformationMessage(`Model changed to ${selected}`); + } + }) + ); + + context.subscriptions.push( + vscode.commands.registerCommand('deepAssistant.showSettings', () => { + vscode.commands.executeCommand('workbench.action.openSettings', 'deepAssistant'); + }) + ); + + // Show welcome message for web version + vscode.window.showInformationMessage( + 'Deep Assistant is ready to use on github.dev! Configure your API token in settings.' + ); +} + +export function deactivate() { + console.log('Deep Assistant web extension is now deactivated'); +} diff --git a/tsconfig.json b/tsconfig.json new file mode 100644 index 0000000..d048271 --- /dev/null +++ b/tsconfig.json @@ -0,0 +1,16 @@ +{ + "compilerOptions": { + "module": "commonjs", + "target": "ES2020", + "lib": ["ES2020"], + "outDir": "out", + "sourceMap": true, + "strict": true, + "rootDir": "src", + "esModuleInterop": true, + "skipLibCheck": true, + "forceConsistentCasingInFileNames": true, + "resolveJsonModule": true + }, + "exclude": ["node_modules", ".vscode-test"] +} diff --git a/webpack.config.js b/webpack.config.js new file mode 100644 index 0000000..e527cad --- /dev/null +++ b/webpack.config.js @@ -0,0 +1,55 @@ +/* eslint-disable @typescript-eslint/no-var-requires */ +const path = require('path'); + +/**@type {import('webpack').Configuration}*/ +const baseConfig = { + mode: 'none', + devtool: 'nosources-source-map', + externals: { + vscode: 'commonjs vscode', + }, + resolve: { + extensions: ['.ts', '.js'], + }, + module: { + rules: [ + { + test: /\.ts$/, + exclude: /node_modules/, + use: [ + { + loader: 'ts-loader', + }, + ], + }, + ], + }, +}; + +/** @type {import('webpack').Configuration} */ +const desktopConfig = { + ...baseConfig, + name: 'desktop', + target: 'node', + entry: './src/extension.ts', + output: { + path: path.resolve(__dirname, 'dist'), + filename: 'extension.js', + libraryTarget: 'commonjs2', + }, +}; + +/** @type {import('webpack').Configuration} */ +const webConfig = { + ...baseConfig, + name: 'web', + target: 'webworker', + entry: './src/web/extension.ts', + output: { + path: path.resolve(__dirname, 'dist', 'web'), + filename: 'extension.js', + libraryTarget: 'commonjs2', + }, +}; + +module.exports = [desktopConfig, webConfig];