ocb-cli 1.0.3 → 1.0.4

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/dist/proxy.js CHANGED
@@ -111,7 +111,8 @@ app.use(express.json());
111
111
  app.use((req, res, next) => {
112
112
  res.header("Access-Control-Allow-Origin", "*");
113
113
  res.header("Access-Control-Allow-Methods", "GET, POST, PUT, DELETE, OPTIONS");
114
- res.header("Access-Control-Allow-Headers", "Content-Type, Authorization");
114
+ res.header("Access-Control-Allow-Headers", "Content-Type, Authorization, x-api-key");
115
+ res.header("Content-Type", "application/json");
115
116
  if (req.method === "OPTIONS")
116
117
  return res.sendStatus(200);
117
118
  next();
@@ -160,16 +161,77 @@ app.post("/api/reset-stats", (req, res) => {
160
161
  totalRequests = 0;
161
162
  res.json({ success: true });
162
163
  });
164
+ const modelAliases = {
165
+ "claude-opus-4-5": "opencode/minimax-m2.5-free",
166
+ "claude-opus-4-5-thinking": "opencode/minimax-m2.5-free",
167
+ "claude-opus-4-6": "opencode/minimax-m2.5-free",
168
+ "claude-opus-4-6-thinking": "opencode/minimax-m2.5-free",
169
+ "claude-sonnet-4-5": "opencode/minimax-m2.5-free",
170
+ "claude-sonnet-4-5-thinking": "opencode/minimax-m2.5-free",
171
+ "claude-sonnet-4-5-20250929": "opencode/minimax-m2.5-free",
172
+ "claude-sonnet-4-5-20250929-thinking": "opencode/minimax-m2.5-free",
173
+ "claude-haiku-4-5": "opencode/minimax-m2.5-free",
174
+ "claude-haiku-4-5-20251001": "opencode/minimax-m2.5-free",
175
+ };
163
176
  app.post("/api/reset-session", async (req, res) => {
164
177
  currentSessionId = await createSession(process.cwd());
165
178
  res.json({ success: true, sessionId: currentSessionId });
166
179
  });
167
180
  app.get("/v1/authenticate", (req, res) => res.json({ type: "authentication", authenticated: true }));
168
181
  app.get("/v1/whoami", (req, res) => res.json({ type: "user", id: "opencode-user", email: "opencode@local" }));
169
- app.get("/v1/models", (req, res) => res.json({ data: availableModels.map(m => ({ id: m.id, type: "model", name: m.name, supports_cached_previews: true, supports_system_instructions: true })) }));
170
- app.get("/v1/models/list", (req, res) => res.json({ data: availableModels.map(m => ({ id: m.id, type: "model", name: m.name, supports_cached_previews: true, supports_system_instructions: true })) }));
182
+ app.get("/v1/models", (req, res) => {
183
+ const aliasModels = Object.keys(modelAliases).map(id => ({
184
+ id,
185
+ type: "model",
186
+ name: id,
187
+ display_name: id,
188
+ supports_cached_previews: true,
189
+ supports_system_instructions: true,
190
+ supports_reasoning: true,
191
+ supports_vision: false
192
+ }));
193
+ const allModels = [...aliasModels, ...availableModels.map(m => ({
194
+ id: m.id,
195
+ type: "model",
196
+ name: m.name,
197
+ display_name: m.name,
198
+ supports_cached_previews: true,
199
+ supports_system_instructions: true,
200
+ supports_reasoning: true,
201
+ supports_vision: false
202
+ }))];
203
+ res.json({ data: allModels });
204
+ });
205
+ app.get("/v1/models/list", (req, res) => {
206
+ const aliasModels = Object.keys(modelAliases).map(id => ({
207
+ id,
208
+ type: "model",
209
+ name: id,
210
+ display_name: id,
211
+ supports_cached_previews: true,
212
+ supports_system_instructions: true,
213
+ supports_reasoning: true,
214
+ supports_vision: false
215
+ }));
216
+ const allModels = [...aliasModels, ...availableModels.map(m => ({
217
+ id: m.id,
218
+ type: "model",
219
+ name: m.name,
220
+ display_name: m.name,
221
+ supports_cached_previews: true,
222
+ supports_system_instructions: true,
223
+ supports_reasoning: true,
224
+ supports_vision: false
225
+ }))];
226
+ res.json({ data: allModels });
227
+ });
171
228
  app.post("/v1/messages", async (req, res) => {
172
229
  try {
230
+ const requestedModel = req.body?.model || currentModel;
231
+ const actualModel = modelAliases[requestedModel] || requestedModel;
232
+ if (modelAliases[requestedModel]) {
233
+ currentModel = modelAliases[requestedModel];
234
+ }
173
235
  if (req.body?.max_tokens === undefined && req.body?.messages) {
174
236
  let totalTokens = 0;
175
237
  for (const msg of req.body.messages) {
@@ -182,7 +244,7 @@ app.post("/v1/messages", async (req, res) => {
182
244
  const { text, tokens } = await sendMessage(currentSessionId, req.body.messages);
183
245
  totalRequests++;
184
246
  totalTokensUsed += tokens;
185
- res.json({ id: `msg_${Date.now()}`, type: "message", role: "assistant", content: [{ type: "text", text }], model: currentModel, stop_reason: "end_turn", usage: { input_tokens: Math.ceil(JSON.stringify(req.body.messages).length / 4), output_tokens: Math.ceil(text.length / 4) } });
247
+ res.json({ id: `msg_${Date.now()}`, type: "message", role: "assistant", content: [{ type: "text", text }], model: actualModel, stop_reason: "end_turn", usage: { input_tokens: Math.ceil(JSON.stringify(req.body.messages).length / 4), output_tokens: Math.ceil(text.length / 4) } });
186
248
  }
187
249
  catch (error) {
188
250
  res.status(500).json({ error: { type: "api_error", message: error instanceof Error ? error.message : String(error) } });
@@ -332,9 +394,9 @@ function generateHTML() {
332
394
  <div class="bg-zinc-950 rounded-xl p-4 font-mono text-sm text-zinc-300 overflow-x-auto">
333
395
  <pre id="configJson">{
334
396
  "env": {
335
- "ANTHROPIC_BASE_URL": "http://localhost:8300/v1",
336
- "ANTHROPIC_AUTH_TOKEN": "test",
337
- "ANTHROPIC_MODEL": "minimax-m2.5-free"
397
+ "ANTHROPIC_BASE_URL": "http://localhost:8300",
398
+ "ANTHROPIC_API_KEY": "test",
399
+ "ANTHROPIC_MODEL": "claude-sonnet-4-5"
338
400
  }
339
401
  }</pre>
340
402
  </div>
@@ -462,7 +524,7 @@ function generateHTML() {
462
524
  currentModelId = modelId;
463
525
  loadStatus();
464
526
  renderModels(currentProvider === 'all' ? allModels : (groupedModels[currentProvider] || []));
465
- document.getElementById('configJson').textContent = JSON.stringify({ env: { ANTHROPIC_BASE_URL: "http://localhost:8300/v1", ANTHROPIC_AUTH_TOKEN: "test", ANTHROPIC_MODEL: modelId } }, null, 2);
527
+ document.getElementById('configJson').textContent = JSON.stringify({ env: { ANTHROPIC_BASE_URL: "http://localhost:8300", ANTHROPIC_API_KEY: "test", ANTHROPIC_MODEL: modelId } }, null, 2);
466
528
  }
467
529
  }
468
530
 
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "ocb-cli",
3
- "version": "1.0.3",
3
+ "version": "1.0.4",
4
4
  "description": "OpenCode Bridge - Use OpenCode AI models in Claude Code",
5
5
  "type": "module",
6
6
  "main": "dist/proxy.js",
package/src/proxy.ts CHANGED
@@ -139,7 +139,8 @@ app.use(express.json());
139
139
  app.use((req, res, next) => {
140
140
  res.header("Access-Control-Allow-Origin", "*");
141
141
  res.header("Access-Control-Allow-Methods", "GET, POST, PUT, DELETE, OPTIONS");
142
- res.header("Access-Control-Allow-Headers", "Content-Type, Authorization");
142
+ res.header("Access-Control-Allow-Headers", "Content-Type, Authorization, x-api-key");
143
+ res.header("Content-Type", "application/json");
143
144
  if (req.method === "OPTIONS") return res.sendStatus(200);
144
145
  next();
145
146
  });
@@ -193,6 +194,19 @@ app.post("/api/reset-stats", (req, res) => {
193
194
  res.json({ success: true });
194
195
  });
195
196
 
197
+ const modelAliases: Record<string, string> = {
198
+ "claude-opus-4-5": "opencode/minimax-m2.5-free",
199
+ "claude-opus-4-5-thinking": "opencode/minimax-m2.5-free",
200
+ "claude-opus-4-6": "opencode/minimax-m2.5-free",
201
+ "claude-opus-4-6-thinking": "opencode/minimax-m2.5-free",
202
+ "claude-sonnet-4-5": "opencode/minimax-m2.5-free",
203
+ "claude-sonnet-4-5-thinking": "opencode/minimax-m2.5-free",
204
+ "claude-sonnet-4-5-20250929": "opencode/minimax-m2.5-free",
205
+ "claude-sonnet-4-5-20250929-thinking": "opencode/minimax-m2.5-free",
206
+ "claude-haiku-4-5": "opencode/minimax-m2.5-free",
207
+ "claude-haiku-4-5-20251001": "opencode/minimax-m2.5-free",
208
+ };
209
+
196
210
  app.post("/api/reset-session", async (req, res) => {
197
211
  currentSessionId = await createSession(process.cwd());
198
212
  res.json({ success: true, sessionId: currentSessionId });
@@ -201,11 +215,62 @@ app.post("/api/reset-session", async (req, res) => {
201
215
  app.get("/v1/authenticate", (req, res) => res.json({ type: "authentication", authenticated: true }));
202
216
  app.get("/v1/whoami", (req, res) => res.json({ type: "user", id: "opencode-user", email: "opencode@local" }));
203
217
 
204
- app.get("/v1/models", (req, res) => res.json({ data: availableModels.map(m => ({ id: m.id, type: "model", name: m.name, supports_cached_previews: true, supports_system_instructions: true })) }));
205
- app.get("/v1/models/list", (req, res) => res.json({ data: availableModels.map(m => ({ id: m.id, type: "model", name: m.name, supports_cached_previews: true, supports_system_instructions: true })) }));
218
+ app.get("/v1/models", (req, res) => {
219
+ const aliasModels = Object.keys(modelAliases).map(id => ({
220
+ id,
221
+ type: "model" as const,
222
+ name: id,
223
+ display_name: id,
224
+ supports_cached_previews: true,
225
+ supports_system_instructions: true,
226
+ supports_reasoning: true,
227
+ supports_vision: false
228
+ }));
229
+ const allModels = [...aliasModels, ...availableModels.map(m => ({
230
+ id: m.id,
231
+ type: "model" as const,
232
+ name: m.name,
233
+ display_name: m.name,
234
+ supports_cached_previews: true,
235
+ supports_system_instructions: true,
236
+ supports_reasoning: true,
237
+ supports_vision: false
238
+ }))];
239
+ res.json({ data: allModels });
240
+ });
241
+ app.get("/v1/models/list", (req, res) => {
242
+ const aliasModels = Object.keys(modelAliases).map(id => ({
243
+ id,
244
+ type: "model" as const,
245
+ name: id,
246
+ display_name: id,
247
+ supports_cached_previews: true,
248
+ supports_system_instructions: true,
249
+ supports_reasoning: true,
250
+ supports_vision: false
251
+ }));
252
+ const allModels = [...aliasModels, ...availableModels.map(m => ({
253
+ id: m.id,
254
+ type: "model" as const,
255
+ name: m.name,
256
+ display_name: m.name,
257
+ supports_cached_previews: true,
258
+ supports_system_instructions: true,
259
+ supports_reasoning: true,
260
+ supports_vision: false
261
+ }))];
262
+ res.json({ data: allModels });
263
+ });
206
264
 
207
265
  app.post("/v1/messages", async (req, res) => {
208
266
  try {
267
+ const requestedModel = req.body?.model || currentModel;
268
+ const actualModel = modelAliases[requestedModel] || requestedModel;
269
+
270
+ if (modelAliases[requestedModel]) {
271
+ currentModel = modelAliases[requestedModel];
272
+ }
273
+
209
274
  if (req.body?.max_tokens === undefined && req.body?.messages) {
210
275
  let totalTokens = 0;
211
276
  for (const msg of req.body.messages) {
@@ -217,7 +282,7 @@ app.post("/v1/messages", async (req, res) => {
217
282
  const { text, tokens } = await sendMessage(currentSessionId, req.body.messages);
218
283
  totalRequests++;
219
284
  totalTokensUsed += tokens;
220
- res.json({ id: `msg_${Date.now()}`, type: "message", role: "assistant", content: [{ type: "text", text }], model: currentModel, stop_reason: "end_turn", usage: { input_tokens: Math.ceil(JSON.stringify(req.body.messages).length / 4), output_tokens: Math.ceil(text.length / 4) } });
285
+ res.json({ id: `msg_${Date.now()}`, type: "message", role: "assistant", content: [{ type: "text", text }], model: actualModel, stop_reason: "end_turn", usage: { input_tokens: Math.ceil(JSON.stringify(req.body.messages).length / 4), output_tokens: Math.ceil(text.length / 4) } });
221
286
  } catch (error) {
222
287
  res.status(500).json({ error: { type: "api_error", message: error instanceof Error ? error.message : String(error) } });
223
288
  }
@@ -368,9 +433,9 @@ function generateHTML() {
368
433
  <div class="bg-zinc-950 rounded-xl p-4 font-mono text-sm text-zinc-300 overflow-x-auto">
369
434
  <pre id="configJson">{
370
435
  "env": {
371
- "ANTHROPIC_BASE_URL": "http://localhost:8300/v1",
372
- "ANTHROPIC_AUTH_TOKEN": "test",
373
- "ANTHROPIC_MODEL": "minimax-m2.5-free"
436
+ "ANTHROPIC_BASE_URL": "http://localhost:8300",
437
+ "ANTHROPIC_API_KEY": "test",
438
+ "ANTHROPIC_MODEL": "claude-sonnet-4-5"
374
439
  }
375
440
  }</pre>
376
441
  </div>
@@ -498,7 +563,7 @@ function generateHTML() {
498
563
  currentModelId = modelId;
499
564
  loadStatus();
500
565
  renderModels(currentProvider === 'all' ? allModels : (groupedModels[currentProvider] || []));
501
- document.getElementById('configJson').textContent = JSON.stringify({ env: { ANTHROPIC_BASE_URL: "http://localhost:8300/v1", ANTHROPIC_AUTH_TOKEN: "test", ANTHROPIC_MODEL: modelId } }, null, 2);
566
+ document.getElementById('configJson').textContent = JSON.stringify({ env: { ANTHROPIC_BASE_URL: "http://localhost:8300", ANTHROPIC_API_KEY: "test", ANTHROPIC_MODEL: modelId } }, null, 2);
502
567
  }
503
568
  }
504
569