the spawned list collapses

a commander firing once an hour has spawned a hundred children by the
weekend, and every id was rendered as a chip in a wrapping grid above the
transcript. so the longer a commander worked, the more of the screen its
own history took from the conversation you came to read.

collapsed by default, one row: SPAWNED 12, plus how many are still running
and the cost caveat. click to see the ids. local state rather than the URL
— a disclosure is not a selection, nothing addresses it and it should not
survive navigating away.

`n running` is on the collapsed row deliberately. it is the difference
between "twelve happened" and "one is happening", which is the only part
worth interrupting the transcript for.

Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
Officer-Session: 656f5c85-e49a-4f1f-b9f3-042a04b4d043
This commit is contained in:
2026-08-24 17:19:24 +00:00
co-authored by Claude Opus 5
parent 7e50134200
commit 46ae8051d4
7 changed files with 44 additions and 4 deletions
@@ -1,7 +1,7 @@
import { useEffect, useRef, useState } from 'react';
import { useQueryClient } from '@tanstack/react-query';
import { Link, useNavigate, useParams, useSearchParams } from 'react-router';
import { Check, FolderOpen, Radar, Trash2, Unplug, X } from 'lucide-react';
import { Check, ChevronRight, FolderOpen, Radar, Trash2, Unplug, X } from 'lucide-react';
import { Button } from '@/components/ui/button';
import { toast } from '@/components/ui/sonner';
import { EditableTitle } from '@/components/EditableTitle';
@@ -431,13 +431,35 @@ function NewCommander({
const SpawnedChildren = ({ sessionId }: { sessionId: string }) => {
const { t, tUi } = useTranslation();
const { children, totalUsd, unknownCost } = useCommandHqChildren(sessionId);
/*
Collapsed by default, and this is the whole point of the component being a disclosure at all.
A commander that fires once an hour has spawned a hundred children by the weekend, and the ids were
rendered as a wrapping grid of chips above the transcript — so the longer a commander worked, the more
of the screen its own history took from the conversation you came to read.
Local state rather than the URL: this is a disclosure, not a selection. Nothing addresses it, nobody
links to it, and it should not survive navigating away.
*/
const [open, setOpen] = useState(false);
if (!children.length) return null;
// Worth seeing without expanding — it is the difference between "twelve happened" and "one is happening".
const running = children.filter((c) => !c.finishedAt).length;
return (
<div className="shrink-0 border-b border-border px-4 py-2">
<div className="flex items-baseline gap-2 text-xs text-muted-foreground">
<button
type="button"
onClick={() => setOpen((v) => !v)}
aria-expanded={open}
title={open ? t('commandHq.spawnedHide') : t('commandHq.spawnedShow')}
className="flex w-full items-baseline gap-2 text-left text-xs text-muted-foreground hover:text-foreground/80 cursor-pointer"
>
<ChevronRight className={`h-3 w-3 shrink-0 self-center transition-transform ${open ? 'rotate-90' : ''}`} />
<span className="font-medium uppercase tracking-wide">{t('commandHq.spawned')}</span>
<span>{children.length}</span>
{running > 0 && <span className="text-duck-orange">· {t('commandHq.spawnedRunning', { n: running })}</span>}
{/*
Cost is stated as a floor when any child's is unknown, never as a confident total. A commander's
line reading $0.28 for a night that spent several dollars is the specific understatement this
@@ -454,8 +476,8 @@ const SpawnedChildren = ({ sessionId }: { sessionId: string }) => {
· {unknownCost} unknown
</span>
)}
</div>
<div className="mt-1 flex flex-wrap gap-1.5">
</button>
<div className={`mt-1 flex flex-wrap gap-1.5 ${open ? '' : 'hidden'}`}>
{children.map((c) => (
<Link
key={c.spawnedSessionId}
@@ -221,6 +221,9 @@
"referencePathHint": "Worauf dieser Kommandant achtet oder woran er arbeitet — nicht, wo er lebt. Er kann später selbst weitere hinzufügen.",
"new": "Neuer Commander",
"spawned": "Gestartet",
"spawnedRunning": "{{n}} laufen",
"spawnedShow": "Erzeugte Sitzungen anzeigen",
"spawnedHide": "Ausblenden",
"deleteQ": "Löschen?",
"uncategorised": "Nicht kategorisiert",
"loading": "Wird geladen…",
@@ -221,6 +221,9 @@
"referencePathHint": "What this commander watches or works on — not where it lives. It can add more of these itself once it's running.",
"new": "New commander",
"spawned": "Spawned",
"spawnedRunning": "{{n}} running",
"spawnedShow": "Show the sessions it spawned",
"spawnedHide": "Hide them",
"deleteQ": "Delete?",
"uncategorised": "Uncategorised",
"loading": "Loading…",
@@ -221,6 +221,9 @@
"referencePathHint": "Lo que este comandante vigila o en lo que trabaja — no dónde vive. Puede añadir más por sí mismo una vez en marcha.",
"new": "Nuevo commander",
"spawned": "Iniciado",
"spawnedRunning": "{{n}} en curso",
"spawnedShow": "Mostrar las sesiones que ha creado",
"spawnedHide": "Ocultar",
"deleteQ": "¿Eliminar?",
"uncategorised": "Sin categoría",
"loading": "Cargando…",
@@ -221,6 +221,9 @@
"referencePathHint": "Ce que ce commandant surveille ou sur quoi il travaille — pas où il vit. Il peut en ajouter d'autres lui-même une fois en cours d'exécution.",
"new": "Nouveau commander",
"spawned": "Lancé",
"spawnedRunning": "{{n}} en cours",
"spawnedShow": "Afficher les sessions lancées",
"spawnedHide": "Masquer",
"deleteQ": "Supprimer ?",
"uncategorised": "Sans catégorie",
"loading": "Chargement…",
@@ -221,6 +221,9 @@
"referencePathHint": "Aquilo que este comandante vigia ou em que trabalha — não onde vive. Pode acrescentar mais por si próprio depois de estar em funcionamento.",
"new": "Novo comandante",
"spawned": "Iniciado",
"spawnedRunning": "{{n}} a correr",
"spawnedShow": "Mostrar as sessões que criou",
"spawnedHide": "Esconder",
"deleteQ": "Eliminar?",
"uncategorised": "Sem categoria",
"loading": "A carregar…",
@@ -221,6 +221,9 @@
"referencePathHint": "Vad denna commander bevakar eller arbetar med — inte var den bor. Den kan lägga till fler av dessa själv när den väl körs.",
"new": "Ny commander",
"spawned": "Startade",
"spawnedRunning": "{{n}} körs",
"spawnedShow": "Visa sessionerna den startat",
"spawnedHide": "Dölj dem",
"deleteQ": "Ta bort?",
"uncategorised": "Okategoriserad",
"loading": "Läser in…",