From d5618b0236192051ff27891af2204584d85dbf63 Mon Sep 17 00:00:00 2001 From: Thomas Ricouard Date: Thu, 19 Feb 2026 10:13:50 +0100 Subject: [PATCH] Use Codex thread names as single source of truth --- .../threads/hooks/useThreadStorage.test.tsx | 30 +------ .../threads/hooks/useThreadStorage.ts | 27 +------ .../hooks/useThreads.integration.test.tsx | 78 ++++++++++++------- src/features/threads/hooks/useThreads.ts | 8 +- 4 files changed, 56 insertions(+), 87 deletions(-) diff --git a/src/features/threads/hooks/useThreadStorage.test.tsx b/src/features/threads/hooks/useThreadStorage.test.tsx index 60deac8df..b37f11f26 100644 --- a/src/features/threads/hooks/useThreadStorage.test.tsx +++ b/src/features/threads/hooks/useThreadStorage.test.tsx @@ -2,9 +2,7 @@ import { act, renderHook, waitFor } from "@testing-library/react"; import { beforeEach, describe, expect, it, vi } from "vitest"; import { - STORAGE_KEY_CUSTOM_NAMES, STORAGE_KEY_PINNED_THREADS, - loadCustomNames, loadPinnedThreads, loadThreadActivity, savePinnedThreads, @@ -14,13 +12,9 @@ import { useThreadStorage } from "./useThreadStorage"; vi.mock("@threads/utils/threadStorage", () => ({ MAX_PINS_SOFT_LIMIT: 2, - STORAGE_KEY_CUSTOM_NAMES: "custom-names", STORAGE_KEY_PINNED_THREADS: "pinned-threads", - loadCustomNames: vi.fn(), loadPinnedThreads: vi.fn(), loadThreadActivity: vi.fn(), - makeCustomNameKey: (workspaceId: string, threadId: string) => - `${workspaceId}:${threadId}`, makePinKey: (workspaceId: string, threadId: string) => `${workspaceId}:${threadId}`, savePinnedThreads: vi.fn(), @@ -32,15 +26,11 @@ describe("useThreadStorage", () => { vi.clearAllMocks(); }); - it("loads initial data and updates custom names on storage events", async () => { + it("loads initial data and does not provide custom names", () => { vi.mocked(loadThreadActivity).mockReturnValue({ "ws-1": { "thread-1": 101 }, }); vi.mocked(loadPinnedThreads).mockReturnValue({ "ws-1:thread-1": 202 }); - vi - .mocked(loadCustomNames) - .mockReturnValueOnce({ "ws-1:thread-1": "Custom" }) - .mockReturnValueOnce({ "ws-1:thread-1": "Updated" }); const { result } = renderHook(() => useThreadStorage()); @@ -50,26 +40,12 @@ describe("useThreadStorage", () => { expect(result.current.pinnedThreadsRef.current).toEqual({ "ws-1:thread-1": 202, }); - - await waitFor(() => { - expect(result.current.getCustomName("ws-1", "thread-1")).toBe("Custom"); - }); - - act(() => { - window.dispatchEvent( - new StorageEvent("storage", { key: STORAGE_KEY_CUSTOM_NAMES }), - ); - }); - - await waitFor(() => { - expect(result.current.getCustomName("ws-1", "thread-1")).toBe("Updated"); - }); + expect(result.current.getCustomName("ws-1", "thread-1")).toBeUndefined(); }); it("records thread activity and persists updates", () => { vi.mocked(loadThreadActivity).mockReturnValue({}); vi.mocked(loadPinnedThreads).mockReturnValue({}); - vi.mocked(loadCustomNames).mockReturnValue({}); const { result } = renderHook(() => useThreadStorage()); @@ -88,7 +64,6 @@ describe("useThreadStorage", () => { it("pins and unpins threads while updating persistence", () => { vi.mocked(loadThreadActivity).mockReturnValue({}); vi.mocked(loadPinnedThreads).mockReturnValue({}); - vi.mocked(loadCustomNames).mockReturnValue({}); const { result } = renderHook(() => useThreadStorage()); @@ -117,7 +92,6 @@ describe("useThreadStorage", () => { it("ignores duplicate pins and reacts to pinned storage changes", async () => { vi.mocked(loadThreadActivity).mockReturnValue({}); vi.mocked(loadPinnedThreads).mockReturnValue({ "ws-1:thread-1": 123 }); - vi.mocked(loadCustomNames).mockReturnValue({}); const { result } = renderHook(() => useThreadStorage()); diff --git a/src/features/threads/hooks/useThreadStorage.ts b/src/features/threads/hooks/useThreadStorage.ts index 54812e236..cdf9ab6e7 100644 --- a/src/features/threads/hooks/useThreadStorage.ts +++ b/src/features/threads/hooks/useThreadStorage.ts @@ -2,22 +2,17 @@ import { useCallback, useEffect, useRef, useState } from "react"; import type { MutableRefObject } from "react"; import { MAX_PINS_SOFT_LIMIT, - STORAGE_KEY_CUSTOM_NAMES, STORAGE_KEY_PINNED_THREADS, - type CustomNamesMap, type PinnedThreadsMap, type ThreadActivityMap, - loadCustomNames, loadPinnedThreads, loadThreadActivity, - makeCustomNameKey, makePinKey, savePinnedThreads, saveThreadActivity, } from "@threads/utils/threadStorage"; type UseThreadStorageResult = { - customNamesRef: MutableRefObject; pinnedThreadsRef: MutableRefObject; threadActivityRef: MutableRefObject; pinnedThreadsVersion: number; @@ -37,26 +32,7 @@ export function useThreadStorage(): UseThreadStorageResult { const threadActivityRef = useRef(loadThreadActivity()); const pinnedThreadsRef = useRef(loadPinnedThreads()); const [pinnedThreadsVersion, setPinnedThreadsVersion] = useState(0); - const customNamesRef = useRef({}); - - useEffect(() => { - if (typeof window === "undefined") { - return undefined; - } - customNamesRef.current = loadCustomNames(); - const handleStorage = (event: StorageEvent) => { - if (event.key === STORAGE_KEY_CUSTOM_NAMES) { - customNamesRef.current = loadCustomNames(); - } - }; - window.addEventListener("storage", handleStorage); - return () => window.removeEventListener("storage", handleStorage); - }, []); - - const getCustomName = useCallback((workspaceId: string, threadId: string) => { - const key = makeCustomNameKey(workspaceId, threadId); - return customNamesRef.current[key]; - }, []); + const getCustomName = useCallback((_workspaceId: string, _threadId: string) => undefined, []); const recordThreadActivity = useCallback( (workspaceId: string, threadId: string, timestamp = Date.now()) => { @@ -138,7 +114,6 @@ export function useThreadStorage(): UseThreadStorageResult { ); return { - customNamesRef, pinnedThreadsRef, threadActivityRef, pinnedThreadsVersion, diff --git a/src/features/threads/hooks/useThreads.integration.test.tsx b/src/features/threads/hooks/useThreads.integration.test.tsx index 106bec643..c4a8ed768 100644 --- a/src/features/threads/hooks/useThreads.integration.test.tsx +++ b/src/features/threads/hooks/useThreads.integration.test.tsx @@ -1114,33 +1114,59 @@ describe("useThreads UX integration", () => { expect(localStorage.getItem(STORAGE_KEY_DETACHED_REVIEW_LINKS)).toBeNull(); }); - it("orders thread lists, applies custom names, and keeps pin ordering stable", async () => { + it("orders thread lists, reflects codex thread names, and keeps pin ordering stable", async () => { const listThreadsMock = vi.mocked(listThreads); - listThreadsMock.mockResolvedValue({ - result: { - data: [ - { - id: "thread-a", - preview: "Alpha", - updated_at: 1000, - cwd: workspace.path, - }, - { - id: "thread-b", - preview: "Beta", - updated_at: 3000, - cwd: workspace.path, - }, - { - id: "thread-c", - preview: "Gamma", - updated_at: 2000, - cwd: workspace.path, - }, - ], - nextCursor: null, - }, - }); + listThreadsMock + .mockResolvedValueOnce({ + result: { + data: [ + { + id: "thread-a", + preview: "Alpha", + updated_at: 1000, + cwd: workspace.path, + }, + { + id: "thread-b", + preview: "Beta", + updated_at: 3000, + cwd: workspace.path, + }, + { + id: "thread-c", + preview: "Gamma", + updated_at: 2000, + cwd: workspace.path, + }, + ], + nextCursor: null, + }, + }) + .mockResolvedValueOnce({ + result: { + data: [ + { + id: "thread-a", + preview: "Alpha", + updated_at: 1000, + cwd: workspace.path, + }, + { + id: "thread-b", + preview: "Custom Beta", + updated_at: 3000, + cwd: workspace.path, + }, + { + id: "thread-c", + preview: "Gamma", + updated_at: 2000, + cwd: workspace.path, + }, + ], + nextCursor: null, + }, + }); const { result } = renderHook(() => useThreads({ diff --git a/src/features/threads/hooks/useThreads.ts b/src/features/threads/hooks/useThreads.ts index bd09b3e4e..f9cf92efb 100644 --- a/src/features/threads/hooks/useThreads.ts +++ b/src/features/threads/hooks/useThreads.ts @@ -24,8 +24,6 @@ import { useThreadTitleAutogeneration } from "./useThreadTitleAutogeneration"; import { setThreadName as setThreadNameService } from "@services/tauri"; import { loadDetachedReviewLinks, - makeCustomNameKey, - saveCustomName, saveDetachedReviewLinks, } from "@threads/utils/threadStorage"; import { getParentThreadIdFromSource } from "@threads/utils/threadRpc"; @@ -103,7 +101,6 @@ export function useThreads({ useThreadApprovals({ dispatch, onDebug }); const { handleUserInputSubmit } = useThreadUserInput({ dispatch }); const { - customNamesRef, threadActivityRef, pinnedThreadsVersion, getCustomName, @@ -162,9 +159,6 @@ export function useThreads({ const renameThread = useCallback( (workspaceId: string, threadId: string, newName: string) => { - saveCustomName(workspaceId, threadId, newName); - const key = makeCustomNameKey(workspaceId, threadId); - customNamesRef.current[key] = newName; dispatch({ type: "setThreadName", workspaceId, threadId, name: newName }); void Promise.resolve( setThreadNameService(workspaceId, threadId, newName), @@ -178,7 +172,7 @@ export function useThreads({ }); }); }, - [customNamesRef, dispatch, onDebug], + [dispatch, onDebug], ); const onSubagentThreadDetected = useCallback(