refresh the commander grid when its first turn ends

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 <noreply@anthropic.com>
This commit is contained in:
2026-08-22 23:44:09 +00:00
co-authored by Claude Opus 5
parent 4f590f8879
commit 038251f9c9
@@ -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