import { useEffect, useState } from 'react' import type { ReactElement } from 'react' import type { PropsLocale, PropsRuntime } from '@deepseek-ai/dsh-client-ui-slots' import { IconChevronLeftOutlineRegular, IconInfoOutlineRegular, IconPanelLeftOutlineRegular } from '@deepseek-ai/dsh-client-ui-primitives' import type { SessionId, UseJobs } from './compat/types.ts' import { NS } from './locales.ts' import { GO_HOME_EVENT, SESSION_INFO_EVENT } from './nav-store.ts' import { BETTER_TOGGLE, readSidebarTarget, toggleSidebarTarget } from './sidebar-panels.ts' import type { SidebarTarget } from './sidebar-panels.ts' /* * The ⓘ button used to render a hand-built info glyph because the * primitives family had no info-circle icon (grepped 2026-08-17: 71 * icons). DSH 0.1.7 ships IconInfoOutlineRegular, so the hand-built twin * is retired in favour of the official one — same 16x16 box the rest of * the header icon family uses. */ /** * Two hand-built 14px glyphs: the primitives family still has no subagent * or background-task icon (re-checked against the 0.1.7-rc.2 exports). * Drawn on the same 16-box with the same stroke so the activity chip * reads as part of the header icon family. */ /** Three linked nodes — a parent delegating to children. */ function IconSubagentGlyph({ size = 14 }: { size?: number }) { return ( ) } /** A clock face — work still ticking in the background. */ function IconTaskGlyph({ size = 14 }: { size?: number }) { return ( ) } /** * What the status dot says. `running` pulses blue, `done` is a steady green, * `warning` covers a job that ended on request or failed — showing that as * "done" green would call a failure a success. */ type ActivityState = 'running' | 'done' | 'warning' /** * The official triggers our pills stand in for. Both are hidden and parked as * invisible anchors at the right end of the view-switch band * (styles/header.css.ts) so their popovers still mount and position from * there; the pill is the visible control and forwards the tap. * * Told apart by `aria-haspopup`: the subagent entry declares `tree` (its menu * is a session tree), the jobs entry declares none. * * Scoped to the HEADER, not to a slot (2026-08-21). DSH 0.1.1 moved the * subagent entry out of `conversation.session.header.actions` into a new * `conversation.session.header.lineage` slot inside the breadcrumb; every * slot-scoped lookup here silently stopped matching and the pill fell back to * opening the info card. The header is the stable boundary — which slot * inside it owns the entry is the suite's business, and it has changed once. * * Also deliberately NOT keyed on the root's class. In 0.1.1 that attribute is * `"ZKlsPq_root "` — with a TRAILING SPACE — so `[class$="_root"]` does not * match it at all (`[class$=]` tests the whole attribute string). The * trigger's own class has no such tail, so anchor on the trigger and reach * the root through `:has()` instead of naming it. */ const HEADER = '[data-phase] header' const SUBAGENT_TRIGGER = `${HEADER} button[aria-haspopup="tree"]` const JOBS_TRIGGER = `${HEADER} button[class$="_trigger"]:not([aria-haspopup])` /** One glanceable group: icon + count + state dot; opens the official popover. */ function ActivityPill( { kind, count, state, label, trigger, onFallback, Icon }: { kind: string count: number state: ActivityState label: string /** CSS selector for the official trigger this pill stands in for. */ trigger: string /** Used when the official entry is absent — never leave a tap dead. */ onFallback: () => void Icon: (props: { size?: number }) => ReactElement }, ) { if (count === 0) return null return (