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/README.md +7 -12
- package/bin/vibora.js +0 -46
- package/dist/assets/{index-r4Upl2GW.js → index-B_0ZMwER.js} +93 -93
- package/dist/assets/index-D643AGV4.css +1 -0
- package/dist/index.html +2 -2
- package/package.json +1 -1
- package/server/index.js +599 -1010
- package/dist/assets/index-C9swvEK_.css +0 -1
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
|
|
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 =
|
|
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
|
|
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 =
|
|
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
|
|
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
|
|
11784
|
-
if (pathChunkIndex <
|
|
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) &&
|
|
11793
|
-
const objectName =
|
|
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((
|
|
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((
|
|
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
|
|
14920
|
-
import
|
|
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 (!
|
|
14035
|
+
if (!fs.existsSync(journalPath)) {
|
|
14926
14036
|
throw new Error(`Can't find meta/_journal.json file`);
|
|
14927
14037
|
}
|
|
14928
|
-
const journalAsString =
|
|
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 =
|
|
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:
|
|
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.
|
|
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
|
|
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
|
|
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
|
|
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
|
|
152659
|
-
|
|
152660
|
-
|
|
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"
|
|
152254
|
+
allowHeaders: ["Content-Type"]
|
|
152664
152255
|
}));
|
|
152665
|
-
|
|
152666
|
-
|
|
152667
|
-
|
|
152668
|
-
|
|
152669
|
-
|
|
152670
|
-
|
|
152671
|
-
|
|
152672
|
-
|
|
152673
|
-
|
|
152674
|
-
|
|
152675
|
-
|
|
152676
|
-
|
|
152677
|
-
|
|
152678
|
-
|
|
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
|
-
|
|
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
|
-
|
|
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
|
-
|
|
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
|
-
|
|
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
|
-
|
|
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
|
|
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
|
|
152861
|
-
var { injectWebSocket, upgradeWebSocket } = createNodeWebSocket({ app:
|
|
152862
|
-
|
|
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:
|
|
152453
|
+
fetch: app13.fetch,
|
|
152865
152454
|
port: PORT,
|
|
152866
152455
|
hostname: HOST
|
|
152867
152456
|
}, (info) => {
|