Merge pull request #1 from devNull-bootloader/copilot/create-vscode-extension-openclaude

Add sleek terminal-style VS Code extension for OpenClaude
This commit is contained in:
Urvish Lanje
2026-04-02 17:13:02 +02:00
committed by GitHub
6 changed files with 374 additions and 0 deletions

View File

@@ -104,6 +104,11 @@ Best if you want local inference on Apple Silicon with Atomic Chat. See [Advance
---
## VS Code Extension
Want a native VS Code experience? Use the in-repo extension at `vscode-extension/openclaude-vscode` for one-command terminal launch and the `OpenClaude Terminal Black` theme.
## What Works
- **All tools**: Bash, FileRead, FileWrite, FileEdit, Glob, Grep, WebFetch, WebSearch, Agent, MCP, LSP, NotebookEdit, Tasks

View File

@@ -0,0 +1,44 @@
# OpenClaude VS Code Extension
A sleek VS Code companion for OpenClaude with a visual **Control Center** plus terminal-first workflows.
## Features
- **Control Center sidebar UI** in the Activity Bar:
- Launch OpenClaude
- Open repository/docs
- Open VS Code theme picker
- **Terminal launch command**: `OpenClaude: Launch in Terminal`
- **Built-in dark theme**: `OpenClaude Terminal Black` (terminal-inspired, low-glare, neon accents)
## Requirements
- VS Code `1.95+`
- `openclaude` available in your terminal PATH (`npm install -g @gitlawb/openclaude`)
## Commands
- `OpenClaude: Open Control Center`
- `OpenClaude: Launch in Terminal`
- `OpenClaude: Open Repository`
## Settings
- `openclaude.launchCommand` (default: `openclaude`)
- `openclaude.terminalName` (default: `OpenClaude`)
- `openclaude.useOpenAIShim` (default: `true`)
## Development
From this folder:
```bash
npm run lint
```
To package (optional):
```bash
npm run package
```

View File

@@ -0,0 +1,6 @@
<svg width="128" height="128" viewBox="0 0 128 128" fill="none" xmlns="http://www.w3.org/2000/svg">
<rect width="128" height="128" rx="20" fill="#0B0F18"/>
<rect x="16" y="20" width="96" height="88" rx="10" fill="#090B10" stroke="#2A3350"/>
<path d="M32 48L46 60L32 72" stroke="#66D9EF" stroke-width="8" stroke-linecap="round" stroke-linejoin="round"/>
<rect x="56" y="68" width="38" height="8" rx="4" fill="#89DD7C"/>
</svg>

After

Width:  |  Height:  |  Size: 434 B

View File

@@ -0,0 +1,101 @@
{
"name": "openclaude-vscode",
"displayName": "OpenClaude",
"description": "Sleek VS Code extension for OpenClaude with a visual Control Center and terminal-aligned theme.",
"version": "0.1.1",
"publisher": "devnull-bootloader",
"engines": {
"vscode": "^1.95.0"
},
"categories": [
"Themes",
"Other"
],
"activationEvents": [
"onCommand:openclaude.start",
"onCommand:openclaude.openDocs",
"onCommand:openclaude.openControlCenter",
"onView:openclaude.controlCenter"
],
"main": "./src/extension.js",
"contributes": {
"commands": [
{
"command": "openclaude.start",
"title": "OpenClaude: Launch in Terminal",
"category": "OpenClaude"
},
{
"command": "openclaude.openDocs",
"title": "OpenClaude: Open Repository",
"category": "OpenClaude"
},
{
"command": "openclaude.openControlCenter",
"title": "OpenClaude: Open Control Center",
"category": "OpenClaude"
}
],
"viewsContainers": {
"activitybar": [
{
"id": "openclaude",
"title": "OpenClaude",
"icon": "media/openclaude.svg"
}
]
},
"views": {
"openclaude": [
{
"id": "openclaude.controlCenter",
"name": "Control Center",
"type": "webview"
}
]
},
"configuration": {
"title": "OpenClaude",
"properties": {
"openclaude.launchCommand": {
"type": "string",
"default": "openclaude",
"description": "Command run in the integrated terminal when launching OpenClaude."
},
"openclaude.terminalName": {
"type": "string",
"default": "OpenClaude",
"description": "Integrated terminal tab name for OpenClaude sessions."
},
"openclaude.useOpenAIShim": {
"type": "boolean",
"default": true,
"description": "Set CLAUDE_CODE_USE_OPENAI=1 in launched OpenClaude terminals."
}
}
},
"themes": [
{
"label": "OpenClaude Terminal Black",
"uiTheme": "vs-dark",
"path": "./themes/OpenClaude-Terminal-Black.json"
}
]
},
"scripts": {
"lint": "node --check ./src/extension.js",
"package": "npx @vscode/vsce package --no-dependencies"
},
"keywords": [
"openclaude",
"terminal",
"theme",
"cli",
"llm"
],
"repository": {
"type": "git",
"url": "https://github.com/devNull-bootloader/openclaude"
},
"license": "MIT"
}

View File

@@ -0,0 +1,140 @@
const vscode = require('vscode');
const crypto = require('crypto');
function launchOpenClaude() {
const configured = vscode.workspace.getConfiguration('openclaude');
const launchCommand = configured.get('launchCommand', 'openclaude');
const terminalName = configured.get('terminalName', 'OpenClaude');
const terminal = vscode.window.createTerminal({
name: terminalName,
env: {
CLAUDE_CODE_USE_OPENAI: configured.get('useOpenAIShim', true) ? '1' : undefined,
},
});
terminal.show(true);
terminal.sendText(launchCommand, true);
}
class OpenClaudeControlCenterProvider {
resolveWebviewView(webviewView) {
webviewView.webview.options = { enableScripts: true };
webviewView.webview.html = this.getHtml(webviewView.webview);
webviewView.webview.onDidReceiveMessage(async (message) => {
if (message?.type === 'launch') {
launchOpenClaude();
return;
}
if (message?.type === 'docs') {
await vscode.env.openExternal(vscode.Uri.parse('https://github.com/devNull-bootloader/openclaude'));
return;
}
if (message?.type === 'theme') {
await vscode.commands.executeCommand('workbench.action.selectTheme');
}
});
}
getHtml(webview) {
const nonce = crypto.randomBytes(16).toString('base64');
return `<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8" />
<meta http-equiv="Content-Security-Policy" content="default-src 'none'; style-src 'unsafe-inline'; script-src 'nonce-${nonce}';" />
<meta name="viewport" content="width=device-width, initial-scale=1.0" />
<style>
body {
font-family: var(--vscode-font-family);
color: var(--vscode-foreground);
background: var(--vscode-sideBar-background);
padding: 12px;
}
.card {
border: 1px solid var(--vscode-editorWidget-border);
border-radius: 10px;
padding: 12px;
background: color-mix(in srgb, var(--vscode-editor-background) 92%, #000 8%);
display: grid;
gap: 10px;
}
.title {
font-size: 13px;
font-weight: 700;
letter-spacing: 0.2px;
}
.sub {
font-size: 12px;
opacity: 0.85;
line-height: 1.4;
}
button {
border: 0;
border-radius: 8px;
padding: 8px 10px;
cursor: pointer;
color: var(--vscode-button-foreground);
background: var(--vscode-button-background);
text-align: left;
font-size: 12px;
}
button.secondary {
color: var(--vscode-button-secondaryForeground);
background: var(--vscode-button-secondaryBackground);
}
button:hover {
filter: brightness(1.05);
}
</style>
</head>
<body>
<div class="card">
<div class="title">OpenClaude Control Center</div>
<div class="sub">Launch OpenClaude, jump to docs, and quickly tune the editor vibe.</div>
<button id="launch">⚡ Launch OpenClaude</button>
<button id="docs" class="secondary">📚 Open Repository</button>
<button id="theme" class="secondary">🎨 Pick Theme</button>
</div>
<script nonce="${nonce}">
const vscode = acquireVsCodeApi();
document.getElementById('launch').addEventListener('click', () => vscode.postMessage({ type: 'launch' }));
document.getElementById('docs').addEventListener('click', () => vscode.postMessage({ type: 'docs' }));
document.getElementById('theme').addEventListener('click', () => vscode.postMessage({ type: 'theme' }));
</script>
</body>
</html>`;
}
}
/**
* @param {vscode.ExtensionContext} context
*/
function activate(context) {
const startCommand = vscode.commands.registerCommand('openclaude.start', async () => {
launchOpenClaude();
});
const openDocsCommand = vscode.commands.registerCommand('openclaude.openDocs', async () => {
await vscode.env.openExternal(vscode.Uri.parse('https://github.com/devNull-bootloader/openclaude'));
});
const openUiCommand = vscode.commands.registerCommand('openclaude.openControlCenter', async () => {
await vscode.commands.executeCommand('workbench.view.extension.openclaude');
});
const provider = new OpenClaudeControlCenterProvider();
const providerDisposable = vscode.window.registerWebviewViewProvider('openclaude.controlCenter', provider);
context.subscriptions.push(startCommand, openDocsCommand, openUiCommand, providerDisposable);
}
function deactivate() {}
module.exports = {
activate,
deactivate,
};

View File

@@ -0,0 +1,78 @@
{
"$schema": "vscode://schemas/color-theme",
"name": "OpenClaude Terminal Black",
"type": "dark",
"colors": {
"editor.background": "#090B10",
"editor.foreground": "#D6E2FF",
"editorCursor.foreground": "#66D9EF",
"editorLineNumber.foreground": "#3D4458",
"editorLineNumber.activeForeground": "#7F8AA3",
"editor.selectionBackground": "#1C2333",
"editor.inactiveSelectionBackground": "#141A27",
"editor.wordHighlightBackground": "#1C233344",
"editor.wordHighlightStrongBackground": "#24304B66",
"editorIndentGuide.background1": "#131825",
"editorIndentGuide.activeBackground1": "#2A3350",
"editorBracketMatch.background": "#25304B66",
"editorBracketMatch.border": "#66D9EF",
"terminal.background": "#090B10",
"terminal.foreground": "#D6E2FF",
"terminalCursor.background": "#66D9EF",
"terminalCursor.foreground": "#66D9EF",
"terminal.ansiBlack": "#090B10",
"terminal.ansiRed": "#FF6B6B",
"terminal.ansiGreen": "#89DD7C",
"terminal.ansiYellow": "#F2C14E",
"terminal.ansiBlue": "#5CA9FF",
"terminal.ansiMagenta": "#C792EA",
"terminal.ansiCyan": "#66D9EF",
"terminal.ansiWhite": "#D6E2FF",
"terminal.ansiBrightBlack": "#4A5165",
"terminal.ansiBrightRed": "#FF8787",
"terminal.ansiBrightGreen": "#A4EFA0",
"terminal.ansiBrightYellow": "#FFD479",
"terminal.ansiBrightBlue": "#86C1FF",
"terminal.ansiBrightMagenta": "#D8B0F5",
"terminal.ansiBrightCyan": "#9DE9FF",
"terminal.ansiBrightWhite": "#E8F0FF",
"statusBar.background": "#0F1420",
"statusBar.foreground": "#D6E2FF",
"activityBar.background": "#0D111B",
"activityBar.foreground": "#D6E2FF",
"sideBar.background": "#0B0F18",
"sideBar.foreground": "#B3BDD4",
"titleBar.activeBackground": "#0B0F18",
"titleBar.activeForeground": "#D6E2FF"
},
"tokenColors": [
{
"scope": ["comment", "punctuation.definition.comment"],
"settings": { "foreground": "#5A637B", "fontStyle": "italic" }
},
{
"scope": ["keyword", "storage.type", "storage.modifier"],
"settings": { "foreground": "#C792EA" }
},
{
"scope": ["string", "constant.other.symbol"],
"settings": { "foreground": "#89DD7C" }
},
{
"scope": ["constant.numeric", "constant.language"],
"settings": { "foreground": "#F2C14E" }
},
{
"scope": ["entity.name.function", "support.function"],
"settings": { "foreground": "#5CA9FF" }
},
{
"scope": ["variable", "entity.name.variable"],
"settings": { "foreground": "#D6E2FF" }
},
{
"scope": ["entity.name.type", "support.type", "entity.name.class"],
"settings": { "foreground": "#66D9EF" }
}
]
}