vibora 2.0.0 → 2.1.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 +5 -5
- package/bin/vibora.js +46 -16
- package/dist/assets/index-B5Ujeicd.js +118 -0
- package/dist/assets/index-DGzCy3yX.css +1 -0
- package/dist/index.html +2 -2
- package/drizzle/0008_loose_killmonger.sql +1 -0
- package/drizzle/meta/0008_snapshot.json +507 -0
- package/drizzle/meta/_journal.json +7 -0
- package/package.json +1 -1
- package/server/index.js +426 -279
- package/dist/assets/index-CjOpmR5n.js +0 -118
- package/dist/assets/index-DsY5_TOf.css +0 -1
package/server/index.js
CHANGED
|
@@ -3503,17 +3503,204 @@ import * as fs from "fs";
|
|
|
3503
3503
|
import * as path from "path";
|
|
3504
3504
|
import * as os from "os";
|
|
3505
3505
|
import * as crypto3 from "crypto";
|
|
3506
|
-
|
|
3507
|
-
|
|
3508
|
-
|
|
3509
|
-
|
|
3510
|
-
|
|
3511
|
-
|
|
3512
|
-
|
|
3513
|
-
|
|
3514
|
-
|
|
3515
|
-
|
|
3506
|
+
|
|
3507
|
+
// server/lib/logger.ts
|
|
3508
|
+
import { appendFileSync } from "fs";
|
|
3509
|
+
import { join } from "path";
|
|
3510
|
+
|
|
3511
|
+
// shared/logger/types.ts
|
|
3512
|
+
var LOG_LEVELS = {
|
|
3513
|
+
debug: 0,
|
|
3514
|
+
info: 1,
|
|
3515
|
+
warn: 2,
|
|
3516
|
+
error: 3
|
|
3517
|
+
};
|
|
3518
|
+
function formatLogEntry(entry) {
|
|
3519
|
+
return JSON.stringify(entry);
|
|
3520
|
+
}
|
|
3521
|
+
// server/lib/logger.ts
|
|
3522
|
+
function getMinLevel() {
|
|
3523
|
+
const level = process.env.LOG_LEVEL;
|
|
3524
|
+
if (level && level in LOG_LEVELS) {
|
|
3525
|
+
return level;
|
|
3526
|
+
}
|
|
3527
|
+
return "info";
|
|
3528
|
+
}
|
|
3529
|
+
var logFilePath = null;
|
|
3530
|
+
function getLogFile() {
|
|
3531
|
+
if (logFilePath !== null) {
|
|
3532
|
+
return logFilePath || null;
|
|
3533
|
+
}
|
|
3534
|
+
try {
|
|
3535
|
+
ensureViboraDir();
|
|
3536
|
+
logFilePath = join(getViboraDir(), "vibora.log");
|
|
3537
|
+
return logFilePath;
|
|
3538
|
+
} catch {
|
|
3539
|
+
logFilePath = "";
|
|
3540
|
+
return null;
|
|
3541
|
+
}
|
|
3542
|
+
}
|
|
3543
|
+
function writeEntry(entry) {
|
|
3544
|
+
const line = formatLogEntry(entry);
|
|
3545
|
+
console.log(line);
|
|
3546
|
+
const logFile = getLogFile();
|
|
3547
|
+
if (logFile) {
|
|
3548
|
+
try {
|
|
3549
|
+
appendFileSync(logFile, line + `
|
|
3550
|
+
`);
|
|
3551
|
+
} catch {}
|
|
3552
|
+
}
|
|
3553
|
+
}
|
|
3554
|
+
|
|
3555
|
+
class ServerLogger {
|
|
3556
|
+
component;
|
|
3557
|
+
minLevel;
|
|
3558
|
+
constructor(component, minLevel) {
|
|
3559
|
+
this.component = component;
|
|
3560
|
+
this.minLevel = minLevel ?? getMinLevel();
|
|
3561
|
+
}
|
|
3562
|
+
shouldLog(level) {
|
|
3563
|
+
return LOG_LEVELS[level] >= LOG_LEVELS[this.minLevel];
|
|
3564
|
+
}
|
|
3565
|
+
log(level, msg, ctx) {
|
|
3566
|
+
if (!this.shouldLog(level))
|
|
3567
|
+
return;
|
|
3568
|
+
writeEntry({
|
|
3569
|
+
ts: new Date().toISOString(),
|
|
3570
|
+
lvl: level,
|
|
3571
|
+
src: this.component,
|
|
3572
|
+
msg,
|
|
3573
|
+
...ctx && Object.keys(ctx).length > 0 ? { ctx } : {}
|
|
3574
|
+
});
|
|
3575
|
+
}
|
|
3576
|
+
debug(msg, ctx) {
|
|
3577
|
+
this.log("debug", msg, ctx);
|
|
3578
|
+
}
|
|
3579
|
+
info(msg, ctx) {
|
|
3580
|
+
this.log("info", msg, ctx);
|
|
3581
|
+
}
|
|
3582
|
+
warn(msg, ctx) {
|
|
3583
|
+
this.log("warn", msg, ctx);
|
|
3584
|
+
}
|
|
3585
|
+
error(msg, ctx) {
|
|
3586
|
+
this.log("error", msg, ctx);
|
|
3587
|
+
}
|
|
3588
|
+
child(component) {
|
|
3589
|
+
return new ServerLogger(`${this.component}/${component}`, this.minLevel);
|
|
3590
|
+
}
|
|
3591
|
+
}
|
|
3592
|
+
function createLogger(component) {
|
|
3593
|
+
return new ServerLogger(component);
|
|
3594
|
+
}
|
|
3595
|
+
var log2 = {
|
|
3596
|
+
pty: createLogger("PTYManager"),
|
|
3597
|
+
ws: createLogger("WS"),
|
|
3598
|
+
terminal: createLogger("Terminal"),
|
|
3599
|
+
buffer: createLogger("BufferManager"),
|
|
3600
|
+
desktop: createLogger("Desktop"),
|
|
3601
|
+
api: createLogger("API"),
|
|
3602
|
+
metrics: createLogger("MetricsCollector"),
|
|
3603
|
+
pr: createLogger("PRMonitor"),
|
|
3604
|
+
github: createLogger("GitHub"),
|
|
3605
|
+
linear: createLogger("Linear"),
|
|
3606
|
+
notification: createLogger("Notification"),
|
|
3607
|
+
server: createLogger("Server"),
|
|
3608
|
+
settings: createLogger("Settings")
|
|
3516
3609
|
};
|
|
3610
|
+
|
|
3611
|
+
// server/lib/settings.ts
|
|
3612
|
+
var CURRENT_SCHEMA_VERSION = 2;
|
|
3613
|
+
var DEFAULT_SETTINGS = {
|
|
3614
|
+
_schemaVersion: CURRENT_SCHEMA_VERSION,
|
|
3615
|
+
server: {
|
|
3616
|
+
port: 7777
|
|
3617
|
+
},
|
|
3618
|
+
paths: {
|
|
3619
|
+
defaultGitReposDir: os.homedir()
|
|
3620
|
+
},
|
|
3621
|
+
authentication: {
|
|
3622
|
+
username: null,
|
|
3623
|
+
password: null
|
|
3624
|
+
},
|
|
3625
|
+
remoteVibora: {
|
|
3626
|
+
host: "",
|
|
3627
|
+
port: 7777
|
|
3628
|
+
},
|
|
3629
|
+
editor: {
|
|
3630
|
+
app: "vscode",
|
|
3631
|
+
host: "",
|
|
3632
|
+
sshPort: 22
|
|
3633
|
+
},
|
|
3634
|
+
integrations: {
|
|
3635
|
+
linearApiKey: null,
|
|
3636
|
+
githubPat: null
|
|
3637
|
+
},
|
|
3638
|
+
appearance: {
|
|
3639
|
+
language: null
|
|
3640
|
+
}
|
|
3641
|
+
};
|
|
3642
|
+
var OLD_DEFAULT_PORT = 3333;
|
|
3643
|
+
var MIGRATION_MAP = {
|
|
3644
|
+
port: "server.port",
|
|
3645
|
+
defaultGitReposDir: "paths.defaultGitReposDir",
|
|
3646
|
+
basicAuthUsername: "authentication.username",
|
|
3647
|
+
basicAuthPassword: "authentication.password",
|
|
3648
|
+
remoteHost: "remoteVibora.host",
|
|
3649
|
+
hostname: "remoteVibora.host",
|
|
3650
|
+
sshPort: "editor.sshPort",
|
|
3651
|
+
linearApiKey: "integrations.linearApiKey",
|
|
3652
|
+
githubPat: "integrations.githubPat",
|
|
3653
|
+
language: "appearance.language"
|
|
3654
|
+
};
|
|
3655
|
+
function getNestedValue(obj, path2) {
|
|
3656
|
+
return path2.split(".").reduce((o, k) => {
|
|
3657
|
+
if (o && typeof o === "object") {
|
|
3658
|
+
return o[k];
|
|
3659
|
+
}
|
|
3660
|
+
return;
|
|
3661
|
+
}, obj);
|
|
3662
|
+
}
|
|
3663
|
+
function setNestedValue(obj, path2, value) {
|
|
3664
|
+
const keys = path2.split(".");
|
|
3665
|
+
const lastKey = keys.pop();
|
|
3666
|
+
let current = obj;
|
|
3667
|
+
for (const key of keys) {
|
|
3668
|
+
if (!(key in current) || typeof current[key] !== "object" || current[key] === null) {
|
|
3669
|
+
current[key] = {};
|
|
3670
|
+
}
|
|
3671
|
+
current = current[key];
|
|
3672
|
+
}
|
|
3673
|
+
current[lastKey] = value;
|
|
3674
|
+
}
|
|
3675
|
+
function migrateSettings(parsed) {
|
|
3676
|
+
const result = { migrated: false, migratedKeys: [], warnings: [] };
|
|
3677
|
+
const version = parsed._schemaVersion ?? 1;
|
|
3678
|
+
if (version >= CURRENT_SCHEMA_VERSION) {
|
|
3679
|
+
return result;
|
|
3680
|
+
}
|
|
3681
|
+
for (const [oldKey, newPath] of Object.entries(MIGRATION_MAP)) {
|
|
3682
|
+
if (oldKey in parsed && parsed[oldKey] !== undefined) {
|
|
3683
|
+
const oldValue = parsed[oldKey];
|
|
3684
|
+
if (oldKey === "port" && oldValue === OLD_DEFAULT_PORT) {
|
|
3685
|
+
delete parsed[oldKey];
|
|
3686
|
+
result.migrated = true;
|
|
3687
|
+
continue;
|
|
3688
|
+
}
|
|
3689
|
+
const existingValue = getNestedValue(parsed, newPath);
|
|
3690
|
+
if (existingValue !== undefined) {
|
|
3691
|
+
result.warnings.push(`Key "${oldKey}" exists but "${newPath}" already set. Removing old key.`);
|
|
3692
|
+
} else {
|
|
3693
|
+
setNestedValue(parsed, newPath, oldValue);
|
|
3694
|
+
result.migratedKeys.push(oldKey);
|
|
3695
|
+
}
|
|
3696
|
+
delete parsed[oldKey];
|
|
3697
|
+
result.migrated = true;
|
|
3698
|
+
}
|
|
3699
|
+
}
|
|
3700
|
+
parsed._schemaVersion = CURRENT_SCHEMA_VERSION;
|
|
3701
|
+
result.migrated = true;
|
|
3702
|
+
return result;
|
|
3703
|
+
}
|
|
3517
3704
|
function expandPath(p) {
|
|
3518
3705
|
if (p.startsWith("~/")) {
|
|
3519
3706
|
return path.join(os.homedir(), p.slice(2));
|
|
@@ -3575,60 +3762,127 @@ function getSettings() {
|
|
|
3575
3762
|
parsed = JSON.parse(content);
|
|
3576
3763
|
} catch {}
|
|
3577
3764
|
}
|
|
3578
|
-
const
|
|
3579
|
-
|
|
3765
|
+
const migrationResult = migrateSettings(parsed);
|
|
3766
|
+
if (migrationResult.migrated) {
|
|
3767
|
+
if (migrationResult.migratedKeys.length > 0) {
|
|
3768
|
+
log2.settings.info("Migrated settings to nested structure", {
|
|
3769
|
+
migratedKeys: migrationResult.migratedKeys
|
|
3770
|
+
});
|
|
3771
|
+
}
|
|
3772
|
+
if (migrationResult.warnings.length > 0) {
|
|
3773
|
+
log2.settings.warn("Settings migration warnings", {
|
|
3774
|
+
warnings: migrationResult.warnings
|
|
3775
|
+
});
|
|
3776
|
+
}
|
|
3777
|
+
fs.writeFileSync(settingsPath, JSON.stringify(parsed, null, 2), "utf-8");
|
|
3778
|
+
}
|
|
3580
3779
|
const fileSettings = {
|
|
3581
|
-
|
|
3582
|
-
|
|
3583
|
-
|
|
3584
|
-
|
|
3585
|
-
|
|
3586
|
-
|
|
3587
|
-
|
|
3588
|
-
|
|
3589
|
-
|
|
3780
|
+
_schemaVersion: CURRENT_SCHEMA_VERSION,
|
|
3781
|
+
server: {
|
|
3782
|
+
port: parsed.server?.port ?? DEFAULT_SETTINGS.server.port
|
|
3783
|
+
},
|
|
3784
|
+
paths: {
|
|
3785
|
+
defaultGitReposDir: expandPath(parsed.paths?.defaultGitReposDir ?? DEFAULT_SETTINGS.paths.defaultGitReposDir)
|
|
3786
|
+
},
|
|
3787
|
+
authentication: {
|
|
3788
|
+
username: parsed.authentication?.username ?? null,
|
|
3789
|
+
password: parsed.authentication?.password ?? null
|
|
3790
|
+
},
|
|
3791
|
+
remoteVibora: {
|
|
3792
|
+
host: parsed.remoteVibora?.host ?? DEFAULT_SETTINGS.remoteVibora.host,
|
|
3793
|
+
port: parsed.remoteVibora?.port ?? DEFAULT_SETTINGS.remoteVibora.port
|
|
3794
|
+
},
|
|
3795
|
+
editor: {
|
|
3796
|
+
app: parsed.editor?.app ?? DEFAULT_SETTINGS.editor.app,
|
|
3797
|
+
host: parsed.editor?.host ?? DEFAULT_SETTINGS.editor.host,
|
|
3798
|
+
sshPort: parsed.editor?.sshPort ?? DEFAULT_SETTINGS.editor.sshPort
|
|
3799
|
+
},
|
|
3800
|
+
integrations: {
|
|
3801
|
+
linearApiKey: parsed.integrations?.linearApiKey ?? null,
|
|
3802
|
+
githubPat: parsed.integrations?.githubPat ?? null
|
|
3803
|
+
},
|
|
3804
|
+
appearance: {
|
|
3805
|
+
language: parsed.appearance?.language ?? null
|
|
3806
|
+
}
|
|
3590
3807
|
};
|
|
3591
|
-
if (hasMissingKeys) {
|
|
3592
|
-
fs.writeFileSync(settingsPath, JSON.stringify(fileSettings, null, 2), "utf-8");
|
|
3593
|
-
}
|
|
3594
3808
|
const portEnv = parseInt(process.env.PORT || "", 10);
|
|
3595
|
-
const
|
|
3809
|
+
const editorSshPortEnv = parseInt(process.env.VIBORA_SSH_PORT || "", 10);
|
|
3596
3810
|
return {
|
|
3597
|
-
|
|
3598
|
-
|
|
3599
|
-
|
|
3600
|
-
|
|
3601
|
-
|
|
3602
|
-
|
|
3603
|
-
|
|
3604
|
-
|
|
3605
|
-
|
|
3811
|
+
...fileSettings,
|
|
3812
|
+
server: {
|
|
3813
|
+
port: !isNaN(portEnv) && portEnv > 0 ? portEnv : fileSettings.server.port
|
|
3814
|
+
},
|
|
3815
|
+
paths: {
|
|
3816
|
+
defaultGitReposDir: process.env.VIBORA_GIT_REPOS_DIR ? expandPath(process.env.VIBORA_GIT_REPOS_DIR) : fileSettings.paths.defaultGitReposDir
|
|
3817
|
+
},
|
|
3818
|
+
authentication: {
|
|
3819
|
+
username: process.env.VIBORA_BASIC_AUTH_USERNAME ?? fileSettings.authentication.username,
|
|
3820
|
+
password: process.env.VIBORA_BASIC_AUTH_PASSWORD ?? fileSettings.authentication.password
|
|
3821
|
+
},
|
|
3822
|
+
remoteVibora: {
|
|
3823
|
+
host: process.env.VIBORA_REMOTE_HOST ?? process.env.VIBORA_HOSTNAME ?? fileSettings.remoteVibora.host,
|
|
3824
|
+
port: fileSettings.remoteVibora.port
|
|
3825
|
+
},
|
|
3826
|
+
editor: {
|
|
3827
|
+
app: fileSettings.editor.app,
|
|
3828
|
+
host: process.env.VIBORA_EDITOR_HOST ?? fileSettings.editor.host,
|
|
3829
|
+
sshPort: !isNaN(editorSshPortEnv) && editorSshPortEnv > 0 ? editorSshPortEnv : fileSettings.editor.sshPort
|
|
3830
|
+
},
|
|
3831
|
+
integrations: {
|
|
3832
|
+
linearApiKey: process.env.LINEAR_API_KEY ?? fileSettings.integrations.linearApiKey,
|
|
3833
|
+
githubPat: process.env.GITHUB_PAT ?? fileSettings.integrations.githubPat
|
|
3834
|
+
},
|
|
3835
|
+
appearance: fileSettings.appearance
|
|
3606
3836
|
};
|
|
3607
3837
|
}
|
|
3608
|
-
function getSetting(
|
|
3609
|
-
|
|
3838
|
+
function getSetting(path2) {
|
|
3839
|
+
const settings = getSettings();
|
|
3840
|
+
return getNestedValue(settings, path2);
|
|
3841
|
+
}
|
|
3842
|
+
function getSettingByKey(key) {
|
|
3843
|
+
const settings = getSettings();
|
|
3844
|
+
const legacySettings = toLegacySettings(settings);
|
|
3845
|
+
return legacySettings[key];
|
|
3846
|
+
}
|
|
3847
|
+
function toLegacySettings(settings) {
|
|
3848
|
+
return {
|
|
3849
|
+
port: settings.server.port,
|
|
3850
|
+
defaultGitReposDir: settings.paths.defaultGitReposDir,
|
|
3851
|
+
remoteHost: settings.remoteVibora.host,
|
|
3852
|
+
sshPort: settings.editor.sshPort,
|
|
3853
|
+
basicAuthUsername: settings.authentication.username,
|
|
3854
|
+
basicAuthPassword: settings.authentication.password,
|
|
3855
|
+
linearApiKey: settings.integrations.linearApiKey,
|
|
3856
|
+
githubPat: settings.integrations.githubPat,
|
|
3857
|
+
language: settings.appearance.language
|
|
3858
|
+
};
|
|
3610
3859
|
}
|
|
3611
3860
|
function isDeveloperMode() {
|
|
3612
3861
|
return process.env.VIBORA_DEVELOPER === "1" || process.env.VIBORA_DEVELOPER === "true";
|
|
3613
3862
|
}
|
|
3614
3863
|
function getSessionSecret() {
|
|
3615
3864
|
const settings = getSettings();
|
|
3616
|
-
if (!settings.
|
|
3865
|
+
if (!settings.authentication.password) {
|
|
3617
3866
|
return null;
|
|
3618
3867
|
}
|
|
3619
|
-
return crypto3.createHash("sha256").update(settings.
|
|
3868
|
+
return crypto3.createHash("sha256").update(settings.authentication.password + "vibora-session").digest("hex");
|
|
3620
3869
|
}
|
|
3621
|
-
function
|
|
3870
|
+
function updateSettingByPath(settingPath, value) {
|
|
3622
3871
|
ensureViboraDir();
|
|
3623
|
-
const
|
|
3624
|
-
|
|
3625
|
-
fs.
|
|
3626
|
-
|
|
3872
|
+
const settingsPath = getSettingsPath();
|
|
3873
|
+
let parsed = {};
|
|
3874
|
+
if (fs.existsSync(settingsPath)) {
|
|
3875
|
+
try {
|
|
3876
|
+
parsed = JSON.parse(fs.readFileSync(settingsPath, "utf-8"));
|
|
3877
|
+
} catch {}
|
|
3878
|
+
}
|
|
3879
|
+
setNestedValue(parsed, settingPath, value);
|
|
3880
|
+
parsed._schemaVersion = CURRENT_SCHEMA_VERSION;
|
|
3881
|
+
fs.writeFileSync(settingsPath, JSON.stringify(parsed, null, 2), "utf-8");
|
|
3882
|
+
return getSettings();
|
|
3627
3883
|
}
|
|
3628
|
-
function
|
|
3629
|
-
|
|
3630
|
-
fs.writeFileSync(getSettingsPath(), JSON.stringify(DEFAULT_SETTINGS, null, 2), "utf-8");
|
|
3631
|
-
return { ...DEFAULT_SETTINGS };
|
|
3884
|
+
function getDefaultValue(settingPath) {
|
|
3885
|
+
return getNestedValue(DEFAULT_SETTINGS, settingPath);
|
|
3632
3886
|
}
|
|
3633
3887
|
var DEFAULT_NOTIFICATION_SETTINGS = {
|
|
3634
3888
|
enabled: false,
|
|
@@ -4444,7 +4698,7 @@ function sql(strings, ...params) {
|
|
|
4444
4698
|
return new SQL([new StringChunk(str)]);
|
|
4445
4699
|
}
|
|
4446
4700
|
sql2.raw = raw2;
|
|
4447
|
-
function
|
|
4701
|
+
function join3(chunks, separator) {
|
|
4448
4702
|
const result = [];
|
|
4449
4703
|
for (const [i, chunk] of chunks.entries()) {
|
|
4450
4704
|
if (i > 0 && separator !== undefined) {
|
|
@@ -4454,7 +4708,7 @@ function sql(strings, ...params) {
|
|
|
4454
4708
|
}
|
|
4455
4709
|
return new SQL(result);
|
|
4456
4710
|
}
|
|
4457
|
-
sql2.join =
|
|
4711
|
+
sql2.join = join3;
|
|
4458
4712
|
function identifier(value) {
|
|
4459
4713
|
return new Name(value);
|
|
4460
4714
|
}
|
|
@@ -6577,7 +6831,7 @@ class SQLiteSelectQueryBuilderBase extends TypedQueryBuilder {
|
|
|
6577
6831
|
const tableName = getTableLikeName(table);
|
|
6578
6832
|
for (const item of extractUsedTable(table))
|
|
6579
6833
|
this.usedTables.add(item);
|
|
6580
|
-
if (typeof tableName === "string" && this.config.joins?.some((
|
|
6834
|
+
if (typeof tableName === "string" && this.config.joins?.some((join3) => join3.alias === tableName)) {
|
|
6581
6835
|
throw new Error(`Alias "${tableName}" is already used in this query`);
|
|
6582
6836
|
}
|
|
6583
6837
|
if (!this.isPartialSelect) {
|
|
@@ -6991,7 +7245,7 @@ class SQLiteUpdateBase extends QueryPromise {
|
|
|
6991
7245
|
createJoin(joinType) {
|
|
6992
7246
|
return (table, on) => {
|
|
6993
7247
|
const tableName = getTableLikeName(table);
|
|
6994
|
-
if (typeof tableName === "string" && this.config.joins.some((
|
|
7248
|
+
if (typeof tableName === "string" && this.config.joins.some((join3) => join3.alias === tableName)) {
|
|
6995
7249
|
throw new Error(`Alias "${tableName}" is already used in this query`);
|
|
6996
7250
|
}
|
|
6997
7251
|
if (typeof on === "function") {
|
|
@@ -7734,7 +7988,7 @@ function migrate(db, config) {
|
|
|
7734
7988
|
|
|
7735
7989
|
// server/db/index.ts
|
|
7736
7990
|
import { Database as Database2 } from "bun:sqlite";
|
|
7737
|
-
import { join as
|
|
7991
|
+
import { join as join3 } from "path";
|
|
7738
7992
|
import { readdirSync } from "fs";
|
|
7739
7993
|
|
|
7740
7994
|
// server/db/schema.ts
|
|
@@ -7804,6 +8058,7 @@ var repositories = sqliteTable("repositories", {
|
|
|
7804
8058
|
startupScript: text("startup_script"),
|
|
7805
8059
|
copyFiles: text("copy_files"),
|
|
7806
8060
|
remoteUrl: text("remote_url"),
|
|
8061
|
+
lastUsedAt: text("last_used_at"),
|
|
7807
8062
|
createdAt: text("created_at").notNull(),
|
|
7808
8063
|
updatedAt: text("updated_at").notNull()
|
|
7809
8064
|
});
|
|
@@ -7825,7 +8080,7 @@ var sqlite = new Database2(dbPath);
|
|
|
7825
8080
|
sqlite.exec("PRAGMA journal_mode = WAL");
|
|
7826
8081
|
var db = drizzle(sqlite, { schema: exports_schema });
|
|
7827
8082
|
if (process.env.VIBORA_PACKAGE_ROOT) {
|
|
7828
|
-
const migrationsPath =
|
|
8083
|
+
const migrationsPath = join3(process.env.VIBORA_PACKAGE_ROOT, "drizzle");
|
|
7829
8084
|
const hasTasksTable = sqlite.query("SELECT name FROM sqlite_master WHERE type='table' AND name='tasks'").get();
|
|
7830
8085
|
if (hasTasksTable) {
|
|
7831
8086
|
sqlite.exec(`
|
|
@@ -13401,7 +13656,7 @@ glob.glob = glob;
|
|
|
13401
13656
|
// node_modules/bun-pty/dist/index.js
|
|
13402
13657
|
import { dlopen, FFIType, ptr } from "bun:ffi";
|
|
13403
13658
|
import { Buffer as Buffer2 } from "buffer";
|
|
13404
|
-
import { join as
|
|
13659
|
+
import { join as join4, dirname as dirname2, basename } from "path";
|
|
13405
13660
|
import { existsSync as existsSync2 } from "fs";
|
|
13406
13661
|
|
|
13407
13662
|
class EventEmitter2 {
|
|
@@ -13444,14 +13699,14 @@ function resolveLibPath() {
|
|
|
13444
13699
|
const dirName = basename(fileDir);
|
|
13445
13700
|
const here = dirName === "src" || dirName === "dist" ? dirname2(fileDir) : fileDir;
|
|
13446
13701
|
const basePaths = [
|
|
13447
|
-
|
|
13448
|
-
|
|
13449
|
-
|
|
13702
|
+
join4(here, "rust-pty", "target", "release"),
|
|
13703
|
+
join4(here, "..", "bun-pty", "rust-pty", "target", "release"),
|
|
13704
|
+
join4(process.cwd(), "node_modules", "bun-pty", "rust-pty", "target", "release")
|
|
13450
13705
|
];
|
|
13451
13706
|
const fallbackPaths = [];
|
|
13452
13707
|
for (const basePath of basePaths) {
|
|
13453
13708
|
for (const filename of filenames) {
|
|
13454
|
-
fallbackPaths.push(
|
|
13709
|
+
fallbackPaths.push(join4(basePath, filename));
|
|
13455
13710
|
}
|
|
13456
13711
|
}
|
|
13457
13712
|
for (const path3 of fallbackPaths) {
|
|
@@ -13724,111 +13979,6 @@ function getDtachService() {
|
|
|
13724
13979
|
// server/terminal/buffer-manager.ts
|
|
13725
13980
|
import { existsSync as existsSync4, mkdirSync as mkdirSync3, readFileSync as readFileSync3, writeFileSync as writeFileSync2, unlinkSync } from "fs";
|
|
13726
13981
|
import * as path4 from "path";
|
|
13727
|
-
|
|
13728
|
-
// server/lib/logger.ts
|
|
13729
|
-
import { appendFileSync } from "fs";
|
|
13730
|
-
import { join as join5 } from "path";
|
|
13731
|
-
|
|
13732
|
-
// shared/logger/types.ts
|
|
13733
|
-
var LOG_LEVELS = {
|
|
13734
|
-
debug: 0,
|
|
13735
|
-
info: 1,
|
|
13736
|
-
warn: 2,
|
|
13737
|
-
error: 3
|
|
13738
|
-
};
|
|
13739
|
-
function formatLogEntry(entry) {
|
|
13740
|
-
return JSON.stringify(entry);
|
|
13741
|
-
}
|
|
13742
|
-
// server/lib/logger.ts
|
|
13743
|
-
function getMinLevel() {
|
|
13744
|
-
const level = process.env.LOG_LEVEL;
|
|
13745
|
-
if (level && level in LOG_LEVELS) {
|
|
13746
|
-
return level;
|
|
13747
|
-
}
|
|
13748
|
-
return "info";
|
|
13749
|
-
}
|
|
13750
|
-
var logFilePath = null;
|
|
13751
|
-
function getLogFile() {
|
|
13752
|
-
if (logFilePath !== null) {
|
|
13753
|
-
return logFilePath || null;
|
|
13754
|
-
}
|
|
13755
|
-
try {
|
|
13756
|
-
ensureViboraDir();
|
|
13757
|
-
logFilePath = join5(getViboraDir(), "vibora.log");
|
|
13758
|
-
return logFilePath;
|
|
13759
|
-
} catch {
|
|
13760
|
-
logFilePath = "";
|
|
13761
|
-
return null;
|
|
13762
|
-
}
|
|
13763
|
-
}
|
|
13764
|
-
function writeEntry(entry) {
|
|
13765
|
-
const line = formatLogEntry(entry);
|
|
13766
|
-
console.log(line);
|
|
13767
|
-
const logFile = getLogFile();
|
|
13768
|
-
if (logFile) {
|
|
13769
|
-
try {
|
|
13770
|
-
appendFileSync(logFile, line + `
|
|
13771
|
-
`);
|
|
13772
|
-
} catch {}
|
|
13773
|
-
}
|
|
13774
|
-
}
|
|
13775
|
-
|
|
13776
|
-
class ServerLogger {
|
|
13777
|
-
component;
|
|
13778
|
-
minLevel;
|
|
13779
|
-
constructor(component, minLevel) {
|
|
13780
|
-
this.component = component;
|
|
13781
|
-
this.minLevel = minLevel ?? getMinLevel();
|
|
13782
|
-
}
|
|
13783
|
-
shouldLog(level) {
|
|
13784
|
-
return LOG_LEVELS[level] >= LOG_LEVELS[this.minLevel];
|
|
13785
|
-
}
|
|
13786
|
-
log(level, msg, ctx) {
|
|
13787
|
-
if (!this.shouldLog(level))
|
|
13788
|
-
return;
|
|
13789
|
-
writeEntry({
|
|
13790
|
-
ts: new Date().toISOString(),
|
|
13791
|
-
lvl: level,
|
|
13792
|
-
src: this.component,
|
|
13793
|
-
msg,
|
|
13794
|
-
...ctx && Object.keys(ctx).length > 0 ? { ctx } : {}
|
|
13795
|
-
});
|
|
13796
|
-
}
|
|
13797
|
-
debug(msg, ctx) {
|
|
13798
|
-
this.log("debug", msg, ctx);
|
|
13799
|
-
}
|
|
13800
|
-
info(msg, ctx) {
|
|
13801
|
-
this.log("info", msg, ctx);
|
|
13802
|
-
}
|
|
13803
|
-
warn(msg, ctx) {
|
|
13804
|
-
this.log("warn", msg, ctx);
|
|
13805
|
-
}
|
|
13806
|
-
error(msg, ctx) {
|
|
13807
|
-
this.log("error", msg, ctx);
|
|
13808
|
-
}
|
|
13809
|
-
child(component) {
|
|
13810
|
-
return new ServerLogger(`${this.component}/${component}`, this.minLevel);
|
|
13811
|
-
}
|
|
13812
|
-
}
|
|
13813
|
-
function createLogger(component) {
|
|
13814
|
-
return new ServerLogger(component);
|
|
13815
|
-
}
|
|
13816
|
-
var log2 = {
|
|
13817
|
-
pty: createLogger("PTYManager"),
|
|
13818
|
-
ws: createLogger("WS"),
|
|
13819
|
-
terminal: createLogger("Terminal"),
|
|
13820
|
-
buffer: createLogger("BufferManager"),
|
|
13821
|
-
desktop: createLogger("Desktop"),
|
|
13822
|
-
api: createLogger("API"),
|
|
13823
|
-
metrics: createLogger("MetricsCollector"),
|
|
13824
|
-
pr: createLogger("PRMonitor"),
|
|
13825
|
-
github: createLogger("GitHub"),
|
|
13826
|
-
linear: createLogger("Linear"),
|
|
13827
|
-
notification: createLogger("Notification"),
|
|
13828
|
-
server: createLogger("Server")
|
|
13829
|
-
};
|
|
13830
|
-
|
|
13831
|
-
// server/terminal/buffer-manager.ts
|
|
13832
13982
|
var MAX_BUFFER_BYTES = 1e6;
|
|
13833
13983
|
function getBuffersDir() {
|
|
13834
13984
|
const dir = path4.join(getViboraDir(), "buffers");
|
|
@@ -137757,7 +137907,7 @@ var LinearClient = class extends LinearSdk {
|
|
|
137757
137907
|
// server/services/linear.ts
|
|
137758
137908
|
var linearClient = null;
|
|
137759
137909
|
function getLinearClient() {
|
|
137760
|
-
const apiKey = getSetting("linearApiKey");
|
|
137910
|
+
const apiKey = getSetting("integrations.linearApiKey");
|
|
137761
137911
|
if (!apiKey)
|
|
137762
137912
|
return null;
|
|
137763
137913
|
if (!linearClient) {
|
|
@@ -137935,7 +138085,7 @@ async function sendPushoverNotification(config, payload) {
|
|
|
137935
138085
|
return { channel: "pushover", success: false, error: message };
|
|
137936
138086
|
}
|
|
137937
138087
|
}
|
|
137938
|
-
function broadcastUINotification(payload) {
|
|
138088
|
+
function broadcastUINotification(payload, playSound) {
|
|
137939
138089
|
const notificationType = payload.type === "pr_merged" || payload.type === "plan_complete" ? "success" : "info";
|
|
137940
138090
|
broadcast({
|
|
137941
138091
|
type: "notification",
|
|
@@ -137944,7 +138094,8 @@ function broadcastUINotification(payload) {
|
|
|
137944
138094
|
title: payload.title,
|
|
137945
138095
|
message: payload.message,
|
|
137946
138096
|
notificationType,
|
|
137947
|
-
taskId: payload.taskId
|
|
138097
|
+
taskId: payload.taskId,
|
|
138098
|
+
playSound
|
|
137948
138099
|
}
|
|
137949
138100
|
});
|
|
137950
138101
|
}
|
|
@@ -137955,7 +138106,8 @@ async function sendNotification(payload) {
|
|
|
137955
138106
|
}
|
|
137956
138107
|
const results = [];
|
|
137957
138108
|
const promises = [];
|
|
137958
|
-
|
|
138109
|
+
const playSound = settings.sound?.enabled ?? false;
|
|
138110
|
+
broadcastUINotification(payload, playSound);
|
|
137959
138111
|
if (settings.sound?.enabled) {
|
|
137960
138112
|
promises.push(sendSoundNotification(settings.sound).then((r) => results.push(r)).catch((e) => results.push({ channel: "sound", success: false, error: e.message })));
|
|
137961
138113
|
}
|
|
@@ -138172,6 +138324,9 @@ app2.post("/", async (c) => {
|
|
|
138172
138324
|
}
|
|
138173
138325
|
}
|
|
138174
138326
|
db.insert(tasks).values(newTask).run();
|
|
138327
|
+
if (body.repoPath) {
|
|
138328
|
+
db.update(repositories).set({ lastUsedAt: now, updatedAt: now }).where(eq(repositories.path, body.repoPath)).run();
|
|
138329
|
+
}
|
|
138175
138330
|
const created = db.select().from(tasks).where(eq(tasks.id, newTask.id)).get();
|
|
138176
138331
|
broadcast({ type: "task:updated", payload: { taskId: newTask.id } });
|
|
138177
138332
|
return c.json(created ? parseViewState(created) : null, 201);
|
|
@@ -139200,16 +139355,61 @@ var filesystem_default = app4;
|
|
|
139200
139355
|
// server/routes/config.ts
|
|
139201
139356
|
import { spawn as spawn3 } from "child_process";
|
|
139202
139357
|
var CONFIG_KEYS = {
|
|
139203
|
-
PORT: "port",
|
|
139204
|
-
DEFAULT_GIT_REPOS_DIR: "defaultGitReposDir",
|
|
139205
|
-
|
|
139206
|
-
|
|
139207
|
-
|
|
139208
|
-
|
|
139209
|
-
|
|
139210
|
-
|
|
139211
|
-
|
|
139212
|
-
|
|
139358
|
+
PORT: "server.port",
|
|
139359
|
+
DEFAULT_GIT_REPOS_DIR: "paths.defaultGitReposDir",
|
|
139360
|
+
BASIC_AUTH_USERNAME: "authentication.username",
|
|
139361
|
+
BASIC_AUTH_PASSWORD: "authentication.password",
|
|
139362
|
+
REMOTE_HOST: "remoteVibora.host",
|
|
139363
|
+
REMOTE_PORT: "remoteVibora.port",
|
|
139364
|
+
EDITOR_APP: "editor.app",
|
|
139365
|
+
EDITOR_HOST: "editor.host",
|
|
139366
|
+
EDITOR_SSH_PORT: "editor.sshPort",
|
|
139367
|
+
LINEAR_API_KEY: "integrations.linearApiKey",
|
|
139368
|
+
GITHUB_PAT: "integrations.githubPat",
|
|
139369
|
+
LANGUAGE: "appearance.language"
|
|
139370
|
+
};
|
|
139371
|
+
var LEGACY_KEY_MAP = {
|
|
139372
|
+
port: "server.port",
|
|
139373
|
+
default_git_repos_dir: "paths.defaultGitReposDir",
|
|
139374
|
+
basic_auth_username: "authentication.username",
|
|
139375
|
+
basic_auth_password: "authentication.password",
|
|
139376
|
+
remote_host: "remoteVibora.host",
|
|
139377
|
+
hostname: "remoteVibora.host",
|
|
139378
|
+
ssh_port: "editor.sshPort",
|
|
139379
|
+
linear_api_key: "integrations.linearApiKey",
|
|
139380
|
+
github_pat: "integrations.githubPat",
|
|
139381
|
+
language: "appearance.language",
|
|
139382
|
+
defaultGitReposDir: "paths.defaultGitReposDir",
|
|
139383
|
+
basicAuthUsername: "authentication.username",
|
|
139384
|
+
basicAuthPassword: "authentication.password",
|
|
139385
|
+
remoteHost: "remoteVibora.host",
|
|
139386
|
+
sshPort: "editor.sshPort",
|
|
139387
|
+
linearApiKey: "integrations.linearApiKey",
|
|
139388
|
+
githubPat: "integrations.githubPat"
|
|
139389
|
+
};
|
|
139390
|
+
var VALID_PATHS = new Set(Object.values(CONFIG_KEYS));
|
|
139391
|
+
function resolveConfigKey(key) {
|
|
139392
|
+
if (VALID_PATHS.has(key)) {
|
|
139393
|
+
return key;
|
|
139394
|
+
}
|
|
139395
|
+
if (key in LEGACY_KEY_MAP) {
|
|
139396
|
+
return LEGACY_KEY_MAP[key];
|
|
139397
|
+
}
|
|
139398
|
+
return null;
|
|
139399
|
+
}
|
|
139400
|
+
function getSettingValue(path8) {
|
|
139401
|
+
const settings = getSettings();
|
|
139402
|
+
const parts = path8.split(".");
|
|
139403
|
+
let current = settings;
|
|
139404
|
+
for (const part of parts) {
|
|
139405
|
+
if (current && typeof current === "object" && part in current) {
|
|
139406
|
+
current = current[part];
|
|
139407
|
+
} else {
|
|
139408
|
+
return;
|
|
139409
|
+
}
|
|
139410
|
+
}
|
|
139411
|
+
return current;
|
|
139412
|
+
}
|
|
139213
139413
|
var app5 = new Hono2;
|
|
139214
139414
|
app5.get("/notifications", (c) => {
|
|
139215
139415
|
const notifications = getNotificationSettings();
|
|
@@ -139299,134 +139499,81 @@ app5.post("/restart", (c) => {
|
|
|
139299
139499
|
return c.json({ error: "Restart only available in developer mode" }, 403);
|
|
139300
139500
|
}
|
|
139301
139501
|
setTimeout(() => {
|
|
139302
|
-
spawn3("bash", ["-c", "cd ~/projects/vibora && mise run build && systemctl --user restart vibora-dev"], {
|
|
139502
|
+
spawn3("bash", ["-c", "cd ~/projects/vibora && mise run build && bun run drizzle-kit push && systemctl --user restart vibora-dev"], {
|
|
139303
139503
|
detached: true,
|
|
139304
139504
|
stdio: "ignore"
|
|
139305
139505
|
}).unref();
|
|
139306
139506
|
}, 100);
|
|
139307
|
-
return c.json({ success: true, message: "Restart initiated (
|
|
139507
|
+
return c.json({ success: true, message: "Restart initiated (build + migrate + restart)" });
|
|
139308
139508
|
});
|
|
139309
139509
|
app5.get("/:key", (c) => {
|
|
139310
139510
|
const key = c.req.param("key");
|
|
139311
|
-
|
|
139312
|
-
let value = null;
|
|
139313
|
-
if (key === "port" || key === CONFIG_KEYS.PORT) {
|
|
139314
|
-
value = settings.port;
|
|
139315
|
-
} else if (key === "default_git_repos_dir" || key === CONFIG_KEYS.DEFAULT_GIT_REPOS_DIR) {
|
|
139316
|
-
value = settings.defaultGitReposDir;
|
|
139317
|
-
} else if (key === "remote_host" || key === "remoteHost" || key === CONFIG_KEYS.REMOTE_HOST || key === "hostname") {
|
|
139318
|
-
value = settings.remoteHost;
|
|
139319
|
-
} else if (key === "ssh_port" || key === CONFIG_KEYS.SSH_PORT) {
|
|
139320
|
-
value = settings.sshPort;
|
|
139321
|
-
} else if (key === "linear_api_key" || key === CONFIG_KEYS.LINEAR_API_KEY) {
|
|
139322
|
-
value = settings.linearApiKey;
|
|
139323
|
-
} else if (key === "github_pat" || key === CONFIG_KEYS.GITHUB_PAT) {
|
|
139324
|
-
value = settings.githubPat;
|
|
139325
|
-
} else if (key === "language" || key === CONFIG_KEYS.LANGUAGE) {
|
|
139326
|
-
return c.json({ key, value: settings.language, isDefault: settings.language === null });
|
|
139327
|
-
} else if (key === "basic_auth_username" || key === CONFIG_KEYS.BASIC_AUTH_USERNAME) {
|
|
139328
|
-
return c.json({ key, value: settings.basicAuthUsername, isDefault: settings.basicAuthUsername === null });
|
|
139329
|
-
} else if (key === "basic_auth_password" || key === CONFIG_KEYS.BASIC_AUTH_PASSWORD) {
|
|
139330
|
-
return c.json({ key, value: settings.basicAuthPassword ? "\u2022\u2022\u2022\u2022\u2022\u2022\u2022\u2022" : null, isDefault: settings.basicAuthPassword === null });
|
|
139331
|
-
} else if (key === "worktree_base_path") {
|
|
139511
|
+
if (key === "worktree_base_path") {
|
|
139332
139512
|
return c.json({ key, value: getWorktreeBasePath(), isDefault: true });
|
|
139333
139513
|
}
|
|
139334
|
-
|
|
139335
|
-
|
|
139514
|
+
const path8 = resolveConfigKey(key);
|
|
139515
|
+
if (!path8) {
|
|
139516
|
+
return c.json({ key, value: null, isDefault: true, error: "Unknown config key" }, 404);
|
|
139517
|
+
}
|
|
139518
|
+
const value = getSettingValue(path8);
|
|
139519
|
+
const defaultValue = getDefaultValue(path8);
|
|
139520
|
+
const isDefault = value === defaultValue || value === undefined || value === null;
|
|
139521
|
+
if (path8 === CONFIG_KEYS.BASIC_AUTH_PASSWORD) {
|
|
139522
|
+
return c.json({
|
|
139523
|
+
key,
|
|
139524
|
+
value: value ? "\u2022\u2022\u2022\u2022\u2022\u2022\u2022\u2022" : null,
|
|
139525
|
+
isDefault: value === null || value === undefined
|
|
139526
|
+
});
|
|
139336
139527
|
}
|
|
139337
|
-
return c.json({ key, value, isDefault
|
|
139528
|
+
return c.json({ key, value: value ?? defaultValue, isDefault });
|
|
139338
139529
|
});
|
|
139339
139530
|
app5.put("/:key", async (c) => {
|
|
139340
139531
|
const key = c.req.param("key");
|
|
139532
|
+
const path8 = resolveConfigKey(key);
|
|
139533
|
+
if (!path8) {
|
|
139534
|
+
return c.json({ error: `Unknown or read-only config key: ${key}` }, 400);
|
|
139535
|
+
}
|
|
139341
139536
|
try {
|
|
139342
139537
|
const body = await c.req.json();
|
|
139343
|
-
|
|
139344
|
-
|
|
139538
|
+
let { value } = body;
|
|
139539
|
+
if (path8 === CONFIG_KEYS.PORT || path8 === CONFIG_KEYS.REMOTE_PORT || path8 === CONFIG_KEYS.EDITOR_SSH_PORT) {
|
|
139540
|
+
const port = typeof value === "number" ? value : parseInt(value, 10);
|
|
139345
139541
|
if (isNaN(port) || port < 1 || port > 65535) {
|
|
139346
139542
|
return c.json({ error: "Port must be a number between 1 and 65535" }, 400);
|
|
139347
139543
|
}
|
|
139348
|
-
|
|
139349
|
-
|
|
139350
|
-
|
|
139351
|
-
if (typeof body.value !== "string") {
|
|
139352
|
-
return c.json({ error: "Value must be a string" }, 400);
|
|
139353
|
-
}
|
|
139354
|
-
updateSettings({ defaultGitReposDir: body.value });
|
|
139355
|
-
return c.json({ key, value: body.value });
|
|
139356
|
-
} else if (key === "remote_host" || key === "remoteHost" || key === CONFIG_KEYS.REMOTE_HOST || key === "hostname") {
|
|
139357
|
-
if (typeof body.value !== "string") {
|
|
139358
|
-
return c.json({ error: "Value must be a string" }, 400);
|
|
139359
|
-
}
|
|
139360
|
-
updateSettings({ remoteHost: body.value });
|
|
139361
|
-
return c.json({ key, value: body.value });
|
|
139362
|
-
} else if (key === "ssh_port" || key === CONFIG_KEYS.SSH_PORT) {
|
|
139363
|
-
const sshPort = typeof body.value === "number" ? body.value : parseInt(body.value, 10);
|
|
139364
|
-
if (isNaN(sshPort) || sshPort < 1 || sshPort > 65535) {
|
|
139365
|
-
return c.json({ error: "SSH port must be a number between 1 and 65535" }, 400);
|
|
139366
|
-
}
|
|
139367
|
-
updateSettings({ sshPort });
|
|
139368
|
-
return c.json({ key, value: sshPort });
|
|
139369
|
-
} else if (key === "linear_api_key" || key === CONFIG_KEYS.LINEAR_API_KEY) {
|
|
139370
|
-
if (typeof body.value !== "string") {
|
|
139371
|
-
return c.json({ error: "Value must be a string" }, 400);
|
|
139372
|
-
}
|
|
139373
|
-
updateSettings({ linearApiKey: body.value || null });
|
|
139374
|
-
return c.json({ key, value: body.value });
|
|
139375
|
-
} else if (key === "github_pat" || key === CONFIG_KEYS.GITHUB_PAT) {
|
|
139376
|
-
if (typeof body.value !== "string") {
|
|
139377
|
-
return c.json({ error: "Value must be a string" }, 400);
|
|
139378
|
-
}
|
|
139379
|
-
updateSettings({ githubPat: body.value || null });
|
|
139380
|
-
return c.json({ key, value: body.value });
|
|
139381
|
-
} else if (key === "language" || key === CONFIG_KEYS.LANGUAGE) {
|
|
139382
|
-
const langValue = body.value === "" || body.value === null ? null : body.value;
|
|
139383
|
-
if (langValue !== null && langValue !== "en" && langValue !== "zh") {
|
|
139544
|
+
value = port;
|
|
139545
|
+
} else if (path8 === CONFIG_KEYS.LANGUAGE) {
|
|
139546
|
+
if (value !== null && value !== "" && value !== "en" && value !== "zh") {
|
|
139384
139547
|
return c.json({ error: 'Language must be "en", "zh", or null' }, 400);
|
|
139385
139548
|
}
|
|
139386
|
-
|
|
139387
|
-
|
|
139388
|
-
|
|
139389
|
-
if (
|
|
139390
|
-
return c.json({ error:
|
|
139549
|
+
value = value === "" ? null : value;
|
|
139550
|
+
} else if (path8 === CONFIG_KEYS.EDITOR_APP) {
|
|
139551
|
+
const validApps = ["vscode", "cursor", "windsurf", "zed"];
|
|
139552
|
+
if (!validApps.includes(value)) {
|
|
139553
|
+
return c.json({ error: `Editor app must be one of: ${validApps.join(", ")}` }, 400);
|
|
139391
139554
|
}
|
|
139392
|
-
|
|
139393
|
-
|
|
139394
|
-
|
|
139395
|
-
if (typeof body.value !== "string") {
|
|
139396
|
-
return c.json({ error: "Value must be a string" }, 400);
|
|
139555
|
+
} else if (typeof value === "string" && value === "") {
|
|
139556
|
+
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) {
|
|
139557
|
+
value = null;
|
|
139397
139558
|
}
|
|
139398
|
-
updateSettings({ basicAuthPassword: body.value || null });
|
|
139399
|
-
return c.json({ key, value: body.value ? "\u2022\u2022\u2022\u2022\u2022\u2022\u2022\u2022" : null });
|
|
139400
|
-
} else {
|
|
139401
|
-
return c.json({ error: `Unknown or read-only config key: ${key}` }, 400);
|
|
139402
139559
|
}
|
|
139560
|
+
updateSettingByPath(path8, value);
|
|
139561
|
+
if (path8 === CONFIG_KEYS.BASIC_AUTH_PASSWORD) {
|
|
139562
|
+
return c.json({ key, value: value ? "\u2022\u2022\u2022\u2022\u2022\u2022\u2022\u2022" : null });
|
|
139563
|
+
}
|
|
139564
|
+
return c.json({ key, value });
|
|
139403
139565
|
} catch (err) {
|
|
139404
139566
|
return c.json({ error: err instanceof Error ? err.message : "Failed to set config" }, 400);
|
|
139405
139567
|
}
|
|
139406
139568
|
});
|
|
139407
139569
|
app5.delete("/:key", (c) => {
|
|
139408
139570
|
const key = c.req.param("key");
|
|
139409
|
-
const
|
|
139410
|
-
|
|
139411
|
-
|
|
139412
|
-
defaultValue = defaults2.port;
|
|
139413
|
-
} else if (key === "default_git_repos_dir" || key === CONFIG_KEYS.DEFAULT_GIT_REPOS_DIR) {
|
|
139414
|
-
defaultValue = defaults2.defaultGitReposDir;
|
|
139415
|
-
} else if (key === "remote_host" || key === "remoteHost" || key === CONFIG_KEYS.REMOTE_HOST || key === "hostname") {
|
|
139416
|
-
defaultValue = defaults2.remoteHost;
|
|
139417
|
-
} else if (key === "ssh_port" || key === CONFIG_KEYS.SSH_PORT) {
|
|
139418
|
-
defaultValue = defaults2.sshPort;
|
|
139419
|
-
} else if (key === "linear_api_key" || key === CONFIG_KEYS.LINEAR_API_KEY) {
|
|
139420
|
-
defaultValue = defaults2.linearApiKey;
|
|
139421
|
-
} else if (key === "github_pat" || key === CONFIG_KEYS.GITHUB_PAT) {
|
|
139422
|
-
defaultValue = defaults2.githubPat;
|
|
139423
|
-
} else if (key === "language" || key === CONFIG_KEYS.LANGUAGE) {
|
|
139424
|
-
defaultValue = defaults2.language;
|
|
139425
|
-
} else if (key === "basic_auth_username" || key === CONFIG_KEYS.BASIC_AUTH_USERNAME) {
|
|
139426
|
-
defaultValue = defaults2.basicAuthUsername;
|
|
139427
|
-
} else if (key === "basic_auth_password" || key === CONFIG_KEYS.BASIC_AUTH_PASSWORD) {
|
|
139428
|
-
defaultValue = defaults2.basicAuthPassword;
|
|
139571
|
+
const path8 = resolveConfigKey(key);
|
|
139572
|
+
if (!path8) {
|
|
139573
|
+
return c.json({ error: `Unknown config key: ${key}` }, 400);
|
|
139429
139574
|
}
|
|
139575
|
+
const defaultValue = getDefaultValue(path8);
|
|
139576
|
+
updateSettingByPath(path8, defaultValue);
|
|
139430
139577
|
return c.json({ key, value: defaultValue, isDefault: true });
|
|
139431
139578
|
});
|
|
139432
139579
|
var config_default = app5;
|
|
@@ -139934,7 +140081,7 @@ var terminal_view_state_default = app8;
|
|
|
139934
140081
|
// server/routes/repositories.ts
|
|
139935
140082
|
var app9 = new Hono2;
|
|
139936
140083
|
app9.get("/", (c) => {
|
|
139937
|
-
const allRepos = db.select().from(repositories).all();
|
|
140084
|
+
const allRepos = db.select().from(repositories).orderBy(desc(sql`COALESCE(${repositories.lastUsedAt}, '1970-01-01')`), desc(repositories.createdAt)).all();
|
|
139938
140085
|
return c.json(allRepos);
|
|
139939
140086
|
});
|
|
139940
140087
|
app9.get("/:id", (c) => {
|
|
@@ -143486,7 +143633,7 @@ var Octokit2 = Octokit.plugin(requestLog, legacyRestEndpointMethods, paginateRes
|
|
|
143486
143633
|
var octokitClient = null;
|
|
143487
143634
|
var cachedPat = null;
|
|
143488
143635
|
function getOctokit() {
|
|
143489
|
-
const pat = getSetting("githubPat");
|
|
143636
|
+
const pat = getSetting("integrations.githubPat");
|
|
143490
143637
|
if (!pat)
|
|
143491
143638
|
return null;
|
|
143492
143639
|
if (pat !== cachedPat) {
|
|
@@ -144490,7 +144637,7 @@ function findViboraInstances() {
|
|
|
144490
144637
|
const isDevBackend = isBunProcess && cmdline.includes("server/index.ts") && env.NODE_ENV !== "production";
|
|
144491
144638
|
const isProdBackend = isBunProcess && (!!env.VIBORA_PACKAGE_ROOT || cmdline.includes("server/index.ts") && env.NODE_ENV === "production");
|
|
144492
144639
|
if (isDevBackend || isProdBackend) {
|
|
144493
|
-
const port = parseInt(env.PORT || "
|
|
144640
|
+
const port = parseInt(env.PORT || "7777", 10);
|
|
144494
144641
|
const cwd = getProcessCwd(pid);
|
|
144495
144642
|
let viboraDir = env.VIBORA_DIR || (isDevBackend ? "~/.vibora/dev" : "~/.vibora");
|
|
144496
144643
|
if (viboraDir.startsWith(".") && cwd !== "(unknown)") {
|
|
@@ -144899,7 +145046,7 @@ function stopPRMonitor() {
|
|
|
144899
145046
|
}
|
|
144900
145047
|
|
|
144901
145048
|
// server/index.ts
|
|
144902
|
-
var PORT =
|
|
145049
|
+
var PORT = getSettingByKey("port");
|
|
144903
145050
|
var ptyManager2 = initPTYManager({
|
|
144904
145051
|
onData: (terminalId, data) => {
|
|
144905
145052
|
broadcastToTerminal(terminalId, {
|