import * as pty from 'node-pty'; import type { IPty } from 'node-pty'; export interface AttachPtyOptions { sessionName: string; projectRoot: string; cols: number; rows: number; tmuxConfPath: string; } function cleanEnv(): { [key: string]: string } { const out: { [key: string]: string } = {}; for (const [k, v] of Object.entries(process.env)) { if (typeof v === 'string') out[k] = v; } out['TERM'] = 'screen-256color'; return out; } // v1.10.8c: no `-d` (multi-attach friendly — boolab pattern). With per-pane // tmux sessions, dropping `-d` means multiple browser tabs viewing the same // pane share one tmux session as N clients; tmux fans I/O at the session // layer just like boolab's backend. The earlier `-d` flag detached EVERY // other client of the session — across windows — which caused the // "[detached] from session" bug whenever a new pane attached to a chat // session that already had another pane open. // // Tmux server + session persist across PTY exits, so a refresh resumes with // full scrollback. Explicit destroy happens via the /kill route (called from // the frontend when the user closes a pane). export function attachPty(opts: AttachPtyOptions): IPty { return pty.spawn( 'tmux', [ '-f', opts.tmuxConfPath, 'attach-session', '-t', opts.sessionName, ], { name: 'xterm-256color', cols: opts.cols, rows: opts.rows, cwd: opts.projectRoot, env: cleanEnv(), }, ); }