feat(tmux): add a per-host mouse toggle and preserve remote configuration (#1513)

This commit is contained in:
ZacharyZcR authored and GitHub committed 2026-09-30 09:53:17 -05:00
1 parent 99cffc9ba6
commit 9801cc7fc7
10 files changed
+183 -44

No files matched your search

@@ -65,6 +65,27 @@ describe("createTmuxSessionsService", () => {
expect(writes[0]).toContain("main");
});
it("uses the host's saved mouse setting when attaching", async () => {
const { ctx } = createFakeContext({ pluginId: "tmux-monitor" });
await ctx.settings.setHost(7, "mouseEnabled", false);
const writes: string[] = [];
const service = createTmuxSessionsService(ctx);
await service.attachOrCreate(
{ write: (value: string) => writes.push(value) },
"main",
undefined,
7,
);
await service.attachOrCreate(
{ write: (value: string) => writes.push(value) },
"other",
undefined,
8,
);
expect(writes[0]).toContain("mouse off");
expect(writes[1]).toContain("mouse on");
});
it("waitForSession() falls back to the requested name on timeout", async () => {
vi.useFakeTimers();
try {
@@ -1,8 +1,12 @@
import { EventEmitter } from "node:events";
import { execFileSync } from "node:child_process";
import type { Client } from "ssh2";
import { mkdtempSync, writeFileSync, rmSync } from "node:fs";
import { tmpdir } from "node:os";
import { join } from "node:path";
import type { Client, ClientChannel } from "ssh2";
import { describe, expect, it } from "vitest";
import {
attachOrCreateTmuxSession,
detectTmux,
tmuxCommand,
withTmuxPath,
@@ -76,3 +80,81 @@ describe("tmux command path handling", () => {
]);
});
});
describe("session-scoped tmux mouse", () => {
it.skipIf(process.platform === "win32")(
"passes an exact session target and literal separator through both shells",
() => {
const dir = mkdtempSync(join(tmpdir(), "termix-tmux-"));
try {
writeFileSync(join(dir, "tmux"), '#!/bin/sh\nprintf "%s\\n" "$@"\n', {
mode: 0o755,
});
let command = "";
const stream = {
write: (value: string) => {
command = value;
},
};
const name = "qa's $(echo injected)";
attachOrCreateTmuxSession(
stream as unknown as ClientChannel,
name,
undefined,
false,
);
expect(command.endsWith("\r")).toBe(true);
const args = execFileSync("/bin/sh", ["-c", command.trim()], {
encoding: "utf8",
env: { ...process.env, PATH: `${dir}:/usr/bin:/bin` },
})
.trim()
.split("\n");
expect(args).toEqual([
"-u",
"set-option",
"-q",
"-t",
`=${name}`,
"mouse",
"off",
";",
"set-option",
"-q",
"-t",
`=${name}`,
"history-limit",
"50000",
";",
"attach-session",
"-t",
`=${name}`,
]);
} finally {
rmSync(dir, { recursive: true, force: true });
}
},
);
it("creates the named session before configuring and attaching it", () => {
let command = "";
attachOrCreateTmuxSession(
{
write: (value: string) => {
command = value;
},
} as unknown as ClientChannel,
undefined,
"work",
);
expect(command.indexOf("new-session")).toBeLessThan(
command.indexOf("set-option"),
);
expect(command.indexOf("set-option")).toBeLessThan(
command.indexOf("attach-session"),
);
expect(command).toContain("mouse on");
expect(command).toContain("history-limit 50000");
expect(command).not.toMatch(/set -g|set-hook|bind-key|set-clipboard/);
});
});
@@ -92,11 +92,17 @@ describe("host editor section", () => {
protocols: { ssh: true },
});
fireEvent.click(screen.getByRole("button"));
fireEvent.click(screen.getAllByRole("button")[0]);
const settings = (form.pluginSettings as Record<string, unknown>)[
"tmux-monitor"
] as { enableTmuxMonitor: boolean };
expect(settings.enableTmuxMonitor).toBe(true);
fireEvent.click(screen.getAllByRole("button")[1]);
expect(
(form.pluginSettings as Record<string, Record<string, unknown>>)[
"tmux-monitor"
],
).toEqual({ enableTmuxMonitor: true, mouseEnabled: false });
});
});