fix(team-mode): preserve tmux focus during layout
Ultraworked with [Sisyphus](https://github.com/code-yeongyu/oh-my-openagent) Co-authored-by: Sisyphus <clio-agent@sisyphuslabs.ai>
This commit is contained in:
@@ -197,6 +197,21 @@ describe("team-layout-tmux", () => {
|
|||||||
expect(titleSetters).toContain("m2")
|
expect(titleSetters).toContain("m2")
|
||||||
})
|
})
|
||||||
|
|
||||||
|
test("#given caller inside tmux #when createTeamLayout runs #then it restores keyboard focus and avoids border status mutation", async () => {
|
||||||
|
// given
|
||||||
|
const { createTeamLayout } = await loadLayoutModule()
|
||||||
|
const members = [{ name: "m1", sessionId: "s-m1", worktreePath: "/tmp/m1" }]
|
||||||
|
|
||||||
|
// when
|
||||||
|
await createTeamLayout("run-options", members, tmuxMgr as never)
|
||||||
|
|
||||||
|
// then
|
||||||
|
const commands = getCommands()
|
||||||
|
const focusRestores = commands.filter((args) => args[0] === "select-pane" && args[1] === "-t" && args[2] === "%42")
|
||||||
|
expect(focusRestores.length).toBe(1)
|
||||||
|
expect(commands.some((args) => args[0] === "set-option" && args.includes("pane-border-status"))).toBe(false)
|
||||||
|
})
|
||||||
|
|
||||||
test("#given ownedSession=false, focusWindowId=@10, gridWindowId=@11 #when removeTeamLayout runs #then tmux kill-window is called twice with -t @10 and -t @11 and kill-session is NEVER called", async () => {
|
test("#given ownedSession=false, focusWindowId=@10, gridWindowId=@11 #when removeTeamLayout runs #then tmux kill-window is called twice with -t @10 and -t @11 and kill-session is NEVER called", async () => {
|
||||||
// given
|
// given
|
||||||
const { removeTeamLayout } = await loadLayoutModule()
|
const { removeTeamLayout } = await loadLayoutModule()
|
||||||
|
|||||||
@@ -38,12 +38,13 @@ const PANE_SHELL_INIT_DELAY_MS = 200
|
|||||||
|
|
||||||
let paneCreationLock: Promise<void> = Promise.resolve()
|
let paneCreationLock: Promise<void> = Promise.resolve()
|
||||||
|
|
||||||
function acquirePaneCreationLock(): Promise<() => void> {
|
async function acquirePaneCreationLock(): Promise<() => void> {
|
||||||
let release: () => void
|
let release: () => void
|
||||||
const newLock = new Promise<void>((resolve) => { release = resolve })
|
const newLock = new Promise<void>((resolve) => { release = resolve })
|
||||||
const previousLock = paneCreationLock
|
const previousLock = paneCreationLock
|
||||||
paneCreationLock = newLock
|
paneCreationLock = newLock
|
||||||
return previousLock.then(() => release!)
|
await previousLock
|
||||||
|
return release!
|
||||||
}
|
}
|
||||||
|
|
||||||
async function resolveCurrentWindowTarget(tmuxPath: string, leaderPaneId: string): Promise<string | null> {
|
async function resolveCurrentWindowTarget(tmuxPath: string, leaderPaneId: string): Promise<string | null> {
|
||||||
@@ -105,6 +106,7 @@ async function createTeammatePaneInCurrentWindow(
|
|||||||
const paneId = splitResult.output.trim()
|
const paneId = splitResult.output.trim()
|
||||||
|
|
||||||
await runTmuxCommand(tmuxPath, ["select-pane", "-t", paneId, "-T", member.name])
|
await runTmuxCommand(tmuxPath, ["select-pane", "-t", paneId, "-T", member.name])
|
||||||
|
await runTmuxCommand(tmuxPath, ["select-pane", "-t", leaderPaneId])
|
||||||
await runTmuxCommand(tmuxPath, ["set-option", "-p", "-t", paneId, "pane-border-style", "fg=cyan"])
|
await runTmuxCommand(tmuxPath, ["set-option", "-p", "-t", paneId, "pane-border-style", "fg=cyan"])
|
||||||
await runTmuxCommand(tmuxPath, ["set-option", "-p", "-t", paneId, "pane-active-border-style", "fg=cyan"])
|
await runTmuxCommand(tmuxPath, ["set-option", "-p", "-t", paneId, "pane-active-border-style", "fg=cyan"])
|
||||||
await runTmuxCommand(tmuxPath, ["set-option", "-p", "-t", paneId, "pane-border-format", "#[fg=cyan,bold] #{pane_title} #[default]"])
|
await runTmuxCommand(tmuxPath, ["set-option", "-p", "-t", paneId, "pane-border-format", "#[fg=cyan,bold] #{pane_title} #[default]"])
|
||||||
@@ -159,8 +161,6 @@ export async function createTeamLayout(teamRunId: string, members: Array<TeamLay
|
|||||||
const windowId = await resolveCurrentWindowId(tmuxPath, leaderPaneId)
|
const windowId = await resolveCurrentWindowId(tmuxPath, leaderPaneId)
|
||||||
if (!windowTarget || !windowId) return null
|
if (!windowTarget || !windowId) return null
|
||||||
|
|
||||||
await runTmuxCommand(tmuxPath, ["set-option", "-w", "-t", windowTarget, "pane-border-status", "top"])
|
|
||||||
|
|
||||||
const panesByMember: Record<string, string> = {}
|
const panesByMember: Record<string, string> = {}
|
||||||
|
|
||||||
for (const member of members) {
|
for (const member of members) {
|
||||||
|
|||||||
Reference in New Issue
Block a user