vibora 2.2.2 → 2.3.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/bin/vibora.js +3 -1
- package/dist/assets/index-8zuRUVkT.js +118 -0
- package/dist/assets/index-BtG6gcrm.css +1 -0
- package/dist/favicon.ico +0 -0
- package/dist/index.html +3 -4
- package/dist/logo-dark.jpg +0 -0
- package/dist/logo-light.jpg +0 -0
- package/dist/sounds/goat-bleat.mp3 +0 -0
- package/dist/vibora-icon.png +0 -0
- package/dist/vibora-logo.png +0 -0
- package/package.json +1 -1
- package/server/index.js +212 -68
- package/dist/assets/index-C5n5kVkQ.js +0 -118
- package/dist/assets/index-DGzCy3yX.css +0 -1
- package/dist/vibora-logo.jpeg +0 -0
- package/dist/vite.svg +0 -1
package/server/index.js
CHANGED
|
@@ -3610,6 +3610,7 @@ var log2 = {
|
|
|
3610
3610
|
|
|
3611
3611
|
// server/lib/settings.ts
|
|
3612
3612
|
var CURRENT_SCHEMA_VERSION = 3;
|
|
3613
|
+
var CLAUDE_CODE_THEMES = ["light", "light-ansi", "light-daltonized", "dark", "dark-ansi", "dark-daltonized"];
|
|
3613
3614
|
var DEFAULT_SETTINGS = {
|
|
3614
3615
|
_schemaVersion: CURRENT_SCHEMA_VERSION,
|
|
3615
3616
|
server: {
|
|
@@ -3622,9 +3623,6 @@ var DEFAULT_SETTINGS = {
|
|
|
3622
3623
|
username: null,
|
|
3623
3624
|
password: null
|
|
3624
3625
|
},
|
|
3625
|
-
remoteVibora: {
|
|
3626
|
-
url: ""
|
|
3627
|
-
},
|
|
3628
3626
|
editor: {
|
|
3629
3627
|
app: "vscode",
|
|
3630
3628
|
host: "",
|
|
@@ -3635,7 +3633,11 @@ var DEFAULT_SETTINGS = {
|
|
|
3635
3633
|
githubPat: null
|
|
3636
3634
|
},
|
|
3637
3635
|
appearance: {
|
|
3638
|
-
language: null
|
|
3636
|
+
language: null,
|
|
3637
|
+
theme: null,
|
|
3638
|
+
syncClaudeCodeTheme: false,
|
|
3639
|
+
claudeCodeLightTheme: "light-ansi",
|
|
3640
|
+
claudeCodeDarkTheme: "dark-ansi"
|
|
3639
3641
|
}
|
|
3640
3642
|
};
|
|
3641
3643
|
var OLD_DEFAULT_PORT = 3333;
|
|
@@ -3647,7 +3649,11 @@ var MIGRATION_MAP = {
|
|
|
3647
3649
|
sshPort: "editor.sshPort",
|
|
3648
3650
|
linearApiKey: "integrations.linearApiKey",
|
|
3649
3651
|
githubPat: "integrations.githubPat",
|
|
3650
|
-
language: "appearance.language"
|
|
3652
|
+
language: "appearance.language",
|
|
3653
|
+
theme: "appearance.theme",
|
|
3654
|
+
syncClaudeCodeTheme: "appearance.syncClaudeCodeTheme",
|
|
3655
|
+
claudeCodeLightTheme: "appearance.claudeCodeLightTheme",
|
|
3656
|
+
claudeCodeDarkTheme: "appearance.claudeCodeDarkTheme"
|
|
3651
3657
|
};
|
|
3652
3658
|
function getNestedValue(obj, path2) {
|
|
3653
3659
|
return path2.split(".").reduce((o, k) => {
|
|
@@ -3669,13 +3675,6 @@ function setNestedValue(obj, path2, value) {
|
|
|
3669
3675
|
}
|
|
3670
3676
|
current[lastKey] = value;
|
|
3671
3677
|
}
|
|
3672
|
-
function constructRemoteUrl(host, port) {
|
|
3673
|
-
if (!host)
|
|
3674
|
-
return "";
|
|
3675
|
-
const effectivePort = port || 7777;
|
|
3676
|
-
const portSuffix = effectivePort === 80 || effectivePort === 443 ? "" : `:${effectivePort}`;
|
|
3677
|
-
return `http://${host}${portSuffix}`;
|
|
3678
|
-
}
|
|
3679
3678
|
function migrateSettings(parsed) {
|
|
3680
3679
|
const result = { migrated: false, migratedKeys: [], warnings: [] };
|
|
3681
3680
|
const version = parsed._schemaVersion ?? 1;
|
|
@@ -3702,26 +3701,9 @@ function migrateSettings(parsed) {
|
|
|
3702
3701
|
result.migrated = true;
|
|
3703
3702
|
}
|
|
3704
3703
|
}
|
|
3705
|
-
|
|
3706
|
-
|
|
3707
|
-
|
|
3708
|
-
setNestedValue(parsed, "remoteVibora.url", url);
|
|
3709
|
-
result.migratedKeys.push("remoteHost");
|
|
3710
|
-
delete parsed.remoteHost;
|
|
3711
|
-
delete parsed.hostname;
|
|
3712
|
-
result.migrated = true;
|
|
3713
|
-
}
|
|
3714
|
-
}
|
|
3715
|
-
if (version < 3) {
|
|
3716
|
-
const remoteVibora = parsed.remoteVibora;
|
|
3717
|
-
if (remoteVibora && "host" in remoteVibora) {
|
|
3718
|
-
const host = remoteVibora.host || "";
|
|
3719
|
-
const port = remoteVibora.port || 7777;
|
|
3720
|
-
const url = constructRemoteUrl(host, port);
|
|
3721
|
-
parsed.remoteVibora = { url };
|
|
3722
|
-
result.migratedKeys.push("remoteVibora.host");
|
|
3723
|
-
result.migrated = true;
|
|
3724
|
-
}
|
|
3704
|
+
delete parsed.remoteHost;
|
|
3705
|
+
delete parsed.hostname;
|
|
3706
|
+
delete parsed.remoteVibora;
|
|
3725
3707
|
}
|
|
3726
3708
|
parsed._schemaVersion = CURRENT_SCHEMA_VERSION;
|
|
3727
3709
|
result.migrated = true;
|
|
@@ -3814,9 +3796,6 @@ function getSettings() {
|
|
|
3814
3796
|
username: parsed.authentication?.username ?? null,
|
|
3815
3797
|
password: parsed.authentication?.password ?? null
|
|
3816
3798
|
},
|
|
3817
|
-
remoteVibora: {
|
|
3818
|
-
url: parsed.remoteVibora?.url ?? DEFAULT_SETTINGS.remoteVibora.url
|
|
3819
|
-
},
|
|
3820
3799
|
editor: {
|
|
3821
3800
|
app: parsed.editor?.app ?? DEFAULT_SETTINGS.editor.app,
|
|
3822
3801
|
host: parsed.editor?.host ?? DEFAULT_SETTINGS.editor.host,
|
|
@@ -3827,7 +3806,11 @@ function getSettings() {
|
|
|
3827
3806
|
githubPat: parsed.integrations?.githubPat ?? null
|
|
3828
3807
|
},
|
|
3829
3808
|
appearance: {
|
|
3830
|
-
language: parsed.appearance?.language ?? null
|
|
3809
|
+
language: parsed.appearance?.language ?? null,
|
|
3810
|
+
theme: parsed.appearance?.theme ?? null,
|
|
3811
|
+
syncClaudeCodeTheme: parsed.appearance?.syncClaudeCodeTheme ?? false,
|
|
3812
|
+
claudeCodeLightTheme: parsed.appearance?.claudeCodeLightTheme ?? "light-ansi",
|
|
3813
|
+
claudeCodeDarkTheme: parsed.appearance?.claudeCodeDarkTheme ?? "dark-ansi"
|
|
3831
3814
|
}
|
|
3832
3815
|
};
|
|
3833
3816
|
const portEnv = parseInt(process.env.PORT || "", 10);
|
|
@@ -3844,9 +3827,6 @@ function getSettings() {
|
|
|
3844
3827
|
username: process.env.VIBORA_BASIC_AUTH_USERNAME ?? fileSettings.authentication.username,
|
|
3845
3828
|
password: process.env.VIBORA_BASIC_AUTH_PASSWORD ?? fileSettings.authentication.password
|
|
3846
3829
|
},
|
|
3847
|
-
remoteVibora: {
|
|
3848
|
-
url: process.env.VIBORA_REMOTE_URL ?? fileSettings.remoteVibora.url
|
|
3849
|
-
},
|
|
3850
3830
|
editor: {
|
|
3851
3831
|
app: fileSettings.editor.app,
|
|
3852
3832
|
host: process.env.VIBORA_EDITOR_HOST ?? fileSettings.editor.host,
|
|
@@ -3872,13 +3852,16 @@ function toLegacySettings(settings) {
|
|
|
3872
3852
|
return {
|
|
3873
3853
|
port: settings.server.port,
|
|
3874
3854
|
defaultGitReposDir: settings.paths.defaultGitReposDir,
|
|
3875
|
-
remoteUrl: settings.remoteVibora.url,
|
|
3876
3855
|
sshPort: settings.editor.sshPort,
|
|
3877
3856
|
basicAuthUsername: settings.authentication.username,
|
|
3878
3857
|
basicAuthPassword: settings.authentication.password,
|
|
3879
3858
|
linearApiKey: settings.integrations.linearApiKey,
|
|
3880
3859
|
githubPat: settings.integrations.githubPat,
|
|
3881
|
-
language: settings.appearance.language
|
|
3860
|
+
language: settings.appearance.language,
|
|
3861
|
+
theme: settings.appearance.theme,
|
|
3862
|
+
syncClaudeCodeTheme: settings.appearance.syncClaudeCodeTheme,
|
|
3863
|
+
claudeCodeLightTheme: settings.appearance.claudeCodeLightTheme,
|
|
3864
|
+
claudeCodeDarkTheme: settings.appearance.claudeCodeDarkTheme
|
|
3882
3865
|
};
|
|
3883
3866
|
}
|
|
3884
3867
|
function isDeveloperMode() {
|
|
@@ -3909,8 +3892,8 @@ function getDefaultValue(settingPath) {
|
|
|
3909
3892
|
return getNestedValue(DEFAULT_SETTINGS, settingPath);
|
|
3910
3893
|
}
|
|
3911
3894
|
var DEFAULT_NOTIFICATION_SETTINGS = {
|
|
3912
|
-
enabled:
|
|
3913
|
-
sound: { enabled:
|
|
3895
|
+
enabled: true,
|
|
3896
|
+
sound: { enabled: true },
|
|
3914
3897
|
slack: { enabled: false },
|
|
3915
3898
|
discord: { enabled: false },
|
|
3916
3899
|
pushover: { enabled: false }
|
|
@@ -3982,6 +3965,33 @@ function updateClaudeSettings(updates) {
|
|
|
3982
3965
|
const merged = { ...current, ...updates };
|
|
3983
3966
|
fs.writeFileSync(settingsPath, JSON.stringify(merged, null, 2), "utf-8");
|
|
3984
3967
|
}
|
|
3968
|
+
function getClaudeConfigPath() {
|
|
3969
|
+
return path.join(os.homedir(), ".claude.json");
|
|
3970
|
+
}
|
|
3971
|
+
function getClaudeConfig() {
|
|
3972
|
+
const configPath = getClaudeConfigPath();
|
|
3973
|
+
if (!fs.existsSync(configPath))
|
|
3974
|
+
return {};
|
|
3975
|
+
try {
|
|
3976
|
+
return JSON.parse(fs.readFileSync(configPath, "utf-8"));
|
|
3977
|
+
} catch {
|
|
3978
|
+
return {};
|
|
3979
|
+
}
|
|
3980
|
+
}
|
|
3981
|
+
function updateClaudeConfig(updates) {
|
|
3982
|
+
const configPath = getClaudeConfigPath();
|
|
3983
|
+
const current = getClaudeConfig();
|
|
3984
|
+
const merged = { ...current, ...updates };
|
|
3985
|
+
fs.writeFileSync(configPath, JSON.stringify(merged, null, 2), "utf-8");
|
|
3986
|
+
}
|
|
3987
|
+
function syncClaudeCodeTheme(resolvedTheme) {
|
|
3988
|
+
const settings = getSettings();
|
|
3989
|
+
if (!settings.appearance.syncClaudeCodeTheme)
|
|
3990
|
+
return;
|
|
3991
|
+
const claudeTheme = resolvedTheme === "light" ? settings.appearance.claudeCodeLightTheme : settings.appearance.claudeCodeDarkTheme;
|
|
3992
|
+
updateClaudeConfig({ theme: claudeTheme });
|
|
3993
|
+
log2.settings.info("Synced Claude Code theme", { claudeTheme, resolvedTheme });
|
|
3994
|
+
}
|
|
3985
3995
|
var DEFAULT_ZAI_SETTINGS = {
|
|
3986
3996
|
enabled: false,
|
|
3987
3997
|
apiKey: null,
|
|
@@ -137999,25 +138009,8 @@ async function updateLinearTicketStatus(identifier, viboraStatus) {
|
|
|
137999
138009
|
}
|
|
138000
138010
|
|
|
138001
138011
|
// server/services/notification-service.ts
|
|
138002
|
-
|
|
138003
|
-
|
|
138004
|
-
if (process.platform !== "darwin") {
|
|
138005
|
-
return { channel: "sound", success: false, error: "Sound only supported on macOS" };
|
|
138006
|
-
}
|
|
138007
|
-
const soundFile = config.soundFile || "/System/Library/Sounds/Glass.aiff";
|
|
138008
|
-
return new Promise((resolve2) => {
|
|
138009
|
-
const proc2 = spawn2("afplay", [soundFile]);
|
|
138010
|
-
proc2.on("close", (code) => {
|
|
138011
|
-
if (code === 0) {
|
|
138012
|
-
resolve2({ channel: "sound", success: true });
|
|
138013
|
-
} else {
|
|
138014
|
-
resolve2({ channel: "sound", success: false, error: `afplay exited with code ${code}` });
|
|
138015
|
-
}
|
|
138016
|
-
});
|
|
138017
|
-
proc2.on("error", (err) => {
|
|
138018
|
-
resolve2({ channel: "sound", success: false, error: err.message });
|
|
138019
|
-
});
|
|
138020
|
-
});
|
|
138012
|
+
async function sendSoundNotification(_config) {
|
|
138013
|
+
return { channel: "sound", success: true };
|
|
138021
138014
|
}
|
|
138022
138015
|
async function sendSlackNotification(config, payload) {
|
|
138023
138016
|
if (!config.webhookUrl) {
|
|
@@ -139028,6 +139021,53 @@ app3.post("/merge-to-main", async (c) => {
|
|
|
139028
139021
|
return c.json({ error: err instanceof Error ? err.message : "Failed to merge" }, 500);
|
|
139029
139022
|
}
|
|
139030
139023
|
});
|
|
139024
|
+
app3.post("/push", async (c) => {
|
|
139025
|
+
try {
|
|
139026
|
+
const body = await c.req.json();
|
|
139027
|
+
const { worktreePath } = body;
|
|
139028
|
+
if (!worktreePath) {
|
|
139029
|
+
return c.json({ error: "Missing required field: worktreePath" }, 400);
|
|
139030
|
+
}
|
|
139031
|
+
if (!fs4.existsSync(worktreePath)) {
|
|
139032
|
+
return c.json({ error: "Worktree path does not exist" }, 404);
|
|
139033
|
+
}
|
|
139034
|
+
let branch;
|
|
139035
|
+
try {
|
|
139036
|
+
branch = gitExec(worktreePath, "rev-parse --abbrev-ref HEAD");
|
|
139037
|
+
} catch {
|
|
139038
|
+
return c.json({ error: "Failed to determine current branch" }, 500);
|
|
139039
|
+
}
|
|
139040
|
+
try {
|
|
139041
|
+
const status = gitExec(worktreePath, "status --porcelain");
|
|
139042
|
+
if (status.trim()) {
|
|
139043
|
+
return c.json({
|
|
139044
|
+
error: "Worktree has uncommitted changes. Please commit or stash changes before pushing.",
|
|
139045
|
+
hasUncommittedChanges: true
|
|
139046
|
+
}, 409);
|
|
139047
|
+
}
|
|
139048
|
+
} catch {}
|
|
139049
|
+
try {
|
|
139050
|
+
gitExec(worktreePath, `push origin ${branch}`);
|
|
139051
|
+
} catch (pushErr) {
|
|
139052
|
+
const errorMsg = pushErr instanceof Error ? pushErr.message : "Unknown error";
|
|
139053
|
+
if (errorMsg.includes("rejected") || errorMsg.includes("non-fast-forward")) {
|
|
139054
|
+
return c.json({
|
|
139055
|
+
error: "Push rejected. The remote has changes you do not have locally. Pull first.",
|
|
139056
|
+
pushRejected: true
|
|
139057
|
+
}, 409);
|
|
139058
|
+
}
|
|
139059
|
+
return c.json({
|
|
139060
|
+
error: `Failed to push: ${errorMsg}`
|
|
139061
|
+
}, 500);
|
|
139062
|
+
}
|
|
139063
|
+
return c.json({
|
|
139064
|
+
success: true,
|
|
139065
|
+
branch
|
|
139066
|
+
});
|
|
139067
|
+
} catch (err) {
|
|
139068
|
+
return c.json({ error: err instanceof Error ? err.message : "Failed to push" }, 500);
|
|
139069
|
+
}
|
|
139070
|
+
});
|
|
139031
139071
|
app3.post("/sync-parent", async (c) => {
|
|
139032
139072
|
try {
|
|
139033
139073
|
const body = await c.req.json();
|
|
@@ -139377,7 +139417,7 @@ app4.get("/is-git-repo", (c) => {
|
|
|
139377
139417
|
var filesystem_default = app4;
|
|
139378
139418
|
|
|
139379
139419
|
// server/routes/config.ts
|
|
139380
|
-
import { spawn as
|
|
139420
|
+
import { spawn as spawn2 } from "child_process";
|
|
139381
139421
|
var CONFIG_KEYS = {
|
|
139382
139422
|
PORT: "server.port",
|
|
139383
139423
|
DEFAULT_GIT_REPOS_DIR: "paths.defaultGitReposDir",
|
|
@@ -139390,7 +139430,11 @@ var CONFIG_KEYS = {
|
|
|
139390
139430
|
EDITOR_SSH_PORT: "editor.sshPort",
|
|
139391
139431
|
LINEAR_API_KEY: "integrations.linearApiKey",
|
|
139392
139432
|
GITHUB_PAT: "integrations.githubPat",
|
|
139393
|
-
LANGUAGE: "appearance.language"
|
|
139433
|
+
LANGUAGE: "appearance.language",
|
|
139434
|
+
THEME: "appearance.theme",
|
|
139435
|
+
SYNC_CLAUDE_CODE_THEME: "appearance.syncClaudeCodeTheme",
|
|
139436
|
+
CLAUDE_CODE_LIGHT_THEME: "appearance.claudeCodeLightTheme",
|
|
139437
|
+
CLAUDE_CODE_DARK_THEME: "appearance.claudeCodeDarkTheme"
|
|
139394
139438
|
};
|
|
139395
139439
|
var LEGACY_KEY_MAP = {
|
|
139396
139440
|
port: "server.port",
|
|
@@ -139403,6 +139447,7 @@ var LEGACY_KEY_MAP = {
|
|
|
139403
139447
|
linear_api_key: "integrations.linearApiKey",
|
|
139404
139448
|
github_pat: "integrations.githubPat",
|
|
139405
139449
|
language: "appearance.language",
|
|
139450
|
+
theme: "appearance.theme",
|
|
139406
139451
|
defaultGitReposDir: "paths.defaultGitReposDir",
|
|
139407
139452
|
basicAuthUsername: "authentication.username",
|
|
139408
139453
|
basicAuthPassword: "authentication.password",
|
|
@@ -139523,13 +139568,26 @@ app5.post("/restart", (c) => {
|
|
|
139523
139568
|
return c.json({ error: "Restart only available in developer mode" }, 403);
|
|
139524
139569
|
}
|
|
139525
139570
|
setTimeout(() => {
|
|
139526
|
-
|
|
139571
|
+
spawn2("bash", ["-c", "cd ~/projects/vibora && mise run build && bun run drizzle-kit push && systemctl --user restart vibora-dev"], {
|
|
139527
139572
|
detached: true,
|
|
139528
139573
|
stdio: "ignore"
|
|
139529
139574
|
}).unref();
|
|
139530
139575
|
}, 100);
|
|
139531
139576
|
return c.json({ success: true, message: "Restart initiated (build + migrate + restart)" });
|
|
139532
139577
|
});
|
|
139578
|
+
app5.post("/sync-claude-theme", async (c) => {
|
|
139579
|
+
try {
|
|
139580
|
+
const body = await c.req.json();
|
|
139581
|
+
const { resolvedTheme } = body;
|
|
139582
|
+
if (resolvedTheme !== "light" && resolvedTheme !== "dark") {
|
|
139583
|
+
return c.json({ error: 'resolvedTheme must be "light" or "dark"' }, 400);
|
|
139584
|
+
}
|
|
139585
|
+
syncClaudeCodeTheme(resolvedTheme);
|
|
139586
|
+
return c.json({ success: true, resolvedTheme });
|
|
139587
|
+
} catch (err) {
|
|
139588
|
+
return c.json({ error: err instanceof Error ? err.message : "Failed to sync theme" }, 400);
|
|
139589
|
+
}
|
|
139590
|
+
});
|
|
139533
139591
|
app5.get("/:key", (c) => {
|
|
139534
139592
|
const key = c.req.param("key");
|
|
139535
139593
|
if (key === "worktree_base_path") {
|
|
@@ -139571,6 +139629,19 @@ app5.put("/:key", async (c) => {
|
|
|
139571
139629
|
return c.json({ error: 'Language must be "en", "zh", or null' }, 400);
|
|
139572
139630
|
}
|
|
139573
139631
|
value = value === "" ? null : value;
|
|
139632
|
+
} else if (path8 === CONFIG_KEYS.THEME) {
|
|
139633
|
+
if (value !== null && value !== "" && value !== "system" && value !== "light" && value !== "dark") {
|
|
139634
|
+
return c.json({ error: 'Theme must be "system", "light", "dark", or null' }, 400);
|
|
139635
|
+
}
|
|
139636
|
+
value = value === "" || value === "system" ? null : value;
|
|
139637
|
+
} else if (path8 === CONFIG_KEYS.SYNC_CLAUDE_CODE_THEME || path8 === CONFIG_KEYS.SYNC_STARSHIP_THEME) {
|
|
139638
|
+
if (typeof value !== "boolean") {
|
|
139639
|
+
return c.json({ error: "Sync setting must be a boolean" }, 400);
|
|
139640
|
+
}
|
|
139641
|
+
} else if (path8 === CONFIG_KEYS.CLAUDE_CODE_LIGHT_THEME || path8 === CONFIG_KEYS.CLAUDE_CODE_DARK_THEME) {
|
|
139642
|
+
if (!CLAUDE_CODE_THEMES.includes(value)) {
|
|
139643
|
+
return c.json({ error: `Claude Code theme must be one of: ${CLAUDE_CODE_THEMES.join(", ")}` }, 400);
|
|
139644
|
+
}
|
|
139574
139645
|
} else if (path8 === CONFIG_KEYS.EDITOR_APP) {
|
|
139575
139646
|
const validApps = ["vscode", "cursor", "windsurf", "zed"];
|
|
139576
139647
|
if (!validApps.includes(value)) {
|
|
@@ -139603,7 +139674,7 @@ app5.delete("/:key", (c) => {
|
|
|
139603
139674
|
var config_default = app5;
|
|
139604
139675
|
|
|
139605
139676
|
// server/routes/uploads.ts
|
|
139606
|
-
import { mkdir, writeFile, readFile } from "fs/promises";
|
|
139677
|
+
import { mkdir, writeFile, readFile, unlink } from "fs/promises";
|
|
139607
139678
|
import { existsSync as existsSync8 } from "fs";
|
|
139608
139679
|
import { join as join10 } from "path";
|
|
139609
139680
|
var mimeTypes = {
|
|
@@ -139612,7 +139683,10 @@ var mimeTypes = {
|
|
|
139612
139683
|
jpeg: "image/jpeg",
|
|
139613
139684
|
gif: "image/gif",
|
|
139614
139685
|
webp: "image/webp",
|
|
139615
|
-
svg: "image/svg+xml"
|
|
139686
|
+
svg: "image/svg+xml",
|
|
139687
|
+
mp3: "audio/mpeg",
|
|
139688
|
+
wav: "audio/wav",
|
|
139689
|
+
ogg: "audio/ogg"
|
|
139616
139690
|
};
|
|
139617
139691
|
var app6 = new Hono2;
|
|
139618
139692
|
function generateFilename(extension) {
|
|
@@ -139664,6 +139738,75 @@ app6.get("/:filename", async (c) => {
|
|
|
139664
139738
|
headers: { "Content-Type": contentType }
|
|
139665
139739
|
});
|
|
139666
139740
|
});
|
|
139741
|
+
app6.post("/sound", async (c) => {
|
|
139742
|
+
const body = await c.req.parseBody();
|
|
139743
|
+
const file = body["file"];
|
|
139744
|
+
if (!file || !(file instanceof File)) {
|
|
139745
|
+
return c.json({ error: "No file provided" }, 400);
|
|
139746
|
+
}
|
|
139747
|
+
const audioMimeTypes = {
|
|
139748
|
+
"audio/mpeg": "mp3",
|
|
139749
|
+
"audio/mp3": "mp3",
|
|
139750
|
+
"audio/wav": "wav",
|
|
139751
|
+
"audio/wave": "wav",
|
|
139752
|
+
"audio/ogg": "ogg"
|
|
139753
|
+
};
|
|
139754
|
+
const extension = audioMimeTypes[file.type];
|
|
139755
|
+
if (!extension) {
|
|
139756
|
+
return c.json({ error: "File must be an audio file (mp3, wav, or ogg)" }, 400);
|
|
139757
|
+
}
|
|
139758
|
+
const viboraDir = getViboraDir();
|
|
139759
|
+
const filename = `notification-sound.${extension}`;
|
|
139760
|
+
const filePath = join10(viboraDir, filename);
|
|
139761
|
+
for (const ext2 of ["mp3", "wav", "ogg"]) {
|
|
139762
|
+
const oldPath = join10(viboraDir, `notification-sound.${ext2}`);
|
|
139763
|
+
if (existsSync8(oldPath)) {
|
|
139764
|
+
try {
|
|
139765
|
+
await unlink(oldPath);
|
|
139766
|
+
} catch {}
|
|
139767
|
+
}
|
|
139768
|
+
}
|
|
139769
|
+
const arrayBuffer = await file.arrayBuffer();
|
|
139770
|
+
await writeFile(filePath, Buffer.from(arrayBuffer));
|
|
139771
|
+
updateNotificationSettings({
|
|
139772
|
+
sound: {
|
|
139773
|
+
...getNotificationSettings().sound,
|
|
139774
|
+
customSoundFile: filePath
|
|
139775
|
+
}
|
|
139776
|
+
});
|
|
139777
|
+
return c.json({ path: filePath, filename });
|
|
139778
|
+
});
|
|
139779
|
+
app6.delete("/sound", async (c) => {
|
|
139780
|
+
const viboraDir = getViboraDir();
|
|
139781
|
+
for (const ext2 of ["mp3", "wav", "ogg"]) {
|
|
139782
|
+
const filePath = join10(viboraDir, `notification-sound.${ext2}`);
|
|
139783
|
+
if (existsSync8(filePath)) {
|
|
139784
|
+
try {
|
|
139785
|
+
await unlink(filePath);
|
|
139786
|
+
} catch {}
|
|
139787
|
+
}
|
|
139788
|
+
}
|
|
139789
|
+
updateNotificationSettings({
|
|
139790
|
+
sound: {
|
|
139791
|
+
...getNotificationSettings().sound,
|
|
139792
|
+
customSoundFile: undefined
|
|
139793
|
+
}
|
|
139794
|
+
});
|
|
139795
|
+
return c.json({ success: true });
|
|
139796
|
+
});
|
|
139797
|
+
app6.get("/sound", async (c) => {
|
|
139798
|
+
const settings = getNotificationSettings();
|
|
139799
|
+
const customSoundFile = settings.sound?.customSoundFile;
|
|
139800
|
+
if (!customSoundFile || !existsSync8(customSoundFile)) {
|
|
139801
|
+
return c.notFound();
|
|
139802
|
+
}
|
|
139803
|
+
const ext2 = customSoundFile.split(".").pop()?.toLowerCase() || "";
|
|
139804
|
+
const contentType = mimeTypes[ext2] || "audio/mpeg";
|
|
139805
|
+
const content = await readFile(customSoundFile);
|
|
139806
|
+
return new Response(content, {
|
|
139807
|
+
headers: { "Content-Type": contentType }
|
|
139808
|
+
});
|
|
139809
|
+
});
|
|
139667
139810
|
var uploads_default = app6;
|
|
139668
139811
|
|
|
139669
139812
|
// node_modules/hono/dist/utils/stream.js
|
|
@@ -145071,6 +145214,7 @@ function stopPRMonitor() {
|
|
|
145071
145214
|
|
|
145072
145215
|
// server/index.ts
|
|
145073
145216
|
var PORT = getSettingByKey("port");
|
|
145217
|
+
var HOST = process.env.HOST || "localhost";
|
|
145074
145218
|
var ptyManager2 = initPTYManager({
|
|
145075
145219
|
onData: (terminalId, data) => {
|
|
145076
145220
|
broadcastToTerminal(terminalId, {
|
|
@@ -145098,7 +145242,7 @@ app13.get("/ws/terminal", upgradeWebSocket(() => terminalWebSocketHandlers));
|
|
|
145098
145242
|
var server = serve({
|
|
145099
145243
|
fetch: app13.fetch,
|
|
145100
145244
|
port: PORT,
|
|
145101
|
-
hostname:
|
|
145245
|
+
hostname: HOST
|
|
145102
145246
|
}, (info) => {
|
|
145103
145247
|
log2.server.info("Vibora server running", {
|
|
145104
145248
|
port: info.port,
|