vibora 1.2.0 → 1.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/dist/index.html CHANGED
@@ -6,7 +6,7 @@
6
6
  <link rel="icon" type="image/png" sizes="512x512" href="/vibora-icon.png" />
7
7
  <meta name="viewport" content="width=device-width, initial-scale=1.0" />
8
8
  <title>Vibora</title>
9
- <script type="module" crossorigin src="/assets/index-qBnZOT-E.js"></script>
9
+ <script type="module" crossorigin src="/assets/index-ClQ5DUcr.js"></script>
10
10
  <link rel="stylesheet" crossorigin href="/assets/index-DCMXlbkM.css">
11
11
  </head>
12
12
  <body>
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "vibora",
3
- "version": "1.2.0",
3
+ "version": "1.3.0",
4
4
  "description": "The Vibe Engineer's Cockpit",
5
5
  "license": "PolyForm-Shield-1.0.0",
6
6
  "repository": {
package/server/index.js CHANGED
@@ -13540,6 +13540,21 @@ function getDescendantPids(pid) {
13540
13540
  } catch {}
13541
13541
  return descendants;
13542
13542
  }
13543
+ function isClaudeProcess(pid) {
13544
+ try {
13545
+ const cmdline = readFileSync2(`/proc/${pid}/cmdline`, "utf-8");
13546
+ return /\bclaude\b/i.test(cmdline);
13547
+ } catch {
13548
+ try {
13549
+ const result = execSync(`ps -p ${pid} -o args= 2>/dev/null || true`, {
13550
+ encoding: "utf-8"
13551
+ });
13552
+ return /\bclaude\b/i.test(result);
13553
+ } catch {
13554
+ return false;
13555
+ }
13556
+ }
13557
+ }
13543
13558
  function killProcessTree(pid) {
13544
13559
  const descendants = getDescendantPids(pid);
13545
13560
  for (const childPid of descendants.reverse()) {
@@ -13582,6 +13597,21 @@ class DtachService {
13582
13597
  killProcessTree(pid);
13583
13598
  }
13584
13599
  }
13600
+ killClaudeInSession(terminalId) {
13601
+ const socketPath = this.getSocketPath(terminalId);
13602
+ const dtachPids = findProcessesByArg(socketPath);
13603
+ let killedAny = false;
13604
+ for (const dtachPid of dtachPids) {
13605
+ const descendants = getDescendantPids(dtachPid);
13606
+ for (const pid of descendants) {
13607
+ if (isClaudeProcess(pid)) {
13608
+ killProcessTree(pid);
13609
+ killedAny = true;
13610
+ }
13611
+ }
13612
+ }
13613
+ return killedAny;
13614
+ }
13585
13615
  static isAvailable() {
13586
13616
  try {
13587
13617
  execSync("which dtach", { encoding: "utf-8" });
@@ -14038,6 +14068,14 @@ class PTYManager {
14038
14068
  listTerminals() {
14039
14069
  return Array.from(this.sessions.values()).map((s) => s.getInfo());
14040
14070
  }
14071
+ killClaudeInTerminal(terminalId) {
14072
+ const session = this.sessions.get(terminalId);
14073
+ if (!session) {
14074
+ return false;
14075
+ }
14076
+ const dtach = getDtachService();
14077
+ return dtach.killClaudeInSession(terminalId);
14078
+ }
14041
14079
  detachAll() {
14042
14080
  for (const session of this.sessions.values()) {
14043
14081
  session.detach();
@@ -14076,6 +14114,19 @@ function destroyTerminalAndBroadcast(terminalId) {
14076
14114
  }
14077
14115
  return success;
14078
14116
  }
14117
+ function killClaudeInTerminalsForWorktree(worktreePath) {
14118
+ const manager = getPTYManager();
14119
+ const terminals2 = manager.listTerminals();
14120
+ let count = 0;
14121
+ for (const terminal of terminals2) {
14122
+ if (terminal.cwd === worktreePath) {
14123
+ if (manager.killClaudeInTerminal(terminal.id)) {
14124
+ count++;
14125
+ }
14126
+ }
14127
+ }
14128
+ return count;
14129
+ }
14079
14130
 
14080
14131
  // server/terminal/tab-manager.ts
14081
14132
  var VIEW_STATE_ID = "singleton";
@@ -138043,6 +138094,22 @@ app2.patch("/:id/status", async (c) => {
138043
138094
  return c.json({ error: err instanceof Error ? err.message : "Failed to update task status" }, 400);
138044
138095
  }
138045
138096
  });
138097
+ app2.post("/:id/kill-claude", (c) => {
138098
+ const id = c.req.param("id");
138099
+ const task = db.select().from(tasks).where(eq(tasks.id, id)).get();
138100
+ if (!task) {
138101
+ return c.json({ error: "Task not found" }, 404);
138102
+ }
138103
+ if (!task.worktreePath) {
138104
+ return c.json({ success: true, terminalsAffected: 0 });
138105
+ }
138106
+ try {
138107
+ const count = killClaudeInTerminalsForWorktree(task.worktreePath);
138108
+ return c.json({ success: true, terminalsAffected: count });
138109
+ } catch {
138110
+ return c.json({ success: true, terminalsAffected: 0 });
138111
+ }
138112
+ });
138046
138113
  var tasks_default = app2;
138047
138114
 
138048
138115
  // server/routes/git.ts