vibora 4.5.2 → 4.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 +45 -15
- package/bin/vibora.js +69 -1
- package/dist/assets/{index-rvVpMwsP.js → index-BHItdbV8.js} +106 -103
- package/dist/assets/index-uq7fsilP.css +1 -0
- package/dist/index.html +2 -2
- package/package.json +1 -1
- package/server/index.js +395 -45
- package/dist/assets/index-DujV-tJ5.css +0 -1
package/server/index.js
CHANGED
|
@@ -14380,6 +14380,11 @@ function migrateSettings(parsed) {
|
|
|
14380
14380
|
return result;
|
|
14381
14381
|
}
|
|
14382
14382
|
function expandPath(p) {
|
|
14383
|
+
if (!p)
|
|
14384
|
+
return p;
|
|
14385
|
+
if (p === "~") {
|
|
14386
|
+
return os.homedir();
|
|
14387
|
+
}
|
|
14383
14388
|
if (p.startsWith("~/")) {
|
|
14384
14389
|
return path.join(os.homedir(), p.slice(2));
|
|
14385
14390
|
}
|
|
@@ -146030,6 +146035,92 @@ app3.post("/sync-parent", async (c) => {
|
|
|
146030
146035
|
return c.json({ error: err instanceof Error ? err.message : "Failed to sync parent" }, 500);
|
|
146031
146036
|
}
|
|
146032
146037
|
});
|
|
146038
|
+
app3.post("/create-pr", async (c) => {
|
|
146039
|
+
try {
|
|
146040
|
+
const body = await c.req.json();
|
|
146041
|
+
const { worktreePath, title, baseBranch } = body;
|
|
146042
|
+
if (!worktreePath || !title) {
|
|
146043
|
+
return c.json({ error: "Missing required fields: worktreePath, title" }, 400);
|
|
146044
|
+
}
|
|
146045
|
+
if (!fs4.existsSync(worktreePath)) {
|
|
146046
|
+
return c.json({ error: "Worktree path does not exist" }, 404);
|
|
146047
|
+
}
|
|
146048
|
+
try {
|
|
146049
|
+
const status = gitExec(worktreePath, "status --porcelain");
|
|
146050
|
+
if (status.trim()) {
|
|
146051
|
+
return c.json({
|
|
146052
|
+
error: "Worktree has uncommitted changes. Please commit changes before creating a PR.",
|
|
146053
|
+
hasUncommittedChanges: true
|
|
146054
|
+
}, 409);
|
|
146055
|
+
}
|
|
146056
|
+
} catch {}
|
|
146057
|
+
let branch;
|
|
146058
|
+
try {
|
|
146059
|
+
branch = gitExec(worktreePath, "rev-parse --abbrev-ref HEAD");
|
|
146060
|
+
} catch {
|
|
146061
|
+
return c.json({ error: "Failed to determine current branch" }, 500);
|
|
146062
|
+
}
|
|
146063
|
+
const args = ["gh", "pr", "create", "--title", JSON.stringify(title), "--fill"];
|
|
146064
|
+
if (baseBranch) {
|
|
146065
|
+
args.push("--base", baseBranch);
|
|
146066
|
+
}
|
|
146067
|
+
try {
|
|
146068
|
+
const output = execSync3(args.join(" "), {
|
|
146069
|
+
cwd: worktreePath,
|
|
146070
|
+
encoding: "utf-8",
|
|
146071
|
+
timeout: 30000,
|
|
146072
|
+
stdio: ["pipe", "pipe", "pipe"]
|
|
146073
|
+
});
|
|
146074
|
+
const prUrl = output.trim();
|
|
146075
|
+
return c.json({
|
|
146076
|
+
success: true,
|
|
146077
|
+
prUrl,
|
|
146078
|
+
branch
|
|
146079
|
+
});
|
|
146080
|
+
} catch (err) {
|
|
146081
|
+
const errorMsg = err instanceof Error ? err.message : "Unknown error";
|
|
146082
|
+
const stderr = err && typeof err === "object" && "stderr" in err ? String(err.stderr).trim() : "";
|
|
146083
|
+
if (stderr.includes("already exists") || errorMsg.includes("already exists")) {
|
|
146084
|
+
try {
|
|
146085
|
+
const prViewOutput = execSync3("gh pr view --json url -q .url", {
|
|
146086
|
+
cwd: worktreePath,
|
|
146087
|
+
encoding: "utf-8",
|
|
146088
|
+
timeout: 1e4,
|
|
146089
|
+
stdio: ["pipe", "pipe", "pipe"]
|
|
146090
|
+
});
|
|
146091
|
+
const existingPrUrl = prViewOutput.trim();
|
|
146092
|
+
return c.json({
|
|
146093
|
+
error: "A pull request already exists for this branch",
|
|
146094
|
+
prAlreadyExists: true,
|
|
146095
|
+
existingPrUrl
|
|
146096
|
+
}, 409);
|
|
146097
|
+
} catch {
|
|
146098
|
+
return c.json({
|
|
146099
|
+
error: "A pull request already exists for this branch",
|
|
146100
|
+
prAlreadyExists: true
|
|
146101
|
+
}, 409);
|
|
146102
|
+
}
|
|
146103
|
+
}
|
|
146104
|
+
if (stderr.includes("not pushed") || errorMsg.includes("not pushed") || stderr.includes("no upstream") || errorMsg.includes("no upstream")) {
|
|
146105
|
+
return c.json({
|
|
146106
|
+
error: "Branch has not been pushed to remote. Please push first.",
|
|
146107
|
+
branchNotPushed: true
|
|
146108
|
+
}, 409);
|
|
146109
|
+
}
|
|
146110
|
+
if (stderr.includes("gh auth login") || errorMsg.includes("gh auth login")) {
|
|
146111
|
+
return c.json({
|
|
146112
|
+
error: "GitHub CLI not authenticated. Run `gh auth login` first.",
|
|
146113
|
+
notAuthenticated: true
|
|
146114
|
+
}, 401);
|
|
146115
|
+
}
|
|
146116
|
+
return c.json({
|
|
146117
|
+
error: stderr || errorMsg || "Failed to create PR"
|
|
146118
|
+
}, 500);
|
|
146119
|
+
}
|
|
146120
|
+
} catch (err) {
|
|
146121
|
+
return c.json({ error: err instanceof Error ? err.message : "Failed to create PR" }, 500);
|
|
146122
|
+
}
|
|
146123
|
+
});
|
|
146033
146124
|
app3.get("/remote", (c) => {
|
|
146034
146125
|
let repoPath = c.req.query("path");
|
|
146035
146126
|
if (!repoPath) {
|
|
@@ -147297,9 +147388,10 @@ app8.patch("/", async (c) => {
|
|
|
147297
147388
|
var terminal_view_state_default = app8;
|
|
147298
147389
|
|
|
147299
147390
|
// server/routes/repositories.ts
|
|
147300
|
-
import { existsSync as existsSync10, rmSync as rmSync4, readdirSync as readdirSync7 } from "fs";
|
|
147301
|
-
import { join as join12 } from "path";
|
|
147391
|
+
import { existsSync as existsSync10, rmSync as rmSync4, readdirSync as readdirSync7, mkdirSync as mkdirSync6 } from "fs";
|
|
147392
|
+
import { join as join12, resolve as resolve4 } from "path";
|
|
147302
147393
|
import { execSync as execSync4 } from "child_process";
|
|
147394
|
+
import { homedir as homedir5 } from "os";
|
|
147303
147395
|
|
|
147304
147396
|
// server/lib/git-utils.ts
|
|
147305
147397
|
function isGitUrl(source) {
|
|
@@ -147343,15 +147435,16 @@ app9.post("/", async (c) => {
|
|
|
147343
147435
|
if (!body.path) {
|
|
147344
147436
|
return c.json({ error: "path is required" }, 400);
|
|
147345
147437
|
}
|
|
147346
|
-
const
|
|
147438
|
+
const repoPath = expandPath(body.path);
|
|
147439
|
+
const existing = db.select().from(repositories).where(eq(repositories.path, repoPath)).get();
|
|
147347
147440
|
if (existing) {
|
|
147348
147441
|
return c.json({ error: "Repository with this path already exists" }, 400);
|
|
147349
147442
|
}
|
|
147350
147443
|
const now = new Date().toISOString();
|
|
147351
|
-
const displayName = body.displayName ||
|
|
147444
|
+
const displayName = body.displayName || repoPath.split("/").pop() || "repo";
|
|
147352
147445
|
const newRepo = {
|
|
147353
147446
|
id: crypto.randomUUID(),
|
|
147354
|
-
path:
|
|
147447
|
+
path: repoPath,
|
|
147355
147448
|
displayName,
|
|
147356
147449
|
startupScript: body.startupScript || null,
|
|
147357
147450
|
copyFiles: body.copyFiles || null,
|
|
@@ -147376,12 +147469,37 @@ app9.post("/clone", async (c) => {
|
|
|
147376
147469
|
return c.json({ error: "Invalid git URL format" }, 400);
|
|
147377
147470
|
}
|
|
147378
147471
|
const settings = getSettings();
|
|
147379
|
-
|
|
147380
|
-
|
|
147381
|
-
const
|
|
147472
|
+
let parentDir = body.targetDir?.trim() || settings.paths.defaultGitReposDir;
|
|
147473
|
+
parentDir = expandPath(parentDir);
|
|
147474
|
+
const home = homedir5();
|
|
147475
|
+
if (resolve4(parentDir) === home) {
|
|
147476
|
+
return c.json({ error: "Cannot clone directly into home directory. Please specify a subdirectory." }, 400);
|
|
147477
|
+
}
|
|
147478
|
+
const repoName = body.folderName?.trim() || extractRepoNameFromUrl(body.url);
|
|
147479
|
+
if (!repoName) {
|
|
147480
|
+
return c.json({ error: "Could not determine folder name from URL" }, 400);
|
|
147481
|
+
}
|
|
147482
|
+
if (repoName === "." || repoName === "..") {
|
|
147483
|
+
return c.json({ error: "Invalid folder name" }, 400);
|
|
147484
|
+
}
|
|
147485
|
+
if (repoName.includes("/") || repoName.includes("\\")) {
|
|
147486
|
+
return c.json({ error: "Folder name cannot contain path separators" }, 400);
|
|
147487
|
+
}
|
|
147488
|
+
const targetPath = join12(parentDir, repoName);
|
|
147489
|
+
const resolvedParent = resolve4(parentDir);
|
|
147490
|
+
const resolvedTarget = resolve4(targetPath);
|
|
147491
|
+
if (!resolvedTarget.startsWith(resolvedParent + "/") && resolvedTarget !== resolvedParent) {
|
|
147492
|
+
return c.json({ error: "Invalid target path" }, 400);
|
|
147493
|
+
}
|
|
147382
147494
|
if (existsSync10(targetPath)) {
|
|
147383
147495
|
return c.json({ error: `Directory already exists: ${targetPath}` }, 400);
|
|
147384
147496
|
}
|
|
147497
|
+
if (!existsSync10(parentDir)) {
|
|
147498
|
+
if (resolve4(parentDir) === home) {
|
|
147499
|
+
return c.json({ error: "Cannot create home directory" }, 400);
|
|
147500
|
+
}
|
|
147501
|
+
mkdirSync6(parentDir, { recursive: true });
|
|
147502
|
+
}
|
|
147385
147503
|
try {
|
|
147386
147504
|
execSync4(`git clone "${body.url}" "${targetPath}"`, {
|
|
147387
147505
|
encoding: "utf-8",
|
|
@@ -147389,7 +147507,7 @@ app9.post("/clone", async (c) => {
|
|
|
147389
147507
|
timeout: 120000
|
|
147390
147508
|
});
|
|
147391
147509
|
} catch (cloneErr) {
|
|
147392
|
-
if (existsSync10(targetPath)) {
|
|
147510
|
+
if (existsSync10(targetPath) && resolvedTarget.startsWith(resolvedParent + "/")) {
|
|
147393
147511
|
rmSync4(targetPath, { recursive: true, force: true });
|
|
147394
147512
|
}
|
|
147395
147513
|
const errorMessage = cloneErr instanceof Error ? cloneErr.message : "Clone failed";
|
|
@@ -147449,18 +147567,43 @@ app9.patch("/:id", async (c) => {
|
|
|
147449
147567
|
});
|
|
147450
147568
|
app9.delete("/:id", (c) => {
|
|
147451
147569
|
const id = c.req.param("id");
|
|
147570
|
+
const deleteDirectory = c.req.query("deleteDirectory") === "true";
|
|
147452
147571
|
const existing = db.select().from(repositories).where(eq(repositories.id, id)).get();
|
|
147453
147572
|
if (!existing) {
|
|
147454
147573
|
return c.json({ error: "Repository not found" }, 404);
|
|
147455
147574
|
}
|
|
147575
|
+
if (deleteDirectory && existing.path) {
|
|
147576
|
+
const repoPath = existing.path;
|
|
147577
|
+
const home = homedir5();
|
|
147578
|
+
if (resolve4(repoPath) === home) {
|
|
147579
|
+
return c.json({ error: "Cannot delete home directory" }, 400);
|
|
147580
|
+
}
|
|
147581
|
+
const dangerousPaths = ["/", "/home", "/usr", "/etc", "/var", "/tmp", "/root"];
|
|
147582
|
+
if (dangerousPaths.includes(resolve4(repoPath))) {
|
|
147583
|
+
return c.json({ error: "Cannot delete system directory" }, 400);
|
|
147584
|
+
}
|
|
147585
|
+
if (existsSync10(repoPath)) {
|
|
147586
|
+
const gitPath = join12(repoPath, ".git");
|
|
147587
|
+
if (!existsSync10(gitPath)) {
|
|
147588
|
+
return c.json({ error: "Directory does not appear to be a git repository" }, 400);
|
|
147589
|
+
}
|
|
147590
|
+
try {
|
|
147591
|
+
rmSync4(repoPath, { recursive: true, force: true });
|
|
147592
|
+
} catch (err) {
|
|
147593
|
+
return c.json({
|
|
147594
|
+
error: `Failed to delete directory: ${err instanceof Error ? err.message : "Unknown error"}`
|
|
147595
|
+
}, 500);
|
|
147596
|
+
}
|
|
147597
|
+
}
|
|
147598
|
+
}
|
|
147456
147599
|
db.delete(repositories).where(eq(repositories.id, id)).run();
|
|
147457
|
-
return c.json({ success: true });
|
|
147600
|
+
return c.json({ success: true, directoryDeleted: deleteDirectory });
|
|
147458
147601
|
});
|
|
147459
147602
|
app9.post("/scan", async (c) => {
|
|
147460
147603
|
try {
|
|
147461
147604
|
const body = await c.req.json().catch(() => ({}));
|
|
147462
147605
|
const settings = getSettings();
|
|
147463
|
-
const directory = body.directory || settings.paths.defaultGitReposDir;
|
|
147606
|
+
const directory = expandPath(body.directory || settings.paths.defaultGitReposDir);
|
|
147464
147607
|
if (!existsSync10(directory)) {
|
|
147465
147608
|
return c.json({ error: `Directory does not exist: ${directory}` }, 400);
|
|
147466
147609
|
}
|
|
@@ -151521,7 +151664,7 @@ var github_default = app12;
|
|
|
151521
151664
|
// server/routes/monitoring.ts
|
|
151522
151665
|
import { readdirSync as readdirSync8, readFileSync as readFileSync7, readlinkSync as readlinkSync2, existsSync as existsSync12 } from "fs";
|
|
151523
151666
|
import { execSync as execSync7 } from "child_process";
|
|
151524
|
-
import { homedir as
|
|
151667
|
+
import { homedir as homedir6 } from "os";
|
|
151525
151668
|
import { join as join14 } from "path";
|
|
151526
151669
|
|
|
151527
151670
|
// server/services/metrics-collector.ts
|
|
@@ -152309,7 +152452,7 @@ monitoringRoutes.post("/vibora-instances/:pid/kill", async (c) => {
|
|
|
152309
152452
|
killedPids.push(pid);
|
|
152310
152453
|
} catch {}
|
|
152311
152454
|
}
|
|
152312
|
-
await new Promise((
|
|
152455
|
+
await new Promise((resolve5) => setTimeout(resolve5, 500));
|
|
152313
152456
|
for (const pid of pidsToKill) {
|
|
152314
152457
|
try {
|
|
152315
152458
|
process.kill(pid, 0);
|
|
@@ -152327,7 +152470,7 @@ var cachedUsage = null;
|
|
|
152327
152470
|
var usageCacheTimestamp = 0;
|
|
152328
152471
|
var USAGE_CACHE_MS = 15 * 1000;
|
|
152329
152472
|
async function getClaudeOAuthToken() {
|
|
152330
|
-
const primaryPath = join14(
|
|
152473
|
+
const primaryPath = join14(homedir6(), ".claude", ".credentials.json");
|
|
152331
152474
|
try {
|
|
152332
152475
|
if (existsSync12(primaryPath)) {
|
|
152333
152476
|
const content = readFileSync7(primaryPath, "utf-8");
|
|
@@ -152493,6 +152636,212 @@ app13.get("/dependencies", (c) => {
|
|
|
152493
152636
|
});
|
|
152494
152637
|
var system_default = app13;
|
|
152495
152638
|
|
|
152639
|
+
// server/routes/exec.ts
|
|
152640
|
+
import { spawn as spawn3 } from "child_process";
|
|
152641
|
+
import { randomUUID } from "crypto";
|
|
152642
|
+
import * as os6 from "os";
|
|
152643
|
+
var DEFAULT_TIMEOUT = 30000;
|
|
152644
|
+
var START_MARKER = `<<VIBORA_CMD_START_${randomUUID().slice(0, 8)}>>`;
|
|
152645
|
+
var END_MARKER_PREFIX = `<<VIBORA_CMD_END_${randomUUID().slice(0, 8)}:`;
|
|
152646
|
+
var sessions = new Map;
|
|
152647
|
+
function createSession(cwd, name) {
|
|
152648
|
+
const id = randomUUID();
|
|
152649
|
+
const initialCwd = cwd || os6.homedir();
|
|
152650
|
+
const proc2 = spawn3("/bin/bash", ["--norc", "--noprofile"], {
|
|
152651
|
+
cwd: initialCwd,
|
|
152652
|
+
env: { ...process.env, TERM: "dumb" },
|
|
152653
|
+
stdio: ["pipe", "pipe", "pipe"]
|
|
152654
|
+
});
|
|
152655
|
+
const session = {
|
|
152656
|
+
id,
|
|
152657
|
+
name,
|
|
152658
|
+
process: proc2,
|
|
152659
|
+
cwd: initialCwd,
|
|
152660
|
+
outputBuffer: "",
|
|
152661
|
+
stderrBuffer: "",
|
|
152662
|
+
pendingResolve: null,
|
|
152663
|
+
pendingReject: null,
|
|
152664
|
+
createdAt: new Date,
|
|
152665
|
+
lastUsedAt: new Date
|
|
152666
|
+
};
|
|
152667
|
+
proc2.stdout?.on("data", (data) => {
|
|
152668
|
+
session.outputBuffer += data.toString();
|
|
152669
|
+
checkForCompletion(session);
|
|
152670
|
+
});
|
|
152671
|
+
proc2.stderr?.on("data", (data) => {
|
|
152672
|
+
session.stderrBuffer += data.toString();
|
|
152673
|
+
});
|
|
152674
|
+
proc2.on("error", (err) => {
|
|
152675
|
+
if (session.pendingReject) {
|
|
152676
|
+
session.pendingReject(err);
|
|
152677
|
+
session.pendingResolve = null;
|
|
152678
|
+
session.pendingReject = null;
|
|
152679
|
+
}
|
|
152680
|
+
});
|
|
152681
|
+
proc2.on("exit", () => {
|
|
152682
|
+
sessions.delete(id);
|
|
152683
|
+
if (session.pendingReject) {
|
|
152684
|
+
session.pendingReject(new Error("Shell process exited unexpectedly"));
|
|
152685
|
+
session.pendingResolve = null;
|
|
152686
|
+
session.pendingReject = null;
|
|
152687
|
+
}
|
|
152688
|
+
});
|
|
152689
|
+
sessions.set(id, session);
|
|
152690
|
+
return session;
|
|
152691
|
+
}
|
|
152692
|
+
function checkForCompletion(session) {
|
|
152693
|
+
if (!session.pendingResolve)
|
|
152694
|
+
return;
|
|
152695
|
+
const endMarkerRegex = new RegExp(`${END_MARKER_PREFIX.replace(/[.*+?^${}()|[\]\\]/g, "\\$&")}(\\d+)>>`);
|
|
152696
|
+
const match3 = session.outputBuffer.match(endMarkerRegex);
|
|
152697
|
+
if (match3) {
|
|
152698
|
+
const exitCode = parseInt(match3[1], 10);
|
|
152699
|
+
const startIdx = session.outputBuffer.indexOf(START_MARKER);
|
|
152700
|
+
const endIdx = session.outputBuffer.indexOf(match3[0]);
|
|
152701
|
+
let stdout = "";
|
|
152702
|
+
if (startIdx !== -1 && endIdx > startIdx) {
|
|
152703
|
+
stdout = session.outputBuffer.slice(startIdx + START_MARKER.length + 1, endIdx);
|
|
152704
|
+
if (stdout.endsWith(`
|
|
152705
|
+
`)) {
|
|
152706
|
+
stdout = stdout.slice(0, -1);
|
|
152707
|
+
}
|
|
152708
|
+
}
|
|
152709
|
+
const stderr = session.stderrBuffer;
|
|
152710
|
+
session.outputBuffer = "";
|
|
152711
|
+
session.stderrBuffer = "";
|
|
152712
|
+
const resolve5 = session.pendingResolve;
|
|
152713
|
+
session.pendingResolve = null;
|
|
152714
|
+
session.pendingReject = null;
|
|
152715
|
+
resolve5({ stdout, stderr, exitCode });
|
|
152716
|
+
}
|
|
152717
|
+
}
|
|
152718
|
+
function destroySession(id) {
|
|
152719
|
+
const session = sessions.get(id);
|
|
152720
|
+
if (!session)
|
|
152721
|
+
return false;
|
|
152722
|
+
try {
|
|
152723
|
+
session.process.kill();
|
|
152724
|
+
} catch {}
|
|
152725
|
+
sessions.delete(id);
|
|
152726
|
+
return true;
|
|
152727
|
+
}
|
|
152728
|
+
async function executeCommand(session, command, timeout) {
|
|
152729
|
+
return new Promise((resolve5, reject) => {
|
|
152730
|
+
session.lastUsedAt = new Date;
|
|
152731
|
+
session.outputBuffer = "";
|
|
152732
|
+
session.stderrBuffer = "";
|
|
152733
|
+
session.pendingResolve = resolve5;
|
|
152734
|
+
session.pendingReject = reject;
|
|
152735
|
+
const wrappedCommand = `echo "${START_MARKER}"; ${command}; echo "${END_MARKER_PREFIX}$?>>"
|
|
152736
|
+
`;
|
|
152737
|
+
const timeoutId = setTimeout(() => {
|
|
152738
|
+
session.pendingResolve = null;
|
|
152739
|
+
session.pendingReject = null;
|
|
152740
|
+
reject(new Error("Command timed out"));
|
|
152741
|
+
}, timeout);
|
|
152742
|
+
const originalResolve = resolve5;
|
|
152743
|
+
session.pendingResolve = (result) => {
|
|
152744
|
+
clearTimeout(timeoutId);
|
|
152745
|
+
originalResolve(result);
|
|
152746
|
+
};
|
|
152747
|
+
session.process.stdin?.write(wrappedCommand);
|
|
152748
|
+
});
|
|
152749
|
+
}
|
|
152750
|
+
async function updateSessionCwd(session) {
|
|
152751
|
+
try {
|
|
152752
|
+
const result = await executeCommand(session, "pwd", 5000);
|
|
152753
|
+
if (result.exitCode === 0 && result.stdout.trim()) {
|
|
152754
|
+
session.cwd = result.stdout.trim();
|
|
152755
|
+
}
|
|
152756
|
+
} catch {}
|
|
152757
|
+
}
|
|
152758
|
+
var app14 = new Hono2;
|
|
152759
|
+
app14.post("/", async (c) => {
|
|
152760
|
+
try {
|
|
152761
|
+
const body = await c.req.json();
|
|
152762
|
+
const { command, sessionId, cwd, timeout = DEFAULT_TIMEOUT, name } = body;
|
|
152763
|
+
if (!command) {
|
|
152764
|
+
return c.json({ error: "command is required" }, 400);
|
|
152765
|
+
}
|
|
152766
|
+
let session;
|
|
152767
|
+
if (sessionId) {
|
|
152768
|
+
const existing = sessions.get(sessionId);
|
|
152769
|
+
if (!existing) {
|
|
152770
|
+
return c.json({ error: `Session ${sessionId} not found` }, 404);
|
|
152771
|
+
}
|
|
152772
|
+
session = existing;
|
|
152773
|
+
} else {
|
|
152774
|
+
session = createSession(cwd, name);
|
|
152775
|
+
}
|
|
152776
|
+
try {
|
|
152777
|
+
const result = await executeCommand(session, command, timeout);
|
|
152778
|
+
await updateSessionCwd(session);
|
|
152779
|
+
const response = {
|
|
152780
|
+
sessionId: session.id,
|
|
152781
|
+
stdout: result.stdout,
|
|
152782
|
+
stderr: result.stderr,
|
|
152783
|
+
exitCode: result.exitCode,
|
|
152784
|
+
timedOut: false
|
|
152785
|
+
};
|
|
152786
|
+
return c.json(response);
|
|
152787
|
+
} catch (err) {
|
|
152788
|
+
if (err instanceof Error && err.message === "Command timed out") {
|
|
152789
|
+
const response = {
|
|
152790
|
+
sessionId: session.id,
|
|
152791
|
+
stdout: session.outputBuffer,
|
|
152792
|
+
stderr: session.stderrBuffer,
|
|
152793
|
+
exitCode: null,
|
|
152794
|
+
timedOut: true
|
|
152795
|
+
};
|
|
152796
|
+
return c.json(response);
|
|
152797
|
+
}
|
|
152798
|
+
throw err;
|
|
152799
|
+
}
|
|
152800
|
+
} catch (err) {
|
|
152801
|
+
return c.json({ error: err instanceof Error ? err.message : "Failed to execute command" }, 500);
|
|
152802
|
+
}
|
|
152803
|
+
});
|
|
152804
|
+
app14.get("/sessions", (c) => {
|
|
152805
|
+
const sessionList = [];
|
|
152806
|
+
for (const [id, session] of sessions) {
|
|
152807
|
+
sessionList.push({
|
|
152808
|
+
id,
|
|
152809
|
+
name: session.name,
|
|
152810
|
+
cwd: session.cwd,
|
|
152811
|
+
createdAt: session.createdAt.toISOString(),
|
|
152812
|
+
lastUsedAt: session.lastUsedAt.toISOString()
|
|
152813
|
+
});
|
|
152814
|
+
}
|
|
152815
|
+
return c.json(sessionList);
|
|
152816
|
+
});
|
|
152817
|
+
app14.patch("/sessions/:id", async (c) => {
|
|
152818
|
+
const id = c.req.param("id");
|
|
152819
|
+
const session = sessions.get(id);
|
|
152820
|
+
if (!session) {
|
|
152821
|
+
return c.json({ error: `Session ${id} not found` }, 404);
|
|
152822
|
+
}
|
|
152823
|
+
const body = await c.req.json();
|
|
152824
|
+
if (body.name !== undefined) {
|
|
152825
|
+
session.name = body.name;
|
|
152826
|
+
}
|
|
152827
|
+
return c.json({
|
|
152828
|
+
id: session.id,
|
|
152829
|
+
name: session.name,
|
|
152830
|
+
cwd: session.cwd,
|
|
152831
|
+
createdAt: session.createdAt.toISOString(),
|
|
152832
|
+
lastUsedAt: session.lastUsedAt.toISOString()
|
|
152833
|
+
});
|
|
152834
|
+
});
|
|
152835
|
+
app14.delete("/sessions/:id", (c) => {
|
|
152836
|
+
const id = c.req.param("id");
|
|
152837
|
+
const destroyed = destroySession(id);
|
|
152838
|
+
if (!destroyed) {
|
|
152839
|
+
return c.json({ error: `Session ${id} not found` }, 404);
|
|
152840
|
+
}
|
|
152841
|
+
return c.json({ success: true });
|
|
152842
|
+
});
|
|
152843
|
+
var exec_default = app14;
|
|
152844
|
+
|
|
152496
152845
|
// server/app.ts
|
|
152497
152846
|
function getDistPath() {
|
|
152498
152847
|
if (process.env.VIBORA_PACKAGE_ROOT) {
|
|
@@ -152501,35 +152850,36 @@ function getDistPath() {
|
|
|
152501
152850
|
return join15(process.cwd(), "dist");
|
|
152502
152851
|
}
|
|
152503
152852
|
function createApp() {
|
|
152504
|
-
const
|
|
152505
|
-
|
|
152506
|
-
|
|
152853
|
+
const app15 = new Hono2;
|
|
152854
|
+
app15.use("*", logger());
|
|
152855
|
+
app15.use("*", cors({
|
|
152507
152856
|
origin: "*",
|
|
152508
152857
|
allowMethods: ["GET", "POST", "PATCH", "PUT", "DELETE", "OPTIONS"],
|
|
152509
152858
|
allowHeaders: ["Content-Type"]
|
|
152510
152859
|
}));
|
|
152511
|
-
|
|
152512
|
-
|
|
152513
|
-
|
|
152514
|
-
|
|
152515
|
-
|
|
152516
|
-
|
|
152517
|
-
|
|
152518
|
-
|
|
152519
|
-
|
|
152520
|
-
|
|
152521
|
-
|
|
152522
|
-
|
|
152523
|
-
|
|
152524
|
-
|
|
152525
|
-
|
|
152860
|
+
app15.route("/health", health_default);
|
|
152861
|
+
app15.route("/api/tasks", tasks_default);
|
|
152862
|
+
app15.route("/api/git", git_default);
|
|
152863
|
+
app15.route("/api/fs", filesystem_default);
|
|
152864
|
+
app15.route("/api/config", config_default);
|
|
152865
|
+
app15.route("/api/uploads", uploads_default);
|
|
152866
|
+
app15.route("/api/worktrees", worktrees_default);
|
|
152867
|
+
app15.route("/api/terminal-view-state", terminal_view_state_default);
|
|
152868
|
+
app15.route("/api/repositories", repositories_default);
|
|
152869
|
+
app15.route("/api/copier", copier_default);
|
|
152870
|
+
app15.route("/api/linear", linear_default);
|
|
152871
|
+
app15.route("/api/github", github_default);
|
|
152872
|
+
app15.route("/api/monitoring", monitoringRoutes);
|
|
152873
|
+
app15.route("/api/system", system_default);
|
|
152874
|
+
app15.route("/api/exec", exec_default);
|
|
152875
|
+
app15.post("/api/logs", async (c) => {
|
|
152526
152876
|
const { entries } = await c.req.json();
|
|
152527
152877
|
for (const entry of entries) {
|
|
152528
152878
|
writeEntry(entry);
|
|
152529
152879
|
}
|
|
152530
152880
|
return c.json({ ok: true });
|
|
152531
152881
|
});
|
|
152532
|
-
|
|
152882
|
+
app15.post("/api/debug", async (c) => {
|
|
152533
152883
|
const body = await c.req.json();
|
|
152534
152884
|
const entry = {
|
|
152535
152885
|
ts: new Date().toISOString(),
|
|
@@ -152566,14 +152916,14 @@ function createApp() {
|
|
|
152566
152916
|
headers: { "Content-Type": mimeTypes2[ext2 || ""] || "application/octet-stream" }
|
|
152567
152917
|
});
|
|
152568
152918
|
};
|
|
152569
|
-
|
|
152919
|
+
app15.get("/assets/*", async (c) => {
|
|
152570
152920
|
const assetPath = join15(distPath, c.req.path);
|
|
152571
152921
|
if (existsSync13(assetPath)) {
|
|
152572
152922
|
return serveFile(assetPath);
|
|
152573
152923
|
}
|
|
152574
152924
|
return c.notFound();
|
|
152575
152925
|
});
|
|
152576
|
-
|
|
152926
|
+
app15.get("/sounds/*", async (c) => {
|
|
152577
152927
|
const soundPath = join15(distPath, c.req.path);
|
|
152578
152928
|
if (existsSync13(soundPath)) {
|
|
152579
152929
|
return serveFile(soundPath);
|
|
@@ -152582,7 +152932,7 @@ function createApp() {
|
|
|
152582
152932
|
});
|
|
152583
152933
|
const staticFiles = ["vibora-icon.png", "vibora-logo.jpeg", "vite.svg", "logo-dark.jpg", "logo-light.jpg", "goat.jpeg"];
|
|
152584
152934
|
for (const file of staticFiles) {
|
|
152585
|
-
|
|
152935
|
+
app15.get(`/${file}`, async () => {
|
|
152586
152936
|
const filePath = join15(distPath, file);
|
|
152587
152937
|
if (existsSync13(filePath)) {
|
|
152588
152938
|
return serveFile(filePath);
|
|
@@ -152590,7 +152940,7 @@ function createApp() {
|
|
|
152590
152940
|
return new Response("Not Found", { status: 404 });
|
|
152591
152941
|
});
|
|
152592
152942
|
}
|
|
152593
|
-
|
|
152943
|
+
app15.get("*", async (c, next) => {
|
|
152594
152944
|
const path9 = c.req.path;
|
|
152595
152945
|
if (path9.startsWith("/api/") || path9.startsWith("/ws/") || path9 === "/health") {
|
|
152596
152946
|
return next();
|
|
@@ -152599,7 +152949,7 @@ function createApp() {
|
|
|
152599
152949
|
return c.html(html);
|
|
152600
152950
|
});
|
|
152601
152951
|
}
|
|
152602
|
-
return
|
|
152952
|
+
return app15;
|
|
152603
152953
|
}
|
|
152604
152954
|
|
|
152605
152955
|
// server/services/pr-monitor.ts
|
|
@@ -152666,11 +153016,11 @@ function stopPRMonitor() {
|
|
|
152666
153016
|
var PORT = getSettingByKey("port");
|
|
152667
153017
|
var HOST = process.env.HOST || "localhost";
|
|
152668
153018
|
async function checkPortAvailable(port, host) {
|
|
152669
|
-
return new Promise((
|
|
153019
|
+
return new Promise((resolve5) => {
|
|
152670
153020
|
const server = createServer();
|
|
152671
|
-
server.once("error", () =>
|
|
153021
|
+
server.once("error", () => resolve5(false));
|
|
152672
153022
|
server.once("listening", () => {
|
|
152673
|
-
server.close(() =>
|
|
153023
|
+
server.close(() => resolve5(true));
|
|
152674
153024
|
});
|
|
152675
153025
|
server.listen(port, host);
|
|
152676
153026
|
});
|
|
@@ -152702,11 +153052,11 @@ setBroadcastDestroyed((terminalId) => {
|
|
|
152702
153052
|
payload: { terminalId }
|
|
152703
153053
|
});
|
|
152704
153054
|
});
|
|
152705
|
-
var
|
|
152706
|
-
var { injectWebSocket, upgradeWebSocket } = createNodeWebSocket({ app:
|
|
152707
|
-
|
|
153055
|
+
var app15 = createApp();
|
|
153056
|
+
var { injectWebSocket, upgradeWebSocket } = createNodeWebSocket({ app: app15 });
|
|
153057
|
+
app15.get("/ws/terminal", upgradeWebSocket(() => terminalWebSocketHandlers));
|
|
152708
153058
|
var server = serve({
|
|
152709
|
-
fetch:
|
|
153059
|
+
fetch: app15.fetch,
|
|
152710
153060
|
port: PORT,
|
|
152711
153061
|
hostname: HOST
|
|
152712
153062
|
}, (info) => {
|