mirror of
https://github.com/Ark0N/Codeman.git
synced 2026-09-30 12:39:42 +02:00
fix: detect stale tmux sessions on startInteractive/startShell
When Claude exits inside a tmux session, tmux destroys the session (remain-on-exit is off), but the _muxSession reference persists. On restart, startInteractive() treats it as a "restored session" and tries to attach to the dead tmux — causing instant exit code 1. Now checks tmux has-session before attaching. If the session is gone, clears the stale reference and creates a fresh tmux session. Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
This commit is contained in:
@@ -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`)
|
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`
|
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
|
## 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
|
npm run typecheck # Type check
|
||||||
tsc --noEmit --watch # Continuous type checking
|
tsc --noEmit --watch # Continuous type checking
|
||||||
|
|
||||||
# Testing
|
# Testing (NEVER run full suite from inside Claudeman — kills tmux sessions)
|
||||||
npx vitest run # All tests
|
# npx vitest run # ALL tests — DANGEROUS inside Claudeman
|
||||||
npx vitest run test/<file>.test.ts # Single file
|
npx vitest run test/<file>.test.ts # Single file (SAFE)
|
||||||
npx vitest run -t "pattern" # Tests matching name
|
npx vitest run -t "pattern" # Tests matching name
|
||||||
npm run test:coverage # With coverage report
|
npm run test:coverage # With coverage report
|
||||||
|
|
||||||
|
|||||||
+1
-1
@@ -1,6 +1,6 @@
|
|||||||
{
|
{
|
||||||
"name": "claudeman",
|
"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",
|
"description": "The missing control plane for Claude Code - run 20 autonomous agents with real-time monitoring and session persistence",
|
||||||
"type": "module",
|
"type": "module",
|
||||||
"main": "dist/index.js",
|
"main": "dist/index.js",
|
||||||
|
|||||||
@@ -155,4 +155,7 @@ export interface TerminalMultiplexer extends EventEmitter {
|
|||||||
|
|
||||||
/** Check if the multiplexer binary is available on the system */
|
/** Check if the multiplexer binary is available on the system */
|
||||||
isAvailable(): boolean;
|
isAvailable(): boolean;
|
||||||
|
|
||||||
|
/** Check if a multiplexer session actually exists (process-level check, not just tracked) */
|
||||||
|
muxSessionExists(muxName: string): boolean;
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -849,6 +849,12 @@ export class Session extends EventEmitter {
|
|||||||
// If mux wrapping is enabled, create or attach to a mux session
|
// If mux wrapping is enabled, create or attach to a mux session
|
||||||
if (this._useMux && this._mux) {
|
if (this._useMux && this._mux) {
|
||||||
try {
|
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)
|
// Check if we already have a mux session (restored session)
|
||||||
const isRestoredSession = this._muxSession !== null;
|
const isRestoredSession = this._muxSession !== null;
|
||||||
if (isRestoredSession) {
|
if (isRestoredSession) {
|
||||||
@@ -1128,6 +1134,11 @@ export class Session extends EventEmitter {
|
|||||||
// If mux wrapping is enabled, create or attach to a mux session
|
// If mux wrapping is enabled, create or attach to a mux session
|
||||||
if (this._useMux && this._mux) {
|
if (this._useMux && this._mux) {
|
||||||
try {
|
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)
|
// Check if we already have a mux session (restored session)
|
||||||
const isRestoredSession = this._muxSession !== null;
|
const isRestoredSession = this._muxSession !== null;
|
||||||
if (isRestoredSession) {
|
if (isRestoredSession) {
|
||||||
|
|||||||
@@ -348,6 +348,10 @@ export class TmuxManager extends EventEmitter implements TerminalMultiplexer {
|
|||||||
/**
|
/**
|
||||||
* Check if a tmux session exists.
|
* Check if a tmux session exists.
|
||||||
*/
|
*/
|
||||||
|
muxSessionExists(muxName: string): boolean {
|
||||||
|
return this.sessionExists(muxName);
|
||||||
|
}
|
||||||
|
|
||||||
private sessionExists(muxName: string): boolean {
|
private sessionExists(muxName: string): boolean {
|
||||||
if (IS_TEST_MODE) return false;
|
if (IS_TEST_MODE) return false;
|
||||||
|
|
||||||
|
|||||||
Reference in New Issue
Block a user