fix(review round 2): daemon symlink tars, orphan-safe removes, unique seed names, git ctx, IsErrNotFound, collision-free slugs, branch validation; web first-run WS, draft reset, IME guard, churn fix, test swap repair; 106 daemon + 190 web tests green

This commit is contained in:
Raphael Westphal
2026-08-18 19:13:51 +02:00
parent 95d2b5da4b
commit 66c90e48bb
22 changed files with 1476 additions and 964 deletions
+29 -11
View File
@@ -69,10 +69,28 @@ function listEvent(seq: number): EventFrame {
describe("useSessions", () => {
it("returns null when unconfigured", () => {
const push = vi.fn();
const { result } = renderHook(() => useSessions(push));
const { result } = renderHook(() => useSessions(push, true));
expect(result.current).toBeNull();
});
it("first-run: inactive -> active starts the ws manager (A)", async () => {
seedSettings();
mockFetchJson(() => []);
const push = vi.fn();
const { result, rerender } = renderHook(
({ active }: { active: boolean }) => useSessions(push, active),
{ initialProps: { active: false } },
);
// gate is up: settings exist but the hook must not dial yet
expect(FakeWebSocket.instances.length).toBe(0);
expect(result.current).not.toBeNull();
// gate saved: active flips true, the effect re-runs and starts the manager
rerender({ active: true });
await waitFor(() => expect(FakeWebSocket.instances.length).toBe(1));
expect(result.current?.state).toBe("connecting");
});
it("seeds via REST, updates from session_list and spawn_status frames, refresh works", async () => {
seedSettings();
const sessions: SessionListItem[] = [
@@ -88,7 +106,7 @@ describe("useSessions", () => {
return [];
});
const push = vi.fn();
const { result } = renderHook(() => useSessions(push));
const { result } = renderHook(() => useSessions(push, true));
expect(result.current?.state).toBe("connecting");
await waitFor(() => expect(result.current?.sessions).toEqual(sessions));
@@ -131,7 +149,7 @@ describe("useSessions", () => {
throw new Error("network down");
});
const push = vi.fn();
const { result } = renderHook(() => useSessions(push));
const { result } = renderHook(() => useSessions(push, true));
await waitFor(() =>
expect(push).toHaveBeenCalledWith("sessions: network down"),
);
@@ -147,7 +165,7 @@ describe("useSessions", () => {
seedSettings();
mockFetchJson(() => []);
const push = vi.fn();
const { result } = renderHook(() => useSessions(push));
const { result } = renderHook(() => useSessions(push, true));
const sock = FakeWebSocket.last();
act(() => sock.serverOpen());
@@ -198,7 +216,7 @@ describe("useSessions", () => {
mockFetchJson(() => []);
const loc = stubReload();
const push = vi.fn();
const { result } = renderHook(() => useSessions(push));
const { result } = renderHook(() => useSessions(push, true));
const sock = FakeWebSocket.last();
act(() => sock.serverOpen());
act(() => sock.serverClose(1008));
@@ -219,7 +237,7 @@ describe("useSessions", () => {
);
const loc = stubReload();
const push = vi.fn();
renderHook(() => useSessions(push));
renderHook(() => useSessions(push, true));
const failConnect = (): void => {
act(() => FakeWebSocket.last().serverClose(1006));
};
@@ -254,7 +272,7 @@ describe("useSessions", () => {
});
const loc = stubReload();
const push = vi.fn();
renderHook(() => useSessions(push));
renderHook(() => useSessions(push, true));
const failConnect = (): void => {
act(() => FakeWebSocket.last().serverClose(1006));
};
@@ -293,7 +311,7 @@ describe("useSessions", () => {
});
const loc = stubReload();
const push = vi.fn();
renderHook(() => useSessions(push));
renderHook(() => useSessions(push, true));
const failConnect = (): void => {
act(() => FakeWebSocket.last().serverClose(1006));
};
@@ -336,7 +354,7 @@ describe("useSessions", () => {
seedSettings();
mockFetchJson(() => []);
const push = vi.fn();
const { unmount } = renderHook(() => useSessions(push));
const { unmount } = renderHook(() => useSessions(push, true));
await waitFor(() => expect(FakeWebSocket.instances.length).toBe(1));
const sock = FakeWebSocket.last();
unmount();
@@ -350,7 +368,7 @@ describe("useSessions", () => {
const stable: SessionListItem[] = [];
mockFetchJson(() => stable);
const push = vi.fn();
const { result, rerender } = renderHook(() => useSessions(push));
const { result, rerender } = renderHook(() => useSessions(push, true));
await waitFor(() => expect(FakeWebSocket.instances.length).toBe(1));
// let the mount-time seed settle
for (let i = 0; i < 4; i += 1) {
@@ -370,7 +388,7 @@ describe("useSessions", () => {
let list: SessionListItem[] = [];
mockFetchJson(() => list);
const push = vi.fn();
const { result } = renderHook(() => useSessions(push));
const { result } = renderHook(() => useSessions(push, true));
await waitFor(() => expect(result.current).not.toBeNull());
const first = result.current;
const sock = FakeWebSocket.last();