├── resources
├── claude-icon.png
├── restart-dark.svg
├── restart-light.svg
├── mode-toggle.svg
├── image-svgrepo-com.svg
└── claude-icon.svg
├── media
├── screenshots
│ ├── context-files.png
│ ├── image-support.png
│ ├── launch-options.png
│ ├── quick-fix-menu.png
│ ├── slash-commands.png
│ ├── auto-start-settings.png
│ └── claude-terminal-input.png
└── codicon.css
├── .gitignore
├── src
├── utils.ts
├── api
│ └── FileService.ts
├── utils
│ ├── slash-commands.ts
│ └── context-mentions.ts
├── ui
│ └── components
│ │ ├── SlashCommandSuggestions.ts
│ │ └── ContextMenu.ts
├── service
│ ├── imageManager.ts
│ ├── customCommandService.ts
│ ├── claudeCodeActionProvider.ts
│ └── terminalDetectionService.ts
├── fileSystem.ts
└── extension.ts
├── tsconfig.json
├── .vscodeignore
├── .vscode
└── tasks.json
├── webpack.config.js
├── .eslintrc.json
├── LICENSE.md
├── .github
└── workflows
│ └── auto-delete-branch.yml
├── CONTRIBUTING.md
├── .clinerules
├── main-rule.md
├── vscode-extension-developer.md
├── tdd.md
├── memory-bank.md
├── taskmaster-ai.md
└── PRD.md
├── docs
├── custom-slash-commands.md
└── claude-cli-usage.md
├── test
└── ui
│ ├── test-drag-drop.html
│ └── test-drag-drop-enhanced.html
├── TROUBLESHOOTING.md
├── package.json
├── SERVICE_WORKER_ERROR_INVESTIGATION.md
├── README.md
└── CHANGELOG.md
/resources/claude-icon.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/codeflow-studio/claude-code-chat/HEAD/resources/claude-icon.png
--------------------------------------------------------------------------------
/media/screenshots/context-files.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/codeflow-studio/claude-code-chat/HEAD/media/screenshots/context-files.png
--------------------------------------------------------------------------------
/media/screenshots/image-support.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/codeflow-studio/claude-code-chat/HEAD/media/screenshots/image-support.png
--------------------------------------------------------------------------------
/media/screenshots/launch-options.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/codeflow-studio/claude-code-chat/HEAD/media/screenshots/launch-options.png
--------------------------------------------------------------------------------
/media/screenshots/quick-fix-menu.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/codeflow-studio/claude-code-chat/HEAD/media/screenshots/quick-fix-menu.png
--------------------------------------------------------------------------------
/media/screenshots/slash-commands.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/codeflow-studio/claude-code-chat/HEAD/media/screenshots/slash-commands.png
--------------------------------------------------------------------------------
/media/screenshots/auto-start-settings.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/codeflow-studio/claude-code-chat/HEAD/media/screenshots/auto-start-settings.png
--------------------------------------------------------------------------------
/media/screenshots/claude-terminal-input.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/codeflow-studio/claude-code-chat/HEAD/media/screenshots/claude-terminal-input.png
--------------------------------------------------------------------------------
/.gitignore:
--------------------------------------------------------------------------------
1 | out
2 | node_modules
3 | .vscode-test/
4 | *.vsix
5 | .DS_Store
6 | dist/
7 |
8 | **/.claude
9 | .memory-bank
10 | CLAUDE.md
11 | docs
12 |
--------------------------------------------------------------------------------
/resources/restart-dark.svg:
--------------------------------------------------------------------------------
1 |
--------------------------------------------------------------------------------
/resources/restart-light.svg:
--------------------------------------------------------------------------------
1 |
--------------------------------------------------------------------------------
/src/utils.ts:
--------------------------------------------------------------------------------
1 | /**
2 | * Generates a nonce string for Content Security Policy
3 | */
4 | export function getNonce() {
5 | let text = '';
6 | const possible = 'ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789';
7 | for (let i = 0; i < 32; i++) {
8 | text += possible.charAt(Math.floor(Math.random() * possible.length));
9 | }
10 | return text;
11 | }
--------------------------------------------------------------------------------
/tsconfig.json:
--------------------------------------------------------------------------------
1 | {
2 | "compilerOptions": {
3 | "module": "commonjs",
4 | "target": "ES2020",
5 | "outDir": "dist",
6 | "lib": ["ES2020", "DOM"],
7 | "sourceMap": true,
8 | "rootDir": "src",
9 | "strict": true,
10 | "esModuleInterop": true,
11 | "skipLibCheck": true,
12 | "forceConsistentCasingInFileNames": true
13 | },
14 | "include": ["src"],
15 | "exclude": ["node_modules", ".vscode-test"]
16 | }
--------------------------------------------------------------------------------
/.vscodeignore:
--------------------------------------------------------------------------------
1 | .vscode/**
2 | .vscode-test/**
3 | .gitignore
4 | .yarnrc
5 | .claude/**
6 | **/node_modules/**
7 | **/*.ts
8 | **/*.map
9 | .eslintrc.json
10 | yarn.lock
11 | webpack.config.js
12 | .git/**
13 | tsconfig.json
14 | vsc-extension-quickstart.md
15 | PRD.md
16 | CLAUDE.md
17 | **/.DS_Store
18 | .memory-bank/**
19 | README-PUBLISHER.md
20 | MARKETPLACE-DESCRIPTION.md
21 | PUBLISH-CHECKLIST.md
22 | DISTRIBUTION-SUMMARY.md
23 | CONTRIBUTING.md
24 | src/**
25 | out/**
26 | test-*.html
--------------------------------------------------------------------------------
/resources/mode-toggle.svg:
--------------------------------------------------------------------------------
1 |
--------------------------------------------------------------------------------
/.vscode/tasks.json:
--------------------------------------------------------------------------------
1 | {
2 | "version": "2.0.0",
3 | "tasks": [
4 | {
5 | "type": "npm",
6 | "script": "watch",
7 | "problemMatcher": "$tsc-watch",
8 | "isBackground": true,
9 | "presentation": {
10 | "reveal": "never"
11 | },
12 | "group": {
13 | "kind": "build",
14 | "isDefault": true
15 | }
16 | },
17 | {
18 | "type": "npm",
19 | "script": "test",
20 | "group": "test",
21 | "problemMatcher": "$tsc"
22 | },
23 | {
24 | "type": "npm",
25 | "script": "compile",
26 | "group": "build",
27 | "problemMatcher": "$tsc"
28 | },
29 | {
30 | "label": "Run Extension",
31 | "type": "shell",
32 | "command": "code --extensionDevelopmentPath=${workspaceFolder} ${workspaceFolder}",
33 | "problemMatcher": []
34 | }
35 | ]
36 | }
--------------------------------------------------------------------------------
/webpack.config.js:
--------------------------------------------------------------------------------
1 | const path = require('path');
2 |
3 | const config = {
4 | target: 'node',
5 | entry: './src/extension.ts',
6 | mode: 'production', // Added mode to fix webpack warning
7 | output: {
8 | path: path.resolve(__dirname, 'dist'),
9 | filename: 'extension.js',
10 | libraryTarget: 'commonjs2',
11 | devtoolModuleFilenameTemplate: '../[resource-path]'
12 | },
13 | devtool: 'source-map',
14 | externals: {
15 | vscode: 'commonjs vscode'
16 | },
17 | resolve: {
18 | extensions: ['.ts', '.js']
19 | },
20 | module: {
21 | rules: [
22 | {
23 | test: /\.ts$/,
24 | exclude: /node_modules/,
25 | use: [
26 | {
27 | loader: 'ts-loader'
28 | }
29 | ]
30 | },
31 | {
32 | test: /\.css$/,
33 | use: ['style-loader', 'css-loader']
34 | }
35 | ]
36 | }
37 | };
38 |
39 | module.exports = config;
--------------------------------------------------------------------------------
/.eslintrc.json:
--------------------------------------------------------------------------------
1 | {
2 | "root": true,
3 | "parser": "@typescript-eslint/parser",
4 | "parserOptions": {
5 | "ecmaVersion": 2020,
6 | "sourceType": "module",
7 | "project": "./tsconfig.json"
8 | },
9 | "plugins": [
10 | "@typescript-eslint"
11 | ],
12 | "extends": [
13 | "eslint:recommended",
14 | "plugin:@typescript-eslint/recommended"
15 | ],
16 | "rules": {
17 | "@typescript-eslint/no-explicit-any": "off",
18 | "@typescript-eslint/no-unused-vars": ["warn", { "argsIgnorePattern": "^_" }],
19 | "@typescript-eslint/naming-convention": [
20 | "warn",
21 | {
22 | "selector": "variable",
23 | "format": ["camelCase", "UPPER_CASE"],
24 | "leadingUnderscore": "allow"
25 | }
26 | ],
27 | "semi": ["warn", "always"]
28 | },
29 | "ignorePatterns": ["node_modules", "dist", "out", "*.js", "webpack.config.js"]
30 | }
--------------------------------------------------------------------------------
/resources/image-svgrepo-com.svg:
--------------------------------------------------------------------------------
1 |
2 |
3 |
--------------------------------------------------------------------------------
/LICENSE.md:
--------------------------------------------------------------------------------
1 | MIT License
2 |
3 | Copyright (c) 2025 CodeFlow Studio
4 |
5 | Permission is hereby granted, free of charge, to any person obtaining a copy
6 | of this software and associated documentation files (the "Software"), to deal
7 | in the Software without restriction, including without limitation the rights
8 | to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
9 | copies of the Software, and to permit persons to whom the Software is
10 | furnished to do so, subject to the following conditions:
11 |
12 | The above copyright notice and this permission notice shall be included in all
13 | copies or substantial portions of the Software.
14 |
15 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
16 | IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
17 | FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
18 | AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
19 | LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
20 | OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
21 | SOFTWARE.
--------------------------------------------------------------------------------
/media/codicon.css:
--------------------------------------------------------------------------------
1 | /* VS Code codicon simplified set for context menus */
2 | @font-face {
3 | font-family: 'codicon';
4 | src: url('https://raw.githubusercontent.com/microsoft/vscode-codicons/main/dist/codicon.ttf') format('truetype');
5 | }
6 |
7 | .codicon {
8 | font-family: 'codicon';
9 | font-display: block;
10 | line-height: 1;
11 | font-weight: normal;
12 | font-style: normal;
13 | font-variant: normal;
14 | text-transform: none;
15 | letter-spacing: normal;
16 | -webkit-font-feature-settings: "liga";
17 | font-feature-settings: "liga";
18 | -webkit-font-smoothing: antialiased;
19 | }
20 |
21 | .codicon-file:before { content: '\ea7b'; }
22 | .codicon-folder:before { content: '\ea83'; }
23 | .codicon-warning:before { content: '\ea6c'; }
24 | .codicon-terminal:before { content: '\ea85'; }
25 | .codicon-link:before { content: '\eb16'; }
26 | .codicon-git-commit:before { content: '\ea8f'; }
27 | .codicon-info:before { content: '\ea74'; }
28 | .codicon-add:before { content: '\ea60'; }
29 | .codicon-chevron-right:before { content: '\eab4'; }
30 | .codicon-loading:before { content: '\eb19'; }
31 | .codicon-modifier-spin:before { content: '\eada'; }
--------------------------------------------------------------------------------
/.github/workflows/auto-delete-branch.yml:
--------------------------------------------------------------------------------
1 | name: Auto Delete Branch After PR Merge
2 |
3 | on:
4 | pull_request:
5 | types: [closed]
6 |
7 | jobs:
8 | delete-branch:
9 | # Only run if the PR was merged (not just closed)
10 | if: github.event.pull_request.merged == true
11 | runs-on: ubuntu-latest
12 |
13 | steps:
14 | - name: Delete merged branch
15 | run: |
16 | BRANCH_NAME="${{ github.event.pull_request.head.ref }}"
17 |
18 | # Safety check: Never delete protected branches
19 | if [[ "$BRANCH_NAME" == "main" ]] || \
20 | [[ "$BRANCH_NAME" == "master" ]] || \
21 | [[ "$BRANCH_NAME" == "develop" ]] || \
22 | [[ "$BRANCH_NAME" == "development" ]] || \
23 | [[ "$BRANCH_NAME" =~ ^release/.* ]] || \
24 | [[ "$BRANCH_NAME" =~ ^hotfix/.* ]]; then
25 | echo "🔒 Skipping deletion of protected branch: $BRANCH_NAME"
26 | exit 0
27 | fi
28 |
29 | # Only delete if it's from the same repository (not a fork)
30 | if [[ "${{ github.event.pull_request.head.repo.full_name }}" == "${{ github.event.pull_request.base.repo.full_name }}" ]]; then
31 | echo "🗑️ Deleting branch: $BRANCH_NAME"
32 | gh api repos/${{ github.repository }}/git/refs/heads/$BRANCH_NAME -X DELETE
33 | else
34 | echo "🔀 Skipping deletion of fork branch: $BRANCH_NAME"
35 | fi
36 | env:
37 | GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }}
--------------------------------------------------------------------------------
/src/api/FileService.ts:
--------------------------------------------------------------------------------
1 | import * as vscode from 'vscode';
2 | import * as path from 'path';
3 |
4 | export interface FileServiceClient {
5 | getRelativePaths(request: { uris: string[] }): Promise<{ paths: string[] }>;
6 | }
7 |
8 | /**
9 | * Converts a list of URIs to workspace-relative paths
10 | * @param request The request containing URIs to convert
11 | * @returns Response with resolved relative paths
12 | */
13 | export async function getRelativePaths(request: { uris: string[] }): Promise<{ paths: string[] }> {
14 | const resolvedPaths = await Promise.all(
15 | request.uris.map(async (uriString) => {
16 | try {
17 | const fileUri = vscode.Uri.parse(uriString, true);
18 | const relativePathToGet = vscode.workspace.asRelativePath(fileUri, false);
19 |
20 | // If the path is still absolute, it's outside the workspace
21 | if (path.isAbsolute(relativePathToGet)) {
22 | console.warn(`Dropped file ${relativePathToGet} is outside the workspace. Sending original path.`);
23 | return fileUri.fsPath.replace(/\\/g, '/');
24 | } else {
25 | let finalPath = relativePathToGet.replace(/\\/g, '/');
26 | try {
27 | const stat = await vscode.workspace.fs.stat(fileUri);
28 | if (stat.type === vscode.FileType.Directory) {
29 | finalPath += '/';
30 | }
31 | } catch (statError) {
32 | console.error(`Error stating file ${fileUri.fsPath}:`, statError);
33 | }
34 | return finalPath;
35 | }
36 | } catch (error) {
37 | console.error(`Error calculating relative path for ${uriString}:`, error);
38 | return null;
39 | }
40 | })
41 | );
42 |
43 | // Filter out any null values from errors
44 | const validPaths = resolvedPaths.filter((path): path is string => path !== null);
45 |
46 | return { paths: validPaths };
47 | }
48 |
49 | export const fileServiceClient: FileServiceClient = {
50 | getRelativePaths
51 | };
--------------------------------------------------------------------------------
/resources/claude-icon.svg:
--------------------------------------------------------------------------------
1 |
11 |
--------------------------------------------------------------------------------
/CONTRIBUTING.md:
--------------------------------------------------------------------------------
1 | # Contributing to Claude Code VSCode Extension
2 |
3 | We love your input! We want to make contributing to this project as easy and transparent as possible, whether it's:
4 |
5 | - Reporting a bug
6 | - Discussing the current state of the code
7 | - Submitting a fix
8 | - Proposing new features
9 | - Becoming a maintainer
10 |
11 | ## Development Process
12 |
13 | We use GitHub to host code, to track issues and feature requests, as well as accept pull requests.
14 |
15 | 1. Fork the repo and create your branch from `main`.
16 | 2. If you've added code that should be tested, add tests.
17 | 3. If you've changed APIs, update the documentation.
18 | 4. Ensure the test suite passes.
19 | 5. Make sure your code lints.
20 | 6. Issue that pull request!
21 |
22 | ## Any contributions you make will be under the MIT Software License
23 |
24 | In short, when you submit code changes, your submissions are understood to be under the same [MIT License](http://choosealicense.com/licenses/mit/) that covers the project. Feel free to contact the maintainers if that's a concern.
25 |
26 | ## Report bugs using GitHub's [issue tracker](https://github.com/codeflow-studio/claude-code-chat/issues)
27 |
28 | We use GitHub issues to track public bugs. Report a bug by [opening a new issue](https://github.com/codeflow-studio/claude-code-chat/issues/new); it's that easy!
29 |
30 | ## Write bug reports with detail, background, and sample code
31 |
32 | **Great Bug Reports** tend to have:
33 |
34 | - A quick summary and/or background
35 | - Steps to reproduce
36 | - Be specific!
37 | - Give sample code if you can
38 | - What you expected would happen
39 | - What actually happens
40 | - Notes (possibly including why you think this might be happening, or stuff you tried that didn't work)
41 |
42 | ## Use a Consistent Coding Style
43 |
44 | * 2 spaces for indentation rather than tabs
45 | * Run `npm run lint` to check code style
46 |
47 | ## Development Setup
48 |
49 | 1. Clone the repository:
50 | ```bash
51 | git clone https://github.com/codeflow-studio/claude-code-chat.git
52 | cd claude-code-chat
53 | ```
54 |
55 | 2. Install dependencies:
56 | ```bash
57 | npm install
58 | ```
59 |
60 | 3. Start development:
61 | ```bash
62 | npm run watch
63 | ```
64 |
65 | 4. Open VSCode and press F5 to launch a new VSCode window with the extension loaded.
66 |
67 | ## Testing
68 |
69 | Run the test suite:
70 | ```bash
71 | npm test
72 | ```
73 |
74 | ## Building
75 |
76 | Build the extension:
77 | ```bash
78 | npm run build
79 | ```
80 |
81 | This creates a `.vsix` file that can be installed in VSCode.
82 |
83 | ## License
84 |
85 | By contributing, you agree that your contributions will be licensed under its MIT License.
86 |
87 | ## References
88 |
89 | This document was adapted from the open-source contribution guidelines for [Facebook's Draft](https://github.com/facebook/draft-js/blob/a9316a723f9e918afde44dea68b5f9f39b7d9b00/CONTRIBUTING.md).
--------------------------------------------------------------------------------
/.clinerules/main-rule.md:
--------------------------------------------------------------------------------
1 |
2 | # Claude Code Development Framework
3 |
4 | This file serves as the central configuration for Claude's development approach. It dynamically loads modules based on project needs and orchestrates how they work together.
5 |
6 | ## Module System
7 |
8 | Claude's development framework uses a plugin architecture where modules can be loaded individually or in combination. Each module provides specific capabilities that can function independently or integrate with other modules for enhanced functionality.
9 |
10 | ### Available Modules
11 |
12 | #### Task Management
13 | @.claude/taskmaster-ai.md
14 | - Breaks down complex tasks into manageable units
15 | - Tracks progress and dependencies
16 | - Maintains focused execution
17 |
18 | #### Memory Bank
19 | @.claude/memory-bank.md
20 | - Maintains project knowledge across sessions
21 | - Organizes technical documentation
22 | - Ensures consistent understanding
23 | - Memory Bank Structure:
24 | - @.memory-bank/activeContext.md
25 | - @.memory-bank/productContext.md
26 | - @.memory-bank/progress.md
27 | - @.memory-bank/projectbrief.md
28 | - @.memory-bank/systemPatterns.md
29 | - @.memory-bank/techContext.md
30 |
31 | #### Developer Profile
32 | Example `@.claude/vscode-extension-developer.md`
33 | - Defines required technical skills
34 | - Guides implementation approaches
35 | - Sets quality standards
36 |
37 | #### TDD Methodology
38 | @.claude/tdd.md
39 | - Implements test-driven development
40 | - Ensures code quality and test coverage
41 | - Structures development cycles
42 |
43 | #### Product Requirements
44 | @.claude/PRD.md
45 | - Defines core product functionality
46 | - Sets user experience expectations
47 | - Establishes success criteria
48 |
49 | ## Integration Patterns
50 |
51 | When multiple modules are loaded, they automatically integrate through these connection points:
52 |
53 | - **Task Management + Memory Bank**: Task info feeds into activeContext.md and progress.md
54 | - **Task Management + TDD**: Testing tasks are integrated into workflow
55 | - **Memory Bank + Developer Profile**: Technical knowledge informs documentation
56 | - **Developer Profile + TDD**: Testing expertise guides implementation
57 | - **All Modules + PRD**: Product requirements inform all aspects of development
58 |
59 | ## Usage Guide
60 |
61 | 1. **Independent Mode**: Load individual modules for focused capabilities
62 | ```
63 | @.claude/taskmaster-ai.md # Just task management
64 | ```
65 |
66 | 2. **Combination Mode**: Load multiple modules for enhanced functionality
67 | ```
68 | @.claude/taskmaster-ai.md
69 | @.claude/memory-bank.md
70 | ```
71 |
72 | 3. **Full Framework**: Load all modules for comprehensive development approach
73 | ```
74 | @.claude/taskmaster-ai.md
75 | @.claude/memory-bank.md
76 | @.claude/developer.md
77 | @.claude/tdd.md
78 | @.claude/PRD.md
79 | ```
80 |
81 | The framework automatically detects which modules are loaded and adjusts its behavior accordingly, maintaining consistency regardless of which combination is used.
82 |
--------------------------------------------------------------------------------
/src/utils/slash-commands.ts:
--------------------------------------------------------------------------------
1 | import { customCommandService } from '../service/customCommandService';
2 |
3 | export interface SlashCommand {
4 | command: string;
5 | description: string;
6 | icon?: string;
7 | shortcut?: string;
8 | isCustom?: boolean; // Flag to identify custom commands
9 | }
10 |
11 | export const BUILT_IN_SLASH_COMMANDS: SlashCommand[] = [
12 | { command: '/bug', description: 'Report bugs (sends conversation to Anthropic)', icon: '🐛' },
13 | { command: '/clear', description: 'Clear conversation history', icon: '🗑️' },
14 | { command: '/compact', description: 'Compact conversation with optional focus instructions', icon: '📦' },
15 | { command: '/config', description: 'View/modify configuration', icon: '⚙️' },
16 | { command: '/cost', description: 'Show token usage statistics', icon: '💰' },
17 | { command: '/doctor', description: 'Checks the health of your Claude Code installation', icon: '🏥' },
18 | { command: '/help', description: 'Get usage help', icon: '❓' },
19 | { command: '/init', description: 'Initialize project with CLAUDE.md guide', icon: '🚀' },
20 | { command: '/login', description: 'Switch Anthropic accounts', icon: '🔐' },
21 | { command: '/logout', description: 'Sign out from your Anthropic account', icon: '🚪' },
22 | { command: '/memory', description: 'Edit CLAUDE.md memory files', icon: '🧠' },
23 | { command: '/pr_comments', description: 'View pull request comments', icon: '💬' },
24 | { command: '/review', description: 'Request code review', icon: '👀' },
25 | { command: '/status', description: 'View account and system statuses', icon: '📊' },
26 | { command: '/terminal-setup', description: 'Install Shift+Enter key binding for newlines', icon: '⌨️' },
27 | { command: '/vim', description: 'Enter vim mode for alternating insert and command modes', icon: '📝' },
28 | ];
29 |
30 | // Keep this for backward compatibility
31 | export const SLASH_COMMANDS = BUILT_IN_SLASH_COMMANDS;
32 |
33 | /**
34 | * Gets all available slash commands including custom ones
35 | * @returns All slash commands (built-in and custom)
36 | */
37 | export async function getAllSlashCommands(): Promise {
38 | await customCommandService.scanCustomCommands();
39 | const customCommands = customCommandService.getCustomCommands();
40 |
41 | // Combine built-in and custom commands
42 | return [...BUILT_IN_SLASH_COMMANDS, ...customCommands];
43 | }
44 |
45 | /**
46 | * Filter slash commands based on input
47 | * @param input The search input
48 | * @param commands The array of commands to filter (defaults to built-in commands)
49 | * @returns Filtered slash commands
50 | */
51 | export function filterSlashCommands(input: string, commands: SlashCommand[] = BUILT_IN_SLASH_COMMANDS): SlashCommand[] {
52 | const searchTerm = input.toLowerCase();
53 | return commands.filter(cmd =>
54 | cmd.command.toLowerCase().includes(searchTerm) ||
55 | cmd.description.toLowerCase().includes(searchTerm)
56 | );
57 | }
58 |
59 | /**
60 | * Gets a slash command by its exact name
61 | * @param command The command name to find
62 | * @param commands The array of commands to search (defaults to built-in commands)
63 | * @returns The found command or undefined
64 | */
65 | export function getSlashCommand(command: string, commands: SlashCommand[] = BUILT_IN_SLASH_COMMANDS): SlashCommand | undefined {
66 | return commands.find(cmd => cmd.command === command);
67 | }
--------------------------------------------------------------------------------
/.clinerules/vscode-extension-developer.md:
--------------------------------------------------------------------------------
1 | # Claude Code Developer Profile
2 |
3 | This module defines the technical skills and knowledge required for developing the Claude Code VSCode Extension. It can be used independently or in conjunction with other framework modules.
4 |
5 | ## Core Technical Skills
6 |
7 | 1. **JavaScript/TypeScript Proficiency**
8 | - Modern JavaScript (ES6+) features
9 | - TypeScript for type safety and organization
10 | - Asynchronous programming (Promises, async/await)
11 |
12 | 2. **Node.js Experience**
13 | - Node.js modules and APIs
14 | - `child_process` module for process management
15 | - Stream handling for stdin/stdout/stderr communication
16 | - Event-driven programming
17 |
18 | 3. **VSCode Extension Development**
19 | - VSCode Extension API
20 | - Extension lifecycle management
21 | - WebView API for custom UI components
22 | - VSCode workspace and editor APIs
23 |
24 | 4. **UI Development**
25 | - HTML/CSS for WebView UI construction
26 | - Responsive layouts
27 | - Accessibility best practices
28 | - Frontend frameworks (optional)
29 |
30 | ## Secondary Technical Skills
31 |
32 | 5. **Process Management**
33 | - Long-running child processes
34 | - Process lifecycle and signals
35 | - Inter-process communication techniques
36 | - Error handling and recovery strategies
37 |
38 | 6. **Authentication & Security**
39 | - OAuth implementation
40 | - Secure storage of credentials
41 | - Security best practices
42 |
43 | 7. **Cross-Platform Development**
44 | - Windows, macOS, and Linux compatibility
45 | - Platform-specific process management
46 | - Cross-platform path handling
47 |
48 | 8. **Testing Expertise**
49 | - Unit testing JavaScript/TypeScript code
50 | - Integration testing for VSCode extensions
51 | - Mocking external processes for testing
52 |
53 | ## Domain Knowledge
54 |
55 | 9. **CLI Tool Integration**
56 | - Command-line tool integration
57 | - Shell environments
58 | - Terminal input/output parsing
59 |
60 | 10. **AI/LLM Understanding**
61 | - AI assistants and capabilities
62 | - Prompt engineering concepts
63 | - Context management for AI conversations
64 |
65 | 11. **Developer Workflows**
66 | - Software development workflows
67 | - Version control systems (Git)
68 | - Common coding tasks and challenges
69 |
70 | ## Soft Skills & Approach
71 |
72 | 12. **Problem Solving**
73 | - Debugging complex integration issues
74 | - Enhancing user experience
75 |
76 | 13. **User Experience Design**
77 | - Developer ergonomics
78 | - UI/UX design attention to detail
79 | - Intuitive interface creation
80 |
81 | 14. **Documentation**
82 | - Technical documentation writing
83 | - User guide and tutorial creation
84 |
85 | ## Integration Points with Other Modules
86 |
87 | - **Memory Bank**: Technical knowledge to document in techContext.md
88 | - **Task Management**: Skills to consider when planning and estimating tasks
89 | - **TDD Methodology**: Testing expertise to apply during development
90 |
91 | ## Development Environment
92 |
93 | - VSCode Extension development environment
94 | - Node.js development tools
95 | - Claude Code installation and authentication
96 | - Cross-platform testing environments
97 |
98 | Use this module to identify required skills, assess team capabilities, or guide personal development for working on the Claude Code VSCode Extension.
--------------------------------------------------------------------------------
/docs/custom-slash-commands.md:
--------------------------------------------------------------------------------
1 | # Custom Slash Commands
2 |
3 | Claude Code VSCode Extension supports custom slash commands for quick access to frequently used prompts or operations.
4 |
5 | ## Types of Custom Commands
6 |
7 | ### Project Commands
8 |
9 | Project commands are specific to your project and accessible to anyone working with the project repository.
10 |
11 | - **Location**: `.claude/commands/` directory in your project
12 | - **Format**: Markdown files (`.md` extension)
13 | - **Usage**: `/project:command-name [arguments]`
14 |
15 | ### User Commands
16 |
17 | User commands are personal commands that work across all projects on your machine.
18 |
19 | - **Location**: `~/.claude/commands/` directory in your home folder
20 | - **Format**: Markdown files (`.md` extension)
21 | - **Usage**: `/user:command-name [arguments]`
22 |
23 | ## How It Works
24 |
25 | The VSCode extension provides **autocomplete suggestions** for your custom commands, making them easy to discover and use.
26 |
27 | When you type `/`, the extension scans for custom commands and displays them alongside built-in commands.
28 |
29 | When you select and execute a custom command, it's sent directly to Claude Code CLI which processes the command - the VSCode extension simply provides the suggestions.
30 |
31 | ## Creating Custom Commands
32 |
33 | 1. Create the appropriate directory:
34 | - Project commands: `mkdir -p .claude/commands` (in your project root)
35 | - User commands: `mkdir -p ~/.claude/commands` (in your home directory)
36 |
37 | 2. Create a Markdown file with your command content:
38 | - The filename (without extension) becomes the command name
39 | - The content of the file is the prompt that Claude Code CLI will read
40 | - Example: `.claude/commands/optimize.md` creates the command `/project:optimize`
41 |
42 | 3. For commands that accept arguments, use the `$ARGUMENTS` placeholder in your command content.
43 | - Example: If your command file contains `Find and fix issue #$ARGUMENTS`, calling `/project:fix-issue 123` will replace `$ARGUMENTS` with `123`
44 |
45 | ## Examples
46 |
47 | ### Project Command Example
48 |
49 | 1. Create a file `.claude/commands/optimize.md` with the content:
50 |
51 | ```markdown
52 | # Optimize Code
53 |
54 | Please optimize the following code for performance and readability:
55 |
56 | $ARGUMENTS
57 |
58 | Focus on:
59 | - Reducing time complexity
60 | - Improving memory usage
61 | - Making the code more readable
62 | - Adding appropriate comments
63 | ```
64 |
65 | 2. Use it in the Claude VSCode extension by typing `/project:optimize` followed by your code.
66 |
67 | ### User Command Example
68 |
69 | 1. Create a file `~/.claude/commands/ios-developer.md` with the content:
70 |
71 | ```markdown
72 | # iOS Developer Mode
73 |
74 | I want you to act as an experienced iOS developer with deep knowledge of Swift, UIKit, and SwiftUI. Please help me with the following:
75 |
76 | $ARGUMENTS
77 |
78 | Focus on Swift best practices and modern iOS development patterns.
79 | ```
80 |
81 | 2. Use it by typing `/user:ios-developer` followed by your question or code.
82 |
83 | ## Updating Commands
84 |
85 | The extension monitors your command directories and automatically refreshes the command list when you:
86 |
87 | 1. Create, modify, or delete command files in the `.claude/commands/` or `~/.claude/commands/` directories
88 | 2. Commands will be visible in the slash command autocomplete menu the next time you type `/`
89 |
90 | ## Tips
91 |
92 | - The first line of the command file can be used as a description (if it starts with `#`)
93 | - Commands can include any markdown formatting
94 | - User commands work across all projects, making them ideal for personal workflows
95 | - Project commands are great for standardizing prompts across your team
--------------------------------------------------------------------------------
/.clinerules/tdd.md:
--------------------------------------------------------------------------------
1 | # TDD Methodology Module
2 |
3 | This module implements a disciplined Test-Driven Development approach for software engineering. It can be used independently or integrated with other framework modules.
4 |
5 | ## Core Concept
6 |
7 | Test-Driven Development (TDD) is a development process that relies on the repetition of a very short development cycle. Requirements are turned into specific test cases, then the code is improved to pass the tests. This module ensures code quality, reduces defects, and creates inherently testable systems.
8 |
9 | ## TDD Core Principles
10 |
11 | 1. **Tests First**: Write tests before implementation code
12 | 2. **Minimal Implementation**: Write only enough code to pass tests
13 | 3. **Continuous Testing**: Run all tests after every change
14 | 4. **Refactor Safely**: Improve code while maintaining test coverage
15 | 5. **Small Increments**: Work in short, testable cycles
16 | 6. **Comprehensive Coverage**: Test all behaviors, edge cases, and error scenarios
17 |
18 | ## TDD Development Cycle
19 |
20 | ### Phase 1: Test Writing (Red)
21 | 1. Analyze requirements and acceptance criteria
22 | 2. Design tests for expected behaviors and edge cases
23 | 3. Write automated tests that will initially fail
24 | 4. Verify tests fail appropriately
25 | 5. Document test coverage expectations
26 | 6. **No implementation code during this phase**
27 |
28 | ### Phase 2: Implementation (Green)
29 | 1. Review failing tests to understand requirements
30 | 2. Write minimal code to make tests pass
31 | 3. Avoid implementing untested functionality
32 | 4. Run full test suite after each change
33 | 5. Return to implementation if tests fail
34 | 6. Proceed only when all tests pass
35 |
36 | ### Phase 3: Refactoring (Refactor)
37 | 1. Review code for quality and maintainability
38 | 2. Apply design patterns and best practices
39 | 3. Remove duplication and improve clarity
40 | 4. Run full test suite after each refactor
41 | 5. Revert changes if tests fail
42 | 6. Proceed only when all tests pass
43 |
44 | ### Phase 4: Cycle Completion
45 | 1. Verify all requirements are satisfied
46 | 2. Confirm all tests pass
47 | 3. Update documentation
48 | 4. Plan the next increment
49 | 5. Repeat the TDD cycle
50 |
51 | ## Quality Metrics
52 |
53 | Track and report the following metrics for each TDD cycle:
54 | - Test Coverage: Percentage of code covered by tests
55 | - Defect Rate: Number of defects per unit of code
56 | - Cycle Time: Duration of each TDD cycle
57 | - Maintainability Index: Code quality and readability measure
58 | - Regression Rate: Number of previously working features broken
59 |
60 | ## Integration with Other Modules
61 |
62 | - **Task Management**: TDD cycles integrated into task workflow
63 | - **Memory Bank**: Test strategies and metrics documented in memory files
64 | - **Developer Profile**: Testing expertise applied to implementation
65 |
66 | ## Usage Guidelines
67 |
68 | ### Independent Usage
69 | When used as a standalone module:
70 | - Follow the complete TDD cycle for all development
71 | - Track metrics independently
72 | - Maintain strict discipline in the test-first approach
73 |
74 | ### Integrated Usage
75 | When combined with other modules:
76 | - Incorporate TDD cycles into Task Management workflow
77 | - Document test strategies in Memory Bank
78 | - Apply testing expertise from Developer Profile
79 | - Ensure all tasks include appropriate test cases
80 |
81 | ## Enforcement Protocol
82 |
83 | To maintain TDD discipline:
84 | 1. Verify failing tests exist before writing implementation code
85 | 2. Confirm all tests pass before proceeding to next phase
86 | 3. Run the full test suite after every code change
87 | 4. When tests fail, immediately return to previous phase
88 | 5. Request assistance if unable to resolve test failures
89 |
90 | This TDD Methodology module ensures high-quality, well-tested code that meets requirements and resists regressions.
--------------------------------------------------------------------------------
/.clinerules/memory-bank.md:
--------------------------------------------------------------------------------
1 | # Memory Bank Module
2 |
3 | This module implements a comprehensive project memory system for maintaining context across development sessions. It can be used independently or integrated with other framework modules.
4 |
5 | ## Core Concept
6 |
7 | The Memory Bank is a structured documentation system that preserves project knowledge across sessions. It ensures consistent understanding of the project regardless of time between interactions.
8 |
9 | ## Memory Bank Structure
10 |
11 | The Memory Bank consists of core files and optional context files, all in Markdown format:
12 |
13 | ```
14 | flowchart TD
15 | PB[projectbrief.md] --> PC[productContext.md]
16 | PB --> SP[systemPatterns.md]
17 | PB --> TC[techContext.md]
18 |
19 | PC --> AC[activeContext.md]
20 | SP --> AC
21 | TC --> AC
22 |
23 | AC --> P[progress.md]
24 | ```
25 |
26 | ### Core Files
27 |
28 | 1. @.memory-bank/projectbrief.md
29 | - Foundation document that shapes all other files
30 | - Core requirements and project goals
31 | - Source of truth for project scope
32 |
33 | 2. @.memory-bank/productContext.md
34 | - Why this project exists
35 | - Problems it solves
36 | - How it should work
37 | - User experience goals
38 |
39 | 3. @.memory-bank/activeContext.md
40 | - Current work focus
41 | - Recent changes
42 | - Next steps
43 | - Active decisions and considerations
44 |
45 | 4. @.memory-bank/systemPatterns.md
46 | - System architecture
47 | - Key technical decisions
48 | - Design patterns in use
49 | - Component relationships
50 |
51 | 5. @.memory-bank/techContext.md
52 | - Technologies used
53 | - Development setup
54 | - Technical constraints
55 | - Dependencies
56 |
57 | 6. @.memory-bank/progress.md
58 | - What works
59 | - What's left to build
60 | - Current status
61 | - Known issues
62 |
63 | ### Additional Context Files
64 | Additional files can be created for specialized documentation:
65 | - Feature specifications
66 | - API documentation
67 | - Testing strategies
68 | - Deployment procedures
69 |
70 | ## Memory Update Protocol
71 |
72 | Update the Memory Bank when:
73 | 1. Completing significant tasks
74 | 2. Discovering new project patterns
75 | 3. Explicitly requested with "update memory bank"
76 | 4. Context needs clarification
77 |
78 | When updating:
79 | 1. Review all existing files
80 | 2. Document current state
81 | 3. Clarify next steps
82 | 4. Document insights and patterns
83 |
84 | ## Core Workflow
85 |
86 | 1. **Session Start**: Read ALL Memory Bank files
87 | 2. **Task Analysis**: Understand requirements in context
88 | 3. **Implementation**: Execute work methodically
89 | 4. **Documentation**: Update Memory Bank with new knowledge
90 |
91 | ## Integration with Other Modules
92 |
93 | - **Developer Profile**: Use technical skills from Developer module to maintain techContext.md
94 | - **Task Management**: Incorporate task tracking data into progress.md and activeContext.md
95 | - **TDD Methodology**: Document test strategies and coverage in testing-specific files
96 |
97 | ## Usage Guidelines
98 |
99 | ### Independent Usage
100 | When used as a standalone module:
101 | - Create and maintain all core Memory Bank files
102 | - Follow the update protocol after significant work
103 | - Document all aspects of the project comprehensively
104 |
105 | ### Integrated Usage
106 | When combined with other modules:
107 | - Task Management data flows into activeContext.md and progress.md
108 | - TDD metrics and strategies are documented in testing files
109 | - Technical skills from Developer Profile inform techContext.md
110 |
111 | ## File Content Guidelines
112 | - Keep each file focused on its specific domain
113 | - Update related files together to maintain consistency
114 | - Place information in the most appropriate context file
115 | - Document decisions along with their rationale
116 |
117 | This Memory Bank module ensures knowledge persistence and consistent understanding regardless of time between development sessions.
--------------------------------------------------------------------------------
/test/ui/test-drag-drop.html:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 | Drag and Drop Test
5 |
41 |
42 |
43 |
Drag and Drop File Test
44 |
45 |
Drag and drop files or folders here
46 |
47 |
48 |
49 |
121 |
122 |
--------------------------------------------------------------------------------
/docs/claude-cli-usage.md:
--------------------------------------------------------------------------------
1 | # Claude CLI Usage Guide
2 |
3 | This document provides information about using the Claude CLI, specifically focusing on print mode which will be utilized in our VSCode extension.
4 |
5 | ## Print Mode Overview
6 |
7 | Print mode enables non-interactive, programmatic usage of Claude Code. Instead of starting an interactive session, Claude will process the input and return the response directly, making it ideal for integration with other applications like our VSCode extension.
8 |
9 | ### Basic Usage
10 |
11 | Print mode is enabled with the `-p` or `--print` flag:
12 |
13 | ```bash
14 | claude -p "What is the capital of France?"
15 | ```
16 |
17 | You can also pipe input through stdin:
18 |
19 | ```bash
20 | echo "What is the capital of France?" | claude -p
21 | ```
22 |
23 | ### Output Formats
24 |
25 | Claude CLI's print mode supports different output formats:
26 |
27 | 1. **Text (default)**: Returns only the response text
28 | ```bash
29 | claude -p "Explain recursion"
30 | ```
31 |
32 | 2. **JSON**: Returns structured data including cost, duration, session ID, and response
33 | ```bash
34 | claude -p --output-format json "Explain recursion"
35 | ```
36 |
37 | 3. **Streaming JSON**: Returns separate JSON objects for each step
38 | ```bash
39 | claude -p --output-format streaming-json "Explain recursion"
40 | ```
41 |
42 | ### Additional Options
43 |
44 | Print mode can be combined with other Claude CLI options:
45 |
46 | - `--max-turns`: Limit the number of agentic turns
47 | ```bash
48 | claude -p --max-turns 3 "Solve this problem step by step"
49 | ```
50 |
51 | - `--verbose`: Enable detailed logging
52 | ```bash
53 | claude -p --verbose "Debug this code"
54 | ```
55 |
56 | - `--permission-prompt-tool`: Control permission handling
57 | ```bash
58 | claude -p --permission-prompt-tool never "Execute this command"
59 | ```
60 |
61 | - `--resume`: Continue a specific session
62 | ```bash
63 | claude -p --resume session_id "Continue from previous point"
64 | ```
65 |
66 | ## Integration Pattern for VSCode Extension
67 |
68 | For our VSCode extension, we'll use the following pattern:
69 |
70 | 1. Spawn a Claude CLI process with print mode and JSON output format
71 | 2. Send the user's query as input
72 | 3. Capture and parse the JSON response
73 | 4. Display the response in the extension UI
74 |
75 | Example implementation pattern:
76 |
77 | ```typescript
78 | import { spawn } from 'child_process';
79 |
80 | function executeClaudeCommand(query: string): Promise {
81 | return new Promise((resolve, reject) => {
82 | const claudeProcess = spawn('claude', ['-p', '--output-format', 'json']);
83 | let output = '';
84 |
85 | claudeProcess.stdout.on('data', (data) => {
86 | output += data.toString();
87 | });
88 |
89 | claudeProcess.stderr.on('data', (data) => {
90 | console.error(`Claude CLI error: ${data}`);
91 | });
92 |
93 | claudeProcess.on('close', (code) => {
94 | if (code === 0) {
95 | try {
96 | const result = JSON.parse(output);
97 | resolve(result);
98 | } catch (error) {
99 | reject(new Error(`Failed to parse Claude output: ${error}`));
100 | }
101 | } else {
102 | reject(new Error(`Claude process exited with code ${code}`));
103 | }
104 | });
105 |
106 | claudeProcess.stdin.write(query);
107 | claudeProcess.stdin.end();
108 | });
109 | }
110 | ```
111 |
112 | ## Benefits of Print Mode for VSCode Extension
113 |
114 | 1. **Simplicity**: No need to maintain an interactive session
115 | 2. **Reliability**: Each request is independent, reducing state management complexity
116 | 3. **Structured data**: JSON output provides clear structure for parsing
117 | 4. **Error handling**: Better isolation of failures
118 | 5. **Resource efficiency**: Processes terminate after completion
119 |
120 | ## Limitations
121 |
122 | 1. No persistent context between requests unless using the `--resume` flag
123 | 2. Each request spawns a new process, which may have performance implications
124 | 3. Authentication needs to be handled for each request
125 |
126 | ## Best Practices
127 |
128 | 1. Use JSON output format for predictable parsing
129 | 2. Include error handling for process failures
130 | 3. Consider implementing a lightweight caching mechanism for recent responses
131 | 4. Monitor process resource usage
132 | 5. Provide clear feedback to users during processing
133 |
134 | ---
135 |
136 | For more detailed information, refer to the [official Claude Code documentation](https://docs.anthropic.com/en/docs/claude-code/cli-usage).
--------------------------------------------------------------------------------
/.clinerules/taskmaster-ai.md:
--------------------------------------------------------------------------------
1 | # Task Management Module
2 |
3 | This module implements a task management system for complex software development workflows. It can be used independently or integrated with other framework modules.
4 |
5 | ## Core Purpose
6 |
7 | The Task Management module breaks down complex projects into manageable tasks, organizes workflows efficiently, and maintains focus throughout the development process. It excels at:
8 | - Decomposing problems into actionable steps
9 | - Managing dependencies and priorities
10 | - Preventing context overload
11 | - Tracking progress dynamically
12 | - Maintaining focus on current objectives
13 |
14 | ## Task Management Principles
15 |
16 | 1. **Task Sizing**: Limit tasks to 2 working hours or 200 lines of code
17 | 2. **Single Responsibility**: Each task focuses on one specific objective
18 | 3. **Dependency Management**: Track prerequisites between tasks
19 | 4. **Progressive Refinement**: Subdivide tasks when they prove too complex
20 | 5. **Focused Execution**: Work on one task at a time
21 | 6. **Comprehensive Documentation**: Record decisions and insights
22 |
23 | ## Development Workflow
24 |
25 | ### Phase 1: Project Understanding
26 | 1. Review requirements and documentation
27 | 2. Examine project structure
28 | 3. Identify objectives and constraints
29 | 4. Document assumptions
30 | 5. Establish baseline understanding (0-100%)
31 |
32 | ### Phase 2: Task Decomposition
33 | 1. Break down the project into components/features
34 | 2. For each component:
35 | - Identify functionality
36 | - Map dependencies
37 | - Estimate complexity
38 | - Size appropriately (≤2h, ≤200 LOC)
39 | 3. Create task breakdown document
40 | 4. Update understanding confidence
41 |
42 | ### Phase 3: Workflow Planning
43 | 1. Sequence tasks based on:
44 | - Dependencies
45 | - Technical requirements
46 | - Implementation efficiency
47 | 2. Design for minimal context switching
48 | 3. Establish validation checkpoints
49 | 4. Identify potential bottlenecks
50 | 5. Document workflow sequence
51 |
52 | ### Phase 4: Task Execution
53 | 1. Start with highest priority task
54 | 2. Define implementation steps and acceptance criteria
55 | 3. Complete task with focused attention
56 | 4. After completion:
57 | - Mark as completed
58 | - Adjust remaining tasks if needed
59 | - Subdivide upcoming tasks if necessary
60 | 5. Select next task based on priorities and dependencies
61 |
62 | ### Phase 5: Progress Tracking
63 | 1. Update task list regularly
64 | 2. Reorganize when requirements change
65 | 3. Document decisions and insights
66 | 4. Maintain focus while considering the big picture
67 |
68 | ## Task List Format
69 |
70 | ```markdown
71 | # Project Task List
72 |
73 | ## Project Overview
74 | Brief description of the project, objectives, and constraints
75 |
76 | ## Progress Summary
77 | - Started: [Date]
78 | - Current Phase: [Phase Name]
79 | - Completed Tasks: [X/Y]
80 | - Current Focus: [Current Task]
81 |
82 | ## Task Breakdown
83 |
84 | ### [Component/Feature 1]
85 | - [ ] Task 1.1: Description
86 | - Subtask 1.1.1: Description
87 | - Subtask 1.1.2: Description
88 | - [X] Task 1.2: Description (Completed on [Date])
89 | - Notes: [Any insights or decisions]
90 |
91 | ### [Component/Feature 2]
92 | - [ ] Task 2.1: Description (Blocked by: Task 1.1)
93 | - [ ] Task 2.2: Description
94 | - Priority: High
95 | - Notes: [Important considerations]
96 |
97 | ## Next Steps
98 | 1. Complete [Current Task]
99 | 2. Proceed to [Next Task]
100 | 3. Review [Related Component]
101 |
102 | ## Issues and Considerations
103 | - [Any discovered challenges or questions]
104 | - [Potential risks identified]
105 | ```
106 |
107 | ## Integration with Other Modules
108 |
109 | - **Memory Bank**: Task information feeds into activeContext.md and progress.md
110 | - **Developer Profile**: Technical skills inform task complexity estimation
111 | - **TDD Methodology**: Testing tasks are integrated into the task workflow
112 |
113 | ## Usage Guidelines
114 |
115 | ### Independent Usage
116 | When used as a standalone module:
117 | - Create and maintain a separate task list document
118 | - Follow the complete five-phase process
119 | - Track all task-related information within the task list
120 |
121 | ### Integrated Usage
122 | When combined with other modules:
123 | - Coordinate task tracking with Memory Bank updates
124 | - Incorporate TDD cycles into task execution
125 | - Apply Developer Profile skills to task estimation
126 |
127 | ## Communication Format
128 | When reporting on tasks, structure responses in this order:
129 | 1. Current task focus
130 | 2. Progress update
131 | 3. Challenges or insights
132 | 4. Next steps
133 | 5. Updated task list (when significant changes occur)
134 |
135 | This Task Management module ensures focused, efficient progress on complex software development projects.
--------------------------------------------------------------------------------
/TROUBLESHOOTING.md:
--------------------------------------------------------------------------------
1 | # Claude Code Extension Troubleshooting Guide
2 |
3 | ## Service Worker Registration Error
4 |
5 | If you're seeing this error:
6 | ```
7 | Error loading webview: Error: Could not register service worker: InvalidStateError: Failed to register a ServiceWorker: The document is in an invalid state.
8 | ```
9 |
10 | **Don't worry!** This is a known VSCode issue, not a problem with the Claude Code extension itself.
11 |
12 | ## Quick Fix (Works 95% of the time)
13 |
14 | ### Option 1: Reinstall VSCode (Recommended - Easiest)
15 |
16 | **This is the most reliable solution:**
17 |
18 | 1. **Uninstall VSCode**
19 | - macOS: Move VSCode from Applications to Trash
20 | - Windows: Use "Add or Remove Programs"
21 | - Linux: Use your package manager (`sudo apt remove code`)
22 |
23 | 2. **Download fresh VSCode**
24 | - Go to [code.visualstudio.com](https://code.visualstudio.com)
25 | - Download and install the latest version
26 |
27 | 3. **Restore your setup**
28 | - Your extensions will sync automatically if you use Settings Sync
29 | - Otherwise, reinstall your extensions
30 |
31 | ✅ **The error should be completely resolved!**
32 |
33 | ### Option 2: Manual Cache Clearing
34 |
35 | If you prefer not to reinstall:
36 |
37 | 1. **Close VSCode completely**
38 | - Close all VSCode windows
39 | - Make sure no VSCode processes are running
40 |
41 | 2. **Clear VSCode cache**
42 | **On macOS:**
43 | ```bash
44 | rm -rf "$HOME/Library/Application Support/Code/Service Worker"
45 | ```
46 |
47 | **On Linux:**
48 | ```bash
49 | rm -rf "$HOME/.config/Code/Service Worker"
50 | ```
51 |
52 | **On Windows (PowerShell):**
53 | ```powershell
54 | Remove-Item "$env:APPDATA\Code\Service Worker" -Recurse -Force
55 | ```
56 |
57 | 3. **Restart VSCode**
58 | Open VSCode normally - the error should be resolved.
59 |
60 | ## Alternative Solutions
61 |
62 | If the quick fix doesn't work, try these in order:
63 |
64 | ### Option 1: Use --no-sandbox flag
65 | ```bash
66 | code --no-sandbox
67 | ```
68 |
69 | ### Option 2: Clear all VSCode cache
70 | **On macOS:**
71 | ```bash
72 | rm -rf "$HOME/Library/Application Support/Code/Cache"
73 | rm -rf "$HOME/Library/Application Support/Code/Service Worker"
74 | ```
75 |
76 | **On Linux:**
77 | ```bash
78 | rm -rf "$HOME/.config/Code/Cache"
79 | rm -rf "$HOME/.config/Code/Service Worker"
80 | ```
81 |
82 | **On Windows:**
83 | ```powershell
84 | Remove-Item "$env:APPDATA\Code\Cache" -Recurse -Force
85 | Remove-Item "$env:APPDATA\Code\Service Worker" -Recurse -Force
86 | ```
87 |
88 | ### Option 3: Reload VSCode window
89 | 1. Open Command Palette (`Cmd+Shift+P` or `Ctrl+Shift+P`)
90 | 2. Type and select "Developer: Reload Window"
91 |
92 | ### Option 4: Kill all VSCode processes
93 | **On macOS/Linux:**
94 | ```bash
95 | killall code
96 | ```
97 |
98 | **On Windows:**
99 | - Open Task Manager
100 | - Find all "Visual Studio Code" processes
101 | - End each task
102 | - Restart VSCode
103 |
104 | ## Why This Happens
105 |
106 | This error occurs due to a VSCode internal issue where:
107 | 1. VSCode automatically tries to register service workers for webview content
108 | 2. Sometimes the document gets into an "invalid state" during this process
109 | 3. Corrupted cache files can cause persistent problems
110 |
111 | **This affects many extensions with webviews, not just Claude Code.**
112 |
113 | ## Prevention
114 |
115 | To reduce the likelihood of this error:
116 |
117 | 1. **Update VSCode regularly** - newer versions have fixes for some cases
118 | 2. **Clear cache occasionally** - run the cache clearing command monthly
119 | 3. **Close VSCode properly** - don't force-quit or kill the process unless necessary
120 |
121 | ## Still Having Issues?
122 |
123 | If none of these solutions work:
124 |
125 | 1. **Check your VSCode version**: Some versions (1.82.2, 1.100.3) are more prone to this issue
126 | 2. **Try a different workspace**: Open VSCode in a different folder to test
127 | 3. **Report to VSCode team**: This is ultimately a VSCode platform issue
128 | 4. **Contact us**: Open an issue at [github.com/codeflow-studio/claude-code-chat/issues](https://github.com/codeflow-studio/claude-code-chat/issues)
129 |
130 | ## Technical Details
131 |
132 | For developers and advanced users:
133 |
134 | - The error originates from VSCode's webview service worker registration system
135 | - The Claude Code extension doesn't contain any service worker code
136 | - The issue is related to document state timing and cache corruption
137 | - Content Security Policy restrictions may contribute to the problem
138 |
139 | ## Related Issues
140 |
141 | This same error has been reported for:
142 | - Julia VSCode extension
143 | - Jupyter notebooks
144 | - Sourcegraph extension
145 | - Postman extension
146 | - Many other webview-based extensions
147 |
148 | You're not alone - this is a widespread VSCode platform issue!
--------------------------------------------------------------------------------
/src/ui/components/SlashCommandSuggestions.ts:
--------------------------------------------------------------------------------
1 | import { SlashCommand, BUILT_IN_SLASH_COMMANDS, filterSlashCommands } from '../../utils/slash-commands';
2 |
3 | export class SlashCommandSuggestions {
4 | private container: HTMLDivElement;
5 | private commands: SlashCommand[] = [];
6 | private allCommands: SlashCommand[] = [...BUILT_IN_SLASH_COMMANDS];
7 | private customCommandsLoaded: boolean = false;
8 | private selectedIndex: number = -1;
9 | private onSelectCallback?: (command: string) => void;
10 | private onDismissCallback?: () => void;
11 |
12 | constructor() {
13 | this.container = document.createElement('div');
14 | this.container.className = 'slash-command-suggestions';
15 | this.container.style.display = 'none';
16 | this.hide();
17 | }
18 |
19 | public getElement(): HTMLDivElement {
20 | return this.container;
21 | }
22 |
23 | public show(
24 | inputElement: HTMLElement,
25 | searchTerm: string = '',
26 | onSelect?: (command: string) => void,
27 | onDismiss?: () => void
28 | ) {
29 | this.onSelectCallback = onSelect;
30 | this.onDismissCallback = onDismiss;
31 |
32 | // Filter commands based on search term
33 | this.commands = searchTerm ? filterSlashCommands(searchTerm, this.allCommands) : this.allCommands;
34 |
35 | if (this.commands.length === 0) {
36 | this.hide();
37 | return;
38 | }
39 |
40 | this.selectedIndex = 0;
41 | this.render();
42 | this.position(inputElement);
43 | this.container.style.display = 'block';
44 | }
45 |
46 | public hide() {
47 | this.container.style.display = 'none';
48 | this.selectedIndex = -1;
49 | this.commands = [];
50 | if (this.onDismissCallback) {
51 | this.onDismissCallback();
52 | }
53 | }
54 |
55 | public isVisible(): boolean {
56 | return this.container.style.display !== 'none';
57 | }
58 |
59 | public handleKeyDown(event: KeyboardEvent): boolean {
60 | if (!this.isVisible()) return false;
61 |
62 | switch (event.key) {
63 | case 'ArrowDown':
64 | event.preventDefault();
65 | this.selectNext();
66 | return true;
67 | case 'ArrowUp':
68 | event.preventDefault();
69 | this.selectPrevious();
70 | return true;
71 | case 'Enter':
72 | event.preventDefault();
73 | this.selectCurrent();
74 | return true;
75 | case 'Tab':
76 | event.preventDefault();
77 | this.selectCurrent();
78 | return true;
79 | case 'Escape':
80 | event.preventDefault();
81 | this.hide();
82 | return true;
83 | default:
84 | return false;
85 | }
86 | }
87 |
88 | private selectNext() {
89 | this.selectedIndex = (this.selectedIndex + 1) % this.commands.length;
90 | this.render();
91 | }
92 |
93 | private selectPrevious() {
94 | this.selectedIndex = this.selectedIndex - 1;
95 | if (this.selectedIndex < 0) {
96 | this.selectedIndex = this.commands.length - 1;
97 | }
98 | this.render();
99 | }
100 |
101 | private selectCurrent() {
102 | if (this.selectedIndex >= 0 && this.selectedIndex < this.commands.length) {
103 | const command = this.commands[this.selectedIndex];
104 | if (this.onSelectCallback) {
105 | this.onSelectCallback(command.command);
106 | }
107 | this.hide();
108 | }
109 | }
110 |
111 | private render() {
112 | this.container.innerHTML = '';
113 |
114 | this.commands.forEach((command, index) => {
115 | const item = document.createElement('div');
116 | item.className = 'slash-command-item';
117 | if (index === this.selectedIndex) {
118 | item.classList.add('selected');
119 | }
120 |
121 | const icon = document.createElement('span');
122 | icon.className = 'slash-command-icon';
123 | icon.textContent = command.icon || '/';
124 |
125 | const content = document.createElement('div');
126 | content.className = 'slash-command-content';
127 |
128 | const commandName = document.createElement('div');
129 | commandName.className = 'slash-command-name';
130 | commandName.textContent = command.command;
131 |
132 | const description = document.createElement('div');
133 | description.className = 'slash-command-description';
134 | description.textContent = command.description;
135 |
136 | content.appendChild(commandName);
137 | content.appendChild(description);
138 |
139 | item.appendChild(icon);
140 | item.appendChild(content);
141 |
142 | item.addEventListener('click', () => {
143 | this.selectedIndex = index;
144 | this.selectCurrent();
145 | });
146 |
147 | item.addEventListener('mouseenter', () => {
148 | this.selectedIndex = index;
149 | this.render();
150 | });
151 |
152 | this.container.appendChild(item);
153 | });
154 | }
155 |
156 | private position(targetElement: HTMLElement) {
157 | const containerRect = targetElement.closest('.input-container')?.getBoundingClientRect();
158 |
159 | if (containerRect) {
160 | this.container.style.position = 'absolute';
161 | this.container.style.bottom = `${containerRect.height}px`;
162 | this.container.style.left = '0';
163 | this.container.style.right = '0';
164 | this.container.style.maxHeight = '300px';
165 | }
166 | }
167 |
168 | /**
169 | * Update the list of custom commands
170 | * @param customCommands Array of custom slash commands
171 | */
172 | public updateCustomCommands(customCommands: SlashCommand[]): void {
173 | // Start with built-in commands
174 | this.allCommands = [...BUILT_IN_SLASH_COMMANDS];
175 |
176 | // Add custom commands
177 | if (customCommands && customCommands.length > 0) {
178 | this.allCommands = [...this.allCommands, ...customCommands];
179 | }
180 |
181 | this.customCommandsLoaded = true;
182 | }
183 | }
--------------------------------------------------------------------------------
/package.json:
--------------------------------------------------------------------------------
1 | {
2 | "name": "claude-code-extension",
3 | "displayName": "Claude Code Assistant for VSCode",
4 | "description": "Unofficial integration of Anthropic's Claude Code AI assistant into VSCode",
5 | "version": "0.1.10",
6 | "publisher": "codeflow-studio",
7 | "icon": "resources/claude-icon.png",
8 | "repository": {
9 | "type": "git",
10 | "url": "https://github.com/codeflow-studio/claude-code-chat"
11 | },
12 | "bugs": {
13 | "url": "https://github.com/codeflow-studio/claude-code-chat/issues"
14 | },
15 | "homepage": "https://github.com/codeflow-studio/claude-code-chat#readme",
16 | "license": "MIT",
17 | "keywords": [
18 | "ai",
19 | "claude",
20 | "code assistant",
21 | "anthropic",
22 | "coding",
23 | "artificial intelligence",
24 | "unofficial",
25 | "codeflow"
26 | ],
27 | "galleryBanner": {
28 | "color": "#1E1E1E",
29 | "theme": "dark"
30 | },
31 | "engines": {
32 | "vscode": "^1.90.0"
33 | },
34 | "categories": [
35 | "Other"
36 | ],
37 | "main": "./dist/extension.js",
38 | "contributes": {
39 | "commands": [
40 | {
41 | "command": "claude-code-extension.launchClaudeCodeTerminal",
42 | "title": "Claude Code: Launch Terminal",
43 | "icon": "resources/claude-icon.svg"
44 | },
45 | {
46 | "command": "claude-code-extension.restartClaudeCode",
47 | "title": "Claude Code: Restart and Continue Last Session",
48 | "icon": {
49 | "light": "resources/restart-light.svg",
50 | "dark": "resources/restart-dark.svg"
51 | }
52 | },
53 | {
54 | "command": "claude-code-extension.addSelectionToInput",
55 | "title": "Add to Claude Code Input"
56 | },
57 | {
58 | "command": "claude-code-extension.toggleMode",
59 | "title": "Claude Code: Toggle Mode (Shift+Tab)"
60 | },
61 | {
62 | "command": "claude-code-extension.focusInput",
63 | "title": "Focus on Claude Code Input"
64 | },
65 | {
66 | "command": "claude-code-extension.explainFile",
67 | "title": "Explain with Claude Code"
68 | },
69 | {
70 | "command": "claude-code-extension.explainFolder",
71 | "title": "Explain Folder with Claude Code"
72 | },
73 | {
74 | "command": "claude-code-extension.explainSelection",
75 | "title": "Explain Selection with Claude Code"
76 | },
77 | {
78 | "command": "claude-code-extension.explainCurrentFile",
79 | "title": "Explain File with Claude Code"
80 | }
81 | ],
82 | "viewsContainers": {
83 | "activitybar": [
84 | {
85 | "id": "claude-code-sidebar",
86 | "title": "Claude Code",
87 | "icon": "resources/claude-icon.svg"
88 | }
89 | ]
90 | },
91 | "views": {
92 | "claude-code-sidebar": [
93 | {
94 | "type": "webview",
95 | "id": "claudeCodeInputView",
96 | "name": "Terminal Input",
97 | "contextualTitle": "Claude Terminal Input"
98 | }
99 | ]
100 | },
101 | "menus": {
102 | "view/title": [
103 | {
104 | "command": "claude-code-extension.launchClaudeCodeTerminal",
105 | "group": "navigation",
106 | "when": "view == claudeCodeInputView"
107 | },
108 | {
109 | "command": "claude-code-extension.restartClaudeCode",
110 | "group": "navigation",
111 | "when": "view == claudeCodeInputView"
112 | }
113 | ],
114 | "editor/context": [
115 | {
116 | "command": "claude-code-extension.addSelectionToInput",
117 | "when": "editorHasSelection",
118 | "group": "claude@1"
119 | },
120 | {
121 | "command": "claude-code-extension.explainSelection",
122 | "when": "editorHasSelection",
123 | "group": "claude@2"
124 | },
125 | {
126 | "command": "claude-code-extension.explainCurrentFile",
127 | "when": "!editorHasSelection",
128 | "group": "claude@1"
129 | }
130 | ],
131 | "explorer/context": [
132 | {
133 | "command": "claude-code-extension.explainFile",
134 | "when": "!explorerResourceIsFolder",
135 | "group": "claude@1"
136 | },
137 | {
138 | "command": "claude-code-extension.explainFolder",
139 | "when": "explorerResourceIsFolder",
140 | "group": "claude@1"
141 | }
142 | ]
143 | },
144 | "configuration": {
145 | "title": "Claude Code",
146 | "properties": {
147 | "claude-code-extension.autoStartOnActivation": {
148 | "type": "boolean",
149 | "default": true,
150 | "description": "Automatically start Claude Code when the extension is activated"
151 | },
152 | "claude-code-extension.autoStartCommand": {
153 | "type": "string",
154 | "enum": [
155 | "claude",
156 | "claude -c",
157 | "claude -r",
158 | "claude --dangerously-skip-permissions"
159 | ],
160 | "default": "claude",
161 | "description": "Command to use when auto-starting Claude Code"
162 | }
163 | }
164 | }
165 | },
166 | "scripts": {
167 | "vscode:prepublish": "npm run package",
168 | "compile": "webpack",
169 | "watch": "webpack --watch",
170 | "package": "webpack --mode production --devtool hidden-source-map",
171 | "lint": "eslint src --ext ts",
172 | "test": "node ./out/test/runTest.js",
173 | "build": "npm run package && npm run vsix",
174 | "vsix": "vsce package"
175 | },
176 | "devDependencies": {
177 | "@types/node": "^22.15.18",
178 | "@types/vscode": "^1.90.0",
179 | "@typescript-eslint/eslint-plugin": "^6.9.0",
180 | "@typescript-eslint/parser": "^6.9.0",
181 | "@vscode/test-electron": "^2.5.2",
182 | "@vscode/vsce": "^2.24.0",
183 | "css-loader": "^6.8.1",
184 | "eslint": "^8.52.0",
185 | "generator-code": "^1.11.9",
186 | "style-loader": "^3.3.3",
187 | "ts-loader": "^9.5.0",
188 | "typescript": "^5.8.3",
189 | "webpack": "^5.89.0",
190 | "webpack-cli": "^5.1.4",
191 | "yo": "^5.1.0"
192 | }
193 | }
194 |
--------------------------------------------------------------------------------
/src/service/imageManager.ts:
--------------------------------------------------------------------------------
1 | import * as vscode from "vscode";
2 | import * as fs from "fs";
3 | import * as path from "path";
4 | import * as os from "os";
5 |
6 | export interface ImageInfo {
7 | originalName: string;
8 | tempPath: string;
9 | size: number;
10 | type: string;
11 | timestamp: number;
12 | }
13 |
14 | export class ImageManager {
15 | private tempDir: string;
16 | private sessionId: string;
17 | private imagePaths: Map = new Map();
18 | private maxImageSize = 10 * 1024 * 1024; // 10MB
19 | private allowedTypes = [
20 | "image/jpeg",
21 | "image/png",
22 | "image/gif",
23 | "image/webp",
24 | "image/svg+xml",
25 | ];
26 |
27 | constructor(private context: vscode.ExtensionContext) {
28 | this.sessionId = Date.now().toString();
29 | this.tempDir = path.join(
30 | os.tmpdir(),
31 | "claude-code-extension",
32 | this.sessionId
33 | );
34 | this.ensureDirectoryExists();
35 |
36 | // Schedule periodic cleanup
37 | const cleanupInterval = setInterval(() => {
38 | this.cleanupOldImages();
39 | }, 60 * 60 * 1000); // Every hour
40 |
41 | // Ensure cleanup on deactivation
42 | context.subscriptions.push({
43 | dispose: () => {
44 | clearInterval(cleanupInterval);
45 | this.cleanupAllImages();
46 | },
47 | });
48 | }
49 |
50 | private ensureDirectoryExists(): void {
51 | if (!fs.existsSync(this.tempDir)) {
52 | fs.mkdirSync(this.tempDir, { recursive: true });
53 | }
54 | }
55 |
56 | async saveImage(
57 | base64Data: string,
58 | fileName: string,
59 | mimeType: string
60 | ): Promise {
61 | // Validate image
62 | this.validateImage(fileName, mimeType, base64Data);
63 |
64 | // Extract base64 content
65 | const base64Content = base64Data.split(",")[1] || base64Data;
66 | const buffer = Buffer.from(base64Content, "base64");
67 |
68 | // Create unique filename
69 | const timestamp = Date.now();
70 | const safeName = this.sanitizeFileName(fileName);
71 | const uniqueName = `${timestamp}-${safeName}`;
72 | const filePath = path.join(this.tempDir, uniqueName);
73 |
74 | // Write to temp file
75 | await fs.promises.writeFile(filePath, buffer);
76 |
77 | // Verify the file was written correctly
78 | try {
79 | const stats = await fs.promises.stat(filePath);
80 | if (stats.size === 0) {
81 | // File was created but is empty
82 | await fs.promises.unlink(filePath);
83 | throw new Error("File was created but is empty");
84 | }
85 |
86 | // Verify the file is readable
87 | await fs.promises.access(filePath, fs.constants.R_OK);
88 | } catch (verifyError) {
89 | // Clean up the failed file
90 | try {
91 | await fs.promises.unlink(filePath);
92 | } catch (cleanupError) {
93 | console.error("Failed to clean up invalid file:", cleanupError);
94 | }
95 | throw new Error(`Failed to verify saved image: ${verifyError}`);
96 | }
97 |
98 | // Store image info only after verification
99 | const imageInfo: ImageInfo = {
100 | originalName: fileName,
101 | tempPath: filePath,
102 | size: buffer.length,
103 | type: mimeType,
104 | timestamp: timestamp,
105 | };
106 |
107 | this.imagePaths.set(filePath, imageInfo);
108 |
109 | return filePath;
110 | }
111 |
112 | private validateImage(
113 | fileName: string,
114 | mimeType: string,
115 | base64Data: string
116 | ): void {
117 | // Check file type
118 | if (!this.allowedTypes.includes(mimeType)) {
119 | throw new Error(
120 | `Invalid file type: ${mimeType}. Allowed types: ${this.allowedTypes.join(
121 | ", "
122 | )}`
123 | );
124 | }
125 |
126 | // Check file size
127 | const sizeInBytes = (base64Data.length * 3) / 4;
128 | if (sizeInBytes > this.maxImageSize) {
129 | const sizeMB = (sizeInBytes / (1024 * 1024)).toFixed(1);
130 | throw new Error(`Image too large: ${sizeMB}MB. Maximum size: 10MB`);
131 | }
132 |
133 | // Check filename
134 | if (!fileName || fileName.trim().length === 0) {
135 | throw new Error("Invalid filename");
136 | }
137 | }
138 |
139 | private sanitizeFileName(fileName: string): string {
140 | const baseName = path.basename(fileName);
141 | // Replace problematic characters while preserving file extension
142 | const nameParts = baseName.split(".");
143 | const extension = nameParts.length > 1 ? "." + nameParts.pop() : "";
144 | const name = nameParts.join(".");
145 | const safeName = name.replace(/[^a-zA-Z0-9.-]/g, "_");
146 | return safeName + extension;
147 | }
148 |
149 | getImageInfo(filePath: string): ImageInfo | undefined {
150 | return this.imagePaths.get(filePath);
151 | }
152 |
153 | getAllImages(): ImageInfo[] {
154 | return Array.from(this.imagePaths.values());
155 | }
156 |
157 | async removeImage(filePath: string): Promise {
158 | try {
159 | if (fs.existsSync(filePath)) {
160 | await fs.promises.unlink(filePath);
161 | }
162 | this.imagePaths.delete(filePath);
163 | } catch (error) {
164 | console.error("Error removing image:", error);
165 | }
166 | }
167 |
168 | async cleanupOldImages(): Promise {
169 | const now = Date.now();
170 | const maxAge = 24 * 60 * 60 * 1000; // 24 hours
171 |
172 | for (const [path, info] of this.imagePaths.entries()) {
173 | if (now - info.timestamp > maxAge) {
174 | await this.removeImage(path);
175 | }
176 | }
177 | }
178 |
179 | async cleanupAllImages(): Promise {
180 | for (const path of this.imagePaths.keys()) {
181 | await this.removeImage(path);
182 | }
183 |
184 | // Try to remove the session directory
185 | try {
186 | if (fs.existsSync(this.tempDir)) {
187 | await fs.promises.rmdir(this.tempDir);
188 | }
189 | } catch (error) {
190 | // Directory might not be empty or might be in use
191 | console.error("Error removing temp directory:", error);
192 | }
193 | }
194 |
195 | formatImageReferences(imagePaths: string[]): string {
196 | if (imagePaths.length === 0) return "";
197 |
198 | let instructions = "\n\n";
199 | const imageCount = imagePaths.length;
200 | if (imageCount === 1) {
201 | instructions += `Attached Image => @${imagePaths[0]}`;
202 | } else {
203 | const imageList = imagePaths
204 | .map((path, index) => `Attached Image ${index + 1} => @${path}`)
205 | .join("\n");
206 | instructions += imageList;
207 | }
208 | instructions += "\n\n";
209 | return instructions;
210 | }
211 | }
212 |
--------------------------------------------------------------------------------
/src/service/customCommandService.ts:
--------------------------------------------------------------------------------
1 | import * as vscode from 'vscode';
2 | import * as fs from 'fs';
3 | import * as path from 'path';
4 | import { SlashCommand } from '../utils/slash-commands';
5 |
6 | export interface CustomCommand {
7 | name: string; // Command name without prefix
8 | file: string; // Path to the command file
9 | type: 'project' | 'user'; // Whether this is a project or user command
10 | description?: string; // Optional description (first line of the file)
11 | }
12 |
13 | export class CustomCommandService {
14 | private projectCommands: CustomCommand[] = [];
15 | private userCommands: CustomCommand[] = [];
16 |
17 | constructor() {}
18 |
19 | /**
20 | * Scans for custom slash commands in both project and user directories
21 | * @returns Promise that resolves when scanning is complete
22 | */
23 | public async scanCustomCommands(): Promise {
24 | // Reset the command arrays
25 | this.projectCommands = [];
26 | this.userCommands = [];
27 |
28 | // Scan project commands
29 | await this.scanProjectCommands();
30 |
31 | // Scan user commands
32 | await this.scanUserCommands();
33 | }
34 |
35 | /**
36 | * Gets all custom commands as SlashCommand objects
37 | * @returns Array of SlashCommand objects
38 | */
39 | public getCustomCommands(): SlashCommand[] {
40 | const commands: SlashCommand[] = [];
41 | const commandMap = new Map();
42 |
43 | // Add project commands first (they take precedence)
44 | for (const cmd of this.projectCommands) {
45 | const command = {
46 | command: `/${cmd.name}`,
47 | description: `📄 ${cmd.description || cmd.name}`,
48 | icon: '📄', // Document icon for project commands
49 | isCustom: true
50 | };
51 | commandMap.set(cmd.name, command);
52 | }
53 |
54 | // Add user commands only if no project command with the same name exists
55 | for (const cmd of this.userCommands) {
56 | if (!commandMap.has(cmd.name)) {
57 | const command = {
58 | command: `/${cmd.name}`,
59 | description: `👤 ${cmd.description || cmd.name}`,
60 | icon: '👤', // User icon for user commands
61 | isCustom: true
62 | };
63 | commandMap.set(cmd.name, command);
64 | }
65 | }
66 |
67 | // Convert map to array
68 | return Array.from(commandMap.values());
69 | }
70 |
71 | /**
72 | * Scans for project commands in the .claude/commands directory
73 | */
74 | private async scanProjectCommands(): Promise {
75 | // Get workspace folders
76 | const workspaceFolders = vscode.workspace.workspaceFolders;
77 | if (!workspaceFolders || workspaceFolders.length === 0) {
78 | return;
79 | }
80 |
81 | // Use the first workspace folder
82 | const workspaceRoot = workspaceFolders[0].uri.fsPath;
83 | const commandsDir = path.join(workspaceRoot, '.claude', 'commands');
84 |
85 | try {
86 | // Check if the commands directory exists
87 | const stats = await fs.promises.stat(commandsDir);
88 | if (!stats.isDirectory()) {
89 | return;
90 | }
91 |
92 | // Read the directory
93 | const files = await fs.promises.readdir(commandsDir);
94 |
95 | // Process each markdown file
96 | for (const file of files) {
97 | if (path.extname(file).toLowerCase() === '.md') {
98 | const filePath = path.join(commandsDir, file);
99 | const name = path.basename(file, '.md');
100 |
101 | // Read the first line for description
102 | try {
103 | const content = await fs.promises.readFile(filePath, 'utf-8');
104 | const firstLine = content.split('\n')[0].trim();
105 | const description = firstLine.startsWith('#')
106 | ? firstLine.substring(1).trim()
107 | : firstLine;
108 |
109 | this.projectCommands.push({
110 | name,
111 | file: filePath,
112 | type: 'project',
113 | description: description || undefined
114 | });
115 | } catch (err) {
116 | console.error(`Error reading project command file ${filePath}:`, err);
117 | // Add without description if we couldn't read it
118 | this.projectCommands.push({
119 | name,
120 | file: filePath,
121 | type: 'project'
122 | });
123 | }
124 | }
125 | }
126 | } catch (err) {
127 | // Directory doesn't exist or can't be read, which is fine
128 | console.log('No project commands directory found or error reading it:', err);
129 | }
130 | }
131 |
132 | /**
133 | * Scans for user commands in the ~/.claude/commands directory
134 | */
135 | private async scanUserCommands(): Promise {
136 | try {
137 | // Get user home directory
138 | const homeDir = process.env.HOME || process.env.USERPROFILE;
139 | if (!homeDir) {
140 | console.error('Could not determine user home directory');
141 | return;
142 | }
143 |
144 | const commandsDir = path.join(homeDir, '.claude', 'commands');
145 |
146 | // Check if the directory exists
147 | const stats = await fs.promises.stat(commandsDir);
148 | if (!stats.isDirectory()) {
149 | return;
150 | }
151 |
152 | // Read the directory
153 | const files = await fs.promises.readdir(commandsDir);
154 |
155 | // Process each markdown file
156 | for (const file of files) {
157 | if (path.extname(file).toLowerCase() === '.md') {
158 | const filePath = path.join(commandsDir, file);
159 | const name = path.basename(file, '.md');
160 |
161 | // Read the first line for description
162 | try {
163 | const content = await fs.promises.readFile(filePath, 'utf-8');
164 | const firstLine = content.split('\n')[0].trim();
165 | const description = firstLine.startsWith('#')
166 | ? firstLine.substring(1).trim()
167 | : firstLine;
168 |
169 | this.userCommands.push({
170 | name,
171 | file: filePath,
172 | type: 'user',
173 | description: description || undefined
174 | });
175 | } catch (err) {
176 | console.error(`Error reading user command file ${filePath}:`, err);
177 | // Add without description if we couldn't read it
178 | this.userCommands.push({
179 | name,
180 | file: filePath,
181 | type: 'user'
182 | });
183 | }
184 | }
185 | }
186 | } catch (err) {
187 | // Directory doesn't exist or can't be read, which is fine
188 | console.log('No user commands directory found or error reading it:', err);
189 | }
190 | }
191 | }
192 |
193 | // Create a singleton instance
194 | export const customCommandService = new CustomCommandService();
195 |
--------------------------------------------------------------------------------
/test/ui/test-drag-drop-enhanced.html:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 | Enhanced Drag and Drop Test
5 |
88 |
89 |
90 |
91 |
Enhanced Drag and Drop Test
92 |
93 |
94 |
Instructions:
95 |
96 |
Drag files from your workspace folder to see @relative/path
97 |
Drag files from outside the workspace to see @/absolute/path
98 |
The extension will determine the appropriate path format automatically
99 |
100 |
101 |
102 |
103 |
Drag and drop files or folders here
104 |
Files from workspace will use relative paths External files will use absolute paths
105 |
106 |
107 |
108 |
Dropped Files:
109 |
110 |
111 |
112 |
113 |
201 |
202 |
--------------------------------------------------------------------------------
/src/service/claudeCodeActionProvider.ts:
--------------------------------------------------------------------------------
1 | import * as vscode from 'vscode';
2 |
3 | /**
4 | * Code Action Provider that adds "Fix with Claude Code" to the Quick Fix menu
5 | * Activates when there are diagnostics (errors, warnings, etc.) in the code
6 | */
7 | export class ClaudeCodeActionProvider implements vscode.CodeActionProvider {
8 | public static readonly providedCodeActionKinds = [
9 | vscode.CodeActionKind.QuickFix
10 | ];
11 |
12 | private _claudeTerminalInputProvider: any;
13 |
14 | constructor(claudeTerminalInputProvider: any) {
15 | this._claudeTerminalInputProvider = claudeTerminalInputProvider;
16 | }
17 |
18 | /**
19 | * Provide code actions for the given document and range
20 | */
21 | public provideCodeActions(
22 | document: vscode.TextDocument,
23 | range: vscode.Range | vscode.Selection,
24 | context: vscode.CodeActionContext,
25 | _token: vscode.CancellationToken
26 | ): vscode.ProviderResult<(vscode.CodeAction | vscode.Command)[]> {
27 |
28 | // Only provide actions if there are diagnostics (errors/warnings)
29 | if (context.diagnostics.length === 0) {
30 | return [];
31 | }
32 |
33 | const actions: vscode.CodeAction[] = [];
34 |
35 | // Create a "Fix with Claude Code" action for each diagnostic
36 | for (const diagnostic of context.diagnostics) {
37 | const action = this.createClaudeFixAction(document, range, diagnostic);
38 | if (action) {
39 | actions.push(action);
40 | }
41 | }
42 |
43 | return actions;
44 | }
45 |
46 | /**
47 | * Create a Claude Code fix action for a specific diagnostic
48 | */
49 | private createClaudeFixAction(
50 | document: vscode.TextDocument,
51 | range: vscode.Range | vscode.Selection,
52 | diagnostic: vscode.Diagnostic
53 | ): vscode.CodeAction | undefined {
54 |
55 | const action = new vscode.CodeAction(
56 | 'Fix with Claude Code',
57 | vscode.CodeActionKind.QuickFix
58 | );
59 |
60 | // Set the action's edit to nothing (we'll handle it in the command)
61 | action.command = {
62 | command: 'claude-code-extension.fixWithClaude',
63 | title: 'Fix with Claude Code',
64 | arguments: [document, range, diagnostic]
65 | };
66 |
67 | // Mark this as preferred if it's an error (not just a warning)
68 | action.isPreferred = diagnostic.severity === vscode.DiagnosticSeverity.Error;
69 |
70 | return action;
71 | }
72 |
73 | /**
74 | * Handle the fix with Claude command
75 | */
76 | public static async handleFixWithClaude(
77 | claudeTerminalInputProvider: any,
78 | document: vscode.TextDocument,
79 | _range: vscode.Range | vscode.Selection,
80 | diagnostic: vscode.Diagnostic
81 | ): Promise {
82 | try {
83 | // Get the workspace folder for relative path
84 | const workspaceFolders = vscode.workspace.workspaceFolders;
85 | let relativePath = document.fileName;
86 |
87 | if (workspaceFolders && workspaceFolders.length > 0) {
88 | const workspaceRoot = workspaceFolders[0].uri.fsPath;
89 | if (relativePath.startsWith(workspaceRoot)) {
90 | relativePath = relativePath.substring(workspaceRoot.length);
91 | // Remove leading slash if present
92 | if (relativePath.startsWith('/') || relativePath.startsWith('\\')) {
93 | relativePath = relativePath.substring(1);
94 | }
95 | }
96 | } else {
97 | // If no workspace, just use the filename
98 | const pathParts = relativePath.split(/[/\\]/);
99 | relativePath = pathParts[pathParts.length - 1];
100 | }
101 |
102 | // Get the line numbers (VSCode uses 0-based indexing, convert to 1-based)
103 | const startLine = diagnostic.range.start.line + 1;
104 | const endLine = diagnostic.range.end.line + 1;
105 |
106 | // Create line range string
107 | const lineRange = startLine === endLine ? `${startLine}` : `${startLine}-${endLine}`;
108 |
109 | // Get the error context - a few lines around the error
110 | const contextStartLine = Math.max(0, diagnostic.range.start.line - 3);
111 | const contextEndLine = Math.min(document.lineCount - 1, diagnostic.range.end.line + 3);
112 | const contextRange = new vscode.Range(contextStartLine, 0, contextEndLine, document.lineAt(contextEndLine).text.length);
113 | const contextCode = document.getText(contextRange);
114 |
115 | // Format the message to Claude Code
116 | const claudeMessage = `Please fix this ${this.getSeverityText(diagnostic.severity)} in my code:
117 |
118 | File: @${relativePath}#L${lineRange}
119 | Error: ${diagnostic.message}
120 | Source: ${diagnostic.source || 'Unknown'}
121 |
122 | Context (lines ${contextStartLine + 1}-${contextEndLine + 1}):
123 | \`\`\`${this.getLanguageId(document)}
124 | ${contextCode}
125 | \`\`\`
126 |
127 | Please analyze the error and provide a fix.`;
128 |
129 | // Show the Claude Code input panel and add the message to input field
130 | await vscode.commands.executeCommand('claudeCodeInputView.focus');
131 |
132 | // Add the message to the input field so it goes through normal input processing
133 | // This will trigger Claude Code's paste detection when user presses Enter
134 | if (claudeTerminalInputProvider && claudeTerminalInputProvider.addTextToInput) {
135 | claudeTerminalInputProvider.addTextToInput(claudeMessage);
136 | } else {
137 | // Fallback: show the message in an info message
138 | vscode.window.showInformationMessage(
139 | 'Claude Code input not available. Please copy this message manually.',
140 | 'Copy Message'
141 | ).then(selection => {
142 | if (selection === 'Copy Message') {
143 | vscode.env.clipboard.writeText(claudeMessage);
144 | }
145 | });
146 | }
147 |
148 | } catch (error) {
149 | console.error('Error in Claude Code fix action:', error);
150 | vscode.window.showErrorMessage(`Failed to send error to Claude Code: ${error}`);
151 | }
152 | }
153 |
154 | /**
155 | * Convert diagnostic severity to readable text
156 | */
157 | private static getSeverityText(severity: vscode.DiagnosticSeverity): string {
158 | switch (severity) {
159 | case vscode.DiagnosticSeverity.Error:
160 | return 'error';
161 | case vscode.DiagnosticSeverity.Warning:
162 | return 'warning';
163 | case vscode.DiagnosticSeverity.Information:
164 | return 'info';
165 | case vscode.DiagnosticSeverity.Hint:
166 | return 'hint';
167 | default:
168 | return 'issue';
169 | }
170 | }
171 |
172 | /**
173 | * Get language identifier for syntax highlighting
174 | */
175 | private static getLanguageId(document: vscode.TextDocument): string {
176 | return document.languageId;
177 | }
178 | }
--------------------------------------------------------------------------------
/src/fileSystem.ts:
--------------------------------------------------------------------------------
1 | import * as vscode from 'vscode';
2 | import * as path from 'path';
3 | import * as fs from 'fs';
4 | import { SearchResult } from './utils/context-mentions';
5 |
6 | /**
7 | * Gets a list of all workspace files and folders
8 | */
9 | export async function getWorkspaceFiles(): Promise {
10 | const results: SearchResult[] = [];
11 |
12 | // Get all workspace folders
13 | const workspaceFolders = vscode.workspace.workspaceFolders;
14 | if (!workspaceFolders) {
15 | return results;
16 | }
17 |
18 | // For each workspace folder, get all files
19 | for (const folder of workspaceFolders) {
20 | const rootPath = folder.uri.fsPath;
21 | const relativeResults = await getFilesInDirectory(rootPath, rootPath);
22 | results.push(...relativeResults);
23 | }
24 |
25 | return results;
26 | }
27 |
28 | /**
29 | * Recursively gets all files in a directory
30 | */
31 | async function getFilesInDirectory(rootPath: string, dirPath: string): Promise {
32 | const results: SearchResult[] = [];
33 |
34 | try {
35 | const items = await fs.promises.readdir(dirPath, { withFileTypes: true });
36 |
37 | // Add current directory to results
38 | const relativePath = path.relative(rootPath, dirPath);
39 | if (relativePath) {
40 | results.push({
41 | path: '/' + relativePath.replace(/\\/g, '/'),
42 | type: 'folder',
43 | label: path.basename(dirPath)
44 | });
45 | }
46 |
47 | // Process all items in this directory
48 | for (const item of items) {
49 | // Skip node_modules, .git, and other system directories
50 | if (item.name.startsWith('.') || item.name === 'node_modules') {
51 | continue;
52 | }
53 |
54 | const itemPath = path.join(dirPath, item.name);
55 | const relPath = path.relative(rootPath, itemPath).replace(/\\/g, '/');
56 |
57 | if (item.isDirectory()) {
58 | // For directories, recurse and add this directory
59 | const subDirResults = await getFilesInDirectory(rootPath, itemPath);
60 | results.push(...subDirResults);
61 | } else {
62 | // For files, add to results
63 | results.push({
64 | path: '/' + relPath,
65 | type: 'file',
66 | label: item.name
67 | });
68 | }
69 | }
70 | } catch (err) {
71 | console.error(`Error reading directory ${dirPath}:`, err);
72 | }
73 |
74 | return results;
75 | }
76 |
77 | /**
78 | * Searches for files and folders matching a query
79 | */
80 | export async function searchFiles(query: string): Promise {
81 | if (!query) {
82 | return [];
83 | }
84 |
85 | // Get all workspace files
86 | const allFiles = await getWorkspaceFiles();
87 |
88 | // Filter files that match the query
89 | const results = allFiles.filter(file => {
90 | // Search in both the path and the filename
91 | return file.path.toLowerCase().includes(query.toLowerCase()) ||
92 | (file.label ? file.label.toLowerCase().includes(query.toLowerCase()) : false);
93 | });
94 |
95 | // Sort results by relevance
96 | results.sort((a, b) => {
97 | const aLabelLower = a.label?.toLowerCase() || '';
98 | const bLabelLower = b.label?.toLowerCase() || '';
99 | const queryLower = query.toLowerCase();
100 |
101 | // Exact filename matches come first
102 | const aExact = aLabelLower === queryLower;
103 | const bExact = bLabelLower === queryLower;
104 |
105 | if (aExact && !bExact) return -1;
106 | if (!aExact && bExact) return 1;
107 |
108 | // Filename starts with query comes next
109 | const aStartsWith = aLabelLower.startsWith(queryLower);
110 | const bStartsWith = bLabelLower.startsWith(queryLower);
111 |
112 | if (aStartsWith && !bStartsWith) return -1;
113 | if (!aStartsWith && bStartsWith) return 1;
114 |
115 | // Path contains query comes next
116 | const aPathContains = a.path.toLowerCase().includes(queryLower);
117 | const bPathContains = b.path.toLowerCase().includes(queryLower);
118 |
119 | if (aPathContains && !bPathContains) return -1;
120 | if (!aPathContains && bPathContains) return 1;
121 |
122 | // Sort by path length
123 | return a.path.length - b.path.length;
124 | });
125 |
126 | // Limit to 50 results to avoid overwhelming the UI
127 | return results.slice(0, 50);
128 | }
129 |
130 | /**
131 | * Represents a Git commit
132 | */
133 | export interface FormattedGitCommit {
134 | hash: string;
135 | shortHash: string;
136 | subject: string;
137 | author: string;
138 | date: string;
139 | }
140 |
141 | /**
142 | * Gets all Git commits from the workspace
143 | */
144 | export async function getGitCommits(query: string): Promise {
145 | // Get VS Code's Git extension
146 | const gitExtension = vscode.extensions.getExtension('vscode.git')?.exports;
147 |
148 | if (!gitExtension || !gitExtension.getAPI) {
149 | // If Git extension is not available, return mock data
150 | return getMockCommits(query);
151 | }
152 |
153 | try {
154 | const git = gitExtension.getAPI(1);
155 | const repositories = git.repositories;
156 |
157 | if (!repositories || repositories.length === 0) {
158 | return getMockCommits(query);
159 | }
160 |
161 | // Use the first repository (most projects only have one)
162 | const repo = repositories[0];
163 |
164 | // Get the last 50 commits
165 | const logOptions = {
166 | maxEntries: 50
167 | };
168 |
169 | const commits = await repo.log(logOptions);
170 |
171 | // Define the commit interface from Git extension
172 | interface GitCommit {
173 | hash: string;
174 | message: string;
175 | authorName?: string;
176 | commitDate: Date | string;
177 | }
178 |
179 | // Convert to our standard format
180 | const formattedCommits = commits.map((commit: GitCommit): FormattedGitCommit => ({
181 | hash: commit.hash,
182 | shortHash: commit.hash.substring(0, 7),
183 | subject: commit.message,
184 | author: commit.authorName || 'Unknown',
185 | date: new Date(commit.commitDate).toISOString().split('T')[0]
186 | }));
187 |
188 | // Filter commits that match the query
189 | return formattedCommits.filter((commit: FormattedGitCommit) =>
190 | commit.hash.startsWith(query) ||
191 | commit.shortHash.startsWith(query) ||
192 | commit.subject.toLowerCase().includes(query.toLowerCase()) ||
193 | commit.author.toLowerCase().includes(query.toLowerCase())
194 | );
195 | } catch (error) {
196 | console.error('Error getting Git commits:', error);
197 | return getMockCommits(query);
198 | }
199 | }
200 |
201 | /**
202 | * Returns mock commit data if the Git extension is not available
203 | */
204 | function getMockCommits(query: string): FormattedGitCommit[] {
205 | // Mock git commits that match the query
206 | const mockCommits = [
207 | {
208 | hash: '1234567890abcdef1234567890abcdef12345678',
209 | shortHash: '1234567',
210 | subject: 'Fix bug in login component',
211 | author: 'John Doe',
212 | date: '2023-05-15'
213 | },
214 | {
215 | hash: 'abcdef1234567890abcdef1234567890abcdef12',
216 | shortHash: 'abcdef1',
217 | subject: 'Add new feature to dashboard',
218 | author: 'Jane Smith',
219 | date: '2023-05-14'
220 | },
221 | {
222 | hash: '9876543210fedcba9876543210fedcba98765432',
223 | shortHash: '9876543',
224 | subject: 'Refactor user authentication',
225 | author: 'John Doe',
226 | date: '2023-05-13'
227 | }
228 | ];
229 |
230 | // Filter commits that match the query
231 | return mockCommits.filter(commit =>
232 | commit.hash.startsWith(query) ||
233 | commit.shortHash.startsWith(query) ||
234 | commit.subject.toLowerCase().includes(query.toLowerCase())
235 | );
236 | }
--------------------------------------------------------------------------------
/SERVICE_WORKER_ERROR_INVESTIGATION.md:
--------------------------------------------------------------------------------
1 | # Service Worker Error Investigation Report
2 |
3 | ## Issue Summary
4 |
5 | GitHub Issue: [#27 - Error loading webview: Could not register service worker: InvalidStateError](https://github.com/codeflow-studio/claude-code-chat/issues/27)
6 |
7 | **Error Message:**
8 | ```
9 | Error loading webview: Error: Could not register service worker: InvalidStateError: Failed to register a ServiceWorker: The document is in an invalid state.
10 | ```
11 |
12 | ## Root Cause Analysis
13 |
14 | After comprehensive investigation, I've identified that this is **NOT an issue with the Claude Code extension itself**, but rather a **known VSCode bug** affecting multiple extensions that use webviews.
15 |
16 | ### Key Findings
17 |
18 | 1. **No Service Worker Code in Extension**: The Claude Code extension contains no service worker registration code
19 | 2. **VSCode Internal Issue**: VSCode's webview system automatically attempts to register service workers
20 | 3. **Known Problem Version**: VSCode 1.100.3 (user's version) is a known problematic version
21 | 4. **CSP Configuration Impact**: The extension's Content Security Policy may contribute to the issue
22 |
23 | ## Investigation Results
24 |
25 | ### Environment Analysis
26 | - **VSCode Version**: 1.100.3 (known problematic version)
27 | - **Platform**: macOS arm64
28 | - **Service Worker State**: VSCode has active service worker cache with 85+ files
29 | - **Cache State**: 4514+ cached files detected
30 |
31 | ### CSP Analysis
32 | The Claude extension uses this CSP configuration:
33 | ```
34 | default-src 'none'; style-src vscode-webview: 'unsafe-inline'; font-src vscode-webview:; img-src vscode-webview: data:; script-src 'nonce-{nonce}';
35 | ```
36 |
37 | **Analysis Result**: This CSP configuration **could block service worker registration** because:
38 | - `default-src 'none'` blocks everything by default
39 | - No explicit `worker-src` directive is specified
40 | - When `worker-src` is not specified, it falls back to `default-src`, which is `'none'`
41 |
42 | ## Affected VSCode Versions
43 |
44 | Based on research of similar issues across multiple extensions, the following VSCode versions are known to have this problem:
45 | - 1.82.2, 1.83.0, 1.84.0
46 | - 1.90.0, 1.91.0, 1.92.0
47 | - 1.100.0, 1.100.1, 1.100.2, 1.100.3
48 |
49 | ## Similar Issues in Other Extensions
50 |
51 | This identical error has been reported in:
52 | - Julia VSCode extension
53 | - Sourcegraph extension
54 | - Jupyter notebooks
55 | - Postman extension
56 | - Multiple other webview-based extensions
57 |
58 | ## Reproduction Methods
59 |
60 | I created several test scenarios to systematically reproduce the issue:
61 |
62 | ### 1. Minimal Webview Test
63 | Created `test-minimal-webview.js` - a minimal extension that replicates Claude's webview pattern without service worker code.
64 |
65 | ### 2. Cache State Analysis
66 | Created `reproduce-service-worker-error.js` - comprehensive script that:
67 | - Analyzes VSCode version compatibility
68 | - Checks service worker cache state
69 | - Tests Content Security Policy configurations
70 | - Simulates various extension lifecycle scenarios
71 |
72 | ### 3. Trigger Test Scenarios
73 | Created `service-worker-trigger-test.js` - specific tests that attempt to trigger the exact error through:
74 | - Direct service worker registration attempts
75 | - Document state manipulation
76 | - Complex DOM operations
77 | - CSP conflicts
78 |
79 | ### 4. Cache Clearing Test
80 | Created `test-cache-clearing.sh` - script to test the most commonly suggested workaround.
81 |
82 | ## Workarounds (In Order of Effectiveness)
83 |
84 | Based on research and testing, here are the proven solutions:
85 |
86 | ### 1. Clear VSCode Service Worker Cache ⭐ (Most Effective)
87 | ```bash
88 | # Close all VSCode instances first
89 | killall code
90 |
91 | # Clear service worker cache
92 | rm -rf "$HOME/Library/Application Support/Code/Service Worker"
93 |
94 | # Restart VSCode
95 | code
96 | ```
97 |
98 | ### 2. Clear All VSCode Cache
99 | ```bash
100 | # Close all VSCode instances
101 | killall code
102 |
103 | # Clear all cache
104 | rm -rf "$HOME/Library/Application Support/Code/Cache"
105 | rm -rf "$HOME/Library/Application Support/Code/Service Worker"
106 |
107 | # Restart VSCode
108 | code
109 | ```
110 |
111 | ### 3. Launch with --no-sandbox Flag
112 | ```bash
113 | code --no-sandbox
114 | ```
115 |
116 | ### 4. Use Developer: Reload Window
117 | - Open Command Palette (Cmd+Shift+P)
118 | - Run "Developer: Reload Window"
119 |
120 | ### 5. Kill All VSCode Processes
121 | ```bash
122 | killall code
123 | # Or on Linux: killall -9 code
124 | ```
125 |
126 | ### 6. System Restart (Last Resort)
127 | Reboot the computer if other methods fail.
128 |
129 | ## Prevention Strategies
130 |
131 | ### For Extension Developers
132 |
133 | 1. **Update CSP Configuration**: Add explicit service worker permissions:
134 | ```html
135 |
136 | ```
137 |
138 | 2. **Error Handling**: Add service worker error detection and user guidance:
139 | ```javascript
140 | window.addEventListener('error', (event) => {
141 | if (event.message.includes('service worker') || event.message.includes('ServiceWorker')) {
142 | // Show user-friendly error message with workaround instructions
143 | console.error('Service worker registration failed. Try clearing VSCode cache.');
144 | }
145 | });
146 | ```
147 |
148 | ### For Users
149 |
150 | 1. **Regular Cache Maintenance**: Clear VSCode cache periodically
151 | 2. **Monitor VSCode Updates**: Update to newer versions when available
152 | 3. **Use Stable VSCode Builds**: Avoid problematic version ranges when possible
153 |
154 | ## Technical Deep Dive
155 |
156 | ### Why This Happens
157 |
158 | 1. **VSCode's Service Worker System**: VSCode automatically registers service workers for webview content
159 | 2. **Document State Conflicts**: The error occurs when VSCode attempts to register a service worker but the document is in an "invalid state"
160 | 3. **Cache Corruption**: Corrupted service worker cache can cause persistent invalid states
161 | 4. **CSP Blocking**: Restrictive Content Security Policies can interfere with service worker registration
162 |
163 | ### Cache Structure Analysis
164 |
165 | VSCode maintains service worker data in:
166 | ```
167 | ~/Library/Application Support/Code/Service Worker/
168 | ├── Database/ # LevelDB database files
169 | │ ├── CURRENT # Current manifest pointer
170 | │ ├── LOCK # Database lock file
171 | │ ├── MANIFEST-* # Database manifests
172 | │ └── *.ldb # Data files
173 | └── ScriptCache/ # Cached service worker scripts
174 | ```
175 |
176 | When this database becomes corrupted or gets into an invalid state, the error occurs.
177 |
178 | ## Files Created During Investigation
179 |
180 | 1. `reproduce-service-worker-error.js` - Comprehensive reproduction script
181 | 2. `test-minimal-webview.js` - Minimal test extension
182 | 3. `service-worker-trigger-test.js` - Targeted error trigger tests
183 | 4. `test-cache-clearing.sh` - Cache clearing test automation
184 | 5. `service-worker-reproduction-report.json` - Detailed analysis results
185 |
186 | ## Recommendations
187 |
188 | ### Immediate Actions for Users
189 | 1. Try the cache clearing workaround (most effective)
190 | 2. If that fails, try the --no-sandbox flag
191 | 3. Consider updating VSCode if using a known problematic version
192 |
193 | ### Long-term Solutions
194 | 1. **VSCode Team**: Fix the underlying service worker registration timing issues
195 | 2. **Extension Authors**: Add explicit service worker handling and better error messages
196 | 3. **Documentation**: Improve troubleshooting guides for webview-based extensions
197 |
198 | ## Status
199 | - ✅ **Root cause identified**: VSCode internal service worker registration bug
200 | - ✅ **Reproduction methods created**: Multiple test scenarios developed
201 | - ✅ **Workarounds verified**: Cache clearing is most effective solution
202 | - ✅ **Prevention strategies documented**: CSP and error handling improvements
203 | - 🔄 **Upstream tracking**: This should be reported to VSCode team as well
204 |
205 | ## Conclusion
206 |
207 | The service worker registration error is a **VSCode platform issue**, not a Claude Code extension bug. The extension itself is implemented correctly according to VSCode webview standards. The issue can be reliably resolved through cache clearing, and future occurrences can be prevented through improved error handling and user guidance.
--------------------------------------------------------------------------------
/README.md:
--------------------------------------------------------------------------------
1 | # Claude Code Assistant for VSCode
2 |
3 |
4 |
5 |
6 |
7 | *Unofficial integration* of Anthropic's Claude Code AI assistant into Visual Studio Code. Get intelligent coding assistance without leaving your editor.
8 |
9 | > **Disclaimer**: This is an unofficial extension not affiliated with Anthropic. It integrates with the official Claude Code CLI tool which must be installed separately.
10 |
11 | ## Features
12 |
13 | ### 🤖 AI-Powered Coding Assistant
14 | - **Seamless Integration**: Access Claude Code directly from VSCode's sidebar
15 | - **Smart Launch Options**: Choose how to start your Claude session
16 | - **Auto-Start Control**: Configure automatic startup behavior
17 | - **Persistent Sessions**: Maintain conversations across your coding sessions
18 | - **Context-Aware**: Claude understands your workspace and current files
19 |
20 |
21 |
22 |
23 |
24 | ### 🚀 Smart Session Management
25 | - **Launch Options**: When Claude isn't running, choose from three convenient options:
26 | - **Start New Session**: Begin a fresh conversation
27 | - **Continue Last Session**: Resume your previous conversation
28 | - **Select History**: Browse and choose from past conversations
29 | - **Auto-Start Configuration**: Control whether Claude starts automatically when VSCode opens
30 | - **Flexible Commands**: Configure which command to use for auto-start (claude, claude -c, etc.)
31 |
32 |
33 |
34 |
35 |
36 | ### 🖼️ Visual Context Support
37 | - **Drag & Drop Images**: Simply drag images into the chat
38 | - **Paste Screenshots**: Ctrl/Cmd+V to paste images directly
39 | - **File Selection**: Use the image button to browse and attach files
40 | - **Multiple Formats**: Supports JPG, PNG, GIF, WebP, and SVG
41 |
42 |
43 |
44 |
45 |
46 | ### 🚀 Quick Fix Integration
47 | - **Instant Error Help**: "Fix with Claude Code" appears in VSCode's Quick Fix menu (Ctrl+. / Cmd+.)
48 | - **Automatic Context**: Sends error details, file references, and surrounding code automatically
49 | - **Seamless Workflow**: Click the lightbulb on any error to get Claude's assistance instantly
50 | - **Smart Detection**: Works with all types of errors and warnings from any language
51 |
52 |
53 |
54 |
55 |
56 | ### 💬 Smart Interactions
57 | - **@mentions**: Reference workspace problems and terminal output
58 | - **Slash Commands**: Quick access to Claude's powerful features
59 | - **Custom Commands**: Create your own project and user slash commands
60 | - **Markdown Support**: Rich formatting with syntax highlighting
61 | - **Code Actions**: Copy code blocks with one click
62 |
63 |
64 |
65 |
66 |
67 | ### 🎨 Beautiful Interface
68 | - **Claude-Styled UI**: Familiar interface matching Claude's design
69 | - **Dark/Light Theme**: Adapts to your VSCode theme
70 | - **Status Indicators**: Real-time feedback on Claude's state
71 | - **Clear History**: Easy conversation management
72 |
73 | ## Prerequisites
74 |
75 | - Visual Studio Code 1.70.0 or newer
76 | - [Claude Code CLI](https://docs.anthropic.com/claude/docs/claude-code) installed on your system
77 | - Active Claude account with authentication
78 |
79 | ## Building the Extension
80 |
81 | To build the extension, follow these steps:
82 |
83 | 1. Install dependencies:
84 | ```
85 | npm install
86 | ```
87 |
88 | 2. Build the extension:
89 | ```
90 | npm run build
91 | ```
92 |
93 | This will generate a .vsix file in the project root directory.
94 |
95 | ## Installing the Extension
96 |
97 | ### From the VSIX file
98 |
99 | 1. Open VSCode
100 | 2. Go to the Extensions view
101 | 3. Click the "..." menu (top-right of Extensions view)
102 | 4. Select "Install from VSIX..."
103 | 5. Browse to the .vsix file generated in the build step
104 | 6. Select the file and click "Install"
105 |
106 | ### From the Command Line
107 |
108 | You can also install the extension using the VSCode CLI:
109 |
110 | ```
111 | code --install-extension claude-code-extension-0.0.1.vsix
112 | ```
113 |
114 | ## Getting Started
115 |
116 | 1. Install the extension from the VSCode Marketplace
117 | 2. Open the Claude Code panel from the sidebar (look for the Claude icon)
118 | 3. Choose how to launch Claude:
119 | - **Auto-start enabled**: Claude starts automatically when VSCode opens
120 | - **Auto-start disabled**: Select from launch options (New Session, Continue Last, or Select History)
121 | 4. Start chatting with Claude about your code!
122 |
123 | ## Usage
124 |
125 | ### 🚀 Launch Options
126 | When Claude isn't running, you'll see three launch options:
127 | - **Start New Session** (▶️): Begin a fresh conversation with Claude
128 | - **Continue Last Session** (⏭️): Resume your previous conversation where you left off
129 | - **Select History** (📚): Browse and choose from your past conversations
130 |
131 | ### 💬 Basic Chat
132 | - Type your questions or requests in the input area
133 | - Press Enter or click Send to submit
134 | - Claude will respond with helpful suggestions and code
135 |
136 | ### 🚀 Quick Fix with Claude
137 | - **Instant Help**: When you see a red/yellow squiggly line under code, press Ctrl+. (Cmd+. on Mac)
138 | - **Select Fix**: Choose "Fix with Claude Code" from the Quick Fix menu
139 | - **Auto Context**: Claude receives the error details, file location, and surrounding code automatically
140 | - **Get Solution**: Claude analyzes the error and provides targeted fixes
141 |
142 | ### 🖼️ Working with Images
143 | - **Drag & Drop**: Drag image files directly onto the input area
144 | - **Paste**: Copy an image and paste with Ctrl/Cmd+V
145 | - **Browse**: Click the 📎 button to select image files
146 | - Supported: JPG, PNG, GIF, WebP, SVG
147 |
148 | ### 🔧 Advanced Features
149 | - **@mentions**: Type @ to reference problems or terminal output
150 | - **Slash Commands**: Type / to see available commands
151 | - **Custom Commands**: Create your own project-specific (`/project:command`) and personal (`/user:command`) slash commands
152 | - **Clear Chat**: Click the clear button to start fresh
153 | - **Restart Claude**: Use the restart button if needed
154 |
155 | ### ⚙️ Configuration
156 | The extension can be customized through VSCode settings:
157 |
158 | - **Auto Start On Activation**: Enable/disable automatic Claude startup when VSCode opens
159 | - **Auto Start Command**: Configure which command to use when auto-starting Claude
160 | - `claude` - Start a new session
161 | - `claude -c` - Continue the last session
162 | - `claude -r` - Select from conversation history
163 | - Custom commands as needed
164 |
165 |
166 |
167 |
168 |
169 | Access these settings through VSCode preferences: `File > Preferences > Settings` and search for "Claude Code Extension".
170 |
171 | See our [documentation](https://github.com/codeflow-studio/claude-code-chat/tree/main/docs) for detailed guides, including [how to create custom slash commands](docs/custom-slash-commands.md).
172 |
173 | ## Development
174 |
175 | - `npm run compile` - Compile the extension
176 | - `npm run watch` - Watch for changes and recompile
177 | - `npm run package` - Package the extension for production (webpack)
178 | - `npm run lint` - Run ESLint on source files
179 | - `npm run test` - Run tests
180 | - `npm run vsix` - Create VSIX package for installation
181 |
182 | ## Support
183 |
184 | - 🔧 **[Troubleshooting Guide](TROUBLESHOOTING.md)** - Fix common issues like service worker errors
185 | - 📖 [Documentation](https://github.com/codeflow-studio/claude-code-chat/tree/main/docs)
186 | - 🐛 [Report Issues](https://github.com/codeflow-studio/claude-code-chat/issues)
187 | - 💬 [Discussions](https://github.com/codeflow-studio/claude-code-chat/discussions)
188 |
189 | ## License
190 |
191 | MIT License - see [LICENSE.md](LICENSE.md) for details
192 |
193 | ## Contributing
194 |
195 | We welcome contributions! Please see our [Contributing Guide](CONTRIBUTING.md) for details.
196 |
197 | ---
198 |
199 | Made with ❤️ by [CodeFlow Studio](https://github.com/codeflow-studio)
200 |
201 | *This is an unofficial extension. Claude and Claude Code are trademarks of Anthropic, PBC.*
--------------------------------------------------------------------------------
/src/ui/components/ContextMenu.ts:
--------------------------------------------------------------------------------
1 | import { ContextMenuOptionType, ContextMenuQueryItem } from '../../utils/context-mentions';
2 |
3 | /**
4 | * Generates the HTML for the context menu displayed when typing '@'
5 | */
6 | export function createContextMenuHtml(
7 | options: ContextMenuQueryItem[],
8 | selectedIndex: number,
9 | onSelect: (type: ContextMenuOptionType, value?: string) => void,
10 | onMouseEnter: (index: number) => void,
11 | isLoading: boolean = false
12 | ): string {
13 | const menuHtml = `
14 |