diff --git a/packages/core/src/__tests__/tmux.test.ts b/packages/core/src/__tests__/tmux.test.ts index bafb50b01..f81dc2dac 100644 --- a/packages/core/src/__tests__/tmux.test.ts +++ b/packages/core/src/__tests__/tmux.test.ts @@ -190,7 +190,7 @@ describe("sendKeys", () => { expect(escapeArgs).toEqual(["send-keys", "-t", "app-1", "Escape"]); // Call 1: text const textArgs = mockExecFile.mock.calls[1][1] as string[]; - expect(textArgs).toEqual(["send-keys", "-t", "app-1", "hello world"]); + expect(textArgs).toEqual(["send-keys", "-t", "app-1", "-l", "hello world"]); // Call 2: Enter const enterArgs = mockExecFile.mock.calls[2][1] as string[]; expect(enterArgs).toEqual(["send-keys", "-t", "app-1", "Enter"]); diff --git a/packages/core/src/lifecycle-manager.ts b/packages/core/src/lifecycle-manager.ts index e4b597b63..ef9f512b5 100644 --- a/packages/core/src/lifecycle-manager.ts +++ b/packages/core/src/lifecycle-manager.ts @@ -453,6 +453,21 @@ export function createLifecycleManager(deps: LifecycleManagerDeps): LifecycleMan // Poll all sessions concurrently await Promise.allSettled(sessionsToCheck.map((s) => checkSession(s))); + // Prune stale entries from states and reactionTrackers for sessions + // that no longer appear in the session list (e.g., after kill/cleanup) + const currentSessionIds = new Set(sessions.map((s) => s.id)); + for (const trackedId of states.keys()) { + if (!currentSessionIds.has(trackedId)) { + states.delete(trackedId); + } + } + for (const trackerKey of reactionTrackers.keys()) { + const sessionId = trackerKey.split(":")[0]; + if (sessionId && !currentSessionIds.has(sessionId)) { + reactionTrackers.delete(trackerKey); + } + } + // Check if all sessions are complete (emit only once) const activeSessions = sessions.filter((s) => s.status !== "merged" && s.status !== "killed"); if (sessions.length > 0 && activeSessions.length === 0 && !allCompleteEmitted) { diff --git a/packages/core/src/tmux.ts b/packages/core/src/tmux.ts index 6d2de1ae1..098a9e875 100644 --- a/packages/core/src/tmux.ts +++ b/packages/core/src/tmux.ts @@ -152,7 +152,9 @@ export async function sendKeys( } } } else { - await tmux("send-keys", "-t", sessionName, text); + // Use -l (literal) to prevent tmux from interpreting text as key names + // (e.g. "Enter", "Escape", "C-c" would be treated as keypresses without -l) + await tmux("send-keys", "-t", sessionName, "-l", text); } if (pressEnter) {