From 00ba61028fb0f1d99cf4c315d06b938e0a4c9c01 Mon Sep 17 00:00:00 2001 From: Peter Steinberger Date: Sat, 24 Jan 2026 00:58:19 +0000 Subject: [PATCH] fix: keep Control UI sidebar sticky; relax tailscale test bin path (#1515) (thanks @pookNast) --- CHANGELOG.md | 1 + src/infra/tailscale.test.ts | 22 +++++++++++----------- 2 files changed, 12 insertions(+), 11 deletions(-) diff --git a/CHANGELOG.md b/CHANGELOG.md index e9fd51907..24fe898c5 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -13,6 +13,7 @@ Docs: https://docs.clawd.bot ### Fixes - Voice wake: auto-save wake words on blur/submit across iOS/Android and align limits with macOS. +- UI: keep the Control UI sidebar visible while scrolling long pages. (#1515) Thanks @pookNast. - Tailscale: retry serve/funnel with sudo only for permission errors and keep original failure details. (#1551) Thanks @sweepies. - Discord: limit autoThread mention bypass to bot-owned threads; keep ack reactions mention-gated. (#1511) Thanks @pvoo. - Gateway: accept null optional fields in exec approval requests. (#1511) Thanks @pvoo. diff --git a/src/infra/tailscale.test.ts b/src/infra/tailscale.test.ts index 410c7befd..0dd3487e5 100644 --- a/src/infra/tailscale.test.ts +++ b/src/infra/tailscale.test.ts @@ -65,7 +65,7 @@ describe("tailscale helpers", () => { it("enableTailscaleServe attempts normal first, then sudo", async () => { // 1. First attempt fails // 2. Second attempt (sudo) succeeds - vi.spyOn(tailscale, "getTailscaleBinary").mockResolvedValue("tailscale"); + const tailscaleBin = expect.stringMatching(/tailscale$/); const exec = vi .fn() .mockRejectedValueOnce(new Error("permission denied")) @@ -75,7 +75,7 @@ describe("tailscale helpers", () => { expect(exec).toHaveBeenNthCalledWith( 1, - "tailscale", + tailscaleBin, expect.arrayContaining(["serve", "--bg", "--yes", "3000"]), expect.any(Object), ); @@ -83,27 +83,27 @@ describe("tailscale helpers", () => { expect(exec).toHaveBeenNthCalledWith( 2, "sudo", - expect.arrayContaining(["-n", "tailscale", "serve", "--bg", "--yes", "3000"]), + expect.arrayContaining(["-n", tailscaleBin, "serve", "--bg", "--yes", "3000"]), expect.any(Object), ); }); it("enableTailscaleServe does NOT use sudo if first attempt succeeds", async () => { - vi.spyOn(tailscale, "getTailscaleBinary").mockResolvedValue("tailscale"); + const tailscaleBin = expect.stringMatching(/tailscale$/); const exec = vi.fn().mockResolvedValue({ stdout: "" }); await enableTailscaleServe(3000, exec as never); expect(exec).toHaveBeenCalledTimes(1); expect(exec).toHaveBeenCalledWith( - "tailscale", + tailscaleBin, expect.arrayContaining(["serve", "--bg", "--yes", "3000"]), expect.any(Object), ); }); it("disableTailscaleServe uses fallback", async () => { - vi.spyOn(tailscale, "getTailscaleBinary").mockResolvedValue("tailscale"); + const tailscaleBin = expect.stringMatching(/tailscale$/); const exec = vi .fn() .mockRejectedValueOnce(new Error("permission denied")) @@ -115,7 +115,7 @@ describe("tailscale helpers", () => { expect(exec).toHaveBeenNthCalledWith( 2, "sudo", - expect.arrayContaining(["-n", "tailscale", "serve", "reset"]), + expect.arrayContaining(["-n", tailscaleBin, "serve", "reset"]), expect.any(Object), ); }); @@ -125,7 +125,7 @@ describe("tailscale helpers", () => { // 1. status (success) // 2. enable (fails) // 3. enable sudo (success) - vi.spyOn(tailscale, "getTailscaleBinary").mockResolvedValue("tailscale"); + const tailscaleBin = expect.stringMatching(/tailscale$/); const exec = vi .fn() .mockResolvedValueOnce({ stdout: JSON.stringify({ BackendState: "Running" }) }) // status @@ -144,14 +144,14 @@ describe("tailscale helpers", () => { // 1. status expect(exec).toHaveBeenNthCalledWith( 1, - "tailscale", + tailscaleBin, expect.arrayContaining(["funnel", "status", "--json"]), ); // 2. enable normal expect(exec).toHaveBeenNthCalledWith( 2, - "tailscale", + tailscaleBin, expect.arrayContaining(["funnel", "--yes", "--bg", "8080"]), expect.any(Object), ); @@ -160,7 +160,7 @@ describe("tailscale helpers", () => { expect(exec).toHaveBeenNthCalledWith( 3, "sudo", - expect.arrayContaining(["-n", "tailscale", "funnel", "--yes", "--bg", "8080"]), + expect.arrayContaining(["-n", tailscaleBin, "funnel", "--yes", "--bg", "8080"]), expect.any(Object), ); });