vibora 8.2.0 → 8.3.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/server/index.js CHANGED
@@ -325,7 +325,8 @@ function getSettings() {
325
325
  cloudflareAccountId: parsed.integrations?.cloudflareAccountId ?? null
326
326
  },
327
327
  agent: {
328
- defaultAgent: parsed.agent?.defaultAgent ?? DEFAULT_SETTINGS.agent.defaultAgent
328
+ defaultAgent: parsed.agent?.defaultAgent ?? DEFAULT_SETTINGS.agent.defaultAgent,
329
+ opencodeModel: parsed.agent?.opencodeModel ?? null
329
330
  },
330
331
  appearance: {
331
332
  language: parsed.appearance?.language ?? null,
@@ -629,7 +630,8 @@ var init_settings = __esm(() => {
629
630
  cloudflareAccountId: null
630
631
  },
631
632
  agent: {
632
- defaultAgent: "claude"
633
+ defaultAgent: "claude",
634
+ opencodeModel: null
633
635
  },
634
636
  appearance: {
635
637
  language: null,
@@ -38761,6 +38763,7 @@ var tasks = sqliteTable("tasks", {
38761
38763
  agent: text("agent").notNull().default("claude"),
38762
38764
  aiMode: text("ai_mode"),
38763
38765
  agentOptions: text("agent_options"),
38766
+ opencodeModel: text("opencode_model"),
38764
38767
  createdAt: text("created_at").notNull(),
38765
38768
  updatedAt: text("updated_at").notNull()
38766
38769
  });
@@ -38804,6 +38807,7 @@ var repositories = sqliteTable("repositories", {
38804
38807
  copyFiles: text("copy_files"),
38805
38808
  claudeOptions: text("claude_options"),
38806
38809
  opencodeOptions: text("opencode_options"),
38810
+ opencodeModel: text("opencode_model"),
38807
38811
  defaultAgent: text("default_agent"),
38808
38812
  remoteUrl: text("remote_url"),
38809
38813
  isCopierTemplate: integer("is_copier_template", { mode: "boolean" }).default(false),
@@ -38936,6 +38940,7 @@ function runMigrations(sqlite, drizzleDb) {
38936
38940
  const hasTunnelsTable = sqlite.query("SELECT name FROM sqlite_master WHERE type='table' AND name='tunnels'").get();
38937
38941
  const hasAgentColumn = sqlite.query("SELECT name FROM pragma_table_info('tasks') WHERE name='agent'").get();
38938
38942
  const hasDefaultAgentColumn = sqlite.query("SELECT name FROM pragma_table_info('repositories') WHERE name='default_agent'").get();
38943
+ const hasOpencodeModelColumn = sqlite.query("SELECT name FROM pragma_table_info('repositories') WHERE name='opencode_model'").get();
38939
38944
  const migrationsToMark = [];
38940
38945
  for (const entry of journal.entries) {
38941
38946
  if (existingHashes.has(entry.tag))
@@ -38957,6 +38962,8 @@ function runMigrations(sqlite, drizzleDb) {
38957
38962
  shouldMark = true;
38958
38963
  } else if (entry.tag.startsWith("0019") && hasDefaultAgentColumn) {
38959
38964
  shouldMark = true;
38965
+ } else if (entry.tag.startsWith("0020") && hasOpencodeModelColumn) {
38966
+ shouldMark = true;
38960
38967
  }
38961
38968
  if (shouldMark) {
38962
38969
  migrationsToMark.push(entry);
@@ -169482,6 +169489,7 @@ app2.post("/", async (c) => {
169482
169489
  agent: body.agent || "claude",
169483
169490
  aiMode: body.aiMode || null,
169484
169491
  agentOptions: body.agentOptions ? JSON.stringify(body.agentOptions) : null,
169492
+ opencodeModel: body.opencodeModel || null,
169485
169493
  createdAt: now,
169486
169494
  updatedAt: now
169487
169495
  };
@@ -170817,6 +170825,7 @@ var CONFIG_KEYS = {
170817
170825
  LINEAR_API_KEY: "integrations.linearApiKey",
170818
170826
  GITHUB_PAT: "integrations.githubPat",
170819
170827
  DEFAULT_AGENT: "agent.defaultAgent",
170828
+ OPENCODE_MODEL: "agent.opencodeModel",
170820
170829
  LANGUAGE: "appearance.language",
170821
170830
  THEME: "appearance.theme",
170822
170831
  SYNC_CLAUDE_CODE_THEME: "appearance.syncClaudeCodeTheme",
@@ -171046,6 +171055,13 @@ app5.put("/:key", async (c) => {
171046
171055
  if (!validAgents.includes(value)) {
171047
171056
  return c.json({ error: `Default agent must be one of: ${validAgents.join(", ")}` }, 400);
171048
171057
  }
171058
+ } else if (path8 === CONFIG_KEYS.OPENCODE_MODEL) {
171059
+ if (value !== null && typeof value !== "string") {
171060
+ return c.json({ error: "OpenCode model must be a string or null" }, 400);
171061
+ }
171062
+ if (value === "") {
171063
+ value = null;
171064
+ }
171049
171065
  } else if (typeof value === "string" && value === "") {
171050
171066
  if (path8 === CONFIG_KEYS.LINEAR_API_KEY || path8 === CONFIG_KEYS.GITHUB_PAT || path8 === CONFIG_KEYS.REMOTE_HOST || path8 === CONFIG_KEYS.EDITOR_HOST) {
171051
171067
  value = null;
@@ -181108,6 +181124,143 @@ app18.post("/:name/run", (c) => {
181108
181124
  });
181109
181125
  var jobs_default = app18;
181110
181126
 
181127
+ // server/routes/opencode.ts
181128
+ init_logger2();
181129
+ import { spawn as spawn7 } from "child_process";
181130
+ var app19 = new Hono2;
181131
+ var PROVIDER_NAME_MAP = {
181132
+ "z.ai coding plan": "zai-coding-plan",
181133
+ anthropic: "anthropic",
181134
+ openai: "openai",
181135
+ google: "google",
181136
+ opencode: "opencode",
181137
+ groq: "groq",
181138
+ xai: "xai",
181139
+ deepseek: "deepseek",
181140
+ mistral: "mistral",
181141
+ azure: "azure",
181142
+ bedrock: "bedrock",
181143
+ vertex: "vertex",
181144
+ ollama: "ollama",
181145
+ openrouter: "openrouter",
181146
+ copilot: "copilot"
181147
+ };
181148
+ async function fetchConfiguredProviders() {
181149
+ return new Promise((resolve6) => {
181150
+ const proc2 = spawn7("opencode", ["auth", "list"], {
181151
+ timeout: 1e4,
181152
+ env: { ...process.env, NO_COLOR: "1" }
181153
+ });
181154
+ let stdout = "";
181155
+ proc2.stdout.on("data", (data) => {
181156
+ stdout += data.toString();
181157
+ });
181158
+ proc2.on("error", () => {
181159
+ resolve6([]);
181160
+ });
181161
+ proc2.on("close", (code) => {
181162
+ if (code !== 0) {
181163
+ resolve6([]);
181164
+ return;
181165
+ }
181166
+ const cleanOutput = stdout.replace(/\x1b\[[0-9;]*m/g, "");
181167
+ const providers = [];
181168
+ const lines = cleanOutput.split(`
181169
+ `);
181170
+ for (const line of lines) {
181171
+ const match3 = line.match(/[\u25CF\u25CB]\s+(.+?)\s+(api|oauth|token|key)\s*$/i);
181172
+ if (match3) {
181173
+ const displayName = match3[1].trim().toLowerCase();
181174
+ const providerId = PROVIDER_NAME_MAP[displayName] || displayName.replace(/\s+/g, "-");
181175
+ providers.push(providerId);
181176
+ log2.server.debug("Parsed configured provider", { displayName, providerId });
181177
+ }
181178
+ }
181179
+ log2.server.debug("Configured providers", { providers });
181180
+ resolve6(providers);
181181
+ });
181182
+ });
181183
+ }
181184
+ async function fetchOpencodeModels() {
181185
+ const configuredProviders = await fetchConfiguredProviders();
181186
+ return new Promise((resolve6) => {
181187
+ const proc2 = spawn7("opencode", ["models"], {
181188
+ timeout: 1e4,
181189
+ env: { ...process.env, NO_COLOR: "1" }
181190
+ });
181191
+ let stdout = "";
181192
+ let stderr = "";
181193
+ proc2.stdout.on("data", (data) => {
181194
+ stdout += data.toString();
181195
+ });
181196
+ proc2.stderr.on("data", (data) => {
181197
+ stderr += data.toString();
181198
+ });
181199
+ proc2.on("error", (err) => {
181200
+ log2.server.warn("opencode command not found", { error: err.message });
181201
+ resolve6({
181202
+ installed: false,
181203
+ providers: {},
181204
+ models: [],
181205
+ configuredProviders: []
181206
+ });
181207
+ });
181208
+ proc2.on("close", (code) => {
181209
+ if (code !== 0) {
181210
+ log2.server.warn("opencode models command failed", { code, stderr });
181211
+ resolve6({
181212
+ installed: false,
181213
+ providers: {},
181214
+ models: [],
181215
+ configuredProviders: []
181216
+ });
181217
+ return;
181218
+ }
181219
+ const lines = stdout.trim().split(`
181220
+ `).filter(Boolean);
181221
+ const allProviders = {};
181222
+ const allModels = [];
181223
+ for (const line of lines) {
181224
+ const trimmed = line.trim();
181225
+ if (!trimmed)
181226
+ continue;
181227
+ allModels.push(trimmed);
181228
+ const slashIndex = trimmed.indexOf("/");
181229
+ if (slashIndex > 0) {
181230
+ const provider = trimmed.substring(0, slashIndex);
181231
+ const model = trimmed.substring(slashIndex + 1);
181232
+ if (!allProviders[provider]) {
181233
+ allProviders[provider] = [];
181234
+ }
181235
+ allProviders[provider].push(model);
181236
+ }
181237
+ }
181238
+ const hasConfigured = configuredProviders.length > 0;
181239
+ const providers = {};
181240
+ const models = [];
181241
+ for (const [provider, providerModels] of Object.entries(allProviders)) {
181242
+ if (!hasConfigured || configuredProviders.includes(provider)) {
181243
+ providers[provider] = providerModels;
181244
+ for (const model of providerModels) {
181245
+ models.push(`${provider}/${model}`);
181246
+ }
181247
+ }
181248
+ }
181249
+ resolve6({
181250
+ installed: true,
181251
+ providers,
181252
+ models,
181253
+ configuredProviders
181254
+ });
181255
+ });
181256
+ });
181257
+ }
181258
+ app19.get("/models", async (c) => {
181259
+ const result = await fetchOpencodeModels();
181260
+ return c.json(result);
181261
+ });
181262
+ var opencode_default = app19;
181263
+
181111
181264
  // server/app.ts
181112
181265
  init_logger2();
181113
181266
  function getDistPath() {
@@ -181117,40 +181270,41 @@ function getDistPath() {
181117
181270
  return join25(process.cwd(), "dist");
181118
181271
  }
181119
181272
  function createApp() {
181120
- const app19 = new Hono2;
181121
- app19.use("*", logger());
181122
- app19.use("*", cors({
181273
+ const app20 = new Hono2;
181274
+ app20.use("*", logger());
181275
+ app20.use("*", cors({
181123
181276
  origin: "*",
181124
181277
  allowMethods: ["GET", "POST", "PATCH", "PUT", "DELETE", "OPTIONS"],
181125
181278
  allowHeaders: ["Content-Type"]
181126
181279
  }));
181127
- app19.route("/health", health_default);
181128
- app19.route("/api/tasks", tasks_default);
181129
- app19.route("/api/git", git_default);
181130
- app19.route("/api/fs", filesystem_default);
181131
- app19.route("/api/config", config_default);
181132
- app19.route("/api/uploads", uploads_default);
181133
- app19.route("/api/worktrees", worktrees_default);
181134
- app19.route("/api/terminal-view-state", terminal_view_state_default);
181135
- app19.route("/api/repositories", repositories_default);
181136
- app19.route("/api/copier", copier_default);
181137
- app19.route("/api/linear", linear_default);
181138
- app19.route("/api/github", github_default);
181139
- app19.route("/api/monitoring", monitoringRoutes);
181140
- app19.route("/api/system", system_default);
181141
- app19.route("/api/exec", exec_default);
181142
- app19.route("/api/apps", apps_default);
181143
- app19.route("/api/compose", compose_default);
181144
- app19.route("/api/deployment", deployment_default);
181145
- app19.route("/api/jobs", jobs_default);
181146
- app19.post("/api/logs", async (c) => {
181280
+ app20.route("/health", health_default);
181281
+ app20.route("/api/tasks", tasks_default);
181282
+ app20.route("/api/git", git_default);
181283
+ app20.route("/api/fs", filesystem_default);
181284
+ app20.route("/api/config", config_default);
181285
+ app20.route("/api/uploads", uploads_default);
181286
+ app20.route("/api/worktrees", worktrees_default);
181287
+ app20.route("/api/terminal-view-state", terminal_view_state_default);
181288
+ app20.route("/api/repositories", repositories_default);
181289
+ app20.route("/api/copier", copier_default);
181290
+ app20.route("/api/linear", linear_default);
181291
+ app20.route("/api/github", github_default);
181292
+ app20.route("/api/monitoring", monitoringRoutes);
181293
+ app20.route("/api/system", system_default);
181294
+ app20.route("/api/exec", exec_default);
181295
+ app20.route("/api/apps", apps_default);
181296
+ app20.route("/api/compose", compose_default);
181297
+ app20.route("/api/deployment", deployment_default);
181298
+ app20.route("/api/jobs", jobs_default);
181299
+ app20.route("/api/opencode", opencode_default);
181300
+ app20.post("/api/logs", async (c) => {
181147
181301
  const { entries } = await c.req.json();
181148
181302
  for (const entry of entries) {
181149
181303
  writeEntry(entry);
181150
181304
  }
181151
181305
  return c.json({ ok: true });
181152
181306
  });
181153
- app19.post("/api/debug", async (c) => {
181307
+ app20.post("/api/debug", async (c) => {
181154
181308
  const body = await c.req.json();
181155
181309
  const entry = {
181156
181310
  ts: new Date().toISOString(),
@@ -181187,14 +181341,14 @@ function createApp() {
181187
181341
  headers: { "Content-Type": mimeTypes2[ext2 || ""] || "application/octet-stream" }
181188
181342
  });
181189
181343
  };
181190
- app19.get("/assets/*", async (c) => {
181344
+ app20.get("/assets/*", async (c) => {
181191
181345
  const assetPath = join25(distPath, c.req.path);
181192
181346
  if (existsSync18(assetPath)) {
181193
181347
  return serveFile(assetPath);
181194
181348
  }
181195
181349
  return c.notFound();
181196
181350
  });
181197
- app19.get("/sounds/*", async (c) => {
181351
+ app20.get("/sounds/*", async (c) => {
181198
181352
  const soundPath = join25(distPath, c.req.path);
181199
181353
  if (existsSync18(soundPath)) {
181200
181354
  return serveFile(soundPath);
@@ -181203,7 +181357,7 @@ function createApp() {
181203
181357
  });
181204
181358
  const staticFiles = ["vibora-icon.png", "vibora-logo.jpeg", "vite.svg", "logo.png", "goat.jpeg"];
181205
181359
  for (const file of staticFiles) {
181206
- app19.get(`/${file}`, async () => {
181360
+ app20.get(`/${file}`, async () => {
181207
181361
  const filePath = join25(distPath, file);
181208
181362
  if (existsSync18(filePath)) {
181209
181363
  return serveFile(filePath);
@@ -181211,7 +181365,7 @@ function createApp() {
181211
181365
  return new Response("Not Found", { status: 404 });
181212
181366
  });
181213
181367
  }
181214
- app19.get("*", async (c, next) => {
181368
+ app20.get("*", async (c, next) => {
181215
181369
  const path10 = c.req.path;
181216
181370
  if (path10.startsWith("/api/") || path10.startsWith("/ws/") || path10 === "/health") {
181217
181371
  return next();
@@ -181220,7 +181374,7 @@ function createApp() {
181220
181374
  return c.html(html);
181221
181375
  });
181222
181376
  }
181223
- return app19;
181377
+ return app20;
181224
181378
  }
181225
181379
 
181226
181380
  // server/index.ts
@@ -181330,11 +181484,11 @@ setBroadcastDestroyed((terminalId) => {
181330
181484
  payload: { terminalId }
181331
181485
  });
181332
181486
  });
181333
- var app19 = createApp();
181334
- var { injectWebSocket, upgradeWebSocket } = createNodeWebSocket({ app: app19 });
181335
- app19.get("/ws/terminal", upgradeWebSocket(() => terminalWebSocketHandlers));
181487
+ var app20 = createApp();
181488
+ var { injectWebSocket, upgradeWebSocket } = createNodeWebSocket({ app: app20 });
181489
+ app20.get("/ws/terminal", upgradeWebSocket(() => terminalWebSocketHandlers));
181336
181490
  var server = serve({
181337
- fetch: app19.fetch,
181491
+ fetch: app20.fetch,
181338
181492
  port: PORT,
181339
181493
  hostname: HOST
181340
181494
  }, (info) => {