vibora 3.6.0 → 3.7.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
@@ -7683,7 +7683,7 @@ var require_public_api = __commonJS((exports) => {
7683
7683
  }
7684
7684
  return doc;
7685
7685
  }
7686
- function parse2(src, reviver, options) {
7686
+ function parse(src, reviver, options) {
7687
7687
  let _reviver = undefined;
7688
7688
  if (typeof reviver === "function") {
7689
7689
  _reviver = reviver;
@@ -7724,7 +7724,7 @@ var require_public_api = __commonJS((exports) => {
7724
7724
  return value.toString(options);
7725
7725
  return new Document2.Document(value, _replacer, options).toString(options);
7726
7726
  }
7727
- exports.parse = parse2;
7727
+ exports.parse = parse;
7728
7728
  exports.parseAllDocuments = parseAllDocuments;
7729
7729
  exports.parseDocument = parseDocument;
7730
7730
  exports.stringify = stringify;
@@ -8511,29 +8511,6 @@ var compose = (middleware, onError, onNotFound) => {
8511
8511
  };
8512
8512
  };
8513
8513
 
8514
- // node_modules/hono/dist/http-exception.js
8515
- var HTTPException = class extends Error {
8516
- res;
8517
- status;
8518
- constructor(status = 500, options) {
8519
- super(options?.message, { cause: options?.cause });
8520
- this.res = options?.res;
8521
- this.status = status;
8522
- }
8523
- getResponse() {
8524
- if (this.res) {
8525
- const newResponse = new Response(this.res.body, {
8526
- status: this.status,
8527
- headers: this.res.headers
8528
- });
8529
- return newResponse;
8530
- }
8531
- return new Response(this.message, {
8532
- status: this.status
8533
- });
8534
- }
8535
- };
8536
-
8537
8514
  // node_modules/hono/dist/request/constants.js
8538
8515
  var GET_MATCH_RESULT = /* @__PURE__ */ Symbol();
8539
8516
 
@@ -10152,873 +10129,6 @@ var logger = (fn = console.log) => {
10152
10129
  };
10153
10130
  };
10154
10131
 
10155
- // node_modules/hono/dist/helper/factory/index.js
10156
- var Factory = class {
10157
- initApp;
10158
- #defaultAppOptions;
10159
- constructor(init) {
10160
- this.initApp = init?.initApp;
10161
- this.#defaultAppOptions = init?.defaultAppOptions;
10162
- }
10163
- createApp = (options) => {
10164
- const app = new Hono2(options && this.#defaultAppOptions ? { ...this.#defaultAppOptions, ...options } : options ?? this.#defaultAppOptions);
10165
- if (this.initApp) {
10166
- this.initApp(app);
10167
- }
10168
- return app;
10169
- };
10170
- createMiddleware = (middleware) => middleware;
10171
- createHandlers = (...handlers) => {
10172
- return handlers.filter((handler) => handler !== undefined);
10173
- };
10174
- };
10175
- var createMiddleware = (middleware) => middleware;
10176
-
10177
- // node_modules/hono/dist/utils/cookie.js
10178
- var algorithm = { name: "HMAC", hash: "SHA-256" };
10179
- var getCryptoKey = async (secret) => {
10180
- const secretBuf = typeof secret === "string" ? new TextEncoder().encode(secret) : secret;
10181
- return await crypto.subtle.importKey("raw", secretBuf, algorithm, false, ["sign", "verify"]);
10182
- };
10183
- var makeSignature = async (value, secret) => {
10184
- const key = await getCryptoKey(secret);
10185
- const signature = await crypto.subtle.sign(algorithm.name, key, new TextEncoder().encode(value));
10186
- return btoa(String.fromCharCode(...new Uint8Array(signature)));
10187
- };
10188
- var verifySignature = async (base64Signature, value, secret) => {
10189
- try {
10190
- const signatureBinStr = atob(base64Signature);
10191
- const signature = new Uint8Array(signatureBinStr.length);
10192
- for (let i = 0, len = signatureBinStr.length;i < len; i++) {
10193
- signature[i] = signatureBinStr.charCodeAt(i);
10194
- }
10195
- return await crypto.subtle.verify(algorithm, secret, signature, new TextEncoder().encode(value));
10196
- } catch {
10197
- return false;
10198
- }
10199
- };
10200
- var validCookieNameRegEx = /^[\w!#$%&'*.^`|~+-]+$/;
10201
- var validCookieValueRegEx = /^[ !#-:<-[\]-~]*$/;
10202
- var parse = (cookie, name) => {
10203
- if (name && cookie.indexOf(name) === -1) {
10204
- return {};
10205
- }
10206
- const pairs = cookie.trim().split(";");
10207
- const parsedCookie = {};
10208
- for (let pairStr of pairs) {
10209
- pairStr = pairStr.trim();
10210
- const valueStartPos = pairStr.indexOf("=");
10211
- if (valueStartPos === -1) {
10212
- continue;
10213
- }
10214
- const cookieName = pairStr.substring(0, valueStartPos).trim();
10215
- if (name && name !== cookieName || !validCookieNameRegEx.test(cookieName)) {
10216
- continue;
10217
- }
10218
- let cookieValue = pairStr.substring(valueStartPos + 1).trim();
10219
- if (cookieValue.startsWith('"') && cookieValue.endsWith('"')) {
10220
- cookieValue = cookieValue.slice(1, -1);
10221
- }
10222
- if (validCookieValueRegEx.test(cookieValue)) {
10223
- parsedCookie[cookieName] = cookieValue.indexOf("%") !== -1 ? tryDecode(cookieValue, decodeURIComponent_) : cookieValue;
10224
- if (name) {
10225
- break;
10226
- }
10227
- }
10228
- }
10229
- return parsedCookie;
10230
- };
10231
- var parseSigned = async (cookie, secret, name) => {
10232
- const parsedCookie = {};
10233
- const secretKey = await getCryptoKey(secret);
10234
- for (const [key, value] of Object.entries(parse(cookie, name))) {
10235
- const signatureStartPos = value.lastIndexOf(".");
10236
- if (signatureStartPos < 1) {
10237
- continue;
10238
- }
10239
- const signedValue = value.substring(0, signatureStartPos);
10240
- const signature = value.substring(signatureStartPos + 1);
10241
- if (signature.length !== 44 || !signature.endsWith("=")) {
10242
- continue;
10243
- }
10244
- const isVerified = await verifySignature(signature, signedValue, secretKey);
10245
- parsedCookie[key] = isVerified ? signedValue : false;
10246
- }
10247
- return parsedCookie;
10248
- };
10249
- var _serialize = (name, value, opt = {}) => {
10250
- let cookie = `${name}=${value}`;
10251
- if (name.startsWith("__Secure-") && !opt.secure) {
10252
- throw new Error("__Secure- Cookie must have Secure attributes");
10253
- }
10254
- if (name.startsWith("__Host-")) {
10255
- if (!opt.secure) {
10256
- throw new Error("__Host- Cookie must have Secure attributes");
10257
- }
10258
- if (opt.path !== "/") {
10259
- throw new Error('__Host- Cookie must have Path attributes with "/"');
10260
- }
10261
- if (opt.domain) {
10262
- throw new Error("__Host- Cookie must not have Domain attributes");
10263
- }
10264
- }
10265
- if (opt && typeof opt.maxAge === "number" && opt.maxAge >= 0) {
10266
- if (opt.maxAge > 34560000) {
10267
- throw new Error("Cookies Max-Age SHOULD NOT be greater than 400 days (34560000 seconds) in duration.");
10268
- }
10269
- cookie += `; Max-Age=${opt.maxAge | 0}`;
10270
- }
10271
- if (opt.domain && opt.prefix !== "host") {
10272
- cookie += `; Domain=${opt.domain}`;
10273
- }
10274
- if (opt.path) {
10275
- cookie += `; Path=${opt.path}`;
10276
- }
10277
- if (opt.expires) {
10278
- if (opt.expires.getTime() - Date.now() > 34560000000) {
10279
- throw new Error("Cookies Expires SHOULD NOT be greater than 400 days (34560000 seconds) in the future.");
10280
- }
10281
- cookie += `; Expires=${opt.expires.toUTCString()}`;
10282
- }
10283
- if (opt.httpOnly) {
10284
- cookie += "; HttpOnly";
10285
- }
10286
- if (opt.secure) {
10287
- cookie += "; Secure";
10288
- }
10289
- if (opt.sameSite) {
10290
- cookie += `; SameSite=${opt.sameSite.charAt(0).toUpperCase() + opt.sameSite.slice(1)}`;
10291
- }
10292
- if (opt.priority) {
10293
- cookie += `; Priority=${opt.priority.charAt(0).toUpperCase() + opt.priority.slice(1)}`;
10294
- }
10295
- if (opt.partitioned) {
10296
- if (!opt.secure) {
10297
- throw new Error("Partitioned Cookie must have Secure attributes");
10298
- }
10299
- cookie += "; Partitioned";
10300
- }
10301
- return cookie;
10302
- };
10303
- var serialize = (name, value, opt) => {
10304
- value = encodeURIComponent(value);
10305
- return _serialize(name, value, opt);
10306
- };
10307
- var serializeSigned = async (name, value, secret, opt = {}) => {
10308
- const signature = await makeSignature(value, secret);
10309
- value = `${value}.${signature}`;
10310
- value = encodeURIComponent(value);
10311
- return _serialize(name, value, opt);
10312
- };
10313
-
10314
- // node_modules/hono/dist/helper/cookie/index.js
10315
- var getCookie = (c, key, prefix) => {
10316
- const cookie = c.req.raw.headers.get("Cookie");
10317
- if (typeof key === "string") {
10318
- if (!cookie) {
10319
- return;
10320
- }
10321
- let finalKey = key;
10322
- if (prefix === "secure") {
10323
- finalKey = "__Secure-" + key;
10324
- } else if (prefix === "host") {
10325
- finalKey = "__Host-" + key;
10326
- }
10327
- const obj2 = parse(cookie, finalKey);
10328
- return obj2[finalKey];
10329
- }
10330
- if (!cookie) {
10331
- return {};
10332
- }
10333
- const obj = parse(cookie);
10334
- return obj;
10335
- };
10336
- var getSignedCookie = async (c, secret, key, prefix) => {
10337
- const cookie = c.req.raw.headers.get("Cookie");
10338
- if (typeof key === "string") {
10339
- if (!cookie) {
10340
- return;
10341
- }
10342
- let finalKey = key;
10343
- if (prefix === "secure") {
10344
- finalKey = "__Secure-" + key;
10345
- } else if (prefix === "host") {
10346
- finalKey = "__Host-" + key;
10347
- }
10348
- const obj2 = await parseSigned(cookie, secret, finalKey);
10349
- return obj2[finalKey];
10350
- }
10351
- if (!cookie) {
10352
- return {};
10353
- }
10354
- const obj = await parseSigned(cookie, secret);
10355
- return obj;
10356
- };
10357
- var generateCookie = (name, value, opt) => {
10358
- let cookie;
10359
- if (opt?.prefix === "secure") {
10360
- cookie = serialize("__Secure-" + name, value, { path: "/", ...opt, secure: true });
10361
- } else if (opt?.prefix === "host") {
10362
- cookie = serialize("__Host-" + name, value, {
10363
- ...opt,
10364
- path: "/",
10365
- secure: true,
10366
- domain: undefined
10367
- });
10368
- } else {
10369
- cookie = serialize(name, value, { path: "/", ...opt });
10370
- }
10371
- return cookie;
10372
- };
10373
- var setCookie = (c, name, value, opt) => {
10374
- const cookie = generateCookie(name, value, opt);
10375
- c.header("Set-Cookie", cookie, { append: true });
10376
- };
10377
- var generateSignedCookie = async (name, value, secret, opt) => {
10378
- let cookie;
10379
- if (opt?.prefix === "secure") {
10380
- cookie = await serializeSigned("__Secure-" + name, value, secret, {
10381
- path: "/",
10382
- ...opt,
10383
- secure: true
10384
- });
10385
- } else if (opt?.prefix === "host") {
10386
- cookie = await serializeSigned("__Host-" + name, value, secret, {
10387
- ...opt,
10388
- path: "/",
10389
- secure: true,
10390
- domain: undefined
10391
- });
10392
- } else {
10393
- cookie = await serializeSigned(name, value, secret, { path: "/", ...opt });
10394
- }
10395
- return cookie;
10396
- };
10397
- var setSignedCookie = async (c, name, value, secret, opt) => {
10398
- const cookie = await generateSignedCookie(name, value, secret, opt);
10399
- c.header("set-cookie", cookie, { append: true });
10400
- };
10401
- var deleteCookie = (c, name, opt) => {
10402
- const deletedCookie = getCookie(c, name, opt?.prefix);
10403
- setCookie(c, name, "", { ...opt, maxAge: 0 });
10404
- return deletedCookie;
10405
- };
10406
-
10407
- // server/lib/settings.ts
10408
- import * as fs from "fs";
10409
- import * as path from "path";
10410
- import * as os from "os";
10411
- import * as crypto3 from "crypto";
10412
-
10413
- // server/lib/logger.ts
10414
- import { appendFileSync, statSync, renameSync, unlinkSync } from "fs";
10415
- import { join } from "path";
10416
-
10417
- // shared/logger/types.ts
10418
- var LOG_LEVELS = {
10419
- debug: 0,
10420
- info: 1,
10421
- warn: 2,
10422
- error: 3
10423
- };
10424
- function formatLogEntry(entry) {
10425
- return JSON.stringify(entry);
10426
- }
10427
- // server/lib/logger.ts
10428
- var MAX_LOG_SIZE = 10 * 1024 * 1024;
10429
- var MAX_LOG_BACKUPS = 2;
10430
- function getMinLevel() {
10431
- const level = process.env.LOG_LEVEL;
10432
- if (level && level in LOG_LEVELS) {
10433
- return level;
10434
- }
10435
- return "info";
10436
- }
10437
- var logFilePath = null;
10438
- function getLogFile() {
10439
- if (logFilePath !== null) {
10440
- return logFilePath || null;
10441
- }
10442
- try {
10443
- ensureViboraDir();
10444
- logFilePath = join(getViboraDir(), "vibora.log");
10445
- return logFilePath;
10446
- } catch {
10447
- logFilePath = "";
10448
- return null;
10449
- }
10450
- }
10451
- function rotateLogIfNeeded(logFile) {
10452
- try {
10453
- const stats = statSync(logFile);
10454
- if (stats.size < MAX_LOG_SIZE)
10455
- return;
10456
- for (let i = MAX_LOG_BACKUPS;i >= 1; i--) {
10457
- const older = `${logFile}.${i}`;
10458
- const newer = i === 1 ? logFile : `${logFile}.${i - 1}`;
10459
- try {
10460
- if (i === MAX_LOG_BACKUPS) {
10461
- unlinkSync(older);
10462
- }
10463
- } catch {}
10464
- try {
10465
- renameSync(newer, older);
10466
- } catch {}
10467
- }
10468
- } catch {}
10469
- }
10470
- function writeEntry(entry) {
10471
- const line = formatLogEntry(entry);
10472
- console.log(line);
10473
- const logFile = getLogFile();
10474
- if (logFile) {
10475
- try {
10476
- rotateLogIfNeeded(logFile);
10477
- appendFileSync(logFile, line + `
10478
- `);
10479
- } catch {}
10480
- }
10481
- }
10482
-
10483
- class ServerLogger {
10484
- component;
10485
- minLevel;
10486
- constructor(component, minLevel) {
10487
- this.component = component;
10488
- this.minLevel = minLevel ?? getMinLevel();
10489
- }
10490
- shouldLog(level) {
10491
- return LOG_LEVELS[level] >= LOG_LEVELS[this.minLevel];
10492
- }
10493
- log(level, msg, ctx) {
10494
- if (!this.shouldLog(level))
10495
- return;
10496
- writeEntry({
10497
- ts: new Date().toISOString(),
10498
- lvl: level,
10499
- src: this.component,
10500
- msg,
10501
- ...ctx && Object.keys(ctx).length > 0 ? { ctx } : {}
10502
- });
10503
- }
10504
- debug(msg, ctx) {
10505
- this.log("debug", msg, ctx);
10506
- }
10507
- info(msg, ctx) {
10508
- this.log("info", msg, ctx);
10509
- }
10510
- warn(msg, ctx) {
10511
- this.log("warn", msg, ctx);
10512
- }
10513
- error(msg, ctx) {
10514
- this.log("error", msg, ctx);
10515
- }
10516
- child(component) {
10517
- return new ServerLogger(`${this.component}/${component}`, this.minLevel);
10518
- }
10519
- }
10520
- function createLogger(component) {
10521
- return new ServerLogger(component);
10522
- }
10523
- var log2 = {
10524
- pty: createLogger("PTYManager"),
10525
- ws: createLogger("WS"),
10526
- terminal: createLogger("Terminal"),
10527
- buffer: createLogger("BufferManager"),
10528
- desktop: createLogger("Desktop"),
10529
- api: createLogger("API"),
10530
- metrics: createLogger("MetricsCollector"),
10531
- pr: createLogger("PRMonitor"),
10532
- github: createLogger("GitHub"),
10533
- linear: createLogger("Linear"),
10534
- notification: createLogger("Notification"),
10535
- server: createLogger("Server"),
10536
- settings: createLogger("Settings")
10537
- };
10538
-
10539
- // server/lib/settings.ts
10540
- var CURRENT_SCHEMA_VERSION = 3;
10541
- var CLAUDE_CODE_THEMES = ["light", "light-ansi", "light-daltonized", "dark", "dark-ansi", "dark-daltonized"];
10542
- var DEFAULT_SETTINGS = {
10543
- _schemaVersion: CURRENT_SCHEMA_VERSION,
10544
- server: {
10545
- port: 7777
10546
- },
10547
- paths: {
10548
- defaultGitReposDir: os.homedir()
10549
- },
10550
- authentication: {
10551
- username: null,
10552
- password: null
10553
- },
10554
- editor: {
10555
- app: "vscode",
10556
- host: "",
10557
- sshPort: 22
10558
- },
10559
- integrations: {
10560
- linearApiKey: null,
10561
- githubPat: null
10562
- },
10563
- appearance: {
10564
- language: null,
10565
- theme: null,
10566
- syncClaudeCodeTheme: false,
10567
- claudeCodeLightTheme: "light-ansi",
10568
- claudeCodeDarkTheme: "dark-ansi"
10569
- }
10570
- };
10571
- var OLD_DEFAULT_PORT = 3333;
10572
- var MIGRATION_MAP = {
10573
- port: "server.port",
10574
- defaultGitReposDir: "paths.defaultGitReposDir",
10575
- basicAuthUsername: "authentication.username",
10576
- basicAuthPassword: "authentication.password",
10577
- sshPort: "editor.sshPort",
10578
- linearApiKey: "integrations.linearApiKey",
10579
- githubPat: "integrations.githubPat",
10580
- language: "appearance.language",
10581
- theme: "appearance.theme",
10582
- syncClaudeCodeTheme: "appearance.syncClaudeCodeTheme",
10583
- claudeCodeLightTheme: "appearance.claudeCodeLightTheme",
10584
- claudeCodeDarkTheme: "appearance.claudeCodeDarkTheme"
10585
- };
10586
- function getNestedValue(obj, path2) {
10587
- return path2.split(".").reduce((o, k) => {
10588
- if (o && typeof o === "object") {
10589
- return o[k];
10590
- }
10591
- return;
10592
- }, obj);
10593
- }
10594
- function setNestedValue(obj, path2, value) {
10595
- const keys = path2.split(".");
10596
- const lastKey = keys.pop();
10597
- let current = obj;
10598
- for (const key of keys) {
10599
- if (!(key in current) || typeof current[key] !== "object" || current[key] === null) {
10600
- current[key] = {};
10601
- }
10602
- current = current[key];
10603
- }
10604
- current[lastKey] = value;
10605
- }
10606
- function migrateSettings(parsed) {
10607
- const result = { migrated: false, migratedKeys: [], warnings: [] };
10608
- const version = parsed._schemaVersion ?? 1;
10609
- if (version >= CURRENT_SCHEMA_VERSION) {
10610
- return result;
10611
- }
10612
- if (version < 2) {
10613
- for (const [oldKey, newPath] of Object.entries(MIGRATION_MAP)) {
10614
- if (oldKey in parsed && parsed[oldKey] !== undefined) {
10615
- const oldValue = parsed[oldKey];
10616
- if (oldKey === "port" && oldValue === OLD_DEFAULT_PORT) {
10617
- delete parsed[oldKey];
10618
- result.migrated = true;
10619
- continue;
10620
- }
10621
- const existingValue = getNestedValue(parsed, newPath);
10622
- if (existingValue !== undefined) {
10623
- result.warnings.push(`Key "${oldKey}" exists but "${newPath}" already set. Removing old key.`);
10624
- } else {
10625
- setNestedValue(parsed, newPath, oldValue);
10626
- result.migratedKeys.push(oldKey);
10627
- }
10628
- delete parsed[oldKey];
10629
- result.migrated = true;
10630
- }
10631
- }
10632
- delete parsed.remoteHost;
10633
- delete parsed.hostname;
10634
- delete parsed.remoteVibora;
10635
- }
10636
- parsed._schemaVersion = CURRENT_SCHEMA_VERSION;
10637
- result.migrated = true;
10638
- return result;
10639
- }
10640
- function expandPath(p) {
10641
- if (p.startsWith("~/")) {
10642
- return path.join(os.homedir(), p.slice(2));
10643
- }
10644
- if (!path.isAbsolute(p)) {
10645
- return path.resolve(p);
10646
- }
10647
- return p;
10648
- }
10649
- function getViboraDir() {
10650
- if (process.env.VIBORA_DIR) {
10651
- return expandPath(process.env.VIBORA_DIR);
10652
- }
10653
- const cwdVibora = path.join(process.cwd(), ".vibora");
10654
- if (fs.existsSync(cwdVibora)) {
10655
- return cwdVibora;
10656
- }
10657
- return path.join(os.homedir(), ".vibora");
10658
- }
10659
- function getDatabasePath() {
10660
- return path.join(getViboraDir(), "vibora.db");
10661
- }
10662
- function getWorktreeBasePath() {
10663
- return path.join(getViboraDir(), "worktrees");
10664
- }
10665
- function getSettingsPath() {
10666
- return path.join(getViboraDir(), "settings.json");
10667
- }
10668
- function ensureViboraDir() {
10669
- const viboraDir = getViboraDir();
10670
- if (!fs.existsSync(viboraDir)) {
10671
- fs.mkdirSync(viboraDir, { recursive: true });
10672
- }
10673
- }
10674
- function ensureWorktreesDir() {
10675
- const worktreesDir = getWorktreeBasePath();
10676
- if (!fs.existsSync(worktreesDir)) {
10677
- fs.mkdirSync(worktreesDir, { recursive: true });
10678
- }
10679
- }
10680
- function ensureSettingsFile() {
10681
- const settingsPath = getSettingsPath();
10682
- if (!fs.existsSync(settingsPath)) {
10683
- fs.writeFileSync(settingsPath, JSON.stringify(DEFAULT_SETTINGS, null, 2), "utf-8");
10684
- }
10685
- }
10686
- function initializeViboraDirectories() {
10687
- ensureViboraDir();
10688
- ensureSettingsFile();
10689
- ensureWorktreesDir();
10690
- }
10691
- function getSettings() {
10692
- ensureViboraDir();
10693
- const settingsPath = getSettingsPath();
10694
- let parsed = {};
10695
- if (fs.existsSync(settingsPath)) {
10696
- try {
10697
- const content = fs.readFileSync(settingsPath, "utf-8");
10698
- parsed = JSON.parse(content);
10699
- } catch {}
10700
- }
10701
- const migrationResult = migrateSettings(parsed);
10702
- if (migrationResult.migrated) {
10703
- if (migrationResult.migratedKeys.length > 0) {
10704
- log2.settings.info("Migrated settings to nested structure", {
10705
- migratedKeys: migrationResult.migratedKeys
10706
- });
10707
- }
10708
- if (migrationResult.warnings.length > 0) {
10709
- log2.settings.warn("Settings migration warnings", {
10710
- warnings: migrationResult.warnings
10711
- });
10712
- }
10713
- fs.writeFileSync(settingsPath, JSON.stringify(parsed, null, 2), "utf-8");
10714
- }
10715
- const fileSettings = {
10716
- _schemaVersion: CURRENT_SCHEMA_VERSION,
10717
- server: {
10718
- port: parsed.server?.port ?? DEFAULT_SETTINGS.server.port
10719
- },
10720
- paths: {
10721
- defaultGitReposDir: expandPath(parsed.paths?.defaultGitReposDir ?? DEFAULT_SETTINGS.paths.defaultGitReposDir)
10722
- },
10723
- authentication: {
10724
- username: parsed.authentication?.username ?? null,
10725
- password: parsed.authentication?.password ?? null
10726
- },
10727
- editor: {
10728
- app: parsed.editor?.app ?? DEFAULT_SETTINGS.editor.app,
10729
- host: parsed.editor?.host ?? DEFAULT_SETTINGS.editor.host,
10730
- sshPort: parsed.editor?.sshPort ?? DEFAULT_SETTINGS.editor.sshPort
10731
- },
10732
- integrations: {
10733
- linearApiKey: parsed.integrations?.linearApiKey ?? null,
10734
- githubPat: parsed.integrations?.githubPat ?? null
10735
- },
10736
- appearance: {
10737
- language: parsed.appearance?.language ?? null,
10738
- theme: parsed.appearance?.theme ?? null,
10739
- syncClaudeCodeTheme: parsed.appearance?.syncClaudeCodeTheme ?? false,
10740
- claudeCodeLightTheme: parsed.appearance?.claudeCodeLightTheme ?? "light-ansi",
10741
- claudeCodeDarkTheme: parsed.appearance?.claudeCodeDarkTheme ?? "dark-ansi"
10742
- }
10743
- };
10744
- const portEnv = parseInt(process.env.PORT || "", 10);
10745
- const editorSshPortEnv = parseInt(process.env.VIBORA_SSH_PORT || "", 10);
10746
- return {
10747
- ...fileSettings,
10748
- server: {
10749
- port: !isNaN(portEnv) && portEnv > 0 ? portEnv : fileSettings.server.port
10750
- },
10751
- paths: {
10752
- defaultGitReposDir: process.env.VIBORA_GIT_REPOS_DIR ? expandPath(process.env.VIBORA_GIT_REPOS_DIR) : fileSettings.paths.defaultGitReposDir
10753
- },
10754
- authentication: {
10755
- username: process.env.VIBORA_BASIC_AUTH_USERNAME ?? fileSettings.authentication.username,
10756
- password: process.env.VIBORA_BASIC_AUTH_PASSWORD ?? fileSettings.authentication.password
10757
- },
10758
- editor: {
10759
- app: fileSettings.editor.app,
10760
- host: process.env.VIBORA_EDITOR_HOST ?? fileSettings.editor.host,
10761
- sshPort: !isNaN(editorSshPortEnv) && editorSshPortEnv > 0 ? editorSshPortEnv : fileSettings.editor.sshPort
10762
- },
10763
- integrations: {
10764
- linearApiKey: process.env.LINEAR_API_KEY ?? fileSettings.integrations.linearApiKey,
10765
- githubPat: process.env.GITHUB_PAT ?? fileSettings.integrations.githubPat
10766
- },
10767
- appearance: fileSettings.appearance
10768
- };
10769
- }
10770
- function getSetting(path2) {
10771
- const settings = getSettings();
10772
- return getNestedValue(settings, path2);
10773
- }
10774
- function getSettingByKey(key) {
10775
- const settings = getSettings();
10776
- const legacySettings = toLegacySettings(settings);
10777
- return legacySettings[key];
10778
- }
10779
- function toLegacySettings(settings) {
10780
- return {
10781
- port: settings.server.port,
10782
- defaultGitReposDir: settings.paths.defaultGitReposDir,
10783
- sshPort: settings.editor.sshPort,
10784
- basicAuthUsername: settings.authentication.username,
10785
- basicAuthPassword: settings.authentication.password,
10786
- linearApiKey: settings.integrations.linearApiKey,
10787
- githubPat: settings.integrations.githubPat,
10788
- language: settings.appearance.language,
10789
- theme: settings.appearance.theme,
10790
- syncClaudeCodeTheme: settings.appearance.syncClaudeCodeTheme,
10791
- claudeCodeLightTheme: settings.appearance.claudeCodeLightTheme,
10792
- claudeCodeDarkTheme: settings.appearance.claudeCodeDarkTheme
10793
- };
10794
- }
10795
- function isDeveloperMode() {
10796
- return process.env.VIBORA_DEVELOPER === "1" || process.env.VIBORA_DEVELOPER === "true";
10797
- }
10798
- function getSessionSecret() {
10799
- const settings = getSettings();
10800
- if (!settings.authentication.password) {
10801
- return null;
10802
- }
10803
- return crypto3.createHash("sha256").update(settings.authentication.password + "vibora-session").digest("hex");
10804
- }
10805
- function updateSettingByPath(settingPath, value) {
10806
- ensureViboraDir();
10807
- const settingsPath = getSettingsPath();
10808
- let parsed = {};
10809
- if (fs.existsSync(settingsPath)) {
10810
- try {
10811
- parsed = JSON.parse(fs.readFileSync(settingsPath, "utf-8"));
10812
- } catch {}
10813
- }
10814
- setNestedValue(parsed, settingPath, value);
10815
- parsed._schemaVersion = CURRENT_SCHEMA_VERSION;
10816
- fs.writeFileSync(settingsPath, JSON.stringify(parsed, null, 2), "utf-8");
10817
- return getSettings();
10818
- }
10819
- function getDefaultValue(settingPath) {
10820
- return getNestedValue(DEFAULT_SETTINGS, settingPath);
10821
- }
10822
- var DEFAULT_NOTIFICATION_SETTINGS = {
10823
- enabled: true,
10824
- sound: { enabled: true },
10825
- slack: { enabled: false },
10826
- discord: { enabled: false },
10827
- pushover: { enabled: false }
10828
- };
10829
- function getNotificationSettings() {
10830
- ensureViboraDir();
10831
- const settingsPath = getSettingsPath();
10832
- if (!fs.existsSync(settingsPath)) {
10833
- return DEFAULT_NOTIFICATION_SETTINGS;
10834
- }
10835
- try {
10836
- const content = fs.readFileSync(settingsPath, "utf-8");
10837
- const parsed = JSON.parse(content);
10838
- const notifications = parsed.notifications;
10839
- if (!notifications) {
10840
- return DEFAULT_NOTIFICATION_SETTINGS;
10841
- }
10842
- return {
10843
- enabled: notifications.enabled ?? false,
10844
- sound: { enabled: false, ...notifications.sound },
10845
- slack: { enabled: false, ...notifications.slack },
10846
- discord: { enabled: false, ...notifications.discord },
10847
- pushover: { enabled: false, ...notifications.pushover }
10848
- };
10849
- } catch {
10850
- return DEFAULT_NOTIFICATION_SETTINGS;
10851
- }
10852
- }
10853
- function updateNotificationSettings(updates) {
10854
- ensureViboraDir();
10855
- const settingsPath = getSettingsPath();
10856
- let parsed = {};
10857
- if (fs.existsSync(settingsPath)) {
10858
- try {
10859
- parsed = JSON.parse(fs.readFileSync(settingsPath, "utf-8"));
10860
- } catch {}
10861
- }
10862
- const current = getNotificationSettings();
10863
- const updated = {
10864
- enabled: updates.enabled ?? current.enabled,
10865
- sound: { ...current.sound, ...updates.sound },
10866
- slack: { ...current.slack, ...updates.slack },
10867
- discord: { ...current.discord, ...updates.discord },
10868
- pushover: { ...current.pushover, ...updates.pushover }
10869
- };
10870
- parsed.notifications = updated;
10871
- fs.writeFileSync(settingsPath, JSON.stringify(parsed, null, 2), "utf-8");
10872
- return updated;
10873
- }
10874
- function getClaudeSettingsPath() {
10875
- return path.join(os.homedir(), ".claude", "settings.json");
10876
- }
10877
- function getClaudeSettings() {
10878
- const settingsPath = getClaudeSettingsPath();
10879
- if (!fs.existsSync(settingsPath))
10880
- return {};
10881
- try {
10882
- return JSON.parse(fs.readFileSync(settingsPath, "utf-8"));
10883
- } catch {
10884
- return {};
10885
- }
10886
- }
10887
- function updateClaudeSettings(updates) {
10888
- const settingsPath = getClaudeSettingsPath();
10889
- const dir = path.dirname(settingsPath);
10890
- if (!fs.existsSync(dir))
10891
- fs.mkdirSync(dir, { recursive: true });
10892
- const current = getClaudeSettings();
10893
- const merged = { ...current, ...updates };
10894
- fs.writeFileSync(settingsPath, JSON.stringify(merged, null, 2), "utf-8");
10895
- }
10896
- function getClaudeConfigPath() {
10897
- return path.join(os.homedir(), ".claude.json");
10898
- }
10899
- function getClaudeConfig() {
10900
- const configPath = getClaudeConfigPath();
10901
- if (!fs.existsSync(configPath))
10902
- return {};
10903
- try {
10904
- return JSON.parse(fs.readFileSync(configPath, "utf-8"));
10905
- } catch {
10906
- return {};
10907
- }
10908
- }
10909
- var claudeConfigLock = Promise.resolve();
10910
- function updateClaudeConfig(updates) {
10911
- claudeConfigLock = claudeConfigLock.then(() => {
10912
- const configPath = getClaudeConfigPath();
10913
- const current = getClaudeConfig();
10914
- const merged = { ...current, ...updates };
10915
- fs.writeFileSync(configPath, JSON.stringify(merged, null, 2), "utf-8");
10916
- }).catch((err) => {
10917
- log2.settings.error("Failed to update Claude config", { error: String(err) });
10918
- });
10919
- }
10920
- function syncClaudeCodeTheme(resolvedTheme) {
10921
- const settings = getSettings();
10922
- if (!settings.appearance.syncClaudeCodeTheme)
10923
- return;
10924
- const claudeTheme = resolvedTheme === "light" ? settings.appearance.claudeCodeLightTheme : settings.appearance.claudeCodeDarkTheme;
10925
- updateClaudeConfig({ theme: claudeTheme });
10926
- log2.settings.info("Synced Claude Code theme", { claudeTheme, resolvedTheme });
10927
- }
10928
- var DEFAULT_ZAI_SETTINGS = {
10929
- enabled: false,
10930
- apiKey: null,
10931
- haikuModel: "glm-4.5-air",
10932
- sonnetModel: "glm-4.7",
10933
- opusModel: "glm-4.7"
10934
- };
10935
- function getZAiSettings() {
10936
- ensureViboraDir();
10937
- const settingsPath = getSettingsPath();
10938
- if (!fs.existsSync(settingsPath)) {
10939
- return DEFAULT_ZAI_SETTINGS;
10940
- }
10941
- try {
10942
- const content = fs.readFileSync(settingsPath, "utf-8");
10943
- const parsed = JSON.parse(content);
10944
- const zai = parsed.zai;
10945
- if (!zai) {
10946
- return DEFAULT_ZAI_SETTINGS;
10947
- }
10948
- return {
10949
- enabled: zai.enabled ?? false,
10950
- apiKey: zai.apiKey ?? null,
10951
- haikuModel: zai.haikuModel ?? DEFAULT_ZAI_SETTINGS.haikuModel,
10952
- sonnetModel: zai.sonnetModel ?? DEFAULT_ZAI_SETTINGS.sonnetModel,
10953
- opusModel: zai.opusModel ?? DEFAULT_ZAI_SETTINGS.opusModel
10954
- };
10955
- } catch {
10956
- return DEFAULT_ZAI_SETTINGS;
10957
- }
10958
- }
10959
- function updateZAiSettings(updates) {
10960
- ensureViboraDir();
10961
- const settingsPath = getSettingsPath();
10962
- let parsed = {};
10963
- if (fs.existsSync(settingsPath)) {
10964
- try {
10965
- parsed = JSON.parse(fs.readFileSync(settingsPath, "utf-8"));
10966
- } catch {}
10967
- }
10968
- const current = getZAiSettings();
10969
- const updated = {
10970
- enabled: updates.enabled ?? current.enabled,
10971
- apiKey: updates.apiKey !== undefined ? updates.apiKey : current.apiKey,
10972
- haikuModel: updates.haikuModel ?? current.haikuModel,
10973
- sonnetModel: updates.sonnetModel ?? current.sonnetModel,
10974
- opusModel: updates.opusModel ?? current.opusModel
10975
- };
10976
- parsed.zai = updated;
10977
- fs.writeFileSync(settingsPath, JSON.stringify(parsed, null, 2), "utf-8");
10978
- return updated;
10979
- }
10980
-
10981
- // server/middleware/auth.ts
10982
- var SESSION_COOKIE_NAME = "vibora_session";
10983
- var PUBLIC_API_PATHS = ["/health", "/api/auth/login", "/api/auth/check"];
10984
- var sessionAuthMiddleware = createMiddleware(async (c, next) => {
10985
- const settings = getSettings();
10986
- if (!settings.basicAuthUsername || !settings.basicAuthPassword) {
10987
- return next();
10988
- }
10989
- const path2 = c.req.path;
10990
- if (!path2.startsWith("/api/") && !path2.startsWith("/ws/")) {
10991
- return next();
10992
- }
10993
- if (PUBLIC_API_PATHS.some((p) => path2 === p || path2.startsWith(p + "/"))) {
10994
- return next();
10995
- }
10996
- const secret = getSessionSecret();
10997
- if (secret) {
10998
- const sessionCookie = await getSignedCookie(c, secret, SESSION_COOKIE_NAME);
10999
- if (sessionCookie) {
11000
- try {
11001
- const session = JSON.parse(sessionCookie);
11002
- if (session.exp && session.exp > Date.now()) {
11003
- return next();
11004
- }
11005
- } catch {}
11006
- }
11007
- }
11008
- const authHeader = c.req.header("Authorization");
11009
- if (authHeader?.startsWith("Basic ")) {
11010
- const base64Credentials = authHeader.slice(6);
11011
- try {
11012
- const credentials = atob(base64Credentials);
11013
- const [username, password] = credentials.split(":");
11014
- if (username === settings.basicAuthUsername && password === settings.basicAuthPassword) {
11015
- return next();
11016
- }
11017
- } catch {}
11018
- }
11019
- throw new HTTPException(401, { message: "Unauthorized" });
11020
- });
11021
-
11022
10132
  // server/app.ts
11023
10133
  import { readFile as readFile2 } from "fs/promises";
11024
10134
  import { join as join14 } from "path";
@@ -11665,7 +10775,7 @@ function sql(strings, ...params) {
11665
10775
  return new SQL([new StringChunk(str)]);
11666
10776
  }
11667
10777
  sql2.raw = raw2;
11668
- function join3(chunks, separator) {
10778
+ function join(chunks, separator) {
11669
10779
  const result = [];
11670
10780
  for (const [i, chunk] of chunks.entries()) {
11671
10781
  if (i > 0 && separator !== undefined) {
@@ -11675,7 +10785,7 @@ function sql(strings, ...params) {
11675
10785
  }
11676
10786
  return new SQL(result);
11677
10787
  }
11678
- sql2.join = join3;
10788
+ sql2.join = join;
11679
10789
  function identifier(value) {
11680
10790
  return new Name(value);
11681
10791
  }
@@ -11768,7 +10878,7 @@ Subquery.prototype.getSQL = function() {
11768
10878
  // node_modules/drizzle-orm/utils.js
11769
10879
  function mapResultRow(columns, row, joinsNotNullableMap) {
11770
10880
  const nullifyMap = {};
11771
- const result = columns.reduce((result2, { path: path2, field }, columnIndex) => {
10881
+ const result = columns.reduce((result2, { path, field }, columnIndex) => {
11772
10882
  let decoder;
11773
10883
  if (is(field, Column)) {
11774
10884
  decoder = field;
@@ -11780,8 +10890,8 @@ function mapResultRow(columns, row, joinsNotNullableMap) {
11780
10890
  decoder = field.sql.decoder;
11781
10891
  }
11782
10892
  let node = result2;
11783
- for (const [pathChunkIndex, pathChunk] of path2.entries()) {
11784
- if (pathChunkIndex < path2.length - 1) {
10893
+ for (const [pathChunkIndex, pathChunk] of path.entries()) {
10894
+ if (pathChunkIndex < path.length - 1) {
11785
10895
  if (!(pathChunk in node)) {
11786
10896
  node[pathChunk] = {};
11787
10897
  }
@@ -11789,8 +10899,8 @@ function mapResultRow(columns, row, joinsNotNullableMap) {
11789
10899
  } else {
11790
10900
  const rawValue = row[columnIndex];
11791
10901
  const value = node[pathChunk] = rawValue === null ? null : decoder.mapFromDriverValue(rawValue);
11792
- if (joinsNotNullableMap && is(field, Column) && path2.length === 2) {
11793
- const objectName = path2[0];
10902
+ if (joinsNotNullableMap && is(field, Column) && path.length === 2) {
10903
+ const objectName = path[0];
11794
10904
  if (!(objectName in nullifyMap)) {
11795
10905
  nullifyMap[objectName] = value === null ? getTableName(field.table) : false;
11796
10906
  } else if (typeof nullifyMap[objectName] === "string" && nullifyMap[objectName] !== getTableName(field.table)) {
@@ -13798,7 +12908,7 @@ class SQLiteSelectQueryBuilderBase extends TypedQueryBuilder {
13798
12908
  const tableName = getTableLikeName(table);
13799
12909
  for (const item of extractUsedTable(table))
13800
12910
  this.usedTables.add(item);
13801
- if (typeof tableName === "string" && this.config.joins?.some((join3) => join3.alias === tableName)) {
12911
+ if (typeof tableName === "string" && this.config.joins?.some((join) => join.alias === tableName)) {
13802
12912
  throw new Error(`Alias "${tableName}" is already used in this query`);
13803
12913
  }
13804
12914
  if (!this.isPartialSelect) {
@@ -14212,7 +13322,7 @@ class SQLiteUpdateBase extends QueryPromise {
14212
13322
  createJoin(joinType) {
14213
13323
  return (table, on) => {
14214
13324
  const tableName = getTableLikeName(table);
14215
- if (typeof tableName === "string" && this.config.joins.some((join3) => join3.alias === tableName)) {
13325
+ if (typeof tableName === "string" && this.config.joins.some((join) => join.alias === tableName)) {
14216
13326
  throw new Error(`Alias "${tableName}" is already used in this query`);
14217
13327
  }
14218
13328
  if (typeof on === "function") {
@@ -14916,21 +14026,21 @@ function drizzle(...params) {
14916
14026
  })(drizzle || (drizzle = {}));
14917
14027
 
14918
14028
  // node_modules/drizzle-orm/migrator.js
14919
- import crypto4 from "crypto";
14920
- import fs2 from "fs";
14029
+ import crypto3 from "crypto";
14030
+ import fs from "fs";
14921
14031
  function readMigrationFiles(config) {
14922
14032
  const migrationFolderTo = config.migrationsFolder;
14923
14033
  const migrationQueries = [];
14924
14034
  const journalPath = `${migrationFolderTo}/meta/_journal.json`;
14925
- if (!fs2.existsSync(journalPath)) {
14035
+ if (!fs.existsSync(journalPath)) {
14926
14036
  throw new Error(`Can't find meta/_journal.json file`);
14927
14037
  }
14928
- const journalAsString = fs2.readFileSync(`${migrationFolderTo}/meta/_journal.json`).toString();
14038
+ const journalAsString = fs.readFileSync(`${migrationFolderTo}/meta/_journal.json`).toString();
14929
14039
  const journal = JSON.parse(journalAsString);
14930
14040
  for (const journalEntry of journal.entries) {
14931
14041
  const migrationPath = `${migrationFolderTo}/${journalEntry.tag}.sql`;
14932
14042
  try {
14933
- const query = fs2.readFileSync(`${migrationFolderTo}/${journalEntry.tag}.sql`).toString();
14043
+ const query = fs.readFileSync(`${migrationFolderTo}/${journalEntry.tag}.sql`).toString();
14934
14044
  const result = query.split("--> statement-breakpoint").map((it) => {
14935
14045
  return it;
14936
14046
  });
@@ -14938,7 +14048,7 @@ function readMigrationFiles(config) {
14938
14048
  sql: result,
14939
14049
  bps: journalEntry.breakpoints,
14940
14050
  folderMillis: journalEntry.when,
14941
- hash: crypto4.createHash("sha256").update(query).digest("hex")
14051
+ hash: crypto3.createHash("sha256").update(query).digest("hex")
14942
14052
  });
14943
14053
  } catch {
14944
14054
  throw new Error(`No file ${migrationPath} found in ${migrationFolderTo} folder`);
@@ -15043,6 +14153,556 @@ var systemMetrics = sqliteTable("system_metrics", {
15043
14153
  diskTotalBytes: integer("disk_total_bytes").notNull()
15044
14154
  });
15045
14155
 
14156
+ // server/lib/settings.ts
14157
+ import * as fs2 from "fs";
14158
+ import * as path from "path";
14159
+ import * as os from "os";
14160
+
14161
+ // server/lib/logger.ts
14162
+ import { appendFileSync, statSync, renameSync, unlinkSync } from "fs";
14163
+ import { join } from "path";
14164
+
14165
+ // shared/logger/types.ts
14166
+ var LOG_LEVELS = {
14167
+ debug: 0,
14168
+ info: 1,
14169
+ warn: 2,
14170
+ error: 3
14171
+ };
14172
+ function formatLogEntry(entry) {
14173
+ return JSON.stringify(entry);
14174
+ }
14175
+ // server/lib/logger.ts
14176
+ var MAX_LOG_SIZE = 10 * 1024 * 1024;
14177
+ var MAX_LOG_BACKUPS = 2;
14178
+ function getMinLevel() {
14179
+ const level = process.env.LOG_LEVEL;
14180
+ if (level && level in LOG_LEVELS) {
14181
+ return level;
14182
+ }
14183
+ return "info";
14184
+ }
14185
+ var logFilePath = null;
14186
+ function getLogFile() {
14187
+ if (logFilePath !== null) {
14188
+ return logFilePath || null;
14189
+ }
14190
+ try {
14191
+ ensureViboraDir();
14192
+ logFilePath = join(getViboraDir(), "vibora.log");
14193
+ return logFilePath;
14194
+ } catch {
14195
+ logFilePath = "";
14196
+ return null;
14197
+ }
14198
+ }
14199
+ function rotateLogIfNeeded(logFile) {
14200
+ try {
14201
+ const stats = statSync(logFile);
14202
+ if (stats.size < MAX_LOG_SIZE)
14203
+ return;
14204
+ for (let i = MAX_LOG_BACKUPS;i >= 1; i--) {
14205
+ const older = `${logFile}.${i}`;
14206
+ const newer = i === 1 ? logFile : `${logFile}.${i - 1}`;
14207
+ try {
14208
+ if (i === MAX_LOG_BACKUPS) {
14209
+ unlinkSync(older);
14210
+ }
14211
+ } catch {}
14212
+ try {
14213
+ renameSync(newer, older);
14214
+ } catch {}
14215
+ }
14216
+ } catch {}
14217
+ }
14218
+ function writeEntry(entry) {
14219
+ const line = formatLogEntry(entry);
14220
+ console.log(line);
14221
+ const logFile = getLogFile();
14222
+ if (logFile) {
14223
+ try {
14224
+ rotateLogIfNeeded(logFile);
14225
+ appendFileSync(logFile, line + `
14226
+ `);
14227
+ } catch {}
14228
+ }
14229
+ }
14230
+
14231
+ class ServerLogger {
14232
+ component;
14233
+ minLevel;
14234
+ constructor(component, minLevel) {
14235
+ this.component = component;
14236
+ this.minLevel = minLevel ?? getMinLevel();
14237
+ }
14238
+ shouldLog(level) {
14239
+ return LOG_LEVELS[level] >= LOG_LEVELS[this.minLevel];
14240
+ }
14241
+ log(level, msg, ctx) {
14242
+ if (!this.shouldLog(level))
14243
+ return;
14244
+ writeEntry({
14245
+ ts: new Date().toISOString(),
14246
+ lvl: level,
14247
+ src: this.component,
14248
+ msg,
14249
+ ...ctx && Object.keys(ctx).length > 0 ? { ctx } : {}
14250
+ });
14251
+ }
14252
+ debug(msg, ctx) {
14253
+ this.log("debug", msg, ctx);
14254
+ }
14255
+ info(msg, ctx) {
14256
+ this.log("info", msg, ctx);
14257
+ }
14258
+ warn(msg, ctx) {
14259
+ this.log("warn", msg, ctx);
14260
+ }
14261
+ error(msg, ctx) {
14262
+ this.log("error", msg, ctx);
14263
+ }
14264
+ child(component) {
14265
+ return new ServerLogger(`${this.component}/${component}`, this.minLevel);
14266
+ }
14267
+ }
14268
+ function createLogger(component) {
14269
+ return new ServerLogger(component);
14270
+ }
14271
+ var log2 = {
14272
+ pty: createLogger("PTYManager"),
14273
+ ws: createLogger("WS"),
14274
+ terminal: createLogger("Terminal"),
14275
+ buffer: createLogger("BufferManager"),
14276
+ desktop: createLogger("Desktop"),
14277
+ api: createLogger("API"),
14278
+ metrics: createLogger("MetricsCollector"),
14279
+ pr: createLogger("PRMonitor"),
14280
+ github: createLogger("GitHub"),
14281
+ linear: createLogger("Linear"),
14282
+ notification: createLogger("Notification"),
14283
+ server: createLogger("Server"),
14284
+ settings: createLogger("Settings")
14285
+ };
14286
+
14287
+ // server/lib/settings.ts
14288
+ var CURRENT_SCHEMA_VERSION = 3;
14289
+ var CLAUDE_CODE_THEMES = ["light", "light-ansi", "light-daltonized", "dark", "dark-ansi", "dark-daltonized"];
14290
+ var DEFAULT_SETTINGS = {
14291
+ _schemaVersion: CURRENT_SCHEMA_VERSION,
14292
+ server: {
14293
+ port: 7777
14294
+ },
14295
+ paths: {
14296
+ defaultGitReposDir: os.homedir()
14297
+ },
14298
+ editor: {
14299
+ app: "vscode",
14300
+ host: "",
14301
+ sshPort: 22
14302
+ },
14303
+ integrations: {
14304
+ linearApiKey: null,
14305
+ githubPat: null
14306
+ },
14307
+ appearance: {
14308
+ language: null,
14309
+ theme: null,
14310
+ syncClaudeCodeTheme: false,
14311
+ claudeCodeLightTheme: "light-ansi",
14312
+ claudeCodeDarkTheme: "dark-ansi"
14313
+ }
14314
+ };
14315
+ var OLD_DEFAULT_PORT = 3333;
14316
+ var MIGRATION_MAP = {
14317
+ port: "server.port",
14318
+ defaultGitReposDir: "paths.defaultGitReposDir",
14319
+ sshPort: "editor.sshPort",
14320
+ linearApiKey: "integrations.linearApiKey",
14321
+ githubPat: "integrations.githubPat",
14322
+ language: "appearance.language",
14323
+ theme: "appearance.theme",
14324
+ syncClaudeCodeTheme: "appearance.syncClaudeCodeTheme",
14325
+ claudeCodeLightTheme: "appearance.claudeCodeLightTheme",
14326
+ claudeCodeDarkTheme: "appearance.claudeCodeDarkTheme"
14327
+ };
14328
+ function getNestedValue(obj, path2) {
14329
+ return path2.split(".").reduce((o, k) => {
14330
+ if (o && typeof o === "object") {
14331
+ return o[k];
14332
+ }
14333
+ return;
14334
+ }, obj);
14335
+ }
14336
+ function setNestedValue(obj, path2, value) {
14337
+ const keys = path2.split(".");
14338
+ const lastKey = keys.pop();
14339
+ let current = obj;
14340
+ for (const key of keys) {
14341
+ if (!(key in current) || typeof current[key] !== "object" || current[key] === null) {
14342
+ current[key] = {};
14343
+ }
14344
+ current = current[key];
14345
+ }
14346
+ current[lastKey] = value;
14347
+ }
14348
+ function migrateSettings(parsed) {
14349
+ const result = { migrated: false, migratedKeys: [], warnings: [] };
14350
+ const version2 = parsed._schemaVersion ?? 1;
14351
+ if (version2 >= CURRENT_SCHEMA_VERSION) {
14352
+ return result;
14353
+ }
14354
+ if (version2 < 2) {
14355
+ for (const [oldKey, newPath] of Object.entries(MIGRATION_MAP)) {
14356
+ if (oldKey in parsed && parsed[oldKey] !== undefined) {
14357
+ const oldValue = parsed[oldKey];
14358
+ if (oldKey === "port" && oldValue === OLD_DEFAULT_PORT) {
14359
+ delete parsed[oldKey];
14360
+ result.migrated = true;
14361
+ continue;
14362
+ }
14363
+ const existingValue = getNestedValue(parsed, newPath);
14364
+ if (existingValue !== undefined) {
14365
+ result.warnings.push(`Key "${oldKey}" exists but "${newPath}" already set. Removing old key.`);
14366
+ } else {
14367
+ setNestedValue(parsed, newPath, oldValue);
14368
+ result.migratedKeys.push(oldKey);
14369
+ }
14370
+ delete parsed[oldKey];
14371
+ result.migrated = true;
14372
+ }
14373
+ }
14374
+ delete parsed.remoteHost;
14375
+ delete parsed.hostname;
14376
+ delete parsed.remoteVibora;
14377
+ }
14378
+ parsed._schemaVersion = CURRENT_SCHEMA_VERSION;
14379
+ result.migrated = true;
14380
+ return result;
14381
+ }
14382
+ function expandPath(p) {
14383
+ if (p.startsWith("~/")) {
14384
+ return path.join(os.homedir(), p.slice(2));
14385
+ }
14386
+ if (!path.isAbsolute(p)) {
14387
+ return path.resolve(p);
14388
+ }
14389
+ return p;
14390
+ }
14391
+ function getViboraDir() {
14392
+ if (process.env.VIBORA_DIR) {
14393
+ return expandPath(process.env.VIBORA_DIR);
14394
+ }
14395
+ const cwdVibora = path.join(process.cwd(), ".vibora");
14396
+ if (fs2.existsSync(cwdVibora)) {
14397
+ return cwdVibora;
14398
+ }
14399
+ return path.join(os.homedir(), ".vibora");
14400
+ }
14401
+ function getDatabasePath() {
14402
+ return path.join(getViboraDir(), "vibora.db");
14403
+ }
14404
+ function getWorktreeBasePath() {
14405
+ return path.join(getViboraDir(), "worktrees");
14406
+ }
14407
+ function getSettingsPath() {
14408
+ return path.join(getViboraDir(), "settings.json");
14409
+ }
14410
+ function ensureViboraDir() {
14411
+ const viboraDir = getViboraDir();
14412
+ if (!fs2.existsSync(viboraDir)) {
14413
+ fs2.mkdirSync(viboraDir, { recursive: true });
14414
+ }
14415
+ }
14416
+ function ensureWorktreesDir() {
14417
+ const worktreesDir = getWorktreeBasePath();
14418
+ if (!fs2.existsSync(worktreesDir)) {
14419
+ fs2.mkdirSync(worktreesDir, { recursive: true });
14420
+ }
14421
+ }
14422
+ function ensureSettingsFile() {
14423
+ const settingsPath = getSettingsPath();
14424
+ if (!fs2.existsSync(settingsPath)) {
14425
+ fs2.writeFileSync(settingsPath, JSON.stringify(DEFAULT_SETTINGS, null, 2), "utf-8");
14426
+ }
14427
+ }
14428
+ function initializeViboraDirectories() {
14429
+ ensureViboraDir();
14430
+ ensureSettingsFile();
14431
+ ensureWorktreesDir();
14432
+ }
14433
+ function getSettings() {
14434
+ ensureViboraDir();
14435
+ const settingsPath = getSettingsPath();
14436
+ let parsed = {};
14437
+ if (fs2.existsSync(settingsPath)) {
14438
+ try {
14439
+ const content = fs2.readFileSync(settingsPath, "utf-8");
14440
+ parsed = JSON.parse(content);
14441
+ } catch {}
14442
+ }
14443
+ const migrationResult = migrateSettings(parsed);
14444
+ if (migrationResult.migrated) {
14445
+ if (migrationResult.migratedKeys.length > 0) {
14446
+ log2.settings.info("Migrated settings to nested structure", {
14447
+ migratedKeys: migrationResult.migratedKeys
14448
+ });
14449
+ }
14450
+ if (migrationResult.warnings.length > 0) {
14451
+ log2.settings.warn("Settings migration warnings", {
14452
+ warnings: migrationResult.warnings
14453
+ });
14454
+ }
14455
+ fs2.writeFileSync(settingsPath, JSON.stringify(parsed, null, 2), "utf-8");
14456
+ }
14457
+ const fileSettings = {
14458
+ _schemaVersion: CURRENT_SCHEMA_VERSION,
14459
+ server: {
14460
+ port: parsed.server?.port ?? DEFAULT_SETTINGS.server.port
14461
+ },
14462
+ paths: {
14463
+ defaultGitReposDir: expandPath(parsed.paths?.defaultGitReposDir ?? DEFAULT_SETTINGS.paths.defaultGitReposDir)
14464
+ },
14465
+ editor: {
14466
+ app: parsed.editor?.app ?? DEFAULT_SETTINGS.editor.app,
14467
+ host: parsed.editor?.host ?? DEFAULT_SETTINGS.editor.host,
14468
+ sshPort: parsed.editor?.sshPort ?? DEFAULT_SETTINGS.editor.sshPort
14469
+ },
14470
+ integrations: {
14471
+ linearApiKey: parsed.integrations?.linearApiKey ?? null,
14472
+ githubPat: parsed.integrations?.githubPat ?? null
14473
+ },
14474
+ appearance: {
14475
+ language: parsed.appearance?.language ?? null,
14476
+ theme: parsed.appearance?.theme ?? null,
14477
+ syncClaudeCodeTheme: parsed.appearance?.syncClaudeCodeTheme ?? false,
14478
+ claudeCodeLightTheme: parsed.appearance?.claudeCodeLightTheme ?? "light-ansi",
14479
+ claudeCodeDarkTheme: parsed.appearance?.claudeCodeDarkTheme ?? "dark-ansi"
14480
+ }
14481
+ };
14482
+ const portEnv = parseInt(process.env.PORT || "", 10);
14483
+ const editorSshPortEnv = parseInt(process.env.VIBORA_SSH_PORT || "", 10);
14484
+ return {
14485
+ ...fileSettings,
14486
+ server: {
14487
+ port: !isNaN(portEnv) && portEnv > 0 ? portEnv : fileSettings.server.port
14488
+ },
14489
+ paths: {
14490
+ defaultGitReposDir: process.env.VIBORA_GIT_REPOS_DIR ? expandPath(process.env.VIBORA_GIT_REPOS_DIR) : fileSettings.paths.defaultGitReposDir
14491
+ },
14492
+ editor: {
14493
+ app: fileSettings.editor.app,
14494
+ host: process.env.VIBORA_EDITOR_HOST ?? fileSettings.editor.host,
14495
+ sshPort: !isNaN(editorSshPortEnv) && editorSshPortEnv > 0 ? editorSshPortEnv : fileSettings.editor.sshPort
14496
+ },
14497
+ integrations: {
14498
+ linearApiKey: process.env.LINEAR_API_KEY ?? fileSettings.integrations.linearApiKey,
14499
+ githubPat: process.env.GITHUB_PAT ?? fileSettings.integrations.githubPat
14500
+ },
14501
+ appearance: fileSettings.appearance
14502
+ };
14503
+ }
14504
+ function getSetting(path2) {
14505
+ const settings = getSettings();
14506
+ return getNestedValue(settings, path2);
14507
+ }
14508
+ function getSettingByKey(key) {
14509
+ const settings = getSettings();
14510
+ const legacySettings = toLegacySettings(settings);
14511
+ return legacySettings[key];
14512
+ }
14513
+ function toLegacySettings(settings) {
14514
+ return {
14515
+ port: settings.server.port,
14516
+ defaultGitReposDir: settings.paths.defaultGitReposDir,
14517
+ sshPort: settings.editor.sshPort,
14518
+ linearApiKey: settings.integrations.linearApiKey,
14519
+ githubPat: settings.integrations.githubPat,
14520
+ language: settings.appearance.language,
14521
+ theme: settings.appearance.theme,
14522
+ syncClaudeCodeTheme: settings.appearance.syncClaudeCodeTheme,
14523
+ claudeCodeLightTheme: settings.appearance.claudeCodeLightTheme,
14524
+ claudeCodeDarkTheme: settings.appearance.claudeCodeDarkTheme
14525
+ };
14526
+ }
14527
+ function isDeveloperMode() {
14528
+ return process.env.VIBORA_DEVELOPER === "1" || process.env.VIBORA_DEVELOPER === "true";
14529
+ }
14530
+ function updateSettingByPath(settingPath, value) {
14531
+ ensureViboraDir();
14532
+ const settingsPath = getSettingsPath();
14533
+ let parsed = {};
14534
+ if (fs2.existsSync(settingsPath)) {
14535
+ try {
14536
+ parsed = JSON.parse(fs2.readFileSync(settingsPath, "utf-8"));
14537
+ } catch {}
14538
+ }
14539
+ setNestedValue(parsed, settingPath, value);
14540
+ parsed._schemaVersion = CURRENT_SCHEMA_VERSION;
14541
+ fs2.writeFileSync(settingsPath, JSON.stringify(parsed, null, 2), "utf-8");
14542
+ return getSettings();
14543
+ }
14544
+ function getDefaultValue(settingPath) {
14545
+ return getNestedValue(DEFAULT_SETTINGS, settingPath);
14546
+ }
14547
+ var DEFAULT_NOTIFICATION_SETTINGS = {
14548
+ enabled: true,
14549
+ sound: { enabled: true },
14550
+ slack: { enabled: false },
14551
+ discord: { enabled: false },
14552
+ pushover: { enabled: false }
14553
+ };
14554
+ function getNotificationSettings() {
14555
+ ensureViboraDir();
14556
+ const settingsPath = getSettingsPath();
14557
+ if (!fs2.existsSync(settingsPath)) {
14558
+ return DEFAULT_NOTIFICATION_SETTINGS;
14559
+ }
14560
+ try {
14561
+ const content = fs2.readFileSync(settingsPath, "utf-8");
14562
+ const parsed = JSON.parse(content);
14563
+ const notifications = parsed.notifications;
14564
+ if (!notifications) {
14565
+ return DEFAULT_NOTIFICATION_SETTINGS;
14566
+ }
14567
+ return {
14568
+ enabled: notifications.enabled ?? false,
14569
+ sound: { enabled: false, ...notifications.sound },
14570
+ slack: { enabled: false, ...notifications.slack },
14571
+ discord: { enabled: false, ...notifications.discord },
14572
+ pushover: { enabled: false, ...notifications.pushover }
14573
+ };
14574
+ } catch {
14575
+ return DEFAULT_NOTIFICATION_SETTINGS;
14576
+ }
14577
+ }
14578
+ function updateNotificationSettings(updates) {
14579
+ ensureViboraDir();
14580
+ const settingsPath = getSettingsPath();
14581
+ let parsed = {};
14582
+ if (fs2.existsSync(settingsPath)) {
14583
+ try {
14584
+ parsed = JSON.parse(fs2.readFileSync(settingsPath, "utf-8"));
14585
+ } catch {}
14586
+ }
14587
+ const current = getNotificationSettings();
14588
+ const updated = {
14589
+ enabled: updates.enabled ?? current.enabled,
14590
+ sound: { ...current.sound, ...updates.sound },
14591
+ slack: { ...current.slack, ...updates.slack },
14592
+ discord: { ...current.discord, ...updates.discord },
14593
+ pushover: { ...current.pushover, ...updates.pushover }
14594
+ };
14595
+ parsed.notifications = updated;
14596
+ fs2.writeFileSync(settingsPath, JSON.stringify(parsed, null, 2), "utf-8");
14597
+ return updated;
14598
+ }
14599
+ function getClaudeSettingsPath() {
14600
+ return path.join(os.homedir(), ".claude", "settings.json");
14601
+ }
14602
+ function getClaudeSettings() {
14603
+ const settingsPath = getClaudeSettingsPath();
14604
+ if (!fs2.existsSync(settingsPath))
14605
+ return {};
14606
+ try {
14607
+ return JSON.parse(fs2.readFileSync(settingsPath, "utf-8"));
14608
+ } catch {
14609
+ return {};
14610
+ }
14611
+ }
14612
+ function updateClaudeSettings(updates) {
14613
+ const settingsPath = getClaudeSettingsPath();
14614
+ const dir = path.dirname(settingsPath);
14615
+ if (!fs2.existsSync(dir))
14616
+ fs2.mkdirSync(dir, { recursive: true });
14617
+ const current = getClaudeSettings();
14618
+ const merged = { ...current, ...updates };
14619
+ fs2.writeFileSync(settingsPath, JSON.stringify(merged, null, 2), "utf-8");
14620
+ }
14621
+ function getClaudeConfigPath() {
14622
+ return path.join(os.homedir(), ".claude.json");
14623
+ }
14624
+ function getClaudeConfig() {
14625
+ const configPath = getClaudeConfigPath();
14626
+ if (!fs2.existsSync(configPath))
14627
+ return {};
14628
+ try {
14629
+ return JSON.parse(fs2.readFileSync(configPath, "utf-8"));
14630
+ } catch {
14631
+ return {};
14632
+ }
14633
+ }
14634
+ var claudeConfigLock = Promise.resolve();
14635
+ function updateClaudeConfig(updates) {
14636
+ claudeConfigLock = claudeConfigLock.then(() => {
14637
+ const configPath = getClaudeConfigPath();
14638
+ const current = getClaudeConfig();
14639
+ const merged = { ...current, ...updates };
14640
+ fs2.writeFileSync(configPath, JSON.stringify(merged, null, 2), "utf-8");
14641
+ }).catch((err) => {
14642
+ log2.settings.error("Failed to update Claude config", { error: String(err) });
14643
+ });
14644
+ }
14645
+ function syncClaudeCodeTheme(resolvedTheme) {
14646
+ const settings = getSettings();
14647
+ if (!settings.appearance.syncClaudeCodeTheme)
14648
+ return;
14649
+ const claudeTheme = resolvedTheme === "light" ? settings.appearance.claudeCodeLightTheme : settings.appearance.claudeCodeDarkTheme;
14650
+ updateClaudeConfig({ theme: claudeTheme });
14651
+ log2.settings.info("Synced Claude Code theme", { claudeTheme, resolvedTheme });
14652
+ }
14653
+ var DEFAULT_ZAI_SETTINGS = {
14654
+ enabled: false,
14655
+ apiKey: null,
14656
+ haikuModel: "glm-4.5-air",
14657
+ sonnetModel: "glm-4.7",
14658
+ opusModel: "glm-4.7"
14659
+ };
14660
+ function getZAiSettings() {
14661
+ ensureViboraDir();
14662
+ const settingsPath = getSettingsPath();
14663
+ if (!fs2.existsSync(settingsPath)) {
14664
+ return DEFAULT_ZAI_SETTINGS;
14665
+ }
14666
+ try {
14667
+ const content = fs2.readFileSync(settingsPath, "utf-8");
14668
+ const parsed = JSON.parse(content);
14669
+ const zai = parsed.zai;
14670
+ if (!zai) {
14671
+ return DEFAULT_ZAI_SETTINGS;
14672
+ }
14673
+ return {
14674
+ enabled: zai.enabled ?? false,
14675
+ apiKey: zai.apiKey ?? null,
14676
+ haikuModel: zai.haikuModel ?? DEFAULT_ZAI_SETTINGS.haikuModel,
14677
+ sonnetModel: zai.sonnetModel ?? DEFAULT_ZAI_SETTINGS.sonnetModel,
14678
+ opusModel: zai.opusModel ?? DEFAULT_ZAI_SETTINGS.opusModel
14679
+ };
14680
+ } catch {
14681
+ return DEFAULT_ZAI_SETTINGS;
14682
+ }
14683
+ }
14684
+ function updateZAiSettings(updates) {
14685
+ ensureViboraDir();
14686
+ const settingsPath = getSettingsPath();
14687
+ let parsed = {};
14688
+ if (fs2.existsSync(settingsPath)) {
14689
+ try {
14690
+ parsed = JSON.parse(fs2.readFileSync(settingsPath, "utf-8"));
14691
+ } catch {}
14692
+ }
14693
+ const current = getZAiSettings();
14694
+ const updated = {
14695
+ enabled: updates.enabled ?? current.enabled,
14696
+ apiKey: updates.apiKey !== undefined ? updates.apiKey : current.apiKey,
14697
+ haikuModel: updates.haikuModel ?? current.haikuModel,
14698
+ sonnetModel: updates.sonnetModel ?? current.sonnetModel,
14699
+ opusModel: updates.opusModel ?? current.opusModel
14700
+ };
14701
+ parsed.zai = updated;
14702
+ fs2.writeFileSync(settingsPath, JSON.stringify(parsed, null, 2), "utf-8");
14703
+ return updated;
14704
+ }
14705
+
15046
14706
  // server/db/index.ts
15047
14707
  var _db = null;
15048
14708
  var _sqlite = null;
@@ -146676,8 +146336,6 @@ import { spawn as spawn2 } from "child_process";
146676
146336
  var CONFIG_KEYS = {
146677
146337
  PORT: "server.port",
146678
146338
  DEFAULT_GIT_REPOS_DIR: "paths.defaultGitReposDir",
146679
- BASIC_AUTH_USERNAME: "authentication.username",
146680
- BASIC_AUTH_PASSWORD: "authentication.password",
146681
146339
  REMOTE_HOST: "remoteVibora.host",
146682
146340
  REMOTE_PORT: "remoteVibora.port",
146683
146341
  EDITOR_APP: "editor.app",
@@ -146694,8 +146352,6 @@ var CONFIG_KEYS = {
146694
146352
  var LEGACY_KEY_MAP = {
146695
146353
  port: "server.port",
146696
146354
  default_git_repos_dir: "paths.defaultGitReposDir",
146697
- basic_auth_username: "authentication.username",
146698
- basic_auth_password: "authentication.password",
146699
146355
  remote_host: "remoteVibora.host",
146700
146356
  hostname: "remoteVibora.host",
146701
146357
  ssh_port: "editor.sshPort",
@@ -146704,8 +146360,6 @@ var LEGACY_KEY_MAP = {
146704
146360
  language: "appearance.language",
146705
146361
  theme: "appearance.theme",
146706
146362
  defaultGitReposDir: "paths.defaultGitReposDir",
146707
- basicAuthUsername: "authentication.username",
146708
- basicAuthPassword: "authentication.password",
146709
146363
  remoteHost: "remoteVibora.host",
146710
146364
  sshPort: "editor.sshPort",
146711
146365
  linearApiKey: "integrations.linearApiKey",
@@ -146862,13 +146516,6 @@ app5.get("/:key", (c) => {
146862
146516
  const value = getSettingValue(path8);
146863
146517
  const defaultValue = getDefaultValue(path8);
146864
146518
  const isDefault = value === defaultValue || value === undefined || value === null;
146865
- if (path8 === CONFIG_KEYS.BASIC_AUTH_PASSWORD) {
146866
- return c.json({
146867
- key,
146868
- value: value ? "\u2022\u2022\u2022\u2022\u2022\u2022\u2022\u2022" : null,
146869
- isDefault: value === null || value === undefined
146870
- });
146871
- }
146872
146519
  return c.json({ key, value: value ?? defaultValue, isDefault });
146873
146520
  });
146874
146521
  app5.put("/:key", async (c) => {
@@ -146910,14 +146557,11 @@ app5.put("/:key", async (c) => {
146910
146557
  return c.json({ error: `Editor app must be one of: ${validApps.join(", ")}` }, 400);
146911
146558
  }
146912
146559
  } else if (typeof value === "string" && value === "") {
146913
- if (path8 === CONFIG_KEYS.LINEAR_API_KEY || path8 === CONFIG_KEYS.GITHUB_PAT || path8 === CONFIG_KEYS.BASIC_AUTH_USERNAME || path8 === CONFIG_KEYS.BASIC_AUTH_PASSWORD || path8 === CONFIG_KEYS.REMOTE_HOST || path8 === CONFIG_KEYS.EDITOR_HOST) {
146560
+ if (path8 === CONFIG_KEYS.LINEAR_API_KEY || path8 === CONFIG_KEYS.GITHUB_PAT || path8 === CONFIG_KEYS.REMOTE_HOST || path8 === CONFIG_KEYS.EDITOR_HOST) {
146914
146561
  value = null;
146915
146562
  }
146916
146563
  }
146917
146564
  updateSettingByPath(path8, value);
146918
- if (path8 === CONFIG_KEYS.BASIC_AUTH_PASSWORD) {
146919
- return c.json({ key, value: value ? "\u2022\u2022\u2022\u2022\u2022\u2022\u2022\u2022" : null });
146920
- }
146921
146565
  return c.json({ key, value });
146922
146566
  } catch (err) {
146923
146567
  return c.json({ error: err instanceof Error ? err.message : "Failed to set config" }, 400);
@@ -148271,7 +147915,7 @@ function expand2(template, context) {
148271
147915
  return template.replace(/\/$/, "");
148272
147916
  }
148273
147917
  }
148274
- function parse2(options) {
147918
+ function parse(options) {
148275
147919
  let method = options.method.toUpperCase();
148276
147920
  let url = (options.url || "/").replace(/:([a-z]\w+)/g, "{$1}");
148277
147921
  let headers = Object.assign({}, options.headers);
@@ -148326,7 +147970,7 @@ function parse2(options) {
148326
147970
  return Object.assign({ method, url, headers }, typeof body !== "undefined" ? { body } : null, options.request ? { request: options.request } : null);
148327
147971
  }
148328
147972
  function endpointWithDefaults(defaults2, route, options) {
148329
- return parse2(merge(defaults2, route, options));
147973
+ return parse(merge(defaults2, route, options));
148330
147974
  }
148331
147975
  function withDefaults(oldDefaults, newDefaults) {
148332
147976
  const DEFAULTS2 = merge(oldDefaults, newDefaults);
@@ -148335,7 +147979,7 @@ function withDefaults(oldDefaults, newDefaults) {
148335
147979
  DEFAULTS: DEFAULTS2,
148336
147980
  defaults: withDefaults.bind(null, DEFAULTS2),
148337
147981
  merge: merge.bind(null, DEFAULTS2),
148338
- parse: parse2
147982
+ parse
148339
147983
  });
148340
147984
  }
148341
147985
  var endpoint = withDefaults(null, DEFAULTS);
@@ -151641,59 +151285,6 @@ app12.get("/prs", async (c) => {
151641
151285
  });
151642
151286
  var github_default = app12;
151643
151287
 
151644
- // server/routes/auth.ts
151645
- var SESSION_COOKIE_NAME2 = "vibora_session";
151646
- var SESSION_EXPIRY_MS = 14 * 24 * 60 * 60 * 1000;
151647
- var app13 = new Hono2;
151648
- app13.post("/login", async (c) => {
151649
- const { username, password } = await c.req.json();
151650
- const settings = getSettings();
151651
- if (!settings.basicAuthUsername || !settings.basicAuthPassword) {
151652
- return c.json({ error: "Authentication not configured" }, 500);
151653
- }
151654
- if (username !== settings.basicAuthUsername || password !== settings.basicAuthPassword) {
151655
- return c.json({ error: "Invalid credentials" }, 401);
151656
- }
151657
- const secret = getSessionSecret();
151658
- if (!secret) {
151659
- return c.json({ error: "Session secret not available" }, 500);
151660
- }
151661
- const expiry = Date.now() + SESSION_EXPIRY_MS;
151662
- const sessionData = JSON.stringify({ exp: expiry });
151663
- await setSignedCookie(c, SESSION_COOKIE_NAME2, sessionData, secret, {
151664
- path: "/",
151665
- httpOnly: true,
151666
- sameSite: "Strict",
151667
- maxAge: SESSION_EXPIRY_MS / 1000
151668
- });
151669
- return c.json({ success: true, expiresAt: new Date(expiry).toISOString() });
151670
- });
151671
- app13.post("/logout", async (c) => {
151672
- deleteCookie(c, SESSION_COOKIE_NAME2, { path: "/" });
151673
- return c.json({ success: true });
151674
- });
151675
- app13.get("/check", async (c) => {
151676
- const settings = getSettings();
151677
- if (!settings.basicAuthUsername || !settings.basicAuthPassword) {
151678
- return c.json({ authRequired: false, authenticated: true });
151679
- }
151680
- const secret = getSessionSecret();
151681
- if (!secret) {
151682
- return c.json({ authRequired: true, authenticated: false });
151683
- }
151684
- const sessionCookie = await getSignedCookie(c, secret, SESSION_COOKIE_NAME2);
151685
- if (sessionCookie) {
151686
- try {
151687
- const session = JSON.parse(sessionCookie);
151688
- if (session.exp && session.exp > Date.now()) {
151689
- return c.json({ authRequired: true, authenticated: true });
151690
- }
151691
- } catch {}
151692
- }
151693
- return c.json({ authRequired: true, authenticated: false });
151694
- });
151695
- var auth_default = app13;
151696
-
151697
151288
  // server/routes/monitoring.ts
151698
151289
  import { readdirSync as readdirSync7, readFileSync as readFileSync7, readlinkSync as readlinkSync2, existsSync as existsSync11 } from "fs";
151699
151290
  import { execSync as execSync6 } from "child_process";
@@ -152655,36 +152246,34 @@ function getDistPath() {
152655
152246
  return join14(process.cwd(), "dist");
152656
152247
  }
152657
152248
  function createApp() {
152658
- const app14 = new Hono2;
152659
- app14.use("*", logger());
152660
- app14.use("*", cors({
152249
+ const app13 = new Hono2;
152250
+ app13.use("*", logger());
152251
+ app13.use("*", cors({
152661
152252
  origin: "*",
152662
152253
  allowMethods: ["GET", "POST", "PATCH", "PUT", "DELETE", "OPTIONS"],
152663
- allowHeaders: ["Content-Type", "Authorization"]
152254
+ allowHeaders: ["Content-Type"]
152664
152255
  }));
152665
- app14.use("*", sessionAuthMiddleware);
152666
- app14.route("/health", health_default);
152667
- app14.route("/api/tasks", tasks_default);
152668
- app14.route("/api/git", git_default);
152669
- app14.route("/api/fs", filesystem_default);
152670
- app14.route("/api/config", config_default);
152671
- app14.route("/api/uploads", uploads_default);
152672
- app14.route("/api/worktrees", worktrees_default);
152673
- app14.route("/api/terminal-view-state", terminal_view_state_default);
152674
- app14.route("/api/repositories", repositories_default);
152675
- app14.route("/api/copier", copier_default);
152676
- app14.route("/api/linear", linear_default);
152677
- app14.route("/api/github", github_default);
152678
- app14.route("/api/auth", auth_default);
152679
- app14.route("/api/monitoring", monitoringRoutes);
152680
- app14.post("/api/logs", async (c) => {
152256
+ app13.route("/health", health_default);
152257
+ app13.route("/api/tasks", tasks_default);
152258
+ app13.route("/api/git", git_default);
152259
+ app13.route("/api/fs", filesystem_default);
152260
+ app13.route("/api/config", config_default);
152261
+ app13.route("/api/uploads", uploads_default);
152262
+ app13.route("/api/worktrees", worktrees_default);
152263
+ app13.route("/api/terminal-view-state", terminal_view_state_default);
152264
+ app13.route("/api/repositories", repositories_default);
152265
+ app13.route("/api/copier", copier_default);
152266
+ app13.route("/api/linear", linear_default);
152267
+ app13.route("/api/github", github_default);
152268
+ app13.route("/api/monitoring", monitoringRoutes);
152269
+ app13.post("/api/logs", async (c) => {
152681
152270
  const { entries } = await c.req.json();
152682
152271
  for (const entry of entries) {
152683
152272
  writeEntry(entry);
152684
152273
  }
152685
152274
  return c.json({ ok: true });
152686
152275
  });
152687
- app14.post("/api/debug", async (c) => {
152276
+ app13.post("/api/debug", async (c) => {
152688
152277
  const body = await c.req.json();
152689
152278
  const entry = {
152690
152279
  ts: new Date().toISOString(),
@@ -152721,14 +152310,14 @@ function createApp() {
152721
152310
  headers: { "Content-Type": mimeTypes2[ext2 || ""] || "application/octet-stream" }
152722
152311
  });
152723
152312
  };
152724
- app14.get("/assets/*", async (c) => {
152313
+ app13.get("/assets/*", async (c) => {
152725
152314
  const assetPath = join14(distPath, c.req.path);
152726
152315
  if (existsSync12(assetPath)) {
152727
152316
  return serveFile(assetPath);
152728
152317
  }
152729
152318
  return c.notFound();
152730
152319
  });
152731
- app14.get("/sounds/*", async (c) => {
152320
+ app13.get("/sounds/*", async (c) => {
152732
152321
  const soundPath = join14(distPath, c.req.path);
152733
152322
  if (existsSync12(soundPath)) {
152734
152323
  return serveFile(soundPath);
@@ -152737,7 +152326,7 @@ function createApp() {
152737
152326
  });
152738
152327
  const staticFiles = ["vibora-icon.png", "vibora-logo.jpeg", "vite.svg", "logo-dark.jpg", "logo-light.jpg", "goat.jpeg"];
152739
152328
  for (const file of staticFiles) {
152740
- app14.get(`/${file}`, async () => {
152329
+ app13.get(`/${file}`, async () => {
152741
152330
  const filePath = join14(distPath, file);
152742
152331
  if (existsSync12(filePath)) {
152743
152332
  return serveFile(filePath);
@@ -152745,7 +152334,7 @@ function createApp() {
152745
152334
  return new Response("Not Found", { status: 404 });
152746
152335
  });
152747
152336
  }
152748
- app14.get("*", async (c, next) => {
152337
+ app13.get("*", async (c, next) => {
152749
152338
  const path9 = c.req.path;
152750
152339
  if (path9.startsWith("/api/") || path9.startsWith("/ws/") || path9 === "/health") {
152751
152340
  return next();
@@ -152754,7 +152343,7 @@ function createApp() {
152754
152343
  return c.html(html);
152755
152344
  });
152756
152345
  }
152757
- return app14;
152346
+ return app13;
152758
152347
  }
152759
152348
 
152760
152349
  // server/services/pr-monitor.ts
@@ -152857,11 +152446,11 @@ setBroadcastDestroyed((terminalId) => {
152857
152446
  payload: { terminalId }
152858
152447
  });
152859
152448
  });
152860
- var app14 = createApp();
152861
- var { injectWebSocket, upgradeWebSocket } = createNodeWebSocket({ app: app14 });
152862
- app14.get("/ws/terminal", upgradeWebSocket(() => terminalWebSocketHandlers));
152449
+ var app13 = createApp();
152450
+ var { injectWebSocket, upgradeWebSocket } = createNodeWebSocket({ app: app13 });
152451
+ app13.get("/ws/terminal", upgradeWebSocket(() => terminalWebSocketHandlers));
152863
152452
  var server = serve({
152864
- fetch: app14.fetch,
152453
+ fetch: app13.fetch,
152865
152454
  port: PORT,
152866
152455
  hostname: HOST
152867
152456
  }, (info) => {