From 038251f9c98d09066ec0dcdc53a88a4d1ccde97f Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Andr=C3=A9=20Padez?= Date: Sat, 22 Aug 2026 23:44:09 +0000 Subject: [PATCH] refresh the commander grid when its first turn ends MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit The name is written server-side into the transcript's summary record on the first `result` — it cannot land earlier, because the transcript does not exist until then. Nothing told the client, so the list kept the title it fetched beforehand. For a self-started commander that title is the opening brief, so the pill read "I have given you a name and a working directory…" next to a header showing the real name from local state. Two names for one commander, both correct about different moments. The falling edge of `isGenerating` rather than a poll or a shorter staleTime: it is the one moment the server is known to have written something the list is displaying. Co-Authored-By: Claude Opus 5 --- .../src/apps/CommandHQ/CommandHqDetail.tsx | 23 ++++++++++++++++++- 1 file changed, 22 insertions(+), 1 deletion(-) diff --git a/src/workspaces/officerdev/src/apps/CommandHQ/CommandHqDetail.tsx b/src/workspaces/officerdev/src/apps/CommandHQ/CommandHqDetail.tsx index aa768bed..3979a951 100644 --- a/src/workspaces/officerdev/src/apps/CommandHQ/CommandHqDetail.tsx +++ b/src/workspaces/officerdev/src/apps/CommandHQ/CommandHqDetail.tsx @@ -1,4 +1,5 @@ -import { useEffect, useState } from 'react'; +import { useEffect, useRef, useState } from 'react'; +import { useQueryClient } from '@tanstack/react-query'; import { useNavigate, useParams, useSearchParams } from 'react-router'; import { Check, FolderOpen, Radar, Trash2, Unplug, X } from 'lucide-react'; import { Button } from '@/components/ui/button'; @@ -226,6 +227,26 @@ function NewCommander({ // updates nothing and says nothing. Same root cause as the navigate below. const { setCategory } = useCommandHqCommanderActions(chat.claudeSessionId ?? ''); const [filed, setFiled] = useState(false); + /* + Refresh the grid when the first turn ends. + + The commander's NAME is written server-side, into the transcript's summary record, on the first + `result` — the rename can only land once the transcript exists. Nothing tells the client that + happened, so the list kept whatever title it had fetched before, which for a self-started commander + is the opening brief: the pill read "I have given you a name and a working directory…" while the + header beside it read the real name from local state. + + The falling edge of `isGenerating` is the signal, rather than a poll or a shorter `staleTime`: it is + the one moment the server is known to have written something the list is showing. + */ + const wasGenerating = useRef(false); + const qc = useQueryClient(); + useEffect(() => { + if (wasGenerating.current && !chat.isGenerating) { + qc.invalidateQueries({ queryKey: ['command-hq', 'commanders'] }); + } + wasGenerating.current = chat.isGenerating; + }, [chat.isGenerating, qc]); useEffect(() => { // `claudeSessionId`, NOT `sessionId`. The commander is filed under Claude's transcript id