feat(tmux-subagent): add replace action to prevent mass eviction

- Add column-based splittable calculation (getColumnCount, getColumnWidth)
- New decision tree: splittable → split, k=1 eviction → close+spawn, else → replace
- Add 'replace' action type using tmux respawn-pane (preserves layout)
- Replace oldest pane in-place instead of closing all panes when unsplittable
- Prevents scenario where all agent panes get closed leaving only 1
This commit is contained in:
justsisyphus
2026-01-26 15:25:05 +09:00
parent 8ebc933118
commit 04f2b513c6
7 changed files with 188 additions and 66 deletions
+16 -2
View File
@@ -1,6 +1,6 @@
import type { TmuxConfig } from "../../config/schema"
import type { PaneAction, WindowState } from "./types"
import { spawnTmuxPane, closeTmuxPane, enforceMainPaneWidth } from "../../shared/tmux"
import { spawnTmuxPane, closeTmuxPane, enforceMainPaneWidth, replaceTmuxPane } from "../../shared/tmux"
import { log } from "../../shared"
export interface ActionResult {
@@ -38,6 +38,20 @@ export async function executeAction(
return { success }
}
if (action.type === "replace") {
const result = await replaceTmuxPane(
action.paneId,
action.newSessionId,
action.description,
ctx.config,
ctx.serverUrl
)
return {
success: result.success,
paneId: result.paneId,
}
}
const result = await spawnTmuxPane(
action.sessionId,
action.description,
@@ -74,7 +88,7 @@ export async function executeActions(
return { success: false, results }
}
if (action.type === "spawn" && result.paneId) {
if ((action.type === "spawn" || action.type === "replace") && result.paneId) {
spawnedPaneId = result.paneId
}
}