Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
52 changes: 52 additions & 0 deletions .github/workflows/build.yml
Original file line number Diff line number Diff line change
@@ -0,0 +1,52 @@
name: Build OCcode

on:
push:
branches: [main, scaffold-mvp]
pull_request:
branches: [main]

jobs:
build-wrapper:
strategy:
matrix:
os: [ubuntu-latest, macos-latest, windows-latest]
runs-on: ${{ matrix.os }}
steps:
- uses: actions/checkout@v4
- uses: actions/setup-node@v4
with:
node-version: '20'
- name: Install dependencies
run: npm ci
working-directory: apps/wrapper
- name: Build Electron app
run: npm run build
working-directory: apps/wrapper
env:
GH_TOKEN: ${{ secrets.GITHUB_TOKEN }}
- uses: actions/upload-artifact@v4
with:
name: occode-${{ matrix.os }}
path: apps/wrapper/dist/*

build-extension:
runs-on: ubuntu-latest
steps:
- uses: actions/checkout@v4
- uses: actions/setup-node@v4
with:
node-version: '20'
- name: Install dependencies
run: npm ci
working-directory: apps/extension
- name: Compile extension
run: npm run compile
working-directory: apps/extension
- name: Package VSIX
run: npx @vscode/vsce package
working-directory: apps/extension
- uses: actions/upload-artifact@v4
with:
name: openclaw-extension
path: apps/extension/*.vsix
84 changes: 58 additions & 26 deletions README.md
Original file line number Diff line number Diff line change
@@ -1,34 +1,66 @@
# OCcode

Branded, crossplatform OpenClaw IDE built on a VS Code portable bundle + custom extension.
**Branded, cross-platform IDE wrapper** that ships a portable VSCodium bundle with the **OpenClaw** VS Code extension pre-installed.

## Structure

```
apps/
wrapper/ # Electron app (branding, install flow)
extension/ # VS Code extension (OpenClaw UI + commands)
scripts/
.github/workflows/
wrapper/ # Electron app — downloads VSCodium, installs extension, launches editor
extension/ # VS Code extension — Home screen, Setup wizard, Status panel
.github/
workflows/ # CI: build wrapper (Win/Mac/Linux) + package extension
```

## Quick Start

### Wrapper (Electron)

```bash
cd apps/wrapper
npm install
npm start
```

The wrapper will:
1. Download portable VSCodium (pinned version) to `~/.occode/vscode/`
2. Install any bundled `.vsix` extensions
3. Set default settings (theme, disable welcome)
4. Launch VSCodium with a custom user-data directory

### Extension (VS Code)

```bash
cd apps/extension
npm install
npm run compile
```

Then press F5 in VS Code to launch the Extension Development Host.

**Commands:**
- `OpenClaw: Home` — branded home screen with quick links
- `OpenClaw: Setup Local` — wizard to detect OS, check prerequisites (git, node, docker), and guide OpenClaw setup
- `OpenClaw: Status` — shows whether the OpenClaw gateway is running

## Building

```bash
# Wrapper — platform-specific installer
cd apps/wrapper && npm run build

# Extension — .vsix package
cd apps/extension && npx @vscode/vsce package
```

## Goals
- Ship OCcode.exe / OCcode.dmg / OCcode.AppImage
- Custom home screen + panels via extension
- Install/config OpenClaw locally via extension wizard

## Plan (MVP)
**Wrapper (Electron)**
1. Download portable VS Code/VSCodium
2. Install OpenClaw extension (.vsix or URL)
3. Write default settings/workspace
4. Launch VS Code

**Extension (OpenClaw)**
- Custom Home webview
- Install/config local OpenClaw
- Start/stop + logs/status

## Next
- Scaffold wrapper app
- Scaffold VS Code extension
- Add CI for Windows/Mac/Linux builds
## CI

GitHub Actions builds the wrapper for Windows, macOS, and Linux on every push to `main`. Extension is compiled and packaged as a `.vsix` artifact.

## Contributing

PRs welcome! See [AGENTS.md](AGENTS.md) for the full plan and milestone tracker.

## License

MIT
42 changes: 42 additions & 0 deletions apps/extension/package.json
Original file line number Diff line number Diff line change
@@ -0,0 +1,42 @@
{
"name": "openclaw-vscode",
"displayName": "OpenClaw",
"description": "OpenClaw home screen, local setup wizard, and status panel for VS Code",
"version": "0.1.0",
"publisher": "openclaw",
"engines": {
"vscode": "^1.85.0"
},
"categories": ["Other"],
"activationEvents": [
"onStartupFinished"
],
"main": "./out/extension.js",
"contributes": {
"commands": [
{
"command": "openclaw.home",
"title": "OpenClaw: Home"
},
{
"command": "openclaw.setupLocal",
"title": "OpenClaw: Setup Local"
},
{
"command": "openclaw.status",
"title": "OpenClaw: Status"
}
]
},
"scripts": {
"compile": "tsc -p ./",
"watch": "tsc -watch -p ./",
"package": "vsce package"
},
"devDependencies": {
"@types/vscode": "^1.85.0",
"@types/node": "^20.0.0",
"typescript": "^5.3.0",
"@vscode/vsce": "^2.22.0"
}
}
23 changes: 23 additions & 0 deletions apps/extension/src/extension.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,23 @@
import * as vscode from 'vscode';
import { HomePanel } from './panels/home';
import { SetupPanel } from './panels/setup';
import { StatusPanel } from './panels/status';

export function activate(context: vscode.ExtensionContext) {
context.subscriptions.push(
vscode.commands.registerCommand('openclaw.home', () => {
HomePanel.createOrShow(context.extensionUri);
}),
vscode.commands.registerCommand('openclaw.setupLocal', () => {
SetupPanel.createOrShow(context.extensionUri);
}),
vscode.commands.registerCommand('openclaw.status', () => {
StatusPanel.createOrShow(context.extensionUri);
}),
);

// Show home panel on first activation
vscode.commands.executeCommand('openclaw.home');
}

export function deactivate() {}
82 changes: 82 additions & 0 deletions apps/extension/src/panels/home.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,82 @@
import * as vscode from 'vscode';

export class HomePanel {
public static currentPanel: HomePanel | undefined;
private readonly _panel: vscode.WebviewPanel;
private _disposables: vscode.Disposable[] = [];

private constructor(panel: vscode.WebviewPanel) {
this._panel = panel;
this._panel.webview.html = this._getHtml();
this._panel.onDidDispose(() => this.dispose(), null, this._disposables);
}

public static createOrShow(extensionUri: vscode.Uri) {
if (HomePanel.currentPanel) {
HomePanel.currentPanel._panel.reveal();
return;
}
const panel = vscode.window.createWebviewPanel(
'openclawHome', 'OpenClaw Home', vscode.ViewColumn.One, { enableScripts: true }
);
HomePanel.currentPanel = new HomePanel(panel);
}

public dispose() {
HomePanel.currentPanel = undefined;
this._panel.dispose();
this._disposables.forEach(d => d.dispose());
}

private _getHtml(): string {
return `<!DOCTYPE html>
<html>
<head>
<meta charset="utf-8">
<style>
body {
font-family: var(--vscode-font-family);
background: var(--vscode-editor-background);
color: var(--vscode-editor-foreground);
display: flex; flex-direction: column; align-items: center;
padding: 40px 20px;
}
h1 { font-size: 32px; margin-bottom: 8px; }
.accent { color: #00d4aa; }
.subtitle { color: var(--vscode-descriptionForeground); margin-bottom: 32px; }
.actions { display: flex; gap: 12px; flex-wrap: wrap; justify-content: center; }
button {
background: #00d4aa; color: #1a1a2e; border: none; padding: 10px 20px;
border-radius: 6px; font-size: 14px; cursor: pointer; font-weight: 600;
}
button:hover { background: #00b894; }
button.secondary {
background: transparent; border: 1px solid var(--vscode-button-border, #555);
color: var(--vscode-editor-foreground);
}
.links { margin-top: 40px; }
.links a {
color: var(--vscode-textLink-foreground); text-decoration: none; margin: 0 12px;
}
</style>
</head>
<body>
<h1>🐾 <span class="accent">OpenClaw</span></h1>
<p class="subtitle">Your AI-powered development companion</p>
<div class="actions">
<button onclick="cmd('openclaw.setupLocal')">Setup Local Environment</button>
<button class="secondary" onclick="cmd('openclaw.status')">Check Status</button>
</div>
<div class="links">
<a href="https://github.com/damoahdominic/occ">GitHub</a>
<a href="https://openclaw.ai">Website</a>
<a href="https://docs.openclaw.ai">Docs</a>
</div>
<script>
const vscode = acquireVsCodeApi();
function cmd(c) { vscode.postMessage({ command: c }); }
</script>
</body>
</html>`;
}
}
Loading