mirror of
https://github.com/garrytan/gstack.git
synced 2026-05-05 05:05:08 +02:00
fix: killAgent() actually kills the sidebar claude subprocess
Cherry-pick PR #743 by @Gonzih. Implements cross-process kill signaling via kill-file + polling pattern, tracks active processes per-tab. Co-Authored-By: Gonzih <gonzih@users.noreply.github.com> Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
This commit is contained in:
@@ -585,6 +585,13 @@ function killAgent(): void {
|
||||
agentStartTime = null;
|
||||
currentMessage = null;
|
||||
agentStatus = 'idle';
|
||||
|
||||
// Signal sidebar-agent.ts to kill its active claude subprocess.
|
||||
// sidebar-agent runs in a separate non-compiled Bun process (posix_spawn
|
||||
// limitation). It polls the kill-signal file and terminates on any write.
|
||||
const agentQueue = process.env.SIDEBAR_QUEUE_PATH || path.join(process.env.HOME || '/tmp', '.gstack', 'sidebar-agent-queue.jsonl');
|
||||
const killFile = path.join(path.dirname(agentQueue), 'sidebar-agent-kill');
|
||||
try { fs.writeFileSync(killFile, String(Date.now())); } catch {}
|
||||
}
|
||||
|
||||
// Agent health check — detect hung processes
|
||||
|
||||
@@ -14,6 +14,7 @@ import * as fs from 'fs';
|
||||
import * as path from 'path';
|
||||
|
||||
const QUEUE = process.env.SIDEBAR_QUEUE_PATH || path.join(process.env.HOME || '/tmp', '.gstack', 'sidebar-agent-queue.jsonl');
|
||||
const KILL_FILE = path.join(path.dirname(QUEUE), 'sidebar-agent-kill');
|
||||
const SERVER_PORT = parseInt(process.env.BROWSE_SERVER_PORT || '34567', 10);
|
||||
const SERVER_URL = `http://127.0.0.1:${SERVER_PORT}`;
|
||||
const POLL_MS = 200; // 200ms poll — keeps time-to-first-token low
|
||||
@@ -23,6 +24,10 @@ let lastLine = 0;
|
||||
let authToken: string | null = null;
|
||||
// Per-tab processing — each tab can run its own agent concurrently
|
||||
const processingTabs = new Set<number>();
|
||||
// Active claude subprocesses — keyed by tabId for targeted kill
|
||||
const activeProcs = new Map<number, ReturnType<typeof spawn>>();
|
||||
// Kill-file timestamp last seen — avoids double-kill on same write
|
||||
let lastKillTs = 0;
|
||||
|
||||
// ─── File drop relay ──────────────────────────────────────────
|
||||
|
||||
@@ -263,6 +268,9 @@ async function askClaude(queueEntry: any): Promise<void> {
|
||||
},
|
||||
});
|
||||
|
||||
// Track active procs so kill-file polling can terminate them
|
||||
activeProcs.set(tid, proc);
|
||||
|
||||
proc.stdin.end();
|
||||
|
||||
let buffer = '';
|
||||
@@ -285,6 +293,7 @@ async function askClaude(queueEntry: any): Promise<void> {
|
||||
});
|
||||
|
||||
proc.on('close', (code) => {
|
||||
activeProcs.delete(tid);
|
||||
if (buffer.trim()) {
|
||||
try { handleStreamEvent(JSON.parse(buffer), tid); } catch (err: any) {
|
||||
console.error(`[sidebar-agent] Tab ${tid}: Failed to parse final buffer:`, buffer.slice(0, 100), err.message);
|
||||
@@ -381,6 +390,27 @@ async function poll() {
|
||||
|
||||
// ─── Main ────────────────────────────────────────────────────────
|
||||
|
||||
function pollKillFile(): void {
|
||||
try {
|
||||
const stat = fs.statSync(KILL_FILE);
|
||||
const mtime = stat.mtimeMs;
|
||||
if (mtime > lastKillTs) {
|
||||
lastKillTs = mtime;
|
||||
if (activeProcs.size > 0) {
|
||||
console.log(`[sidebar-agent] Kill signal received — terminating ${activeProcs.size} active agent(s)`);
|
||||
for (const [tid, proc] of activeProcs) {
|
||||
try { proc.kill('SIGTERM'); } catch {}
|
||||
setTimeout(() => { try { proc.kill('SIGKILL'); } catch {} }, 2000);
|
||||
processingTabs.delete(tid);
|
||||
}
|
||||
activeProcs.clear();
|
||||
}
|
||||
}
|
||||
} catch {
|
||||
// Kill file doesn't exist yet — normal state
|
||||
}
|
||||
}
|
||||
|
||||
async function main() {
|
||||
const dir = path.dirname(QUEUE);
|
||||
fs.mkdirSync(dir, { recursive: true });
|
||||
@@ -394,6 +424,7 @@ async function main() {
|
||||
console.log(`[sidebar-agent] Browse binary: ${B}`);
|
||||
|
||||
setInterval(poll, POLL_MS);
|
||||
setInterval(pollKillFile, POLL_MS);
|
||||
}
|
||||
|
||||
main().catch(console.error);
|
||||
|
||||
Reference in New Issue
Block a user