2026-01-26 12:02:37 +09:00
|
|
|
import { spawn } from "bun"
|
|
|
|
|
import type { WindowState, TmuxPaneInfo } from "./types"
|
2026-02-08 13:57:26 +09:00
|
|
|
import { getTmuxPath } from "../../tools/interactive-bash/tmux-path-resolver"
|
2026-01-26 12:02:37 +09:00
|
|
|
import { log } from "../../shared"
|
|
|
|
|
|
|
|
|
|
export async function queryWindowState(sourcePaneId: string): Promise<WindowState | null> {
|
|
|
|
|
const tmux = await getTmuxPath()
|
|
|
|
|
if (!tmux) return null
|
|
|
|
|
|
|
|
|
|
const proc = spawn(
|
|
|
|
|
[
|
|
|
|
|
tmux,
|
|
|
|
|
"list-panes",
|
|
|
|
|
"-t",
|
|
|
|
|
sourcePaneId,
|
|
|
|
|
"-F",
|
2026-01-26 15:11:16 +09:00
|
|
|
"#{pane_id},#{pane_width},#{pane_height},#{pane_left},#{pane_top},#{pane_title},#{pane_active},#{window_width},#{window_height}",
|
2026-01-26 12:02:37 +09:00
|
|
|
],
|
|
|
|
|
{ stdout: "pipe", stderr: "pipe" }
|
|
|
|
|
)
|
|
|
|
|
|
|
|
|
|
const exitCode = await proc.exited
|
|
|
|
|
const stdout = await new Response(proc.stdout).text()
|
|
|
|
|
|
|
|
|
|
if (exitCode !== 0) {
|
|
|
|
|
log("[pane-state-querier] list-panes failed", { exitCode })
|
|
|
|
|
return null
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
const lines = stdout.trim().split("\n").filter(Boolean)
|
|
|
|
|
if (lines.length === 0) return null
|
|
|
|
|
|
|
|
|
|
let windowWidth = 0
|
2026-01-26 15:11:16 +09:00
|
|
|
let windowHeight = 0
|
2026-01-26 12:02:37 +09:00
|
|
|
const panes: TmuxPaneInfo[] = []
|
|
|
|
|
|
|
|
|
|
for (const line of lines) {
|
2026-01-26 15:11:16 +09:00
|
|
|
const [paneId, widthStr, heightStr, leftStr, topStr, title, activeStr, windowWidthStr, windowHeightStr] = line.split(",")
|
2026-01-26 12:02:37 +09:00
|
|
|
const width = parseInt(widthStr, 10)
|
2026-01-26 15:11:16 +09:00
|
|
|
const height = parseInt(heightStr, 10)
|
2026-01-26 12:02:37 +09:00
|
|
|
const left = parseInt(leftStr, 10)
|
2026-01-26 15:11:16 +09:00
|
|
|
const top = parseInt(topStr, 10)
|
2026-01-26 12:02:37 +09:00
|
|
|
const isActive = activeStr === "1"
|
|
|
|
|
windowWidth = parseInt(windowWidthStr, 10)
|
2026-01-26 15:11:16 +09:00
|
|
|
windowHeight = parseInt(windowHeightStr, 10)
|
2026-01-26 12:02:37 +09:00
|
|
|
|
2026-01-26 15:11:16 +09:00
|
|
|
if (!isNaN(width) && !isNaN(left) && !isNaN(height) && !isNaN(top)) {
|
|
|
|
|
panes.push({ paneId, width, height, left, top, title, isActive })
|
2026-01-26 12:02:37 +09:00
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
2026-01-26 15:11:16 +09:00
|
|
|
panes.sort((a, b) => a.left - b.left || a.top - b.top)
|
2026-01-26 12:02:37 +09:00
|
|
|
|
2026-01-26 15:11:16 +09:00
|
|
|
const mainPane = panes.find((p) => p.paneId === sourcePaneId)
|
|
|
|
|
if (!mainPane) {
|
|
|
|
|
log("[pane-state-querier] CRITICAL: sourcePaneId not found in panes", {
|
|
|
|
|
sourcePaneId,
|
|
|
|
|
availablePanes: panes.map((p) => p.paneId),
|
|
|
|
|
})
|
|
|
|
|
return null
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
const agentPanes = panes.filter((p) => p.paneId !== mainPane.paneId)
|
2026-01-26 12:02:37 +09:00
|
|
|
|
|
|
|
|
log("[pane-state-querier] window state", {
|
|
|
|
|
windowWidth,
|
2026-01-26 15:11:16 +09:00
|
|
|
windowHeight,
|
|
|
|
|
mainPane: mainPane.paneId,
|
2026-01-26 12:02:37 +09:00
|
|
|
agentPaneCount: agentPanes.length,
|
|
|
|
|
})
|
|
|
|
|
|
2026-01-26 15:11:16 +09:00
|
|
|
return { windowWidth, windowHeight, mainPane, agentPanes }
|
2026-01-26 12:02:37 +09:00
|
|
|
}
|