feat(v0.3): H1 — tmux keepalive (sessions survive a server restart)
- src/session/tmux.ts: sync tmux CLI wrappers (available/has/kill), best-effort - config: useTmux from USE_TMUX env (1/0/auto→detect tmux on PATH) - session: when useTmux, spawn 'tmux new-session -A -s web_<id> <shell>' (the node-pty proc is a tmux CLIENT); createSession takes an optional id for re-attach; Session.tmuxName; kill() runs tmux kill-session - manager: handleAttach re-attaches to a surviving 'web_<id>' tmux session after a restart (Case 3.5); shutdown kills only the client pty for tmux sessions so the shell keeps running - tests: USE_TMUX:0 in shared integration cfg (no tmux leakage); unit CFGs useTmux:false; integration 'H1' (real tmux): set var → restart server → re-attach → var survived. 208 tests green.
This commit is contained in:
46
src/session/tmux.ts
Normal file
46
src/session/tmux.ts
Normal file
@@ -0,0 +1,46 @@
|
||||
/**
|
||||
* src/session/tmux.ts (H1) — thin synchronous wrappers around the tmux CLI.
|
||||
*
|
||||
* Used only when cfg.useTmux is on. Running the shell inside a tmux session
|
||||
* lets it survive a server/host restart: the node-pty process is just a tmux
|
||||
* *client*; killing it detaches, and the tmux server keeps the shell alive.
|
||||
*
|
||||
* Every call is best-effort and never throws (tmux missing / session gone are
|
||||
* treated as "false"/no-op).
|
||||
*/
|
||||
|
||||
import { execFileSync } from 'node:child_process'
|
||||
|
||||
/** Is the tmux binary available on PATH? */
|
||||
export function tmuxAvailable(): boolean {
|
||||
try {
|
||||
execFileSync('tmux', ['-V'], { stdio: 'ignore' })
|
||||
return true
|
||||
} catch {
|
||||
return false
|
||||
}
|
||||
}
|
||||
|
||||
/** tmux session name for a web-terminal session id (UUIDs are tmux-safe). */
|
||||
export function tmuxName(sessionId: string): string {
|
||||
return `web_${sessionId}`
|
||||
}
|
||||
|
||||
/** Does a tmux session with this name already exist (e.g. after a restart)? */
|
||||
export function hasSession(name: string): boolean {
|
||||
try {
|
||||
execFileSync('tmux', ['has-session', '-t', name], { stdio: 'ignore' })
|
||||
return true
|
||||
} catch {
|
||||
return false
|
||||
}
|
||||
}
|
||||
|
||||
/** Kill a tmux session (ends the shell). No-op if it's already gone. */
|
||||
export function killSession(name: string): void {
|
||||
try {
|
||||
execFileSync('tmux', ['kill-session', '-t', name], { stdio: 'ignore' })
|
||||
} catch {
|
||||
// already gone — fine
|
||||
}
|
||||
}
|
||||
Reference in New Issue
Block a user