diff --git a/CLAUDE.md b/CLAUDE.md index 280a6fab..ac1f3e90 100644 --- a/CLAUDE.md +++ b/CLAUDE.md @@ -35,7 +35,7 @@ When user says "COM": 1. Increment version in BOTH `package.json` AND `CLAUDE.md` (verify they match with `grep version package.json && grep Version CLAUDE.md`) 2. Run: `git add -A && git commit -m "chore: bump version to X.XXXX" && git push && npm run build && systemctl --user restart claudeman-web` -**Version**: 0.1557 (must match `package.json` for npm publish) +**Version**: 0.1558 (must match `package.json` for npm publish) ## Project Overview @@ -63,9 +63,9 @@ npx tsx src/index.ts web --https # With TLS (only needed for remote access) npm run typecheck # Type check tsc --noEmit --watch # Continuous type checking -# Testing -npx vitest run # All tests -npx vitest run test/.test.ts # Single file +# Testing (NEVER run full suite from inside Claudeman — kills tmux sessions) +# npx vitest run # ALL tests — DANGEROUS inside Claudeman +npx vitest run test/.test.ts # Single file (SAFE) npx vitest run -t "pattern" # Tests matching name npm run test:coverage # With coverage report diff --git a/package.json b/package.json index e05b294c..cf3960cd 100644 --- a/package.json +++ b/package.json @@ -1,6 +1,6 @@ { "name": "claudeman", - "version": "0.1557", + "version": "0.1558", "description": "The missing control plane for Claude Code - run 20 autonomous agents with real-time monitoring and session persistence", "type": "module", "main": "dist/index.js", diff --git a/src/mux-interface.ts b/src/mux-interface.ts index 19f7e7d2..9b206638 100644 --- a/src/mux-interface.ts +++ b/src/mux-interface.ts @@ -155,4 +155,7 @@ export interface TerminalMultiplexer extends EventEmitter { /** Check if the multiplexer binary is available on the system */ isAvailable(): boolean; + + /** Check if a multiplexer session actually exists (process-level check, not just tracked) */ + muxSessionExists(muxName: string): boolean; } diff --git a/src/session.ts b/src/session.ts index ef0616cb..9cd28065 100644 --- a/src/session.ts +++ b/src/session.ts @@ -849,6 +849,12 @@ export class Session extends EventEmitter { // If mux wrapping is enabled, create or attach to a mux session if (this._useMux && this._mux) { try { + // Verify stale mux session — tmux destroys session when command exits + // (remain-on-exit is off), but _muxSession reference persists + if (this._muxSession && !this._mux.muxSessionExists(this._muxSession.muxName)) { + console.log('[Session] Stale mux session detected (tmux gone):', this._muxSession.muxName); + this._muxSession = null; + } // Check if we already have a mux session (restored session) const isRestoredSession = this._muxSession !== null; if (isRestoredSession) { @@ -1128,6 +1134,11 @@ export class Session extends EventEmitter { // If mux wrapping is enabled, create or attach to a mux session if (this._useMux && this._mux) { try { + // Verify stale mux session — tmux destroys session when command exits + if (this._muxSession && !this._mux.muxSessionExists(this._muxSession.muxName)) { + console.log('[Session] Stale mux session detected (tmux gone):', this._muxSession.muxName); + this._muxSession = null; + } // Check if we already have a mux session (restored session) const isRestoredSession = this._muxSession !== null; if (isRestoredSession) { diff --git a/src/tmux-manager.ts b/src/tmux-manager.ts index a79502c9..92ebf4bc 100644 --- a/src/tmux-manager.ts +++ b/src/tmux-manager.ts @@ -348,6 +348,10 @@ export class TmuxManager extends EventEmitter implements TerminalMultiplexer { /** * Check if a tmux session exists. */ + muxSessionExists(muxName: string): boolean { + return this.sessionExists(muxName); + } + private sessionExists(muxName: string): boolean { if (IS_TEST_MODE) return false;