diff --git a/src/workspaces/officerdev/src/hooks/useChat.ts b/src/workspaces/officerdev/src/hooks/useChat.ts index 631343b7..ee9d8f88 100644 --- a/src/workspaces/officerdev/src/hooks/useChat.ts +++ b/src/workspaces/officerdev/src/hooks/useChat.ts @@ -1,5 +1,6 @@ import { useState, useEffect, useRef, useCallback } from 'react'; import { useQueryClient } from '@tanstack/react-query'; +import { useNavigate } from 'react-router'; import { useChatWebSocket } from 'hooks/useChatWebSocket'; import { useClient } from 'hooks/useClient'; import { useSettings } from 'state/useSettings'; @@ -44,11 +45,23 @@ type UsePiChatOptions = { * contradict it — which is what a hand-edited or stale `?cwd=` used to do. Anything else in the query * string is left alone. */ -function writePermalink(claudeSessionId: string): void { +/** + * The permalink, as a ROUTER navigation rather than a raw history write. + * + * It was `window.history.replaceState`, which changes the address bar and tells react-router nothing. Every + * consumer that reads the URL through the router therefore never saw it: on the /chat screen the title and + * the rename control both come from `useParams().sessionId` (see `ChatDetailPanel`), so a new conversation + * stayed "New chat" and could not be renamed until something else forced the router to re-read the + * location — which is exactly what navigating away and back did. + * + * `replace`, not push, so the browser Back button still leaves the conversation rather than stepping through + * the same one under a different name. + */ +function permalinkTo(claudeSessionId: string): { pathname: string; search: string } { const params = new URLSearchParams(window.location.search); params.delete('cwd'); const search = params.toString(); - window.history.replaceState(null, '', `/chat/${claudeSessionId}${search ? `?${search}` : ''}`); + return { pathname: `/chat/${claudeSessionId}`, search: search ? `?${search}` : '' }; } export function useChat(initialSessionId?: string, initialModel?: string | null, options?: UsePiChatOptions) { @@ -202,6 +215,21 @@ export function useChat(initialSessionId?: string, initialModel?: string | null, const client = useClient(); const queryClient = useQueryClient(); + const navigate = useNavigate(); + + /* + Written through the router so `useParams` updates. A raw `history.replaceState` moves the address bar and + leaves react-router believing the location is unchanged — see `permalinkTo`. + + In a ref because the message handler is re-created per render and closes over whatever it had; a stable + callback keeps the socket's copy valid. + */ + const writePermalink = useCallback( + (claudeSessionId: string) => { + navigate(permalinkTo(claudeSessionId), { replace: true }); + }, + [navigate], + ); /* Tell the session LISTS that this conversation exists.