ocb-cli 1.0.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
package/README.md ADDED
@@ -0,0 +1,66 @@
1
+ # OCB - OpenCode Bridge
2
+
3
+ **Use OpenCode AI models directly in Claude Code!**
4
+
5
+ ## Quick Start
6
+
7
+ ```bash
8
+ # Clone the repo
9
+ git clone https://github.com/veokhan/ocb.git
10
+ cd ocb
11
+
12
+ # Install dependencies
13
+ npm install
14
+
15
+ # Build
16
+ npm run build
17
+
18
+ # Start the server
19
+ npm run start
20
+ ```
21
+
22
+ ## Usage Commands
23
+
24
+ ```bash
25
+ # Start server only
26
+ npm run start
27
+
28
+ # Stop server
29
+ npm run stop
30
+
31
+ # Setup Claude Code config
32
+ npm run cli -- setup
33
+ ```
34
+
35
+ ## Or Use npx (No Install Needed)
36
+
37
+ ```bash
38
+ # Clone
39
+ git clone https://github.com/veokhan/ocb.git
40
+ cd ocb
41
+
42
+ # Install deps
43
+ npm install
44
+
45
+ # Use via npx
46
+ npx tsx src/cli.ts start
47
+ npx tsx src/cli.ts setup
48
+ ```
49
+
50
+ ## After Running
51
+
52
+ 1. **Dashboard:** http://localhost:8300
53
+ 2. **Use Claude Code:**
54
+ ```bash
55
+ claude --print
56
+ ```
57
+
58
+ ## Features
59
+
60
+ - 🌐 **2540+ Models** from 89 providers
61
+ - šŸ“Š **Usage Tracking**
62
+ - ⚔ **Auto-Configuration**
63
+
64
+ ## GitHub
65
+
66
+ https://github.com/veokhan/ocb
package/dist/cli.js ADDED
@@ -0,0 +1,225 @@
1
+ #!/usr/bin/env node
2
+ import { spawn, execSync } from "child_process";
3
+ import { readFileSync, writeFileSync, existsSync, mkdirSync } from "fs";
4
+ import { join, dirname } from "path";
5
+ import { fileURLToPath } from "url";
6
+ const __filename = fileURLToPath(import.meta.url);
7
+ const __dirname = dirname(__filename);
8
+ const PROXY_PORT = 8300;
9
+ const OPENCODE_PORT = 4096;
10
+ const isWindows = process.platform === 'win32';
11
+ const OPENCODE_CMD = isWindows ? 'opencode.cmd' : 'opencode';
12
+ const colors = {
13
+ reset: '\x1b[0m',
14
+ bright: '\x1b[1m',
15
+ green: '\x1b[32m',
16
+ yellow: '\x1b[33m',
17
+ blue: '\x1b[34m',
18
+ cyan: '\x1b[36m'
19
+ };
20
+ function log(msg, color = colors.reset) {
21
+ console.log(`${color}${msg}${colors.reset}`);
22
+ }
23
+ function getHomeDir() {
24
+ return process.env.HOME || process.env.USERPROFILE || process.env.HOMEPATH || '';
25
+ }
26
+ function getClaudeSettingsPath() {
27
+ const home = getHomeDir();
28
+ return join(home, '.claude', 'settings.json');
29
+ }
30
+ function getOpencodeSettingsPath() {
31
+ const home = getHomeDir();
32
+ return join(home, '.config', 'opencode', 'opencode.json');
33
+ }
34
+ function ensureDir(path) {
35
+ const dir = dirname(path);
36
+ if (!existsSync(dir)) {
37
+ mkdirSync(dir, { recursive: true });
38
+ }
39
+ }
40
+ function readJson(path) {
41
+ try {
42
+ if (existsSync(path)) {
43
+ return JSON.parse(readFileSync(path, 'utf-8'));
44
+ }
45
+ }
46
+ catch (e) { }
47
+ return {};
48
+ }
49
+ function writeJson(path, data) {
50
+ ensureDir(path);
51
+ writeFileSync(path, JSON.stringify(data, null, 2));
52
+ }
53
+ async function configureClaudeCode(port) {
54
+ log('\nšŸ“ Configuring Claude Code...', colors.cyan);
55
+ const settingsPath = getClaudeSettingsPath();
56
+ const settings = readJson(settingsPath);
57
+ settings.env = settings.env || {};
58
+ settings.env.ANTHROPIC_BASE_URL = `http://localhost:${port}`;
59
+ settings.env.ANTHROPIC_API_KEY = 'test-key';
60
+ writeJson(settingsPath, settings);
61
+ log('āœ… Claude Code configured!', colors.green);
62
+ log(` Settings: ${settingsPath}`, colors.yellow);
63
+ }
64
+ async function unconfigureClaudeCode() {
65
+ log('\nšŸ“ Removing Claude Code configuration...', colors.cyan);
66
+ const settingsPath = getClaudeSettingsPath();
67
+ const settings = readJson(settingsPath);
68
+ if (settings.env) {
69
+ delete settings.env.ANTHROPIC_BASE_URL;
70
+ delete settings.env.ANTHROPIC_API_KEY;
71
+ }
72
+ if (Object.keys(settings.env || {}).length === 0) {
73
+ delete settings.env;
74
+ }
75
+ if (Object.keys(settings).length > 0) {
76
+ writeJson(settingsPath, settings);
77
+ }
78
+ else if (existsSync(settingsPath)) {
79
+ const fs = await import('fs');
80
+ fs.unlinkSync(settingsPath);
81
+ }
82
+ log('āœ… Claude Code configuration removed!', colors.green);
83
+ }
84
+ function checkOpenCode() {
85
+ log('\nšŸ” Checking OpenCode...', colors.cyan);
86
+ try {
87
+ const result = execSync(OPENCODE_CMD + ' --version', { encoding: 'utf-8' });
88
+ log(`āœ… OpenCode found: ${result.trim()}`, colors.green);
89
+ return true;
90
+ }
91
+ catch (e) {
92
+ log('āŒ OpenCode not found!', colors.yellow);
93
+ log(' Install: npm install -g opencode-ai', colors.yellow);
94
+ return false;
95
+ }
96
+ }
97
+ async function startOpenCode() {
98
+ log('\nšŸš€ Starting OpenCode server...', colors.cyan);
99
+ return new Promise((resolve) => {
100
+ const proc = spawn(OPENCODE_CMD, ['serve', '--port', OPENCODE_PORT.toString()], {
101
+ stdio: 'pipe',
102
+ detached: false,
103
+ shell: true
104
+ });
105
+ proc.stdout.on('data', (data) => {
106
+ if (data.toString().includes('listening')) {
107
+ log('āœ… OpenCode server running on port ' + OPENCODE_PORT, colors.green);
108
+ resolve(proc);
109
+ }
110
+ });
111
+ proc.stderr.on('data', (data) => {
112
+ if (data.toString().includes('listening')) {
113
+ log('āœ… OpenCode server running on port ' + OPENCODE_PORT, colors.green);
114
+ resolve(proc);
115
+ }
116
+ });
117
+ setTimeout(() => resolve(proc), 3000);
118
+ });
119
+ }
120
+ async function startProxy() {
121
+ log('\nšŸš€ Starting Bridge server...', colors.cyan);
122
+ const proxyPath = join(__dirname, 'proxy.js');
123
+ return new Promise((resolve) => {
124
+ const proc = spawn('node', [proxyPath], {
125
+ stdio: 'pipe',
126
+ env: { ...process.env, PROXY_PORT: PROXY_PORT.toString() },
127
+ detached: false
128
+ });
129
+ proc.stdout.on('data', (data) => {
130
+ if (data.toString().includes('running')) {
131
+ log('āœ… Bridge server running!', colors.green);
132
+ resolve(proc);
133
+ }
134
+ });
135
+ proc.stderr.on('data', (data) => {
136
+ const str = data.toString();
137
+ if (str.includes('running')) {
138
+ log('āœ… Bridge server running!', colors.green);
139
+ resolve(proc);
140
+ }
141
+ console.error(str);
142
+ });
143
+ setTimeout(() => resolve(proc), 2000);
144
+ });
145
+ }
146
+ async function setup() {
147
+ log('\nšŸ› ļø Setting up OpenCode Bridge...', colors.blue);
148
+ // Check if OpenCode is installed
149
+ if (!checkOpenCode()) {
150
+ log('\nāš ļø Please install OpenCode first:', colors.yellow);
151
+ log(' npm install -g opencode-ai', colors.yellow);
152
+ process.exit(1);
153
+ }
154
+ // Configure Claude Code
155
+ await configureClaudeCode(PROXY_PORT);
156
+ log('\nāœ… Setup complete!', colors.green);
157
+ }
158
+ async function start() {
159
+ log('\nšŸš€ Starting OpenCode Bridge...', colors.blue);
160
+ // Check if OpenCode is installed
161
+ if (!checkOpenCode()) {
162
+ log('\nāš ļø Please install OpenCode first:', colors.yellow);
163
+ log(' npm install -g opencode-ai', colors.yellow);
164
+ process.exit(1);
165
+ }
166
+ // Start OpenCode server
167
+ await startOpenCode();
168
+ // Start proxy
169
+ await startProxy();
170
+ log('\n' + '='.repeat(50), colors.green);
171
+ log('šŸŽ‰ All services running!', colors.green);
172
+ log('='.repeat(50), colors.green);
173
+ log('\nšŸ“Š Dashboard: http://localhost:' + PROXY_PORT, colors.cyan);
174
+ log('šŸ¤– Claude Code: claude --print', colors.cyan);
175
+ log('\nPress Ctrl+C to stop all services\n', colors.yellow);
176
+ }
177
+ async function stop() {
178
+ log('\nšŸ›‘ Stopping OpenCode Bridge...', colors.yellow);
179
+ // Kill processes on ports
180
+ try {
181
+ execSync('taskkill /F /IM node.exe 2>nul', { stdio: 'ignore' });
182
+ }
183
+ catch (e) { }
184
+ try {
185
+ execSync('taskkill /F /IM opencode.exe 2>nul', { stdio: 'ignore' });
186
+ }
187
+ catch (e) { }
188
+ log('āœ… Services stopped!', colors.green);
189
+ }
190
+ async function remove() {
191
+ log('\nšŸ—‘ļø Removing OpenCode Bridge...', colors.yellow);
192
+ // Unconfigure Claude Code
193
+ await unconfigureClaudeCode();
194
+ log('āœ… Bridge removed from Claude Code!', colors.green);
195
+ }
196
+ // CLI Commands
197
+ const command = process.argv[2];
198
+ switch (command) {
199
+ case 'setup':
200
+ setup();
201
+ break;
202
+ case 'start':
203
+ start();
204
+ break;
205
+ case 'stop':
206
+ stop();
207
+ break;
208
+ case 'remove':
209
+ remove();
210
+ break;
211
+ case 'install':
212
+ setup().then(() => start());
213
+ break;
214
+ default:
215
+ log('\nšŸ“– OCB - OpenCode Bridge CLI', colors.blue);
216
+ log('\nUsage:', colors.cyan);
217
+ log(' ocb setup - Configure Claude Code', colors.reset);
218
+ log(' ocb start - Start all services', colors.reset);
219
+ log(' ocb install - Setup + Start (all in one)', colors.reset);
220
+ log(' ocb stop - Stop all services', colors.reset);
221
+ log(' ocb remove - Remove configuration', colors.reset);
222
+ log('\nOr run with npx:', colors.yellow);
223
+ log(' npx ocb install\n', colors.yellow);
224
+ process.exit(1);
225
+ }