Files
oh-my-opencode/src/features/tmux-subagent/pane-state-querier.ts
T

83 lines
2.8 KiB
TypeScript
Raw Normal View History

import type { WindowState, TmuxPaneInfo } from "./types"
2026-03-11 17:55:53 +09:00
import { parsePaneStateOutput } from "./pane-state-parser"
import { getTmuxPath } from "../../tools/interactive-bash/tmux-path-resolver"
import { log } from "../../shared"
2026-05-07 17:47:53 +09:00
import type { TmuxCommandResult } from "../../shared/tmux"
2026-05-07 17:47:53 +09:00
type QueryWindowStateDeps = {
getTmuxPath: typeof getTmuxPath
runTmuxCommand: (tmuxPath: string, args: string[]) => Promise<TmuxCommandResult>
log: typeof log
}
export async function queryWindowStateWithDeps(sourcePaneId: string, deps: QueryWindowStateDeps): Promise<WindowState | null> {
const tmux = await deps.getTmuxPath()
if (!tmux) return null
2026-05-07 17:47:53 +09:00
const result = await deps.runTmuxCommand(tmux, [
"list-panes",
"-t",
sourcePaneId,
"-F",
"#{pane_id}\t#{pane_width}\t#{pane_height}\t#{pane_left}\t#{pane_top}\t#{pane_active}\t#{window_width}\t#{window_height}\t#{window_active}\t#{session_attached}\t#{pane_title}",
])
if (result.exitCode !== 0) {
2026-05-07 17:47:53 +09:00
deps.log("[pane-state-querier] list-panes failed", { exitCode: result.exitCode })
return null
}
const parsedPaneState = parsePaneStateOutput(result.output)
if (!parsedPaneState) {
2026-05-07 17:47:53 +09:00
deps.log("[pane-state-querier] failed to parse pane state output", {
sourcePaneId,
})
return null
}
2026-03-11 17:55:53 +09:00
const { panes } = parsedPaneState
const windowWidth = parsedPaneState.windowWidth
const windowHeight = parsedPaneState.windowHeight
const windowActive = parsedPaneState.windowActive
const sessionAttached = parsedPaneState.sessionAttached
panes.sort((a, b) => a.left - b.left || a.top - b.top)
const mainPane = panes.reduce<TmuxPaneInfo | null>((selected, pane) => {
if (!selected) return pane
if (pane.left !== selected.left) {
return pane.left < selected.left ? pane : selected
}
if (pane.width !== selected.width) {
return pane.width > selected.width ? pane : selected
}
if (pane.top !== selected.top) {
return pane.top < selected.top ? pane : selected
}
return pane.paneId === sourcePaneId ? pane : selected
}, null)
if (!mainPane) {
2026-05-07 17:47:53 +09:00
deps.log("[pane-state-querier] CRITICAL: failed to determine main pane", {
sourcePaneId,
availablePanes: panes.map((p) => p.paneId),
})
return null
}
const agentPanes = panes.filter((p) => p.paneId !== mainPane.paneId)
2026-05-07 17:47:53 +09:00
deps.log("[pane-state-querier] window state", {
windowWidth,
windowHeight,
mainPane: mainPane.paneId,
agentPaneCount: agentPanes.length,
})
return { windowWidth, windowHeight, windowActive, sessionAttached, mainPane, agentPanes }
}
2026-05-07 17:47:53 +09:00
export async function queryWindowState(sourcePaneId: string): Promise<WindowState | null> {
const { runTmuxCommand } = await import("../../shared/tmux")
return queryWindowStateWithDeps(sourcePaneId, { getTmuxPath, runTmuxCommand, log })
}