dsh-group-status 0.2.2 → 0.3.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/CHANGELOG.md +53 -0
- package/README.en.md +36 -18
- package/README.md +39 -19
- package/lib/client.js +659 -300
- package/lib/client.js.map +1 -1
- package/lib/index.js +22 -9
- package/lib/types/client/BadgeSettingsCard.d.ts +24 -0
- package/lib/types/client/BadgeSettingsCard.d.ts.map +1 -0
- package/lib/types/client/BadgeSettingsCard.js +73 -0
- package/lib/types/client/BadgeSettingsCard.js.map +1 -0
- package/lib/types/client/badge-field.d.ts +44 -0
- package/lib/types/client/badge-field.d.ts.map +1 -0
- package/lib/types/client/badge-field.js +77 -0
- package/lib/types/client/badge-field.js.map +1 -0
- package/lib/types/client/badge-labels.d.ts +92 -0
- package/lib/types/client/badge-labels.d.ts.map +1 -0
- package/lib/types/client/badge-labels.js +150 -0
- package/lib/types/client/badge-labels.js.map +1 -0
- package/lib/types/client/badge-settings.d.ts +31 -3
- package/lib/types/client/badge-settings.d.ts.map +1 -1
- package/lib/types/client/badge-settings.js +50 -6
- package/lib/types/client/badge-settings.js.map +1 -1
- package/lib/types/client/facet-store.d.ts +46 -0
- package/lib/types/client/facet-store.d.ts.map +1 -0
- package/lib/types/client/facet-store.js +123 -0
- package/lib/types/client/facet-store.js.map +1 -0
- package/lib/types/client/facet-visibility.d.ts +17 -0
- package/lib/types/client/facet-visibility.d.ts.map +1 -0
- package/lib/types/client/facet-visibility.js +18 -0
- package/lib/types/client/facet-visibility.js.map +1 -0
- package/lib/types/client/facets.d.ts +265 -0
- package/lib/types/client/facets.d.ts.map +1 -0
- package/lib/types/client/facets.js +209 -0
- package/lib/types/client/facets.js.map +1 -0
- package/lib/types/client/group-status.d.ts +97 -45
- package/lib/types/client/group-status.d.ts.map +1 -1
- package/lib/types/client/group-status.js +148 -85
- package/lib/types/client/group-status.js.map +1 -1
- package/lib/types/client/index.d.ts +25 -0
- package/lib/types/client/index.d.ts.map +1 -1
- package/lib/types/client/index.js +59 -1
- package/lib/types/client/index.js.map +1 -1
- package/lib/types/client/legacy/bridge.d.ts +30 -0
- package/lib/types/client/legacy/bridge.d.ts.map +1 -0
- package/lib/types/client/legacy/bridge.js +58 -0
- package/lib/types/client/legacy/bridge.js.map +1 -0
- package/lib/types/client/legacy/register-legacy-facets.d.ts +14 -0
- package/lib/types/client/legacy/register-legacy-facets.d.ts.map +1 -0
- package/lib/types/client/legacy/register-legacy-facets.js +77 -0
- package/lib/types/client/legacy/register-legacy-facets.js.map +1 -0
- package/lib/types/client/legacy/schedule.d.ts +49 -0
- package/lib/types/client/legacy/schedule.d.ts.map +1 -0
- package/lib/types/client/legacy/schedule.js +73 -0
- package/lib/types/client/legacy/schedule.js.map +1 -0
- package/lib/types/client/legacy/store-source.d.ts +78 -0
- package/lib/types/client/legacy/store-source.d.ts.map +1 -0
- package/lib/types/client/legacy/store-source.js +82 -0
- package/lib/types/client/legacy/store-source.js.map +1 -0
- package/lib/types/client/legacy/waiting-review.d.ts +85 -0
- package/lib/types/client/legacy/waiting-review.d.ts.map +1 -0
- package/lib/types/client/legacy/waiting-review.js +179 -0
- package/lib/types/client/legacy/waiting-review.js.map +1 -0
- package/lib/types/client/locales.d.ts +46 -4
- package/lib/types/client/locales.d.ts.map +1 -1
- package/lib/types/client/locales.js +46 -4
- package/lib/types/client/locales.js.map +1 -1
- package/lib/types/client/rows/GroupBadge.d.ts +19 -25
- package/lib/types/client/rows/GroupBadge.d.ts.map +1 -1
- package/lib/types/client/rows/GroupBadge.js +45 -106
- package/lib/types/client/rows/GroupBadge.js.map +1 -1
- package/lib/types/client/rows/Rows.d.ts +7 -3
- package/lib/types/client/rows/Rows.d.ts.map +1 -1
- package/lib/types/client/rows/Rows.js +6 -6
- package/lib/types/client/rows/Rows.js.map +1 -1
- package/lib/types/client/rows/WorkspaceBrowser.d.ts.map +1 -1
- package/lib/types/client/rows/WorkspaceBrowser.js +21 -21
- package/lib/types/client/rows/WorkspaceBrowser.js.map +1 -1
- package/lib/types/client/tree.d.ts +2 -5
- package/lib/types/client/tree.d.ts.map +1 -1
- package/lib/types/client/tree.js +0 -5
- package/lib/types/client/tree.js.map +1 -1
- package/lib/types/index.d.ts +31 -1
- package/lib/types/index.d.ts.map +1 -1
- package/lib/types/index.js +13 -1
- package/lib/types/index.js.map +1 -1
- package/package.json +1 -5
package/lib/client.js.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"client.js","names":["createSnapshotStore","useMemo","SettingsFormModel","useSyncExternalStore","useId","SettingsForm","css","Switch","assertNever","assertNever","defineStore","Service","createSnapshotStore","StateDot","IconClockOutlineRegular","IconListPenOutlineRegular","css","useRef","useMemo","relativeTime","css","StateDot","useState","IconEditOutlineRegular","IconTrashOutlineRegular","IconFolderOpenRegular","IconFolderCloseRegular","IconTriangleRightFillRegular","Menu","IconEllipsisOutlineRegular","Tooltip","IconNewChatOutlineRegular","HoverCard","IconPinFillRegular","IconArchiveOutlineRegular","IconUnarchiveOutlineRegular","Component","createRef","css","useCallback","useState","IconPlusOutlineRegular","IconFolderCloseRegular","Menu","css","Modal","Button","useState","Menu","IconFolderCloseRegular","IconWorkspaceTreeOutlineRegular","IconFlatListOutlineRegular","IconChevronsUpDownOutlineRegular","IconClockOutlineRegular","IconArchiveOffOutlineRegular","IconQueueOutlineRegular","IconArchiveCheckOutlineRegular","css","Tooltip","IconSlidersTwoOutlineRegular","IconArchiveOutlineRegular","useRef","useMemo","IconSearchOutlineRegular","IconCloseFillRegular","IconProjectAddOutlineRegular","Modal","Button","Toast","MenuItemButton","IconUnarchiveOutlineRegular","IconArchiveOutlineRegular","Tooltip","css","useState","Modal","Button","browserCss","MenuItemButton","IconBranchOutlineRegular","MenuItemButton","IconPinFillRegular","IconPinOutlineRegular","Tooltip","css","MenuItemButton","IconEditOutlineRegular","useState","useRef","Modal","Button","css","Toast","IconWarningOutlineRegular","assertNever","createSnapshotStore"],"sources":["../src/client/contract/slots.ts","../src/client/shortcuts.ts","../src/client/badge-settings.ts","../src/client/badge-field.ts","../src/client/BadgeSettingsCard.tsx","../node_modules/.pnpm/@deepseek-ai+dsh-util-values@0.2.0-rc.2_@deepseek-ai+cordis@4.0.4/node_modules/@deepseek-ai/dsh-util-values/lib/index.js","../node_modules/.pnpm/@deepseek-ai+dsh-util-workspace-path@0.2.0-rc.2_@deepseek-ai+cordis@4.0.4/node_modules/@deepseek-ai/dsh-util-workspace-path/lib/index.js","../src/client/tree.ts","../src/client/stores.ts","../src/client/pin-order.ts","../src/client/navigation.ts","../node_modules/.pnpm/clsx@2.1.1/node_modules/clsx/dist/clsx.mjs","../node_modules/.pnpm/@deepseek-ai+dsh-api-workspace-controller@0.2.0-rc.2_7b1cc3b3e03980f49f8901a2ede23841/node_modules/@deepseek-ai/dsh-api-workspace-controller/lib/types/default-workspace.js","../src/client/group-status.ts","../src/client/rows/GroupBadge.tsx","../src/client/rows/Rows.tsx","../src/client/rows/AnimatedRows.tsx","../src/client/WorkspacePicker.tsx","../src/client/rows/WorkspaceBrowser.tsx","../src/client/session-actions/ArchiveSession.tsx","../src/client/session-actions/derived.ts","../src/client/session-actions/ForkSession.tsx","../src/client/session-actions/PinSession.tsx","../src/client/session-actions/RenameSession.tsx","../src/client/session-actions/RowActionToast.tsx","../src/client/locales.ts","../src/client/index.ts"],"sourcesContent":["/**\n * ui-workspace contracts. Two registrations share this package:\n *\n * - WorkspaceBrowser fills the sidebar shell's `sidebar.workspaces` hole —\n * the whole browsing region (section header, search, grouped/flat session\n * list, workspace dialogs). It registers this package's viewing store and\n * consumes the shell's two-fact owner share (wide / expandSidebar).\n * - WorkspacePicker fills the conversation empty-state hole (menu + error\n * dialog shared with the browser).\n *\n * Both registrations declare a **directory-flow hole** (`single` kind): the\n * slot a composed picker package's client half fills with its\n * picking interaction — a renderless native-chooser driver or an in-app\n * browsing dialog. ui-workspace owns the trigger (the \"Add workspace…\"\n * entry, present only while the hole is occupied) and the adoption\n * semantics (`createWorkspace({ path })`, the retryable error dialog,\n * Choose again); the occupant owns everything between `open` and the picked path,\n * including creating a new directory to hand back. That occupant-owned\n * creation is why adding a workspace has a single route: an unoccupied hole\n * leaves the surface with no add affordance at all.\n * Two holes exist because the two menu surfaces are independent slot entries\n * and a hole has exactly one declaring entry — they carry the same owner\n * contract and the same occupant.\n *\n * WorkspaceBrowser also declares the two **Session row action lists**: every\n * row of a Session's \"...\" menu is an entry of\n * `sidebar.workspaces.session.menu.item`, and every hover button at the row's\n * end is an entry of `sidebar.workspaces.session.row.action`. The shipped\n * actions — pin, rename, fork, archive — are ordinary entries this package\n * registers from `apply`, each carrying its own behavior in its own inject\n * face and reading its own Host state through hooks that face injects, so a\n * client plugin's action lands beside them by `order` and needs nothing from\n * the browser beyond the row identity.\n *\n * The browser entry additionally declares two `list` seats per Session row\n * (`sidebar.session.row.leading` / `sidebar.session.row.hover`) for ambient\n * row decorations. Both take the row's Session identity and nothing else: a\n * session-scoped seat would force a Session binding, which would activate and\n * retain every listed Session.\n */\nimport type {\n HostObservable, InjectFace, PropsHooks, PropsLocale, PropsRenderSlots, PropsRuntime, PropsStore, SlotHookFactory,\n} from '@deepseek-ai/dsh-client-ui-slots'\n// Type-only: pull the owner SlotMap merges into programs that resolve the\n// runtime shares below.\nimport type {} from '@deepseek-ai/dsh-client-ui-sidebar/client'\nimport type {} from '@deepseek-ai/dsh-client-ui-conversation/client'\nimport type {} from '@deepseek-ai/dsh-client-ui-layout/client'\nimport type { SessionSearchResultItem } from '@deepseek-ai/dsh-api-session-controller/client'\nimport type { RemoteHostFacts } from '@deepseek-ai/dsh-api-remotes/client'\nimport type { SessionActivity, WorkspaceId, WorkspaceView } from '@deepseek-ai/dsh-api-workspace-controller/client'\nimport type { SessionId } from '@deepseek-ai/dsh-session/types'\nimport type { ShortcutCatalogEntry } from '@deepseek-ai/dsh-client-shortcuts/client'\nimport type { WorkspaceShortcutState } from '../shortcuts.ts'\nimport type { createWorkspaceViewStore } from '../stores.ts'\n\n/**\n * Owner share of the directory-flow holes: the complete conversation between\n * the trigger surface and the picking interaction. The occupant reads `open`\n * to run/render its interaction and reports exactly one outcome per open.\n */\nexport interface DirectoryFlowOwnerProps {\n /** True while a picking interaction is requested; flipping back to false withdraws the request. */\n open: boolean\n /** True while the owner adopts a picked path (`createWorkspace` in flight); occupants disable their commit affordances. */\n busy: boolean\n /** The operator picked a directory (absolute host path); the owner adopts it. */\n onPicked: (path: string) => void\n /** The operator dismissed the interaction; the owner just closes the flow. */\n onCancel: () => void\n /** The interaction itself failed (chooser missing, listing denied); the owner shows its error surface. */\n onError: (message: string) => void\n}\n\n/** Owner share of one Session row action occurrence: the row the action belongs to. */\nexport interface SessionRowOwnerProps {\n /** Session the row shows. */\n sessionId: SessionId\n /** Row display title: persisted title, or empty when the Session has none. */\n displayTitle: string\n}\n\n/** The row menu's open state as its owner holds it: the `useState` pair. */\nexport type MenuOpenState = readonly [open: boolean, setOpen: (open: boolean) => void]\n\n/**\n * Hook every row-menu entry receives. Rows only render while the menu is\n * open, so an entry reads it for the setter: `setOpen(false)` dismisses the\n * menu the entry sits in — the same state the owner's `onClose` sets.\n */\nexport type UseMenuOpenState = () => MenuOpenState\n\n/**\n * Bind the row's render occurrence into the entries' `useMenuOpenState` hook:\n * the owner supplies its open-state pair as the occurrence's `hookContext`,\n * and the hook hands that pair back.\n * @param _standard - framework standard props (unused).\n * @param state - the menu's open-state pair from the render occurrence.\n * @returns the hook the entry calls.\n */\nexport const menuOpenStateFactory: SlotHookFactory<'sidebar.workspaces.session.menu.item', UseMenuOpenState> =\n (_standard, state) => () => state\n\n/**\n * Owner share of the two Session-row schedule seats. Both receive only the\n * row's Session identity: the occupant reads that Session's own scheduled\n * tasks, and reading them activates nothing.\n */\nexport interface SessionRowScheduleOwnerProps {\n /** Session this row shows; the occupant addresses its own data by this id. */\n readonly sessionId: SessionId\n}\n\ndeclare module '@deepseek-ai/dsh-client-ui-slots' {\n interface SlotMap {\n /** Directory-flow hole under the conversation empty-state picker (declared by the WorkspacePicker entry). */\n 'conversation.hero.workspace.directoryFlow': { kind: 'single'; scope: 'root'; owner: DirectoryFlowOwnerProps }\n /** Directory-flow hole under the sidebar browsing region (declared by the WorkspaceBrowser entry). */\n 'sidebar.workspaces.directoryFlow': { kind: 'single'; scope: 'root'; owner: DirectoryFlowOwnerProps }\n /**\n * Leading decoration of one Session row, in the 16px cell before the title\n * that the row's own state dot otherwise occupies. A higher-priority state\n * (a pending interaction, a new message, live activity) replaces the seat\n * with that dot for the same row, so an occupant here never renders beside\n * a status dot and is mounted only by a row whose primary state is idle.\n * An archived row keeps that cell blank — neither its status dot nor this\n * seat renders there, and its live status appears on the hover card only.\n */\n 'sidebar.session.row.leading': { kind: 'list'; scope: 'root'; owner: SessionRowScheduleOwnerProps }\n /**\n * Section of the Session row's hover card between its relative time and\n * its trailing status line. Mounted only while that card is open.\n */\n 'sidebar.session.row.hover': { kind: 'list'; scope: 'root'; owner: SessionRowScheduleOwnerProps }\n /**\n * The rows of one Session's \"...\" menu, in ascending `order`. ui-workspace\n * registers the shipped rows here — `pin` (100), `rename` (200), `fork`\n * (300), `archive` (400) — so a plugin row is placed by its own `order`\n * among them. Use a package-namespaced `id`; reusing a shipped id at\n * another `priority` shadows that row. Each entry renders one\n * `role=\"menuitem\"` `<button>` (the shipped rows use ui-primitives'\n * `MenuItemButton`, which adds the host styling and `separatorBefore`),\n * decides its own visibility from its own state, and dismisses the menu\n * through the injected `useMenuOpenState` hook after acting; the list's\n * keyboard walk and focus return read the DOM, so any such button joins\n * them. Labels come from the contributing package's locale namespace.\n * @example\n * return {\n * inject: ['slots'],\n * apply(ctx) {\n * const copyLabel = 'Copy Session ID' // Localize in the contributing package.\n * ctx.slots.inject('sidebar.workspaces.session.menu.item', () => ctx.slots.register(\n * { name: 'sidebar.workspaces.session.menu.item', id: 'copy-session-id', order: 500 },\n * ({ sessionId, useMenuOpenState }) => {\n * const [, setMenuOpen] = useMenuOpenState()\n * return React.createElement(\n * 'button',\n * { type: 'button', role: 'menuitem', onClick: () => { setMenuOpen(false); void navigator.clipboard.writeText(sessionId) } },\n * copyLabel,\n * )\n * },\n * ))\n * },\n * }\n */\n 'sidebar.workspaces.session.menu.item': {\n kind: 'list'\n scope: 'root'\n owner: SessionRowOwnerProps\n hookContext: MenuOpenState\n inject: { hooks: {\n menuOpenState: SlotHookFactory<'sidebar.workspaces.session.menu.item', UseMenuOpenState>\n shortcuts: HostObservable<readonly ShortcutCatalogEntry[]>\n } }\n }\n /**\n * The hover buttons at the end of one Session row, in ascending `order`,\n * after the \"...\" menu trigger. ui-workspace registers `archive` (100) and\n * `pin` (200) here. An entry renders one icon button (or nothing, when its\n * action does not apply to the row) and owns the action it performs. Clicks\n * inside the strip stay in the strip, so the button needs no propagation\n * handling to keep the row from opening.\n */\n 'sidebar.workspaces.session.row.action': { kind: 'list'; scope: 'root'; owner: SessionRowOwnerProps }\n }\n}\n\n/** The two directory-flow holes; a flow package's client half registers its one component into both. */\nexport type DirectoryFlowSlotName =\n | 'conversation.hero.workspace.directoryFlow'\n | 'sidebar.workspaces.directoryFlow'\n\n/**\n * Directory-picking share both trigger surfaces consume. Occupancy rides the\n * inject face's reserved `hooks` compartment: the renderer binds the source\n * into the `useDirectoryFlow` selector hook, so an empty hole hides the\n * \"Add workspace…\" entry reactively and the surface withdraws an open\n * flow whose occupant unloaded mid-interaction (nobody is left to cancel).\n */\nexport type DirectoryPickingInjected = {\n hooks: {\n /** True while this surface's directory-flow hole is occupied. */\n directoryFlow: HostObservable<boolean>\n }\n}\n\n/** Component-side view of the picking share: the bound occupancy selector hook. */\nexport type DirectoryPickingHooks = PropsHooks<DirectoryPickingInjected['hooks']>\n\n/**\n * Browser-private injected share (arrives via the register inject factory).\n * Data reads use the global framework hooks; these are the Host actions the\n * browsing region drives.\n */\nexport type WorkspaceBrowserInjected = {\n hooks: DirectoryPickingInjected['hooks'] & {\n /**\n * Fixed Host facts, reached through a hook rather than injected as values:\n * the renderer memoizes an entry's inject result for the registration's\n * lifetime, so facts read there would freeze at whatever the first render\n * saw. Select the field the surface needs (`info => info.home`).\n */\n hostInfo: HostObservable<RemoteHostFacts>\n workspaceShortcuts: HostObservable<WorkspaceShortcutState>\n shortcuts: HostObservable<readonly ShortcutCatalogEntry[]>\n }\n /** Open the browser search and focus its input. */\n requestSearch: () => void\n /** Request the existing directory picker. */\n requestAddWorkspace: () => void\n /** Consume the directory-picker opening request. */\n closeAddWorkspace: () => void\n /** Publish directory interaction occupancy for command availability. */\n setDirectoryBusy: (busy: boolean) => void\n /** Dismiss the shortcut's fork-failure notification. */\n dismissForkError: () => void\n /**\n * Start a New Session in a Workspace: reuse-or-create its blank session and\n * open it; without an explicit workspace, inherit the current Session\n * Workspace, then the recent Workspace, or clear into the New Session view.\n */\n startSession: (workspaceId?: WorkspaceId) => void\n /** Open a real Session. */\n open: (sessionId: SessionId) => void\n /**\n * Search current visible conversation messages. The Host fixes the result\n * bound; `hasMore` means the query needs narrowing.\n */\n searchSessions: (\n query: string,\n signal: AbortSignal,\n ) => Promise<{ items: readonly SessionSearchResultItem[]; hasMore: boolean }>\n /** Maximum number of merged rows rendered for one search. */\n searchResultLimit: number\n /** Open the Session rename dialog (a row title double-click); the rename action entry raises the same request. */\n requestSessionRename: (sessionId: SessionId, currentTitle: string) => void\n /** Tell the user an archived row cannot be opened (a click on it). */\n notifyArchivedNotOpenable: () => void\n /** Rename a Host Workspace (rejects on name conflict; resolves on durability). */\n renameWorkspace: (workspaceId: WorkspaceId, title: string) => Promise<void>\n /** Delete only a Host Workspace registration; directory and Session logs remain. */\n deleteWorkspace: (workspaceId: WorkspaceId) => Promise<void>\n /**\n * Reorder a Workspace in the durable registry display order.\n * Omitted anchor appends to the end.\n */\n insertWorkspaceBefore: (workspaceId: WorkspaceId, beforeWorkspaceId?: WorkspaceId) => Promise<void>\n /** Remove a Session from the registry-global archived set (the search results' restore button). */\n unarchiveSession: (sessionId: SessionId) => Promise<void>\n /** Adopt a picked host directory as a real Workspace before targeting a Session. */\n createWorkspace: (input: { path: string }) => Promise<WorkspaceView>\n}\n\n/** The browser's declared viewing store handle, shared with the row actions that write view state. */\nexport type WorkspaceViewStoreHandle = ReturnType<typeof createWorkspaceViewStore>\n\n/** Props of one shipped row-menu entry: owner share + locale seat + the entry's own injected share. */\nexport type SessionMenuItemProps<Injected extends object = object> =\n PropsRuntime<'sidebar.workspaces.session.menu.item'>\n & PropsLocale<'workspace'>\n & InjectFace<Injected>\n\n/** Props of one shipped row hover button: owner share + locale seat + the entry's own injected share. */\nexport type SessionRowActionProps<Injected extends object = object> =\n PropsRuntime<'sidebar.workspaces.session.row.action'>\n & PropsLocale<'workspace'>\n & InjectFace<Injected>\n\n/** One transient Workspace notice rendered by the overlay toast entry. */\nexport type RowToast =\n | { kind: 'archived'; sessionId: SessionId }\n | { kind: 'stoppedAndArchived'; sessionId: SessionId }\n | { kind: 'pinFailed' }\n | { kind: 'unpinFailed' }\n | { kind: 'archivedNotOpenable' }\n | { kind: 'defaultWorkspaceFailed' }\n /**\n * An explicit New Session request that failed. `message` is untranslated:\n * a Host refusal as `code: message` — the stable code stays in the copy so\n * a report can be searched by it — and any other failure's own message.\n */\n | { kind: 'createFailed'; message: string }\n\n/** The notice on display; `seq` keys remounts so a repeated notice restarts its hold. */\nexport type RowToastState = RowToast & { seq: number }\n\n/**\n * Pin action share (menu row and hover button). The callbacks carry the whole\n * behavior: the Host call, fronting the Session in its saved orders after a\n * pin, and the failure notice. The hooks are the registry-global sets as\n * Sets, so a row reads its own membership with one lookup.\n */\nexport interface PinSessionInjected {\n hooks: {\n /** Pinned Session ids. */\n pinned: HostObservable<ReadonlySet<SessionId>>\n /** Archived Session ids (pin does not apply to an archived row). */\n archived: HostObservable<ReadonlySet<SessionId>>\n }\n /** Pin a Session; on success it leads its accounts' saved orders, on failure the notice says so. */\n pinSession: (sessionId: SessionId) => void\n /** Unpin a Session; saved positions stay as they are. */\n unpinSession: (sessionId: SessionId) => void\n}\n\n/**\n * Archive action share (menu row and hover button). The callbacks carry the\n * whole behavior: the Host call, the notice a success raises, the\n * stop-and-archive confirmation a Host refusal for running work raises, and\n * the diagnostics for any other rejection.\n */\nexport interface ArchiveSessionInjected {\n hooks: {\n /** Archived Session ids. */\n archived: HostObservable<ReadonlySet<SessionId>>\n }\n /**\n * Archive a Session into the registry-global set: the row keeps its\n * account position and shows per the archived filter; archiving the\n * current session clears the selection into the New Session view state.\n * A Session with running work is not archived by this call: the Host's\n * refusal opens the stop-and-archive confirmation instead.\n */\n archiveSession: (sessionId: SessionId) => void\n /** Remove a Session from the registry-global archived set. */\n unarchiveSession: (sessionId: SessionId) => void\n}\n\n/**\n * A stop-and-archive confirmation the archive action asked for: the Host\n * refused the plain archive because this work still runs.\n */\nexport interface SessionArchiveConfirmRequest {\n /** Session to stop and archive. */\n sessionId: SessionId\n /** The row's display title, named in the dialog. */\n displayTitle: string\n /** What the Host reported running, in family order. */\n activity: readonly SessionActivity[]\n}\n\n/**\n * Stop-and-archive dialog share: the pending confirmation, its settlement,\n * and the archive hop that asks the Host to stop the work first.\n */\nexport interface SessionArchiveConfirmInjected {\n hooks: {\n /** The confirmation asked for, until the dialog consumes or cancels it. */\n archiveRequest: HostObservable<SessionArchiveConfirmRequest | null>\n }\n /** Consume or cancel the pending confirmation. */\n settleSessionArchive: () => void\n /**\n * Archive a Session after the Host stops its running work; resolves once\n * the archive set is durable (the stops settle in the background) and\n * raises the stopped-and-archived notice.\n */\n stopAndArchiveSession: (sessionId: SessionId) => Promise<void>\n}\n\n/** Fork action share. */\nexport interface ForkSessionInjected {\n /** Fork a Session at its last completed turn; the child arrives through the Host list. */\n forkSession: (sessionId: SessionId) => void\n}\n\n/** Rename action share: the row only raises the request; the dialog entry answers it. */\nexport interface RenameSessionInjected {\n /** Ask for the rename dialog, seeded with the row's current title. */\n requestSessionRename: (sessionId: SessionId, currentTitle: string) => void\n}\n\n/** A Session rename the rename action asked for; the dialog entry opens on it. */\nexport interface SessionRenameTarget {\n /** Session to rename. */\n sessionId: SessionId\n /** Title the dialog seeds its draft from. */\n currentTitle: string\n}\n\n/** Rename dialog share: the pending request, its settlement, and the rename hop the dialog confirms with. */\nexport interface SessionRenameDialogInjected {\n hooks: {\n /** The rename asked for, until the dialog consumes or cancels it. */\n renameRequest: HostObservable<SessionRenameTarget | null>\n }\n /** Consume or cancel the pending request. */\n settleSessionRename: () => void\n /** Rename a Session (explicit user title; resolves on host acceptance). */\n renameSession: (sessionId: SessionId, title: string) => Promise<void>\n}\n\n/** Row toast share: the notice on display, its dismissal, and the two actions the archived notice offers. */\nexport interface RowToastInjected {\n hooks: {\n /** The notice on display, or none. */\n toast: HostObservable<RowToastState | null>\n }\n /** Take the notice down. */\n dismissToast: () => void\n /** Undo an archive from its notice. */\n undoArchive: (sessionId: SessionId) => void\n /** Switch the archived filter to \"show\" so the archived row is back in view. */\n showArchived: () => void\n}\n\n/** Props of the rename dialog entry in `shell.overlay`. */\nexport type SessionRenameDialogProps =\n PropsRuntime<'shell.overlay'>\n & PropsLocale<'workspace'>\n & Omit<SessionRenameDialogInjected, 'hooks'>\n & PropsHooks<SessionRenameDialogInjected['hooks']>\n\n/** Props of the stop-and-archive dialog entry in `shell.overlay`. */\nexport type SessionArchiveConfirmProps =\n PropsRuntime<'shell.overlay'>\n & PropsLocale<'workspace'>\n & Omit<SessionArchiveConfirmInjected, 'hooks'>\n & PropsHooks<SessionArchiveConfirmInjected['hooks']>\n\n/**\n * Props of the row toast entry in `shell.overlay`. The declared viewing store\n * carries the archived filter; the archived notice omits its filter action\n * when archived rows are already visible.\n */\nexport type RowToastProps =\n PropsRuntime<'shell.overlay'>\n & PropsLocale<'workspace'>\n & PropsStore<WorkspaceViewStoreHandle>\n & Omit<RowToastInjected, 'hooks'>\n & PropsHooks<RowToastInjected['hooks']>\n\n/** Full browser props: shell owner share + viewing store + injected actions + the locale seat. */\nexport type WorkspaceBrowserProps =\n PropsRuntime<'sidebar.workspaces'>\n & PropsRenderSlots<\n | 'sidebar.workspaces.directoryFlow'\n | 'sidebar.workspaces.session.menu.item'\n | 'sidebar.workspaces.session.row.action'\n | 'sidebar.session.row.leading'\n | 'sidebar.session.row.hover'\n >\n & PropsStore<WorkspaceViewStoreHandle>\n & Omit<WorkspaceBrowserInjected, 'hooks'>\n & PropsHooks<WorkspaceBrowserInjected['hooks']>\n & PropsLocale<'workspace'>\n\n/**\n * Picker-private injected share. Pick semantics remain in the owner's onPick\n * callback; this callback creates only the real Host Workspace. A type alias\n * supplies the implicit index signature required by the registry.\n */\nexport type WorkspacePickerInjected = DirectoryPickingInjected & {\n /** Adopt a picked host directory as a real Workspace before targeting a Session. */\n createWorkspace: (input: { path: string }) => Promise<WorkspaceView>\n}\n\n/**\n * Full picker props: the owner share plus the creation callback and the\n * locale seat. The two picker holes (blank-session hero / New-Session view)\n * share one owner currency, so one composed type serves both registrations.\n */\nexport type WorkspacePickerProps =\n PropsRuntime<'conversation.hero.workspace'>\n & PropsRenderSlots<'conversation.hero.workspace.directoryFlow'>\n & Omit<WorkspacePickerInjected, 'hooks'>\n & PropsHooks<WorkspacePickerInjected['hooks']>\n & PropsLocale<'workspace'>\n","/** Workspace command registration and browser-owned opening requests. */\nimport type { Context } from '@deepseek-ai/cordis'\nimport type { SessionForkError } from '@deepseek-ai/dsh-api-session-controller/client'\nimport { createSnapshotStore } from '@deepseek-ai/dsh-client-store'\nimport type { ShortcutCommand, ShortcutCommandId } from '@deepseek-ai/dsh-client-shortcuts/client'\nimport type { SnapshotStore } from '@deepseek-ai/dsh-client-store'\nimport type { SessionId } from '@deepseek-ai/dsh-session/types'\nimport type { UiWorkspace } from './navigation.ts'\n\n/** Transient requests consumed by the existing workspace browser. */\nexport interface WorkspaceShortcutState {\n readonly searchRequest: number\n readonly addRequested: boolean\n readonly directoryBusy: boolean\n readonly renameTarget: { readonly sessionId: SessionId; readonly currentTitle: string } | null\n readonly forkError: { readonly reason: 'unavailable' | 'failed'; readonly seq: number } | null\n}\n\ninterface WorkspaceShortcutControls {\n state: SnapshotStore<WorkspaceShortcutState>\n search: () => void\n add: () => void\n closeAdd: () => void\n directoryBusy: (busy: boolean) => void\n rename: (sessionId: SessionId, currentTitle: string) => void\n closeRename: () => void\n forkFailed: (reason: 'unavailable' | 'failed') => void\n dismissForkError: () => void\n}\n\n/**\n * Create the private browser request source shared by commands and controls.\n * @returns observable state and its complete mutation callbacks.\n */\nexport function createWorkspaceShortcutControls(): WorkspaceShortcutControls {\n const state = createSnapshotStore<WorkspaceShortcutState>({\n searchRequest: 0, addRequested: false, directoryBusy: false, renameTarget: null, forkError: null,\n })\n let forkErrorSeq = 0\n return {\n state,\n search: () => { state.set({ ...state.getSnapshot(), searchRequest: state.getSnapshot().searchRequest + 1 }) },\n add: () => { state.set(state.getSnapshot().directoryBusy ? state.getSnapshot() : { ...state.getSnapshot(), addRequested: true }) },\n closeAdd: () => { state.set({ ...state.getSnapshot(), addRequested: false }) },\n directoryBusy: (busy: boolean) => { state.set({ ...state.getSnapshot(), directoryBusy: busy }) },\n rename: (sessionId: SessionId, currentTitle: string) => {\n state.set({ ...state.getSnapshot(), renameTarget: { sessionId, currentTitle } })\n },\n closeRename: () => { state.set({ ...state.getSnapshot(), renameTarget: null }) },\n forkFailed: (reason) => {\n forkErrorSeq += 1\n state.set({ ...state.getSnapshot(), forkError: { reason, seq: forkErrorSeq } })\n },\n dismissForkError: () => { state.set({ ...state.getSnapshot(), forkError: null }) },\n }\n}\n\n/**\n * Register navigation commands against the existing workspace owner.\n * Rename requires a nonblank main Conversation with no modal obscuring it.\n * @param ctx - plugin context with the shortcut, locale, and model services.\n * @param navigation - session creation and forking from the pointer controls' navigation service.\n * @param controls - browser-owned opening requests.\n * @param archiveSession - shared archive action, including running-work confirmation and notices.\n */\nexport function installWorkspaceShortcuts(\n ctx: Context,\n navigation: Pick<UiWorkspace, 'startSession' | 'forkSession'>,\n controls: ReturnType<typeof createWorkspaceShortcutControls>,\n archiveSession: (sessionId: SessionId) => void,\n): void {\n const t = ctx.locale.bind('workspace')\n const current = () => Object.values(ctx.sessions.list.getSnapshot().byId)\n .find(row => (row.retainedBy.mainView ?? 0) > 0)\n const addReason = () => ctx.slots.entries('sidebar.workspaces.directoryFlow').length === 0\n ? t('shortcut.noPicker')\n : controls.state.getSnapshot().directoryBusy ? t('shortcut.directoryBusy') : null\n const register = (id: string, label: () => string, aliases: string[], code: string,\n modifiers: ('primary' | 'alt' | 'shift')[], webModifiers: ('primary' | 'alt' | 'shift')[], resolve: ShortcutCommand['resolve']): void => {\n ctx.effect(() => ctx.shortcuts.register({\n id: id as ShortcutCommandId, label, aliases, defaults: {\n 'desktop:macos': { code, modifiers }, 'desktop:windows': { code, modifiers }, 'desktop:linux': { code, modifiers },\n 'web:macos': { code, modifiers: webModifiers }, 'web:windows': { code, modifiers: webModifiers },\n },\n regions: ['page', 'editable'], modals: [], resolve,\n }), `ui-workspace: ${id}`)\n }\n register('session.new', () => t('session.new'), ['new session', 'new chat'], 'KeyN', ['primary'], ['primary', 'alt'],\n () => ({ status: 'handled', run: () => { navigation.startSession() } }))\n register('session.search', () => t('search.sessions.aria'), ['search sessions'], 'KeyK', ['primary'], ['primary', 'alt'],\n () => ({ status: 'handled', run: controls.search }))\n register('workspace.add', () => t('workspace.add'), ['add workspace', 'open folder'], 'KeyO', ['primary'], ['primary', 'alt'],\n () => {\n const reason = addReason()\n return reason === null ? { status: 'handled', run: controls.add } : { status: 'blocked', reason }\n })\n register('session.rename', () => t('rename.session.title'), ['rename session'], 'KeyG', ['primary', 'alt'], ['primary', 'alt'], (context) => {\n const target = current()\n return target === undefined || target.blank || context.modal !== null || ctx.layout.panelInfo.getSnapshot().activePanelId !== null\n ? { status: 'blocked', reason: t('shortcut.noSession') }\n : { status: 'handled', run: () => { controls.rename(target.id, target.title?.trim() ?? '') } }\n })\n register('session.fork', () => t('menu.fork'), ['fork session'], 'KeyF', ['primary', 'alt'], ['primary', 'shift'], () => {\n const target = current()\n if (target === undefined) return { status: 'blocked', reason: t('shortcut.noSession') }\n if (target.blank) return { status: 'blocked', reason: t('shortcut.noCompletedTurn') }\n return { status: 'handled', run: () => {\n void navigation.forkSession(target.id).catch((error: unknown) => {\n // Client plugin bundles do not share error-class identity.\n const unavailable = error instanceof Error && error.name === 'SessionForkError'\n && (error as SessionForkError).rpcError.code === 'session/fork-unavailable'\n controls.forkFailed(unavailable ? 'unavailable' : 'failed')\n if (!unavailable) console.warn('session fork rejected:', error)\n })\n } }\n })\n register('session.archive', () => t('menu.archiveSession'), ['archive session'], 'KeyA', ['primary', 'shift'], ['primary', 'alt'], () => {\n const target = current()\n return target === undefined ? { status: 'blocked', reason: t('shortcut.noSession') }\n : { status: 'handled', run: () => {\n archiveSession(target.id)\n } }\n })\n}\n","/**\n * 插件设置读取(折叠徽标显示偏好)。\n *\n * 数据流:apply 时先建一个**稳定**的标准 props 源并经 `provideRoot` 挂上(此时还不知道\n * 设置面在不在),再用 `ctx.inject(['configForms'], …)` 等宿主设置服务就绪——就绪后\n * 订阅本条目设置面,把快照推给源。设置页保存 → 宿主替换快照 → 源通知 → 徽标即时重渲染。\n *\n * 为什么不在 apply 里直接 `ctx.get('configForms')`:服务可能在**本插件之后**才注册,\n * 那时读到的 undefined 会永久生效(设置被静默忽略,直到刷新)。`ctx.inject` 是非阻塞的\n * 嵌套插件,服务永不到达也不会影响本插件其余功能。\n *\n * 为什么源必须一开始就存在:标准 props 的 hook 调用顺序必须稳定——挂上/摘掉\n * `useBadgeSettings` 会改变调用顺序而崩渲染。故源恒在,只有它的**值**随设置变化。\n *\n * 稳定性约定(React 外部存储,见 dsh-later 的同名 hook):`getSnapshot` 必须返回稳定\n * 引用——每次都构造新对象会让选择器的 `Object.is` 比较永不成立,触发\n * 「Maximum update depth exceeded」死循环(React #185),折叠行徽标会整块崩掉。\n *\n * 设置面缺席或未就绪时,回落到**默认全部显示**,与 `Config` 各字段的 schema 默认值同源:\n * 读不到配置不是「关掉」。\n */\n\n/** Loader 条目 id —— 设置页的寻址键,也是宿主 `describe()` 的 ns。 */\nexport const ENTRY_ID = 'dsh-group-status'\n\n/** 设置面快照的最小结构面(与宿主 `ConfigFormSnapshot` 兼容)。 */\nexport interface SettingsSnapshotLike {\n readonly status: string\n readonly value?: unknown\n}\n\n/** 设置面的最小结构面(与宿主 `ConfigForm` 兼容)。 */\nexport interface SettingsScopeLike {\n getSnapshot(): SettingsSnapshotLike\n subscribe(listener: () => void): () => void\n}\n\n/** 本插件在浏览器半关心的设置项。 */\nexport interface ResolvedBadgeSettings {\n /** 折叠徽标是否显示「已完成」绿点;缺失/非法一律回落 true。 */\n showCompletedInBadge: boolean\n /** 折叠徽标是否显示「进行中」转圈(含子智能体);缺失/非法一律回落 true。 */\n showRunningInBadge: boolean\n /** 折叠徽标是否显示「待审批」黄点(approval / plan-review / question);缺失/非法一律回落 true。 */\n showPendingInBadge: boolean\n /** 折叠徽标是否显示「定时任务」时钟图标(数据来自 dsh-later);缺失/非法一律回落 true。 */\n showScheduledInBadge: boolean\n /** 折叠徽标是否显示「等待评审」列表笔图标(数据来自 dsh-gitea-dispatch);缺失/非法一律回落 true。 */\n showWaitingReviewInBadge: boolean\n /** 悬停卡里是否显示聚合明细行;缺失/非法一律回落 true。 */\n showHoverDetails: boolean\n /** 徽标数字显示阈值:数量 >= 此值时才显示数字;缺失/非法一律回落 2(默认 count=1 时省略)。 */\n countThreshold: number\n}\n\n/** 标准 props 源的结构面(与 `HostObservable<ResolvedBadgeSettings>` 兼容)。 */\nexport interface BadgeSettingsSource {\n getSnapshot(): ResolvedBadgeSettings\n subscribe(listener: () => void): () => void\n}\n\n/** 始终存在的源:由 {@link createBadgeSettingsSource} 创建。 */\nexport interface MutableBadgeSettingsSource extends BadgeSettingsSource {\n /**\n * 采纳一条新快照(设置面就绪或宿主变更时推入)。\n *\n * 引用或取值都没变则**不通知**:宿主会为无关变更替换快照,无谓通知会让折叠行整列\n * 重渲染。\n * @param snapshot - 设置面快照;undefined 表示设置面缺失/收回。\n */\n publish(snapshot: SettingsSnapshotLike | undefined): void\n}\n\n/** 默认值:与 `Config` 各字段的 schema 默认同源(全部显示,数字阈值 2 即 count=1 时省略)。 */\nexport const DEFAULT_BADGE_SETTINGS: ResolvedBadgeSettings = Object.freeze({\n showCompletedInBadge: true,\n showRunningInBadge: true,\n showPendingInBadge: true,\n showScheduledInBadge: true,\n showWaitingReviewInBadge: true,\n showHoverDetails: true,\n countThreshold: 2,\n})\n\n/** 两个设置对象是否逐字段相等(用于发布前比较,避免无谓通知)。 */\nfunction settingsEqual(a: ResolvedBadgeSettings, b: ResolvedBadgeSettings): boolean {\n return (\n a.showCompletedInBadge === b.showCompletedInBadge &&\n a.showRunningInBadge === b.showRunningInBadge &&\n a.showPendingInBadge === b.showPendingInBadge &&\n a.showScheduledInBadge === b.showScheduledInBadge &&\n a.showWaitingReviewInBadge === b.showWaitingReviewInBadge &&\n a.showHoverDetails === b.showHoverDetails &&\n a.countThreshold === b.countThreshold\n )\n}\n\n/** 从原始快照派生:只有**显式 false** 才隐藏,缺失/非法一律显示(countThreshold 默认 2)。 */\nfunction resolveFromSnapshot(snap: SettingsSnapshotLike | undefined): ResolvedBadgeSettings {\n if (snap === undefined || snap.status !== 'ready') return DEFAULT_BADGE_SETTINGS\n const value = snap.value as Record<string, unknown> | undefined\n if (value === undefined || value === null || typeof value !== 'object') return DEFAULT_BADGE_SETTINGS\n const getBool = (field: string, def: boolean): boolean => {\n const v = value[field]\n return typeof v === 'boolean' ? v : def\n }\n const getNumber = (field: string, def: number): number => {\n const v = value[field]\n return typeof v === 'number' && Number.isFinite(v) && v >= 0 ? Math.floor(v) : def\n }\n return {\n showCompletedInBadge: getBool('showCompletedInBadge', true),\n showRunningInBadge: getBool('showRunningInBadge', true),\n showPendingInBadge: getBool('showPendingInBadge', true),\n showScheduledInBadge: getBool('showScheduledInBadge', true),\n showWaitingReviewInBadge: getBool('showWaitingReviewInBadge', true),\n showHoverDetails: getBool('showHoverDetails', true),\n countThreshold: getNumber('countThreshold', 2),\n }\n}\n\n/**\n * 建一个恒在、取值稳定的徽标设置源。\n *\n * `getSnapshot` 是**纯读**(无副作用、无订阅),因此可以安全地在渲染期间被反复调用,\n * 也满足外部存储的引用稳定要求;订阅只由 {@link MutableBadgeSettingsSource.publish}\n * 在取值真正变化时触发。\n * @returns 源;调用方持有它并在设置面就绪后 `publish`。\n */\nexport function createBadgeSettingsSource(): MutableBadgeSettingsSource {\n const listeners = new Set<() => void>()\n let resolved: ResolvedBadgeSettings = DEFAULT_BADGE_SETTINGS\n let seen: SettingsSnapshotLike | undefined\n let seenSet = false\n return {\n getSnapshot: () => resolved,\n subscribe: (listener) => {\n listeners.add(listener)\n return () => { listeners.delete(listener) }\n },\n publish: (snapshot) => {\n // 同一快照引用重复推入(含 undefined ↔ undefined)直接丢弃。\n if (seenSet && snapshot === seen) return\n seen = snapshot\n seenSet = true\n const next = resolveFromSnapshot(snapshot)\n // 取值没变就不替换引用、不通知:宿主为无关字段替换快照时不该惊动折叠行。\n if (settingsEqual(next, resolved)) return\n resolved = next\n for (const listener of [...listeners]) listener()\n },\n }\n}\n\n/** 旧口径的纯解析函数,保留给测试与 `publish` 复用。 */\nexport function resolveBadgeSettings(snapshot: SettingsSnapshotLike | undefined): ResolvedBadgeSettings {\n return resolveFromSnapshot(snapshot)\n}","/**\n * 折叠徽标设置项的字段定义(纯逻辑,不碰 React / 宿主组件)。\n *\n * 官方设置卡片的模型(`SettingsFormModel`)把每个字段都当**草稿文本**处理:控件读\n * `format(存储值)` 得到文本,用户编辑后 `parse(文本)` 决定这次保存写什么。布尔字段\n * 没有现成的官方 spec(官方只提供 `settingsTextField` / `settingsNumberField`),所以\n * 这里按同一契约写一份:文本就是 schema 的布尔字面量。\n *\n * 单独成文件是为了可测:`parse` 必须对非法草稿返回 `undefined`(模型据此把该字段标为\n * invalid 并挡住保存,而不是把畸形值写下去),`format` 必须把缺失值读成默认 `true`\n * ——与 `Config` 各字段的 schema 默认、`badge-settings.ts` 的解析同源。\n *\n * 类型从 primitives **type-only** 引入:编译期接住官方契约,运行时不留依赖,\n * 测试里也就不必把那个包(及其整棵依赖闭包)拉进来。\n */\nimport type { SettingsFieldSpec } from '@deepseek-ai/dsh-client-ui-primitives'\n\n/** 卡片字段名(与 `src/index.ts` 的 `Config` 同名同义)。 */\nexport const BADGE_FIELDS = {\n showCompletedInBadge: 'showCompletedInBadge',\n showRunningInBadge: 'showRunningInBadge',\n showPendingInBadge: 'showPendingInBadge',\n showScheduledInBadge: 'showScheduledInBadge',\n showWaitingReviewInBadge: 'showWaitingReviewInBadge',\n showHoverDetails: 'showHoverDetails',\n countThreshold: 'countThreshold',\n} as const\n\n/** 存储值解析成开关状态:只有显式 false 才是「关闭」。 */\nexport function isFieldEnabled(value: unknown): boolean {\n return value !== false\n}\n\n/**\n * 草稿文本解析成开关状态:与 {@link isFieldEnabled} 不同,这里比较的是模型给的\n * **文本**,别把字符串喂给上面那个函数(`'false' !== false` 恒真)。\n */\nexport function isDraftEnabled(text: string): boolean {\n return text !== 'false'\n}\n\n/**\n * 构造一个布尔字段的字段转换规格。\n *\n * `parse` 只接受 `'true'` / `'false'`:空串、任意其它文本都返回 `undefined`,\n * 让模型把字段判为 invalid 并拒绝保存(官方模型的既定行为)。\n *\n * @param field - 字段名(与 Config 同名)。\n * @param defaultValue - 缺失值时的默认(true = 默认显示,false = 默认隐藏)。\n */\nfunction makeBooleanField(field: string, defaultValue: boolean): SettingsFieldSpec {\n return {\n field,\n format: value => {\n const enabled = value === undefined || value === null || typeof value !== 'boolean'\n ? defaultValue\n : value\n return enabled ? 'true' : 'false'\n },\n parse: text =>\n text === 'true' ? { kind: 'set', value: true }\n : text === 'false' ? { kind: 'set', value: false }\n : undefined,\n }\n}\n\n/** 各字段的字段转换规格。 */\nexport const showCompletedField: SettingsFieldSpec = makeBooleanField(BADGE_FIELDS.showCompletedInBadge, true)\nexport const showRunningField: SettingsFieldSpec = makeBooleanField(BADGE_FIELDS.showRunningInBadge, true)\nexport const showPendingField: SettingsFieldSpec = makeBooleanField(BADGE_FIELDS.showPendingInBadge, true)\nexport const showScheduledField: SettingsFieldSpec = makeBooleanField(BADGE_FIELDS.showScheduledInBadge, true)\nexport const showWaitingReviewField: SettingsFieldSpec = makeBooleanField(BADGE_FIELDS.showWaitingReviewInBadge, true)\nexport const showHoverDetailsField: SettingsFieldSpec = makeBooleanField(BADGE_FIELDS.showHoverDetails, true)\nexport const countThresholdField: SettingsFieldSpec = {\n field: BADGE_FIELDS.countThreshold,\n format: value => {\n const n = value === undefined || value === null || typeof value !== 'number' || !Number.isFinite(value)\n ? 2\n : Math.floor(value)\n return String(n < 0 ? 0 : n)\n },\n parse: text => {\n const n = Number(text)\n if (!Number.isFinite(n) || n < 0 || n !== Math.floor(n)) return undefined\n return { kind: 'set', value: n }\n },\n}\n\n/** 所有字段规格(按卡片渲染顺序)。 */\nexport const ALL_BADGE_FIELDS: SettingsFieldSpec[] = [\n showCompletedField,\n showRunningField,\n showPendingField,\n showScheduledField,\n showWaitingReviewField,\n showHoverDetailsField,\n countThresholdField,\n]\n","/**\n * 折叠徽标的设置卡片:插件 → dsh-group-status(bundle 详情页的配置表单)。\n *\n * 为什么需要这张卡片:0.2.0 起宿主把插件 `Config`(`src/index.ts`,根节点\n * `.volatile()`)投影到客户端 `configForms` 服务上,但**不会**自动把表单画进\n * 「插件」页——插件页只在客户端往 `plugins.bundle.config` 注册了卡片时才渲染\n * (见 dsh-later / dsh-gitea-dispatch 的同款做法)。没有它,README「设置项」一节\n * 描述的配置表单在 GUI 里根本不存在。\n *\n * 视觉与交互**不自造**,全部交给官方组件(`@deepseek-ai/dsh-client-ui-primitives`):\n * - `SettingsForm`:表单框架——只读提示、不可用提示、保存按钮、失败行、间距;\n * - `SettingsFormModel`:分步草稿与保存(revision 围栏、宿主拒绝时不丢草稿);\n * - `Switch`:开关本体。\n * 官方设置页(设置 → 内置插件 → 子智能体 / 网页搜索)用的就是这三件,本卡片的\n * 类名与取值也逐条对齐它们的 CSS(见 `BadgeSettingsCard.module.css` 头部)。\n *\n * 字段定义在 `badge-field.ts`(纯逻辑,可单测);这里只管把它们接到模型与槽位上。\n */\nimport { useEffect, useId, useMemo, useSyncExternalStore } from 'react'\nimport type { JSX } from 'react'\nimport {\n SettingsForm,\n SettingsFormModel,\n Switch,\n type SettingsFormLabels,\n type SettingsFormScope,\n} from '@deepseek-ai/dsh-client-ui-primitives'\nimport { ALL_BADGE_FIELDS, BADGE_FIELDS, isDraftEnabled } from './badge-field.ts'\nimport type { WorkspaceKey } from './locales.ts'\nimport css from './BadgeSettingsCard.module.css'\n\n/**\n * 卡片 props:宿主设置表单 + 本命名空间文案取值器。\n *\n * `scope` 直接用官方 `SettingsFormScope`(= `configForms.get(条目 id)` 的运行时形状:\n * `getSnapshot` / `subscribe` / `mutate`),因此不需要本地复刻契约,也就不会与宿主漂移。\n * `locale: NS` 由框架按声明注入 `t`。\n */\nexport interface BadgeSettingsCardProps {\n readonly scope: SettingsFormScope<Record<string, unknown>>\n readonly t: (key: WorkspaceKey) => string\n}\n\n/**\n * 渲染折叠徽标的设置表单。\n *\n * 模型与投影都按 `scope` 记忆:宿主换一份表单(条目重新服务)时整体重建,旧模型\n * 在 effect 清理里 `dispose()`,不会留下悬挂订阅。\n * @param props - 宿主设置表单与文案取值器。\n * @returns 官方表单框架包着本插件的开关字段。\n */\nexport function BadgeSettingsCard({ scope, t }: BadgeSettingsCardProps): JSX.Element {\n const model = useMemo(\n () => new SettingsFormModel<Record<string, unknown>>(scope, ALL_BADGE_FIELDS),\n [scope],\n )\n useEffect(() => () => { model.dispose() }, [model])\n // 投影:框架状态 + 所有字段的草稿。模型的 publish 会在宿主折叠或草稿变化时重算。\n const store = useMemo(\n () => model.bind(() => ({\n ...model.shell(),\n fields: ALL_BADGE_FIELDS.map(spec => ({ field: spec.field, text: model.field(spec.field).text })),\n })),\n [model],\n )\n const state = useSyncExternalStore(store.subscribe, store.getSnapshot)\n const actions = useMemo(() => model.actions(), [model])\n const badgeSectionId = useId()\n const hoverSectionId = useId()\n const countSectionId = useId()\n\n const labels: SettingsFormLabels = {\n unavailable: t('settings.unavailable'),\n readOnly: t('settings.readOnly'),\n saveFailed: t('settings.saveFailed'),\n save: t('settings.save'),\n saving: t('settings.saving'),\n }\n\n // 按字段名查草稿文本。\n const fieldText = (field: string): string => {\n const found = state.fields.find(f => f.field === field)\n return found?.text ?? 'true'\n }\n\n return (\n <SettingsForm\n labels={labels}\n state={state}\n onSave={() => { actions.save() }}\n onDiscard={() => { actions.discard() }}\n >\n <section className={css.section} aria-labelledby={badgeSectionId}>\n <h3 className={css.heading} id={badgeSectionId}>{t('settings.badge.section')}</h3>\n <ToggleRow field={BADGE_FIELDS.showRunningInBadge} text={fieldText(BADGE_FIELDS.showRunningInBadge)} label={t('settings.badge.showRunning')} hint={t('settings.badge.showRunningHint')} state={state} actions={actions} />\n <ToggleRow field={BADGE_FIELDS.showPendingInBadge} text={fieldText(BADGE_FIELDS.showPendingInBadge)} label={t('settings.badge.showPending')} hint={t('settings.badge.showPendingHint')} state={state} actions={actions} />\n <ToggleRow field={BADGE_FIELDS.showCompletedInBadge} text={fieldText(BADGE_FIELDS.showCompletedInBadge)} label={t('settings.badge.showCompleted')} hint={t('settings.badge.showCompletedHint')} state={state} actions={actions} />\n <ToggleRow field={BADGE_FIELDS.showScheduledInBadge} text={fieldText(BADGE_FIELDS.showScheduledInBadge)} label={t('settings.badge.showScheduled')} hint={t('settings.badge.showScheduledHint')} state={state} actions={actions} />\n <ToggleRow field={BADGE_FIELDS.showWaitingReviewInBadge} text={fieldText(BADGE_FIELDS.showWaitingReviewInBadge)} label={t('settings.badge.showWaitingReview')} hint={t('settings.badge.showWaitingReviewHint')} state={state} actions={actions} />\n </section>\n <section className={css.section} aria-labelledby={hoverSectionId}>\n <h3 className={css.heading} id={hoverSectionId}>{t('settings.hover.section')}</h3>\n <ToggleRow field={BADGE_FIELDS.showHoverDetails} text={fieldText(BADGE_FIELDS.showHoverDetails)} label={t('settings.hover.showDetails')} hint={t('settings.hover.showDetailsHint')} state={state} actions={actions} />\n </section>\n <section className={css.section} aria-labelledby={countSectionId}>\n <h3 className={css.heading} id={countSectionId}>{t('settings.count.section')}</h3>\n <NumberRow field={BADGE_FIELDS.countThreshold} text={fieldText(BADGE_FIELDS.countThreshold)} label={t('settings.count.threshold')} hint={t('settings.count.thresholdHint')} state={state} actions={actions} />\n </section>\n </SettingsForm>\n )\n}\n\n/** 单行开关:label + Switch + hint。 */\nfunction ToggleRow({ field, text, label, hint, state, actions }: {\n field: string\n text: string\n label: string\n hint: string\n state: { writable: boolean; saving: boolean }\n actions: { edit: (field: string, value: string) => void }\n}): JSX.Element {\n return (\n <div className={css.badgeField}>\n <div className={css.badgeToggleRow}>\n <span className={css.badgeToggleLabel}>{label}</span>\n <Switch\n checked={isDraftEnabled(text)}\n label={label}\n disabled={!state.writable || state.saving}\n onChange={next => { actions.edit(field, next ? 'true' : 'false') }}\n />\n </div>\n <p className={css.hint}>{hint}</p>\n </div>\n )\n}\n\n/** 单行数字输入:label + 带加减按钮的数字输入 + hint。 */\nfunction NumberRow({ field, text, label, hint, state, actions }: {\n field: string\n text: string\n label: string\n hint: string\n state: { writable: boolean; saving: boolean }\n actions: { edit: (field: string, value: string) => void }\n}): JSX.Element {\n const disabled = !state.writable || state.saving\n const currentValue = Number(text) || 0\n const decrement = () => { if (!disabled && currentValue > 0) actions.edit(field, String(currentValue - 1)) }\n const increment = () => { if (!disabled) actions.edit(field, String(currentValue + 1)) }\n return (\n <div className={css.badgeField}>\n <div className={css.badgeToggleRow}>\n <span className={css.badgeToggleLabel}>{label}</span>\n <div className={css.badgeNumberControl}>\n <button\n type=\"button\"\n className={css.badgeNumberButton}\n disabled={disabled || currentValue <= 0}\n onClick={decrement}\n aria-label=\"减少\"\n >\n −\n </button>\n <span className={css.badgeNumberValue}>{text}</span>\n <button\n type=\"button\"\n className={css.badgeNumberButton}\n disabled={disabled}\n onClick={increment}\n aria-label=\"增加\"\n >\n +\n </button>\n </div>\n </div>\n <p className={css.hint}>{hint}</p>\n </div>\n )\n}\n","//#region lib/types/index.js\n/** Duplicate-install-safe JSON and immutable-value helpers. @module @deepseek-ai/dsh-util-values */\n/**\n* Mark an unreachable closed-union branch.\n* @param value - impossible value; an unhandled typed variant fails at the call site.\n* @param context - optional switch-site label included in the failure message.\n* @returns never; a runtime value that escaped its type always throws.\n*/\nfunction assertNever(value, context) {\n\tconst rendered = JSON.stringify(value) ?? String(value);\n\tthrow new Error(`unreachable variant${context ? ` in ${context}` : \"\"}: ${rendered}`);\n}\n/** Whether a realm-owned intrinsic prototype has a native constructor matching this engine's representation. */\nfunction hasIntrinsicConstructor(prototype, name) {\n\tconst constructor = Object.getOwnPropertyDescriptor(prototype, \"constructor\")?.value;\n\tif (typeof constructor !== \"function\") return false;\n\ttry {\n\t\treturn constructor.name === name && constructor.prototype === prototype && Function.prototype.toString.call(constructor) === Function.prototype.toString.call(name === \"Array\" ? Array : Object);\n\t} catch {\n\t\treturn false;\n\t}\n}\n/** Whether a candidate is one realm's intrinsic `Object.prototype`. */\nfunction isIntrinsicObjectPrototype(value) {\n\treturn Object.getPrototypeOf(value) === null && hasIntrinsicConstructor(value, \"Object\");\n}\n/** Whether an array uses one realm's intrinsic `Array.prototype`, not a subclass or forged prototype. */\nfunction hasPlainArrayPrototype(value) {\n\tconst prototype = Object.getPrototypeOf(value);\n\tif (!Array.isArray(prototype) || !hasIntrinsicConstructor(prototype, \"Array\")) return false;\n\tconst objectPrototype = Object.getPrototypeOf(prototype);\n\treturn typeof objectPrototype === \"object\" && objectPrototype !== null && isIntrinsicObjectPrototype(objectPrototype);\n}\n/** Whether an object is a plain or null-prototype record from any JavaScript realm. */\nfunction hasPlainObjectPrototype(value) {\n\tconst prototype = Object.getPrototypeOf(value);\n\treturn prototype === null || typeof prototype === \"object\" && isIntrinsicObjectPrototype(prototype);\n}\n/** Return every JSON-visible object key, or reject own data JSON would discard. */\nfunction enumerableStringKeys(value) {\n\tconst keys = Reflect.ownKeys(value);\n\tif (keys.some((key) => typeof key !== \"string\" || !Object.prototype.propertyIsEnumerable.call(value, key))) return void 0;\n\treturn keys;\n}\n/** Validate lossless JSON iteratively, optionally materializing a detached snapshot. */\nfunction walkJsonValue(value, detach) {\n\tconst ancestors = /* @__PURE__ */ new Set();\n\tlet root;\n\tconst assign = (destination, item) => {\n\t\tif (destination === void 0) return;\n\t\tif (destination.kind === \"root\") root = item;\n\t\telse if (destination.kind === \"array\") destination.target[destination.index] = item;\n\t\telse Object.defineProperty(destination.target, destination.key, {\n\t\t\tvalue: item,\n\t\t\tenumerable: true,\n\t\t\tconfigurable: true,\n\t\t\twritable: true\n\t\t});\n\t};\n\tconst tasks = [{\n\t\tkind: \"visit\",\n\t\tvalue,\n\t\t...detach ? { destination: { kind: \"root\" } } : {}\n\t}];\n\tfor (let task = tasks.pop(); task !== void 0; task = tasks.pop()) {\n\t\tif (task.kind === \"leave\") {\n\t\t\tancestors.delete(task.source);\n\t\t\tcontinue;\n\t\t}\n\t\tif (task.kind === \"array-item\") {\n\t\t\tif (!Object.prototype.hasOwnProperty.call(task.source, task.index)) return void 0;\n\t\t\ttasks.push({\n\t\t\t\tkind: \"visit\",\n\t\t\t\tvalue: task.source[task.index],\n\t\t\t\t...task.target === void 0 ? {} : { destination: {\n\t\t\t\t\tkind: \"array\",\n\t\t\t\t\ttarget: task.target,\n\t\t\t\t\tindex: task.index\n\t\t\t\t} }\n\t\t\t});\n\t\t\tcontinue;\n\t\t}\n\t\tif (task.kind === \"object-property\") {\n\t\t\ttasks.push({\n\t\t\t\tkind: \"visit\",\n\t\t\t\tvalue: task.source[task.key],\n\t\t\t\t...task.target === void 0 ? {} : { destination: {\n\t\t\t\t\tkind: \"object\",\n\t\t\t\t\ttarget: task.target,\n\t\t\t\t\tkey: task.key\n\t\t\t\t} }\n\t\t\t});\n\t\t\tcontinue;\n\t\t}\n\t\tconst current = task.value;\n\t\tif (current === null) {\n\t\t\tassign(task.destination, null);\n\t\t\tcontinue;\n\t\t}\n\t\tif (typeof current === \"boolean\" || typeof current === \"string\") {\n\t\t\tassign(task.destination, current);\n\t\t\tcontinue;\n\t\t}\n\t\tif (typeof current === \"number\") {\n\t\t\tif (!Number.isFinite(current) || Object.is(current, -0)) return void 0;\n\t\t\tassign(task.destination, current);\n\t\t\tcontinue;\n\t\t}\n\t\tif (typeof current !== \"object\") return void 0;\n\t\tif (ancestors.has(current)) return void 0;\n\t\tif (Array.isArray(current)) {\n\t\t\tif (!hasPlainArrayPrototype(current)) return void 0;\n\t\t\tconst length = current.length;\n\t\t\tif (Reflect.ownKeys(current).length !== length + 1) return void 0;\n\t\t\tconst target = detach ? [] : void 0;\n\t\t\tif (target !== void 0) assign(task.destination, target);\n\t\t\tancestors.add(current);\n\t\t\ttasks.push({\n\t\t\t\tkind: \"leave\",\n\t\t\t\tsource: current\n\t\t\t});\n\t\t\tfor (let index = length - 1; index >= 0; index--) tasks.push({\n\t\t\t\tkind: \"array-item\",\n\t\t\t\tsource: current,\n\t\t\t\tindex,\n\t\t\t\t...target === void 0 ? {} : { target }\n\t\t\t});\n\t\t\tcontinue;\n\t\t}\n\t\tif (!hasPlainObjectPrototype(current)) return void 0;\n\t\tconst keys = enumerableStringKeys(current);\n\t\tif (keys === void 0) return void 0;\n\t\tconst target = detach ? {} : void 0;\n\t\tif (target !== void 0) assign(task.destination, target);\n\t\tancestors.add(current);\n\t\ttasks.push({\n\t\t\tkind: \"leave\",\n\t\t\tsource: current\n\t\t});\n\t\tfor (let index = keys.length - 1; index >= 0; index--) {\n\t\t\tconst key = keys[index];\n\t\t\t/* v8 ignore next -- the loop is bounded by the captured key count. */\n\t\t\tif (key === void 0) return void 0;\n\t\t\ttasks.push({\n\t\t\t\tkind: \"object-property\",\n\t\t\t\tsource: current,\n\t\t\t\tkey,\n\t\t\t\t...target === void 0 ? {} : { target }\n\t\t\t});\n\t\t}\n\t}\n\treturn detach ? root : true;\n}\n/**\n* Validate and detach lossless JSON in one read per property.\n* @param value - candidate value to validate and detach.\n* @returns the detached snapshot, or `undefined` when the value is not losslessly JSON-serializable.\n*/\nfunction snapshotJsonValue(value) {\n\treturn walkJsonValue(value, true);\n}\n/**\n* Test the same lossless JSON rules as {@link snapshotJsonValue} without detaching the value.\n* @param value - candidate value to test.\n* @returns whether the value survives a JSON round trip without loss.\n*/\nfunction isJsonValue(value) {\n\treturn walkJsonValue(value, false) === true;\n}\n/**\n* Compare JSON-compatible values structurally.\n* @param a - one JSON-compatible value.\n* @param b - the other JSON-compatible value.\n* @returns whether both values contain the same JSON data.\n*/\nfunction deepEqualJson(a, b) {\n\tif (a === b) return true;\n\tif (typeof a !== \"object\" || typeof b !== \"object\" || a === null || b === null) return false;\n\tif (Array.isArray(a) || Array.isArray(b)) {\n\t\tif (!Array.isArray(a) || !Array.isArray(b) || a.length !== b.length) return false;\n\t\treturn a.every((entry, index) => deepEqualJson(entry, b[index]));\n\t}\n\tconst left = a;\n\tconst right = b;\n\tconst keys = Object.keys(left);\n\tif (keys.length !== Object.keys(right).length) return false;\n\treturn keys.every((key) => key in right && deepEqualJson(left[key], right[key]));\n}\n/**\n* Deep-freeze an object graph in place while leaving live AbortSignal objects mutable.\n* @param value - value to freeze.\n* @returns the same value after every reachable enumerable child is frozen.\n*/\nfunction deepFreeze(value) {\n\tconst seen = /* @__PURE__ */ new WeakSet();\n\tconst pending = [{\n\t\tkind: \"visit\",\n\t\tnode: value\n\t}];\n\twhile (pending.length > 0) {\n\t\tconst task = pending.pop();\n\t\t/* v8 ignore next -- the loop condition guarantees one pending task. */\n\t\tif (task === void 0) continue;\n\t\tif (task.kind === \"property\") {\n\t\t\tpending.push({\n\t\t\t\tkind: \"visit\",\n\t\t\t\tnode: task.source[task.key]\n\t\t\t});\n\t\t\tcontinue;\n\t\t}\n\t\tconst node = task.node;\n\t\tif (node === null || typeof node !== \"object\") continue;\n\t\tif (node instanceof AbortSignal) continue;\n\t\tif (seen.has(node)) continue;\n\t\tseen.add(node);\n\t\tObject.freeze(node);\n\t\tconst keys = Object.keys(node);\n\t\tfor (let index = keys.length - 1; index >= 0; index--) {\n\t\t\tconst key = keys[index];\n\t\t\t/* v8 ignore next -- the loop is bounded by the captured key count. */\n\t\t\tif (key === void 0) continue;\n\t\t\tpending.push({\n\t\t\t\tkind: \"property\",\n\t\t\t\tsource: node,\n\t\t\t\tkey\n\t\t\t});\n\t\t}\n\t}\n\treturn value;\n}\n/**\n* Weak-key lookup with a strongly retained iterable set of associated values.\n*\n* Each value must belong to only one key. The container performs no automatic\n* cleanup; owners delete associations or clear the container at lifecycle end.\n*/\nvar WeakMapWithValues = class {\n\tkeys = /* @__PURE__ */ new WeakMap();\n\tvalueSet = /* @__PURE__ */ new Set();\n\t/** Live strongly retained values in insertion order. */\n\tvalues = this.valueSet;\n\t/**\n\t* Read the value associated with a key.\n\t* @param key - weakly held lookup key.\n\t* @returns the associated value, or absence.\n\t*/\n\tget(key) {\n\t\treturn this.keys.get(key);\n\t}\n\t/**\n\t* Test whether a key has an association.\n\t* @param key - weakly held lookup key.\n\t* @returns whether the key is present.\n\t*/\n\thas(key) {\n\t\treturn this.keys.has(key);\n\t}\n\t/**\n\t* Associate one key with one caller-unique value.\n\t* @param key - weakly held lookup key.\n\t* @param value - strongly retained value that belongs to no other key.\n\t* @returns this container.\n\t*/\n\tset(key, value) {\n\t\tif (this.keys.has(key)) {\n\t\t\tconst previous = this.keys.get(key);\n\t\t\tif (previous === value) return this;\n\t\t\tthis.valueSet.delete(previous);\n\t\t}\n\t\tthis.keys.set(key, value);\n\t\tthis.valueSet.add(value);\n\t\treturn this;\n\t}\n\t/**\n\t* Remove one association and its strongly retained value.\n\t* @param key - weakly held lookup key.\n\t* @returns whether an association was removed.\n\t*/\n\tdelete(key) {\n\t\tif (!this.keys.has(key)) return false;\n\t\tconst value = this.keys.get(key);\n\t\tconst deleted = this.keys.delete(key);\n\t\tthis.valueSet.delete(value);\n\t\treturn deleted;\n\t}\n\t/** Remove every association and strongly retained value. */\n\tclear() {\n\t\tthis.keys = /* @__PURE__ */ new WeakMap();\n\t\tthis.valueSet.clear();\n\t}\n};\n//#endregion\nexport { WeakMapWithValues, assertNever, deepEqualJson, deepFreeze, isJsonValue, snapshotJsonValue };\n","//#region lib/types/file-address.js\n/**\n* The `dsh-resource://file/…` address grammar: how a file is named across the\n* Sidebar and the resource model, built and parsed without touching a\n* filesystem.\n* @module\n*/\n/** The scheme and type every file address opens with. */\nconst FILE_ADDRESS_PREFIX = \"dsh-resource://file/\";\n/** Component-encode one id or path segment, keeping `:` literal for drive letters. */\nfunction encodeSegment(segment) {\n\treturn encodeURIComponent(segment).replace(/%3A/gi, \":\");\n}\n/** Encode a `/`-separated path segment by segment. */\nfunction encodePath(path) {\n\treturn path.split(\"/\").map(encodeSegment).join(\"/\");\n}\n/** Whether a decoded first path segment is a Windows drive (`C:`). */\nfunction isDriveSegment(segment) {\n\treturn segment !== void 0 && /^[A-Za-z]:$/.test(segment);\n}\n/**\n* Build the address of a file read through one Session.\n* @param sessionId - the Session whose Host workspace resolves the path.\n* @param path - absolute or workspace-relative path; backslashes are normalized to `/`, and leading `./` prefixes are dropped.\n* @returns the `dsh-resource://file/session/<sessionId>/<path>` address.\n*/\nfunction sessionFileAddress(sessionId, path) {\n\tconst normalized = path.replace(/\\\\/g, \"/\").replace(/^(?:\\.\\/)+/, \"\");\n\treturn `${FILE_ADDRESS_PREFIX}session/${encodeSegment(sessionId)}/${encodePath(normalized)}`;\n}\n/**\n* Build the address of a file by its absolute path.\n* @param path - absolute path; backslashes are normalized to `/` and the leading `/` is dropped,\n* except that a UNC path (`\\\\server\\share`) keeps one empty first segment.\n* @returns the `dsh-resource://file/absolute/<path>` address.\n*/\nfunction absoluteFileAddress(path) {\n\tconst normalized = path.replace(/\\\\/g, \"/\");\n\tconst unc = normalized.startsWith(\"//\");\n\tconst absolute = normalized.replace(/^\\/+/, \"\");\n\treturn `${FILE_ADDRESS_PREFIX}absolute/${unc ? \"/\" : \"\"}${encodePath(absolute)}`;\n}\n/**\n* Read a file address back into its parts without resolving `.` or `..`.\n* Query and fragment suffixes are ignored; encoded path segments are decoded.\n* @param address - a candidate address.\n* @returns the parts, or `undefined` when the string is not a `dsh-resource://file/` URI in a known scope with a path, or a segment is not validly encoded.\n*/\nfunction parseFileAddress(address) {\n\ttry {\n\t\tif (!address.startsWith(FILE_ADDRESS_PREFIX)) return void 0;\n\t\tconst end = address.search(/[?#]/);\n\t\tconst [scope, ...rest] = address.slice(20, end === -1 ? void 0 : end).split(\"/\");\n\t\tif (scope === \"session\") {\n\t\t\tconst [id, ...segments] = rest;\n\t\t\tif (id === void 0 || id === \"\" || segments.length === 0) return void 0;\n\t\t\treturn {\n\t\t\t\tscope,\n\t\t\t\tsessionId: decodeURIComponent(id),\n\t\t\t\tpath: segments.map(decodeURIComponent).join(\"/\")\n\t\t\t};\n\t\t}\n\t\tif (scope === \"absolute\") {\n\t\t\tconst unc = rest[0] === \"\" && rest.length > 1;\n\t\t\tconst segments = (unc ? rest.slice(1) : rest).map(decodeURIComponent);\n\t\t\tif (segments.length === 0 || segments[0] === \"\") return void 0;\n\t\t\tif (unc) return {\n\t\t\t\tscope,\n\t\t\t\tpath: `//${segments.join(\"/\")}`\n\t\t\t};\n\t\t\treturn {\n\t\t\t\tscope,\n\t\t\t\tpath: isDriveSegment(segments[0]) ? segments.join(\"/\") : `/${segments.join(\"/\")}`\n\t\t\t};\n\t\t}\n\t\treturn;\n\t} catch {\n\t\treturn;\n\t}\n}\n//#endregion\n//#region lib/types/index.js\n/**\n* Browser-safe Workspace path and display helpers.\n* @module @deepseek-ai/dsh-util-workspace-path\n*/\n/** Whether a path uses a Windows drive or UNC prefix. */\nfunction isWindowsStylePath(value) {\n\treturn /^[A-Za-z]:[/\\\\]/.test(value) || value.startsWith(\"\\\\\\\\\");\n}\n/**\n* Whether a path is absolute in either spelling the Host accepts: POSIX (`/a/b`) or Windows drive or UNC.\n* @param path - the path to classify.\n* @returns `true` for an absolute path; `false` for a Workspace-relative one.\n*/\nfunction isAbsoluteWorkspacePath(path) {\n\treturn path.startsWith(\"/\") || isWindowsStylePath(path);\n}\n/**\n* Resolve a Workspace-relative path into the Host-facing spelling used by path operations.\n* @param cwd - Session Workspace root, when known.\n* @param path - Absolute or Workspace-relative path.\n* @returns an absolute path when a Workspace root is available, otherwise the original path.\n*/\nfunction resolveWorkspacePath(cwd, path) {\n\tif (isAbsoluteWorkspacePath(path)) return path;\n\tif (cwd === void 0 || cwd === \"\") return path;\n\tconst separator = isWindowsStylePath(cwd) && cwd.includes(\"\\\\\") ? \"\\\\\" : \"/\";\n\treturn `${cwd.replace(/[/\\\\]+$/, \"\")}${separator}${path.replace(/^[/\\\\]+/, \"\")}`;\n}\n/**\n* Abbreviate a POSIX home directory for display.\n* @param path - Absolute or already-short display path.\n* @param home - Host account home; absent skips abbreviation.\n* @returns `~` or `~/…` for the POSIX home and its descendants, otherwise `path`.\n*/\nfunction abbreviateHomePath(path, home) {\n\tif (home === void 0 || home === \"\") return path;\n\tif (isWindowsStylePath(path) || isWindowsStylePath(home)) return path;\n\tconst root = home.replace(/\\/+$/, \"\");\n\tif (root === \"\" || root === \"/\") return path;\n\tif (path.replace(/\\/+$/, \"\") === root) return \"~\";\n\tif (path.startsWith(`${root}/`)) return `~${path.slice(root.length)}`;\n\treturn path;\n}\n/**\n* Read the final non-empty segment of a Workspace path for display.\n* Workspace-label surfaces use this helper instead of deriving another basename.\n* @param path - Workspace directory path using POSIX or Windows separators.\n* @returns the final segment, or an empty string for a separator-only path.\n*/\nfunction workspaceTitleOf(path) {\n\tconst trimmed = path.replace(/[/\\\\]+$/, \"\");\n\tconst separator = Math.max(trimmed.lastIndexOf(\"/\"), trimmed.lastIndexOf(\"\\\\\"));\n\treturn trimmed.slice(separator + 1);\n}\n/**\n* Split a path for display: the directories through their last separator, and\n* the final segment after it. Both `/` and `\\` separate, so a Windows path\n* splits where its own segments end; trailing separators are dropped first, so\n* a directory path names its own last segment. A path with no separator, or a\n* separator-only path, is all name.\n* @param path - file or directory path using POSIX or Windows separators.\n* @returns the directory prefix (possibly empty) and the final segment.\n*/\nfunction pathPartsOf(path) {\n\tconst trimmed = path.replace(/[/\\\\]+$/, \"\");\n\tif (trimmed === \"\") return {\n\t\tdirectory: \"\",\n\t\tname: path\n\t};\n\tconst cut = Math.max(trimmed.lastIndexOf(\"/\"), trimmed.lastIndexOf(\"\\\\\")) + 1;\n\treturn {\n\t\tdirectory: trimmed.slice(0, cut),\n\t\tname: trimmed.slice(cut)\n\t};\n}\n/**\n* The address for a path as a caller holds it: a relative path, or an absolute\n* path inside the Session's workspace, becomes a `session`-scoped address; an\n* absolute path outside it, or one whose workspace root is unknown, keeps its\n* absolute path in that Session's address.\n* @param sessionId - the Session the path is read in.\n* @param cwd - that Session's workspace root, when known.\n* @param path - absolute or workspace-relative path, in either separator spelling.\n* @returns the `dsh-resource://file/…` address.\n*/\nfunction fileAddressFor(sessionId, cwd, path) {\n\tconst normalized = path.replace(/\\\\/g, \"/\");\n\tif (!isAbsoluteWorkspacePath(normalized)) return sessionFileAddress(sessionId, normalized);\n\tconst root = cwd === void 0 ? \"\" : cwd.replace(/\\\\/g, \"/\").replace(/\\/+$/, \"\");\n\tif (root !== \"\" && normalized === root) return sessionFileAddress(sessionId, \"\");\n\tif (root !== \"\" && normalized.startsWith(`${root}/`)) return sessionFileAddress(sessionId, normalized.slice(root.length + 1));\n\treturn sessionFileAddress(sessionId, normalized);\n}\n/**\n* Strip the workspace root from a workspace-rooted absolute path (display only).\n* @param text - the path to shorten.\n* @param cwd - session workspace root; absent or empty leaves the path unchanged.\n* @returns the path relative to the workspace root, or unchanged when it is not rooted there.\n*/\nfunction relativizeToCwd(text, cwd) {\n\tif (cwd === void 0 || cwd === \"\") return text;\n\tconst root = cwd.replace(/[/\\\\]+$/, \"\");\n\tif (text.startsWith(`${root}/`) || text.startsWith(`${root}\\\\`)) return text.slice(root.length + 1);\n\treturn text;\n}\n/**\n* Address a decoded absolute file path through the authenticated file route.\n* @param base - HTTP(S) application base, including its deployment prefix, or `dsh-app://app/`.\n* @param path - Native file path; URL escapes in authored Markdown must already be decoded.\n* @returns File URL, or undefined for unsupported transports and non-absolute paths.\n*/\nfunction fileMediaUrl(base, path) {\n\tif (!/^https?:/u.test(base) && !base.startsWith(\"dsh-app://app/\") || !isAbsoluteWorkspacePath(path) || /^[/\\\\]{2}/u.test(path) || /[\\u0000-\\u001f\\u007f]/u.test(path)) return void 0;\n\treturn new URL(`api/file?path=${encodeURIComponent(path)}`, base).href;\n}\n//#endregion\nexport { abbreviateHomePath, absoluteFileAddress, fileAddressFor, fileMediaUrl, isAbsoluteWorkspacePath, parseFileAddress, pathPartsOf, relativizeToCwd, resolveWorkspacePath, sessionFileAddress, workspaceTitleOf };\n","/**\n * Derives the workspace browser tree from caller-projected Workspace and\n * Session order. Unassigned Sessions trail under Ungrouped; only the selected\n * blank Session remains visible.\n */\nimport {\n type SessionListState, type SessionSearchResultItem, type SessionSummary,\n} from '@deepseek-ai/dsh-api-session-controller/client'\nimport type { WorkspaceId, WorkspaceView } from '@deepseek-ai/dsh-api-workspace-controller/client'\nimport type {\n SessionStatusSnapshot,\n} from '@deepseek-ai/dsh-client-ui-session/client'\nimport type { SessionId } from '@deepseek-ai/dsh-session/types'\nimport { assertNever } from '@deepseek-ai/dsh-util-values'\nimport { workspaceTitleOf } from '@deepseek-ai/dsh-util-workspace-path'\n// Fork-owned: `GroupLiveStatus` lives in ./group-status.ts and is re-exported here so\n// the vendored row components can keep importing every group type from one module.\n// Nothing else is re-exported: the status computation has no reason to pass through\n// this file, and the cross-plugin summary types had no consumers at all.\nimport type { GroupLiveStatus } from './group-status.ts'\n\nexport type { GroupLiveStatus }\n\n/** Group key for Sessions outside every Workspace. */\nexport const UNGROUPED_KEY = ''\n\n/**\n * Resolve the Workspace browser group that owns one Session.\n * @param workspaces - authoritative Workspace membership.\n * @param sessionId - Session whose browser group is required.\n * @returns owning Workspace id, or {@link UNGROUPED_KEY} when no Workspace accounts for it.\n */\nexport function owningGroupKey(\n workspaces: readonly WorkspaceView[],\n sessionId: SessionId,\n): string {\n return (workspaces.find(workspace => workspace.sessionIds.includes(sessionId))\n ?.workspaceId as string | undefined) ?? UNGROUPED_KEY\n}\n\n/** Pending interaction kinds with dedicated Workspace-row presentation. */\nexport type SessionPendingInteractionStatus = 'approval' | 'plan-review' | 'question'\ntype SessionStatuses = SessionStatusSnapshot\n\nfunction mainSessionId(list: SessionListState): SessionId | undefined {\n return Object.values(list.byId)\n .find(session => (session.retainedBy.mainView ?? 0) > 0)?.id\n}\n\n/** One top-level session row in a group or the flat list. */\nexport interface SessionNode {\n id: SessionId\n /** Stored title, or empty; the renderer localizes blank and unnamed row labels. */\n title: string\n /** The provisional blank session (renderer shows the localized New Session title). */\n blank: boolean\n /** A Session-scoped UI consumer is awaiting this user. */\n pendingInteraction?: SessionPendingInteractionStatus\n running: boolean\n /** Running direct children in the loaded subagent catalog. */\n runningSubagentCount: number\n /** Finished running while not selected and not yet opened (the green \"done\" reminder dot). */\n completed: boolean\n /** In the registry-global pin set: leads its section, reorderable only among pinned rows. */\n pinned: boolean\n /** In the registry-global archive set: shown grayed in place and not openable. */\n archived: boolean\n updatedAt: number\n}\n\n/** Session order selected by the Workspace browser. */\nexport type SessionOrderBy = 'manual' | 'updated'\n\n// ── Group node shapes ──\n// The live-status computation this fork adds lives entirely in ./group-status.ts;\n// only its `GroupLiveStatus` type is re-exported above. Keeping it in a separate\n// file minimises the upstream diff surface.\n\n/** One workspace group section: header row facts + visible top-level session rows. */\nexport interface GroupNode {\n /** Group key: the workspace id or {@link UNGROUPED_KEY}. */\n key: string\n /** Backing Workspace id; absent only for the ungrouped bucket. */\n workspaceId: WorkspaceId | undefined\n cwd: string | undefined\n /** Workspace creation time (epoch ms); absent only for the ungrouped bucket. */\n createdAt: number | undefined\n label: string\n /** Total visible sessions in the group. */\n sessionCount: number\n expanded: boolean\n /** The group contains the selected session (active folder tint; supplied here so the renderer never scans). */\n containsCurrent: boolean\n /** Aggregated member status; computed externally by HOC in WorkspaceBrowser.tsx. */\n liveStatus?: GroupLiveStatus\n /** Visible session rows (empty while the group is folded). */\n sessions: readonly SessionNode[]\n}\n\n/** One flat search row combining list metadata with an optional content match. */\nexport interface SearchResultNode {\n id: SessionId\n title: string\n workspace: string\n /** A Session-scoped UI consumer is awaiting this user. */\n pendingInteraction?: SessionPendingInteractionStatus\n running: boolean\n /** Running direct children in the loaded subagent catalog. */\n runningSubagentCount: number\n /** Finished running while not selected and not yet opened (the green \"done\" reminder dot). */\n completed: boolean\n /** In the registry-global archive set: shown grayed and not openable. */\n archived: boolean\n snippet?: string\n}\n\n/** Bounded merged search projection plus the refine-query hint bit. */\nexport interface SearchResultSet {\n items: readonly SearchResultNode[]\n hasMore: boolean\n}\n\n/** Viewing state consumed by the derivation. */\nexport interface TreeView {\n expandedGroups: readonly string[]\n /** Browser-local order for Sessions without a backing Workspace account. */\n ungroupedOrder?: readonly string[]\n}\n\ninterface Group {\n key: string\n workspaceId: WorkspaceId | undefined\n cwd: string | undefined\n createdAt: number | undefined\n label: string\n sessions: SessionSummary[]\n}\n\n/**\n * Directory display label: basename of the path (both separators accepted).\n * Ungrouped-bucket fallback for surfaces without a workspace title.\n * @param cwd - directory path, or undefined for the ungrouped bucket.\n * @returns basename, the raw cwd when it has no basename, or an empty ungrouped marker.\n */\nexport function workspaceLabel(cwd: string | undefined): string {\n if (cwd === undefined || cwd === '') return ''\n const base = workspaceTitleOf(cwd)\n return base !== '' ? base : cwd\n}\n\n/**\n * Project known account members by current Session recency.\n * @param sessionIds - authoritative account membership.\n * @param summaries - current Session summaries; members without a summary are omitted until it arrives.\n * @returns known members newest first, with Session identity as the deterministic tie-break.\n */\nexport function orderByRecency(\n sessionIds: readonly SessionId[],\n summaries: SessionListState['byId'],\n): SessionId[] {\n return sessionIds.flatMap((id) => {\n const summary = summaries[id]\n if (summary === undefined) return []\n return [{ id, rank: summary.updatedAt }]\n })\n .sort((a, b) => {\n if (a.rank !== b.rank) return b.rank - a.rank\n return a.id < b.id ? -1 : 1\n })\n .map(member => member.id)\n}\n\n/**\n * Reconcile a browser-local manual order with current account membership.\n * New ordinary forks precede their sources without changing saved entries' relative order.\n * @param memberIds - authoritative account membership.\n * @param savedOrder - previously saved browser-local order.\n * @param summaries - current Session metadata; unknown new members wait for their summaries.\n * @param rowState - global pin and archive membership; only account members can supplement the order.\n * @returns saved relative positions plus missing members ordered by pin, fork source, recency, and archive status.\n */\nexport function reconcileManualOrder(\n memberIds: readonly SessionId[],\n savedOrder: readonly string[] | undefined,\n summaries: SessionListState['byId'],\n rowState?: Pick<SessionRowState, 'pinnedSessionIds' | 'archivedSessionIds'>,\n): SessionId[] {\n const members = new Map(memberIds.map(id => [id as string, id]))\n const included = new Set<string>()\n const ordered: SessionId[] = []\n for (const key of savedOrder ?? []) {\n const id = members.get(key)\n if (id === undefined || included.has(key)) continue\n ordered.push(id)\n included.add(key)\n }\n const archived = new Set(rowState?.archivedSessionIds)\n const pins: SessionId[] = []\n for (const sessionId of rowState?.pinnedSessionIds ?? []) {\n const id = members.get(sessionId)\n if (id === undefined || included.has(id) || archived.has(id) || summaries[id] === undefined) continue\n pins.push(id)\n included.add(id)\n }\n const ordinary: SessionId[] = []\n const archives: SessionId[] = []\n for (const id of orderByRecency([...members.values()].filter(id => !included.has(id)), summaries)) {\n if (archived.has(id)) archives.push(id)\n else ordinary.push(id)\n }\n const result = [...pins, ...ordered, ...ordinary, ...archives]\n const pending = new Set(ordinary)\n const placeFork = (id: SessionId): void => {\n if (!pending.delete(id)) return\n const parentId = summaries[id]?.parentId\n if (parentId === undefined || parentId === id || !result.includes(parentId)) return\n placeFork(parentId)\n result.splice(result.indexOf(id), 1)\n result.splice(result.indexOf(parentId), 0, id)\n }\n for (const id of [...ordinary].reverse()) placeFork(id)\n return result\n}\n\n/**\n * Keep the selected provisional New Session ahead of either base order.\n * @param order - recency or reconciled manual order.\n * @param currentBlank - selected blank Session in this account, when present.\n * @returns a copy with the selected blank first and no duplicate slot.\n */\nexport function pinCurrentBlank(\n order: readonly SessionId[],\n currentBlank: SessionId | undefined,\n): SessionId[] {\n if (currentBlank === undefined) return [...order]\n return [currentBlank, ...order.filter(id => id !== currentBlank)]\n}\n\n/**\n * Archived-row visibility choice: the default hides archived rows, `show`\n * mixes them into their kept slots, and `only` restricts the view (and\n * search) to archived rows.\n */\nexport type ArchivedFilter = 'default' | 'show' | 'only'\n\n/**\n * Ordinary sessions are visible; among blank sessions, only the current one\n * is visible. Subagent children use their parent header catalog; archived\n * sessions follow the archived filter, while their accounting slots remain\n * either way so unarchiving restores position.\n */\nfunction sessionVisible(\n session: SessionSummary,\n current: SessionId | undefined,\n archived: ReadonlySet<SessionId>,\n archivedFilter: ArchivedFilter,\n): boolean {\n if (session.origin === 'subagent') return false\n if (session.blank && session.id !== current) return false\n switch (archivedFilter) {\n case 'default':\n return !archived.has(session.id)\n case 'show':\n return true\n case 'only':\n return archived.has(session.id)\n /* v8 ignore next 2 -- closed-union backstop; only reached if the filter is forged */\n default:\n return assertNever(archivedFilter)\n }\n}\n\n/** Registry-global row state consumed by every tree derivation. */\nexport interface SessionRowState {\n /** Registry-global pin ids; pinned rows lead their section in the local order. */\n pinnedSessionIds: readonly SessionId[]\n /** Archive set; members keep their slots and show grayed while visible. */\n archivedSessionIds: readonly SessionId[]\n /** Archived-row visibility choice applied to lists and search alike. */\n archivedFilter: ArchivedFilter\n}\n\n/**\n * Keep the visible New Session placeholder first, then partition pinned and\n * ordinary rows without changing either partition's caller order.\n */\nfunction sectionMembers(\n members: readonly SessionSummary[],\n pinned: ReadonlySet<SessionId>,\n archived: ReadonlySet<SessionId>,\n): SessionSummary[] {\n const placeholders: SessionSummary[] = []\n const leading: SessionSummary[] = []\n const rest: SessionSummary[] = []\n for (const member of members) {\n if (member.blank) placeholders.push(member)\n else if (!archived.has(member.id) && pinned.has(member.id)) leading.push(member)\n else rest.push(member)\n }\n return [...placeholders, ...leading, ...rest]\n}\n\n/**\n * A blank session is the selected Workspace's provisional New Session row;\n * its canonical title never enters search (blank rows are query-excluded)\n * and the renderer localizes its display label. Unnamed history also yields an\n * empty title for localization and does not match a directory-name title search.\n */\nfunction sessionTitle(session: SessionSummary): string {\n return session.blank ? '' : (session.title?.trim() ?? '')\n}\n\n/** Build one group without projecting session lineage into presentation. */\nfunction buildGroup(\n key: string,\n workspaceId: WorkspaceId | undefined,\n cwd: string | undefined,\n createdAt: number | undefined,\n label: string,\n members: readonly SessionSummary[],\n): Group {\n return { key, workspaceId, cwd, createdAt, label, sessions: [...members] }\n}\n\n/** Apply a stored Ungrouped order and append newly loose Sessions by recency. */\nfunction orderedUngrouped(\n members: readonly SessionSummary[],\n stored: readonly string[] | undefined,\n summaries: SessionListState['byId'],\n): SessionSummary[] {\n const byId = new Map(members.map(session => [session.id as string, session]))\n const ids = stored === undefined\n ? orderByRecency(members.map(session => session.id), summaries)\n : reconcileManualOrder(members.map(session => session.id), stored, summaries)\n return ids.flatMap((id) => {\n const session = byId.get(id)\n /* v8 ignore next -- ids are projected exclusively from the members used to build byId. */\n return session === undefined ? [] : [session]\n })\n}\n\n/**\n * Group Sessions by Workspace: one group per caller-ordered entity, with\n * members resolved from caller-ordered sessionIds. Sessions outside every\n * Workspace trail in the browser-local Ungrouped order, which falls back to\n * recency before that order is initialized.\n */\nfunction groupByWorkspace(\n list: SessionListState,\n workspaces: readonly WorkspaceView[],\n archived: ReadonlySet<SessionId>,\n archivedFilter: ArchivedFilter,\n ungroupedOrder: readonly string[] | undefined,\n): Group[] {\n const current = mainSessionId(list)\n const groups: Group[] = []\n const accounted = new Set<SessionId>()\n for (const workspace of workspaces) {\n const members: SessionSummary[] = []\n for (const id of workspace.sessionIds) {\n const summary = list.byId[id]\n if (summary === undefined) continue // account may lead the list pull; the row appears when the summary lands\n accounted.add(id)\n if (!sessionVisible(summary, current, archived, archivedFilter)) continue\n members.push(summary)\n }\n // The archived-only view lists archives, not the Workspace inventory, so\n // a Workspace without archived Sessions contributes no group.\n if (archivedFilter === 'only' && members.length === 0) continue\n groups.push(buildGroup(\n workspace.workspaceId, workspace.workspaceId, workspace.path,\n Date.parse(workspace.createdAt), workspace.title, members,\n ))\n }\n const stray = list.ids\n .map(id => list.byId[id])\n .filter((s): s is SessionSummary =>\n s !== undefined && !accounted.has(s.id) && sessionVisible(s, current, archived, archivedFilter))\n if (stray.length > 0) {\n groups.push(buildGroup(\n UNGROUPED_KEY,\n undefined,\n undefined,\n undefined,\n '',\n orderedUngrouped(stray, ungroupedOrder, list.byId),\n ))\n }\n return groups\n}\n\n/** Keep navigation presentation independent from domain-owned interaction objects. */\nfunction visiblePendingKind(kind: string | undefined): SessionPendingInteractionStatus | undefined {\n switch (kind) {\n case 'approval':\n case 'plan-review':\n case 'question':\n return kind\n default:\n return undefined\n }\n}\n\nfunction runningChildCount(list: SessionListState, parentId: SessionId, statuses: SessionStatuses): number {\n return list.projectionsBySession[parentId]?.values.subagentCatalog?.reduce(\n (count, child) => count + ((statuses.get(child.id)?.running ?? list.byId[child.id]?.running) === true ? 1 : 0),\n 0,\n ) ?? 0\n}\n\nfunction sessionNode(\n s: SessionSummary,\n list: SessionListState,\n statuses: SessionStatuses,\n pinned: ReadonlySet<SessionId>,\n archived: ReadonlySet<SessionId>,\n): SessionNode {\n const status = statuses.get(s.id)\n const pendingInteraction = visiblePendingKind(status?.pendingInteraction?.kind)\n return {\n id: s.id,\n title: sessionTitle(s),\n blank: s.blank,\n running: status?.running ?? s.running,\n runningSubagentCount: runningChildCount(list, s.id, statuses),\n completed: status?.completionUnread === true,\n pinned: !archived.has(s.id) && pinned.has(s.id),\n archived: archived.has(s.id),\n updatedAt: s.updatedAt,\n ...(pendingInteraction === undefined ? {} : { pendingInteraction }),\n }\n}\n\n/**\n * Derive the workspace browser groups with every session as a top-level row.\n *\n * Every group shows, except that the archived-only filter drops groups\n * without visible members; sessions populate under expanded groups with\n * pinned rows leading in the selected local order. Blank sessions are\n * excluded except for the selected provisional New Session row; archived\n * sessions keep their slots and appear per the archived filter. Content\n * search lives outside this derivation (see {@link deriveSearchResults}).\n * @param list - sessions list snapshot (`mainView` retention feeds containsCurrent).\n * @param workspaces - real Workspaces in Host group order with caller-projected Session order.\n * @param rowState - registry-global pin and archive sets plus the archived filter.\n * @param statuses - unified UI status by Session.\n * @param view - local expansion arrays.\n * @param waitingReviewSummary - dsh-gitea-dispatch waiting map (session id → waiting entry).\n * @param scheduleSummary - dsh-later schedule map (session id → schedule entry).\n * @returns group sections in render order.\n */\nexport function deriveGroups(\n list: SessionListState,\n workspaces: readonly WorkspaceView[],\n rowState: SessionRowState,\n statuses: SessionStatuses,\n view: TreeView,\n): GroupNode[] {\n const archived = new Set(rowState.archivedSessionIds)\n const pinned = new Set(rowState.pinnedSessionIds)\n const expandedGroups = new Set(view.expandedGroups)\n const current = mainSessionId(list)\n const currentGroup = current === undefined\n ? undefined\n : owningGroupKey(workspaces, current)\n const groups: GroupNode[] = []\n for (const g of groupByWorkspace(list, workspaces, archived, rowState.archivedFilter, view.ungroupedOrder)) {\n const expanded = expandedGroups.has(g.key)\n const members = sectionMembers(g.sessions, pinned, archived)\n .map(session => sessionNode(session, list, statuses, pinned, archived))\n groups.push({\n key: g.key,\n workspaceId: g.workspaceId,\n cwd: g.cwd,\n createdAt: g.createdAt,\n label: g.label,\n sessionCount: g.sessions.length,\n expanded,\n containsCurrent: g.key === currentGroup,\n // Sessions always included so HOC in WorkspaceBrowser.tsx can compute badge.\n // Rendering logic in WorkspaceBrowser.tsx still checks `expanded` before rendering rows.\n sessions: members,\n })\n }\n return groups\n}\n\n/**\n * Select complete flat-list membership, independently of archive visibility.\n * @param list - sessions list snapshot.\n * @returns known ordinary Session ids, including archives and only the current blank.\n */\nexport function sessionMemberIds(list: SessionListState): SessionId[] {\n return visibleSessionIds(list, [], 'show')\n}\n\n/**\n * Select visible flat-list members without deriving row presentation or ordering.\n * @param list - sessions list snapshot.\n * @param archivedSessionIds - registry-global archive set.\n * @param archivedFilter - archived-row visibility choice.\n * @returns known visible Session ids in list order, including ordinary forks and only the current blank.\n */\nexport function visibleSessionIds(\n list: SessionListState,\n archivedSessionIds: readonly SessionId[],\n archivedFilter: ArchivedFilter,\n): SessionId[] {\n const archived = new Set(archivedSessionIds)\n const current = mainSessionId(list)\n return list.ids.filter((id) => {\n const s = list.byId[id]\n return s !== undefined && sessionVisible(s, current, archived, archivedFilter)\n })\n}\n\n/**\n * Derive flat rows from the browser's complete ordered Session ids, with\n * pinned rows fronted ahead of the supplied order.\n * @param list - sessions list snapshot used to select the ids.\n * @param sessionIds - complete account members in the selected order, including hidden archives.\n * @param rowState - registry-global pin and archive sets plus the archived filter.\n * @param statuses - unified UI status by Session.\n * @returns flat rows in sectioned order with current status indicators.\n */\nexport function deriveFlat(\n list: SessionListState,\n sessionIds: readonly SessionId[],\n rowState: SessionRowState,\n statuses: SessionStatuses,\n): SessionNode[] {\n const archived = new Set(rowState.archivedSessionIds)\n const pinned = new Set(rowState.pinnedSessionIds)\n const current = mainSessionId(list)\n const members = sessionIds.flatMap((id) => {\n const session = list.byId[id]\n return session !== undefined && sessionVisible(session, current, archived, rowState.archivedFilter)\n ? [session]\n : []\n })\n return sectionMembers(members, pinned, archived)\n .map(session => sessionNode(session, list, statuses, pinned, archived))\n}\n\n/**\n * Merge immediate title/Workspace substring matches with ranked Host content\n * matches. Local rows lead newest-first, content-only rows retain backend\n * order, and duplicate sessions receive the backend snippet in place.\n * @param list - session metadata authority.\n * @param workspaces - Workspace membership and display labels.\n * @param query - caller text; surrounding whitespace is ignored.\n * @param archivedSessionIds - registry-global archive set (members match per the archived filter).\n * @param archivedFilter - archived-row visibility choice; search follows it.\n * @param statuses - unified UI status by Session.\n * @param content - ranked Host content-search page.\n * @param limit - protocol-owned maximum merged row count.\n * @returns bounded deduplicated flat rows and a refine-query hint bit.\n */\nexport function deriveSearchResults(\n list: SessionListState,\n workspaces: readonly WorkspaceView[],\n query: string,\n archivedSessionIds: readonly SessionId[],\n archivedFilter: ArchivedFilter,\n statuses: SessionStatuses,\n content: { items: readonly SessionSearchResultItem[]; hasMore: boolean },\n limit: number,\n): SearchResultSet {\n const q = query.trim().toLowerCase()\n if (q === '') return { items: [], hasMore: false }\n const archived = new Set(archivedSessionIds)\n const current = mainSessionId(list)\n\n const workspaceBySession = new Map<SessionId, string>()\n for (const workspace of workspaces) {\n for (const sessionId of workspace.sessionIds) {\n if (!workspaceBySession.has(sessionId)) workspaceBySession.set(sessionId, workspace.title)\n }\n }\n const labelOf = (summary: SessionSummary): string =>\n workspaceBySession.get(summary.id) ?? workspaceLabel(summary.cwd)\n const contentBySession = new Map<SessionId, SessionSearchResultItem>()\n for (const item of content.items) {\n if (!contentBySession.has(item.sessionId)) contentBySession.set(item.sessionId, item)\n }\n\n const local: SessionSummary[] = []\n for (const id of list.ids) {\n const summary = list.byId[id]\n // Blank placeholders never match a query (their canonical title displays\n // localized, so matching it would tie search to one language).\n if (summary === undefined || summary.blank || !sessionVisible(summary, current, archived, archivedFilter)) continue\n if (\n sessionTitle(summary).toLowerCase().includes(q)\n || labelOf(summary).toLowerCase().includes(q)\n ) {\n local.push(summary)\n }\n }\n const localById = new Map(local.map(summary => [summary.id, summary]))\n const orderedLocal = orderByRecency(local.map(summary => summary.id), list.byId)\n .map(id => localById.get(id) as SessionSummary)\n\n const ordered: SessionSummary[] = []\n const included = new Set<SessionId>()\n const include = (summary: SessionSummary): void => {\n if (included.has(summary.id)) return\n included.add(summary.id)\n ordered.push(summary)\n }\n for (const summary of orderedLocal) include(summary)\n for (const item of content.items) {\n const summary = list.byId[item.sessionId]\n if (summary !== undefined && !summary.blank && sessionVisible(summary, current, archived, archivedFilter)) include(summary)\n }\n\n return {\n items: ordered.slice(0, limit).map((summary) => {\n const match = contentBySession.get(summary.id)\n const status = statuses.get(summary.id)\n const pendingInteraction = visiblePendingKind(status?.pendingInteraction?.kind)\n return {\n id: summary.id,\n title: sessionTitle(summary),\n workspace: labelOf(summary),\n running: status?.running ?? summary.running,\n runningSubagentCount: runningChildCount(list, summary.id, statuses),\n ...(pendingInteraction === undefined\n ? {}\n : { pendingInteraction }),\n completed: status?.completionUnread === true,\n archived: archived.has(summary.id),\n ...match === undefined ? {} : { snippet: match.snippet },\n }\n }),\n hasMore: content.hasMore || ordered.length > limit,\n }\n}\n\n/** Normalize separators for comparison without interpreting POSIX backslashes as separators. */\nfunction folderPath(path: string): string {\n const windows = /^[A-Za-z]:[/\\\\]/.test(path) || path.startsWith('\\\\\\\\')\n return (windows ? path.replaceAll('\\\\', '/') : path).replace(/\\/+$/, '')\n}\n\n/**\n * Find the nearest registered ancestor, excluding the Workspace directory itself.\n * Paths use Host spelling; matching is case-sensitive, like Workspace identity.\n * @param path - Workspace directory.\n * @param parents - registered Workspace directory paths.\n * @returns the owning parent path, or undefined when no parent contains the Workspace.\n */\nexport function owningParentFolder(path: string, parents: readonly string[]): string | undefined {\n const child = folderPath(path)\n let owner: string | undefined\n let length = -1\n for (const parent of parents) {\n const root = folderPath(parent)\n if (root.length > length && child !== root && child.startsWith(`${root}/`)) {\n owner = parent\n length = root.length\n }\n }\n return owner\n}\n","/**\n * The workspace browser's viewing store: the session-list grouping mode,\n * persisted across reloads. Module level exports the factory only (a\n * module-level handle would pin the store identity across plugin reloads);\n * register() receives the factory and the browser derives its PropsStore\n * share from the return type.\n */\nimport { defineStore, type EngineStoreHandle } from '@deepseek-ai/dsh-client-store'\nimport type { SessionListState } from '@deepseek-ai/dsh-api-session-controller/client'\nimport type { SessionId } from '@deepseek-ai/dsh-session/types'\nimport { reconcileManualOrder, type ArchivedFilter, type SessionRowState } from './tree.ts'\n\n/** Browser-local order account for the hierarchy-free flat Session list. */\nexport const FLAT_SESSION_ORDER_KEY = '__flat_session_order__'\n\n/** Session-list grouping mode: sibling Workspace sections, a Workspace tree, or one flat list. */\nexport type SessionGroupBy = 'workspace' | 'workspace-tree' | 'flat'\n/** Session order: saved manual positions or current recency. */\nexport type SessionOrderBy = 'manual' | 'updated'\n\n/** Workspace browser viewing state persisted across surface remounts and reloads. */\ntype WorkspaceViewState = {\n groupBy: SessionGroupBy\n orderBy: SessionOrderBy\n /** Explicit group expansion keyed by Workspace identity, including descendants in tree mode. */\n groupExpansion: Record<string, boolean>\n /** Saved manual order per Workspace group plus the browser-local flat-list account. */\n sessionOrderByAccount: Record<string, string[]>\n /** Archived-row visibility; omitted in pre-filter v5 snapshots and read as 'default'. */\n archivedFilter?: ArchivedFilter\n}\n\ntype SessionOrderSource = {\n members: Readonly<Record<string, readonly SessionId[]>>\n summaries: SessionListState['byId']\n rowState: Pick<SessionRowState, 'pinnedSessionIds' | 'archivedSessionIds'>\n}\n\n/**\n * Annotation twin of the actions literal below (the export needs a declared\n * return type); drift fails assignability at the defineStore call.\n */\ntype WorkspaceViewActions = {\n setGroupBy: (draft: WorkspaceViewState, mode: SessionGroupBy) => void\n setOrderBy: (\n draft: WorkspaceViewState,\n mode: SessionOrderBy,\n initialOrders: Readonly<Record<string, readonly string[]>>,\n ) => void\n setGroupExpanded: (draft: WorkspaceViewState, key: string, expanded: boolean) => void\n retainAccountKeys: (draft: WorkspaceViewState, workspaceKeys: readonly string[]) => void\n syncSessionOrders: (\n draft: WorkspaceViewState,\n orders: Readonly<Record<string, readonly string[]>>,\n ) => void\n setSessionOrder: (\n draft: WorkspaceViewState,\n accountKey: string,\n order: readonly string[],\n initialOrders: Readonly<Record<string, readonly string[]>>,\n ) => void\n pinSessionOrder: (\n draft: WorkspaceViewState,\n sessionId: string,\n accountKeys: readonly string[],\n source: SessionOrderSource,\n ) => void\n setArchivedFilter: (draft: WorkspaceViewState, filter: ArchivedFilter) => void\n}\n\n/** Copy read-only projections into the persisted mutable store representation. */\nfunction copySessionOrders(\n orders: Readonly<Record<string, readonly string[]>>,\n): Record<string, string[]> {\n return Object.fromEntries(Object.entries(orders).map(([key, order]) => [key, [...order]]))\n}\n\n/**\n * Create the workspace browser viewing store handle.\n * @returns the store handle (spec + type + identity + factory in one).\n */\nexport function createWorkspaceViewStore(): EngineStoreHandle<WorkspaceViewState, WorkspaceViewActions> {\n return defineStore({\n init: (): WorkspaceViewState => ({\n groupBy: 'workspace',\n orderBy: 'updated',\n groupExpansion: {},\n sessionOrderByAccount: {},\n archivedFilter: 'default',\n }),\n persist: 'dsh.workspace.view.v5',\n actions: {\n setGroupBy: (d, mode: SessionGroupBy) => { d.groupBy = mode },\n setOrderBy: (d, mode: SessionOrderBy, initialOrders) => {\n if (mode === d.orderBy) return\n d.sessionOrderByAccount = mode === 'manual' ? copySessionOrders(initialOrders) : {}\n d.orderBy = mode\n },\n setGroupExpanded: (d, key: string, expanded: boolean) => { d.groupExpansion[key] = expanded },\n retainAccountKeys: (d, workspaceKeys: readonly string[]) => {\n const retained = new Set(workspaceKeys)\n d.groupExpansion = Object.fromEntries(\n Object.entries(d.groupExpansion).filter(([key]) => retained.has(key)),\n )\n d.sessionOrderByAccount = Object.fromEntries(\n Object.entries(d.sessionOrderByAccount).filter(([key]) => retained.has(key)),\n )\n delete (d as WorkspaceViewState & { sessionUpdatedAtByAccount?: unknown }).sessionUpdatedAtByAccount\n },\n syncSessionOrders: (d, orders) => {\n if (d.orderBy !== 'manual') return\n Object.assign(d.sessionOrderByAccount, copySessionOrders(orders))\n },\n setSessionOrder: (d, accountKey, order, initialOrders) => {\n if (d.orderBy === 'updated') d.sessionOrderByAccount = copySessionOrders(initialOrders)\n else Object.assign(d.sessionOrderByAccount, copySessionOrders(initialOrders))\n d.orderBy = 'manual'\n d.sessionOrderByAccount[accountKey] = [...order]\n },\n pinSessionOrder: (d, sessionId, accountKeys, source) => {\n const selected = new Set(accountKeys)\n d.sessionOrderByAccount = Object.fromEntries(Object.entries(source.members).map(([key, members]) => {\n const order = reconcileManualOrder(members, d.sessionOrderByAccount[key], source.summaries, source.rowState)\n return [key, selected.has(key) ? [sessionId, ...order.filter(id => id !== sessionId)] : order]\n }))\n },\n setArchivedFilter: (d, filter: ArchivedFilter) => { d.archivedFilter = filter },\n },\n })\n}\n\n/** The bound write set of one viewing-store instance (what the UiWorkspace service drives). */\nexport type WorkspaceViewStoreActions = ReturnType<ReturnType<typeof createWorkspaceViewStore>['create']>['actions']\n","/**\n * The complete account memberships a Pin order write reconciles against,\n * derived from the same Host snapshots the browser orders by, so the\n * UiWorkspace service can complete the write without the browser in the loop.\n */\nimport type { SessionListState } from '@deepseek-ai/dsh-api-session-controller/client'\nimport type { WorkspaceView } from '@deepseek-ai/dsh-api-workspace-controller/client'\nimport type { SessionId } from '@deepseek-ai/dsh-session/types'\nimport { FLAT_SESSION_ORDER_KEY } from './stores.ts'\nimport { owningGroupKey, sessionMemberIds, type SessionRowState, UNGROUPED_KEY } from './tree.ts'\n\n/** What `pinSessionOrder` reconciles a pinned Session's accounts against. */\nexport interface PinOrderSource {\n members: Readonly<Record<string, readonly SessionId[]>>\n summaries: SessionListState['byId']\n rowState: Pick<SessionRowState, 'pinnedSessionIds' | 'archivedSessionIds'>\n}\n\n/**\n * Every account's complete membership: each Workspace, Ungrouped, and the flat list.\n * @param workspaces - current Host Workspaces.\n * @param list - current Session list snapshot.\n * @param rowState - registry-global pin and archive sets.\n * @returns the order source for one pin write.\n */\nexport function pinOrderSource(\n workspaces: readonly WorkspaceView[],\n list: SessionListState,\n rowState: PinOrderSource['rowState'],\n): PinOrderSource {\n const accounted = new Set(workspaces.flatMap(workspace => workspace.sessionIds))\n return {\n members: Object.fromEntries([\n ...workspaces.map(workspace => [workspace.workspaceId, workspace.sessionIds] as const),\n [UNGROUPED_KEY, list.ids.filter(id => list.byId[id] !== undefined && !accounted.has(id))],\n [FLAT_SESSION_ORDER_KEY, sessionMemberIds(list)],\n ]),\n summaries: list.byId,\n rowState,\n }\n}\n\n/**\n * The accounts a pinned Session leads: its group (or Ungrouped) and the flat list.\n * @param workspaces - current Host Workspaces.\n * @param sessionId - the Session being pinned.\n * @returns the account keys `pinSessionOrder` fronts.\n */\nexport function pinOrderAccounts(workspaces: readonly WorkspaceView[], sessionId: SessionId): readonly string[] {\n return [owningGroupKey(workspaces, sessionId), FLAT_SESSION_ORDER_KEY]\n}\n","/** Workspace archive and directory UI capability. */\n\nimport { Service, type Context } from '@deepseek-ai/cordis'\nimport type { ClientRemote, DirectoryListing, RemoteFailure } from '@deepseek-ai/dsh-api-remotes/client'\nimport type {\n ISessions,\n SessionCreateError,\n SessionReference,\n SessionTarget,\n SessionListState,\n} from '@deepseek-ai/dsh-api-session-controller/client'\nimport { createSnapshotStore } from '@deepseek-ai/dsh-client-store'\nimport type { SubagentAddress } from '@deepseek-ai/dsh-subagent/client'\nimport type {\n IWorkspaces, WorkspaceId, WorkspaceSnapshot, WorkspaceView,\n} from '@deepseek-ai/dsh-api-workspace-controller/client'\nimport type { SessionId } from '@deepseek-ai/dsh-session/types'\nimport type {} from '@deepseek-ai/dsh-client-ui-layout/client'\nimport type { RowToast } from './contract/slots.ts'\nimport { pinOrderAccounts, pinOrderSource } from './pin-order.ts'\nimport type { WorkspaceViewStoreActions } from './stores.ts'\n\ninterface MainSelection {\n readonly sessionId?: SessionId\n readonly subagentAddress?: SubagentAddress\n}\n\n/** Workspace archive and directory operations consumed by Client UI domains. */\nexport interface UiWorkspace {\n /**\n * Select a Session and show its Conversation as one UI navigation action.\n * @param target - known Session identity or durable direct-parent subagent address to display.\n */\n openSession(target: SessionTarget): void\n /**\n * Connect a Workspace and open its Session unless a later navigation supersedes it.\n * @param workspaceId - target Workspace.\n * @param beforeOpen - optional synchronous preparation for the selected Session,\n * skipped after supersession; a throw aborts the open and releases the retained reference.\n * @returns completion; a superseded request may create a Session but does not open it.\n * @throws on failure; a refused creation is also shown through the Workspace\n * notice unless a later navigation or disposal superseded the request.\n */\n openWorkspace(workspaceId: WorkspaceId, beforeOpen?: (sessionId: SessionId) => void): Promise<void>\n /**\n * Fork a Session without changing the current selection.\n * @param sessionId - source Session.\n * @param onCreated - observer before the optional child-title update.\n * @returns the child SessionId after creation and inherited-title increment.\n */\n forkSession(sessionId: SessionId, onCreated?: (childId: SessionId) => void): Promise<SessionId>\n /**\n * Resolve the reusable or newly created blank Session for a Workspace.\n * @param workspaceId - target Workspace.\n * @returns a Session already addressable through the Session Controller.\n */\n connectWorkspace(workspaceId: WorkspaceId): Promise<SessionId>\n /**\n * Start a New Session flow and navigate to its Session; a creation the Host\n * refuses is shown through the Workspace notice and leaves the selection as it was.\n * @param workspaceId - explicit target; absent inherits the current or most recent Workspace.\n */\n startSession(workspaceId?: WorkspaceId): void\n /**\n * Archive a Session and clear it when it is the current selection.\n * @param sessionId - Session to archive.\n * @param options - `stopActivity` asks the Host to stop the Session's running work instead of refusing.\n */\n archiveSession(sessionId: SessionId, options?: { readonly stopActivity?: boolean }): Promise<void>\n /**\n * Unarchive a Session, restoring it to its recorded Workspace position.\n * @param sessionId - Session to unarchive.\n */\n unarchiveSession(sessionId: SessionId): Promise<void>\n /**\n * Pin a Session on the Host, then lead it in its accounts' saved orders\n * (its Workspace group or Ungrouped, and the flat list). The order write\n * reads the memberships current at completion, so reorders that landed\n * while the Host call was pending keep their positions.\n * @param sessionId - Session to pin.\n */\n pinSession(sessionId: SessionId): Promise<void>\n /**\n * Unpin a Session on the Host; saved positions stay as they are.\n * @param sessionId - Session to unpin.\n */\n unpinSession(sessionId: SessionId): Promise<void>\n /**\n * Open the Host-native directory picker.\n * @returns the selected directory, or null when cancelled.\n */\n pickDirectory(): Promise<string | null>\n /**\n * List one Host directory level.\n * @param path - directory path; absent selects the Host home.\n * @param signal - cancellation for a superseded scan.\n * @returns directory entries and breadcrumb ancestry.\n */\n listDirectory(path?: string, signal?: AbortSignal): Promise<DirectoryListing>\n /**\n * Create a child directory.\n * @param path - existing parent directory.\n * @param name - child directory name.\n * @returns created absolute path.\n */\n createDirectory(path: string, name: string): Promise<string>\n}\n\ndeclare module '@deepseek-ai/cordis' {\n interface Context {\n /** Cross-Controller Workspace navigation and directory UI capability. */\n uiWorkspace: UiWorkspace\n }\n}\n\n/** Structured directory failure exposed to directory UI consumers. */\nexport class DirectoryBrowseError extends Error {\n override readonly name = 'DirectoryBrowseError'\n\n /** @param rpcError - Host directory business failure. */\n constructor(readonly rpcError: RemoteFailure) {\n super(`directory browse failed: ${rpcError.code}: ${rpcError.message}`)\n }\n}\n\n/** Implements Workspace archive and directory UI operations. */\nclass UiWorkspaceService extends Service implements UiWorkspace {\n private readonly connecting = new Map<WorkspaceId, Promise<SessionId>>()\n private readonly lifetime = new AbortController()\n private readonly selection = createSnapshotStore<MainSelection>(\n {}, { persist: { name: 'dsh.sessions.current' } },\n )\n private mainReference: SessionReference | undefined\n\n /**\n * @param ctx - Client root Context.\n * @param directoryPicker - the directory-picking Remote namespace.\n * @param workspaces - pure Workspace Controller.\n * @param sessions - pure Session Controller.\n * @param view - the browser's viewing-store write set (one instance shared with its registration).\n * @param notify - show one notice through the Workspace notice channel.\n */\n constructor(\n ctx: Context,\n private readonly directoryPicker: ClientRemote['directoryPicker'],\n private readonly workspaces: IWorkspaces,\n private readonly sessions: ISessions,\n private readonly view: Pick<WorkspaceViewStoreActions, 'pinSessionOrder'>,\n private readonly notify: (toast: RowToast) => void,\n ) {\n super(ctx, 'uiWorkspace')\n ctx.effect(() => {\n const stop = this.watchNavigation()\n return () => {\n stop()\n this.lifetime.abort()\n const reference = this.mainReference\n this.mainReference = undefined\n reference?.release()\n }\n }, 'ui-workspace: Workspace navigation policy')\n }\n\n async connectWorkspace(workspaceId: WorkspaceId): Promise<SessionId> {\n const workspace = this.workspaces.list.getSnapshot().items\n .find(item => item.workspaceId === workspaceId)\n if (workspace === undefined) {\n throw new Error(`uiWorkspace.connectWorkspace: unknown workspace ${workspaceId}`)\n }\n const inflight = this.connecting.get(workspaceId)\n if (inflight !== undefined) return inflight\n\n const attempt = this.reuseOrCreateBlank(workspace)\n .finally(() => { this.connecting.delete(workspaceId) })\n this.connecting.set(workspaceId, attempt)\n return attempt\n }\n\n private reuseOrCreateBlank(workspace: WorkspaceView): Promise<SessionId> {\n const archived = this.workspaces.list.getSnapshot().archivedSessionIds\n const sessions = this.sessions.list.getSnapshot()\n for (const id of sessions.ids) {\n const summary = sessions.byId[id]\n if (summary === undefined || !summary.blank || summary.cwd !== workspace.path\n || !workspace.sessionIds.includes(id) || archived.includes(id)) continue\n return this.reuseBlank(workspace.workspaceId, id)\n }\n return this.sessions.create({ workspaceId: workspace.workspaceId })\n }\n\n private async reuseBlank(workspaceId: WorkspaceId, sessionId: SessionId): Promise<SessionId> {\n try {\n return await this.sessions.create({ workspaceId, sessionId })\n } catch (error: unknown) {\n if (sessionCreateErrorOf(error)?.rpcError.code !== 'session/writer-held') throw error\n return this.sessions.create({ workspaceId })\n }\n }\n\n openSession(target: SessionTarget): void {\n this.replaceMain(target, this.lifetime.signal, 'reveal')\n }\n\n async openWorkspace(workspaceId: WorkspaceId, beforeOpen?: (sessionId: SessionId) => void): Promise<void> {\n const navigation = AbortSignal.any([this.ctx.layout.beginNavigation(), this.lifetime.signal])\n let sessionId: SessionId\n try {\n sessionId = await this.connectWorkspace(workspaceId)\n } catch (error: unknown) {\n // Reported here, not in connectWorkspace: startup restoration calls that\n // directly and stays console-only.\n if (!navigation.aborted) this.notify({ kind: 'createFailed', message: creationFailureMessage(error) })\n throw error\n }\n if (navigation.aborted) return\n this.replaceMain(sessionId, navigation, 'reveal', beforeOpen)\n }\n\n async forkSession(sessionId: SessionId, onCreated?: (childId: SessionId) => void): Promise<SessionId> {\n return this.sessions.fork({ sessionId, increaseTitle: true, ...onCreated === undefined ? {} : { onCreated } })\n }\n\n startSession(workspaceId?: WorkspaceId): void {\n const workspace = this.workspaces.list.getSnapshot()\n const sessions = this.sessions.list.getSnapshot()\n const current = this.mainReference?.sessionId\n const currentWorkspaceId = current === undefined\n ? undefined\n : workspace.items.find(item => item.sessionIds.includes(current))?.workspaceId\n const recent = workspace.phase === 'ready' && sessions.phase === 'ready'\n ? recentWorkspace(workspace.items, sessions.byId)\n : undefined\n const target = workspaceId ?? currentWorkspaceId ?? recent\n if (target === undefined) {\n this.clearMain()\n return\n }\n void this.openWorkspace(target).catch(\n (reason: unknown) => { console.warn('new session failed:', reason) },\n )\n }\n\n async archiveSession(sessionId: SessionId, options: { readonly stopActivity?: boolean } = {}): Promise<void> {\n await this.workspaces.archiveSession(sessionId, options)\n if (this.mainReference?.sessionId === sessionId) this.clearMain()\n }\n\n async unarchiveSession(sessionId: SessionId): Promise<void> {\n await this.workspaces.unarchiveSession(sessionId)\n }\n\n async pinSession(sessionId: SessionId): Promise<void> {\n await this.workspaces.pinSession(sessionId)\n const { items, pinnedSessionIds, archivedSessionIds } = this.workspaces.list.getSnapshot()\n this.view.pinSessionOrder(\n sessionId,\n pinOrderAccounts(items, sessionId),\n pinOrderSource(items, this.sessions.list.getSnapshot(), { pinnedSessionIds, archivedSessionIds }),\n )\n }\n\n async unpinSession(sessionId: SessionId): Promise<void> {\n await this.workspaces.unpinSession(sessionId)\n }\n\n async pickDirectory(): Promise<string | null> {\n const result = await this.directoryPicker.pick()\n if (!result.ok) throw new Error(`directory picker failed: ${result.error.message}`)\n return result.value\n }\n\n async listDirectory(path?: string, signal?: AbortSignal): Promise<DirectoryListing> {\n const result = await this.directoryPicker.list(path, signal)\n if (!result.ok) throw new DirectoryBrowseError(result.error)\n return result.value\n }\n\n async createDirectory(path: string, name: string): Promise<string> {\n const result = await this.directoryPicker.createDirectory(path, name)\n if (!result.ok) throw new DirectoryBrowseError(result.error)\n return result.value\n }\n\n private watchNavigation(): () => void {\n let initial: 'waiting' | 'connecting' | 'done' = 'waiting'\n const reconcile = (): void => {\n if (this.lifetime.signal.aborted) return\n if (this.clearArchivedCurrent()) return\n if (initial !== 'waiting') return\n const workspace = this.workspaces.list.getSnapshot()\n const sessions = this.sessions.list.getSnapshot()\n if (workspace.phase !== 'ready' || sessions.phase !== 'ready') return\n if (this.mainReference !== undefined) {\n initial = 'done'\n return\n }\n initial = 'connecting'\n void this.restoreSelection(workspace, sessions).then(\n () => { initial = 'done' },\n (reason: unknown) => {\n if (this.lifetime.signal.aborted) return\n initial = 'waiting'\n console.warn('initial Session restoration failed:', reason)\n },\n )\n }\n\n const disposeWorkspaces = this.workspaces.list.subscribe(reconcile)\n const disposeSessions = this.sessions.list.subscribe(reconcile)\n reconcile()\n return () => {\n this.lifetime.abort()\n disposeSessions()\n disposeWorkspaces()\n }\n }\n\n private async restoreSelection(workspaces: WorkspaceSnapshot, sessions: SessionListState): Promise<void> {\n const saved = this.selection.getSnapshot()\n if (saved.subagentAddress !== undefined) {\n this.replaceMain(saved.subagentAddress, this.lifetime.signal, 'preserve')\n return\n }\n const summary = saved.sessionId === undefined ? undefined : sessions.byId[saved.sessionId]\n const workspace = summary === undefined ? undefined\n : workspaces.items.find(item => item.sessionIds.includes(summary.id))\n if (summary !== undefined && (!summary.blank || workspace === undefined)) {\n this.replaceMain(summary.id, this.lifetime.signal, 'preserve')\n return\n }\n const navigation = AbortSignal.any([this.ctx.layout.beginNavigation(), this.lifetime.signal])\n let sessionId: SessionId | undefined\n if (summary !== undefined && workspace !== undefined && summary.cwd === workspace.path\n && !workspaces.archivedSessionIds.includes(summary.id)) {\n sessionId = await this.reuseBlank(workspace.workspaceId, summary.id)\n }\n let target = workspace?.workspaceId ?? recentWorkspace(workspaces.items, sessions.byId)\n if (target === undefined && workspaces.items.length === 0 && sessions.ids.length === 0) {\n const prepared = await this.initializeDefaultWorkspace(navigation)\n if (navigation.aborted) return\n target = prepared?.workspaceId\n }\n if (sessionId === undefined && target !== undefined) sessionId = await this.connectWorkspace(target)\n if (sessionId !== undefined && !navigation.aborted) {\n this.replaceMain(sessionId, navigation, 'preserve')\n }\n }\n\n private async initializeDefaultWorkspace(signal: AbortSignal): Promise<WorkspaceView | undefined> {\n try {\n return await this.workspaces.initializeDefault(signal)\n } catch (_error: unknown) {\n if (!signal.aborted) this.notify({ kind: 'defaultWorkspaceFailed' })\n return undefined\n }\n }\n\n /** @returns true when an archived current selection was cleared. */\n private clearArchivedCurrent(): boolean {\n const current = this.mainReference?.sessionId\n if (current === undefined\n || !this.workspaces.list.getSnapshot().archivedSessionIds.includes(current)) return false\n this.clearMain()\n return true\n }\n\n private clearMain(): void {\n const previous = this.mainReference\n this.mainReference = undefined\n this.selection.set({})\n previous?.release()\n this.ctx.layout.selectPanel(null)\n }\n\n private replaceMain(\n target: SessionTarget,\n signal: AbortSignal,\n panel: 'reveal' | 'preserve',\n beforeOpen?: (sessionId: SessionId) => void,\n ): void {\n signal.throwIfAborted()\n const reference = this.sessions.retain(target, { source: 'mainView' })\n try {\n signal.throwIfAborted()\n beforeOpen?.(reference.sessionId)\n if (signal.aborted) {\n reference.release()\n return\n }\n const subagentAddress = typeof target === 'string'\n ? this.sessions.subagentAddress(reference.sessionId)\n : target\n this.selection.set({\n sessionId: reference.sessionId,\n ...(subagentAddress === undefined ? {} : { subagentAddress }),\n })\n } catch (error: unknown) {\n reference.release()\n throw error\n }\n const previous = this.mainReference\n this.mainReference = reference\n previous?.release()\n if (panel === 'reveal') this.ctx.layout.selectPanel(null)\n }\n\n}\n\n/**\n * `error` as the Session Controller's creation failure, or undefined when it\n * is not one. Client plugin bundles do not share error-class identity, so the\n * name decides.\n */\nfunction sessionCreateErrorOf(error: unknown): SessionCreateError | undefined {\n return error instanceof Error && error.name === 'SessionCreateError' ? error as SessionCreateError : undefined\n}\n\n/**\n * The words a failed Session creation is reported in: a Host refusal keeps its\n * stable code and message; any other failure keeps its own message.\n */\nfunction creationFailureMessage(error: unknown): string {\n const refused = sessionCreateErrorOf(error)\n if (refused !== undefined) return `${refused.rpcError.code}: ${refused.rpcError.message}`\n return error instanceof Error ? error.message : String(error)\n}\n\n/** Stable tie-breaking follows Host Workspace order. */\nfunction recentWorkspace(\n workspaces: readonly WorkspaceView[],\n sessions: SessionListState['byId'],\n): WorkspaceId | undefined {\n let selected: WorkspaceId | undefined\n let selectedTime = Number.NEGATIVE_INFINITY\n for (const workspace of workspaces) {\n let latest = Number.NEGATIVE_INFINITY\n for (const sessionId of workspace.sessionIds) {\n const session = sessions[sessionId]\n if (session !== undefined) latest = Math.max(latest, session.updatedAt)\n }\n if (latest === Number.NEGATIVE_INFINITY) latest = Date.parse(workspace.createdAt)\n if (selected === undefined || latest > selectedTime) {\n selected = workspace.workspaceId\n selectedTime = latest\n }\n }\n return selected\n}\n\nexport { UiWorkspaceService }\n","function r(e){var t,f,n=\"\";if(\"string\"==typeof e||\"number\"==typeof e)n+=e;else if(\"object\"==typeof e)if(Array.isArray(e)){var o=e.length;for(t=0;t<o;t++)e[t]&&(f=r(e[t]))&&(n&&(n+=\" \"),n+=f)}else for(f in e)e[f]&&(n&&(n+=\" \"),n+=f);return n}export function clsx(){for(var e,t,f=0,n=\"\",o=arguments.length;f<o;f++)(e=arguments[f])&&(t=r(e))&&(n&&(n+=\" \"),n+=t);return n}export default clsx;","/**\n * Fixed first-use Workspace naming, shared by the Host that creates the\n * directory and by browser consumers that label the resulting row. A pure fold\n * with no imports, so client bundles inline it instead of requesting a\n * module-table row this package does not publish.\n * @module @deepseek-ai/dsh-api-workspace-controller/default-workspace\n */\n/**\n * Leaf directory name of the first-use Workspace under\n * `<Documents>/deepseek-harness`. Language-neutral, so one installation keeps\n * one on-disk path across language switches. The registry derives the initial\n * title from this same segment, which is the title\n * {@link workspaceDisplayTitle} recognizes as automatic.\n */\nexport const DEFAULT_WORKSPACE_DIRECTORY = 'default-workspace';\n/**\n * The text one Workspace is labeled with. A Workspace still carrying the\n * automatic first-use title reads as the caller's localized default name; every\n * other title reads verbatim in every language. A title the user typed as\n * exactly {@link DEFAULT_WORKSPACE_DIRECTORY} is labeled as the default too;\n * nothing else depends on the distinction.\n * @param title - stored Workspace title.\n * @param localizedDefault - the default Workspace name in the active language.\n * @returns the title to display.\n */\nexport function workspaceDisplayTitle(title, localizedDefault) {\n return title === DEFAULT_WORKSPACE_DIRECTORY ? localizedDefault : title;\n}\n//# sourceMappingURL=default-workspace.js.map","/**\n * Fork-owned: aggregated live-status computation for collapsed workspace groups.\n *\n * Extracted from `tree.ts` so the upstream diff surface is minimal — the\n * vendored file only needs one import line and one field assignment to wire\n * the badge aggregation in. Everything fork-specific lives here.\n *\n * @module\n */\nimport type { GroupNode, SessionNode } from './tree.ts'\n\n// ── Types (structurally typed to avoid compile-time dependency on cross-plugin packages) ──\n\n/**\n * One session's waiting-review fact, as published by dsh-gitea-dispatch's\n * `useWaitingSummary()` (issue: dsh-gitea-dispatch#16).\n */\nexport interface WaitingReviewSummaryEntry {\n readonly prNumber: number\n readonly state: 'waiting' | 'overdue'\n}\n\n/** Session id → that session's waiting-review fact (no entry = not waiting). */\nexport type WaitingReviewSummaryMap = ReadonlyMap<string, WaitingReviewSummaryEntry>\n\n/**\n * One session's schedule fact, as published by dsh-later's `useScheduleSummary()`.\n */\nexport interface ScheduleSummaryEntry {\n readonly count: number\n readonly pausedCount: number\n readonly nextAt?: number\n readonly state: 'scheduled' | 'urgent' | 'overdue'\n}\n\n/** Session id → that session's schedule fact (no entry = no scheduled tasks). */\nexport type ScheduleSummaryMap = ReadonlyMap<string, ScheduleSummaryEntry>\n\n// ── Aggregated status ──\n\n/**\n * Aggregated live-session counts for one group, computed over all members so a\n * folded folder row can hint at hidden activity.\n */\nexport interface GroupLiveStatus {\n /** Members currently running. */\n running: number\n /** Members awaiting tool approval. */\n approval: number\n /** Members awaiting plan review. */\n planReview: number\n /** Members awaiting a question answer. */\n question: number\n /** Members finished and not yet opened (the green \"done\" reminder). */\n done: number\n /** Running direct children across members. */\n subagents: number\n /** Members with scheduled tasks (from dsh-later). */\n scheduledSessions: number\n /** Total scheduled tasks across members (including paused). */\n scheduledCount: number\n /** Highest-priority schedule state: overdue > urgent > scheduled. */\n scheduleState: 'scheduled' | 'urgent' | 'overdue' | undefined\n /** Members waiting for CI review of their PR (from dsh-gitea-dispatch). */\n waitingReviewCount: number\n /** Highest-priority waiting state across members: overdue > waiting. */\n waitingReviewState: 'waiting' | 'overdue' | undefined\n}\n\n/**\n * Zero-valued sentinel for {@link GroupLiveStatus}.\n *\n * Used when a group is expanded (badge is hidden, so aggregation is wasted\n * work) or when no cross-plugin data is available. Kept as a frozen constant\n * so the reference is stable across renders — `Object.is` comparisons in\n * React selectors never trigger spurious re-renders on it.\n */\nexport const EMPTY_LIVE_STATUS: GroupLiveStatus = Object.freeze({\n running: 0, approval: 0, planReview: 0, question: 0, done: 0, subagents: 0,\n scheduledSessions: 0, scheduledCount: 0, scheduleState: undefined,\n waitingReviewCount: 0, waitingReviewState: undefined,\n}) as GroupLiveStatus\n\n/**\n * Merge two {@link GroupLiveStatus} objects by summing counters and taking the\n * highest-priority state (overdue > urgent > scheduled for schedule; overdue > waiting\n * for waiting-review).\n *\n * Used for multi-level aggregation: when a parent group is collapsed, its badge\n * must reflect all descendant sessions, not just direct members.\n */\nexport function mergeLiveStatus(a: GroupLiveStatus, b: GroupLiveStatus): GroupLiveStatus {\n // Schedule state: overdue (3) > urgent (2) > scheduled (1) > undefined (0)\n const priorityOf = (s: 'scheduled' | 'urgent' | 'overdue' | undefined): number =>\n s === 'overdue' ? 3 : s === 'urgent' ? 2 : s === 'scheduled' ? 1 : 0\n const schedulePriorityA = priorityOf(a.scheduleState)\n const schedulePriorityB = priorityOf(b.scheduleState)\n const scheduleState = schedulePriorityA >= schedulePriorityB ? a.scheduleState : b.scheduleState\n\n // Waiting-review state: overdue > waiting > undefined\n const waitingPriorityA = a.waitingReviewState === 'overdue' ? 2 : a.waitingReviewState === 'waiting' ? 1 : 0\n const waitingPriorityB = b.waitingReviewState === 'overdue' ? 2 : b.waitingReviewState === 'waiting' ? 1 : 0\n const waitingReviewState = waitingPriorityA >= waitingPriorityB ? a.waitingReviewState : b.waitingReviewState\n\n return {\n running: a.running + b.running,\n approval: a.approval + b.approval,\n planReview: a.planReview + b.planReview,\n question: a.question + b.question,\n done: a.done + b.done,\n subagents: a.subagents + b.subagents,\n scheduledSessions: a.scheduledSessions + b.scheduledSessions,\n scheduledCount: a.scheduledCount + b.scheduledCount,\n scheduleState,\n waitingReviewCount: a.waitingReviewCount + b.waitingReviewCount,\n waitingReviewState,\n }\n}\n\n// ── Helpers ──\n\n/**\n * Strip the `session-` / `webhook-` prefix from a Session id.\n *\n * dsh-gitea-dispatch publishes its waiting map keyed by the host SessionId, but\n * its HTTP endpoints key by this normalized form. Accepting both here keeps the\n * badge working across that publisher's conventions without knowing which is in\n * play.\n */\nfunction stripSessionPrefix(id: string): string {\n return id.replace(/^(?:session|webhook)-/, '')\n}\n\n// ── Main computation ──\n\n/**\n * Fold every member row of a group into counts so a collapsed folder can hint at\n * hidden live sessions. Mirrors the session-row status priority (pending\n * outranks running outranks completed) at the counting level; labels resolve with\n * locale at render time.\n * @param nodes - member rows of the group.\n * @param sessionIds - the same members' Session ids (schedule and waiting facts are keyed by id).\n * @param waitingReviewSummary - dsh-gitea-dispatch waiting map, when that plugin is loaded.\n * @param scheduleSummary - dsh-later schedule map, when that plugin is loaded.\n */\nexport function summarizeGroupStatus(\n nodes: readonly SessionNode[],\n sessionIds: readonly string[],\n waitingReviewSummary?: WaitingReviewSummaryMap,\n scheduleSummary?: ScheduleSummaryMap,\n): GroupLiveStatus {\n let running = 0\n let approval = 0\n let planReview = 0\n let question = 0\n let done = 0\n let subagents = 0\n for (const n of nodes) {\n if (n.blank || n.archived) continue\n if (n.pendingInteraction === 'approval') { approval += 1; continue }\n if (n.pendingInteraction === 'plan-review') { planReview += 1; continue }\n if (n.pendingInteraction === 'question') { question += 1; continue }\n if (n.running) running += 1\n else if (n.completed) done += 1\n subagents += n.runningSubagentCount\n }\n\n // Aggregate schedule summary from dsh-later\n let scheduledSessions = 0\n let scheduledCount = 0\n let scheduleState: 'scheduled' | 'urgent' | 'overdue' | undefined = undefined\n\n if (scheduleSummary && sessionIds.length > 0) {\n let totalSessions = 0\n let totalCount = 0\n let highestPriority = 0 // 0=none, 1=scheduled, 2=urgent, 3=overdue\n\n for (const id of sessionIds) {\n const entry = scheduleSummary.get(id)\n if (entry) {\n totalSessions += 1\n totalCount += entry.count\n const priority = entry.state === 'overdue' ? 3 : entry.state === 'urgent' ? 2 : 1\n if (priority > highestPriority) highestPriority = priority\n }\n }\n\n scheduledSessions = totalSessions\n scheduledCount = totalCount\n scheduleState = highestPriority === 3 ? 'overdue' : highestPriority === 2 ? 'urgent' : highestPriority === 1 ? 'scheduled' : undefined\n }\n\n // Aggregate waiting-review summary from dsh-gitea-dispatch (its #16).\n //\n // Counts **members**, not PRs: one session waits on exactly one PR, and the\n // badge's number must mean \"how many sessions in this folder need attention\".\n // `overdue` outranks `waiting` for the dot color, mirroring the schedule rule.\n let waitingReviewCount = 0\n let waitingReviewState: 'waiting' | 'overdue' | undefined = undefined\n if (waitingReviewSummary && sessionIds.length > 0) {\n for (const id of sessionIds) {\n const entry = waitingReviewSummary.get(id) ?? waitingReviewSummary.get(stripSessionPrefix(id))\n if (entry === undefined) continue\n waitingReviewCount += 1\n if (entry.state === 'overdue') waitingReviewState = 'overdue'\n else if (waitingReviewState === undefined) waitingReviewState = 'waiting'\n }\n }\n\n return {\n running, approval, planReview, question, done, subagents,\n scheduledSessions, scheduledCount, scheduleState,\n waitingReviewCount, waitingReviewState,\n }\n}\n\n/**\n * Measure each group's own members, as the input to {@link aggregateGroupStatuses}.\n *\n * Every group is measured, expanded ones included. A folder row shows no badge while\n * it is expanded, but its sessions still need attention and a collapsed ancestor must\n * keep counting them — so expansion is a rendering fact, never an input to the\n * aggregation. Short-circuiting expanded groups to `EMPTY_LIVE_STATUS` (the shape this\n * had before the tree-wide aggregator existed, harmless while nothing aggregated) makes\n * every collapsed parent undercount by the size of its expanded descendants.\n *\n * @param groups - derived groups, each with its member rows already populated.\n * @param waitingReviewSummary - dsh-gitea-dispatch waiting map, when that plugin is loaded.\n * @param scheduleSummary - dsh-later schedule map, when that plugin is loaded.\n */\nexport function directStatusesForGroups(\n groups: readonly { key: string; sessions: readonly SessionNode[] }[],\n waitingReviewSummary?: WaitingReviewSummaryMap,\n scheduleSummary?: ScheduleSummaryMap,\n): Map<string, GroupLiveStatus> {\n const map = new Map<string, GroupLiveStatus>()\n for (const group of groups) {\n map.set(group.key, summarizeGroupStatus(\n group.sessions, group.sessions.map(s => s.id), waitingReviewSummary, scheduleSummary,\n ))\n }\n return map\n}\n\n/**\n * Fold every group's DIRECT status up the workspace tree, so a collapsed folder\n * counts every descendant session. A group's own row shows no badge while it is\n * expanded, but its sessions still need attention and its collapsed ancestor must\n * keep counting them — so the walk never depends on a group's expanded state.\n *\n * @param direct - each group's own-member status, keyed by group key.\n * @param childrenByParent - the rendered tree: parent key (`undefined` = roots) → children.\n * @returns aggregated status per group key: own members plus the whole subtree.\n */\nexport function aggregateGroupStatuses(\n direct: ReadonlyMap<string, GroupLiveStatus>,\n childrenByParent: ReadonlyMap<string | undefined, readonly { key: string }[]>,\n): Map<string, GroupLiveStatus> {\n const aggregated = new Map<string, GroupLiveStatus>()\n // Parentage comes from path-prefix matching, so a self- or mutual-parent edge is\n // representable; without this guard the fold would recurse forever and hang the sidebar.\n const visiting = new Set<string>()\n const fold = (key: string): GroupLiveStatus => {\n const cached = aggregated.get(key)\n if (cached !== undefined) return cached\n if (visiting.has(key)) return direct.get(key) ?? EMPTY_LIVE_STATUS\n visiting.add(key)\n let total = direct.get(key) ?? EMPTY_LIVE_STATUS\n for (const child of childrenByParent.get(key) ?? []) {\n total = mergeLiveStatus(total, fold(child.key))\n }\n visiting.delete(key)\n aggregated.set(key, total)\n return total\n }\n // Every listed child is folded, not just the roots: an unreachable group would\n // otherwise be missing from the map and lose its badge.\n for (const children of childrenByParent.values()) {\n for (const child of children) fold(child.key)\n }\n return aggregated\n}\n\n/**\n * A group row whose badge input is resolved: its own members plus its whole subtree.\n *\n * `GroupNode.liveStatus` is optional only because upstream never fills it — this\n * package's aggregator is the sole producer. Typing a rendered row as\n * `StatusedGroupNode` is what turns \"a row that skipped the aggregator\" into a compile\n * error instead of a folder that silently lost its badge, which is how the PR #10\n * regression reached main.\n */\nexport interface StatusedGroupNode extends GroupNode {\n liveStatus: GroupLiveStatus\n}\n\n/**\n * Attach each group's subtree-wide status, in derivation order. This is the producer\n * the sidebar renders from.\n *\n * Expanded groups carry their status too: their own row draws no badge (a decision\n * inside `groupLiveBadge`), but a collapsed ancestor still has to count them, so\n * expansion never suppresses the measurement.\n *\n * @param groups - derived rows, in the order they render.\n * @param direct - each group's own-member status, from {@link directStatusesForGroups}.\n * @param childrenByParent - the rendered tree: parent key (`undefined` = roots) → children.\n */\nexport function withAggregatedStatus(\n groups: readonly GroupNode[],\n direct: ReadonlyMap<string, GroupLiveStatus>,\n childrenByParent: ReadonlyMap<string | undefined, readonly GroupNode[]>,\n): StatusedGroupNode[] {\n const aggregated = aggregateGroupStatuses(direct, childrenByParent)\n // A group missing from the fold has neither measured members nor listed children,\n // so it is idle rather than unknown.\n return groups.map(group => ({ ...group, liveStatus: aggregated.get(group.key) ?? EMPTY_LIVE_STATUS }))\n}\n","/**\n * Fork-owned: aggregated status badge for collapsed workspace groups.\n *\n * Extracted from `Rows.tsx` so the upstream diff surface is minimal — the\n * vendored file only needs one import and one `<GroupBadge />` call to wire\n * the badge in. Everything fork-specific lives here.\n *\n * @module\n */\nimport type { ReactNode } from 'react'\nimport {\n IconClockOutlineRegular, IconListPenOutlineRegular, StateDot,\n} from '@deepseek-ai/dsh-client-ui-primitives'\nimport type { WorkspaceBrowserProps } from '../contract/slots.ts'\nimport type { GroupNode } from '../tree.ts'\nimport type { GroupLiveStatus } from '../group-status.ts'\nimport type { ResolvedBadgeSettings } from '../badge-settings.ts'\nimport css from './Rows.module.css'\n\n/** The standard locale seat, prop-passed from the browser root. */\ntype RowTranslate = WorkspaceBrowserProps['t']\n\n// ── Accessible label ──\n\n/**\n * Accessible label for a folded group's aggregated status, reusing the\n * session-row locale keys so both surfaces read identically.\n *\n * 按设置过滤:关掉的来源不出现在标签里(aria-label 与徽标视觉一致)。\n */\nexport function groupLiveLabel(s: GroupLiveStatus, t: RowTranslate, settings: ResolvedBadgeSettings): string {\n const parts: string[] = []\n if (settings.showPendingInBadge) {\n if (s.approval > 0) parts.push(`${s.approval} ${t('status.waitingApproval')}`)\n if (s.planReview > 0) parts.push(`${s.planReview} ${t('status.planReview')}`)\n if (s.question > 0) parts.push(`${s.question} ${t('status.waitingAnswer')}`)\n }\n if (settings.showRunningInBadge) {\n if (s.running > 0) parts.push(`${s.running} ${t('status.running')}`)\n if (s.subagents > 0) {\n parts.push(t(s.subagents === 1 ? 'status.subagentsRunning.one' : 'status.subagentsRunning.other', { n: s.subagents }))\n }\n }\n if (settings.showWaitingReviewInBadge && s.waitingReviewCount > 0) parts.push(`${s.waitingReviewCount} ${t('status.waitingReview')}`)\n if (settings.showScheduledInBadge && s.scheduledSessions > 0) parts.push(`${s.scheduledSessions} ${t('status.scheduled')}`)\n if (settings.showCompletedInBadge && s.done > 0) parts.push(`${s.done} ${t('status.completed')}`)\n return parts.join(' · ')\n}\n\n// ── Badge ──\n\n/**\n * Aggregated live-status badge for a folded folder row. Dots reuse StateDot so\n * colors match session rows (warning = pending, ongoing = running, done = completed).\n * Renders nothing while expanded or when nothing is pending/active/completed/scheduled/waiting.\n *\n * Count matches the dots: pending + active + completed + waiting-review + scheduled sessions.\n *\n * `settings` 按来源过滤:关掉的来源不画点、不计数、不进 aria-label、不参与「是否显示徽标」\n * 的判断。会话行自身的状态不受影响:那是行级状态,不是分组提示。\n */\nexport function groupLiveBadge(group: GroupNode, t: RowTranslate, settings: ResolvedBadgeSettings): ReactNode {\n const s = group.liveStatus\n if (group.expanded || s === undefined) return null\n const pending = settings.showPendingInBadge ? s.approval + s.planReview + s.question : 0\n const active = settings.showRunningInBadge ? s.running + s.subagents : 0\n const scheduled = settings.showScheduledInBadge ? s.scheduledSessions : 0\n const hasWaitingReview = settings.showWaitingReviewInBadge && s.waitingReviewCount > 0\n const completed = settings.showCompletedInBadge ? s.done : 0\n // 只在有 pending / active / 已完成 / 定时任务 / 等待评审时显示徽标\n if (pending === 0 && active === 0 && completed === 0 && scheduled === 0 && !hasWaitingReview) return null\n const label = groupLiveLabel(s, t, settings)\n const dots: ReactNode[] = []\n if (pending > 0) dots.push(<StateDot key=\"warn\" state=\"warning\" />)\n if (active > 0) dots.push(<StateDot key=\"run\" state=\"ongoing\" />)\n if (completed > 0) dots.push(<StateDot key=\"done\" state=\"done\" />)\n // 定时任务图标(紫色 #8b5cf6 与 dsh-later 定时徽标同源,浅深底对比均 >=3:1;\n // urgent 橙 / overdue 红走宿主 warn/error 语义令牌)。与等待评审**用不同图标**——\n // 两者同属\"在等\"的语义,只靠颜色区分对色盲用户不可用。\n if (scheduled > 0) {\n const stateColor = s.scheduleState === 'overdue' ? 'var(--dsw-alias-state-error-primary)' : s.scheduleState === 'urgent' ? 'var(--dsw-alias-state-warn-secondary)' : '#8b5cf6'\n dots.push(\n <span key=\"schedule\" style={{ color: stateColor, display: 'inline-flex', alignItems: 'center' }}>\n <IconClockOutlineRegular size={14} />\n </span>\n )\n }\n // 等待评审图标(琥珀色;超时转红)。数据来自 dsh-gitea-dispatch 的\n // useWaitingSummary()——本插件不自己轮询该端点(其 store 是唯一轮询方)。\n if (hasWaitingReview) {\n const stateColor = s.waitingReviewState === 'overdue' ? 'var(--dsw-alias-state-error-primary)' : 'var(--dsw-alias-state-warn-secondary)'\n dots.push(\n <span key=\"waiting-review\" style={{ color: stateColor, display: 'inline-flex', alignItems: 'center' }}>\n <IconListPenOutlineRegular size={14} />\n </span>\n )\n }\n // 数字统计 pending + active + 已完成 + 定时任务会话 + 等待评审会话(与 dot 一致)\n // P2-3: 数字上限 99+,避免大项目组徽标过宽。\n // P3-3: count < countThreshold 时省略数字(点已表达\"有东西\");设置项 countThreshold 可调。\n const count = pending + active + completed + scheduled + (hasWaitingReview ? s.waitingReviewCount : 0)\n const countLabel = count > 99 ? '99+' : count >= settings.countThreshold ? String(count) : ''\n // P2-2: 紧急状态(overdue/urgent)时添加脉冲动画类。\n const isUrgent = s.scheduleState === 'overdue' || s.scheduleState === 'urgent'\n || s.waitingReviewState === 'overdue'\n const badgeClass = isUrgent ? `${css.groupBadge} ${css.groupBadgeUrgent}` : css.groupBadge\n return (\n <span className={badgeClass} role=\"img\" aria-label={label} title={label}>\n {dots}\n {countLabel && <span className={css.groupBadgeCount}>{countLabel}</span>}\n </span>\n )\n}\n\n// ── Hover-card status lines ──\n\n/**\n * Build the status detail lines for the workspace hover card.\n *\n * Extracted so `WorkspaceHoverContent` in `Rows.tsx` only needs to map the\n * returned array — the fork-specific status→line logic lives here.\n *\n * 按设置过滤:关掉的来源不出现在明细行里;`showHoverDetails=false` 时整段返回空。\n */\nexport function hoverStatusLines(\n status: GroupLiveStatus | undefined,\n t: RowTranslate,\n settings: ResolvedBadgeSettings,\n): { state: 'warning' | 'ongoing' | 'done'; text: string }[] {\n const lines: { state: 'warning' | 'ongoing' | 'done'; text: string }[] = []\n if (status === undefined || !settings.showHoverDetails) return lines\n if (settings.showPendingInBadge) {\n if (status.approval > 0) lines.push({ state: 'warning', text: `${status.approval} ${t('status.waitingApproval')}` })\n if (status.planReview > 0) lines.push({ state: 'warning', text: `${status.planReview} ${t('status.planReview')}` })\n if (status.question > 0) lines.push({ state: 'warning', text: `${status.question} ${t('status.waitingAnswer')}` })\n }\n if (settings.showRunningInBadge) {\n if (status.running > 0) lines.push({ state: 'ongoing', text: `${status.running} ${t('status.running')}` })\n if (status.subagents > 0) {\n lines.push({\n state: 'ongoing',\n text: t(status.subagents === 1 ? 'status.subagentsRunning.one' : 'status.subagentsRunning.other', { n: status.subagents }),\n })\n }\n }\n if (settings.showWaitingReviewInBadge && status.waitingReviewCount > 0) {\n lines.push({ state: 'warning', text: `${status.waitingReviewCount} ${t('status.waitingReview')}` })\n }\n if (settings.showScheduledInBadge && status.scheduledSessions > 0) {\n lines.push({ state: 'warning', text: `${status.scheduledSessions} ${t('status.scheduled')}` })\n }\n if (settings.showCompletedInBadge && status.done > 0) lines.push({ state: 'done', text: `${status.done} ${t('status.completed')}` })\n return lines\n}\n","/**\n * Workspace browser tree row components (figma Cell set 14:3080): pure presentational —\n * all data and callbacks arrive via props. Hover swaps (folder->chevron,\n * time->ellipsis, action buttons) are CSS-only, and a session row's clipped\n * title marquees programmatically while the row is hovered. Workspace row\n * menus are visual-only except Rename/Delete. A Session row's \"...\" menu and\n * its hover buttons are the `sidebar.workspaces.session.menu.item` and\n * `sidebar.workspaces.session.row.action` lists, rendered through the\n * browser's `renderSlot` with the menu's open state as the occurrence's hook\n * context; this package's own actions are entries like any plugin's. The\n * session and workspace hover cards are suppressed while a menu is open.\n */\nimport { useEffect, useMemo, useRef, useState } from 'react'\nimport type { RefObject } from 'react'\nimport clsx from 'clsx'\nimport type { PropsRenderSlots } from '@deepseek-ai/dsh-client-ui-slots'\nimport {\n HoverCard, IconArchiveOutlineRegular, IconEditOutlineRegular,\n IconEllipsisOutlineRegular, IconFolderCloseRegular, IconFolderOpenRegular,\n IconNewChatOutlineRegular, IconPinFillRegular, IconTrashOutlineRegular,\n IconTriangleRightFillRegular, IconUnarchiveOutlineRegular, Menu, relativeTime, StateDot, Tooltip,\n} from '@deepseek-ai/dsh-client-ui-primitives'\nimport type { ShortcutCatalogEntry } from '@deepseek-ai/dsh-client-shortcuts/client'\nimport type { StateDotState } from '@deepseek-ai/dsh-client-ui-primitives'\nimport { abbreviateHomePath } from '@deepseek-ai/dsh-util-workspace-path'\nimport type { MenuOpenState, WorkspaceBrowserProps } from '../contract/slots.ts'\nimport type { GroupLiveStatus, GroupNode, SearchResultNode, SessionNode } from '../tree.ts'\nimport { groupLiveBadge, hoverStatusLines } from './GroupBadge.tsx'\nimport css from './Rows.module.css'\n\n/** The standard locale seat, prop-passed from the browser root. */\ntype RowTranslate = WorkspaceBrowserProps['t']\n\n/**\n * Child-seat renderer threaded from the browser root: the row's action lists,\n * its leading decoration, and its hover-card section. The leading seat is\n * rendered only while the row's primary state is idle, so a status dot and a\n * leading occupant never share the row; the hover seat only while the row's\n * card is open.\n */\ntype RowRenderSlots = PropsRenderSlots<\n | 'sidebar.workspaces.session.menu.item'\n | 'sidebar.workspaces.session.row.action'\n | 'sidebar.session.row.leading'\n | 'sidebar.session.row.hover'\n>['renderSlot']\n\n/** Row display title: blank rows show the localized New Session label. */\nfunction displayTitle(node: SessionNode, t: RowTranslate): string {\n return node.blank ? t('session.new') : (node.title || t('session.untitled'))\n}\n\n/* Overflow this small hides no meaningful tail; scrolling for it reads as an\n accidental jitter, so the title stays put. */\nconst MIN_TITLE_REVEAL_PX = 8\n\n/* Marquee travel speed: slow enough to read the text as it passes. */\nconst TITLE_MARQUEE_PX_PER_MS = 0.03\n\n/**\n * Place the title's scroll position and publish the stylesheet's fade-mask\n * hooks: `data-scrolled` while the title has left its start (left fade) and\n * `data-clipped` while text remains beyond the right edge (right fade).\n * @param title - the row's clipping title element.\n * @param left - scroll offset in CSS pixels.\n * @param range - the title's maximum scroll offset in CSS pixels.\n */\nfunction placeTitle(title: HTMLSpanElement, left: number, range: number): void {\n // jsdom implements no scrollTo; the lane's direct assignment is instant there\n // anyway, so both paths land on the same position.\n if (typeof title.scrollTo === 'function') title.scrollTo({ left, behavior: 'instant' })\n else title.scrollLeft = left\n if (left > 0) title.dataset.scrolled = ''\n else delete title.dataset.scrolled\n if (left < range) title.dataset.clipped = ''\n else delete title.dataset.clipped\n}\n\n/**\n * Return the title to its resting state: scrolled to the start with both fade\n * masks off, so the resting ellipsis renders at full strength.\n * @param title - the row's clipping title element.\n */\nfunction restTitle(title: HTMLSpanElement): void {\n if (typeof title.scrollTo === 'function') title.scrollTo({ left: 0, behavior: 'instant' })\n else title.scrollLeft = 0\n delete title.dataset.scrolled\n delete title.dataset.clipped\n}\n\n/**\n * Marquee a title wider than its one-line cell while its row is hovered: the\n * title clips its own text, so entering crawls it at a constant speed until the\n * far edge (a fork's incremented title, for example) is in view, then rests\n * there under the pointer. Overflow of at most {@link MIN_TITLE_REVEAL_PX}\n * stays put — a barely-clipped title moving a few pixels reads as jitter, not a\n * reveal. Leaving returns the title to the start in one step, because the\n * resting ellipsis and the narrowed cell would otherwise meet the text while it\n * travelled back. Reduced motion jumps to the far edge instead of crawling.\n * @param title - ref to the row's clipping title element.\n * @returns stable pointer enter/leave handlers for the row.\n */\nfunction useTitleMarquee(title: RefObject<HTMLSpanElement | null>): { enter: () => void; leave: () => void } {\n const frame = useRef(0)\n useEffect(() => () => { cancelAnimationFrame(frame.current) }, [])\n return useMemo(() => ({\n enter: (): void => {\n /* v8 ignore next -- defensive: the title span renders unconditionally. */\n if (title.current === null) return\n const element = title.current\n const range = element.scrollWidth - element.clientWidth\n if (range <= MIN_TITLE_REVEAL_PX) return\n if (window.matchMedia('(prefers-reduced-motion: reduce)').matches) {\n placeTitle(element, range, range)\n return\n }\n cancelAnimationFrame(frame.current)\n let previous: number | undefined\n let position = 0\n const step = (now: DOMHighResTimeStamp): void => {\n position += previous === undefined ? 0 : (now - previous) * TITLE_MARQUEE_PX_PER_MS\n previous = now\n placeTitle(element, Math.min(position, range), range)\n if (position < range) frame.current = requestAnimationFrame(step)\n }\n frame.current = requestAnimationFrame(step)\n },\n leave: (): void => {\n cancelAnimationFrame(frame.current)\n /* v8 ignore next -- defensive: the title span renders unconditionally. */\n if (title.current === null) return\n restTitle(title.current)\n },\n }), [title])\n}\n\n/** Localized compact relative time (\"刚刚\"/\"5分钟\" in zh, \"now\"/\"5min\" in en). */\nfunction timeLabel(updatedAt: number, now: number, t: RowTranslate): string {\n const { unit, n } = relativeTime(updatedAt, now)\n return unit === 'now' ? t('time.now') : t(`time.${unit}`, { n })\n}\n\n/** Hover-card variant: distances wrap in the ago template; the now bucket stays bare (no \"now ago\"). */\nfunction hoverTimeLabel(updatedAt: number, now: number, t: RowTranslate): string {\n const { unit, n } = relativeTime(updatedAt, now)\n return unit === 'now' ? t('time.now') : t('time.ago', { t: t(`time.${unit}`, { n }) })\n}\n\n/**\n * Absolute creation time through the dictionary's date template (the message\n * clock pattern): `toLocaleString` would follow the browser language, not the\n * app locale, and produce mixed-language text after a switch.\n */\nfunction createdLabel(createdAt: number, t: RowTranslate): string {\n const d = new Date(createdAt)\n const pad2 = (v: number): string => String(v).padStart(2, '0')\n const date = t('date.ymd', { y: d.getFullYear(), m: d.getMonth() + 1, d: d.getDate() })\n return t('hover.created', { time: `${date} ${pad2(d.getHours())}:${pad2(d.getMinutes())}` })\n}\n\n// groupLiveBadge and groupLiveLabel are fork-owned — imported from ./GroupBadge.tsx.\n\n/** Hover-card body: workspace title, display directory path, absolute creation time. */\nfunction WorkspaceHoverContent({ label, cwd, createdAt, status, settings, t }: {\n label: string\n cwd: string | undefined\n createdAt: number\n /** Aggregated member status, supplied only while the group is folded. */\n status: GroupLiveStatus | undefined\n /** 徽标设置:悬停明细按来源过滤;`showHoverDetails=false` 时整段为空。 */\n settings: import('../badge-settings.ts').ResolvedBadgeSettings\n t: RowTranslate\n}) {\n // Fork-owned: status detail lines computed by GroupBadge.tsx.\n const lines = hoverStatusLines(status, t, settings)\n return (\n <div className={css.hoverContent}>\n <div className={css.hoverTitle}>{label}</div>\n <div className={css.hoverPath}>{cwd}</div>\n <div className={css.hoverTime}>{createdLabel(createdAt, t)}</div>\n {lines.map(line => (\n <div className={css.hoverStatus} key={line.text}>\n <StateDot state={line.state} />\n <span>{line.text}</span>\n </div>\n ))}\n </div>\n )\n}\n\n/**\n * Row drag wiring supplied by the tree owner. `drop` reports the half of the\n * row where the pointer released so the owner can resolve an insert anchor.\n */\nexport interface RowDragProps {\n /** Start dragging this row. */\n start: () => void\n /** A compatible row drag is in flight. */\n active: boolean\n /** Current marker on this row: insert line above, below, or none. */\n marker: 'before' | 'after' | null\n /** Report the hovered half while a compatible drag passes over this row. */\n hover: (half: 'before' | 'after') => void\n drop: (half: 'before' | 'after') => void\n end: () => void\n}\n\n/** Drag lifecycle owned by a workspace row; its enclosing group owns hit testing. */\ninterface WorkspaceRowDragProps {\n start: () => void\n end: () => void\n}\n\n/** Pointer-position half of a row (insert line above or below). */\nfunction rowHalf(e: { clientY: number; currentTarget: HTMLElement }): 'before' | 'after' {\n const rect = e.currentTarget.getBoundingClientRect()\n return e.clientY < rect.top + rect.height / 2 ? 'before' : 'after'\n}\n\n/**\n * Project (workspace) header row: folder + title;\n * hover reveals the chevron and create button, and dwelling on a real\n * Workspace shows its hover card (the ungrouped bucket has none).\n * `containsCurrent` arrives on the node (derivation fact, no renderer scan).\n * @param props.group - derived group node.\n * @param props.containsCurrentDescendant - highlight an ancestor even when its subtree is collapsed.\n * @param props.onToggle - expand/collapse the group.\n * @param props.onCreate - start a frontend Session inside this Workspace.\n * @param props.drag - optional workspace-row drag wiring.\n * @param props.home - host account home for POSIX hover-path abbreviation.\n * @param props.t - the browser root's locale seat.\n * @returns the row element.\n */\nexport function ProjectRowItem({ group, containsCurrentDescendant = false, onToggle, onCreate, actions, drag, home, newShortcut, settings, t }: {\n group: GroupNode\n newShortcut?: ShortcutCatalogEntry | undefined\n containsCurrentDescendant?: boolean\n onToggle: () => void\n onCreate: () => void\n /** Real-Workspace actions; absent for the ungrouped bucket (no menu shown). */\n actions?: { rename: () => void; delete: () => void } | undefined\n /** Present only for real Workspace rows in the grouped view. */\n drag?: WorkspaceRowDragProps | undefined\n /** Host account home; POSIX home-rooted hover paths display as `~`. */\n home?: string | undefined\n /** 徽标设置:各来源显隐、悬停明细、数字样式。 */\n settings: import('../badge-settings.ts').ResolvedBadgeSettings\n t: RowTranslate\n}) {\n const row = group\n // The ungrouped bucket has no workspace title: its label is dictionary copy.\n const label = row.workspaceId === undefined ? t('group.ungrouped') : row.label\n const active = containsCurrentDescendant || (group.expanded && group.containsCurrent)\n const [menuOpen, setMenuOpen] = useState(false)\n const workspaceMenuItems = [\n { id: 'rename', label: t('rename'), icon: <IconEditOutlineRegular /> },\n { id: 'delete', label: t('delete.workspace'), icon: <IconTrashOutlineRegular />, danger: true },\n ]\n const ownRow = (\n <div\n className={clsx(css.projectRow, menuOpen && css.menuOpen)}\n data-row-key={`workspace:${group.key}`}\n role=\"treeitem\"\n aria-expanded={row.expanded}\n onClick={onToggle}\n draggable={drag !== undefined}\n onDragStart={drag === undefined\n ? undefined\n : (e) => {\n e.dataTransfer.effectAllowed = 'move'\n e.dataTransfer.setData('text/plain', row.key)\n drag.start()\n }}\n onDragEnd={drag?.end}\n >\n <span className={clsx(css.slot, css.folder, active && css.folderActive)}>\n {row.expanded ? <IconFolderOpenRegular /> : <IconFolderCloseRegular />}\n </span>\n <span className={clsx(css.slot, css.chevron)}>\n <IconTriangleRightFillRegular className={clsx(css.arrow, row.expanded && css.arrowOpen)} />\n </span>\n <span className={css.projectText}>\n <span className={css.title}>{label}</span>\n </span>\n {groupLiveBadge(group, t, settings)}\n <span className={css.rowActions}>\n {actions !== undefined && (\n <Menu\n open={menuOpen}\n onClose={() => { setMenuOpen(false) }}\n items={workspaceMenuItems}\n onSelect={(id) => {\n setMenuOpen(false)\n // Unknown ids leave before the dispatch: a future menu row must\n // not inherit the destructive branch as an else fallback.\n /* v8 ignore next -- Menu can emit only the rename and delete rows supplied above. */\n if (id !== 'rename' && id !== 'delete') return\n if (id === 'rename') actions.rename()\n else actions.delete()\n }}\n portal\n closeOnPointerLeave\n anchor={(\n <button\n type=\"button\"\n className={css.iconButton}\n aria-label={t('actions.workspace.aria', { name: label })}\n onClick={(e) => { e.stopPropagation(); setMenuOpen(v => !v) }}\n >\n <IconEllipsisOutlineRegular />\n </button>\n )}\n />\n )}\n <Tooltip label={t('actions.newSession')} shortcutKeys={newShortcut?.keys} side=\"bottom\" align=\"end\" delayMs={500}>\n <button\n type=\"button\"\n className={css.iconButton}\n aria-keyshortcuts={newShortcut?.aria}\n aria-label={t('actions.newSession.aria', { name: label })}\n onClick={(e) => { e.stopPropagation(); onCreate() }}\n >\n <IconNewChatOutlineRegular />\n </button>\n </Tooltip>\n </span>\n </div>\n )\n // The ungrouped bucket has no backing Workspace: no card to show.\n if (row.createdAt === undefined) return ownRow\n return (\n <HoverCard\n anchor={ownRow}\n content={<WorkspaceHoverContent\n label={row.label}\n cwd={row.cwd === undefined ? undefined : abbreviateHomePath(row.cwd, home)}\n createdAt={row.createdAt}\n status={row.expanded ? undefined : row.liveStatus}\n settings={settings}\n t={t}\n />}\n openDelayMs={800}\n disabled={menuOpen}\n copyText={row.cwd}\n copyLabel={t('copy')}\n copiedLabel={t('hover.copied')}\n />\n )\n}\n\n/* v8 ignore next 3 -- closed-union backstop; only reached if the status is forged */\nfunction assertNever(value: never): never {\n throw new Error(`unknown pending interaction: ${String(value)}`)\n}\n\ninterface SessionStatus {\n state: StateDotState\n label: string\n /** Compact text that replaces the Session row's update time. */\n trailingLabel?: string\n}\n\n/**\n * Session status presentation; pending interaction is primary and live activity\n * outranks completion reminders.\n */\nfunction sessionStatuses(\n node: Pick<SessionNode, 'pendingInteraction' | 'running' | 'runningSubagentCount' | 'completed'>,\n t: RowTranslate,\n): readonly [SessionStatus, ...SessionStatus[]] {\n const subagents: SessionStatus | undefined = node.runningSubagentCount === 0\n ? undefined\n : {\n state: 'ongoing',\n label: t(\n node.runningSubagentCount === 1\n ? 'status.subagentsRunning.one'\n : 'status.subagentsRunning.other',\n { n: node.runningSubagentCount },\n ),\n }\n let pending: SessionStatus | undefined\n switch (node.pendingInteraction) {\n case 'approval':\n pending = {\n state: 'warning',\n label: t('status.waitingApproval'),\n trailingLabel: t('status.compact.approval'),\n }\n break\n case 'plan-review':\n pending = {\n state: 'warning',\n label: t('status.planReview'),\n trailingLabel: t('status.compact.planReview'),\n }\n break\n case 'question':\n pending = {\n state: 'warning',\n label: t('status.waitingAnswer'),\n trailingLabel: t('status.compact.answer'),\n }\n break\n case undefined: break\n /* v8 ignore next -- closed PendingInteractionStatus union */\n default: return assertNever(node.pendingInteraction)\n }\n if (pending !== undefined) return subagents === undefined ? [pending] : [pending, subagents]\n if (node.running) {\n const primary: SessionStatus = { state: 'ongoing', label: t('status.running') }\n return subagents === undefined ? [primary] : [primary, subagents]\n }\n if (subagents !== undefined) return [subagents]\n if (node.completed) return [{ state: 'done', label: t('status.completed') }]\n return [{ state: 'idle', label: t('status.idle') }]\n}\n\n/** Primary status dot plus every status's screen-reader label, shared by the search and session rows. */\nfunction SessionStatusDots({ statuses }: { statuses: readonly [SessionStatus, ...SessionStatus[]] }) {\n return (\n <>\n <StateDot state={statuses[0].state} />\n {statuses.map(status => (\n <span className={css.visuallyHidden} key={status.label}>{status.label}</span>\n ))}\n </>\n )\n}\n\n/** Non-interactive pinned-row marker; the enclosing row remains the only action. */\nfunction PinnedIndicator({ t }: { t: RowTranslate }) {\n const label = t('row.pinned')\n return (\n <span className={css.pinIndicator} role=\"img\" aria-label={label} title={label}>\n <IconPinFillRegular size={14} />\n </span>\n )\n}\n\n/**\n * Hover-card body: full title, relative time, the Session's own scheduled-task\n * section, and every relevant live status. The task section sits above the\n * status lines so they stay the card's trailing status line.\n */\nfunction SessionHoverContent({ node, now, renderSlot, t }: {\n node: SessionNode\n now: number\n renderSlot: RowRenderSlots\n t: RowTranslate\n}) {\n // On archived rows the archived line already says the session is inactive,\n // so resting statuses (idle/completed) drop; live activity still shows.\n const statuses = sessionStatuses(node, t)\n .filter(status => !(node.archived && (status.state === 'done' || status.state === 'idle')))\n return (\n <div className={css.hoverContent}>\n <div className={css.hoverTitle}>{displayTitle(node, t)}</div>\n {/* Same placeholder rule as the row's trailing cell: no timestamp\n before the first prompt. */}\n {!node.blank && <div className={css.hoverTime}>{hoverTimeLabel(node.updatedAt, now, t)}</div>}\n {renderSlot('sidebar.session.row.hover', { sessionId: node.id })}\n {statuses.map(status => (\n <div className={css.hoverStatus} key={status.label}>\n <StateDot state={status.state} />\n <span>{status.label}</span>\n </div>\n ))}\n {node.archived && (\n <div className={clsx(css.hoverStatus, css.hoverArchived)}>\n <IconArchiveOutlineRegular size={14} />\n <span>{t('row.archived')}</span>\n </div>\n )}\n </div>\n )\n}\n\n/**\n * One flat search result: title, Workspace context, and optional content\n * excerpt. Search navigation opens the session only; it does not address an\n * event inside the conversation. Archived rows carry a hover unarchive\n * button, because search is where the filter surfaces them for recovery.\n * @param props.result - merged local/content search row.\n * @param props.currentId - selected session id.\n * @param props.onOpen - open the selected session.\n * @param props.onUnarchive - unarchive an archived result row.\n * @param props.t - Workspace-browser translation seat.\n * @returns the result row.\n */\nexport function SearchResultItem({ result, currentId, onOpen, onUnarchive, t }: {\n result: SearchResultNode\n currentId: string | undefined\n onOpen: (id: SearchResultNode['id']) => void\n onUnarchive: (id: SearchResultNode['id']) => void\n t: RowTranslate\n}) {\n const selected = result.id === currentId\n const statuses = sessionStatuses(result, t)\n const primaryStatus = statuses[0]\n return (\n <div\n className={clsx(css.searchResultRow, selected && css.selected, result.archived && css.archived)}\n role=\"treeitem\"\n aria-selected={selected}\n aria-description={result.archived ? t('toast.archivedNotOpenable') : undefined}\n onClick={() => { onOpen(result.id) }}\n >\n <span className={css.searchResultHeading}>\n {/* Like session rows, the leading slot owns every row marker; on\n archived rows it stays blank — the grayed row carries the\n archived look. */}\n <span className={css.slot}>\n {!result.archived && primaryStatus.state !== 'idle' && (\n <SessionStatusDots statuses={statuses} />\n )}\n </span>\n <span className={css.searchResultTitle}>{result.title || t('session.untitled')}</span>\n {result.archived && (\n <span className={css.rowActions}>\n <Tooltip label={t('actions.unarchive')} side=\"bottom\" align=\"end\" delayMs={500}>\n <button\n type=\"button\"\n className={css.iconButton}\n aria-label={t('menu.unarchiveSession')}\n onClick={(e) => { e.stopPropagation(); onUnarchive(result.id) }}\n >\n <IconUnarchiveOutlineRegular size={14} />\n </button>\n </Tooltip>\n </span>\n )}\n </span>\n <span className={css.searchResultMeta}>\n <span className={css.searchResultWorkspace}>{result.workspace || t('group.ungrouped')}</span>\n {result.snippet !== undefined && (\n <span className={css.searchResultSnippet}>{result.snippet}</span>\n )}\n </span>\n </div>\n )\n}\n\n/**\n * One top-level 32px session row: leading 16px cell (status dot, or the\n * leading seat while the row's primary state is idle), title, relative time or\n * compact pending label, and the row actions menu. A row that owns a state dot\n * keeps that cell and renders no seat, so an ambient automation mark never\n * appears beside the row's own state dot. An archived row keeps the cell blank:\n * neither marker renders there, and its live status stays on the hover card.\n * @param props.node - derived session node.\n * @param props.currentId - selected session id (row highlight).\n * @param props.now - epoch ms for relative-time formatting.\n * @param props.onOpen - open a session by id.\n * @param props.onRenameRequest - open the rename dialog from a title double-click (id + current title).\n * @param props.renderSlot - child-seat renderer for the row's action lists\n * (`sidebar.workspaces.session.menu.item` / `sidebar.workspaces.session.row.action`),\n * its leading decoration, and its hover-card section.\n * @param props.onReveal - scroll this row into view after search navigation, then acknowledge it.\n * @param props.drag - optional row-drag target wiring; blank rows cannot start a drag.\n * @param props.t - the browser root's locale seat.\n * @returns the session row.\n */\nexport function SessionNodeItem({\n node, currentId, now, onOpen, onRenameRequest, renderSlot, onReveal, drag, t,\n}: {\n node: SessionNode\n currentId: string | undefined\n now: number\n onOpen: (id: SessionNode['id']) => void\n /** Open the rename dialog from a title double-click (id + current title). */\n onRenameRequest: (id: SessionNode['id'], currentTitle: string) => void\n /** Scroll this row into view after search navigation, then acknowledge it. */\n onReveal?: (() => void) | undefined\n /** Present on reorderable-list rows so every row can remain a drop target. */\n drag?: RowDragProps | undefined\n t: RowTranslate\n} & PropsRenderSlots<\n | 'sidebar.workspaces.session.menu.item'\n | 'sidebar.workspaces.session.row.action'\n | 'sidebar.session.row.leading'\n | 'sidebar.session.row.hover'\n>) {\n const row = node\n const title = displayTitle(node, t)\n const selected = node.id === currentId\n const statuses = sessionStatuses(node, t)\n const primaryStatus = statuses[0]\n const showStatus = primaryStatus.state !== 'idle'\n // Archived rows hold their in-place grayed slot, so manual reorder cannot\n // move them. Pinned rows drag within the pinned block: the browser gates\n // their drop targets to fellow pinned rows.\n const draggable = drag !== undefined && !row.blank && !row.archived\n const [menuOpen, setMenuOpen] = useState(false)\n // The menu's open state, bound into the row entries' `useMenuOpenState` hook.\n const menuOpenState = useMemo((): MenuOpenState => [menuOpen, setMenuOpen], [menuOpen])\n const rowRef = useRef<HTMLDivElement>(null)\n const titleRef = useRef<HTMLSpanElement>(null)\n const marquee = useTitleMarquee(titleRef)\n useEffect(() => {\n if (onReveal === undefined) return\n rowRef.current?.scrollIntoView({ block: 'nearest' })\n onReveal()\n }, [onReveal])\n // Figma session cell: pad 8, status slot 16, then a 4px title gap.\n const ownRow = (\n <div\n ref={rowRef}\n data-row-key={`session:${node.id}`}\n className={clsx(\n css.sessionRow, selected && css.selected, menuOpen && css.menuOpen,\n row.archived && css.archived,\n drag?.marker === 'before' && css.dropBefore, drag?.marker === 'after' && css.dropAfter,\n )}\n role=\"treeitem\"\n aria-selected={selected}\n aria-description={row.archived ? t('toast.archivedNotOpenable') : undefined}\n onClick={() => { onOpen(node.id) }}\n onPointerEnter={marquee.enter}\n onPointerLeave={marquee.leave}\n draggable={draggable}\n onDragStart={!draggable\n ? undefined\n : (e) => {\n e.dataTransfer.effectAllowed = 'move'\n e.dataTransfer.setData('text/plain', node.id)\n drag.start()\n }}\n onDragEnd={!draggable ? undefined : drag.end}\n onDragOver={drag === undefined\n ? undefined\n : (e) => {\n if (!drag.active) return\n e.preventDefault()\n e.dataTransfer.dropEffect = 'move'\n drag.hover(rowHalf(e))\n }}\n onDrop={drag === undefined\n ? undefined\n : (e) => {\n if (!drag.active) return\n e.preventDefault()\n drag.drop(rowHalf(e))\n }}\n >\n {/* Pending interaction and own or descendant activity outrank the\n finished-but-unviewed reminder, which returns after activity stops\n and is cleared by opening the session. Archived rows keep the slot\n blank — the grayed row carries the archived look — and their live\n status stays on the hover card only. */}\n <span className={css.slot}>\n {!row.archived && !row.blank && (showStatus\n ? <SessionStatusDots statuses={statuses} />\n : renderSlot('sidebar.session.row.leading', { sessionId: node.id }))}\n </span>\n <span\n ref={titleRef}\n className={css.title}\n onDoubleClick={row.blank\n ? undefined\n : (e) => { e.stopPropagation(); onRenameRequest(node.id, row.title) }}\n >\n {title}\n </span>\n {/* A blank New Session row is a provisional placeholder: nothing has\n happened in it yet, so a \"now\" timestamp and the row verbs\n (rename/fork/archive) would all act on content that does not\n exist — both trailing cells stay off until the first prompt. */}\n {!row.blank && (\n <span\n className={css.time}\n aria-hidden={primaryStatus.trailingLabel === undefined ? undefined : true}\n >\n {primaryStatus.trailingLabel ?? timeLabel(row.updatedAt, now, t)}\n </span>\n )}\n {/* Trails the time so the marker occupies the same right-edge cell as\n the hover pin button that replaces it. */}\n {row.pinned && !row.archived && <PinnedIndicator t={t} />}\n {/* The strip's clicks stay in the strip: the trigger and every\n row.action entry act without also opening the row, so an entry's\n button needs no propagation handling of its own. */}\n {!row.blank && (\n <span className={css.rowActions} onClick={(e) => { e.stopPropagation() }}>\n <Menu\n open={menuOpen}\n onClose={() => { setMenuOpen(false) }}\n portal\n closeOnPointerLeave\n anchor={(\n <button\n type=\"button\"\n className={css.iconButton}\n aria-label={t('actions.session.aria', { name: title })}\n onClick={() => { setMenuOpen(v => !v) }}\n >\n <IconEllipsisOutlineRegular />\n </button>\n )}\n >\n {renderSlot(\n 'sidebar.workspaces.session.menu.item',\n { sessionId: node.id, displayTitle: row.title },\n { hookContext: menuOpenState },\n )}\n </Menu>\n {renderSlot('sidebar.workspaces.session.row.action', { sessionId: node.id, displayTitle: row.title })}\n </span>\n )}\n </div>\n )\n return (\n <HoverCard\n anchor={ownRow}\n content={<SessionHoverContent node={node} now={now} renderSlot={renderSlot} t={t} />}\n openDelayMs={800}\n disabled={menuOpen || drag?.active === true}\n copyText={row.blank || row.title === '' ? undefined : row.title}\n copyLabel={t('copy')}\n copiedLabel={t('hover.copied')}\n />\n )\n}\n","/** React-commit-driven movement and entry/exit fades for the sidebar's keyed rows. */\nimport { Component, createRef, type ReactNode } from 'react'\nimport css from './AnimatedRows.module.css'\n\nconst ROW_FADE_MS = 100\nconst ROW_GLIDE_MS = 200\n\ninterface AnimatedRowsProps {\n children: ReactNode\n className: string\n label: string\n /** Unique DOM-order keys matching the rendered data-row-key attributes. */\n rowKeys: readonly string[]\n ready: boolean\n /** Changes that replace the view or reveal hidden rows settle immediately. */\n resetKey: string\n}\n\ninterface RowPosition {\n element: HTMLElement\n rect: DOMRect\n opacity: number\n}\n\ninterface RowSnapshot {\n positions: Map<string, RowPosition>\n removed: Map<string, RowPosition>\n}\n\nfunction sameRows(previous: AnimatedRowsProps, next: AnimatedRowsProps): boolean {\n return previous.rowKeys.length === next.rowKeys.length\n && previous.rowKeys.every((key, index) => key === next.rowKeys[index])\n}\n\nfunction intersects(row: DOMRect, viewport: DOMRect): boolean {\n return row.bottom > viewport.top && row.top < viewport.bottom\n && row.right > viewport.left && row.left < viewport.right\n}\n\n/**\n * Animates keyed sidebar rows only when their rendered membership or order changes.\n * Motion starts after the first pointer or keyboard input inside the mounted list.\n * The parent supplies a positioned container for the inert exit overlay.\n */\nexport class AnimatedRows extends Component<AnimatedRowsProps> {\n private armed = false\n private readonly list = createRef<HTMLDivElement>()\n private readonly overlay = createRef<HTMLDivElement>()\n private readonly movements = new Map<HTMLElement, Animation>()\n private readonly exits = new Map<string, { element: HTMLElement; animation: Animation }>()\n\n override getSnapshotBeforeUpdate(previous: AnimatedRowsProps): RowSnapshot | null {\n const list = this.list.current\n if (!this.armed || sameRows(previous, this.props) || previous.resetKey !== this.props.resetKey\n || !previous.ready || !this.props.ready || list === null\n || typeof list.animate !== 'function'\n || window.matchMedia('(prefers-reduced-motion: reduce)').matches) return null\n\n const viewport = list.getBoundingClientRect()\n const positions = this.readPositions()\n const nextKeys = new Set(this.props.rowKeys)\n const removed = new Map<string, RowPosition>()\n for (const [key, row] of positions) {\n if (nextKeys.has(key) || !intersects(row.rect, viewport)) continue\n const clone = row.element.cloneNode(true) as HTMLElement\n clone.removeAttribute('data-row-key')\n clone.inert = true\n clone.style.setProperty(\n '--dsh-workspace-indent', getComputedStyle(row.element).getPropertyValue('--dsh-workspace-indent'),\n )\n removed.set(key, { ...row, element: clone })\n }\n return { positions, removed }\n }\n\n override componentDidUpdate(previous: AnimatedRowsProps, _state: unknown, snapshot: RowSnapshot | null): void {\n if (snapshot === null) {\n if (!sameRows(previous, this.props) || previous.resetKey !== this.props.resetKey\n || previous.ready !== this.props.ready) this.clear()\n return\n }\n\n this.cancelMovements()\n const list = this.list.current as HTMLDivElement\n const overlay = this.overlay.current as HTMLDivElement\n const viewport = list.getBoundingClientRect()\n const origin = overlay.getBoundingClientRect()\n const positions = this.readPositions()\n\n for (const [key, row] of positions) {\n this.removeExit(key)\n const previousRow = snapshot.positions.get(key)\n if (!intersects(row.rect, viewport)\n && (previousRow === undefined || !intersects(previousRow.rect, viewport))) continue\n if (previousRow === undefined) {\n this.move(row.element, [{ opacity: 0 }, { opacity: 1 }], ROW_FADE_MS)\n continue\n }\n const dx = previousRow.rect.left - row.rect.left\n const dy = previousRow.rect.top - row.rect.top\n if (dx === 0 && dy === 0 && previousRow.opacity === 1) continue\n this.move(row.element, [\n { transform: `translate(${String(dx)}px, ${String(dy)}px)`, opacity: previousRow.opacity },\n { transform: 'translate(0, 0)', opacity: 1 },\n ], ROW_GLIDE_MS)\n }\n\n for (const [key, row] of snapshot.removed) {\n const { element } = row\n this.removeExit(key)\n Object.assign(element.style, {\n position: 'absolute', margin: '0', transform: 'none', boxSizing: 'border-box',\n left: `${String(row.rect.left - origin.left)}px`,\n top: `${String(row.rect.top - origin.top)}px`,\n width: `${String(row.rect.width)}px`, height: `${String(row.rect.height)}px`,\n })\n overlay.append(element)\n const animation = element.animate([{ opacity: row.opacity }, { opacity: 0 }], {\n duration: ROW_FADE_MS, easing: 'ease-out', fill: 'forwards',\n })\n this.exits.set(key, { element, animation })\n animation.onfinish = () => { this.removeExit(key) }\n }\n }\n\n override componentWillUnmount(): void {\n this.clear()\n }\n\n private readPositions(): Map<string, RowPosition> {\n const list = this.list.current as HTMLDivElement\n const rows = list.querySelectorAll<HTMLElement>('[data-row-key]')\n return new Map(Array.from(rows, element => [element.dataset.rowKey as string, {\n element,\n rect: element.getBoundingClientRect(),\n opacity: this.movements.has(element) ? Number(getComputedStyle(element).opacity) : 1,\n }]))\n }\n\n private move(element: HTMLElement, keyframes: Keyframe[], duration: number): void {\n const animation = element.animate(keyframes, { duration, easing: 'ease-out' })\n this.movements.set(element, animation)\n animation.onfinish = () => { this.movements.delete(element); animation.cancel() }\n }\n\n private cancelMovements(): void {\n for (const animation of this.movements.values()) {\n animation.onfinish = null\n animation.cancel()\n }\n this.movements.clear()\n }\n\n private removeExit(key: string): void {\n const exit = this.exits.get(key)\n if (exit === undefined) return\n exit.animation.onfinish = null\n exit.animation.cancel()\n exit.element.remove()\n this.exits.delete(key)\n }\n\n private clear(): void {\n this.cancelMovements()\n for (const key of this.exits.keys()) this.removeExit(key)\n }\n\n override render(): ReactNode {\n return <>\n <div\n ref={this.list}\n className={this.props.className}\n role=\"tree\"\n aria-label={this.props.label}\n onPointerDownCapture={() => { this.armed = true }}\n onKeyDownCapture={() => { this.armed = true }}\n >\n {this.props.children}\n </div>\n <div ref={this.overlay} className={css.exits} aria-hidden=\"true\" />\n </>\n }\n}\n","/**\n * Workspace pick/add flow. WorkspacePickFlow is the reusable core (menu +\n * path error dialog) consumed directly by WorkspaceBrowser (same package) and\n * wrapped by WorkspacePicker for the conversation empty-state slot\n * registration. Directory picking itself lives in the composed flow package's\n * slot occupant (see the contract module doc): this core only opens the flow,\n * adopts the picked path, and owns the error surface. Adding a workspace has\n * exactly one route — pick a host directory, new or existing — because the\n * occupant's own create-folder affordance already covers creating one.\n */\nimport type { ReactNode, RefObject } from 'react'\nimport { useCallback, useEffect, useState } from 'react'\nimport {\n Button, IconFolderCloseRegular, IconPlusOutlineRegular, Menu, Modal, type MenuEntry,\n} from '@deepseek-ai/dsh-client-ui-primitives'\nimport type {\n WorkspaceId, WorkspaceSnapshot, WorkspaceView,\n} from '@deepseek-ai/dsh-api-workspace-controller/client'\nimport { workspaceDisplayTitle } from '@deepseek-ai/dsh-api-workspace-controller/default-workspace'\nimport type { SnapshotSelectorHook } from '@deepseek-ai/dsh-client-ui-slots'\nimport type { DirectoryFlowOwnerProps, WorkspacePickerProps } from './contract/slots.ts'\nimport css from './WorkspacePicker.module.css'\n\nconst ADD_WORKSPACE = '::add-workspace'\n\n/** Core flow props: the owner supplies popover control and pick semantics. */\nexport interface WorkspacePickFlowProps {\n /** The standard locale seat, forwarded by whichever slot entry hosts the flow. */\n t: WorkspacePickerProps['t']\n /** Popover visibility (anchor button toggle state, owner-local). */\n open: boolean\n /** The anchor button element — the popover's placement anchor. */\n anchorRef?: RefObject<HTMLElement | null> | undefined\n /** Selector hook over the workspace list (framework standard hook). */\n useWorkspaces: <S>(selector: (state: WorkspaceSnapshot) => S) => S\n /** Adopt a picked host directory as a real Workspace. */\n createWorkspace: (input: { path: string }) => Promise<WorkspaceView>\n /** Bound occupancy selector hook for this surface's directory-flow hole (empty leaves the surface with no add action). */\n useDirectoryFlow: SnapshotSelectorHook<boolean>\n /** Render this surface's directory-flow hole with the owner conversation (the entry's narrowed renderSlot). */\n renderDirectoryFlow: (owner: DirectoryFlowOwnerProps) => ReactNode\n /** A real Workspace was picked or created. */\n onPick: (workspaceId: WorkspaceId) => void\n /** Close the popover (outside click / Escape / post-pick). */\n onClose: () => void\n /** Report the picking interaction and adoption occupancy. */\n onBusyChange?: (busy: boolean) => void\n /** Only offer the add action, hide existing workspaces. */\n addOnly?: boolean\n /** Menu opening direction relative to the anchor. */\n side?: 'bottom' | 'top' | 'right'\n /** Currently active workspace (trailing check in the picker list). */\n selectedId?: WorkspaceId | undefined\n}\n\n/**\n * Render the pick menu plus the adoption error dialog.\n * @param props - owner-controlled flow props.\n * @returns menu + dialog elements.\n */\nexport function WorkspacePickFlow({\n t,\n open,\n anchorRef,\n useWorkspaces,\n createWorkspace,\n useDirectoryFlow,\n renderDirectoryFlow,\n onPick,\n onClose,\n addOnly = false,\n onBusyChange,\n side = 'bottom',\n selectedId,\n}: WorkspacePickFlowProps) {\n const workspaceSnapshot = useWorkspaces(state => state)\n const workspaces = workspaceSnapshot.items\n const getAnchorRect = useCallback(\n () => anchorRef?.current?.getBoundingClientRect() ?? null,\n [anchorRef],\n )\n const [errorOpen, setErrorOpen] = useState(false)\n const [modalError, setModalError] = useState<string | null>(null)\n const [flowOpen, setFlowOpen] = useState(false)\n const [pickingFolder, setPickingFolder] = useState(false)\n // One picking interaction at a time: while the flow is open (native chooser\n // pending, browse dialog up) or its pick is being adopted, every other\n // menu action stays disabled — a late outcome must not race a concurrent\n // selection or adoption.\n const flowBusy = flowOpen || pickingFolder\n useEffect(() => { onBusyChange?.(flowBusy) }, [flowBusy, onBusyChange])\n\n // The occupied hole gates the picking affordance: with no composed flow the\n // entry simply is not there (the seam's documented no-flow default). The\n // framework-bound hook keeps occupancy live: flow plugins activate (and\n // HMR-reload) independently of this menu's renders.\n const flowAvailable = useDirectoryFlow(occupied => occupied)\n // An occupant that unloads mid-interaction leaves nobody to cancel: an\n // open flow over an empty hole withdraws so the menu actions come back.\n // flowOpen is a dependency because the flow can also OPEN over an already\n // empty hole (Choose again after the occupant unloaded with the error\n // dialog up) — that transition must snap back too, not just occupancy loss.\n useEffect(() => {\n if (flowOpen && !flowAvailable) setFlowOpen(false)\n }, [flowOpen, flowAvailable])\n const addEntries: MenuEntry[] = flowAvailable\n ? [{ id: ADD_WORKSPACE, label: t('menu.addWorkspace'), icon: <IconPlusOutlineRegular size={16} />, disabled: flowBusy }]\n : []\n // With workspaces listed, the add action pins below the scroll region\n // (divider + always visible); otherwise it IS the menu.\n const pinAdd = !addOnly && workspaces.length > 0\n const items: MenuEntry[] = pinAdd\n ? workspaces.map(workspace => ({\n id: workspace.workspaceId,\n label: workspaceDisplayTitle(workspace.title, t('workspace.defaultName')),\n icon: <IconFolderCloseRegular size={16} />,\n disabled: flowBusy,\n }))\n : addEntries\n // Nothing listed and nothing to add with (a composition that mounts this\n // package without any directory-picker): an empty popover would claim a\n // choice that does not exist, so the anchor gesture shows nothing at all.\n const menuIsEmpty = items.length === 0\n\n const closeModal = (): void => {\n setErrorOpen(false)\n setModalError(null)\n }\n\n /** Adopt a picked directory; failures land in the folder-error dialog (Choose again reopens the flow). */\n const adoptDirectory = (path: string): Promise<void> =>\n createWorkspace({ path }).then((workspace) => {\n setFlowOpen(false)\n onPick(workspace.workspaceId)\n }).catch((reason: unknown) => {\n setModalError(reason instanceof Error ? reason.message : String(reason))\n setFlowOpen(false)\n setErrorOpen(true)\n })\n\n const openDirectoryFlow = useCallback((): void => {\n onClose()\n setErrorOpen(false)\n setModalError(null)\n setFlowOpen(true)\n }, [onClose])\n\n // A menu exists to disambiguate between targets. With no workspaces listed\n // and the add action the only entry left, the anchor gesture IS that action:\n // a one-row popover would cost a click and offer nothing to choose between.\n // The owner's open request is consumed the same way selecting the entry\n // would consume it (close the popover, raise the flow). An empty list is\n // only final once the baseline lands — until then the menu stays up with its\n // loading status instead of jumping into a flow the arriving list would have\n // made unnecessary; the add-only surface lists nothing and never waits.\n const listSettled = addOnly || workspaceSnapshot.phase === 'ready'\n const addIsTheOnlyEntry = !pinAdd && listSettled && addEntries.length === 1\n // `flowBusy` gates this exactly as it disables the equivalent menu entry: a\n // pick still being adopted owns the surface until it settles.\n useEffect(() => {\n if (open && addIsTheOnlyEntry && !flowBusy) openDirectoryFlow()\n }, [open, addIsTheOnlyEntry, flowBusy, openDirectoryFlow])\n\n /** Owner side of the flow conversation: adopt keeps the flow open (busy) until the Host answers. */\n const flowOwner: DirectoryFlowOwnerProps = {\n open: flowOpen,\n busy: pickingFolder,\n onPicked: (path) => {\n setPickingFolder(true)\n void adoptDirectory(path).finally(() => { setPickingFolder(false) })\n },\n onCancel: () => { setFlowOpen(false) },\n onError: (message) => {\n setFlowOpen(false)\n setModalError(message)\n setErrorOpen(true)\n },\n }\n\n const handleSelect = (id: string): void => {\n if (id === ADD_WORKSPACE) {\n openDirectoryFlow()\n return\n }\n onPick(id as WorkspaceId)\n }\n\n return (\n <>\n <Menu\n open={open && !addIsTheOnlyEntry && !menuIsEmpty}\n anchor={null}\n items={items}\n {...pinAdd ? { footer: addEntries } : {}}\n selectedId={selectedId}\n onSelect={handleSelect}\n onClose={onClose}\n side={side}\n portal\n getAnchorRect={getAnchorRect}\n />\n {open && !addIsTheOnlyEntry && !menuIsEmpty && workspaceSnapshot.phase === 'pending' && <div className={css.menuStatus} role=\"status\">{t('picker.loading')}</div>}\n {renderDirectoryFlow(flowOwner)}\n <Modal\n open={errorOpen}\n onClose={closeModal}\n closeLabel={t('close')}\n title={t('folderError.title')}\n footer={(\n <>\n <Button variant=\"outline\" className={css.modalAction} onClick={closeModal}>{t('cancel')}</Button>\n {/* Retrying needs an occupant to serve the flow; without one the\n * button would open a flow nobody can answer or cancel. */}\n <Button variant=\"primary\" className={css.modalAction} disabled={!flowAvailable} onClick={openDirectoryFlow}>{t('folderError.retry')}</Button>\n </>\n )}\n >\n <div className={css.modalError} role=\"alert\">{modalError}</div>\n </Modal>\n </>\n )\n}\n\n/**\n * The conversation empty-state registration: adapts the owner share to the\n * core flow (all state and semantics live in the flow / the owner).\n * @param props - empty-state slot props (owner share + injected creation callback).\n * @returns the flow element.\n */\nexport function WorkspacePicker({\n open,\n anchorRef,\n useWorkspaces,\n selectedId,\n onPick,\n onClose,\n createWorkspace,\n useDirectoryFlow,\n renderSlot,\n t,\n}: WorkspacePickerProps) {\n return (\n <WorkspacePickFlow\n t={t}\n open={open}\n anchorRef={anchorRef}\n useWorkspaces={useWorkspaces}\n createWorkspace={createWorkspace}\n useDirectoryFlow={useDirectoryFlow}\n renderDirectoryFlow={owner => renderSlot('conversation.hero.workspace.directoryFlow', owner)}\n selectedId={selectedId}\n onPick={onPick}\n onClose={onClose}\n />\n )\n}\n","/**\n * The workspace/session browsing region filling the sidebar shell's\n * `sidebar.workspaces` hole: section header (title + view options + add\n * workspace), search, the grouped tree or flat list, and the workspace\n * dialogs. Wide state renders the full browser; rail state renders the two\n * region icons (search / add workspace) as 36px controls on the shell's shared\n * rail entry path, each requesting expansion through the owner share. Adding\n * is the header button's one action, so it raises the directory flow with no\n * menu in between; the flow and its error dialog live in WorkspacePicker\n * (same package — direct composition, no slot between them). A Session row's\n * \"...\" menu and hover buttons are the `sidebar.workspaces.session.menu.item`\n * and `sidebar.workspaces.session.row.action` lists rendered through this\n * entry's `renderSlot`; the actions in them, this package's own included,\n * are slot entries with their own behavior, so this component threads no\n * action callbacks and hosts no action surface.\n */\nimport { type CSSProperties, type ReactNode, useEffect, useMemo, useRef, useState } from 'react'\nimport clsx from 'clsx'\nimport {\n Button, IconArchiveCheckOutlineRegular, IconArchiveOffOutlineRegular, IconArchiveOutlineRegular,\n IconChevronsUpDownOutlineRegular, IconClockOutlineRegular, IconCloseFillRegular,\n IconFlatListOutlineRegular, IconFolderCloseRegular, IconProjectAddOutlineRegular,\n IconQueueOutlineRegular, IconSearchOutlineRegular, IconSlidersTwoOutlineRegular,\n IconWorkspaceTreeOutlineRegular, Menu, Modal, Toast, Tooltip,\n} from '@deepseek-ai/dsh-client-ui-primitives'\nimport type {\n SessionListState, SessionSearchResultItem,\n} from '@deepseek-ai/dsh-api-session-controller/client'\nimport type { WorkspaceId, WorkspaceView } from '@deepseek-ai/dsh-api-workspace-controller/client'\nimport { workspaceDisplayTitle } from '@deepseek-ai/dsh-api-workspace-controller/default-workspace'\n\n// Cross-plugin hooks: each sibling plugin is optional and degrades to \"absent\".\n//\n// The lookup uses this bundle's **injected** `require` — the CJS factory parameter\n// `window.__ModuleLoader__.load({ factory: (require) => … })` supplies, which resolves\n// the module-table rows declared in package.json `dsh.client.external`.\n//\n// It must NOT be `globalThis.require`: the host defines no global require (verified in\n// the live page: `typeof globalThis.require === 'undefined'`), so a global lookup\n// silently disables every cross-plugin integration while still building and booting\n// cleanly. The bundle preset externalizes exactly these specifiers (deps.neverBundle\n// matches dsh.client.external), keeping them runtime requires instead of inlining.\ndeclare const require: (id: string) => unknown\n\n// dsh-later schedule summary API (optional — gracefully degrades when absent)\ntype ScheduleSummaryMap = ReadonlyMap<string, { count: number; pausedCount: number; nextAt?: number; state: 'scheduled' | 'urgent' | 'overdue' }>\nlet useScheduleSummaryHook: (() => ScheduleSummaryMap | undefined) | undefined\ntry {\n const dshLater = require('dsh-later/client') as { useScheduleSummary?: () => ScheduleSummaryMap } | undefined\n useScheduleSummaryHook = dshLater?.useScheduleSummary\n} catch {\n // dsh-later not installed — schedule summary will be undefined\n}\n\n// dsh-gitea-dispatch waiting-review API (dsh-gitea-dispatch#16, same optional rule).\n// Its store owns the only poll of /api/gitea-dispatch/waiting, so this plugin never\n// issues that request itself: the badge costs no extra traffic.\ntype WaitingReviewSummaryMap = ReadonlyMap<string, { prNumber: number; state: 'waiting' | 'overdue' }>\nlet useWaitingSummaryHook: (() => WaitingReviewSummaryMap | undefined) | undefined\ntry {\n const giteaDispatch = require('dsh-gitea-dispatch/client') as { useWaitingSummary?: () => WaitingReviewSummaryMap } | undefined\n useWaitingSummaryHook = giteaDispatch?.useWaitingSummary\n} catch {\n // dsh-gitea-dispatch not installed — waiting review count stays 0\n}\nimport type { SessionId } from '@deepseek-ai/dsh-session/types'\nimport type { PropsRenderSlots } from '@deepseek-ai/dsh-client-ui-slots'\nimport type { WorkspaceBrowserProps } from '../contract/slots.ts'\nimport type { ArchivedFilter, GroupNode, SessionNode, SessionOrderBy, SessionRowState } from '../tree.ts'\nimport {\n deriveFlat, deriveGroups, deriveSearchResults, orderByRecency, owningGroupKey, owningParentFolder,\n pinCurrentBlank, reconcileManualOrder, sessionMemberIds, UNGROUPED_KEY,\n} from '../tree.ts'\nimport { directStatusesForGroups, withAggregatedStatus, type StatusedGroupNode } from '../group-status.ts'\nimport { ProjectRowItem, SearchResultItem, SessionNodeItem } from './Rows.tsx'\nimport { AnimatedRows } from './AnimatedRows.tsx'\nimport { FLAT_SESSION_ORDER_KEY, type SessionGroupBy } from '../stores.ts'\nimport { WorkspacePickFlow } from '../WorkspacePicker.tsx'\nimport css from './WorkspaceBrowser.module.css'\n\n/**\n * Column slide length (--ds-transition-duration-slow): rail-search focus waits it out —\n * focus() forces a synchronous layout and would jank the slide.\n */\nconst EXPAND_SLIDE_MS = 300\n/** Pause between the latest keystroke and a Host content-search request. */\nconst SEARCH_DEBOUNCE_MS = 250\n/** `session.search` wire bound, measured in JavaScript UTF-16 code units. */\nconst SEARCH_QUERY_MAX_CODE_UNITS = 500\n/** Idle Session rows visible per Workspace before the local overflow control. */\nconst COLLAPSED_SESSION_LIMIT = 5\n\n/** Keep provisional and running rows outside the idle-session quota, including parents with running children. */\nfunction collapsedSessionRows(sessions: readonly SessionNode[], limit = COLLAPSED_SESSION_LIMIT): {\n rows: readonly SessionNode[]\n hiddenCount: number\n} {\n let idleCount = 0\n const rows = sessions.filter((session) => {\n if (session.blank || session.running || session.runningSubagentCount > 0) return true\n if (idleCount >= limit) return false\n idleCount += 1\n return true\n })\n return { rows, hiddenCount: sessions.length - rows.length }\n}\n\n/** Keep controlled input and RPC payload inside the session.search wire contract. */\nfunction sanitizeSearchQuery(value: string): string {\n const withoutNul = value.replaceAll('\\0', '')\n if (withoutNul.length <= SEARCH_QUERY_MAX_CODE_UNITS) return withoutNul\n let end = SEARCH_QUERY_MAX_CODE_UNITS\n const last = withoutNul.charCodeAt(end - 1)\n const next = withoutNul.charCodeAt(end)\n if (last >= 0xD800 && last <= 0xDBFF && next >= 0xDC00 && next <= 0xDFFF) end--\n return withoutNul.slice(0, end)\n}\n\n/**\n * Accept the native drag at document level while a row drag is active: row\n * hover still owns the insertion marker, and releasing outside the list must\n * not be rendered as a rejected drop before dragend commits that last marker.\n */\nfunction useNativeDragAcceptance(active: boolean): void {\n useEffect(() => {\n if (!active) return\n const acceptDrag = (event: DragEvent): void => {\n event.preventDefault()\n if (event.dataTransfer !== null) event.dataTransfer.dropEffect = 'move'\n }\n const acceptDrop = (event: DragEvent): void => { event.preventDefault() }\n document.addEventListener('dragover', acceptDrag)\n document.addEventListener('drop', acceptDrop)\n return () => {\n document.removeEventListener('dragover', acceptDrag)\n document.removeEventListener('drop', acceptDrop)\n }\n }, [active])\n}\n\n/** Grouping, ordering, and archived-filter menu; own open state so it resets with the wide chrome. */\nfunction ViewOptionsMenu({ groupBy, orderBy, archivedFilter, onGroupPick, onOrderPick, onArchivedFilterPick, t }: {\n groupBy: SessionGroupBy\n orderBy: SessionOrderBy\n archivedFilter: ArchivedFilter\n onGroupPick: (mode: SessionGroupBy) => void\n onOrderPick: (mode: SessionOrderBy) => void\n onArchivedFilterPick: (filter: ArchivedFilter) => void\n t: WorkspaceBrowserProps['t']\n}) {\n const [open, setOpen] = useState(false)\n return (\n <Menu\n open={open}\n onClose={() => { setOpen(false) }}\n items={[\n { type: 'label' as const, id: 'group-by', text: t('groupBy.label') },\n { id: 'workspace', label: t('groupBy.workspace'), icon: <IconFolderCloseRegular /> },\n { id: 'workspace-tree', label: t('groupBy.workspaceTree'), icon: <IconWorkspaceTreeOutlineRegular /> },\n { id: 'flat', label: t('groupBy.flat'), icon: <IconFlatListOutlineRegular /> },\n { type: 'separator' as const, id: 'order-by-separator' },\n { type: 'label' as const, id: 'order-by', text: t('orderBy.label') },\n { id: 'manual', label: t('orderBy.manual'), icon: <IconChevronsUpDownOutlineRegular /> },\n { id: 'updated', label: t('orderBy.updated'), icon: <IconClockOutlineRegular /> },\n { type: 'separator' as const, id: 'archived-filter-separator' },\n { type: 'label' as const, id: 'filter-by', text: t('filterBy.label') },\n { id: 'hide-archived', label: t('viewOptions.hideArchived'), icon: <IconArchiveOffOutlineRegular /> },\n { id: 'show-archived', label: t('viewOptions.showArchived'), icon: <IconQueueOutlineRegular /> },\n { id: 'only-archived', label: t('viewOptions.onlyArchived'), icon: <IconArchiveCheckOutlineRegular /> },\n ]}\n selectedIds={[\n groupBy,\n orderBy,\n { default: 'hide-archived', show: 'show-archived', only: 'only-archived' }[archivedFilter],\n ]}\n onSelect={(id) => {\n if (id === 'workspace' || id === 'workspace-tree' || id === 'flat') onGroupPick(id)\n else if (id === 'manual' || id === 'updated') onOrderPick(id)\n else if (id === 'hide-archived') onArchivedFilterPick('default')\n else if (id === 'show-archived') onArchivedFilterPick('show')\n else if (id === 'only-archived') onArchivedFilterPick('only')\n setOpen(false)\n }}\n align=\"end\"\n dense\n listClassName={css.viewOptionsMenu}\n // Portal: the section header clips overflow, so an in-place list would\n // be cut off at the header's bounds.\n portal\n anchor={(\n <Tooltip label={t('viewOptions.label')} side=\"bottom\" delayMs={500}>\n <button\n type=\"button\"\n className={clsx(css.iconButton, css.wide)}\n aria-label={t('viewOptions.label')}\n onClick={() => { setOpen(v => !v) }}\n >\n <IconSlidersTwoOutlineRegular />\n </button>\n </Tooltip>\n )}\n />\n )\n}\n\n/** In-flight root-row drag: source identity plus the current insert marker. */\ninterface DragState {\n /** Workspace id, or {@link UNGROUPED_KEY} for the browser-local loose-session account. */\n accountKey: string\n sessionId: SessionNode['id']\n /** Source row was pinned at drag start; drop targets share the pinned block. */\n pinned: boolean\n /** Row the marker sits on and which half (insert above/below it). */\n over: { id: SessionNode['id']; half: 'before' | 'after' } | null\n}\n\n/** Apply a visible drop to the complete account without removing hidden members. */\nfunction sessionDragOrder(\n order: readonly SessionId[],\n rows: readonly SessionNode[],\n drag: DragState,\n over: NonNullable<DragState['over']>,\n): SessionId[] | undefined {\n const source = rows.find(row => row.id === drag.sessionId)\n const target = rows.find(row => row.id === over.id)\n if (source === undefined || target === undefined || source.blank\n || source.pinned !== drag.pinned || target.pinned !== drag.pinned\n || source.id === target.id || !order.includes(source.id)) return\n const section = rows.filter(row => row.pinned === drag.pinned)\n const sourceIndex = section.findIndex(row => row.id === source.id)\n const withoutSource = section.filter(row => row.id !== source.id)\n const insertAt = withoutSource.findIndex(row => row.id === target.id) + (over.half === 'after' ? 1 : 0)\n if (insertAt === sourceIndex) return\n const next = order.filter(id => id !== source.id)\n const targetIndex = next.indexOf(target.id)\n if (targetIndex === -1) return\n next.splice(targetIndex + (over.half === 'after' ? 1 : 0), 0, source.id)\n return pinCurrentBlank(next, rows.find(row => row.blank)?.id)\n}\n\n/** In-flight Workspace-row drag: source identity plus the current marker. */\ninterface WorkspaceDragState {\n workspaceId: WorkspaceId\n over: { id: WorkspaceId; half: 'before' | 'after' } | null\n}\n\n/** Resolve an insertion side across the Workspace header, descendants, and Sessions. */\nfunction workspaceGroupHalf(e: { clientY: number; currentTarget: HTMLElement }): 'before' | 'after' {\n const rect = e.currentTarget.getBoundingClientRect()\n return e.clientY < rect.top + rect.height / 2 ? 'before' : 'after'\n}\n\ntype SessionTreeProps = Pick<\n WorkspaceBrowserProps,\n 'useSessionStatus' | 'startSession' | 'open'\n | 'insertWorkspaceBefore' | 't' | 'usePanelInfo' | 'useBadgeSettings'\n> & PropsRenderSlots<\n | 'sidebar.workspaces.session.menu.item'\n | 'sidebar.workspaces.session.row.action'\n | 'sidebar.session.row.leading'\n | 'sidebar.session.row.hover'\n> & {\n shortcuts: readonly import('@deepseek-ai/dsh-client-shortcuts/client').ShortcutCatalogEntry[]\n /** Always-mounted Session list snapshot. */\n list: SessionListState\n /** Host account home for POSIX hover-path abbreviation. */\n home?: string | undefined\n /** Workspaces in Host group order with browser-projected Session order. */\n workspaces: readonly WorkspaceView[]\n /** Browser-projected order for Sessions outside every Workspace. */\n ungroupedSessionIds: readonly SessionId[]\n /** Whether the current Workspace stream has a complete Host baseline. */\n workspaceReady: boolean\n /** Grouping, ordering, and filter changes replace the view without row motion. */\n animationResetKey: string\n /** Nest Workspaces under their nearest registered ancestors. */\n nestWorkspaces: boolean\n /** Explicit persisted group expansion, including descendants in tree mode. */\n groupExpansion: Readonly<Record<string, boolean>>\n /** Persist one Workspace group's expansion. */\n setGroupExpanded: (key: string, expanded: boolean) => void\n /** Save a drag order and select Manual. */\n setSessionOrder: (accountKey: string, order: readonly string[]) => void\n /** Registry-global pin and archive sets plus the archived-visibility choice. */\n rowState: SessionRowState\n /** Switch the archived filter back to the default hide-archived view. */\n onLeaveArchivedOnly: () => void\n /** Open the browser-owned rename dialog for a real Workspace group. */\n onRenameRequest: (workspaceId: WorkspaceId, currentTitle: string) => void\n /** Open the browser-owned delete-confirmation dialog for a real Workspace group. */\n onDeleteRequest: (workspaceId: WorkspaceId, currentTitle: string) => void\n /** Open the rename dialog from a row title double-click. */\n onSessionRenameRequest: (sessionId: SessionNode['id'], currentTitle: string) => void\n /** One Session chosen from search that must be exposed and scrolled into view. */\n revealSessionId?: SessionId | undefined\n /** Acknowledge that the chosen Session row has been revealed. */\n onSessionRevealed: (sessionId: SessionId) => void\n}\n\n/** The list-empty placeholder — a glyph over the text; the archived-only view names its filter and offers the way back. */\nfunction EmptySessions({ rowState, onLeaveArchivedOnly, t }: Pick<SessionTreeProps, 'rowState' | 'onLeaveArchivedOnly' | 't'>) {\n const archivedOnly = rowState.archivedFilter === 'only'\n return (\n <div className={css.emptyState} data-row-key=\"empty\">\n {archivedOnly ? <IconArchiveOutlineRegular size={24} /> : <IconQueueOutlineRegular size={24} />}\n <div>{archivedOnly ? t('empty.noneArchived') : t('empty.none')}</div>\n {archivedOnly && (\n <button type=\"button\" className={css.emptyAction} onClick={onLeaveArchivedOnly}>\n {t('empty.viewOthers')}\n </button>\n )}\n </div>\n )\n}\n\n/** The scrolling session tree; unmounting drops the sessions subscription and local row limits. */\nfunction SessionTree({\n list, useSessionStatus, startSession, open, workspaces, ungroupedSessionIds,\n rowState, onLeaveArchivedOnly,\n workspaceReady, animationResetKey, usePanelInfo,\n onRenameRequest, onDeleteRequest, onSessionRenameRequest,\n renderSlot,\n insertWorkspaceBefore,\n nestWorkspaces, groupExpansion, setGroupExpanded,\n setSessionOrder, home, t,\n revealSessionId, onSessionRevealed, shortcuts, useBadgeSettings,\n}: SessionTreeProps) {\n const panelActive = usePanelInfo(info => info.activePanelId !== null)\n // 徽标设置:各来源显隐、悬停明细、数字样式。\n const badgeSettings = useBadgeSettings(settings => settings)\n const statuses = useSessionStatus(s => s)\n const scheduleSummary = useScheduleSummaryHook?.()\n const waitingReviewSummary = useWaitingSummaryHook?.()\n const current = panelActive\n ? undefined\n : Object.values(list.byId).find(session => (session.retainedBy.mainView ?? 0) > 0)?.id\n const revealGroup = revealSessionId === undefined || !workspaceReady\n ? undefined\n : owningGroupKey(workspaces, revealSessionId)\n const [sessionLimits, setSessionLimits] = useState<Readonly<Record<string, number>>>({})\n // Transient drag marker state; the selected mode owns the resulting order.\n const [drag, setDrag] = useState<DragState | null>(null)\n const sessionDropCommitted = useRef(false)\n const [workspaceDrag, setWorkspaceDrag] = useState<WorkspaceDragState | null>(null)\n const workspaceDropCommitted = useRef(false)\n const nativeDragActive = drag !== null || workspaceDrag !== null\n useNativeDragAcceptance(nativeDragActive)\n const currentGroup = current === undefined || !workspaceReady\n ? undefined\n : owningGroupKey(workspaces, current)\n useEffect(() => {\n if (current === undefined || currentGroup === undefined || Object.hasOwn(groupExpansion, currentGroup)) return\n setGroupExpanded(currentGroup, true)\n }, [current, currentGroup, setGroupExpanded, groupExpansion])\n const parents = useMemo(() => {\n if (!nestWorkspaces) return new Map<string, WorkspaceId | undefined>()\n const keysByPath = new Map(workspaces.map(workspace => [workspace.path, workspace.workspaceId]))\n const paths = [...keysByPath.keys()]\n return new Map<string, WorkspaceId | undefined>(workspaces.map((workspace) => {\n const path = owningParentFolder(workspace.path, paths)\n return [workspace.workspaceId, path === undefined ? undefined : keysByPath.get(path)]\n }))\n }, [nestWorkspaces, workspaces])\n const currentAncestors = useMemo(() => {\n const keys = new Set<string>()\n for (let key = currentGroup === undefined ? undefined : parents.get(currentGroup); key !== undefined; key = parents.get(key)) {\n keys.add(key)\n }\n return keys\n }, [currentGroup, parents])\n const expandedGroups = useMemo(() => {\n const ancestorKeys = new Set<string | undefined>(parents.values())\n return [...workspaces.map(workspace => workspace.workspaceId), UNGROUPED_KEY]\n .filter(key => groupExpansion[key] ?? ancestorKeys.has(key))\n }, [groupExpansion, parents, workspaces])\n const groups = useMemo(\n () => deriveGroups(list, workspaces, rowState, statuses, {\n expandedGroups,\n ungroupedOrder: ungroupedSessionIds,\n }),\n [list, workspaces, rowState, statuses, expandedGroups, ungroupedSessionIds],\n )\n useEffect(() => {\n for (let key = revealGroup; key !== undefined; key = parents.get(key)) {\n if (groupExpansion[key] === false || (key === revealGroup && groupExpansion[key] !== true)) {\n setGroupExpanded(key, true)\n }\n }\n }, [groupExpansion, parents, revealGroup, setGroupExpanded])\n useEffect(() => {\n if (revealSessionId === undefined || revealGroup === undefined) return\n const group = groups.find(candidate => candidate.key === revealGroup)\n if (group === undefined || !group.expanded || !group.sessions.some(row => row.id === revealSessionId)) return\n if (collapsedSessionRows(group.sessions).rows.some(row => row.id === revealSessionId)) return\n setSessionLimits(limits => limits[revealGroup] === Infinity ? limits : { ...limits, [revealGroup]: Infinity })\n }, [groups, revealGroup, revealSessionId])\n const now = Date.now()\n const commitSessionDrag = (activeDrag: DragState, over: NonNullable<DragState['over']>): void => {\n if (sessionDropCommitted.current) return\n sessionDropCommitted.current = true\n setDrag(null)\n const group = groups.find(candidate => candidate.key === activeDrag.accountKey)\n if (group === undefined) return\n if (over.id === activeDrag.sessionId) return\n const accountSessionIds = activeDrag.accountKey === UNGROUPED_KEY\n ? ungroupedSessionIds\n : workspaces.find(workspace => workspace.workspaceId === activeDrag.accountKey)?.sessionIds\n if (accountSessionIds === undefined) return\n const renderedSessions = collapsedSessionRows(group.sessions, sessionLimits[group.key]).rows\n const nextOrder = sessionDragOrder(accountSessionIds, renderedSessions, activeDrag, over)\n if (nextOrder !== undefined) setSessionOrder(activeDrag.accountKey, nextOrder)\n }\n const commitWorkspaceDrag = (\n activeDrag: WorkspaceDragState,\n over: NonNullable<WorkspaceDragState['over']>,\n ): void => {\n if (workspaceDropCommitted.current) return\n workspaceDropCommitted.current = true\n setWorkspaceDrag(null)\n const owner = parents.get(activeDrag.workspaceId)\n const siblings = workspaces.filter(workspace => parents.get(workspace.workspaceId) === owner)\n const rowIndex = siblings.findIndex(workspace => workspace.workspaceId === over.id)\n if (rowIndex === -1) return\n const anchor = over.half === 'before' ? over.id : siblings[rowIndex + 1]?.workspaceId\n if (anchor === activeDrag.workspaceId) return\n const sourceIndex = siblings.findIndex(workspace => workspace.workspaceId === activeDrag.workspaceId)\n const anchorIndex = anchor === undefined\n ? siblings.length\n : siblings.findIndex(workspace => workspace.workspaceId === anchor)\n if (sourceIndex !== -1 && (anchorIndex === sourceIndex || anchorIndex === sourceIndex + 1)) return\n insertWorkspaceBefore(activeDrag.workspaceId, anchor).catch((reason: unknown) => {\n console.warn('workspace reorder rejected:', reason)\n })\n }\n // Build tree structure from original groups (for aggregation traversal)\n const childrenByParentForAggregation = useMemo(() => {\n const rendered = new Set(groups.map(group => group.key))\n const children = new Map<string | undefined, GroupNode[]>()\n for (const group of groups) {\n let parent = parents.get(group.key)\n while (parent !== undefined && !rendered.has(parent)) parent = parents.get(parent)\n const siblings = children.get(parent)\n if (siblings === undefined) children.set(parent, [group])\n else siblings.push(group)\n }\n return children\n }, [groups, parents])\n\n // Fork-owned: each group's DIRECT member status — the input to the tree-wide\n // aggregation below. deriveGroups stopped computing liveStatus (PR #10 moved it\n // out), so this map is the aggregator's only data source. Expanded groups are\n // measured too; see directStatusesForGroups.\n const directStatusByGroup = useMemo(\n () => directStatusesForGroups(groups, waitingReviewSummary, scheduleSummary),\n [groups, waitingReviewSummary, scheduleSummary],\n )\n\n // Multi-level aggregation: a collapsed folder's badge covers its own members plus\n // every descendant group's, at any depth. Every row comes back measured, so the\n // render path can never see an unresolved liveStatus.\n const groupsWithAggregatedStatus = useMemo(\n () => withAggregatedStatus(groups, directStatusByGroup, childrenByParentForAggregation),\n [groups, directStatusByGroup, childrenByParentForAggregation],\n )\n\n // Rebuild tree structure with aggregated groups (for rendering)\n const childrenByParent = useMemo(() => {\n const rendered = new Set(groupsWithAggregatedStatus.map(group => group.key))\n const children = new Map<string | undefined, StatusedGroupNode[]>()\n for (const group of groupsWithAggregatedStatus) {\n // The archived-only view drops empty groups, so an ancestor may be\n // absent; nest under the nearest rendered one.\n let parent = parents.get(group.key)\n while (parent !== undefined && !rendered.has(parent)) parent = parents.get(parent)\n const siblings = children.get(parent)\n if (siblings === undefined) children.set(parent, [group])\n else siblings.push(group)\n }\n return children\n }, [groupsWithAggregatedStatus, parents])\n\n const rootGroups = childrenByParent.get(undefined) ?? []\n const workspaceDropAtListStart = rootGroups[0]?.workspaceId !== undefined\n && workspaceDrag?.over?.id === rootGroups[0].workspaceId\n && workspaceDrag.over.half === 'before'\n\n const rowKeys: string[] = groupsWithAggregatedStatus.length === 0 ? ['empty'] : []\n const renderGroup = (group: StatusedGroupNode, depth: number): ReactNode => {\n const workspaceId = group.workspaceId\n const children = childrenByParent.get(group.key) ?? []\n const compatibleDrag = workspaceDrag !== null && parents.get(workspaceDrag.workspaceId) === parents.get(group.key)\n const collapsed = collapsedSessionRows(group.sessions)\n const visible = collapsedSessionRows(group.sessions, sessionLimits[group.key])\n const sessionsExpanded = visible.hiddenCount === 0\n rowKeys.push(`workspace:${group.key}`)\n const childRows = group.expanded ? children.map(child => renderGroup(child, depth + 1)) : []\n const sessions = visible.rows\n for (const node of sessions) rowKeys.push(`session:${node.id}`)\n if (collapsed.hiddenCount > 0) rowKeys.push(`overflow:${group.key}`)\n const workspaceMarker = workspaceId !== undefined && workspaceDrag?.over?.id === workspaceId\n ? workspaceDrag.over.half\n : null\n const workspaceDragProps = workspaceId === undefined ? undefined : {\n start: () => {\n workspaceDropCommitted.current = false\n setWorkspaceDrag({ workspaceId, over: null })\n },\n end: () => {\n if (workspaceDrag?.over !== null && workspaceDrag?.over !== undefined) {\n commitWorkspaceDrag(workspaceDrag, workspaceDrag.over)\n } else {\n setWorkspaceDrag(null)\n }\n workspaceDropCommitted.current = false\n },\n }\n const hoverWorkspace = workspaceId === undefined || !compatibleDrag\n ? undefined\n : (half: 'before' | 'after') => {\n setWorkspaceDrag(active => active === null\n ? active\n : { ...active, over: { id: workspaceId, half } })\n }\n const dropWorkspace = workspaceId === undefined || !compatibleDrag\n ? undefined\n : (half: 'before' | 'after') => {\n commitWorkspaceDrag(workspaceDrag, { id: workspaceId, half })\n }\n // group arrives from groupsWithAggregatedStatus: collapsed groups already\n // carry the bottom-up aggregated liveStatus (direct + all descendants).\n return (\n // Group section: header, descendant Workspaces, and own Session rows. The\n // inter-group breathing room is the section's own margin\n // (WorkspaceBrowser.module.css).\n <div\n key={group.key}\n style={{ '--dsh-workspace-indent': `${depth * 12}px` } as CSSProperties}\n className={clsx(\n css.groupSection,\n workspaceMarker === 'before' && css.workspaceDropBefore,\n workspaceMarker === 'after' && css.workspaceDropAfter,\n )}\n onDragOver={workspaceDrag === null\n ? undefined\n : (e) => {\n e.preventDefault()\n if (hoverWorkspace === undefined && parents.get(group.key) !== undefined) return\n e.stopPropagation()\n if (hoverWorkspace === undefined) {\n e.dataTransfer.dropEffect = 'none'\n if (workspaceDrag.over !== null) setWorkspaceDrag({ ...workspaceDrag, over: null })\n } else {\n e.dataTransfer.dropEffect = 'move'\n hoverWorkspace(workspaceGroupHalf(e))\n }\n }}\n onDrop={workspaceDrag === null\n ? undefined\n : (e) => {\n e.preventDefault()\n if (dropWorkspace === undefined && parents.get(group.key) !== undefined) return\n e.stopPropagation()\n if (dropWorkspace === undefined) {\n workspaceDropCommitted.current = true\n setWorkspaceDrag(null)\n } else {\n dropWorkspace(workspaceGroupHalf(e))\n }\n }}\n >\n <ProjectRowItem\n newShortcut={shortcuts.find(row => row.id === 'session.new')}\n group={group}\n containsCurrentDescendant={currentAncestors.has(group.key)}\n home={home}\n settings={badgeSettings}\n t={t}\n onToggle={() => {\n if (group.expanded) {\n setSessionLimits(limits => ({ ...limits, [group.key]: COLLAPSED_SESSION_LIMIT }))\n }\n setGroupExpanded(group.key, !group.expanded)\n }}\n onCreate={() => {\n if (group.workspaceId !== undefined) {\n setGroupExpanded(group.key, true)\n startSession(group.workspaceId)\n }\n }}\n drag={workspaceDragProps}\n actions={group.workspaceId === undefined\n ? undefined\n : {\n rename: () => {\n /* v8 ignore next -- narrowing guard: the actions object exists only for real-workspace groups. */\n if (group.workspaceId !== undefined) onRenameRequest(group.workspaceId, group.label)\n },\n delete: () => {\n /* v8 ignore next -- narrowing guard: the actions object exists only for real-workspace groups. */\n if (group.workspaceId !== undefined) onDeleteRequest(group.workspaceId, group.label)\n },\n }}\n />\n {childRows.length > 0 && (\n <div role=\"group\">\n {childRows}\n </div>\n )}\n {group.expanded && sessions.map((node) => {\n // Session drag never leaves its browser-local account, and pinned\n // rows reorder only within their leading pinned block.\n const sameGroupDrag = drag !== null && drag.accountKey === group.key\n const compatibleTarget = sameGroupDrag && drag.pinned === node.pinned\n const normalizeHalf = (half: 'before' | 'after'): 'before' | 'after' =>\n node.blank ? 'after' : half\n const dragProps = {\n start: () => {\n sessionDropCommitted.current = false\n setDrag({ accountKey: group.key, sessionId: node.id, pinned: node.pinned, over: null })\n },\n active: compatibleTarget,\n marker: sameGroupDrag && drag.over?.id === node.id ? drag.over.half : null,\n hover: (half: 'before' | 'after') => {\n /* v8 ignore next -- narrowing guard: Rows gates hover on `active`, which is false while the drag state is null. */\n setDrag(d => (d === null ? d : {\n ...d, over: { id: node.id, half: normalizeHalf(half) },\n }))\n },\n drop: (half: 'before' | 'after') => {\n /* v8 ignore next -- narrowing guard: Rows gates drop on `active`, which is false while the drag state is null. */\n if (drag === null) return\n commitSessionDrag(drag, { id: node.id, half: normalizeHalf(half) })\n },\n end: () => {\n if (drag?.over !== null && drag?.over !== undefined) commitSessionDrag(drag, drag.over)\n else setDrag(null)\n sessionDropCommitted.current = false\n },\n }\n return (\n <SessionNodeItem\n key={node.id}\n node={node}\n currentId={current}\n now={now}\n onOpen={open}\n onRenameRequest={onSessionRenameRequest}\n renderSlot={renderSlot}\n onReveal={node.id === revealSessionId && group.key === revealGroup\n ? () => { onSessionRevealed(node.id) }\n : undefined}\n drag={dragProps}\n t={t}\n />\n )\n })}\n {group.expanded && collapsed.hiddenCount > 0 && (\n <button\n type=\"button\"\n className={css.sessionOverflowButton}\n data-row-key={`overflow:${group.key}`}\n aria-expanded={sessionsExpanded}\n onClick={() => {\n setSessionLimits(limits => ({\n ...limits,\n [group.key]: sessionsExpanded\n ? COLLAPSED_SESSION_LIMIT\n : visible.hiddenCount <= COLLAPSED_SESSION_LIMIT\n ? Infinity\n : (limits[group.key] ?? COLLAPSED_SESSION_LIMIT) + COLLAPSED_SESSION_LIMIT,\n }))\n }}\n >\n {sessionsExpanded\n ? t('sessions.collapse')\n : t('sessions.expand', { n: visible.hiddenCount })}\n </button>\n )}\n </div>\n )\n }\n\n const groupRows = rootGroups.map(group => renderGroup(group, 0))\n return (\n <div className={clsx(css.treeBody, css.wide)}>\n {workspaceDropAtListStart && <span className={css.listTopDropIndicator} aria-hidden=\"true\" />}\n <AnimatedRows\n className={clsx(css.list, workspaceDropAtListStart && css.listTopDropActive)}\n label={t('section.sessions')}\n rowKeys={rowKeys}\n ready={list.phase === 'ready' && workspaceReady && !nativeDragActive}\n // Fork-owned: upstream also mixes `sessionLimits` into this key so that\n // revealing hidden rows settles instantly. But folding a group writes\n // sessionLimits too (reset to COLLAPSED_SESSION_LIMIT), which silently\n // suppressed the row fade-out on every collapse. Keep only the\n // view-replacement key so collapse/expand still animates.\n resetKey={animationResetKey}\n >\n {groupsWithAggregatedStatus.length === 0 && (\n <EmptySessions rowState={rowState} onLeaveArchivedOnly={onLeaveArchivedOnly} t={t} />\n )}\n {groupRows}\n </AnimatedRows>\n <span className={css.fade} />\n </div>\n )\n}\n\n/** The flat \"In one list\" body: every session is one draggable top-level row. */\nfunction FlatList({\n list, sessionIds, rowState, onLeaveArchivedOnly, useSessionStatus, open, onSessionRenameRequest,\n usePanelInfo, setSessionOrder, workspaceReady, animationResetKey,\n revealSessionId, onSessionRevealed, renderSlot, t,\n}: Pick<\n SessionTreeProps,\n | 'useSessionStatus'\n | 'open'\n | 'onSessionRenameRequest'\n | 'renderSlot'\n | 'usePanelInfo'\n | 'setSessionOrder'\n | 'workspaceReady'\n | 'animationResetKey'\n | 'revealSessionId'\n | 'onSessionRevealed'\n | 'rowState'\n | 'onLeaveArchivedOnly'\n | 't'\n> & {\n list: SessionListState\n sessionIds: readonly SessionId[]\n}) {\n const panelActive = usePanelInfo(info => info.activePanelId !== null)\n const statuses = useSessionStatus(s => s)\n const rows = useMemo(\n () => deriveFlat(list, sessionIds, rowState, statuses),\n [list, sessionIds, rowState, statuses],\n )\n const [drag, setDrag] = useState<DragState | null>(null)\n const dropCommitted = useRef(false)\n useNativeDragAcceptance(drag !== null)\n const currentId = panelActive\n ? undefined\n : Object.values(list.byId).find(session => (session.retainedBy.mainView ?? 0) > 0)?.id\n const commitDrag = (activeDrag: DragState, over: NonNullable<DragState['over']>): void => {\n if (dropCommitted.current) return\n dropCommitted.current = true\n setDrag(null)\n const nextOrder = sessionDragOrder(sessionIds, rows, activeDrag, over)\n if (nextOrder !== undefined) setSessionOrder(FLAT_SESSION_ORDER_KEY, nextOrder)\n }\n const now = Date.now()\n return (\n <div className={clsx(css.treeBody, css.wide)}>\n <AnimatedRows\n className={clsx(css.list, css.flatList)}\n label={t('section.sessions')}\n rowKeys={rows.length === 0 ? ['empty'] : rows.map(row => `session:${row.id}`)}\n ready={list.phase === 'ready' && workspaceReady && drag === null}\n resetKey={animationResetKey}\n >\n {rows.length === 0 && (\n <EmptySessions rowState={rowState} onLeaveArchivedOnly={onLeaveArchivedOnly} t={t} />\n )}\n {rows.map((node) => {\n const active = drag !== null && drag.pinned === node.pinned\n const normalizeHalf = (half: 'before' | 'after'): 'before' | 'after' =>\n node.blank ? 'after' : half\n return (\n <SessionNodeItem\n key={node.id}\n node={node}\n currentId={currentId}\n now={now}\n onOpen={open}\n onRenameRequest={onSessionRenameRequest}\n renderSlot={renderSlot}\n onReveal={node.id === revealSessionId\n ? () => { onSessionRevealed(node.id) }\n : undefined}\n drag={{\n start: () => {\n dropCommitted.current = false\n setDrag({ accountKey: FLAT_SESSION_ORDER_KEY, sessionId: node.id, pinned: node.pinned, over: null })\n },\n active,\n marker: active && drag.over?.id === node.id ? drag.over.half : null,\n hover: (half) => {\n setDrag(current => current === null ? current : {\n ...current, over: { id: node.id, half: normalizeHalf(half) },\n })\n },\n drop: (half) => {\n if (drag !== null) commitDrag(drag, { id: node.id, half: normalizeHalf(half) })\n },\n end: () => {\n if (drag?.over !== null && drag?.over !== undefined) commitDrag(drag, drag.over)\n else setDrag(null)\n dropCommitted.current = false\n },\n }}\n t={t}\n />\n )\n })}\n </AnimatedRows>\n <span className={css.fade} />\n </div>\n )\n}\n\ninterface RemoteSearchState {\n query: string\n status: 'idle' | 'loading' | 'ready' | 'error'\n items: readonly SessionSearchResultItem[]\n hasMore: boolean\n}\n\n/** Flat search body: local metadata matches plus the current Host result page. */\nfunction SearchResults({\n useSessions,\n useSessionStatus,\n open,\n onUnarchive,\n workspaces,\n archivedSessionIds,\n archivedFilter,\n query,\n remote,\n resultLimit,\n usePanelInfo,\n t,\n}: Pick<WorkspaceBrowserProps, 'useSessions' | 'useSessionStatus' | 'open' | 't' | 'usePanelInfo'> & {\n workspaces: readonly WorkspaceView[]\n archivedSessionIds: readonly SessionNode['id'][]\n /** Search matches follow the archived filter selected for the list. */\n archivedFilter: ArchivedFilter\n /** Unarchive an archived result row in place. */\n onUnarchive: (id: SessionNode['id']) => void\n query: string\n remote: RemoteSearchState\n resultLimit: number\n}) {\n const panelActive = usePanelInfo(info => info.activePanelId !== null)\n const list = useSessions(s => s)\n const statuses = useSessionStatus(s => s)\n const currentRemote = remote.query === query\n ? remote\n : { query, status: 'loading' as const, items: [], hasMore: false }\n const results = useMemo(\n () => deriveSearchResults(\n list,\n workspaces,\n query,\n archivedSessionIds,\n archivedFilter,\n statuses,\n currentRemote,\n resultLimit,\n ),\n [list, workspaces, query, archivedSessionIds, archivedFilter, statuses, currentRemote, resultLimit],\n )\n const pending = currentRemote.status === 'loading'\n const currentId = panelActive\n ? undefined\n : Object.values(list.byId).find(session => (session.retainedBy.mainView ?? 0) > 0)?.id\n\n return (\n <div className={clsx(css.treeBody, css.wide)}>\n <div className={css.list}>\n <div className={css.searchTree} role=\"tree\" aria-label={t('search.results.aria')}>\n {results.items.map(result => (\n <SearchResultItem\n key={result.id}\n result={result}\n currentId={currentId}\n onOpen={open}\n onUnarchive={onUnarchive}\n t={t}\n />\n ))}\n </div>\n {pending && (\n /* Two skeleton rows on an empty list, one when local matches already\n show and only the content hits are outstanding. */\n <div role=\"status\" aria-label={t('search.pending')}>\n {(results.items.length === 0 ? [0, 1] : [0]).map(i => (\n <div key={i} className={css.skeletonRow} aria-hidden=\"true\">\n <span className={css.skeletonDot} />\n <span className={css.skeletonBars}>\n <span className={css.skeletonBar} />\n <span className={clsx(css.skeletonBar, css.skeletonBarWide)} />\n </span>\n </div>\n ))}\n </div>\n )}\n {!pending && results.items.length === 0 && (\n <div className={css.empty}>{t('search.noMatches')}</div>\n )}\n {results.hasMore && (\n <div className={css.searchStatus}>\n {t('search.hasMore', { n: resultLimit })}\n </div>\n )}\n </div>\n <span className={css.fade} />\n </div>\n )\n}\n\n/**\n * Render the browsing region.\n * @param props - composed slot props (shell owner share + store + injected actions).\n * @returns the region element tree.\n */\nexport function WorkspaceBrowser({\n wide,\n usePanelInfo,\n expandSidebar,\n useSessions,\n useSessionStatus,\n useWorkspaces,\n useStore,\n actions,\n startSession,\n open,\n requestSessionRename,\n notifyArchivedNotOpenable,\n renameWorkspace,\n deleteWorkspace,\n insertWorkspaceBefore,\n unarchiveSession,\n createWorkspace,\n searchSessions,\n searchResultLimit,\n useDirectoryFlow,\n useHostInfo,\n useShortcuts,\n useWorkspaceShortcuts,\n useBadgeSettings,\n requestSearch,\n requestAddWorkspace,\n closeAddWorkspace,\n setDirectoryBusy,\n dismissForkError,\n renderSlot,\n t,\n}: WorkspaceBrowserProps) {\n const home = useHostInfo(info => info.home)\n const shortcuts = useShortcuts(rows => rows)\n const searchShortcut = shortcuts.find(row => row.id === 'session.search')\n const addShortcut = shortcuts.find(row => row.id === 'workspace.add')\n const shortcutState = useWorkspaceShortcuts(state => state)\n // Ordering remains live while the rail or search replaces the list body.\n const list = useSessions(state => state)\n const storedWorkspaces = useWorkspaces(state => state.items)\n // The resolved name, not `t`, is the memo dependency: the bound seat keeps\n // its identity across a language switch.\n const defaultWorkspaceName = t('workspace.defaultName')\n const workspaces = useMemo(\n () => storedWorkspaces.map(workspace => ({\n ...workspace,\n title: workspaceDisplayTitle(workspace.title, defaultWorkspaceName),\n })),\n [storedWorkspaces, defaultWorkspaceName],\n )\n const workspacePhase = useWorkspaces(state => state.phase)\n const workspaceStreamState = useWorkspaces(state => state.state)\n const archivedSessionIds = useWorkspaces(state => state.archivedSessionIds)\n const pinnedSessionIds = useWorkspaces(state => state.pinnedSessionIds)\n // Live occupancy of this surface's directory-flow hole (the same source the\n // flow reads): a composition without a picking affordance can add nothing.\n const directoryFlowAvailable = useDirectoryFlow(occupied => occupied)\n const groupBy = useStore(s => s.groupBy)\n const orderBy = useStore(s => s.orderBy)\n // Persisted view blobs written before the archived filter existed rehydrate\n // without the field; they read as the default hide-archived view.\n const archivedFilter = useStore(s => s.archivedFilter ?? 'default')\n const groupExpansion = useStore(s => s.groupExpansion)\n const sessionOrderByAccount = useStore(s => s.sessionOrderByAccount)\n // Archived sessions are not openable: the row stays visible under the\n // filter but a click explains instead of navigating.\n const guardedOpen = (sessionId: SessionId): void => {\n if (archivedSessionIds.includes(sessionId)) {\n notifyArchivedNotOpenable()\n return\n }\n open(sessionId)\n }\n const leaveArchivedOnly = (): void => { actions.setArchivedFilter('default') }\n const workspaceReady = workspacePhase === 'ready' && workspaceStreamState !== 'loading'\n const mainSessionId = Object.values(list.byId)\n .find(session => (session.retainedBy.mainView ?? 0) > 0)?.id\n const currentBlank = mainSessionId !== undefined && list.byId[mainSessionId]?.blank === true\n ? mainSessionId\n : undefined\n const ungroupedMemberIds = useMemo(() => {\n const accounted = new Set(workspaces.flatMap(workspace => workspace.sessionIds))\n return list.ids.filter(id => list.byId[id] !== undefined && !accounted.has(id))\n }, [list, workspaces])\n const orderState = useMemo(\n () => ({ pinnedSessionIds, archivedSessionIds }),\n [archivedSessionIds, pinnedSessionIds],\n )\n const rowState = useMemo<SessionRowState>(\n () => ({ ...orderState, archivedFilter }),\n [orderState, archivedFilter],\n )\n const flatMemberIds = useMemo(() => sessionMemberIds(list), [list])\n const orderedWorkspaces = useMemo(() => workspaces.map((workspace) => {\n const memberIds = workspace.sessionIds\n const baseOrder = orderBy === 'updated'\n ? orderByRecency(memberIds, list.byId)\n : reconcileManualOrder(memberIds, sessionOrderByAccount[workspace.workspaceId], list.byId, orderState)\n return {\n ...workspace,\n sessionIds: pinCurrentBlank(\n baseOrder,\n currentBlank !== undefined && memberIds.includes(currentBlank) ? currentBlank : undefined,\n ),\n }\n }), [currentBlank, list.byId, orderBy, orderState, sessionOrderByAccount, workspaces])\n const orderedUngroupedSessionIds = useMemo(() => {\n const baseOrder = orderBy === 'updated'\n ? orderByRecency(ungroupedMemberIds, list.byId)\n : reconcileManualOrder(ungroupedMemberIds, sessionOrderByAccount[UNGROUPED_KEY], list.byId, orderState)\n return pinCurrentBlank(\n baseOrder,\n currentBlank !== undefined && ungroupedMemberIds.includes(currentBlank) ? currentBlank : undefined,\n )\n }, [currentBlank, list.byId, orderBy, orderState, sessionOrderByAccount, ungroupedMemberIds])\n const orderedFlatSessionIds = useMemo(() => {\n const baseOrder = orderBy === 'updated'\n ? orderByRecency(flatMemberIds, list.byId)\n : reconcileManualOrder(flatMemberIds, sessionOrderByAccount[FLAT_SESSION_ORDER_KEY], list.byId, orderState)\n return pinCurrentBlank(\n baseOrder,\n currentBlank !== undefined && flatMemberIds.includes(currentBlank) ? currentBlank : undefined,\n )\n }, [currentBlank, flatMemberIds, list.byId, orderBy, orderState, sessionOrderByAccount])\n const activeSessionOrders = useMemo<Readonly<Record<string, readonly SessionId[]>>>(() => Object.fromEntries([\n ...orderedWorkspaces.map(workspace => [workspace.workspaceId, workspace.sessionIds] as const),\n [UNGROUPED_KEY, orderedUngroupedSessionIds] as const,\n [FLAT_SESSION_ORDER_KEY, orderedFlatSessionIds] as const,\n ]), [orderedFlatSessionIds, orderedUngroupedSessionIds, orderedWorkspaces])\n useEffect(() => {\n if (workspacePhase !== 'ready') return\n actions.retainAccountKeys([\n UNGROUPED_KEY,\n FLAT_SESSION_ORDER_KEY,\n ...workspaces.map(workspace => workspace.workspaceId),\n ])\n }, [actions.retainAccountKeys, workspacePhase, workspaces])\n useEffect(() => {\n if (list.phase !== 'ready' || workspaceReady || orderBy !== 'manual' || currentBlank === undefined) return\n // A first prompt can end blank pinning before the Workspace baseline arrives.\n // Preserve saved members until that baseline can establish departures.\n const changed: Record<string, readonly string[]> = {}\n for (const [key, ids] of Object.entries(activeSessionOrders)) {\n if (key !== FLAT_SESSION_ORDER_KEY && workspacePhase !== 'ready') continue\n const saved = sessionOrderByAccount[key] ?? []\n if (ids[0] !== currentBlank || saved[0] === currentBlank) continue\n changed[key] = [currentBlank, ...saved.filter(id => id !== currentBlank)]\n }\n if (Object.keys(changed).length > 0) actions.syncSessionOrders(changed)\n }, [\n actions.syncSessionOrders,\n activeSessionOrders,\n currentBlank,\n list.phase,\n orderBy,\n sessionOrderByAccount,\n workspacePhase,\n workspaceReady,\n ])\n useEffect(() => {\n if (list.phase !== 'ready' || !workspaceReady || orderBy !== 'manual' || currentBlank === undefined) return\n const moved = Object.entries(activeSessionOrders).some(([key, ids]) =>\n ids[0] === currentBlank && sessionOrderByAccount[key]?.[0] !== currentBlank)\n if (moved) actions.syncSessionOrders(activeSessionOrders)\n }, [\n actions.syncSessionOrders,\n activeSessionOrders,\n currentBlank,\n list.phase,\n orderBy,\n sessionOrderByAccount,\n workspaceReady,\n ])\n const saveSessionOrder = (accountKey: string, order: readonly string[]): void => {\n actions.setSessionOrder(accountKey, order, activeSessionOrders)\n }\n // The query outlives the tree and the input (both wide-only) so collapsing\n // does not silently drop an in-progress filter.\n const [query, setQuery] = useState('')\n const [searchExpanded, setSearchExpanded] = useState(false)\n const [revealSessionId, setRevealSessionId] = useState<SessionId | undefined>(undefined)\n const normalizedQuery = sanitizeSearchQuery(query).trim()\n const [remoteSearch, setRemoteSearch] = useState<RemoteSearchState>({\n query: '',\n status: 'idle',\n items: [],\n hasMore: false,\n })\n const searchRoot = useRef<HTMLDivElement | null>(null)\n const searchInput = useRef<HTMLInputElement | null>(null)\n // Section-header + opens the picker menu (same popover in wide and rail\n // states; the menu anchors on this button).\n const wsPickerOpen = shortcutState.addRequested\n const wsPlusRef = useRef<HTMLButtonElement>(null)\n const composingRef = useRef(false)\n\n const openSearchResult = (sessionId: SessionId): void => {\n if (archivedSessionIds.includes(sessionId)) {\n notifyArchivedNotOpenable()\n return\n }\n setRevealSessionId(sessionId)\n setQuery('')\n setSearchExpanded(false)\n open(sessionId)\n }\n const acknowledgeSessionReveal = (sessionId: SessionId): void => {\n setRevealSessionId(current => current === sessionId ? undefined : current)\n }\n useEffect(() => {\n if (normalizedQuery !== '') setRevealSessionId(undefined)\n }, [normalizedQuery])\n\n // Rail search = expand + land in the search box: the flag arms before the\n // expand request; once the shell flips wide the input mounts and takes focus.\n const [searchOnExpand, setSearchOnExpand] = useState(false)\n useEffect(() => {\n if (wide && searchOnExpand) {\n const timer = window.setTimeout(() => {\n searchInput.current?.focus({ preventScroll: true })\n setSearchOnExpand(false)\n }, EXPAND_SLIDE_MS)\n return () => { window.clearTimeout(timer) }\n }\n }, [wide, searchOnExpand])\n useEffect(() => {\n if (shortcutState.searchRequest === 0) return\n closeAddWorkspace()\n setSearchExpanded(true)\n if (!wide) {\n setSearchOnExpand(true)\n expandSidebar()\n } else searchInput.current?.focus({ preventScroll: true })\n }, [shortcutState.searchRequest])\n\n useEffect(() => {\n if (!wide || !searchExpanded || searchOnExpand) return\n searchInput.current?.focus({ preventScroll: true })\n }, [wide, searchExpanded, searchOnExpand])\n\n // Outside-click dismissal stays off while the rail gesture is in flight\n // (searchOnExpand): the rail click flips the shell wide and mounts this\n // listener during its own dispatch, then keeps bubbling to document with\n // the now-unmounted rail button as its target — outside searchRoot, so the\n // listener would dismiss the search that click just opened.\n useEffect(() => {\n if (!wide || !searchExpanded || searchOnExpand) return\n const onClick = (event: MouseEvent): void => {\n if (!(event.target instanceof Node) || searchRoot.current?.contains(event.target) === true) return\n searchInput.current?.blur()\n if (normalizedQuery !== '') return\n setSearchExpanded(false)\n }\n document.addEventListener('click', onClick)\n return () => { document.removeEventListener('click', onClick) }\n }, [normalizedQuery, wide, searchExpanded, searchOnExpand])\n\n useEffect(() => {\n if (normalizedQuery === '') {\n setRemoteSearch({ query: '', status: 'idle', items: [], hasMore: false })\n return\n }\n const controller = new AbortController()\n setRemoteSearch({\n query: normalizedQuery,\n status: 'loading',\n items: [],\n hasMore: false,\n })\n const timer = window.setTimeout(() => {\n searchSessions(normalizedQuery, controller.signal).then((result) => {\n if (controller.signal.aborted) return\n setRemoteSearch({\n query: normalizedQuery,\n status: 'ready',\n items: result.items,\n hasMore: result.hasMore,\n })\n }).catch(() => {\n if (controller.signal.aborted) return\n setRemoteSearch({\n query: normalizedQuery,\n status: 'error',\n items: [],\n hasMore: false,\n })\n })\n }, SEARCH_DEBOUNCE_MS)\n return () => {\n window.clearTimeout(timer)\n controller.abort()\n }\n }, [normalizedQuery, searchSessions])\n\n // Rename dialog (browser-owned so it outlives row unmounts during collapse).\n // The stored title decides whether confirming is a real rename; the draft is\n // seeded with the label on screen. They differ for a Workspace still\n // carrying its automatic title, so confirming the prefill pins that name.\n const [renameTarget, setRenameTarget] = useState<{ workspaceId: WorkspaceId; storedTitle: string } | null>(null)\n const [renameDraft, setRenameDraft] = useState('')\n const [renaming, setRenaming] = useState(false)\n const [renameError, setRenameError] = useState<string | null>(null)\n const renameTrimmed = renameDraft.trim()\n // Self is excluded by identity, not by title: the draft is seeded with the\n // localized label, which for an automatically titled Workspace equals its\n // own displayed title without being a conflict with itself.\n const renameDuplicate = renameTarget !== null && renameTrimmed !== ''\n && workspaces.some(w => w.workspaceId !== renameTarget.workspaceId && w.title === renameTrimmed)\n const renameBlocked = renaming || renameTrimmed === ''\n || renameTarget === null || renameTrimmed === renameTarget.storedTitle || renameDuplicate\n const closeRename = () => {\n if (renaming) return\n setRenameTarget(null)\n setRenameError(null)\n }\n const confirmRename = () => {\n if (renameBlocked) return\n setRenaming(true)\n setRenameError(null)\n renameWorkspace(renameTarget.workspaceId, renameTrimmed).then(() => {\n setRenaming(false)\n setRenameTarget(null)\n }).catch((reason: unknown) => {\n setRenaming(false)\n setRenameError(reason instanceof Error ? reason.message : String(reason))\n })\n }\n\n // The search results' restore button; the row actions own the rest of the\n // Session verbs as slot entries.\n const onSessionUnarchive = (sessionId: SessionNode['id']) => {\n unarchiveSession(sessionId).catch((reason: unknown) => {\n console.warn('session unarchive rejected:', reason)\n })\n }\n\n // Delete dialog is separate from the row so a successful removal can\n // unmount that row without tearing down the in-flight confirmation state.\n const [deleteTarget, setDeleteTarget] = useState<{ workspaceId: WorkspaceId; title: string } | null>(null)\n const [deleting, setDeleting] = useState(false)\n const [deleteCommittedId, setDeleteCommittedId] = useState<WorkspaceId | null>(null)\n const [deleteError, setDeleteError] = useState<string | null>(null)\n useEffect(() => {\n if (deleteCommittedId === null\n || workspaces.some(workspace => workspace.workspaceId === deleteCommittedId)) return\n setDeleting(false)\n setDeleteCommittedId(null)\n setDeleteTarget(null)\n }, [deleteCommittedId, workspaces])\n const closeDelete = () => {\n if (deleting) return\n setDeleteTarget(null)\n setDeleteError(null)\n }\n const confirmDelete = () => {\n /* v8 ignore next -- the Modal is absent without a target and its button is disabled while deleting. */\n if (deleting || deleteTarget === null) return\n setDeleting(true)\n setDeleteCommittedId(null)\n setDeleteError(null)\n deleteWorkspace(deleteTarget.workspaceId).then(() => {\n // Keep the confirmation pending until this component has rendered the\n // committed list projection without the deleted id. Closing earlier\n // exposes one stale React frame to the next Create Workspace gesture.\n setDeleteCommittedId(deleteTarget.workspaceId)\n }).catch((reason: unknown) => {\n setDeleting(false)\n setDeleteError(reason instanceof Error ? reason.message : String(reason))\n })\n }\n\n return (\n <div className={clsx(css.root, !wide && css.rail)}>\n <div className={css.sectionHeader}>\n {wide && (\n <span className={clsx(css.sectionLabel, css.wide, searchExpanded && css.sectionLabelHidden)}>\n {groupBy === 'flat' ? t('section.sessions') : t('section.workspaces')}\n </span>\n )}\n {wide && (\n <div className={clsx(css.searchSlot, searchExpanded && css.searchSlotExpanded)}>\n <div\n ref={searchRoot}\n className={clsx(css.search, searchExpanded && css.searchExpanded)}\n onClick={() => {\n closeAddWorkspace()\n setSearchExpanded(true)\n searchInput.current?.focus()\n }}\n >\n <Tooltip label={t('search')} shortcutKeys={searchShortcut?.keys} side=\"bottom\" delayMs={500} disabled={searchExpanded}>\n <button\n type=\"button\"\n className={css.searchButton}\n aria-label={t('search.sessions.aria')}\n aria-keyshortcuts={searchShortcut?.aria}\n aria-expanded={searchExpanded}\n onClick={() => {\n requestSearch()\n }}\n >\n <IconSearchOutlineRegular size={searchExpanded ? 11 : 14} />\n </button>\n </Tooltip>\n <input\n ref={searchInput}\n className={css.searchInput}\n type=\"text\"\n placeholder={t('search.placeholder')}\n maxLength={SEARCH_QUERY_MAX_CODE_UNITS}\n value={query}\n tabIndex={searchExpanded ? 0 : -1}\n onChange={(e) => { setQuery(sanitizeSearchQuery(e.target.value)) }}\n onKeyDown={(e) => {\n if (e.key !== 'Escape') return\n setQuery('')\n setSearchExpanded(false)\n }}\n />\n {searchExpanded && (\n <button\n type=\"button\"\n className={css.clearButton}\n aria-label={t('search.clear')}\n onClick={(e) => {\n e.stopPropagation()\n setQuery('')\n setSearchExpanded(false)\n }}\n >\n <IconCloseFillRegular />\n </button>\n )}\n </div>\n </div>\n )}\n <div className={clsx(css.headerActions, wide && searchExpanded && css.headerActionsHidden)}>\n {wide && (\n <ViewOptionsMenu\n groupBy={groupBy}\n orderBy={orderBy}\n archivedFilter={archivedFilter}\n onGroupPick={actions.setGroupBy}\n onOrderPick={(mode) => { actions.setOrderBy(mode, activeSessionOrders) }}\n onArchivedFilterPick={actions.setArchivedFilter}\n t={t}\n />\n )}\n {/* Adding is the button's one action, so a composition with no\n picking affordance has nothing to offer here: the region hides the\n button rather than leaving a dead one in the header. */}\n {directoryFlowAvailable && (\n <Tooltip label={t('workspace.add')} shortcutKeys={addShortcut?.keys} side=\"bottom\" delayMs={500}>\n <button\n ref={wsPlusRef}\n type=\"button\"\n className={css.iconButton}\n aria-label={t('workspace.add')}\n aria-keyshortcuts={addShortcut?.aria}\n onClick={() => {\n requestAddWorkspace()\n }}\n >\n <IconProjectAddOutlineRegular size={wide ? 16 : 18} />\n </button>\n </Tooltip>\n )}\n </div>\n {/* Add flow + its error dialog (same package — direct composition). */}\n <WorkspacePickFlow\n t={t}\n open={wsPickerOpen}\n anchorRef={wsPlusRef}\n useWorkspaces={useWorkspaces}\n createWorkspace={createWorkspace}\n useDirectoryFlow={useDirectoryFlow}\n renderDirectoryFlow={owner => renderSlot('sidebar.workspaces.directoryFlow', owner)}\n addOnly\n onBusyChange={setDirectoryBusy}\n side=\"right\"\n onPick={(workspaceId) => {\n closeAddWorkspace()\n startSession(workspaceId)\n }}\n onClose={() => { closeAddWorkspace() }}\n />\n </div>\n\n {/* The collapsed rail keeps search as its own 36px control. */}\n {!wide && <div className={css.search}>\n <Tooltip label={t('search')} shortcutKeys={searchShortcut?.keys}>\n <button\n type=\"button\"\n className={css.searchButton}\n aria-label={t('search.sessions.aria')}\n aria-keyshortcuts={searchShortcut?.aria}\n onClick={() => {\n requestSearch()\n }}\n >\n <IconSearchOutlineRegular size={18} />\n </button>\n </Tooltip>\n </div>}\n\n {/* Always-mounted seat keeps the region's flex slot while the list\n itself is wide-only. */}\n <div className={css.listArea}>\n {wide && (normalizedQuery !== ''\n ? (\n <SearchResults\n usePanelInfo={usePanelInfo}\n useSessions={useSessions}\n useSessionStatus={useSessionStatus}\n open={openSearchResult}\n onUnarchive={onSessionUnarchive}\n workspaces={workspaces}\n archivedSessionIds={archivedSessionIds}\n archivedFilter={archivedFilter}\n query={normalizedQuery}\n remote={remoteSearch}\n resultLimit={searchResultLimit}\n t={t}\n />\n )\n : groupBy === 'flat'\n ? (\n <FlatList\n usePanelInfo={usePanelInfo}\n list={list}\n sessionIds={orderedFlatSessionIds}\n rowState={rowState}\n onLeaveArchivedOnly={leaveArchivedOnly}\n workspaceReady={workspaceReady}\n animationResetKey={`${groupBy}/${orderBy}/${archivedFilter}`}\n useSessionStatus={useSessionStatus}\n open={guardedOpen}\n onSessionRenameRequest={requestSessionRename}\n renderSlot={renderSlot}\n setSessionOrder={saveSessionOrder}\n revealSessionId={revealSessionId}\n onSessionRevealed={acknowledgeSessionReveal}\n t={t}\n />\n )\n : (\n <SessionTree\n usePanelInfo={usePanelInfo}\n useBadgeSettings={useBadgeSettings}\n list={list}\n shortcuts={shortcuts}\n useSessionStatus={useSessionStatus}\n onSessionRenameRequest={requestSessionRename}\n renderSlot={renderSlot}\n workspaces={orderedWorkspaces}\n ungroupedSessionIds={orderedUngroupedSessionIds}\n workspaceReady={workspaceReady}\n nestWorkspaces={groupBy === 'workspace-tree'}\n animationResetKey={`${groupBy}/${orderBy}/${archivedFilter}`}\n groupExpansion={groupExpansion}\n setGroupExpanded={actions.setGroupExpanded}\n setSessionOrder={saveSessionOrder}\n rowState={rowState}\n onLeaveArchivedOnly={leaveArchivedOnly}\n startSession={startSession}\n open={guardedOpen}\n insertWorkspaceBefore={insertWorkspaceBefore}\n revealSessionId={revealSessionId}\n onSessionRevealed={acknowledgeSessionReveal}\n home={home}\n t={t}\n onRenameRequest={(workspaceId, displayTitle) => {\n setRenameTarget({\n workspaceId,\n storedTitle: storedWorkspaces.find(w => w.workspaceId === workspaceId)?.title ?? displayTitle,\n })\n setRenameDraft(displayTitle)\n setRenameError(null)\n }}\n onDeleteRequest={(workspaceId, title) => {\n setDeleteTarget({ workspaceId, title })\n setDeleteError(null)\n }}\n />\n ))}\n </div>\n\n <Modal\n open={renameTarget !== null}\n onClose={closeRename}\n closeLabel={t('close')}\n title={t('rename.workspace.title')}\n footer={(\n <>\n <Button variant=\"outline\" disabled={renaming} onClick={closeRename}>{t('cancel')}</Button>\n <Button variant=\"primary\" disabled={renameBlocked} onClick={confirmRename}>{t('rename')}</Button>\n </>\n )}\n >\n <input\n className={css.renameInput}\n value={renameDraft}\n aria-label={t('field.workspaceName')}\n data-modal-autofocus\n disabled={renaming}\n onFocus={(e) => { e.target.select() }}\n onChange={(e) => { setRenameDraft(e.target.value); setRenameError(null) }}\n onCompositionStart={() => { composingRef.current = true }}\n onCompositionEnd={() => { composingRef.current = false }}\n onKeyDown={(e) => {\n if (e.key === 'Enter' && !composingRef.current) {\n e.preventDefault()\n confirmRename()\n }\n }}\n />\n {renameDuplicate && (\n <div className={css.renameError} role=\"alert\">{t('conflict.named', { name: renameTrimmed })}</div>\n )}\n {renameError !== null && <div className={css.renameError} role=\"alert\">{renameError}</div>}\n </Modal>\n\n <Modal\n open={deleteTarget !== null}\n onClose={closeDelete}\n closeLabel={t('close')}\n title={t('delete.workspace')}\n {...deleteTarget === null\n ? {}\n : { description: t('delete.desc', { name: deleteTarget.title }) }}\n footer={(\n <>\n <Button variant=\"outline\" disabled={deleting} onClick={closeDelete}>{t('cancel')}</Button>\n <Button\n variant=\"outline\"\n className={css.deleteAction}\n disabled={deleting}\n onClick={confirmDelete}\n >\n {t('delete.workspace')}\n </Button>\n </>\n )}\n >\n {deleting && <div className={css.deleteStatus} role=\"status\">{t('delete.pending')}</div>}\n {deleteError !== null && <div className={css.renameError} role=\"alert\">{deleteError}</div>}\n </Modal>\n {shortcutState.forkError !== null && <Toast key={shortcutState.forkError.seq}\n text={t(shortcutState.forkError.reason === 'unavailable' ? 'shortcut.noCompletedTurn' : 'shortcut.forkFailed')}\n onDone={dismissForkError} />}\n </div>\n )\n}\n","/**\n * The archive action: a `sidebar.workspaces.session.menu.item` row and a\n * `sidebar.workspaces.session.row.action` button over one injected behavior,\n * plus the `shell.overlay` dialog that confirms stopping a Session's running\n * work before archiving it. The same entries restore an archived row; the\n * notice a successful archive raises and the diagnostics for Host rejections\n * live in the injected callbacks, not here.\n */\nimport { useState } from 'react'\nimport type { SessionActivity } from '@deepseek-ai/dsh-api-workspace-controller/client'\n// Type-only: the family keys each provider merges; a key this program did not compile takes the generic line.\nimport type {} from '@deepseek-ai/dsh-agent/types'\nimport type {} from '@deepseek-ai/dsh-jobs/view'\nimport type {} from '@deepseek-ai/dsh-schedule/client'\nimport type {} from '@deepseek-ai/dsh-subagent/client'\nimport {\n Button, IconArchiveOutlineRegular, IconUnarchiveOutlineRegular, MenuItemButton, Modal, Tooltip,\n} from '@deepseek-ai/dsh-client-ui-primitives'\nimport type {\n ArchiveSessionInjected, SessionArchiveConfirmInjected, SessionArchiveConfirmProps, SessionArchiveConfirmRequest,\n SessionMenuItemProps, SessionRowActionProps,\n} from '../contract/slots.ts'\nimport css from '../rows/Rows.module.css'\nimport browserCss from '../rows/WorkspaceBrowser.module.css'\n\n/**\n * Menu row (order 400): archive, or restore an archived row.\n * @param props - owner share, the archive share, and the menu open state.\n * @returns the row.\n */\nexport function ArchiveSessionMenuItem({\n sessionId, useArchived, useMenuOpenState, useShortcuts, archiveSession, unarchiveSession, t,\n}: SessionMenuItemProps<ArchiveSessionInjected>) {\n const [, setMenuOpen] = useMenuOpenState()\n const shortcut = useShortcuts(rows => rows.find(row => row.id === 'session.archive'))\n const archived = useArchived(set => set.has(sessionId))\n return (\n <MenuItemButton\n shortcut={archived ? undefined : shortcut}\n icon={archived ? <IconUnarchiveOutlineRegular size={14} /> : <IconArchiveOutlineRegular size={14} />}\n onSelect={() => {\n setMenuOpen(false)\n ;(archived ? unarchiveSession : archiveSession)(sessionId)\n }}\n >\n {t(archived ? 'menu.unarchiveSession' : 'menu.archiveSession')}\n </MenuItemButton>\n )\n}\n\n/**\n * Hover button (order 100): archive, or restore an archived row.\n * @param props - owner share and the archive share.\n * @returns the button.\n */\nexport function ArchiveSessionRowButton({\n sessionId, useArchived, archiveSession, unarchiveSession, t,\n}: SessionRowActionProps<ArchiveSessionInjected>) {\n const archived = useArchived(set => set.has(sessionId))\n return (\n <Tooltip label={t(archived ? 'actions.unarchive' : 'actions.archive')} side=\"bottom\" align=\"end\" delayMs={500}>\n <button\n type=\"button\"\n className={css.iconButton}\n aria-label={t(archived ? 'menu.unarchiveSession' : 'menu.archiveSession')}\n onClick={() => { (archived ? unarchiveSession : archiveSession)(sessionId) }}\n >\n {archived ? <IconUnarchiveOutlineRegular size={14} /> : <IconArchiveOutlineRegular size={14} />}\n </button>\n </Tooltip>\n )\n}\n\n/**\n * The `shell.overlay` entry: nothing while no confirmation is pending,\n * otherwise one dialog per request (keyed by the Session). Confirming asks\n * the Host to stop the listed work and archive; cancelling leaves the\n * Session running and visible.\n * @param props - the request hook, its settlement, the stop-and-archive hop, and the locale seat.\n * @returns the open dialog, or null.\n */\nexport function SessionArchiveConfirmDialog({\n useArchiveRequest, settleSessionArchive, stopAndArchiveSession, t,\n}: SessionArchiveConfirmProps) {\n const request = useArchiveRequest(pending => pending)\n if (request === null) return null\n return (\n <ArchiveConfirmForm\n key={request.sessionId}\n request={request}\n stopAndArchiveSession={stopAndArchiveSession}\n onSettle={settleSessionArchive}\n t={t}\n />\n )\n}\n\n/** One request's dialog: in-flight and error state die with it. */\nfunction ArchiveConfirmForm({ request, stopAndArchiveSession, onSettle, t }: {\n request: SessionArchiveConfirmRequest\n stopAndArchiveSession: SessionArchiveConfirmInjected['stopAndArchiveSession']\n onSettle: () => void\n t: SessionArchiveConfirmProps['t']\n}) {\n const [archiving, setArchiving] = useState(false)\n const [error, setError] = useState<string | null>(null)\n const close = () => {\n if (archiving) return\n onSettle()\n }\n const confirm = () => {\n setArchiving(true)\n setError(null)\n stopAndArchiveSession(request.sessionId).then(() => {\n setArchiving(false)\n onSettle()\n }).catch((reason: unknown) => {\n setArchiving(false)\n setError(reason instanceof Error ? reason.message : String(reason))\n })\n }\n return (\n <Modal\n open\n onClose={close}\n closeLabel={t('close')}\n title={t('archive.confirm.title')}\n description={t('archive.confirm.desc', { title: request.displayTitle })}\n footer={(\n <>\n <Button variant=\"outline\" disabled={archiving} onClick={close}>{t('cancel')}</Button>\n <Button\n variant=\"outline\"\n className={browserCss.deleteAction}\n disabled={archiving}\n onClick={confirm}\n >\n {t('archive.confirm.action')}\n </Button>\n </>\n )}\n >\n <ul className={browserCss.archiveActivity} aria-label={t('archive.confirm.activity')}>\n {request.activity.map((entry, index) => (\n <li key={`${entry.kind}-${String(index)}`}>{activityLine(entry, t)}</li>\n ))}\n </ul>\n {archiving && <div className={browserCss.deleteStatus} role=\"status\">{t('archive.confirm.pending')}</div>}\n {error !== null && <div className={browserCss.renameError} role=\"alert\">{error}</div>}\n </Modal>\n )\n}\n\n/**\n * One family's line: its count and the items' labels (ids when a family\n * carries no label). A family this dictionary does not know — a provider\n * merged into the kind map — falls through to the generic line.\n */\nfunction activityLine(entry: SessionActivity, t: SessionArchiveConfirmProps['t']): string {\n const items = entry.items ?? []\n const n = items.length\n const names = items.map(item => item.label ?? item.id).join(t('archive.confirm.listSeparator'))\n const plural = n === 1 ? 'one' : 'other'\n switch (entry.kind) {\n case 'turn': return t('archive.confirm.turn')\n case 'subagent': return t(`archive.confirm.subagents.${plural}`, { n, names })\n case 'job': return t(`archive.confirm.jobs.${plural}`, { n, names })\n case 'schedule': return t(`archive.confirm.schedules.${plural}`, { n, names })\n default: return t(`archive.confirm.other.${plural}`, { kind: entry.kind, n })\n }\n}\n","/** Derived observable sources for the row actions' injected hooks. */\nimport type { HostObservable } from '@deepseek-ai/dsh-client-ui-slots'\n\n/**\n * Project one observable into another, recomputing only when the source\n * snapshot changes identity, so consumers that select from the projection\n * (a Set lookup per row) never rebuild it per read.\n * @param source - the observable to project.\n * @param project - pure projection of one source snapshot.\n * @returns the projected observable, subscribing through the source.\n */\nexport function derive<S, T>(source: HostObservable<S>, project: (snapshot: S) => T): HostObservable<T> {\n let seen: S | undefined\n let value: T | undefined\n return {\n getSnapshot: () => {\n const snapshot = source.getSnapshot()\n if (value === undefined || snapshot !== seen) {\n seen = snapshot\n value = project(snapshot)\n }\n return value\n },\n subscribe: listener => source.subscribe(listener),\n }\n}\n","/** The fork action: one `sidebar.workspaces.session.menu.item` row. */\nimport { IconBranchOutlineRegular, MenuItemButton } from '@deepseek-ai/dsh-client-ui-primitives'\nimport type { ForkSessionInjected, SessionMenuItemProps } from '../contract/slots.ts'\n\n/**\n * Menu row (order 300): fork at the Session's last completed turn; the child\n * arrives through the Host list beside its source.\n * @param props - owner share, menu open state, and the fork share.\n * @returns the row.\n */\nexport function ForkSessionMenuItem({\n sessionId, useMenuOpenState, useShortcuts, forkSession, t,\n}: SessionMenuItemProps<ForkSessionInjected>) {\n const [, setMenuOpen] = useMenuOpenState()\n const shortcut = useShortcuts(rows => rows.find(row => row.id === 'session.fork'))\n return (\n <MenuItemButton\n shortcut={shortcut}\n icon={<IconBranchOutlineRegular />}\n onSelect={() => {\n setMenuOpen(false)\n forkSession(sessionId)\n }}\n >\n {t('menu.fork')}\n </MenuItemButton>\n )\n}\n","/**\n * The pin action: a `sidebar.workspaces.session.menu.item` row and a\n * `sidebar.workspaces.session.row.action` button over one injected behavior.\n * Pin and archive are mutually exclusive on the Host, so the action reads both\n * sets and does not offer itself on an archived row; what a pin does beyond\n * the Host call (fronting the Session in its saved orders, the failure\n * notice) lives in the injected callbacks, not here.\n */\nimport {\n IconPinFillRegular, IconPinOutlineRegular, MenuItemButton, Tooltip,\n} from '@deepseek-ai/dsh-client-ui-primitives'\nimport type { PinSessionInjected, SessionMenuItemProps, SessionRowActionProps } from '../contract/slots.ts'\nimport css from '../rows/Rows.module.css'\n\ntype PinState = Pick<SessionMenuItemProps<PinSessionInjected>, 'sessionId' | 'usePinned' | 'useArchived'>\n\n/** The row's pin and archive membership, one Set lookup each. */\nfunction usePinState({ sessionId, usePinned, useArchived }: PinState) {\n return {\n pinned: usePinned(pinned => pinned.has(sessionId)),\n archived: useArchived(archived => archived.has(sessionId)),\n }\n}\n\n/**\n * Menu row (order 100): pin or unpin by the row's current state; absent on archived rows.\n * @param props - owner share, the pin share, and the menu open state.\n * @returns the row, or null for an archived Session.\n */\nexport function PinSessionMenuItem(props: SessionMenuItemProps<PinSessionInjected>) {\n const { sessionId, useMenuOpenState, pinSession, unpinSession, t } = props\n const [, setMenuOpen] = useMenuOpenState()\n const { pinned, archived } = usePinState(props)\n if (archived) return null\n return (\n <MenuItemButton\n icon={pinned ? <IconPinFillRegular /> : <IconPinOutlineRegular />}\n onSelect={() => {\n setMenuOpen(false)\n ;(pinned ? unpinSession : pinSession)(sessionId)\n }}\n >\n {t(pinned ? 'menu.unpinSession' : 'menu.pinSession')}\n </MenuItemButton>\n )\n}\n\n/**\n * Hover button (order 200, rightmost: it lands where the rest-state pin marker sits); absent on archived rows.\n * @param props - owner share and the pin share.\n * @returns the button, or null for an archived Session.\n */\nexport function PinSessionRowButton(props: SessionRowActionProps<PinSessionInjected>) {\n const { sessionId, pinSession, unpinSession, t } = props\n const { pinned, archived } = usePinState(props)\n if (archived) return null\n return (\n <Tooltip label={t(pinned ? 'actions.unpin' : 'actions.pin')} side=\"bottom\" align=\"end\" delayMs={500}>\n <button\n type=\"button\"\n className={css.iconButton}\n aria-label={t(pinned ? 'menu.unpinSession' : 'menu.pinSession')}\n onClick={() => { (pinned ? unpinSession : pinSession)(sessionId) }}\n >\n {pinned ? <IconPinFillRegular size={14} /> : <IconPinOutlineRegular size={14} />}\n </button>\n </Tooltip>\n )\n}\n","/**\n * The rename action: a `sidebar.workspaces.session.menu.item` row that raises\n * the rename request, and the `shell.overlay` dialog entry that answers it.\n * The dialog lives outside the row menu because the row unmounts with the\n * menu; the browser raises the same request from a title double-click.\n */\nimport { useRef, useState } from 'react'\nimport { Button, IconEditOutlineRegular, MenuItemButton, Modal } from '@deepseek-ai/dsh-client-ui-primitives'\nimport type {\n RenameSessionInjected, SessionMenuItemProps, SessionRenameDialogInjected, SessionRenameDialogProps, SessionRenameTarget,\n} from '../contract/slots.ts'\nimport css from '../rows/WorkspaceBrowser.module.css'\n\n/**\n * Menu row (order 200): ask for the rename dialog, seeded with the row's current title.\n * @param props - owner share, menu open state, and the rename share.\n * @returns the row.\n */\nexport function RenameSessionMenuItem({\n sessionId, displayTitle, useMenuOpenState, useShortcuts, requestSessionRename, t,\n}: SessionMenuItemProps<RenameSessionInjected>) {\n const [, setMenuOpen] = useMenuOpenState()\n const shortcut = useShortcuts(rows => rows.find(row => row.id === 'session.rename'))\n return (\n <MenuItemButton\n shortcut={shortcut}\n icon={<IconEditOutlineRegular />}\n onSelect={() => {\n setMenuOpen(false)\n requestSessionRename(sessionId, displayTitle)\n }}\n >\n {t('rename')}\n </MenuItemButton>\n )\n}\n\n/**\n * The `shell.overlay` entry: nothing while no rename is requested, otherwise\n * one dialog per request (keyed by the Session, so a new request starts a\n * fresh draft). Sessions have no client-side name-conflict rule (the host\n * normalizes), and unlike Workspace rename an unchanged title is NOT\n * blocked. An unnamed Session starts with an empty draft and requires a name.\n * @param props - the request hook, its settlement, the rename hop, and the locale seat.\n * @returns the open dialog, or null.\n */\nexport function SessionRenameDialog({ useRenameRequest, settleSessionRename, renameSession, t }: SessionRenameDialogProps) {\n const request = useRenameRequest(pending => pending)\n if (request === null) return null\n return (\n <RenameForm\n key={request.sessionId}\n request={request}\n renameSession={renameSession}\n onSettle={settleSessionRename}\n t={t}\n />\n )\n}\n\n/** One request's dialog: the draft seeds from the request on mount; in-flight and error state die with it. */\nfunction RenameForm({ request, renameSession, onSettle, t }: {\n request: SessionRenameTarget\n renameSession: SessionRenameDialogInjected['renameSession']\n onSettle: () => void\n t: SessionRenameDialogProps['t']\n}) {\n const [draft, setDraft] = useState(request.currentTitle)\n const [renaming, setRenaming] = useState(false)\n const [error, setError] = useState<string | null>(null)\n // IME composition: Enter that commits a composition must not submit.\n const composingRef = useRef(false)\n const trimmed = draft.trim()\n const blocked = renaming || trimmed === ''\n const close = () => {\n if (renaming) return\n onSettle()\n }\n const confirm = () => {\n if (blocked) return\n setRenaming(true)\n setError(null)\n renameSession(request.sessionId, trimmed).then(() => {\n setRenaming(false)\n onSettle()\n }).catch((reason: unknown) => {\n setRenaming(false)\n setError(reason instanceof Error ? reason.message : String(reason))\n })\n }\n return (\n <Modal\n open\n onClose={close}\n closeLabel={t('close')}\n title={t('rename.session.title')}\n footer={(\n <>\n <Button variant=\"outline\" disabled={renaming} onClick={close}>{t('cancel')}</Button>\n <Button variant=\"primary\" disabled={blocked} onClick={confirm}>{t('rename')}</Button>\n </>\n )}\n >\n <input\n className={css.renameInput}\n value={draft}\n aria-label={t('field.sessionName')}\n data-modal-autofocus\n disabled={renaming}\n onFocus={(e) => { e.target.select() }}\n onChange={(e) => { setDraft(e.target.value); setError(null) }}\n onCompositionStart={() => { composingRef.current = true }}\n onCompositionEnd={() => { composingRef.current = false }}\n onKeyDown={(e) => {\n if (e.key === 'Enter' && !composingRef.current) {\n e.preventDefault()\n confirm()\n }\n }}\n />\n {error !== null && <div className={css.renameError} role=\"alert\">{error}</div>}\n </Modal>\n )\n}\n","/**\n * The `shell.overlay` entry for Workspace and Session notices.\n * One notice is visible at a time; a parent rerender does not extend its hold.\n */\nimport { IconWarningOutlineRegular, Toast } from '@deepseek-ai/dsh-client-ui-primitives'\nimport { assertNever } from '@deepseek-ai/dsh-util-values'\nimport type { RowToastProps, RowToastState } from '../contract/slots.ts'\n\n/**\n * Hold for the notices that take longer to read than a one-line warning: the\n * actionable archived notice (two buttons to react to) and a refused Session\n * creation, which quotes the Host's reason.\n */\nconst LONG_TOAST_HOLD_MS = 6000\n\n/**\n * Render the current notice: the archived and stopped-and-archived notices\n * with their undo action — plus the show-archived action while archived rows\n * are hidden — on a 6 s hold, a refused Session creation with the Host's\n * reason on the same hold, or a plain warning for a failed pin, an archived\n * row that was clicked, or default Workspace creation.\n * @param props - the notice hook, the shared viewing store, the notice dismissal, the two archived-notice actions, and the locale seat.\n * @returns the notice on display, or null.\n */\nexport function RowActionToast({ useToast, useStore, dismissToast, undoArchive, showArchived, t }: RowToastProps) {\n const toast = useToast(current => current)\n const archivedRowsVisible = useStore(state => (state.archivedFilter ?? 'default') !== 'default')\n if (toast === null) return null\n if (toast.kind === 'archived' || toast.kind === 'stoppedAndArchived') {\n const { sessionId } = toast\n return (\n <Toast\n key={`toast-${String(toast.seq)}`}\n text={t(toast.kind === 'archived' ? 'toast.archived' : 'toast.stoppedAndArchived')}\n tone=\"success\"\n holdMs={LONG_TOAST_HOLD_MS}\n actions={[\n { label: t('toast.archivedUndo'), onClick: () => { dismissToast(); undoArchive(sessionId) } },\n ...archivedRowsVisible ? [] : [\n { prefix: t('toast.archivedOr'), label: t('toast.archivedFilter'), onClick: () => { dismissToast(); showArchived() } },\n ],\n ]}\n onDone={dismissToast}\n />\n )\n }\n if (toast.kind === 'createFailed') {\n return (\n <Toast\n key={`toast-${String(toast.seq)}`}\n text={t('toast.createFailed', { message: toast.message })}\n icon={<IconWarningOutlineRegular />}\n holdMs={LONG_TOAST_HOLD_MS}\n onDone={dismissToast}\n />\n )\n }\n return (\n <Toast\n key={`toast-${String(toast.seq)}`}\n text={plainNoticeText(toast, t)}\n icon={<IconWarningOutlineRegular />}\n onDone={dismissToast}\n />\n )\n}\n\n/** The copy of one plain warning, keyed by the notice kind the union closes over. */\nfunction plainNoticeText(\n toast: Exclude<RowToastState, { kind: 'archived' | 'stoppedAndArchived' | 'createFailed' }>,\n t: RowToastProps['t'],\n): string {\n switch (toast.kind) {\n case 'pinFailed': return t('toast.pinFailed')\n case 'unpinFailed': return t('toast.unpinFailed')\n case 'defaultWorkspaceFailed': return t('defaultWorkspace.failed')\n case 'archivedNotOpenable': return t('toast.archivedNotOpenable')\n /* v8 ignore next 2 -- closed-union backstop; only reached if a notice kind is forged */\n default:\n return assertNever(toast)\n }\n}\n","/**\n * `workspace` namespace dictionaries: the browsing region (section header,\n * search, tree rows, dialogs) and the pick/add flow. Runtime failure\n * messages (wire error strings) pass through untranslated by policy.\n */\n\n/** Simplified Chinese dictionary (the key-set source of truth). */\nexport const zh = {\n 'defaultWorkspace.failed': '无法创建默认工作区,请通过“选择工作区”选择文件夹',\n 'group.ungrouped': '未分组',\n 'session.new': '新会话',\n 'session.untitled': '未命名',\n 'shortcut.noSession': '请先选择一个会话',\n 'shortcut.noPicker': '目录选择器不可用',\n 'shortcut.directoryBusy': '正在选择或添加工作区',\n 'shortcut.noCompletedTurn': '当前会话没有已结束的轮次',\n 'shortcut.forkFailed': '无法分叉会话,请重试',\n 'section.workspaces': '工作区',\n 'section.sessions': '会话',\n 'viewOptions.label': '视图选项',\n 'groupBy.label': '分组方式',\n 'groupBy.workspace': '按工作区',\n 'groupBy.workspaceTree': '按工作区树',\n 'groupBy.flat': '单列表',\n 'orderBy.label': '排序方式',\n 'orderBy.manual': '手动排序',\n 'orderBy.updated': '最近更新',\n 'filterBy.label': '筛选会话',\n 'viewOptions.hideArchived': '隐藏已归档',\n 'viewOptions.showArchived': '全部对话(显示已归档)',\n 'viewOptions.onlyArchived': '仅显示已归档',\n 'sessions.expand': '展开其余 {n} 个会话',\n 'sessions.collapse': '收起',\n 'empty.none': '暂无会话',\n 'empty.noneArchived': '暂无已归档会话',\n 'empty.viewOthers': '查看其他会话',\n 'empty.noMatches': '无匹配结果',\n 'workspace.add': '添加工作区',\n 'search.sessions.aria': '搜索会话',\n 'search.placeholder': '搜索会话名称',\n 'search.clear': '清除搜索',\n 'search.results.aria': '搜索结果',\n 'search.pending': '正在搜索会话历史…',\n 'search.noMatches': '无匹配会话',\n 'search.hasMore': '仅显示前 {n} 条结果,请缩小搜索范围。',\n 'menu.addWorkspace': '添加工作区…',\n 'picker.loading': '正在加载工作区…',\n 'conflict.named': '已存在名为“{name}”的工作区。',\n 'folderError.title': '无法打开文件夹',\n 'folderError.retry': '重新选择',\n 'rename': '重命名',\n 'rename.workspace.title': '重命名工作区',\n 'rename.session.title': '重命名会话',\n 'field.workspaceName': '工作区名称',\n 'field.sessionName': '会话名称',\n 'delete.workspace': '删除工作区',\n 'delete.desc': '将把“{name}”从工作区列表中移除。文件夹与会话记录会保留,其会话将显示在“未分组”下。',\n 'delete.pending': '正在删除工作区…',\n 'menu.fork': '分叉会话',\n 'menu.archiveSession': '归档会话',\n 'menu.unarchiveSession': '取消归档',\n 'menu.pinSession': '置顶会话',\n 'menu.unpinSession': '取消置顶',\n 'row.archived': '已归档',\n 'row.pinned': '已置顶',\n 'toast.archivedNotOpenable': '已归档对话暂时无法查看,请取消归档后查看',\n 'toast.archived': '会话已归档,可',\n 'toast.stoppedAndArchived': '已停止并归档,可',\n 'archive.confirm.title': '停止并归档此会话?',\n 'archive.confirm.desc': '“{title}”仍有正在进行的工作。归档会先停止这些工作;之后可在侧栏筛选“全部对话(显示已归档)”中恢复会话,被停止的工作不会自动继续。',\n 'archive.confirm.activity': '将被停止的工作',\n 'archive.confirm.turn': '进行中的回合',\n 'archive.confirm.subagents.one': '{n} 个运行中的子智能体:{names}',\n 'archive.confirm.subagents.other': '{n} 个运行中的子智能体:{names}',\n 'archive.confirm.jobs.one': '{n} 个后台任务:{names}',\n 'archive.confirm.jobs.other': '{n} 个后台任务:{names}',\n 'archive.confirm.schedules.one': '{n} 条定时提醒:{names}',\n 'archive.confirm.schedules.other': '{n} 条定时提醒:{names}',\n 'archive.confirm.other.one': '{n} 项其他工作({kind})',\n 'archive.confirm.other.other': '{n} 项其他工作({kind})',\n 'archive.confirm.listSeparator': '、',\n 'archive.confirm.action': '停止并归档',\n 'archive.confirm.pending': '正在停止并归档…',\n 'toast.archivedUndo': '撤销',\n 'toast.archivedOr': '或',\n 'toast.archivedFilter': '筛选已归档会话',\n 'toast.pinFailed': '置顶失败,请稍后重试',\n 'toast.unpinFailed': '取消置顶失败,请稍后重试',\n 'toast.createFailed': '新建会话失败:{message}',\n 'sessions.count.one': '{n} 个会话',\n 'sessions.count.other': '{n} 个会话',\n 'actions.workspace.aria': '工作区“{name}”的操作',\n 'actions.session.aria': '会话“{name}”的操作',\n 'actions.archive': '归档会话',\n 'actions.unarchive': '取消归档',\n 'actions.pin': '置顶会话',\n 'actions.unpin': '取消置顶',\n 'actions.newSession': '新会话',\n 'actions.newSession.aria': '在“{name}”中新建会话',\n 'status.running': '进行中',\n 'status.subagentsRunning.one': '{n} 个子智能体运行中',\n 'status.subagentsRunning.other': '{n} 个子智能体运行中',\n 'status.idle': '空闲',\n 'status.waitingApproval': '等待审批',\n 'status.planReview': '计划待审',\n 'status.waitingAnswer': '等待回答',\n 'status.compact.approval': '待审批',\n 'status.compact.planReview': '计划待审',\n 'status.compact.answer': '待回答',\n 'status.waitingReview': '等待评审',\n 'status.scheduled': '定时任务',\n 'status.completed': '已完成',\n 'hover.created': '创建于 {time}',\n 'hover.copied': '已复制',\n 'date.ymd': '{y}年{m}月{d}日',\n 'time.now': '刚刚',\n 'time.minutes': '{n}分钟',\n 'time.hours': '{n}小时',\n 'time.days': '{n}天',\n 'time.months': '{n}个月',\n 'time.years': '{n}年',\n 'time.ago': '{t}前',\n 'settings.badge.section': '折叠徽标',\n 'settings.badge.showRunning': '显示「进行中」转圈',\n 'settings.badge.showRunningHint': '关闭后,进行中的会话(含子智能体)不再画转圈,也不再计入折叠徽标的数字与悬停明细。',\n 'settings.badge.showPending': '显示「待审批」黄点',\n 'settings.badge.showPendingHint': '关闭后,等待审批 / 计划评审 / 等待回答的会话不再画黄点,也不再计入折叠徽标的数字与悬停明细。',\n 'settings.badge.showCompleted': '显示「已完成」绿点',\n 'settings.badge.showCompletedHint': '关闭后,「已完成」的会话不再画绿点,也不再计入折叠徽标的数字与悬停明细。会话行自身的绿点不受影响。',\n 'settings.badge.showScheduled': '显示「定时任务」时钟',\n 'settings.badge.showScheduledHint': '关闭后,带定时提醒的会话(来自 dsh-later)不再画时钟图标,也不再计入折叠徽标的数字与悬停明细。',\n 'settings.badge.showWaitingReview': '显示「等待评审」列表笔',\n 'settings.badge.showWaitingReviewHint': '关闭后,等待代码评审的会话(来自 dsh-gitea-dispatch)不再画列表笔图标,也不再计入折叠徽标的数字与悬停明细。',\n 'settings.hover.section': '悬停明细',\n 'settings.hover.showDetails': '显示状态明细行',\n 'settings.hover.showDetailsHint': '关闭后,悬停卡只显示工作区标题、路径和创建时间——不再显示聚合状态明细行。',\n 'settings.count.section': '数字显示',\n 'settings.count.threshold': '数字显示阈值',\n 'settings.count.thresholdHint': '数量 >= 此值时才在徽标上显示数字。默认 2(即 count=1 时省略,因为状态点已表达\"有东西\")。设为 1 则始终显示。',\n 'settings.save': '保存',\n 'settings.saving': '保存中…',\n 'settings.saveFailed': '本部署没有接受这些值,已保留供你修改。',\n 'settings.readOnly': '本部署的设置为只读。',\n 'settings.unavailable': '该插件当前未加载,暂时无法配置。',\n} satisfies Record<string, string>\n\n/** The workspace namespace key union. */\nexport type WorkspaceKey = keyof typeof zh\n\n/** English dictionary, checked complete against the zh key set. */\nexport const en = {\n 'defaultWorkspace.failed': 'Unable to create default workspace. Use Choose workspace to select a folder.',\n 'group.ungrouped': 'Ungrouped',\n 'session.new': 'New Session',\n 'session.untitled': 'Untitled',\n 'shortcut.noSession': 'Select a session first',\n 'shortcut.noPicker': 'Directory picker unavailable',\n 'shortcut.directoryBusy': 'Selecting or adding a workspace',\n 'shortcut.noCompletedTurn': 'This session has no completed turn',\n 'shortcut.forkFailed': 'Could not fork the session. Try again.',\n 'section.workspaces': 'Workspaces',\n 'section.sessions': 'Sessions',\n 'viewOptions.label': 'View options',\n 'groupBy.label': 'Group by',\n 'groupBy.workspace': 'WorkSpace',\n 'groupBy.workspaceTree': 'Workspace Tree',\n 'groupBy.flat': 'In one list',\n 'orderBy.label': 'Order by',\n 'orderBy.manual': 'Manual',\n 'orderBy.updated': 'Last updated',\n 'filterBy.label': 'Filter sessions',\n 'viewOptions.hideArchived': 'Hide archived',\n 'viewOptions.showArchived': 'All conversations (show archived)',\n 'viewOptions.onlyArchived': 'Archived only',\n 'sessions.expand': 'Show {n} more sessions',\n 'sessions.collapse': 'Show less',\n 'empty.none': 'No sessions yet',\n 'empty.noneArchived': 'No archived sessions yet',\n 'empty.viewOthers': 'View other sessions',\n 'empty.noMatches': 'No matches',\n 'workspace.add': 'Add workspace',\n 'search.sessions.aria': 'Search sessions',\n 'search.placeholder': 'Search session names',\n 'search.clear': 'Clear search',\n 'search.results.aria': 'Search results',\n 'search.pending': 'Searching session history…',\n 'search.noMatches': 'No matching sessions',\n 'search.hasMore': 'Showing the first {n} results. Narrow your search.',\n 'menu.addWorkspace': 'Add workspace…',\n 'picker.loading': 'Loading workspaces…',\n 'conflict.named': 'A workspace named “{name}” already exists.',\n 'folderError.title': 'Couldn’t open folder',\n 'folderError.retry': 'Choose again',\n 'rename': 'Rename',\n 'rename.workspace.title': 'Rename workspace',\n 'rename.session.title': 'Rename session',\n 'field.workspaceName': 'Workspace name',\n 'field.sessionName': 'Session name',\n 'delete.workspace': 'Delete workspace',\n 'delete.desc': 'This removes “{name}” from the workspace list. The folder and session logs will be kept. Its sessions will appear under Ungrouped.',\n 'delete.pending': 'Deleting workspace…',\n 'menu.fork': 'Fork session',\n 'menu.archiveSession': 'Archive session',\n 'menu.unarchiveSession': 'Unarchive session',\n 'menu.pinSession': 'Pin session',\n 'menu.unpinSession': 'Unpin session',\n 'row.archived': 'Archived',\n 'row.pinned': 'Pinned',\n 'toast.archivedNotOpenable': 'Archived sessions cannot be opened. Unarchive it to view.',\n 'toast.archived': 'Session archived. You can ',\n 'toast.stoppedAndArchived': 'Session stopped and archived. You can ',\n 'archive.confirm.title': 'Stop and archive this session?',\n 'archive.confirm.desc': '“{title}” still has work in progress. Archiving stops it first; you can restore the session later from the “All conversations (show archived)” filter in the sidebar, and the stopped work will not resume on its own.',\n 'archive.confirm.activity': 'Work that will be stopped',\n 'archive.confirm.turn': 'The turn in progress',\n 'archive.confirm.subagents.one': '{n} running subagent: {names}',\n 'archive.confirm.subagents.other': '{n} running subagents: {names}',\n 'archive.confirm.jobs.one': '{n} background job: {names}',\n 'archive.confirm.jobs.other': '{n} background jobs: {names}',\n 'archive.confirm.schedules.one': '{n} scheduled reminder: {names}',\n 'archive.confirm.schedules.other': '{n} scheduled reminders: {names}',\n 'archive.confirm.other.one': '{n} other item of work ({kind})',\n 'archive.confirm.other.other': '{n} other items of work ({kind})',\n 'archive.confirm.listSeparator': ', ',\n 'archive.confirm.action': 'Stop and archive',\n 'archive.confirm.pending': 'Stopping and archiving…',\n 'toast.archivedUndo': 'undo',\n 'toast.archivedOr': ' or ',\n 'toast.archivedFilter': 'filter archived sessions',\n 'toast.pinFailed': 'Pin failed. Try again later.',\n 'toast.unpinFailed': 'Unpin failed. Try again later.',\n 'toast.createFailed': 'New session failed: {message}',\n 'sessions.count.one': '{n} session',\n 'sessions.count.other': '{n} sessions',\n 'actions.workspace.aria': 'Workspace actions for {name}',\n 'actions.session.aria': 'Session actions for {name}',\n 'actions.archive': 'Archive',\n 'actions.unarchive': 'Unarchive',\n 'actions.pin': 'Pin',\n 'actions.unpin': 'Unpin',\n 'actions.newSession': 'New session',\n 'actions.newSession.aria': 'New session in {name}',\n 'status.running': 'Running',\n 'status.subagentsRunning.one': '{n} subagent running',\n 'status.subagentsRunning.other': '{n} subagents running',\n 'status.idle': 'Idle',\n 'status.waitingApproval': 'Waiting for approval',\n 'status.planReview': 'Plan awaiting review',\n 'status.waitingAnswer': 'Waiting for answer',\n 'status.compact.approval': 'Approval',\n 'status.compact.planReview': 'Plan review',\n 'status.compact.answer': 'Answer',\n 'status.waitingReview': 'Waiting for review',\n 'status.scheduled': 'Scheduled',\n 'status.completed': 'Completed',\n 'hover.created': 'Created {time}',\n 'hover.copied': 'Copied',\n 'date.ymd': '{y}-{m}-{d}',\n 'time.now': 'now',\n 'time.minutes': '{n}min',\n 'time.hours': '{n}h',\n 'time.days': '{n}d',\n 'time.months': '{n}mo',\n 'time.years': '{n}y',\n 'time.ago': '{t} ago',\n 'settings.badge.section': 'Collapsed badge',\n 'settings.badge.showRunning': 'Show the running dot',\n 'settings.badge.showRunningHint': 'When off, running Sessions (and subagents) stop drawing the spinning dot and drop out of the collapsed badge count and its hover details.',\n 'settings.badge.showPending': 'Show the pending dot',\n 'settings.badge.showPendingHint': 'When off, Sessions waiting for approval / plan review / answer stop drawing the yellow dot and drop out of the collapsed badge count and its hover details.',\n 'settings.badge.showCompleted': 'Show the completed dot',\n 'settings.badge.showCompletedHint': 'When off, completed Sessions stop drawing the dot and drop out of the collapsed badge count and its hover details. The Session row\\'s own dot is unaffected.',\n 'settings.badge.showScheduled': 'Show the scheduled icon',\n 'settings.badge.showScheduledHint': 'When off, Sessions with scheduled reminders (from dsh-later) stop drawing the clock icon and drop out of the collapsed badge count and its hover details.',\n 'settings.badge.showWaitingReview': 'Show the waiting-for-review icon',\n 'settings.badge.showWaitingReviewHint': 'When off, Sessions waiting for code review (from dsh-gitea-dispatch) stop drawing the list-pen icon and drop out of the collapsed badge count and its hover details.',\n 'settings.hover.section': 'Hover details',\n 'settings.hover.showDetails': 'Show status detail lines',\n 'settings.hover.showDetailsHint': 'When off, the hover card shows only the workspace title, path, and creation time — no aggregated status lines.',\n 'settings.count.section': 'Count display',\n 'settings.count.threshold': 'Count display threshold',\n 'settings.count.thresholdHint': 'The count is shown on the badge only when the total is >= this value. Default 2 (omits the count when it equals 1 — the dots already convey \"something is happening\"). Set to 1 to always show.',\n 'settings.save': 'Save',\n 'settings.saving': 'Saving…',\n 'settings.saveFailed': 'The deployment did not accept these values; they were left for you to correct.',\n 'settings.readOnly': 'This deployment stores settings read-only.',\n 'settings.unavailable': 'This plugin is not loaded, so it cannot be configured right now.',\n} satisfies Record<WorkspaceKey, string>\n","/**\n * Workspace plugin, browser half. Two registrations: WorkspaceBrowser fills\n * the sidebar shell's `sidebar.workspaces` hole (the whole browsing region),\n * and WorkspacePicker fills the conversation hero's picker hole\n * (`conversation.hero.workspace` — both hero forms). Both read real Host\n * Workspaces through the global useWorkspaces hook, and each declares its\n * own `single` directory-flow child hole for the composed picker package's\n * client half. WorkspaceBrowser additionally declares the two Session row\n * action lists, and this apply registers the shipped actions — pin, rename,\n * fork, archive — into them the way any client plugin would, each with its\n * own behavior, plus the rename dialog and the row-action notice into\n * `shell.overlay` (see the contract module doc). It also declares two\n * Session-row seats: the leading decoration a row renders only while its own\n * primary state is idle, and the section the row's hover card renders between\n * its relative time and its trailing status line. Export discipline:\n * packages/client/AGENTS.md.\n */\nimport type {} from '@deepseek-ai/dsh-client-product-analytics/client'\nimport type { Context } from '@deepseek-ai/cordis'\nimport type { RemoteHostFacts } from '@deepseek-ai/dsh-api-remotes/client'\nimport type { ISessions } from '@deepseek-ai/dsh-api-session-controller/client'\nimport type {\n IWorkspaces, SessionActivity, WorkspaceArchiveError, WorkspaceSnapshot,\n} from '@deepseek-ai/dsh-api-workspace-controller/client'\nimport { createSnapshotStore } from '@deepseek-ai/dsh-client-store'\nimport type { HostObservable, SnapshotSelectorHook } from '@deepseek-ai/dsh-client-ui-slots'\nimport type { SessionId } from '@deepseek-ai/dsh-session/types'\n// Type-only: pulls the Controller service merges.\nimport type {} from '@deepseek-ai/dsh-api-session-controller/client'\nimport type {} from '@deepseek-ai/dsh-api-workspace-controller/client'\n// Type-only: pulls the locale plugin's Context merge (ctx.locale).\nimport type {} from '@deepseek-ai/dsh-client-locale/client'\n// Type-only: pulls the SlotRegistry service merge (ctx.slots).\nimport type {} from '@deepseek-ai/dsh-client-ui-renderer/client'\nimport type {} from '@deepseek-ai/dsh-client-ui-layout/client'\n// Type-only: pulls the Session root standard-hook merge.\nimport type {} from '@deepseek-ai/dsh-client-ui-session/client'\n// Type-only:插件页卡片的官方设置表单契约(运行时由 `configForms` 服务提供)。\nimport type { SettingsFormScope } from '@deepseek-ai/dsh-client-ui-primitives'\nimport {\n type ArchiveSessionInjected, type ForkSessionInjected, menuOpenStateFactory, type PinSessionInjected,\n type SessionArchiveConfirmInjected, type SessionArchiveConfirmRequest,\n type RenameSessionInjected, type RowToast, type RowToastInjected, type RowToastState, type SessionRenameDialogInjected,\n type WorkspaceBrowserInjected, type WorkspacePickerInjected,\n} from './contract/slots.ts'\nimport { createWorkspaceShortcutControls, installWorkspaceShortcuts } from './shortcuts.ts'\nimport { createBadgeSettingsSource, ENTRY_ID, type ResolvedBadgeSettings } from './badge-settings.ts'\nimport { BadgeSettingsCard } from './BadgeSettingsCard.tsx'\nimport { UiWorkspaceService } from './navigation.ts'\nimport { createWorkspaceViewStore } from './stores.ts'\nimport { WorkspaceBrowser } from './rows/WorkspaceBrowser.tsx'\nimport { ArchiveSessionMenuItem, ArchiveSessionRowButton, SessionArchiveConfirmDialog } from './session-actions/ArchiveSession.tsx'\nimport { derive } from './session-actions/derived.ts'\nimport { ForkSessionMenuItem } from './session-actions/ForkSession.tsx'\nimport { PinSessionMenuItem, PinSessionRowButton } from './session-actions/PinSession.tsx'\nimport { RenameSessionMenuItem, SessionRenameDialog } from './session-actions/RenameSession.tsx'\nimport { RowActionToast } from './session-actions/RowActionToast.tsx'\nimport { WorkspacePicker } from './WorkspacePicker.tsx'\nimport { en, zh, type WorkspaceKey } from './locales.ts'\n\nexport type { UiWorkspace } from './navigation.ts'\nexport type {\n DirectoryFlowOwnerProps, DirectoryFlowSlotName, DirectoryPickingHooks, DirectoryPickingInjected,\n MenuOpenState, RowToast, SessionRenameTarget, SessionRowOwnerProps, UseMenuOpenState, WorkspaceBrowserInjected,\n SessionRowScheduleOwnerProps,\n WorkspaceBrowserProps,\n WorkspacePickerInjected, WorkspacePickerProps,\n} from './contract/slots.ts'\nexport type { WorkspaceKey } from './locales.ts'\n\ndeclare module '@deepseek-ai/dsh-client-ui-slots' {\n interface GlobalStandardProps {\n /** Selector hook over the pure Workspace Controller snapshot. */\n useWorkspaces: SnapshotSelectorHook<WorkspaceSnapshot>\n /** Selector hook over this plugin's own settings face (badge preferences). */\n useBadgeSettings: SnapshotSelectorHook<ResolvedBadgeSettings>\n }\n\n interface LocaleNamespaceMap {\n /** The workspace browsing region and pick/create flow copy. */\n workspace: WorkspaceKey\n }\n}\n\ndeclare module '@deepseek-ai/dsh-api-session-controller/client' {\n interface SessionReferenceSourceMap {\n workspaceOperation: unknown\n }\n}\n\n/** Dictionary namespace owned by this plugin. */\nconst NS = 'workspace'\n\n/**\n * `configForms` 服务的最小结构面(宿主 `@deepseek-ai/dsh-client-ui-settings` 的\n * 一部分)。此处按结构声明而非导入该包:本插件不需要设置页的其余能力,窄化的\n * 形状让服务缺席时降级为一个 `undefined` 检查而非编译期依赖。\n *\n * `get` 的返回类型直接用官方 `SettingsFormScope`:那就是 `configForms.get(条目 id)`\n * 的运行时形状(`getSnapshot` / `subscribe` / `mutate`),设置卡片(官方\n * `SettingsFormModel`)要的也正是它,因此不需要本地复刻一份契约。\n *\n * `whileServed` 可选:它在 0.1.7 settings rewrite 一代才有,用于「宿主仍在服务该\n * 条目命名空间时」维持一段注册。缺席时只跳过插件页卡片,折叠徽标的读通道照常。\n */\ninterface ConfigFormsLike {\n get(entryId: string): SettingsFormScope<Record<string, unknown>>\n whileServed?(\n entryIds: readonly string[],\n register: (served: ReadonlySet<string>) => () => void,\n ): () => void\n}\n\n/** 插件详情页配置表单的槽位名(按包名寻址;契约见 `plugin-manager-slot.d.ts`)。 */\nconst CONFIG_CARD_SLOT = 'plugins.bundle.config'\n\n/**\n * 插件管理器分发 `plugins.bundle.config` 用的键 = **包名**(不是条目 id)。\n * 本包的补丁把行 id 也写成同名,但两者是不同概念,别改成 ENTRY_ID 的引用。\n */\nconst CONFIG_CARD_KEY = 'dsh-group-status'\n\n/**\n * Required services (cordis fiber inject). The target slots are declared by\n * the ui-sidebar / ui-conversation applies, whose activation order relative\n * to this one is NOT constrained: dsh.client.inject edges are informational\n * (loading/prefetch metadata, never apply sequencing) and neither owner\n * provides a waitable service. apply therefore depends on each slot\n * declaration through `slots.inject()` instead of assuming order.\n */\nexport const inject = [\n 'slots', 'sessions', 'workspaces', 'locale', 'remote', 'remote.directoryPicker', 'layout', 'shortcuts',\n]\n\n/**\n * Register the browser and picker once their slot declarations are on the\n * ledger. Inject factories return plain callbacks; data reads use the\n * framework's global hooks.\n * @param ctx - client root context.\n */\nexport function apply(ctx: Context): void {\n const sessions = ctx.get('sessions') as ISessions\n const workspaces = ctx.get('workspaces') as IWorkspaces\n // One viewing-store instance, created here as ui-layout does for its layout\n // store: the browser declares the handle, and the UiWorkspace service writes\n // view order through the same instance the renderer hands the browser.\n const viewHandle = createWorkspaceViewStore()\n const viewInstance = viewHandle.create()\n const viewStore: typeof viewHandle = { ...viewHandle, create: () => viewInstance }\n const rowToast = createSnapshotStore<RowToastState | null>(null)\n let toastSeq = 0\n const notify = (toast: RowToast): void => { rowToast.set({ ...toast, seq: ++toastSeq }) }\n const uiWorkspace = new UiWorkspaceService(\n ctx, ctx.remote.directoryPicker, workspaces, sessions, viewInstance.actions, notify,\n )\n ctx.slots.provideRoot({ hooks: { workspaces: workspaces.list } })\n ctx.effect(() => ctx.locale.register(NS, { zh, en }), 'ui-workspace: dictionaries')\n const shortcutControls = createWorkspaceShortcutControls()\n\n // 折叠徽标的显示偏好(`showCompletedInBadge`)。\n //\n // 源先挂上(**恒在**,值先是默认):标准 props 的 hook 调用顺序必须稳定,晚挂或\n // 摘掉 `useBadgeSettings` 都会改变顺序而崩渲染。设置面随后经 `ctx.inject` 接入,\n // 只改源的值,不改源的存亡。\n const badgeSettings = createBadgeSettingsSource()\n ctx.slots.provideRoot({ hooks: { badgeSettings } })\n\n // 等宿主设置服务就绪——**非阻塞**:`ctx.inject` 是嵌套插件,服务永不到达也只是设置\n // 读不到(回落默认),本插件其余功能不受影响。这里不直接用 `ctx.get` 读:服务可能在\n // 本插件之后才注册,那时读到的 undefined 会永久生效(设置被静默忽略直到刷新)。\n //\n // 寻址键是**条目 id**(`cordis.patch.yml` 的 `id: dsh-group-status`),不是 settings\n // namespace——宿主 `describe()` 的 `ns` 即条目 id。\n ctx.inject(['configForms'], (configCtx) => {\n const forms = configCtx.get('configForms') as ConfigFormsLike | undefined\n if (forms === undefined || typeof forms.get !== 'function') return\n // 同一份官方设置表单既喂折叠徽标(只读快照),也喂插件页卡片(读写)。\n const scope = forms.get(ENTRY_ID)\n if (scope === undefined) return\n badgeSettings.publish(scope.getSnapshot())\n configCtx.effect(\n () => scope.subscribe(() => { badgeSettings.publish(scope.getSnapshot()) }),\n 'dsh-group-status: badge settings',\n )\n\n // 插件详情页(插件 → dsh-group-status)的配置表单。宿主把 `Config` 投影成\n // 上面这份表单,但页面要插件自己注册卡片才画得出来——没有这段,设置项在\n // GUI 里不存在(README 的「设置项」一节描述的就是这张卡片)。\n //\n // 键取**包名**(插件管理器按包名分发该槽位),寻址的表单仍是上面同一份 scope,\n // 于是卡片与折叠徽标永远读同一个值。\n //\n // `whileServed` 盯住条目命名空间:宿主不再服务该条目时连卡片一起注销,避免\n // 留下一张点开即空的表单。`bind` 是必需的:它是类原型方法,内部读写\n // `this.mirror`,取下来裸调用会丢接收者。\n const whileServed = forms.whileServed?.bind(forms)\n if (whileServed === undefined) return\n configCtx.effect(\n () => whileServed([ENTRY_ID], () => ctx.slots.inject(CONFIG_CARD_SLOT, () =>\n ctx.slots.register(\n {\n name: CONFIG_CARD_SLOT,\n key: CONFIG_CARD_KEY,\n locale: NS,\n inject: () => ({ scope }),\n },\n BadgeSettingsCard,\n ))),\n 'dsh-group-status: plugins-page card',\n )\n })\n\n const searchSessions: WorkspaceBrowserInjected['searchSessions'] = async (query, signal) => {\n const result = await sessions.search(query, signal)\n if (!result.ok) throw new Error(result.error.message)\n return result.value\n }\n\n // Stable per-surface occupancy sources (the renderer's hook cache keys by\n // source identity): true while the surface's directory-flow hole is filled.\n const flowSource = (hole: 'sidebar.workspaces.directoryFlow' | 'conversation.hero.workspace.directoryFlow'): HostObservable<boolean> => ({\n getSnapshot: () => ctx.slots.entries(hole).length > 0,\n subscribe: listener => ctx.slots.subscribe(hole, listener),\n })\n const browserFlowSource = flowSource('sidebar.workspaces.directoryFlow')\n const hostInfo: HostObservable<RemoteHostFacts> = {\n getSnapshot: () => ctx.remote.$host,\n subscribe: listener => ctx.on('connection/reset', listener),\n }\n const pickerFlowSource = flowSource('conversation.hero.workspace.directoryFlow')\n const openSession: WorkspaceBrowserInjected['open'] = (sessionId) => {\n uiWorkspace.openSession(sessionId)\n }\n // Registry-global sets as Sets, rebuilt only when the Workspace snapshot changes.\n const pinnedSet = derive(workspaces.list, snapshot => new Set<SessionId>(snapshot.pinnedSessionIds))\n const archivedSet = derive(workspaces.list, snapshot => new Set<SessionId>(snapshot.archivedSessionIds))\n // Plugin-private facts the row actions and their overlay surfaces share:\n // the pending rename request and the notice on display. Each business\n // writes through its own injected callback and the surface reads through\n // its bound hook.\n const renameRequest = derive(shortcutControls.state, state => state.renameTarget)\n const archiveRequest = createSnapshotStore<SessionArchiveConfirmRequest | null>(null)\n const requestSessionRename = shortcutControls.rename\n const unarchiveSession = (sessionId: SessionId): void => {\n uiWorkspace.unarchiveSession(sessionId).catch((reason: unknown) => {\n console.warn('session unarchive rejected:', reason)\n })\n }\n const renameSession: SessionRenameDialogInjected['renameSession'] = async (sessionId, title) => {\n const result = await sessions.using(\n sessionId,\n { source: 'workspaceOperation' },\n reference => reference.binding.session.rename(title),\n )\n if (!result.ok) throw new Error(result.error.message)\n }\n const pinInjected = (): PinSessionInjected => ({\n hooks: { pinned: pinnedSet, archived: archivedSet },\n // Pin failures surface as a notice: nothing else on the surface moves, so\n // a silent failure would read as a dead action.\n pinSession: (sessionId) => {\n uiWorkspace.pinSession(sessionId).catch(() => { notify({ kind: 'pinFailed' }) })\n },\n unpinSession: (sessionId) => {\n uiWorkspace.unpinSession(sessionId).catch(() => { notify({ kind: 'unpinFailed' }) })\n },\n })\n const archiveInjected = (): ArchiveSessionInjected => ({\n hooks: { archived: archivedSet },\n // Archive preserves the log and the account position, so a quiet Session\n // needs no confirmation; the notice offers undo and the archived filter.\n // The Host's refusal for running work is the one case that asks first:\n // the confirmation names that work and offers to stop it.\n archiveSession: (sessionId) => {\n uiWorkspace.archiveSession(sessionId).then(() => {\n notify({ kind: 'archived', sessionId })\n }).catch((reason: unknown) => {\n const activity = activeSessionRefusal(reason)\n if (activity === undefined) {\n console.warn('session archive rejected:', reason)\n return\n }\n const displayTitle = sessions.list.getSnapshot().byId[sessionId]?.displayTitle ?? sessionId\n archiveRequest.set({ sessionId, displayTitle, activity })\n })\n },\n unarchiveSession,\n })\n installWorkspaceShortcuts(ctx, uiWorkspace, shortcutControls, archiveInjected().archiveSession)\n const archiveConfirmInjected = (): SessionArchiveConfirmInjected => ({\n hooks: { archiveRequest },\n settleSessionArchive: () => { archiveRequest.set(null) },\n stopAndArchiveSession: async (sessionId) => {\n await uiWorkspace.archiveSession(sessionId, { stopActivity: true })\n notify({ kind: 'stoppedAndArchived', sessionId })\n },\n })\n const forkInjected = (): ForkSessionInjected => ({\n forkSession: (sessionId) => {\n uiWorkspace.forkSession(sessionId, (childId) => {\n ctx.get('productAnalytics')?.track('branch_session_click', { session_id: childId, parent_session_id: sessionId, click_position: 'sidebar' })\n }).catch(() => {\n // Fork or child-title failure leaves the list as it was.\n })\n },\n })\n const renameInjected = (): RenameSessionInjected => ({ requestSessionRename })\n const renameDialogInjected = (): SessionRenameDialogInjected => ({\n hooks: { renameRequest },\n settleSessionRename: shortcutControls.closeRename,\n renameSession,\n })\n const rowToastInjected = (): RowToastInjected => ({\n hooks: { toast: rowToast },\n dismissToast: () => { rowToast.set(null) },\n undoArchive: unarchiveSession,\n showArchived: () => { viewInstance.actions.setArchivedFilter('show') },\n })\n const browserInjected = (): WorkspaceBrowserInjected => ({\n // Explicit group actions keep their target; unscoped New Session inherits\n // the current Session Workspace before the recent-Workspace fallback.\n startSession: (workspaceId) => { uiWorkspace.startSession(workspaceId) },\n open: openSession,\n searchSessions,\n searchResultLimit: sessions.searchResultLimit,\n requestSessionRename,\n notifyArchivedNotOpenable: () => { notify({ kind: 'archivedNotOpenable' }) },\n renameWorkspace: async (workspaceId, title) => { await workspaces.rename(workspaceId, title) },\n deleteWorkspace: async (workspaceId) => { await workspaces.delete(workspaceId) },\n insertWorkspaceBefore: async (workspaceId, beforeWorkspaceId) => {\n await workspaces.insertBefore(workspaceId, beforeWorkspaceId)\n },\n unarchiveSession: async (sessionId) => { await uiWorkspace.unarchiveSession(sessionId) },\n createWorkspace: input => workspaces.create(input),\n requestSearch: shortcutControls.search,\n requestAddWorkspace: shortcutControls.add,\n closeAddWorkspace: shortcutControls.closeAdd,\n setDirectoryBusy: shortcutControls.directoryBusy,\n dismissForkError: shortcutControls.dismissForkError,\n hooks: { directoryFlow: browserFlowSource, hostInfo, workspaceShortcuts: shortcutControls.state, shortcuts: ctx.shortcuts.catalog },\n })\n const pickerInjected = (): WorkspacePickerInjected => ({\n createWorkspace: input => workspaces.create(input),\n hooks: { directoryFlow: pickerFlowSource },\n })\n // Each registration declares its owned children in the same call; slot\n // injection follows both the owner and declaration HMR lifetimes.\n ctx.slots.inject('sidebar.workspaces', () => ctx.slots.register(\n {\n name: 'sidebar.workspaces',\n children: {\n 'sidebar.workspaces.directoryFlow': { kind: 'single', scope: 'root' },\n // Every row entry reads the menu's open state through a hook bound\n // from the row's render occurrence (the owner passes the state pair\n // as hookContext).\n 'sidebar.workspaces.session.menu.item': {\n kind: 'list', scope: 'root', inject: { hooks: { menuOpenState: menuOpenStateFactory, shortcuts: ctx.shortcuts.catalog } },\n },\n 'sidebar.workspaces.session.row.action': { kind: 'list', scope: 'root' },\n 'sidebar.session.row.leading': { kind: 'list', scope: 'root' },\n 'sidebar.session.row.hover': { kind: 'list', scope: 'root' },\n },\n store: viewStore,\n inject: browserInjected,\n locale: NS,\n },\n WorkspaceBrowser,\n ))\n // The shipped row actions take the same route as a plugin's: `slots.inject`\n // waits for the browser registration above to declare each list, and the\n // entries leave with it. Orders step by 100 so a plugin entry can land\n // between them.\n ctx.slots.inject('sidebar.workspaces.session.menu.item', function* () {\n yield ctx.slots.register({ name: 'sidebar.workspaces.session.menu.item', id: 'pin', order: 100, locale: NS, inject: pinInjected }, PinSessionMenuItem)\n yield ctx.slots.register({ name: 'sidebar.workspaces.session.menu.item', id: 'rename', order: 200, locale: NS, inject: renameInjected }, RenameSessionMenuItem)\n yield ctx.slots.register({ name: 'sidebar.workspaces.session.menu.item', id: 'fork', order: 300, locale: NS, inject: forkInjected }, ForkSessionMenuItem)\n yield ctx.slots.register({ name: 'sidebar.workspaces.session.menu.item', id: 'archive', order: 400, locale: NS, inject: archiveInjected }, ArchiveSessionMenuItem)\n })\n ctx.slots.inject('sidebar.workspaces.session.row.action', function* () {\n yield ctx.slots.register({ name: 'sidebar.workspaces.session.row.action', id: 'archive', order: 100, locale: NS, inject: archiveInjected }, ArchiveSessionRowButton)\n yield ctx.slots.register({ name: 'sidebar.workspaces.session.row.action', id: 'pin', order: 200, locale: NS, inject: pinInjected }, PinSessionRowButton)\n })\n // The surfaces the actions raise live in the frame-wide layer: they must\n // outlive the row menu the action sat in.\n ctx.slots.inject('shell.overlay', function* () {\n yield ctx.slots.register({\n name: 'shell.overlay', id: 'workspace.session-rename', locale: NS, inject: renameDialogInjected,\n }, SessionRenameDialog)\n yield ctx.slots.register({\n name: 'shell.overlay', id: 'workspace.session-archive', locale: NS, inject: archiveConfirmInjected,\n }, SessionArchiveConfirmDialog)\n // The toast shares the browser's viewing store: it reads the archived\n // filter to drop the archived notice's filter action once rows are visible.\n yield ctx.slots.register({\n name: 'shell.overlay', id: 'workspace.row-toast', locale: NS, store: viewStore, inject: rowToastInjected,\n }, RowActionToast)\n })\n ctx.slots.inject('conversation.hero.workspace', () => ctx.slots.register(\n {\n name: 'conversation.hero.workspace',\n children: { 'conversation.hero.workspace.directoryFlow': { kind: 'single', scope: 'root' } },\n inject: pickerInjected,\n locale: NS,\n },\n WorkspacePicker,\n ))\n}\n\n/**\n * The activity a Host `workspace/session-active` refusal reported, or nothing\n * for any other failure. The class identity check goes by name: client plugin\n * bundles do not share error-class identity.\n */\nfunction activeSessionRefusal(reason: unknown): readonly SessionActivity[] | undefined {\n if (!(reason instanceof Error) || reason.name !== 'WorkspaceArchiveError') return undefined\n const { rpcError } = reason as WorkspaceArchiveError\n return rpcError.code === 'workspace/session-active' ? rpcError.details.activity : undefined\n}\n"],"ignoreList":[5,6,11,12],"mappings":"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"}
|
|
1
|
+
{"version":3,"file":"client.js","names":["createSnapshotStore","useMemo","SettingsFormModel","useSyncExternalStore","useId","SettingsForm","css","Switch","assertNever","assertNever","defineStore","Service","createSnapshotStore","StateDot","css","useRef","useMemo","relativeTime","css","StateDot","useState","IconEditOutlineRegular","IconTrashOutlineRegular","IconFolderOpenRegular","IconFolderCloseRegular","IconTriangleRightFillRegular","Menu","IconEllipsisOutlineRegular","Tooltip","IconNewChatOutlineRegular","HoverCard","IconPinFillRegular","IconArchiveOutlineRegular","IconUnarchiveOutlineRegular","Component","createRef","css","useCallback","useState","IconPlusOutlineRegular","IconFolderCloseRegular","Menu","css","Modal","Button","useState","Menu","IconFolderCloseRegular","IconWorkspaceTreeOutlineRegular","IconFlatListOutlineRegular","IconChevronsUpDownOutlineRegular","IconClockOutlineRegular","IconArchiveOffOutlineRegular","IconQueueOutlineRegular","IconArchiveCheckOutlineRegular","css","Tooltip","IconSlidersTwoOutlineRegular","IconArchiveOutlineRegular","useMemo","useRef","IconSearchOutlineRegular","IconCloseFillRegular","IconProjectAddOutlineRegular","Modal","Button","Toast","MenuItemButton","IconUnarchiveOutlineRegular","IconArchiveOutlineRegular","Tooltip","css","useState","Modal","Button","browserCss","MenuItemButton","IconBranchOutlineRegular","MenuItemButton","IconPinFillRegular","IconPinOutlineRegular","Tooltip","css","MenuItemButton","IconEditOutlineRegular","useState","useRef","Modal","Button","css","Toast","IconWarningOutlineRegular","assertNever","createSnapshotStore"],"sources":["../src/client/contract/slots.ts","../src/client/shortcuts.ts","../src/client/badge-settings.ts","../src/client/facets.ts","../src/client/facet-store.ts","../src/client/badge-field.ts","../src/client/BadgeSettingsCard.tsx","../node_modules/.pnpm/@deepseek-ai+dsh-util-values@0.2.0-rc.2_@deepseek-ai+cordis@4.0.4/node_modules/@deepseek-ai/dsh-util-values/lib/index.js","../node_modules/.pnpm/@deepseek-ai+dsh-util-workspace-path@0.2.0-rc.2_@deepseek-ai+cordis@4.0.4/node_modules/@deepseek-ai/dsh-util-workspace-path/lib/index.js","../src/client/tree.ts","../src/client/stores.ts","../src/client/pin-order.ts","../src/client/navigation.ts","../node_modules/.pnpm/clsx@2.1.1/node_modules/clsx/dist/clsx.mjs","../node_modules/.pnpm/@deepseek-ai+dsh-api-workspace-controller@0.2.0-rc.2_7b1cc3b3e03980f49f8901a2ede23841/node_modules/@deepseek-ai/dsh-api-workspace-controller/lib/types/default-workspace.js","../src/client/group-status.ts","../src/client/facet-visibility.ts","../src/client/badge-labels.ts","../src/client/rows/GroupBadge.tsx","../src/client/rows/Rows.tsx","../src/client/rows/AnimatedRows.tsx","../src/client/WorkspacePicker.tsx","../src/client/rows/WorkspaceBrowser.tsx","../src/client/session-actions/ArchiveSession.tsx","../src/client/session-actions/derived.ts","../src/client/session-actions/ForkSession.tsx","../src/client/session-actions/PinSession.tsx","../src/client/session-actions/RenameSession.tsx","../src/client/session-actions/RowActionToast.tsx","../src/client/locales.ts","../src/client/index.ts"],"sourcesContent":["/**\n * ui-workspace contracts. Two registrations share this package:\n *\n * - WorkspaceBrowser fills the sidebar shell's `sidebar.workspaces` hole —\n * the whole browsing region (section header, search, grouped/flat session\n * list, workspace dialogs). It registers this package's viewing store and\n * consumes the shell's two-fact owner share (wide / expandSidebar).\n * - WorkspacePicker fills the conversation empty-state hole (menu + error\n * dialog shared with the browser).\n *\n * Both registrations declare a **directory-flow hole** (`single` kind): the\n * slot a composed picker package's client half fills with its\n * picking interaction — a renderless native-chooser driver or an in-app\n * browsing dialog. ui-workspace owns the trigger (the \"Add workspace…\"\n * entry, present only while the hole is occupied) and the adoption\n * semantics (`createWorkspace({ path })`, the retryable error dialog,\n * Choose again); the occupant owns everything between `open` and the picked path,\n * including creating a new directory to hand back. That occupant-owned\n * creation is why adding a workspace has a single route: an unoccupied hole\n * leaves the surface with no add affordance at all.\n * Two holes exist because the two menu surfaces are independent slot entries\n * and a hole has exactly one declaring entry — they carry the same owner\n * contract and the same occupant.\n *\n * WorkspaceBrowser also declares the two **Session row action lists**: every\n * row of a Session's \"...\" menu is an entry of\n * `sidebar.workspaces.session.menu.item`, and every hover button at the row's\n * end is an entry of `sidebar.workspaces.session.row.action`. The shipped\n * actions — pin, rename, fork, archive — are ordinary entries this package\n * registers from `apply`, each carrying its own behavior in its own inject\n * face and reading its own Host state through hooks that face injects, so a\n * client plugin's action lands beside them by `order` and needs nothing from\n * the browser beyond the row identity.\n *\n * The browser entry additionally declares two `list` seats per Session row\n * (`sidebar.session.row.leading` / `sidebar.session.row.hover`) for ambient\n * row decorations. Both take the row's Session identity and nothing else: a\n * session-scoped seat would force a Session binding, which would activate and\n * retain every listed Session.\n */\nimport type {\n HostObservable, InjectFace, PropsHooks, PropsLocale, PropsRenderSlots, PropsRuntime, PropsStore, SlotHookFactory,\n} from '@deepseek-ai/dsh-client-ui-slots'\n// Type-only: pull the owner SlotMap merges into programs that resolve the\n// runtime shares below.\nimport type {} from '@deepseek-ai/dsh-client-ui-sidebar/client'\nimport type {} from '@deepseek-ai/dsh-client-ui-conversation/client'\nimport type {} from '@deepseek-ai/dsh-client-ui-layout/client'\nimport type { SessionSearchResultItem } from '@deepseek-ai/dsh-api-session-controller/client'\nimport type { RemoteHostFacts } from '@deepseek-ai/dsh-api-remotes/client'\nimport type { SessionActivity, WorkspaceId, WorkspaceView } from '@deepseek-ai/dsh-api-workspace-controller/client'\nimport type { SessionId } from '@deepseek-ai/dsh-session/types'\nimport type { ShortcutCatalogEntry } from '@deepseek-ai/dsh-client-shortcuts/client'\nimport type { WorkspaceShortcutState } from '../shortcuts.ts'\nimport type { createWorkspaceViewStore } from '../stores.ts'\n\n/**\n * Owner share of the directory-flow holes: the complete conversation between\n * the trigger surface and the picking interaction. The occupant reads `open`\n * to run/render its interaction and reports exactly one outcome per open.\n */\nexport interface DirectoryFlowOwnerProps {\n /** True while a picking interaction is requested; flipping back to false withdraws the request. */\n open: boolean\n /** True while the owner adopts a picked path (`createWorkspace` in flight); occupants disable their commit affordances. */\n busy: boolean\n /** The operator picked a directory (absolute host path); the owner adopts it. */\n onPicked: (path: string) => void\n /** The operator dismissed the interaction; the owner just closes the flow. */\n onCancel: () => void\n /** The interaction itself failed (chooser missing, listing denied); the owner shows its error surface. */\n onError: (message: string) => void\n}\n\n/** Owner share of one Session row action occurrence: the row the action belongs to. */\nexport interface SessionRowOwnerProps {\n /** Session the row shows. */\n sessionId: SessionId\n /** Row display title: persisted title, or empty when the Session has none. */\n displayTitle: string\n}\n\n/** The row menu's open state as its owner holds it: the `useState` pair. */\nexport type MenuOpenState = readonly [open: boolean, setOpen: (open: boolean) => void]\n\n/**\n * Hook every row-menu entry receives. Rows only render while the menu is\n * open, so an entry reads it for the setter: `setOpen(false)` dismisses the\n * menu the entry sits in — the same state the owner's `onClose` sets.\n */\nexport type UseMenuOpenState = () => MenuOpenState\n\n/**\n * Bind the row's render occurrence into the entries' `useMenuOpenState` hook:\n * the owner supplies its open-state pair as the occurrence's `hookContext`,\n * and the hook hands that pair back.\n * @param _standard - framework standard props (unused).\n * @param state - the menu's open-state pair from the render occurrence.\n * @returns the hook the entry calls.\n */\nexport const menuOpenStateFactory: SlotHookFactory<'sidebar.workspaces.session.menu.item', UseMenuOpenState> =\n (_standard, state) => () => state\n\n/**\n * Owner share of the two Session-row schedule seats. Both receive only the\n * row's Session identity: the occupant reads that Session's own scheduled\n * tasks, and reading them activates nothing.\n */\nexport interface SessionRowScheduleOwnerProps {\n /** Session this row shows; the occupant addresses its own data by this id. */\n readonly sessionId: SessionId\n}\n\ndeclare module '@deepseek-ai/dsh-client-ui-slots' {\n interface SlotMap {\n /** Directory-flow hole under the conversation empty-state picker (declared by the WorkspacePicker entry). */\n 'conversation.hero.workspace.directoryFlow': { kind: 'single'; scope: 'root'; owner: DirectoryFlowOwnerProps }\n /** Directory-flow hole under the sidebar browsing region (declared by the WorkspaceBrowser entry). */\n 'sidebar.workspaces.directoryFlow': { kind: 'single'; scope: 'root'; owner: DirectoryFlowOwnerProps }\n /**\n * Leading decoration of one Session row, in the 16px cell before the title\n * that the row's own state dot otherwise occupies. A higher-priority state\n * (a pending interaction, a new message, live activity) replaces the seat\n * with that dot for the same row, so an occupant here never renders beside\n * a status dot and is mounted only by a row whose primary state is idle.\n * An archived row keeps that cell blank — neither its status dot nor this\n * seat renders there, and its live status appears on the hover card only.\n */\n 'sidebar.session.row.leading': { kind: 'list'; scope: 'root'; owner: SessionRowScheduleOwnerProps }\n /**\n * Section of the Session row's hover card between its relative time and\n * its trailing status line. Mounted only while that card is open.\n */\n 'sidebar.session.row.hover': { kind: 'list'; scope: 'root'; owner: SessionRowScheduleOwnerProps }\n /**\n * The rows of one Session's \"...\" menu, in ascending `order`. ui-workspace\n * registers the shipped rows here — `pin` (100), `rename` (200), `fork`\n * (300), `archive` (400) — so a plugin row is placed by its own `order`\n * among them. Use a package-namespaced `id`; reusing a shipped id at\n * another `priority` shadows that row. Each entry renders one\n * `role=\"menuitem\"` `<button>` (the shipped rows use ui-primitives'\n * `MenuItemButton`, which adds the host styling and `separatorBefore`),\n * decides its own visibility from its own state, and dismisses the menu\n * through the injected `useMenuOpenState` hook after acting; the list's\n * keyboard walk and focus return read the DOM, so any such button joins\n * them. Labels come from the contributing package's locale namespace.\n * @example\n * return {\n * inject: ['slots'],\n * apply(ctx) {\n * const copyLabel = 'Copy Session ID' // Localize in the contributing package.\n * ctx.slots.inject('sidebar.workspaces.session.menu.item', () => ctx.slots.register(\n * { name: 'sidebar.workspaces.session.menu.item', id: 'copy-session-id', order: 500 },\n * ({ sessionId, useMenuOpenState }) => {\n * const [, setMenuOpen] = useMenuOpenState()\n * return React.createElement(\n * 'button',\n * { type: 'button', role: 'menuitem', onClick: () => { setMenuOpen(false); void navigator.clipboard.writeText(sessionId) } },\n * copyLabel,\n * )\n * },\n * ))\n * },\n * }\n */\n 'sidebar.workspaces.session.menu.item': {\n kind: 'list'\n scope: 'root'\n owner: SessionRowOwnerProps\n hookContext: MenuOpenState\n inject: { hooks: {\n menuOpenState: SlotHookFactory<'sidebar.workspaces.session.menu.item', UseMenuOpenState>\n shortcuts: HostObservable<readonly ShortcutCatalogEntry[]>\n } }\n }\n /**\n * The hover buttons at the end of one Session row, in ascending `order`,\n * after the \"...\" menu trigger. ui-workspace registers `archive` (100) and\n * `pin` (200) here. An entry renders one icon button (or nothing, when its\n * action does not apply to the row) and owns the action it performs. Clicks\n * inside the strip stay in the strip, so the button needs no propagation\n * handling to keep the row from opening.\n */\n 'sidebar.workspaces.session.row.action': { kind: 'list'; scope: 'root'; owner: SessionRowOwnerProps }\n }\n}\n\n/** The two directory-flow holes; a flow package's client half registers its one component into both. */\nexport type DirectoryFlowSlotName =\n | 'conversation.hero.workspace.directoryFlow'\n | 'sidebar.workspaces.directoryFlow'\n\n/**\n * Directory-picking share both trigger surfaces consume. Occupancy rides the\n * inject face's reserved `hooks` compartment: the renderer binds the source\n * into the `useDirectoryFlow` selector hook, so an empty hole hides the\n * \"Add workspace…\" entry reactively and the surface withdraws an open\n * flow whose occupant unloaded mid-interaction (nobody is left to cancel).\n */\nexport type DirectoryPickingInjected = {\n hooks: {\n /** True while this surface's directory-flow hole is occupied. */\n directoryFlow: HostObservable<boolean>\n }\n}\n\n/** Component-side view of the picking share: the bound occupancy selector hook. */\nexport type DirectoryPickingHooks = PropsHooks<DirectoryPickingInjected['hooks']>\n\n/**\n * Browser-private injected share (arrives via the register inject factory).\n * Data reads use the global framework hooks; these are the Host actions the\n * browsing region drives.\n */\nexport type WorkspaceBrowserInjected = {\n hooks: DirectoryPickingInjected['hooks'] & {\n /**\n * Fixed Host facts, reached through a hook rather than injected as values:\n * the renderer memoizes an entry's inject result for the registration's\n * lifetime, so facts read there would freeze at whatever the first render\n * saw. Select the field the surface needs (`info => info.home`).\n */\n hostInfo: HostObservable<RemoteHostFacts>\n workspaceShortcuts: HostObservable<WorkspaceShortcutState>\n shortcuts: HostObservable<readonly ShortcutCatalogEntry[]>\n }\n /** Open the browser search and focus its input. */\n requestSearch: () => void\n /** Request the existing directory picker. */\n requestAddWorkspace: () => void\n /** Consume the directory-picker opening request. */\n closeAddWorkspace: () => void\n /** Publish directory interaction occupancy for command availability. */\n setDirectoryBusy: (busy: boolean) => void\n /** Dismiss the shortcut's fork-failure notification. */\n dismissForkError: () => void\n /**\n * Start a New Session in a Workspace: reuse-or-create its blank session and\n * open it; without an explicit workspace, inherit the current Session\n * Workspace, then the recent Workspace, or clear into the New Session view.\n */\n startSession: (workspaceId?: WorkspaceId) => void\n /** Open a real Session. */\n open: (sessionId: SessionId) => void\n /**\n * Search current visible conversation messages. The Host fixes the result\n * bound; `hasMore` means the query needs narrowing.\n */\n searchSessions: (\n query: string,\n signal: AbortSignal,\n ) => Promise<{ items: readonly SessionSearchResultItem[]; hasMore: boolean }>\n /** Maximum number of merged rows rendered for one search. */\n searchResultLimit: number\n /** Open the Session rename dialog (a row title double-click); the rename action entry raises the same request. */\n requestSessionRename: (sessionId: SessionId, currentTitle: string) => void\n /** Tell the user an archived row cannot be opened (a click on it). */\n notifyArchivedNotOpenable: () => void\n /** Rename a Host Workspace (rejects on name conflict; resolves on durability). */\n renameWorkspace: (workspaceId: WorkspaceId, title: string) => Promise<void>\n /** Delete only a Host Workspace registration; directory and Session logs remain. */\n deleteWorkspace: (workspaceId: WorkspaceId) => Promise<void>\n /**\n * Reorder a Workspace in the durable registry display order.\n * Omitted anchor appends to the end.\n */\n insertWorkspaceBefore: (workspaceId: WorkspaceId, beforeWorkspaceId?: WorkspaceId) => Promise<void>\n /** Remove a Session from the registry-global archived set (the search results' restore button). */\n unarchiveSession: (sessionId: SessionId) => Promise<void>\n /** Adopt a picked host directory as a real Workspace before targeting a Session. */\n createWorkspace: (input: { path: string }) => Promise<WorkspaceView>\n}\n\n/** The browser's declared viewing store handle, shared with the row actions that write view state. */\nexport type WorkspaceViewStoreHandle = ReturnType<typeof createWorkspaceViewStore>\n\n/** Props of one shipped row-menu entry: owner share + locale seat + the entry's own injected share. */\nexport type SessionMenuItemProps<Injected extends object = object> =\n PropsRuntime<'sidebar.workspaces.session.menu.item'>\n & PropsLocale<'workspace'>\n & InjectFace<Injected>\n\n/** Props of one shipped row hover button: owner share + locale seat + the entry's own injected share. */\nexport type SessionRowActionProps<Injected extends object = object> =\n PropsRuntime<'sidebar.workspaces.session.row.action'>\n & PropsLocale<'workspace'>\n & InjectFace<Injected>\n\n/** One transient Workspace notice rendered by the overlay toast entry. */\nexport type RowToast =\n | { kind: 'archived'; sessionId: SessionId }\n | { kind: 'stoppedAndArchived'; sessionId: SessionId }\n | { kind: 'pinFailed' }\n | { kind: 'unpinFailed' }\n | { kind: 'archivedNotOpenable' }\n | { kind: 'defaultWorkspaceFailed' }\n /**\n * An explicit New Session request that failed. `message` is untranslated:\n * a Host refusal as `code: message` — the stable code stays in the copy so\n * a report can be searched by it — and any other failure's own message.\n */\n | { kind: 'createFailed'; message: string }\n\n/** The notice on display; `seq` keys remounts so a repeated notice restarts its hold. */\nexport type RowToastState = RowToast & { seq: number }\n\n/**\n * Pin action share (menu row and hover button). The callbacks carry the whole\n * behavior: the Host call, fronting the Session in its saved orders after a\n * pin, and the failure notice. The hooks are the registry-global sets as\n * Sets, so a row reads its own membership with one lookup.\n */\nexport interface PinSessionInjected {\n hooks: {\n /** Pinned Session ids. */\n pinned: HostObservable<ReadonlySet<SessionId>>\n /** Archived Session ids (pin does not apply to an archived row). */\n archived: HostObservable<ReadonlySet<SessionId>>\n }\n /** Pin a Session; on success it leads its accounts' saved orders, on failure the notice says so. */\n pinSession: (sessionId: SessionId) => void\n /** Unpin a Session; saved positions stay as they are. */\n unpinSession: (sessionId: SessionId) => void\n}\n\n/**\n * Archive action share (menu row and hover button). The callbacks carry the\n * whole behavior: the Host call, the notice a success raises, the\n * stop-and-archive confirmation a Host refusal for running work raises, and\n * the diagnostics for any other rejection.\n */\nexport interface ArchiveSessionInjected {\n hooks: {\n /** Archived Session ids. */\n archived: HostObservable<ReadonlySet<SessionId>>\n }\n /**\n * Archive a Session into the registry-global set: the row keeps its\n * account position and shows per the archived filter; archiving the\n * current session clears the selection into the New Session view state.\n * A Session with running work is not archived by this call: the Host's\n * refusal opens the stop-and-archive confirmation instead.\n */\n archiveSession: (sessionId: SessionId) => void\n /** Remove a Session from the registry-global archived set. */\n unarchiveSession: (sessionId: SessionId) => void\n}\n\n/**\n * A stop-and-archive confirmation the archive action asked for: the Host\n * refused the plain archive because this work still runs.\n */\nexport interface SessionArchiveConfirmRequest {\n /** Session to stop and archive. */\n sessionId: SessionId\n /** The row's display title, named in the dialog. */\n displayTitle: string\n /** What the Host reported running, in family order. */\n activity: readonly SessionActivity[]\n}\n\n/**\n * Stop-and-archive dialog share: the pending confirmation, its settlement,\n * and the archive hop that asks the Host to stop the work first.\n */\nexport interface SessionArchiveConfirmInjected {\n hooks: {\n /** The confirmation asked for, until the dialog consumes or cancels it. */\n archiveRequest: HostObservable<SessionArchiveConfirmRequest | null>\n }\n /** Consume or cancel the pending confirmation. */\n settleSessionArchive: () => void\n /**\n * Archive a Session after the Host stops its running work; resolves once\n * the archive set is durable (the stops settle in the background) and\n * raises the stopped-and-archived notice.\n */\n stopAndArchiveSession: (sessionId: SessionId) => Promise<void>\n}\n\n/** Fork action share. */\nexport interface ForkSessionInjected {\n /** Fork a Session at its last completed turn; the child arrives through the Host list. */\n forkSession: (sessionId: SessionId) => void\n}\n\n/** Rename action share: the row only raises the request; the dialog entry answers it. */\nexport interface RenameSessionInjected {\n /** Ask for the rename dialog, seeded with the row's current title. */\n requestSessionRename: (sessionId: SessionId, currentTitle: string) => void\n}\n\n/** A Session rename the rename action asked for; the dialog entry opens on it. */\nexport interface SessionRenameTarget {\n /** Session to rename. */\n sessionId: SessionId\n /** Title the dialog seeds its draft from. */\n currentTitle: string\n}\n\n/** Rename dialog share: the pending request, its settlement, and the rename hop the dialog confirms with. */\nexport interface SessionRenameDialogInjected {\n hooks: {\n /** The rename asked for, until the dialog consumes or cancels it. */\n renameRequest: HostObservable<SessionRenameTarget | null>\n }\n /** Consume or cancel the pending request. */\n settleSessionRename: () => void\n /** Rename a Session (explicit user title; resolves on host acceptance). */\n renameSession: (sessionId: SessionId, title: string) => Promise<void>\n}\n\n/** Row toast share: the notice on display, its dismissal, and the two actions the archived notice offers. */\nexport interface RowToastInjected {\n hooks: {\n /** The notice on display, or none. */\n toast: HostObservable<RowToastState | null>\n }\n /** Take the notice down. */\n dismissToast: () => void\n /** Undo an archive from its notice. */\n undoArchive: (sessionId: SessionId) => void\n /** Switch the archived filter to \"show\" so the archived row is back in view. */\n showArchived: () => void\n}\n\n/** Props of the rename dialog entry in `shell.overlay`. */\nexport type SessionRenameDialogProps =\n PropsRuntime<'shell.overlay'>\n & PropsLocale<'workspace'>\n & Omit<SessionRenameDialogInjected, 'hooks'>\n & PropsHooks<SessionRenameDialogInjected['hooks']>\n\n/** Props of the stop-and-archive dialog entry in `shell.overlay`. */\nexport type SessionArchiveConfirmProps =\n PropsRuntime<'shell.overlay'>\n & PropsLocale<'workspace'>\n & Omit<SessionArchiveConfirmInjected, 'hooks'>\n & PropsHooks<SessionArchiveConfirmInjected['hooks']>\n\n/**\n * Props of the row toast entry in `shell.overlay`. The declared viewing store\n * carries the archived filter; the archived notice omits its filter action\n * when archived rows are already visible.\n */\nexport type RowToastProps =\n PropsRuntime<'shell.overlay'>\n & PropsLocale<'workspace'>\n & PropsStore<WorkspaceViewStoreHandle>\n & Omit<RowToastInjected, 'hooks'>\n & PropsHooks<RowToastInjected['hooks']>\n\n/** Full browser props: shell owner share + viewing store + injected actions + the locale seat. */\nexport type WorkspaceBrowserProps =\n PropsRuntime<'sidebar.workspaces'>\n & PropsRenderSlots<\n | 'sidebar.workspaces.directoryFlow'\n | 'sidebar.workspaces.session.menu.item'\n | 'sidebar.workspaces.session.row.action'\n | 'sidebar.session.row.leading'\n | 'sidebar.session.row.hover'\n >\n & PropsStore<WorkspaceViewStoreHandle>\n & Omit<WorkspaceBrowserInjected, 'hooks'>\n & PropsHooks<WorkspaceBrowserInjected['hooks']>\n & PropsLocale<'workspace'>\n\n/**\n * Picker-private injected share. Pick semantics remain in the owner's onPick\n * callback; this callback creates only the real Host Workspace. A type alias\n * supplies the implicit index signature required by the registry.\n */\nexport type WorkspacePickerInjected = DirectoryPickingInjected & {\n /** Adopt a picked host directory as a real Workspace before targeting a Session. */\n createWorkspace: (input: { path: string }) => Promise<WorkspaceView>\n}\n\n/**\n * Full picker props: the owner share plus the creation callback and the\n * locale seat. The two picker holes (blank-session hero / New-Session view)\n * share one owner currency, so one composed type serves both registrations.\n */\nexport type WorkspacePickerProps =\n PropsRuntime<'conversation.hero.workspace'>\n & PropsRenderSlots<'conversation.hero.workspace.directoryFlow'>\n & Omit<WorkspacePickerInjected, 'hooks'>\n & PropsHooks<WorkspacePickerInjected['hooks']>\n & PropsLocale<'workspace'>\n","/** Workspace command registration and browser-owned opening requests. */\nimport type { Context } from '@deepseek-ai/cordis'\nimport type { SessionForkError } from '@deepseek-ai/dsh-api-session-controller/client'\nimport { createSnapshotStore } from '@deepseek-ai/dsh-client-store'\nimport type { ShortcutCommand, ShortcutCommandId } from '@deepseek-ai/dsh-client-shortcuts/client'\nimport type { SnapshotStore } from '@deepseek-ai/dsh-client-store'\nimport type { SessionId } from '@deepseek-ai/dsh-session/types'\nimport type { UiWorkspace } from './navigation.ts'\n\n/** Transient requests consumed by the existing workspace browser. */\nexport interface WorkspaceShortcutState {\n readonly searchRequest: number\n readonly addRequested: boolean\n readonly directoryBusy: boolean\n readonly renameTarget: { readonly sessionId: SessionId; readonly currentTitle: string } | null\n readonly forkError: { readonly reason: 'unavailable' | 'failed'; readonly seq: number } | null\n}\n\ninterface WorkspaceShortcutControls {\n state: SnapshotStore<WorkspaceShortcutState>\n search: () => void\n add: () => void\n closeAdd: () => void\n directoryBusy: (busy: boolean) => void\n rename: (sessionId: SessionId, currentTitle: string) => void\n closeRename: () => void\n forkFailed: (reason: 'unavailable' | 'failed') => void\n dismissForkError: () => void\n}\n\n/**\n * Create the private browser request source shared by commands and controls.\n * @returns observable state and its complete mutation callbacks.\n */\nexport function createWorkspaceShortcutControls(): WorkspaceShortcutControls {\n const state = createSnapshotStore<WorkspaceShortcutState>({\n searchRequest: 0, addRequested: false, directoryBusy: false, renameTarget: null, forkError: null,\n })\n let forkErrorSeq = 0\n return {\n state,\n search: () => { state.set({ ...state.getSnapshot(), searchRequest: state.getSnapshot().searchRequest + 1 }) },\n add: () => { state.set(state.getSnapshot().directoryBusy ? state.getSnapshot() : { ...state.getSnapshot(), addRequested: true }) },\n closeAdd: () => { state.set({ ...state.getSnapshot(), addRequested: false }) },\n directoryBusy: (busy: boolean) => { state.set({ ...state.getSnapshot(), directoryBusy: busy }) },\n rename: (sessionId: SessionId, currentTitle: string) => {\n state.set({ ...state.getSnapshot(), renameTarget: { sessionId, currentTitle } })\n },\n closeRename: () => { state.set({ ...state.getSnapshot(), renameTarget: null }) },\n forkFailed: (reason) => {\n forkErrorSeq += 1\n state.set({ ...state.getSnapshot(), forkError: { reason, seq: forkErrorSeq } })\n },\n dismissForkError: () => { state.set({ ...state.getSnapshot(), forkError: null }) },\n }\n}\n\n/**\n * Register navigation commands against the existing workspace owner.\n * Rename requires a nonblank main Conversation with no modal obscuring it.\n * @param ctx - plugin context with the shortcut, locale, and model services.\n * @param navigation - session creation and forking from the pointer controls' navigation service.\n * @param controls - browser-owned opening requests.\n * @param archiveSession - shared archive action, including running-work confirmation and notices.\n */\nexport function installWorkspaceShortcuts(\n ctx: Context,\n navigation: Pick<UiWorkspace, 'startSession' | 'forkSession'>,\n controls: ReturnType<typeof createWorkspaceShortcutControls>,\n archiveSession: (sessionId: SessionId) => void,\n): void {\n const t = ctx.locale.bind('workspace')\n const current = () => Object.values(ctx.sessions.list.getSnapshot().byId)\n .find(row => (row.retainedBy.mainView ?? 0) > 0)\n const addReason = () => ctx.slots.entries('sidebar.workspaces.directoryFlow').length === 0\n ? t('shortcut.noPicker')\n : controls.state.getSnapshot().directoryBusy ? t('shortcut.directoryBusy') : null\n const register = (id: string, label: () => string, aliases: string[], code: string,\n modifiers: ('primary' | 'alt' | 'shift')[], webModifiers: ('primary' | 'alt' | 'shift')[], resolve: ShortcutCommand['resolve']): void => {\n ctx.effect(() => ctx.shortcuts.register({\n id: id as ShortcutCommandId, label, aliases, defaults: {\n 'desktop:macos': { code, modifiers }, 'desktop:windows': { code, modifiers }, 'desktop:linux': { code, modifiers },\n 'web:macos': { code, modifiers: webModifiers }, 'web:windows': { code, modifiers: webModifiers },\n },\n regions: ['page', 'editable'], modals: [], resolve,\n }), `ui-workspace: ${id}`)\n }\n register('session.new', () => t('session.new'), ['new session', 'new chat'], 'KeyN', ['primary'], ['primary', 'alt'],\n () => ({ status: 'handled', run: () => { navigation.startSession() } }))\n register('session.search', () => t('search.sessions.aria'), ['search sessions'], 'KeyK', ['primary'], ['primary', 'alt'],\n () => ({ status: 'handled', run: controls.search }))\n register('workspace.add', () => t('workspace.add'), ['add workspace', 'open folder'], 'KeyO', ['primary'], ['primary', 'alt'],\n () => {\n const reason = addReason()\n return reason === null ? { status: 'handled', run: controls.add } : { status: 'blocked', reason }\n })\n register('session.rename', () => t('rename.session.title'), ['rename session'], 'KeyG', ['primary', 'alt'], ['primary', 'alt'], (context) => {\n const target = current()\n return target === undefined || target.blank || context.modal !== null || ctx.layout.panelInfo.getSnapshot().activePanelId !== null\n ? { status: 'blocked', reason: t('shortcut.noSession') }\n : { status: 'handled', run: () => { controls.rename(target.id, target.title?.trim() ?? '') } }\n })\n register('session.fork', () => t('menu.fork'), ['fork session'], 'KeyF', ['primary', 'alt'], ['primary', 'shift'], () => {\n const target = current()\n if (target === undefined) return { status: 'blocked', reason: t('shortcut.noSession') }\n if (target.blank) return { status: 'blocked', reason: t('shortcut.noCompletedTurn') }\n return { status: 'handled', run: () => {\n void navigation.forkSession(target.id).catch((error: unknown) => {\n // Client plugin bundles do not share error-class identity.\n const unavailable = error instanceof Error && error.name === 'SessionForkError'\n && (error as SessionForkError).rpcError.code === 'session/fork-unavailable'\n controls.forkFailed(unavailable ? 'unavailable' : 'failed')\n if (!unavailable) console.warn('session fork rejected:', error)\n })\n } }\n })\n register('session.archive', () => t('menu.archiveSession'), ['archive session'], 'KeyA', ['primary', 'shift'], ['primary', 'alt'], () => {\n const target = current()\n return target === undefined ? { status: 'blocked', reason: t('shortcut.noSession') }\n : { status: 'handled', run: () => {\n archiveSession(target.id)\n } }\n })\n}\n","/**\n * 插件设置读取(折叠徽标显示偏好)。\n *\n * 数据流:apply 时先建一个**稳定**的标准 props 源并经 `provideRoot` 挂上(此时还不知道\n * 设置面在不在),再用 `ctx.inject(['configForms'], …)` 等宿主设置服务就绪——就绪后\n * 订阅本条目设置面,把快照推给源。设置页保存 → 宿主替换快照 → 源通知 → 徽标即时重渲染。\n *\n * 为什么不在 apply 里直接 `ctx.get('configForms')`:服务可能在**本插件之后**才注册,\n * 那时读到的 undefined 会永久生效(设置被静默忽略,直到刷新)。`ctx.inject` 是非阻塞的\n * 嵌套插件,服务永不到达也不会影响本插件其余功能。\n *\n * 为什么源必须一开始就存在:标准 props 的 hook 调用顺序必须稳定——挂上/摘掉\n * `useBadgeSettings` 会改变调用顺序而崩渲染。故源恒在,只有它的**值**随设置变化。\n *\n * 稳定性约定(React 外部存储,见 dsh-later 的同名 hook):`getSnapshot` 必须返回稳定\n * 引用——每次都构造新对象会让选择器的 `Object.is` 比较永不成立,触发\n * 「Maximum update depth exceeded」死循环(React #185),折叠行徽标会整块崩掉。\n *\n * 设置面缺席或未就绪时,回落到**默认全部显示**,与 `Config` 各字段的 schema 默认值同源:\n * 读不到配置不是「关掉」。\n */\n\n/** Loader 条目 id —— 设置页的寻址键,也是宿主 `describe()` 的 ns。 */\nexport const ENTRY_ID = 'dsh-group-status'\n\n/** 设置面快照的最小结构面(与宿主 `ConfigFormSnapshot` 兼容)。 */\nexport interface SettingsSnapshotLike {\n readonly status: string\n readonly value?: unknown\n}\n\n/** 设置面的最小结构面(与宿主 `ConfigForm` 兼容)。 */\nexport interface SettingsScopeLike {\n getSnapshot(): SettingsSnapshotLike\n subscribe(listener: () => void): () => void\n}\n\n/** 本插件在浏览器半关心的设置项。 */\nexport interface ResolvedBadgeSettings {\n /** 折叠徽标是否显示「已完成」绿点;缺失/非法一律回落 true。 */\n showCompletedInBadge: boolean\n /** 折叠徽标是否显示「进行中」转圈(含子智能体);缺失/非法一律回落 true。 */\n showRunningInBadge: boolean\n /** 折叠徽标是否显示「待审批」黄点(approval / plan-review / question);缺失/非法一律回落 true。 */\n showPendingInBadge: boolean\n /** 折叠徽标是否显示「定时任务」时钟图标(数据来自 dsh-later);缺失/非法一律回落 true。 */\n showScheduledInBadge: boolean\n /** 折叠徽标是否显示「等待评审」沙漏图标(数据来自 dsh-gitea-dispatch,自其 #56 起画沙漏;缺失/非法一律回落 true)。 */\n showWaitingReviewInBadge: boolean\n /** 悬停卡里是否显示聚合明细行;缺失/非法一律回落 true。 */\n showHoverDetails: boolean\n /** 徽标数字显示阈值:数量 >= 此值时才显示数字;缺失/非法一律回落 2(默认 count=1 时省略)。 */\n countThreshold: number\n}\n\n/**\n * `ResolvedBadgeSettings` 里的布尔开关键。\n *\n * facet 的 `settingKey` 就是它的字符串形态:状态所有者声明\"我受哪个开关管\",\n * 而开关的语义与取值仍由本插件判定。\n */\nexport type BooleanSettingKey = {\n [K in keyof ResolvedBadgeSettings]: ResolvedBadgeSettings[K] extends boolean ? K : never\n}[keyof ResolvedBadgeSettings]\n\n/**\n * 一个 facet 是否被设置关掉。\n *\n * - 没有 `settingKey` → 始终参与(缺省是\"显示\",与其余开关的默认值同源)。\n * - 声明了但不是布尔开关键 → 同样按显示处理:拼错的键不该让一个状态整块消失。\n */\nexport function facetVisibleBySettings(settings: ResolvedBadgeSettings, settingKey: string | undefined): boolean {\n if (settingKey === undefined) return true\n const value = settings[settingKey as keyof ResolvedBadgeSettings]\n return typeof value === 'boolean' ? value : true\n}\n\n/** 标准 props 源的结构面(与 `HostObservable<ResolvedBadgeSettings>` 兼容)。 */\nexport interface BadgeSettingsSource {\n getSnapshot(): ResolvedBadgeSettings\n subscribe(listener: () => void): () => void\n}\n\n/** 始终存在的源:由 {@link createBadgeSettingsSource} 创建。 */\nexport interface MutableBadgeSettingsSource extends BadgeSettingsSource {\n /**\n * 采纳一条新快照(设置面就绪或宿主变更时推入)。\n *\n * 引用或取值都没变则**不通知**:宿主会为无关变更替换快照,无谓通知会让折叠行整列\n * 重渲染。\n * @param snapshot - 设置面快照;undefined 表示设置面缺失/收回。\n */\n publish(snapshot: SettingsSnapshotLike | undefined): void\n}\n\n/** 默认值:与 `Config` 各字段的 schema 默认同源(全部显示,数字阈值 2 即 count=1 时省略)。 */\nexport const DEFAULT_BADGE_SETTINGS: ResolvedBadgeSettings = Object.freeze({\n showCompletedInBadge: true,\n showRunningInBadge: true,\n showPendingInBadge: true,\n showScheduledInBadge: true,\n showWaitingReviewInBadge: true,\n showHoverDetails: true,\n countThreshold: 2,\n})\n\n/** 两个设置对象是否逐字段相等(用于发布前比较,避免无谓通知)。 */\nfunction settingsEqual(a: ResolvedBadgeSettings, b: ResolvedBadgeSettings): boolean {\n return (\n a.showCompletedInBadge === b.showCompletedInBadge &&\n a.showRunningInBadge === b.showRunningInBadge &&\n a.showPendingInBadge === b.showPendingInBadge &&\n a.showScheduledInBadge === b.showScheduledInBadge &&\n a.showWaitingReviewInBadge === b.showWaitingReviewInBadge &&\n a.showHoverDetails === b.showHoverDetails &&\n a.countThreshold === b.countThreshold\n )\n}\n\n/** 从原始快照派生:只有**显式 false** 才隐藏,缺失/非法一律显示(countThreshold 默认 2)。 */\nfunction resolveFromSnapshot(snap: SettingsSnapshotLike | undefined): ResolvedBadgeSettings {\n if (snap === undefined || snap.status !== 'ready') return DEFAULT_BADGE_SETTINGS\n const value = snap.value as Record<string, unknown> | undefined\n if (value === undefined || value === null || typeof value !== 'object') return DEFAULT_BADGE_SETTINGS\n const getBool = (field: string, def: boolean): boolean => {\n const v = value[field]\n return typeof v === 'boolean' ? v : def\n }\n const getNumber = (field: string, def: number): number => {\n const v = value[field]\n return typeof v === 'number' && Number.isFinite(v) && v >= 0 ? Math.floor(v) : def\n }\n return {\n showCompletedInBadge: getBool('showCompletedInBadge', true),\n showRunningInBadge: getBool('showRunningInBadge', true),\n showPendingInBadge: getBool('showPendingInBadge', true),\n showScheduledInBadge: getBool('showScheduledInBadge', true),\n showWaitingReviewInBadge: getBool('showWaitingReviewInBadge', true),\n showHoverDetails: getBool('showHoverDetails', true),\n countThreshold: getNumber('countThreshold', 2),\n }\n}\n\n/**\n * 建一个恒在、取值稳定的徽标设置源。\n *\n * `getSnapshot` 是**纯读**(无副作用、无订阅),因此可以安全地在渲染期间被反复调用,\n * 也满足外部存储的引用稳定要求;订阅只由 {@link MutableBadgeSettingsSource.publish}\n * 在取值真正变化时触发。\n * @returns 源;调用方持有它并在设置面就绪后 `publish`。\n */\nexport function createBadgeSettingsSource(): MutableBadgeSettingsSource {\n const listeners = new Set<() => void>()\n let resolved: ResolvedBadgeSettings = DEFAULT_BADGE_SETTINGS\n let seen: SettingsSnapshotLike | undefined\n let seenSet = false\n return {\n getSnapshot: () => resolved,\n subscribe: (listener) => {\n listeners.add(listener)\n return () => { listeners.delete(listener) }\n },\n publish: (snapshot) => {\n // 同一快照引用重复推入(含 undefined ↔ undefined)直接丢弃。\n if (seenSet && snapshot === seen) return\n seen = snapshot\n seenSet = true\n const next = resolveFromSnapshot(snapshot)\n // 取值没变就不替换引用、不通知:宿主为无关字段替换快照时不该惊动折叠行。\n if (settingsEqual(next, resolved)) return\n resolved = next\n for (const listener of [...listeners]) listener()\n },\n }\n}\n\n/** 旧口径的纯解析函数,保留给测试与 `publish` 复用。 */\nexport function resolveBadgeSettings(snapshot: SettingsSnapshotLike | undefined): ResolvedBadgeSettings {\n return resolveFromSnapshot(snapshot)\n}","/**\n * 分组状态 **facet 协议**:本插件对外提供的唯一接入面。\n *\n * ## 为什么是这个方向\n *\n * 折叠分组的徽标要把「组内有没有别的插件的状态」折成一个数字。此前是**本插件逐家\n * 适配**:`require('dsh-later/client')`、`require('dsh-gitea-dispatch/client')`,再把\n * 各家的字段翻成自己的类型。那个方向的代价已经实测过一次:提供方把 `deadline` /\n * `waitMaxSec` / `prNumber` 发出来了,本插件的接收类型只声明了两个字段,于是信息\n * **静默丢失**(编译不报错、运行不报错、测试不报错,见 CHANGELOG 0.2.3「适配只做了一半」)。\n *\n * 现在方向反过来:**状态的所有者把自己的事实注册进来**,本插件只认协议形状。\n * 新增一个状态源,本插件一行都不改。\n *\n * ```ts\n * // provider 侧(在自己的 apply 里)\n * const groupStatus = require('dsh-group-status/client')\n * groupStatus?.registerGroupStatusFacet?.({\n * protocol: 1,\n * id: 'my-plugin.review',\n * subscribe: store.subscribe,\n * getSnapshot: store.getSnapshot,\n * fold: (snapshot, sessionIds, now) => ({ count, tone, pulse, data }),\n * merge: (a, b) => ({ ... }),\n * label: (fold, now) => '等待评审(剩 3分钟) · #15',\n * renderIcon: (fold) => h('svg', …),\n * })\n * ```\n *\n * ## 为什么用 `subscribe` / `getSnapshot` 而不是 React hook\n *\n * 上一版让每家导出一个 hook,本插件在同一个组件里 `useXxxHook?.()` 调。两条都不成立:\n *\n * 1. **hook 数量必须逐次渲染恒定**,而 facet 是运行时注册/注销的:注册面一变,同一个\n * 组件的 hook 调用序列就变了,React 直接抛 \"Rendered more hooks than during the\n * previous render\"。\n * 2. 本插件因此必须知道\"有几个 facet、各叫什么\"——正是想消掉的那个耦合。\n *\n * `subscribe` / `getSnapshot` 是同一份能力的非 React 形态(宿主\n * `useSyncExternalStore` 的外部存储面),一个通用订阅器就能覆盖任意多个 facet。\n *\n * ## 为什么 `fold` 返回 `data`,而不是返回可渲染文本\n *\n * 多层文件夹要把同一个 facet 在子树各层的折叠结果**再合并**一次。文本合并不了\n * (「剩 3分钟」和「剩 5分钟」拼起来不是答案),结构化 `data` 能合并——合并规则归\n * facet 自己({@link GroupStatusFacet.merge}),渲染时刻再由\n * {@link GroupStatusFacet.label} 现算文案。本插件全程不解释 `data`。\n *\n * ## 兼容性\n *\n * 协议带 `protocol` 版本号。本插件只接受\n * {@link GROUP_STATUS_FACET_PROTOCOL_VERSION} 的 facet,其它版本**拒绝注册**并在\n * console 点名(静默忽略会让\"我注册了为什么没显示\"变成不可诊断的问题)。\n *\n * @module dsh-group-status/client/facets\n */\nimport type { ReactNode } from 'react'\n\n/** 本协议文件的协议版本。provider 必须原样填这个常量。 */\nexport const GROUP_STATUS_FACET_PROTOCOL_VERSION = 1\n\n/** 徽标可用的三档语义色(本插件的色板;provider 选档,不选具体颜色)。 */\nexport type FacetTone = 'info' | 'warn' | 'error'\n\n/** tone 之间的优先级(越大越紧急),用于多层合并时取更高档。 */\nexport const FACET_TONE_RANK: Readonly<Record<FacetTone, number>> = Object.freeze({\n info: 0, warn: 1, error: 2,\n})\n\n/**\n * 一个 facet 在**一组会话**上折出来的事实。\n *\n * 字段是本插件与 provider 之间唯一的运行时契约:`count` 进徽标数字,`tone` 选色,\n * `pulse` 决定要不要脉冲,`data` 归 provider 自用(本插件从不读它)。\n */\nexport interface FacetFold<Data = unknown> {\n /**\n * 贡献给徽标数字的条数。`0` 表示这个来源此刻不参与徽标(本插件会跳过它,\n * 不画图标、不进文案)。\n */\n count: number\n /** 语义色档。 */\n tone: FacetTone\n /** 是否脉冲。紧迫感由状态所有者判定,不由徽标反推。 */\n pulse: boolean\n /** 合并与文案所需的原始事实,形状由 facet 自定。 */\n data?: Data\n}\n\n/** {@link GroupStatusFacet.label} / {@link GroupStatusFacet.renderIcon} 的渲染上下文。 */\nexport interface FacetRenderContext {\n /** 渲染时刻(epoch ms)。用于把 `data` 里的截止时刻换算成「还剩多久」。 */\n now: number\n /**\n * 侧栏行的翻译位(本插件的 `workspace` 命名空间)。\n *\n * ⚠️ 这是**便利项,不是义务**:provider 若有自己的 locale 命名空间,应当闭包自己\n * 的翻译函数、忽略这里。这个字段是为**代管方**(`origin: 'legacy'`)复用本插件的行\n * 文案而存在的;内置适配器已删除(迁移史见 `docs/facet-protocol.md`),字段保留给下一次代管。\n */\n t: (key: string, options?: Record<string, string | number>) => string\n}\n\n/** 一个注册进来的状态源。 */\nexport interface GroupStatusFacet<Input = unknown, Data = unknown> {\n /** 必须是 {@link GROUP_STATUS_FACET_PROTOCOL_VERSION}。 */\n readonly protocol: number\n /**\n * 全局唯一 id,建议 `'<包名>.<状态名>'`(如 `'dsh-gitea-dispatch.waiting-review'`)。\n * 它同时是 React key、重复注册的判据,以及本插件设置项的挂钩键({@link settingKey})。\n */\n readonly id: string\n /**\n * 外部存储订阅面(宿主 `useSyncExternalStore` 的第一参数)。\n *\n * 必须在快照可能变化时被调用,并且**允许多个订阅者**;返回退订函数。\n */\n subscribe(listener: () => void): () => void\n /** 当前快照;还没拿到数据时返回 `undefined`(本插件会把该 facet 当作无贡献)。 */\n getSnapshot(): Input | undefined\n /**\n * 把快照折成这一组会话上的事实。\n *\n * 纯函数要求:同样的 `(snapshot, sessionIds, now)` 必须给出等价的折果——\n * 它在每次渲染里被调用,不该有副作用。\n * @param snapshot - {@link getSnapshot} 的结果。\n * @param sessionIds - 组内会话 id(含前缀形态;口径归 provider 判定)。\n * @param now - 本次折叠的时刻(epoch ms)。\n */\n fold(snapshot: Input | undefined, sessionIds: readonly string[], now: number): FacetFold<Data>\n /**\n * 合并同一 facet 在子树各层的折果(多层文件夹)。\n *\n * 缺省实现按 `count` 相加、`tone` 取更紧急的一档、`pulse` 取或;facet 若需要\n * 合并自己的 `data`(例如 PR 号并集、最早截止时刻)就必须覆盖它。\n */\n merge?(a: FacetFold<Data>, b: FacetFold<Data>): FacetFold<Data>\n /**\n * 徽标 `aria-label` / `title` 与悬停明细里的那句话。\n *\n * 由 provider 自己本地化(用它自己的 locale 命名空间);本插件不参与措辞。\n * 返回空串视为「这个 facet 没有可显示文案」,只保留数字贡献。\n */\n label?(fold: FacetFold<Data>, context: FacetRenderContext): string\n /**\n * 图标。provider 交出**已含配色**的 React 元素(它最懂自己的状态该怎么画,\n * 包括\"超时该静止还是该闪\"这类视觉语义)。\n *\n * 不提供时,本插件退回一个按 `tone` 取色的通用点。\n */\n renderIcon?(fold: FacetFold<Data>, context: FacetRenderContext): ReactNode\n /**\n * 受本插件哪个设置项开关控制(如 `'showWaitingReviewInBadge'`)。\n *\n * 省略 = 不受开关控制,始终参与。开关的**语义**(关掉意味着什么)由本插件判定,\n * provider 只声明挂钩键。\n */\n settingKey?: string\n /**\n * 渲染顺序(升序)。**缺省排在所有声明过 `order` 的来源之后**,彼此按注册先后,\n * 这样新接入的陌生来源不会插到既有状态前面抢视觉位置。\n */\n order?: number\n /**\n * 来源标记。**provider 不用填**(缺省即 `provider`)。\n *\n * 代管某个来源的一方显式写 `'legacy'`,用它声明「我是在替状态所有者代管」,从而在\n * 对方接入同名 facet 时自动让位。本插件目前不代管任何来源,这条规则为**下一次**迁移\n * 保留。见 {@link FACET_ORIGIN_RANK}。\n */\n origin?: FacetOrigin\n}\n\n/** 协议来源:`provider` = 状态所有者自己注册;`legacy` = 替状态所有者代管的注册方(本插件目前不代管任何来源)。 */\nexport type FacetOrigin = 'provider' | 'legacy'\n\n/**\n * 同 id 冲突时**由来源决胜,与注册顺序无关**。\n *\n * 宿主不保证插件 apply 的先后。过渡期内\"本插件代 provider 写的适配器\"与\"provider\n * 自己注册的 facet\"会撞同一个 id:若靠顺序决胜,同一份部署今天显示、明天不显示。\n * `provider` 恒胜 `legacy`:所有者一接入,代管方立刻让位,且不重复计数。迁移因此\n * 不需要协商发布顺序。\n */\nexport const FACET_ORIGIN_RANK: Readonly<Record<FacetOrigin, number>> = Object.freeze({\n legacy: 0, provider: 1,\n})\n\n/** 一个 facet 的来源;缺省按 `provider`(最保守的假设:别人主动注册就是所有者)。 */\nexport function facetOrigin(facet: { readonly origin?: FacetOrigin }): FacetOrigin {\n return facet.origin === 'legacy' ? 'legacy' : 'provider'\n}\n\n/** 任意来源的 facet / 折果:聚合与渲染侧使用的**非泛型**形态。\n *\n * 协议对 provider 是泛型的(它能拿到自己的 `data` 类型),但登记面、折果表、渲染层\n * 都不关心 `data` 是什么,所以内部一律用这两个别名。方法用**方法语法**声明,于是\n * 具体 facet 的 `fold` / `merge` 在这些位置上是可赋值的(双变),不需要 `as never`。\n */\nexport type AnyFacet = GroupStatusFacet<unknown, unknown>\nexport type AnyFacetFold = FacetFold<unknown>\n\n/** 一个已登记 facet 及其排序位。 */\nexport interface RegisteredFacet {\n facet: AnyFacet\n /** 注册序号,作为 `order` 相同时的稳定 tie-break。 */\n sequence: number\n}\n\n/** {@link registerGroupStatusFacet} 的失败原因。 */\nexport type FacetRejection =\n | 'not-an-object'\n | 'protocol-mismatch'\n | 'missing-id'\n | 'missing-methods'\n /** 同 id 上已有更高来源的登记(过渡期适配器被状态所有者顶掉) */\n | 'superseded'\n\n/** 注册结果:成功带 `id`,失败带原因(且**不**静默丢弃)。 */\nexport type FacetRegistration = { ok: true; id: string } | { ok: false; id: string; reason: FacetRejection }\n\n/** 退订/注销函数。 */\nexport type Unregister = () => void\n\n// #25③:此处原有 `const TONE_ORDER = ['info','warn','error']`,与对外导出的\n// `FACET_TONE_RANK` 是同一个事实的两份实现,且只有 `defaultMergeFold` 一个使用者。\n// 现已统一到 `FACET_TONE_RANK`(见该函数),私有那份删除。\n\n/**\n * 检查一个 facet 是否符合协议 v1。\n * @returns 拒绝原因;`undefined` 表示可用。\n */\nexport function facetRejection(facet: unknown): FacetRejection | undefined {\n if (typeof facet !== 'object' || facet === null) return 'not-an-object'\n const candidate = facet as Partial<GroupStatusFacet>\n if (candidate.protocol !== GROUP_STATUS_FACET_PROTOCOL_VERSION) return 'protocol-mismatch'\n if (typeof candidate.id !== 'string' || candidate.id === '') return 'missing-id'\n if (\n typeof candidate.subscribe !== 'function'\n || typeof candidate.getSnapshot !== 'function'\n || typeof candidate.fold !== 'function'\n ) return 'missing-methods'\n return undefined\n}\n\n/**\n * 缺省折果合并:数量相加、色档取更紧急的一档、脉冲取或。\n *\n * ⚠️ 它**不**合并 `data`(本插件不知道 `data` 是什么)。需要合并原始事实的 facet\n * 必须自己实现 {@link GroupStatusFacet.merge}。\n */\nexport function defaultMergeFold(a: AnyFacetFold, b: AnyFacetFold): AnyFacetFold {\n // #25③:读对外导出的 `FACET_TONE_RANK`,不再另持一份私有 `TONE_ORDER`。两份表的顺序\n // 逐项相同(`{info:0,warn:1,error:2}` 与 `['info','warn','error']` 的下标一致),所以对\n // 合法色档这是**零行为变更**;收口的是「同一个事实两份实现」本身。\n //\n // ⚠️ `?? -1` **不是防御性冗余,是负载性的,别顺手删**。`facetRejection` 只校验\n // protocol / id / 三个方法,**不校验 `fold()` 返回的 `tone`** —— 那是跨插件边界,坏\n // provider 交回一个非法档位是真能到达这里的。旧的 `TONE_ORDER.indexOf(非法值)` 得到\n // `-1`,于是另一侧的合法档位必胜(`2 > -1`);而 `FACET_TONE_RANK[非法值]` 得到\n // `undefined`,任何比较都是 `false`,非法档位就会被**传播出去**。少了这个 `?? -1`,\n // 本次重构会在坏输入下静默改变结果。\n const toneA = FACET_TONE_RANK[a.tone] ?? -1\n const toneB = FACET_TONE_RANK[b.tone] ?? -1\n return {\n count: a.count + b.count,\n tone: toneB > toneA ? b.tone : a.tone,\n pulse: a.pulse || b.pulse,\n }\n}\n\n/**\n * 登记表面:一个可订阅的 facet 列表。\n *\n * 用闭包工厂里的**模块级单例**,于是 provider 与本插件拿到的是同一张表:模块表行\n * 只在首次 `require` 时 materialize,之后所有调用方共享同一实例。\n */\nexport interface FacetRegistry {\n /**\n * 登记一个 facet。\n *\n * 同 id 已存在时按**来源**决胜({@link FACET_ORIGIN_RANK}):更高来源保持原位,\n * 同来源或更高者覆盖。返回失败而不静默丢弃,调用方能在 console 里查到原因。\n */\n register(facet: AnyFacet): FacetRegistration\n /**\n * 摘掉一个登记项。\n *\n * 给了 `facet` 时只摘\"**当前登记的还是它**\"的那一份:同 id 已被后来的实现替换后,\n * 旧 provider 的 dispose 不该把新登记摘掉。\n * @returns 是否真的摘掉了。\n */\n remove(id: string, facet?: AnyFacet): boolean\n /** 当前登记项,按 `order` 再按注册先后排序。 */\n list(): readonly RegisteredFacet[]\n /** 订阅登记面变化(注册/注销时触发)。 */\n subscribe(listener: () => void): () => void\n}\n\n/** 创建一张登记表面(测试用;生产走模块级单例 {@link registry})。 */\nexport function createFacetRegistry(): FacetRegistry {\n const entries = new Map<string, RegisteredFacet>()\n const listeners = new Set<() => void>()\n let sequence = 0\n let sorted: readonly RegisteredFacet[] = []\n\n const resort = (): void => {\n sorted = [...entries.values()].sort((x, y) => {\n // 排序键 = (有没有声明 order, order, 注册序号)。\n // 没声明 order 的来源一律排在**所有声明过的之后**,彼此按注册先后:陌生新来者\n // 不该插到既有状态前面抢视觉位置,而两两之间又没有可比的新排序键。\n const declaredX = x.facet.order !== undefined\n const declaredY = y.facet.order !== undefined\n if (declaredX !== declaredY) return declaredX ? -1 : 1\n if (declaredX && declaredY) return (x.facet.order as number) - (y.facet.order as number)\n return x.sequence - y.sequence\n })\n }\n\n let notifying = false\n let pending = false\n\n /**\n * 通知订阅者,并把**重入合并成一轮补跑**。\n *\n * 订阅者在自己的回调里登记/注销 facet 是完全合法的(消费方常在收到变更后立即\n * 补登记一个派生来源)。直接递归会有两个问题:嵌套深度由订阅者数量决定(两个互相\n * 触发的订阅者就是无界递归),而且中间那轮通知看到的登记面是**改到一半**的。\n * 所以内层调用只置脏标志,外层跑完一轮后再补一轮,直到没有新的改动 —— 每个订阅者\n * 都看得到最终状态,递归深度恒为 1。\n */\n const notify = (): void => {\n if (notifying) {\n pending = true\n return\n }\n notifying = true\n try {\n do {\n pending = false\n // 复制一份再遍历:订阅者可能在回调里退订自己。\n for (const listener of [...listeners]) {\n try {\n listener()\n } catch {\n /* 单个订阅者异常不影响其余订阅者 */\n }\n }\n } while (pending)\n } finally {\n notifying = false\n pending = false\n }\n }\n\n return {\n register: (facet) => {\n const reason = facetRejection(facet)\n const id = typeof facet?.id === 'string' ? facet.id : ''\n if (reason !== undefined) return { ok: false, id, reason }\n const existing = entries.get(id)\n const nextRank = FACET_ORIGIN_RANK[facetOrigin(facet)]\n if (existing !== undefined && FACET_ORIGIN_RANK[facetOrigin(existing.facet)] > nextRank) {\n // 同 id 上站着更高来源的登记(状态所有者已经自己接入),低的一边让位。\n return { ok: false, id, reason: 'superseded' }\n }\n sequence += 1\n // 同来源重复登记直接覆盖:provider 热替换实现不必先注销再登记。\n entries.set(id, { facet, sequence })\n resort()\n notify()\n return { ok: true, id }\n },\n remove: (id, facet) => {\n const current = entries.get(id)\n if (current === undefined) return false\n if (facet !== undefined && current.facet !== facet) return false\n entries.delete(id)\n resort()\n notify()\n return true\n },\n list: () => sorted,\n subscribe: (listener) => {\n listeners.add(listener)\n return () => {\n listeners.delete(listener)\n }\n },\n }\n}\n\n/**\n * 生产用的模块级单例登记表面。\n *\n * 与 {@link createFacetRegistry} 分开,是为了让测试能对着一张干净的表断言协议行为,\n * 而不会被别的用例或别的插件登记的 facet 污染。\n */\nexport const registry: FacetRegistry = createFacetRegistry()\n\n/**\n * 本插件 client 入口对外的登记函数(provider 侧唯一需要认识的符号)。\n *\n * @param facet - 待登记的 facet。\n * @returns 注销函数;**注册失败时返回一个空操作**,同时把原因写进 console——\n * 返回值形状保持稳定,provider 的 dispose 路径不必区分成败。\n */\nexport function registerGroupStatusFacet(facet: AnyFacet): Unregister {\n const result = registry.register(facet)\n if (!result.ok) {\n // 过渡期适配器被状态所有者顶掉是**预期结果**,不是错误:报一条 warn 会让人以为\n // 徽标坏了。除此之外的每一次失败都必须可见,否则\"注册了却没显示\"无从诊断。\n if (!(result.reason === 'superseded' && facetOrigin(facet) === 'legacy')) reportRejection(result)\n return () => undefined\n }\n // 只摘\"还是自己\"的那一份:同 id 已被后来的实现替换时,旧 dispose 不该动新登记。\n return () => {\n registry.remove(result.id, facet)\n }\n}\n\n/**\n * 把注册失败写成一条可诊断的日志。\n *\n * 刻意不抛错:状态显示是增强功能,一个插件协议填错不该把宿主界面渲染打断;\n * 但也不静默——\"注册了却没显示\"必须能查出原因。\n */\nfunction reportRejection(rejection: { id: string; reason: FacetRejection }): void {\n const detail = rejection.reason === 'protocol-mismatch'\n ? `本插件只接受 protocol: ${GROUP_STATUS_FACET_PROTOCOL_VERSION}`\n : rejection.reason === 'missing-methods'\n ? 'subscribe / getSnapshot / fold 三个方法必须齐备'\n : rejection.reason === 'missing-id'\n ? \"id 必须是非空字符串,建议 '<包名>.<状态名>'\"\n : rejection.reason === 'superseded'\n ? '同 id 上已有更高来源的登记;两个不同插件用了同一个 id,请各自换名'\n : 'facet 必须是一个对象'\n console.warn(`dsh-group-status: 拒绝登记状态 facet \"${rejection.id}\"(${rejection.reason}):${detail}`)\n}\n","/**\n * facet 的**消费侧**:把「登记表面 + 每个 facet 自己的外部存储」压成一份 React 可订阅的\n * 单一存储。\n *\n * ## 为什么必须是一个存储,而不是逐个 hook\n *\n * 见 `./facets.ts` 的文件头:hook 数量在同一个组件里必须逐次渲染恒定,而 facet 是运行\n * 时注册/注销的。所以这里只暴露一个**版本号**(数字,引用天然稳定)给\n * `useSyncExternalStore`,实际的快照读取与折叠都发生在渲染期。\n *\n * ## 快照读取为什么放在渲染期\n *\n * `getSnapshot` 必须返回稳定引用,而「每个 facet 的快照」是一个对象图:为它造一个\n * 缓存就需要判定失效,而判定失效又要读快照本身。改成「版本号变 → 重新渲染 → 现读现折」\n * 之后,缓存问题消失,代价是一次 O(facet × 组内会话) 的纯计算,量级与原有实现相同。\n *\n * @module dsh-group-status/client/facet-store\n */\nimport { registry, type AnyFacet, type FacetRegistry, type RegisteredFacet } from './facets.ts'\n\n/** facet 自己存储的订阅句柄与它当时的快照来源。 */\ninterface FacetLink {\n facet: AnyFacet\n unsubscribe: () => void\n}\n\n/** {@link createFacetStore} 的产物。 */\nexport interface FacetStore {\n /** 订阅「快照可能变了」或「登记面变了」。 */\n subscribe(listener: () => void): () => void\n /** 单调递增的版本号;引用天然稳定,可直接作为 `useSyncExternalStore` 的快照。 */\n getVersion(): number\n /** 服务端渲染快照:与 {@link getVersion} 同型,避免 hydration 不一致。 */\n getServerVersion(): number\n /** 当前登记项(已排序)。 */\n list(): readonly RegisteredFacet[]\n /** 释放所有对 facet 存储的订阅(宿主卸载本插件时调用)。 */\n dispose(): void\n}\n\n/**\n * 创建 facet 存储。\n *\n * 对登记面做一次订阅,并在登记变化时**重新接线**各 facet 的 `subscribe`:provider 热替换\n * 实现(同 id 再注册)或运行中启用/停用插件,都只会走到这里一次,不会留下野订阅。\n *\n * @param source - 登记表面;缺省用模块级单例,测试传入自建实例以隔离。\n */\nexport function createFacetStore(source: FacetRegistry = registry): FacetStore {\n const listeners = new Set<() => void>()\n const links = new Map<string, FacetLink>()\n let version = 0\n let disposed = false\n\n /** 任一来源变化都要让消费方重新渲染,因此统一 bump。 */\n const bump = (): void => {\n if (disposed) return\n version += 1\n for (const listener of [...listeners]) {\n try {\n listener()\n } catch {\n /* 单个订阅者异常不影响其余订阅者 */\n }\n }\n }\n\n /** 把 links 对齐到当前登记项:新增接线、移除退订、替换重接。 */\n const rewire = (): void => {\n if (disposed) return\n const current = new Map(source.list().map((entry) => [entry.facet.id, entry.facet]))\n for (const [id, link] of [...links]) {\n if (current.get(id) === link.facet) continue\n try {\n link.unsubscribe()\n } catch {\n /* 退订失败不影响其它 facet 的接线 */\n }\n links.delete(id)\n }\n for (const [id, facet] of current) {\n if (links.has(id)) continue\n links.set(id, { facet, unsubscribe: facet.subscribe(bump) })\n }\n }\n\n const unsubscribeRegistry = source.subscribe(() => {\n rewire()\n bump()\n })\n rewire()\n\n return {\n subscribe: (listener) => {\n listeners.add(listener)\n return () => {\n listeners.delete(listener)\n }\n },\n getVersion: () => version,\n getServerVersion: () => 0,\n list: () => source.list(),\n dispose: () => {\n if (disposed) return\n disposed = true\n for (const link of links.values()) {\n try {\n link.unsubscribe()\n } catch {\n /* 释放阶段忽略单个退订异常 */\n }\n }\n links.clear()\n unsubscribeRegistry()\n listeners.clear()\n },\n }\n}\n\n/**\n * 生产用的单例存储:消费侧(`WorkspaceBrowser`)订阅它,\n * `apply` 的 effect 结束时用 {@link disposeFacetStore} 释放全部接线。\n *\n * 单例而非每次渲染新建,是因为它持有**对每个 facet 存储的订阅**;随渲染重建会把\n * provider 的 store 拖进无谓的退订/重订,也让\"快照在两个文件夹行之间读数不同\"成为可能。\n */\nlet singleton: FacetStore | undefined\n\n/** 取(并首次创建)单例存储。 */\nexport function facetStore(): FacetStore {\n if (singleton === undefined) singleton = createFacetStore()\n return singleton\n}\n\n/** 释放单例存储(插件卸载时调用;下次 {@link facetStore} 会重建)。 */\nexport function disposeFacetStore(): void {\n if (singleton === undefined) return\n singleton.dispose()\n singleton = undefined\n}\n","/**\n * 折叠徽标设置项的字段定义(纯逻辑,不碰 React / 宿主组件)。\n *\n * 官方设置卡片的模型(`SettingsFormModel`)把每个字段都当**草稿文本**处理:控件读\n * `format(存储值)` 得到文本,用户编辑后 `parse(文本)` 决定这次保存写什么。布尔字段\n * 没有现成的官方 spec(官方只提供 `settingsTextField` / `settingsNumberField`),所以\n * 这里按同一契约写一份:文本就是 schema 的布尔字面量。\n *\n * 单独成文件是为了可测:`parse` 必须对非法草稿返回 `undefined`(模型据此把该字段标为\n * invalid 并挡住保存,而不是把畸形值写下去),`format` 必须把缺失值读成默认 `true`\n * ——与 `Config` 各字段的 schema 默认、`badge-settings.ts` 的解析同源。\n *\n * 类型从 primitives **type-only** 引入:编译期接住官方契约,运行时不留依赖,\n * 测试里也就不必把那个包(及其整棵依赖闭包)拉进来。\n */\nimport type { SettingsFieldSpec } from '@deepseek-ai/dsh-client-ui-primitives'\n\n/** 卡片字段名(与 `src/index.ts` 的 `Config` 同名同义)。 */\nexport const BADGE_FIELDS = {\n showCompletedInBadge: 'showCompletedInBadge',\n showRunningInBadge: 'showRunningInBadge',\n showPendingInBadge: 'showPendingInBadge',\n showScheduledInBadge: 'showScheduledInBadge',\n showWaitingReviewInBadge: 'showWaitingReviewInBadge',\n showHoverDetails: 'showHoverDetails',\n countThreshold: 'countThreshold',\n} as const\n\n/** 存储值解析成开关状态:只有显式 false 才是「关闭」。 */\nexport function isFieldEnabled(value: unknown): boolean {\n return value !== false\n}\n\n/**\n * 草稿文本解析成开关状态:与 {@link isFieldEnabled} 不同,这里比较的是模型给的\n * **文本**,别把字符串喂给上面那个函数(`'false' !== false` 恒真)。\n */\nexport function isDraftEnabled(text: string): boolean {\n return text !== 'false'\n}\n\n/**\n * 构造一个布尔字段的字段转换规格。\n *\n * `parse` 只接受 `'true'` / `'false'`:空串、任意其它文本都返回 `undefined`,\n * 让模型把字段判为 invalid 并拒绝保存(官方模型的既定行为)。\n *\n * @param field - 字段名(与 Config 同名)。\n * @param defaultValue - 缺失值时的默认(true = 默认显示,false = 默认隐藏)。\n */\nfunction makeBooleanField(field: string, defaultValue: boolean): SettingsFieldSpec {\n return {\n field,\n format: value => {\n const enabled = value === undefined || value === null || typeof value !== 'boolean'\n ? defaultValue\n : value\n return enabled ? 'true' : 'false'\n },\n parse: text =>\n text === 'true' ? { kind: 'set', value: true }\n : text === 'false' ? { kind: 'set', value: false }\n : undefined,\n }\n}\n\n/** 各字段的字段转换规格。 */\nexport const showCompletedField: SettingsFieldSpec = makeBooleanField(BADGE_FIELDS.showCompletedInBadge, true)\nexport const showRunningField: SettingsFieldSpec = makeBooleanField(BADGE_FIELDS.showRunningInBadge, true)\nexport const showPendingField: SettingsFieldSpec = makeBooleanField(BADGE_FIELDS.showPendingInBadge, true)\nexport const showScheduledField: SettingsFieldSpec = makeBooleanField(BADGE_FIELDS.showScheduledInBadge, true)\nexport const showWaitingReviewField: SettingsFieldSpec = makeBooleanField(BADGE_FIELDS.showWaitingReviewInBadge, true)\nexport const showHoverDetailsField: SettingsFieldSpec = makeBooleanField(BADGE_FIELDS.showHoverDetails, true)\nexport const countThresholdField: SettingsFieldSpec = {\n field: BADGE_FIELDS.countThreshold,\n format: value => {\n const n = value === undefined || value === null || typeof value !== 'number' || !Number.isFinite(value)\n ? 2\n : Math.floor(value)\n return String(n < 0 ? 0 : n)\n },\n parse: text => {\n const n = Number(text)\n if (!Number.isFinite(n) || n < 0 || n !== Math.floor(n)) return undefined\n return { kind: 'set', value: n }\n },\n}\n\n/** 所有字段规格(按卡片渲染顺序)。 */\nexport const ALL_BADGE_FIELDS: SettingsFieldSpec[] = [\n showCompletedField,\n showRunningField,\n showPendingField,\n showScheduledField,\n showWaitingReviewField,\n showHoverDetailsField,\n countThresholdField,\n]\n","/**\n * 折叠徽标的设置卡片:插件 → dsh-group-status(bundle 详情页的配置表单)。\n *\n * 为什么需要这张卡片:0.2.0 起宿主把插件 `Config`(`src/index.ts`,根节点\n * `.volatile()`)投影到客户端 `configForms` 服务上,但**不会**自动把表单画进\n * 「插件」页——插件页只在客户端往 `plugins.bundle.config` 注册了卡片时才渲染\n * (见 dsh-later / dsh-gitea-dispatch 的同款做法)。没有它,README「设置项」一节\n * 描述的配置表单在 GUI 里根本不存在。\n *\n * 视觉与交互**不自造**,全部交给官方组件(`@deepseek-ai/dsh-client-ui-primitives`):\n * - `SettingsForm`:表单框架——只读提示、不可用提示、保存按钮、失败行、间距;\n * - `SettingsFormModel`:分步草稿与保存(revision 围栏、宿主拒绝时不丢草稿);\n * - `Switch`:开关本体。\n * 官方设置页(设置 → 内置插件 → 子智能体 / 网页搜索)用的就是这三件,本卡片的\n * 类名与取值也逐条对齐它们的 CSS(见 `BadgeSettingsCard.module.css` 头部)。\n *\n * 字段定义在 `badge-field.ts`(纯逻辑,可单测);这里只管把它们接到模型与槽位上。\n */\nimport { useEffect, useId, useMemo, useSyncExternalStore } from 'react'\nimport type { JSX } from 'react'\nimport {\n SettingsForm,\n SettingsFormModel,\n Switch,\n type SettingsFormLabels,\n type SettingsFormScope,\n} from '@deepseek-ai/dsh-client-ui-primitives'\nimport { ALL_BADGE_FIELDS, BADGE_FIELDS, isDraftEnabled } from './badge-field.ts'\nimport type { WorkspaceKey } from './locales.ts'\nimport css from './BadgeSettingsCard.module.css'\n\n/**\n * 卡片 props:宿主设置表单 + 本命名空间文案取值器。\n *\n * `scope` 直接用官方 `SettingsFormScope`(= `configForms.get(条目 id)` 的运行时形状:\n * `getSnapshot` / `subscribe` / `mutate`),因此不需要本地复刻契约,也就不会与宿主漂移。\n * `locale: NS` 由框架按声明注入 `t`。\n */\nexport interface BadgeSettingsCardProps {\n readonly scope: SettingsFormScope<Record<string, unknown>>\n readonly t: (key: WorkspaceKey) => string\n}\n\n/**\n * 渲染折叠徽标的设置表单。\n *\n * 模型与投影都按 `scope` 记忆:宿主换一份表单(条目重新服务)时整体重建,旧模型\n * 在 effect 清理里 `dispose()`,不会留下悬挂订阅。\n * @param props - 宿主设置表单与文案取值器。\n * @returns 官方表单框架包着本插件的开关字段。\n */\nexport function BadgeSettingsCard({ scope, t }: BadgeSettingsCardProps): JSX.Element {\n const model = useMemo(\n () => new SettingsFormModel<Record<string, unknown>>(scope, ALL_BADGE_FIELDS),\n [scope],\n )\n useEffect(() => () => { model.dispose() }, [model])\n // 投影:框架状态 + 所有字段的草稿。模型的 publish 会在宿主折叠或草稿变化时重算。\n const store = useMemo(\n () => model.bind(() => ({\n ...model.shell(),\n fields: ALL_BADGE_FIELDS.map(spec => ({ field: spec.field, text: model.field(spec.field).text })),\n })),\n [model],\n )\n const state = useSyncExternalStore(store.subscribe, store.getSnapshot)\n const actions = useMemo(() => model.actions(), [model])\n const badgeSectionId = useId()\n const hoverSectionId = useId()\n const countSectionId = useId()\n\n const labels: SettingsFormLabels = {\n unavailable: t('settings.unavailable'),\n readOnly: t('settings.readOnly'),\n saveFailed: t('settings.saveFailed'),\n save: t('settings.save'),\n saving: t('settings.saving'),\n }\n\n // 按字段名查草稿文本。\n const fieldText = (field: string): string => {\n const found = state.fields.find(f => f.field === field)\n return found?.text ?? 'true'\n }\n\n return (\n <SettingsForm\n labels={labels}\n state={state}\n onSave={() => { actions.save() }}\n onDiscard={() => { actions.discard() }}\n >\n <section className={css.section} aria-labelledby={badgeSectionId}>\n <h3 className={css.heading} id={badgeSectionId}>{t('settings.badge.section')}</h3>\n <ToggleRow field={BADGE_FIELDS.showRunningInBadge} text={fieldText(BADGE_FIELDS.showRunningInBadge)} label={t('settings.badge.showRunning')} hint={t('settings.badge.showRunningHint')} state={state} actions={actions} />\n <ToggleRow field={BADGE_FIELDS.showPendingInBadge} text={fieldText(BADGE_FIELDS.showPendingInBadge)} label={t('settings.badge.showPending')} hint={t('settings.badge.showPendingHint')} state={state} actions={actions} />\n <ToggleRow field={BADGE_FIELDS.showCompletedInBadge} text={fieldText(BADGE_FIELDS.showCompletedInBadge)} label={t('settings.badge.showCompleted')} hint={t('settings.badge.showCompletedHint')} state={state} actions={actions} />\n <ToggleRow field={BADGE_FIELDS.showScheduledInBadge} text={fieldText(BADGE_FIELDS.showScheduledInBadge)} label={t('settings.badge.showScheduled')} hint={t('settings.badge.showScheduledHint')} state={state} actions={actions} />\n <ToggleRow field={BADGE_FIELDS.showWaitingReviewInBadge} text={fieldText(BADGE_FIELDS.showWaitingReviewInBadge)} label={t('settings.badge.showWaitingReview')} hint={t('settings.badge.showWaitingReviewHint')} state={state} actions={actions} />\n </section>\n <section className={css.section} aria-labelledby={hoverSectionId}>\n <h3 className={css.heading} id={hoverSectionId}>{t('settings.hover.section')}</h3>\n <ToggleRow field={BADGE_FIELDS.showHoverDetails} text={fieldText(BADGE_FIELDS.showHoverDetails)} label={t('settings.hover.showDetails')} hint={t('settings.hover.showDetailsHint')} state={state} actions={actions} />\n </section>\n <section className={css.section} aria-labelledby={countSectionId}>\n <h3 className={css.heading} id={countSectionId}>{t('settings.count.section')}</h3>\n <NumberRow field={BADGE_FIELDS.countThreshold} text={fieldText(BADGE_FIELDS.countThreshold)} label={t('settings.count.threshold')} hint={t('settings.count.thresholdHint')} state={state} actions={actions} />\n </section>\n </SettingsForm>\n )\n}\n\n/** 单行开关:label + Switch + hint。 */\nfunction ToggleRow({ field, text, label, hint, state, actions }: {\n field: string\n text: string\n label: string\n hint: string\n state: { writable: boolean; saving: boolean }\n actions: { edit: (field: string, value: string) => void }\n}): JSX.Element {\n return (\n <div className={css.badgeField}>\n <div className={css.badgeToggleRow}>\n <span className={css.badgeToggleLabel}>{label}</span>\n <Switch\n checked={isDraftEnabled(text)}\n label={label}\n disabled={!state.writable || state.saving}\n onChange={next => { actions.edit(field, next ? 'true' : 'false') }}\n />\n </div>\n <p className={css.hint}>{hint}</p>\n </div>\n )\n}\n\n/** 单行数字输入:label + 带加减按钮的数字输入 + hint。 */\nfunction NumberRow({ field, text, label, hint, state, actions }: {\n field: string\n text: string\n label: string\n hint: string\n state: { writable: boolean; saving: boolean }\n actions: { edit: (field: string, value: string) => void }\n}): JSX.Element {\n const disabled = !state.writable || state.saving\n const currentValue = Number(text) || 0\n const decrement = () => { if (!disabled && currentValue > 0) actions.edit(field, String(currentValue - 1)) }\n const increment = () => { if (!disabled) actions.edit(field, String(currentValue + 1)) }\n return (\n <div className={css.badgeField}>\n <div className={css.badgeToggleRow}>\n <span className={css.badgeToggleLabel}>{label}</span>\n <div className={css.badgeNumberControl}>\n <button\n type=\"button\"\n className={css.badgeNumberButton}\n disabled={disabled || currentValue <= 0}\n onClick={decrement}\n aria-label=\"减少\"\n >\n −\n </button>\n <span className={css.badgeNumberValue}>{text}</span>\n <button\n type=\"button\"\n className={css.badgeNumberButton}\n disabled={disabled}\n onClick={increment}\n aria-label=\"增加\"\n >\n +\n </button>\n </div>\n </div>\n <p className={css.hint}>{hint}</p>\n </div>\n )\n}\n","//#region lib/types/index.js\n/** Duplicate-install-safe JSON and immutable-value helpers. @module @deepseek-ai/dsh-util-values */\n/**\n* Mark an unreachable closed-union branch.\n* @param value - impossible value; an unhandled typed variant fails at the call site.\n* @param context - optional switch-site label included in the failure message.\n* @returns never; a runtime value that escaped its type always throws.\n*/\nfunction assertNever(value, context) {\n\tconst rendered = JSON.stringify(value) ?? String(value);\n\tthrow new Error(`unreachable variant${context ? ` in ${context}` : \"\"}: ${rendered}`);\n}\n/** Whether a realm-owned intrinsic prototype has a native constructor matching this engine's representation. */\nfunction hasIntrinsicConstructor(prototype, name) {\n\tconst constructor = Object.getOwnPropertyDescriptor(prototype, \"constructor\")?.value;\n\tif (typeof constructor !== \"function\") return false;\n\ttry {\n\t\treturn constructor.name === name && constructor.prototype === prototype && Function.prototype.toString.call(constructor) === Function.prototype.toString.call(name === \"Array\" ? Array : Object);\n\t} catch {\n\t\treturn false;\n\t}\n}\n/** Whether a candidate is one realm's intrinsic `Object.prototype`. */\nfunction isIntrinsicObjectPrototype(value) {\n\treturn Object.getPrototypeOf(value) === null && hasIntrinsicConstructor(value, \"Object\");\n}\n/** Whether an array uses one realm's intrinsic `Array.prototype`, not a subclass or forged prototype. */\nfunction hasPlainArrayPrototype(value) {\n\tconst prototype = Object.getPrototypeOf(value);\n\tif (!Array.isArray(prototype) || !hasIntrinsicConstructor(prototype, \"Array\")) return false;\n\tconst objectPrototype = Object.getPrototypeOf(prototype);\n\treturn typeof objectPrototype === \"object\" && objectPrototype !== null && isIntrinsicObjectPrototype(objectPrototype);\n}\n/** Whether an object is a plain or null-prototype record from any JavaScript realm. */\nfunction hasPlainObjectPrototype(value) {\n\tconst prototype = Object.getPrototypeOf(value);\n\treturn prototype === null || typeof prototype === \"object\" && isIntrinsicObjectPrototype(prototype);\n}\n/** Return every JSON-visible object key, or reject own data JSON would discard. */\nfunction enumerableStringKeys(value) {\n\tconst keys = Reflect.ownKeys(value);\n\tif (keys.some((key) => typeof key !== \"string\" || !Object.prototype.propertyIsEnumerable.call(value, key))) return void 0;\n\treturn keys;\n}\n/** Validate lossless JSON iteratively, optionally materializing a detached snapshot. */\nfunction walkJsonValue(value, detach) {\n\tconst ancestors = /* @__PURE__ */ new Set();\n\tlet root;\n\tconst assign = (destination, item) => {\n\t\tif (destination === void 0) return;\n\t\tif (destination.kind === \"root\") root = item;\n\t\telse if (destination.kind === \"array\") destination.target[destination.index] = item;\n\t\telse Object.defineProperty(destination.target, destination.key, {\n\t\t\tvalue: item,\n\t\t\tenumerable: true,\n\t\t\tconfigurable: true,\n\t\t\twritable: true\n\t\t});\n\t};\n\tconst tasks = [{\n\t\tkind: \"visit\",\n\t\tvalue,\n\t\t...detach ? { destination: { kind: \"root\" } } : {}\n\t}];\n\tfor (let task = tasks.pop(); task !== void 0; task = tasks.pop()) {\n\t\tif (task.kind === \"leave\") {\n\t\t\tancestors.delete(task.source);\n\t\t\tcontinue;\n\t\t}\n\t\tif (task.kind === \"array-item\") {\n\t\t\tif (!Object.prototype.hasOwnProperty.call(task.source, task.index)) return void 0;\n\t\t\ttasks.push({\n\t\t\t\tkind: \"visit\",\n\t\t\t\tvalue: task.source[task.index],\n\t\t\t\t...task.target === void 0 ? {} : { destination: {\n\t\t\t\t\tkind: \"array\",\n\t\t\t\t\ttarget: task.target,\n\t\t\t\t\tindex: task.index\n\t\t\t\t} }\n\t\t\t});\n\t\t\tcontinue;\n\t\t}\n\t\tif (task.kind === \"object-property\") {\n\t\t\ttasks.push({\n\t\t\t\tkind: \"visit\",\n\t\t\t\tvalue: task.source[task.key],\n\t\t\t\t...task.target === void 0 ? {} : { destination: {\n\t\t\t\t\tkind: \"object\",\n\t\t\t\t\ttarget: task.target,\n\t\t\t\t\tkey: task.key\n\t\t\t\t} }\n\t\t\t});\n\t\t\tcontinue;\n\t\t}\n\t\tconst current = task.value;\n\t\tif (current === null) {\n\t\t\tassign(task.destination, null);\n\t\t\tcontinue;\n\t\t}\n\t\tif (typeof current === \"boolean\" || typeof current === \"string\") {\n\t\t\tassign(task.destination, current);\n\t\t\tcontinue;\n\t\t}\n\t\tif (typeof current === \"number\") {\n\t\t\tif (!Number.isFinite(current) || Object.is(current, -0)) return void 0;\n\t\t\tassign(task.destination, current);\n\t\t\tcontinue;\n\t\t}\n\t\tif (typeof current !== \"object\") return void 0;\n\t\tif (ancestors.has(current)) return void 0;\n\t\tif (Array.isArray(current)) {\n\t\t\tif (!hasPlainArrayPrototype(current)) return void 0;\n\t\t\tconst length = current.length;\n\t\t\tif (Reflect.ownKeys(current).length !== length + 1) return void 0;\n\t\t\tconst target = detach ? [] : void 0;\n\t\t\tif (target !== void 0) assign(task.destination, target);\n\t\t\tancestors.add(current);\n\t\t\ttasks.push({\n\t\t\t\tkind: \"leave\",\n\t\t\t\tsource: current\n\t\t\t});\n\t\t\tfor (let index = length - 1; index >= 0; index--) tasks.push({\n\t\t\t\tkind: \"array-item\",\n\t\t\t\tsource: current,\n\t\t\t\tindex,\n\t\t\t\t...target === void 0 ? {} : { target }\n\t\t\t});\n\t\t\tcontinue;\n\t\t}\n\t\tif (!hasPlainObjectPrototype(current)) return void 0;\n\t\tconst keys = enumerableStringKeys(current);\n\t\tif (keys === void 0) return void 0;\n\t\tconst target = detach ? {} : void 0;\n\t\tif (target !== void 0) assign(task.destination, target);\n\t\tancestors.add(current);\n\t\ttasks.push({\n\t\t\tkind: \"leave\",\n\t\t\tsource: current\n\t\t});\n\t\tfor (let index = keys.length - 1; index >= 0; index--) {\n\t\t\tconst key = keys[index];\n\t\t\t/* v8 ignore next -- the loop is bounded by the captured key count. */\n\t\t\tif (key === void 0) return void 0;\n\t\t\ttasks.push({\n\t\t\t\tkind: \"object-property\",\n\t\t\t\tsource: current,\n\t\t\t\tkey,\n\t\t\t\t...target === void 0 ? {} : { target }\n\t\t\t});\n\t\t}\n\t}\n\treturn detach ? root : true;\n}\n/**\n* Validate and detach lossless JSON in one read per property.\n* @param value - candidate value to validate and detach.\n* @returns the detached snapshot, or `undefined` when the value is not losslessly JSON-serializable.\n*/\nfunction snapshotJsonValue(value) {\n\treturn walkJsonValue(value, true);\n}\n/**\n* Test the same lossless JSON rules as {@link snapshotJsonValue} without detaching the value.\n* @param value - candidate value to test.\n* @returns whether the value survives a JSON round trip without loss.\n*/\nfunction isJsonValue(value) {\n\treturn walkJsonValue(value, false) === true;\n}\n/**\n* Compare JSON-compatible values structurally.\n* @param a - one JSON-compatible value.\n* @param b - the other JSON-compatible value.\n* @returns whether both values contain the same JSON data.\n*/\nfunction deepEqualJson(a, b) {\n\tif (a === b) return true;\n\tif (typeof a !== \"object\" || typeof b !== \"object\" || a === null || b === null) return false;\n\tif (Array.isArray(a) || Array.isArray(b)) {\n\t\tif (!Array.isArray(a) || !Array.isArray(b) || a.length !== b.length) return false;\n\t\treturn a.every((entry, index) => deepEqualJson(entry, b[index]));\n\t}\n\tconst left = a;\n\tconst right = b;\n\tconst keys = Object.keys(left);\n\tif (keys.length !== Object.keys(right).length) return false;\n\treturn keys.every((key) => key in right && deepEqualJson(left[key], right[key]));\n}\n/**\n* Deep-freeze an object graph in place while leaving live AbortSignal objects mutable.\n* @param value - value to freeze.\n* @returns the same value after every reachable enumerable child is frozen.\n*/\nfunction deepFreeze(value) {\n\tconst seen = /* @__PURE__ */ new WeakSet();\n\tconst pending = [{\n\t\tkind: \"visit\",\n\t\tnode: value\n\t}];\n\twhile (pending.length > 0) {\n\t\tconst task = pending.pop();\n\t\t/* v8 ignore next -- the loop condition guarantees one pending task. */\n\t\tif (task === void 0) continue;\n\t\tif (task.kind === \"property\") {\n\t\t\tpending.push({\n\t\t\t\tkind: \"visit\",\n\t\t\t\tnode: task.source[task.key]\n\t\t\t});\n\t\t\tcontinue;\n\t\t}\n\t\tconst node = task.node;\n\t\tif (node === null || typeof node !== \"object\") continue;\n\t\tif (node instanceof AbortSignal) continue;\n\t\tif (seen.has(node)) continue;\n\t\tseen.add(node);\n\t\tObject.freeze(node);\n\t\tconst keys = Object.keys(node);\n\t\tfor (let index = keys.length - 1; index >= 0; index--) {\n\t\t\tconst key = keys[index];\n\t\t\t/* v8 ignore next -- the loop is bounded by the captured key count. */\n\t\t\tif (key === void 0) continue;\n\t\t\tpending.push({\n\t\t\t\tkind: \"property\",\n\t\t\t\tsource: node,\n\t\t\t\tkey\n\t\t\t});\n\t\t}\n\t}\n\treturn value;\n}\n/**\n* Weak-key lookup with a strongly retained iterable set of associated values.\n*\n* Each value must belong to only one key. The container performs no automatic\n* cleanup; owners delete associations or clear the container at lifecycle end.\n*/\nvar WeakMapWithValues = class {\n\tkeys = /* @__PURE__ */ new WeakMap();\n\tvalueSet = /* @__PURE__ */ new Set();\n\t/** Live strongly retained values in insertion order. */\n\tvalues = this.valueSet;\n\t/**\n\t* Read the value associated with a key.\n\t* @param key - weakly held lookup key.\n\t* @returns the associated value, or absence.\n\t*/\n\tget(key) {\n\t\treturn this.keys.get(key);\n\t}\n\t/**\n\t* Test whether a key has an association.\n\t* @param key - weakly held lookup key.\n\t* @returns whether the key is present.\n\t*/\n\thas(key) {\n\t\treturn this.keys.has(key);\n\t}\n\t/**\n\t* Associate one key with one caller-unique value.\n\t* @param key - weakly held lookup key.\n\t* @param value - strongly retained value that belongs to no other key.\n\t* @returns this container.\n\t*/\n\tset(key, value) {\n\t\tif (this.keys.has(key)) {\n\t\t\tconst previous = this.keys.get(key);\n\t\t\tif (previous === value) return this;\n\t\t\tthis.valueSet.delete(previous);\n\t\t}\n\t\tthis.keys.set(key, value);\n\t\tthis.valueSet.add(value);\n\t\treturn this;\n\t}\n\t/**\n\t* Remove one association and its strongly retained value.\n\t* @param key - weakly held lookup key.\n\t* @returns whether an association was removed.\n\t*/\n\tdelete(key) {\n\t\tif (!this.keys.has(key)) return false;\n\t\tconst value = this.keys.get(key);\n\t\tconst deleted = this.keys.delete(key);\n\t\tthis.valueSet.delete(value);\n\t\treturn deleted;\n\t}\n\t/** Remove every association and strongly retained value. */\n\tclear() {\n\t\tthis.keys = /* @__PURE__ */ new WeakMap();\n\t\tthis.valueSet.clear();\n\t}\n};\n//#endregion\nexport { WeakMapWithValues, assertNever, deepEqualJson, deepFreeze, isJsonValue, snapshotJsonValue };\n","//#region lib/types/file-address.js\n/**\n* The `dsh-resource://file/…` address grammar: how a file is named across the\n* Sidebar and the resource model, built and parsed without touching a\n* filesystem.\n* @module\n*/\n/** The scheme and type every file address opens with. */\nconst FILE_ADDRESS_PREFIX = \"dsh-resource://file/\";\n/** Component-encode one id or path segment, keeping `:` literal for drive letters. */\nfunction encodeSegment(segment) {\n\treturn encodeURIComponent(segment).replace(/%3A/gi, \":\");\n}\n/** Encode a `/`-separated path segment by segment. */\nfunction encodePath(path) {\n\treturn path.split(\"/\").map(encodeSegment).join(\"/\");\n}\n/** Whether a decoded first path segment is a Windows drive (`C:`). */\nfunction isDriveSegment(segment) {\n\treturn segment !== void 0 && /^[A-Za-z]:$/.test(segment);\n}\n/**\n* Build the address of a file read through one Session.\n* @param sessionId - the Session whose Host workspace resolves the path.\n* @param path - absolute or workspace-relative path; backslashes are normalized to `/`, and leading `./` prefixes are dropped.\n* @returns the `dsh-resource://file/session/<sessionId>/<path>` address.\n*/\nfunction sessionFileAddress(sessionId, path) {\n\tconst normalized = path.replace(/\\\\/g, \"/\").replace(/^(?:\\.\\/)+/, \"\");\n\treturn `${FILE_ADDRESS_PREFIX}session/${encodeSegment(sessionId)}/${encodePath(normalized)}`;\n}\n/**\n* Build the address of a file by its absolute path.\n* @param path - absolute path; backslashes are normalized to `/` and the leading `/` is dropped,\n* except that a UNC path (`\\\\server\\share`) keeps one empty first segment.\n* @returns the `dsh-resource://file/absolute/<path>` address.\n*/\nfunction absoluteFileAddress(path) {\n\tconst normalized = path.replace(/\\\\/g, \"/\");\n\tconst unc = normalized.startsWith(\"//\");\n\tconst absolute = normalized.replace(/^\\/+/, \"\");\n\treturn `${FILE_ADDRESS_PREFIX}absolute/${unc ? \"/\" : \"\"}${encodePath(absolute)}`;\n}\n/**\n* Read a file address back into its parts without resolving `.` or `..`.\n* Query and fragment suffixes are ignored; encoded path segments are decoded.\n* @param address - a candidate address.\n* @returns the parts, or `undefined` when the string is not a `dsh-resource://file/` URI in a known scope with a path, or a segment is not validly encoded.\n*/\nfunction parseFileAddress(address) {\n\ttry {\n\t\tif (!address.startsWith(FILE_ADDRESS_PREFIX)) return void 0;\n\t\tconst end = address.search(/[?#]/);\n\t\tconst [scope, ...rest] = address.slice(20, end === -1 ? void 0 : end).split(\"/\");\n\t\tif (scope === \"session\") {\n\t\t\tconst [id, ...segments] = rest;\n\t\t\tif (id === void 0 || id === \"\" || segments.length === 0) return void 0;\n\t\t\treturn {\n\t\t\t\tscope,\n\t\t\t\tsessionId: decodeURIComponent(id),\n\t\t\t\tpath: segments.map(decodeURIComponent).join(\"/\")\n\t\t\t};\n\t\t}\n\t\tif (scope === \"absolute\") {\n\t\t\tconst unc = rest[0] === \"\" && rest.length > 1;\n\t\t\tconst segments = (unc ? rest.slice(1) : rest).map(decodeURIComponent);\n\t\t\tif (segments.length === 0 || segments[0] === \"\") return void 0;\n\t\t\tif (unc) return {\n\t\t\t\tscope,\n\t\t\t\tpath: `//${segments.join(\"/\")}`\n\t\t\t};\n\t\t\treturn {\n\t\t\t\tscope,\n\t\t\t\tpath: isDriveSegment(segments[0]) ? segments.join(\"/\") : `/${segments.join(\"/\")}`\n\t\t\t};\n\t\t}\n\t\treturn;\n\t} catch {\n\t\treturn;\n\t}\n}\n//#endregion\n//#region lib/types/index.js\n/**\n* Browser-safe Workspace path and display helpers.\n* @module @deepseek-ai/dsh-util-workspace-path\n*/\n/** Whether a path uses a Windows drive or UNC prefix. */\nfunction isWindowsStylePath(value) {\n\treturn /^[A-Za-z]:[/\\\\]/.test(value) || value.startsWith(\"\\\\\\\\\");\n}\n/**\n* Whether a path is absolute in either spelling the Host accepts: POSIX (`/a/b`) or Windows drive or UNC.\n* @param path - the path to classify.\n* @returns `true` for an absolute path; `false` for a Workspace-relative one.\n*/\nfunction isAbsoluteWorkspacePath(path) {\n\treturn path.startsWith(\"/\") || isWindowsStylePath(path);\n}\n/**\n* Resolve a Workspace-relative path into the Host-facing spelling used by path operations.\n* @param cwd - Session Workspace root, when known.\n* @param path - Absolute or Workspace-relative path.\n* @returns an absolute path when a Workspace root is available, otherwise the original path.\n*/\nfunction resolveWorkspacePath(cwd, path) {\n\tif (isAbsoluteWorkspacePath(path)) return path;\n\tif (cwd === void 0 || cwd === \"\") return path;\n\tconst separator = isWindowsStylePath(cwd) && cwd.includes(\"\\\\\") ? \"\\\\\" : \"/\";\n\treturn `${cwd.replace(/[/\\\\]+$/, \"\")}${separator}${path.replace(/^[/\\\\]+/, \"\")}`;\n}\n/**\n* Abbreviate a POSIX home directory for display.\n* @param path - Absolute or already-short display path.\n* @param home - Host account home; absent skips abbreviation.\n* @returns `~` or `~/…` for the POSIX home and its descendants, otherwise `path`.\n*/\nfunction abbreviateHomePath(path, home) {\n\tif (home === void 0 || home === \"\") return path;\n\tif (isWindowsStylePath(path) || isWindowsStylePath(home)) return path;\n\tconst root = home.replace(/\\/+$/, \"\");\n\tif (root === \"\" || root === \"/\") return path;\n\tif (path.replace(/\\/+$/, \"\") === root) return \"~\";\n\tif (path.startsWith(`${root}/`)) return `~${path.slice(root.length)}`;\n\treturn path;\n}\n/**\n* Read the final non-empty segment of a Workspace path for display.\n* Workspace-label surfaces use this helper instead of deriving another basename.\n* @param path - Workspace directory path using POSIX or Windows separators.\n* @returns the final segment, or an empty string for a separator-only path.\n*/\nfunction workspaceTitleOf(path) {\n\tconst trimmed = path.replace(/[/\\\\]+$/, \"\");\n\tconst separator = Math.max(trimmed.lastIndexOf(\"/\"), trimmed.lastIndexOf(\"\\\\\"));\n\treturn trimmed.slice(separator + 1);\n}\n/**\n* Split a path for display: the directories through their last separator, and\n* the final segment after it. Both `/` and `\\` separate, so a Windows path\n* splits where its own segments end; trailing separators are dropped first, so\n* a directory path names its own last segment. A path with no separator, or a\n* separator-only path, is all name.\n* @param path - file or directory path using POSIX or Windows separators.\n* @returns the directory prefix (possibly empty) and the final segment.\n*/\nfunction pathPartsOf(path) {\n\tconst trimmed = path.replace(/[/\\\\]+$/, \"\");\n\tif (trimmed === \"\") return {\n\t\tdirectory: \"\",\n\t\tname: path\n\t};\n\tconst cut = Math.max(trimmed.lastIndexOf(\"/\"), trimmed.lastIndexOf(\"\\\\\")) + 1;\n\treturn {\n\t\tdirectory: trimmed.slice(0, cut),\n\t\tname: trimmed.slice(cut)\n\t};\n}\n/**\n* The address for a path as a caller holds it: a relative path, or an absolute\n* path inside the Session's workspace, becomes a `session`-scoped address; an\n* absolute path outside it, or one whose workspace root is unknown, keeps its\n* absolute path in that Session's address.\n* @param sessionId - the Session the path is read in.\n* @param cwd - that Session's workspace root, when known.\n* @param path - absolute or workspace-relative path, in either separator spelling.\n* @returns the `dsh-resource://file/…` address.\n*/\nfunction fileAddressFor(sessionId, cwd, path) {\n\tconst normalized = path.replace(/\\\\/g, \"/\");\n\tif (!isAbsoluteWorkspacePath(normalized)) return sessionFileAddress(sessionId, normalized);\n\tconst root = cwd === void 0 ? \"\" : cwd.replace(/\\\\/g, \"/\").replace(/\\/+$/, \"\");\n\tif (root !== \"\" && normalized === root) return sessionFileAddress(sessionId, \"\");\n\tif (root !== \"\" && normalized.startsWith(`${root}/`)) return sessionFileAddress(sessionId, normalized.slice(root.length + 1));\n\treturn sessionFileAddress(sessionId, normalized);\n}\n/**\n* Strip the workspace root from a workspace-rooted absolute path (display only).\n* @param text - the path to shorten.\n* @param cwd - session workspace root; absent or empty leaves the path unchanged.\n* @returns the path relative to the workspace root, or unchanged when it is not rooted there.\n*/\nfunction relativizeToCwd(text, cwd) {\n\tif (cwd === void 0 || cwd === \"\") return text;\n\tconst root = cwd.replace(/[/\\\\]+$/, \"\");\n\tif (text.startsWith(`${root}/`) || text.startsWith(`${root}\\\\`)) return text.slice(root.length + 1);\n\treturn text;\n}\n/**\n* Address a decoded absolute file path through the authenticated file route.\n* @param base - HTTP(S) application base, including its deployment prefix, or `dsh-app://app/`.\n* @param path - Native file path; URL escapes in authored Markdown must already be decoded.\n* @returns File URL, or undefined for unsupported transports and non-absolute paths.\n*/\nfunction fileMediaUrl(base, path) {\n\tif (!/^https?:/u.test(base) && !base.startsWith(\"dsh-app://app/\") || !isAbsoluteWorkspacePath(path) || /^[/\\\\]{2}/u.test(path) || /[\\u0000-\\u001f\\u007f]/u.test(path)) return void 0;\n\treturn new URL(`api/file?path=${encodeURIComponent(path)}`, base).href;\n}\n//#endregion\nexport { abbreviateHomePath, absoluteFileAddress, fileAddressFor, fileMediaUrl, isAbsoluteWorkspacePath, parseFileAddress, pathPartsOf, relativizeToCwd, resolveWorkspacePath, sessionFileAddress, workspaceTitleOf };\n","/**\n * Derives the workspace browser tree from caller-projected Workspace and\n * Session order. Unassigned Sessions trail under Ungrouped; only the selected\n * blank Session remains visible.\n */\nimport {\n type SessionListState, type SessionSearchResultItem, type SessionSummary,\n} from '@deepseek-ai/dsh-api-session-controller/client'\nimport type { WorkspaceId, WorkspaceView } from '@deepseek-ai/dsh-api-workspace-controller/client'\nimport type {\n SessionStatusSnapshot,\n} from '@deepseek-ai/dsh-client-ui-session/client'\nimport type { SessionId } from '@deepseek-ai/dsh-session/types'\nimport { assertNever } from '@deepseek-ai/dsh-util-values'\nimport { workspaceTitleOf } from '@deepseek-ai/dsh-util-workspace-path'\n// Fork-owned: `GroupLiveStatus` lives in ./group-status.ts and is re-exported here so\n// the vendored row components can keep importing every group type from one module.\n// Nothing else is re-exported: the status computation has no reason to pass through\n// this file, and the cross-plugin summary types had no consumers at all.\nimport type { GroupLiveStatus } from './group-status.ts'\n\nexport type { GroupLiveStatus }\n\n/** Group key for Sessions outside every Workspace. */\nexport const UNGROUPED_KEY = ''\n\n/**\n * Resolve the Workspace browser group that owns one Session.\n * @param workspaces - authoritative Workspace membership.\n * @param sessionId - Session whose browser group is required.\n * @returns owning Workspace id, or {@link UNGROUPED_KEY} when no Workspace accounts for it.\n */\nexport function owningGroupKey(\n workspaces: readonly WorkspaceView[],\n sessionId: SessionId,\n): string {\n return (workspaces.find(workspace => workspace.sessionIds.includes(sessionId))\n ?.workspaceId as string | undefined) ?? UNGROUPED_KEY\n}\n\n/** Pending interaction kinds with dedicated Workspace-row presentation. */\nexport type SessionPendingInteractionStatus = 'approval' | 'plan-review' | 'question'\ntype SessionStatuses = SessionStatusSnapshot\n\nfunction mainSessionId(list: SessionListState): SessionId | undefined {\n return Object.values(list.byId)\n .find(session => (session.retainedBy.mainView ?? 0) > 0)?.id\n}\n\n/** One top-level session row in a group or the flat list. */\nexport interface SessionNode {\n id: SessionId\n /** Stored title, or empty; the renderer localizes blank and unnamed row labels. */\n title: string\n /** The provisional blank session (renderer shows the localized New Session title). */\n blank: boolean\n /** A Session-scoped UI consumer is awaiting this user. */\n pendingInteraction?: SessionPendingInteractionStatus\n running: boolean\n /** Running direct children in the loaded subagent catalog. */\n runningSubagentCount: number\n /** Finished running while not selected and not yet opened (the green \"done\" reminder dot). */\n completed: boolean\n /** In the registry-global pin set: leads its section, reorderable only among pinned rows. */\n pinned: boolean\n /** In the registry-global archive set: shown grayed in place and not openable. */\n archived: boolean\n updatedAt: number\n}\n\n/** Session order selected by the Workspace browser. */\nexport type SessionOrderBy = 'manual' | 'updated'\n\n// ── Group node shapes ──\n// The live-status computation this fork adds lives entirely in ./group-status.ts;\n// only its `GroupLiveStatus` type is re-exported above. Keeping it in a separate\n// file minimises the upstream diff surface.\n\n/** One workspace group section: header row facts + visible top-level session rows. */\nexport interface GroupNode {\n /** Group key: the workspace id or {@link UNGROUPED_KEY}. */\n key: string\n /** Backing Workspace id; absent only for the ungrouped bucket. */\n workspaceId: WorkspaceId | undefined\n cwd: string | undefined\n /** Workspace creation time (epoch ms); absent only for the ungrouped bucket. */\n createdAt: number | undefined\n label: string\n /** Total visible sessions in the group. */\n sessionCount: number\n expanded: boolean\n /** The group contains the selected session (active folder tint; supplied here so the renderer never scans). */\n containsCurrent: boolean\n /** Aggregated member status; computed externally by HOC in WorkspaceBrowser.tsx. */\n liveStatus?: GroupLiveStatus\n /** Visible session rows (empty while the group is folded). */\n sessions: readonly SessionNode[]\n}\n\n/** One flat search row combining list metadata with an optional content match. */\nexport interface SearchResultNode {\n id: SessionId\n title: string\n workspace: string\n /** A Session-scoped UI consumer is awaiting this user. */\n pendingInteraction?: SessionPendingInteractionStatus\n running: boolean\n /** Running direct children in the loaded subagent catalog. */\n runningSubagentCount: number\n /** Finished running while not selected and not yet opened (the green \"done\" reminder dot). */\n completed: boolean\n /** In the registry-global archive set: shown grayed and not openable. */\n archived: boolean\n snippet?: string\n}\n\n/** Bounded merged search projection plus the refine-query hint bit. */\nexport interface SearchResultSet {\n items: readonly SearchResultNode[]\n hasMore: boolean\n}\n\n/** Viewing state consumed by the derivation. */\nexport interface TreeView {\n expandedGroups: readonly string[]\n /** Browser-local order for Sessions without a backing Workspace account. */\n ungroupedOrder?: readonly string[]\n}\n\ninterface Group {\n key: string\n workspaceId: WorkspaceId | undefined\n cwd: string | undefined\n createdAt: number | undefined\n label: string\n sessions: SessionSummary[]\n}\n\n/**\n * Directory display label: basename of the path (both separators accepted).\n * Ungrouped-bucket fallback for surfaces without a workspace title.\n * @param cwd - directory path, or undefined for the ungrouped bucket.\n * @returns basename, the raw cwd when it has no basename, or an empty ungrouped marker.\n */\nexport function workspaceLabel(cwd: string | undefined): string {\n if (cwd === undefined || cwd === '') return ''\n const base = workspaceTitleOf(cwd)\n return base !== '' ? base : cwd\n}\n\n/**\n * Project known account members by current Session recency.\n * @param sessionIds - authoritative account membership.\n * @param summaries - current Session summaries; members without a summary are omitted until it arrives.\n * @returns known members newest first, with Session identity as the deterministic tie-break.\n */\nexport function orderByRecency(\n sessionIds: readonly SessionId[],\n summaries: SessionListState['byId'],\n): SessionId[] {\n return sessionIds.flatMap((id) => {\n const summary = summaries[id]\n if (summary === undefined) return []\n return [{ id, rank: summary.updatedAt }]\n })\n .sort((a, b) => {\n if (a.rank !== b.rank) return b.rank - a.rank\n return a.id < b.id ? -1 : 1\n })\n .map(member => member.id)\n}\n\n/**\n * Reconcile a browser-local manual order with current account membership.\n * New ordinary forks precede their sources without changing saved entries' relative order.\n * @param memberIds - authoritative account membership.\n * @param savedOrder - previously saved browser-local order.\n * @param summaries - current Session metadata; unknown new members wait for their summaries.\n * @param rowState - global pin and archive membership; only account members can supplement the order.\n * @returns saved relative positions plus missing members ordered by pin, fork source, recency, and archive status.\n */\nexport function reconcileManualOrder(\n memberIds: readonly SessionId[],\n savedOrder: readonly string[] | undefined,\n summaries: SessionListState['byId'],\n rowState?: Pick<SessionRowState, 'pinnedSessionIds' | 'archivedSessionIds'>,\n): SessionId[] {\n const members = new Map(memberIds.map(id => [id as string, id]))\n const included = new Set<string>()\n const ordered: SessionId[] = []\n for (const key of savedOrder ?? []) {\n const id = members.get(key)\n if (id === undefined || included.has(key)) continue\n ordered.push(id)\n included.add(key)\n }\n const archived = new Set(rowState?.archivedSessionIds)\n const pins: SessionId[] = []\n for (const sessionId of rowState?.pinnedSessionIds ?? []) {\n const id = members.get(sessionId)\n if (id === undefined || included.has(id) || archived.has(id) || summaries[id] === undefined) continue\n pins.push(id)\n included.add(id)\n }\n const ordinary: SessionId[] = []\n const archives: SessionId[] = []\n for (const id of orderByRecency([...members.values()].filter(id => !included.has(id)), summaries)) {\n if (archived.has(id)) archives.push(id)\n else ordinary.push(id)\n }\n const result = [...pins, ...ordered, ...ordinary, ...archives]\n const pending = new Set(ordinary)\n const placeFork = (id: SessionId): void => {\n if (!pending.delete(id)) return\n const parentId = summaries[id]?.parentId\n if (parentId === undefined || parentId === id || !result.includes(parentId)) return\n placeFork(parentId)\n result.splice(result.indexOf(id), 1)\n result.splice(result.indexOf(parentId), 0, id)\n }\n for (const id of [...ordinary].reverse()) placeFork(id)\n return result\n}\n\n/**\n * Keep the selected provisional New Session ahead of either base order.\n * @param order - recency or reconciled manual order.\n * @param currentBlank - selected blank Session in this account, when present.\n * @returns a copy with the selected blank first and no duplicate slot.\n */\nexport function pinCurrentBlank(\n order: readonly SessionId[],\n currentBlank: SessionId | undefined,\n): SessionId[] {\n if (currentBlank === undefined) return [...order]\n return [currentBlank, ...order.filter(id => id !== currentBlank)]\n}\n\n/**\n * Archived-row visibility choice: the default hides archived rows, `show`\n * mixes them into their kept slots, and `only` restricts the view (and\n * search) to archived rows.\n */\nexport type ArchivedFilter = 'default' | 'show' | 'only'\n\n/**\n * Ordinary sessions are visible; among blank sessions, only the current one\n * is visible. Subagent children use their parent header catalog; archived\n * sessions follow the archived filter, while their accounting slots remain\n * either way so unarchiving restores position.\n */\nfunction sessionVisible(\n session: SessionSummary,\n current: SessionId | undefined,\n archived: ReadonlySet<SessionId>,\n archivedFilter: ArchivedFilter,\n): boolean {\n if (session.origin === 'subagent') return false\n if (session.blank && session.id !== current) return false\n switch (archivedFilter) {\n case 'default':\n return !archived.has(session.id)\n case 'show':\n return true\n case 'only':\n return archived.has(session.id)\n /* v8 ignore next 2 -- closed-union backstop; only reached if the filter is forged */\n default:\n return assertNever(archivedFilter)\n }\n}\n\n/** Registry-global row state consumed by every tree derivation. */\nexport interface SessionRowState {\n /** Registry-global pin ids; pinned rows lead their section in the local order. */\n pinnedSessionIds: readonly SessionId[]\n /** Archive set; members keep their slots and show grayed while visible. */\n archivedSessionIds: readonly SessionId[]\n /** Archived-row visibility choice applied to lists and search alike. */\n archivedFilter: ArchivedFilter\n}\n\n/**\n * Keep the visible New Session placeholder first, then partition pinned and\n * ordinary rows without changing either partition's caller order.\n */\nfunction sectionMembers(\n members: readonly SessionSummary[],\n pinned: ReadonlySet<SessionId>,\n archived: ReadonlySet<SessionId>,\n): SessionSummary[] {\n const placeholders: SessionSummary[] = []\n const leading: SessionSummary[] = []\n const rest: SessionSummary[] = []\n for (const member of members) {\n if (member.blank) placeholders.push(member)\n else if (!archived.has(member.id) && pinned.has(member.id)) leading.push(member)\n else rest.push(member)\n }\n return [...placeholders, ...leading, ...rest]\n}\n\n/**\n * A blank session is the selected Workspace's provisional New Session row;\n * its canonical title never enters search (blank rows are query-excluded)\n * and the renderer localizes its display label. Unnamed history also yields an\n * empty title for localization and does not match a directory-name title search.\n */\nfunction sessionTitle(session: SessionSummary): string {\n return session.blank ? '' : (session.title?.trim() ?? '')\n}\n\n/** Build one group without projecting session lineage into presentation. */\nfunction buildGroup(\n key: string,\n workspaceId: WorkspaceId | undefined,\n cwd: string | undefined,\n createdAt: number | undefined,\n label: string,\n members: readonly SessionSummary[],\n): Group {\n return { key, workspaceId, cwd, createdAt, label, sessions: [...members] }\n}\n\n/** Apply a stored Ungrouped order and append newly loose Sessions by recency. */\nfunction orderedUngrouped(\n members: readonly SessionSummary[],\n stored: readonly string[] | undefined,\n summaries: SessionListState['byId'],\n): SessionSummary[] {\n const byId = new Map(members.map(session => [session.id as string, session]))\n const ids = stored === undefined\n ? orderByRecency(members.map(session => session.id), summaries)\n : reconcileManualOrder(members.map(session => session.id), stored, summaries)\n return ids.flatMap((id) => {\n const session = byId.get(id)\n /* v8 ignore next -- ids are projected exclusively from the members used to build byId. */\n return session === undefined ? [] : [session]\n })\n}\n\n/**\n * Group Sessions by Workspace: one group per caller-ordered entity, with\n * members resolved from caller-ordered sessionIds. Sessions outside every\n * Workspace trail in the browser-local Ungrouped order, which falls back to\n * recency before that order is initialized.\n */\nfunction groupByWorkspace(\n list: SessionListState,\n workspaces: readonly WorkspaceView[],\n archived: ReadonlySet<SessionId>,\n archivedFilter: ArchivedFilter,\n ungroupedOrder: readonly string[] | undefined,\n): Group[] {\n const current = mainSessionId(list)\n const groups: Group[] = []\n const accounted = new Set<SessionId>()\n for (const workspace of workspaces) {\n const members: SessionSummary[] = []\n for (const id of workspace.sessionIds) {\n const summary = list.byId[id]\n if (summary === undefined) continue // account may lead the list pull; the row appears when the summary lands\n accounted.add(id)\n if (!sessionVisible(summary, current, archived, archivedFilter)) continue\n members.push(summary)\n }\n // The archived-only view lists archives, not the Workspace inventory, so\n // a Workspace without archived Sessions contributes no group.\n if (archivedFilter === 'only' && members.length === 0) continue\n groups.push(buildGroup(\n workspace.workspaceId, workspace.workspaceId, workspace.path,\n Date.parse(workspace.createdAt), workspace.title, members,\n ))\n }\n const stray = list.ids\n .map(id => list.byId[id])\n .filter((s): s is SessionSummary =>\n s !== undefined && !accounted.has(s.id) && sessionVisible(s, current, archived, archivedFilter))\n if (stray.length > 0) {\n groups.push(buildGroup(\n UNGROUPED_KEY,\n undefined,\n undefined,\n undefined,\n '',\n orderedUngrouped(stray, ungroupedOrder, list.byId),\n ))\n }\n return groups\n}\n\n/** Keep navigation presentation independent from domain-owned interaction objects. */\nfunction visiblePendingKind(kind: string | undefined): SessionPendingInteractionStatus | undefined {\n switch (kind) {\n case 'approval':\n case 'plan-review':\n case 'question':\n return kind\n default:\n return undefined\n }\n}\n\nfunction runningChildCount(list: SessionListState, parentId: SessionId, statuses: SessionStatuses): number {\n return list.projectionsBySession[parentId]?.values.subagentCatalog?.reduce(\n (count, child) => count + ((statuses.get(child.id)?.running ?? list.byId[child.id]?.running) === true ? 1 : 0),\n 0,\n ) ?? 0\n}\n\nfunction sessionNode(\n s: SessionSummary,\n list: SessionListState,\n statuses: SessionStatuses,\n pinned: ReadonlySet<SessionId>,\n archived: ReadonlySet<SessionId>,\n): SessionNode {\n const status = statuses.get(s.id)\n const pendingInteraction = visiblePendingKind(status?.pendingInteraction?.kind)\n return {\n id: s.id,\n title: sessionTitle(s),\n blank: s.blank,\n running: status?.running ?? s.running,\n runningSubagentCount: runningChildCount(list, s.id, statuses),\n completed: status?.completionUnread === true,\n pinned: !archived.has(s.id) && pinned.has(s.id),\n archived: archived.has(s.id),\n updatedAt: s.updatedAt,\n ...(pendingInteraction === undefined ? {} : { pendingInteraction }),\n }\n}\n\n/**\n * Derive the workspace browser groups with every session as a top-level row.\n *\n * Every group shows, except that the archived-only filter drops groups\n * without visible members; sessions populate under expanded groups with\n * pinned rows leading in the selected local order. Blank sessions are\n * excluded except for the selected provisional New Session row; archived\n * sessions keep their slots and appear per the archived filter. Content\n * search lives outside this derivation (see {@link deriveSearchResults}).\n * @param list - sessions list snapshot (`mainView` retention feeds containsCurrent).\n * @param workspaces - real Workspaces in Host group order with caller-projected Session order.\n * @param rowState - registry-global pin and archive sets plus the archived filter.\n * @param statuses - unified UI status by Session.\n * @param view - local expansion arrays.\n * @returns group sections in render order.\n */\nexport function deriveGroups(\n list: SessionListState,\n workspaces: readonly WorkspaceView[],\n rowState: SessionRowState,\n statuses: SessionStatuses,\n view: TreeView,\n): GroupNode[] {\n const archived = new Set(rowState.archivedSessionIds)\n const pinned = new Set(rowState.pinnedSessionIds)\n const expandedGroups = new Set(view.expandedGroups)\n const current = mainSessionId(list)\n const currentGroup = current === undefined\n ? undefined\n : owningGroupKey(workspaces, current)\n const groups: GroupNode[] = []\n for (const g of groupByWorkspace(list, workspaces, archived, rowState.archivedFilter, view.ungroupedOrder)) {\n const expanded = expandedGroups.has(g.key)\n const members = sectionMembers(g.sessions, pinned, archived)\n .map(session => sessionNode(session, list, statuses, pinned, archived))\n groups.push({\n key: g.key,\n workspaceId: g.workspaceId,\n cwd: g.cwd,\n createdAt: g.createdAt,\n label: g.label,\n sessionCount: g.sessions.length,\n expanded,\n containsCurrent: g.key === currentGroup,\n // Sessions always included so HOC in WorkspaceBrowser.tsx can compute badge.\n // Rendering logic in WorkspaceBrowser.tsx still checks `expanded` before rendering rows.\n sessions: members,\n })\n }\n return groups\n}\n\n/**\n * Select complete flat-list membership, independently of archive visibility.\n * @param list - sessions list snapshot.\n * @returns known ordinary Session ids, including archives and only the current blank.\n */\nexport function sessionMemberIds(list: SessionListState): SessionId[] {\n return visibleSessionIds(list, [], 'show')\n}\n\n/**\n * Select visible flat-list members without deriving row presentation or ordering.\n * @param list - sessions list snapshot.\n * @param archivedSessionIds - registry-global archive set.\n * @param archivedFilter - archived-row visibility choice.\n * @returns known visible Session ids in list order, including ordinary forks and only the current blank.\n */\nexport function visibleSessionIds(\n list: SessionListState,\n archivedSessionIds: readonly SessionId[],\n archivedFilter: ArchivedFilter,\n): SessionId[] {\n const archived = new Set(archivedSessionIds)\n const current = mainSessionId(list)\n return list.ids.filter((id) => {\n const s = list.byId[id]\n return s !== undefined && sessionVisible(s, current, archived, archivedFilter)\n })\n}\n\n/**\n * Derive flat rows from the browser's complete ordered Session ids, with\n * pinned rows fronted ahead of the supplied order.\n * @param list - sessions list snapshot used to select the ids.\n * @param sessionIds - complete account members in the selected order, including hidden archives.\n * @param rowState - registry-global pin and archive sets plus the archived filter.\n * @param statuses - unified UI status by Session.\n * @returns flat rows in sectioned order with current status indicators.\n */\nexport function deriveFlat(\n list: SessionListState,\n sessionIds: readonly SessionId[],\n rowState: SessionRowState,\n statuses: SessionStatuses,\n): SessionNode[] {\n const archived = new Set(rowState.archivedSessionIds)\n const pinned = new Set(rowState.pinnedSessionIds)\n const current = mainSessionId(list)\n const members = sessionIds.flatMap((id) => {\n const session = list.byId[id]\n return session !== undefined && sessionVisible(session, current, archived, rowState.archivedFilter)\n ? [session]\n : []\n })\n return sectionMembers(members, pinned, archived)\n .map(session => sessionNode(session, list, statuses, pinned, archived))\n}\n\n/**\n * Merge immediate title/Workspace substring matches with ranked Host content\n * matches. Local rows lead newest-first, content-only rows retain backend\n * order, and duplicate sessions receive the backend snippet in place.\n * @param list - session metadata authority.\n * @param workspaces - Workspace membership and display labels.\n * @param query - caller text; surrounding whitespace is ignored.\n * @param archivedSessionIds - registry-global archive set (members match per the archived filter).\n * @param archivedFilter - archived-row visibility choice; search follows it.\n * @param statuses - unified UI status by Session.\n * @param content - ranked Host content-search page.\n * @param limit - protocol-owned maximum merged row count.\n * @returns bounded deduplicated flat rows and a refine-query hint bit.\n */\nexport function deriveSearchResults(\n list: SessionListState,\n workspaces: readonly WorkspaceView[],\n query: string,\n archivedSessionIds: readonly SessionId[],\n archivedFilter: ArchivedFilter,\n statuses: SessionStatuses,\n content: { items: readonly SessionSearchResultItem[]; hasMore: boolean },\n limit: number,\n): SearchResultSet {\n const q = query.trim().toLowerCase()\n if (q === '') return { items: [], hasMore: false }\n const archived = new Set(archivedSessionIds)\n const current = mainSessionId(list)\n\n const workspaceBySession = new Map<SessionId, string>()\n for (const workspace of workspaces) {\n for (const sessionId of workspace.sessionIds) {\n if (!workspaceBySession.has(sessionId)) workspaceBySession.set(sessionId, workspace.title)\n }\n }\n const labelOf = (summary: SessionSummary): string =>\n workspaceBySession.get(summary.id) ?? workspaceLabel(summary.cwd)\n const contentBySession = new Map<SessionId, SessionSearchResultItem>()\n for (const item of content.items) {\n if (!contentBySession.has(item.sessionId)) contentBySession.set(item.sessionId, item)\n }\n\n const local: SessionSummary[] = []\n for (const id of list.ids) {\n const summary = list.byId[id]\n // Blank placeholders never match a query (their canonical title displays\n // localized, so matching it would tie search to one language).\n if (summary === undefined || summary.blank || !sessionVisible(summary, current, archived, archivedFilter)) continue\n if (\n sessionTitle(summary).toLowerCase().includes(q)\n || labelOf(summary).toLowerCase().includes(q)\n ) {\n local.push(summary)\n }\n }\n const localById = new Map(local.map(summary => [summary.id, summary]))\n const orderedLocal = orderByRecency(local.map(summary => summary.id), list.byId)\n .map(id => localById.get(id) as SessionSummary)\n\n const ordered: SessionSummary[] = []\n const included = new Set<SessionId>()\n const include = (summary: SessionSummary): void => {\n if (included.has(summary.id)) return\n included.add(summary.id)\n ordered.push(summary)\n }\n for (const summary of orderedLocal) include(summary)\n for (const item of content.items) {\n const summary = list.byId[item.sessionId]\n if (summary !== undefined && !summary.blank && sessionVisible(summary, current, archived, archivedFilter)) include(summary)\n }\n\n return {\n items: ordered.slice(0, limit).map((summary) => {\n const match = contentBySession.get(summary.id)\n const status = statuses.get(summary.id)\n const pendingInteraction = visiblePendingKind(status?.pendingInteraction?.kind)\n return {\n id: summary.id,\n title: sessionTitle(summary),\n workspace: labelOf(summary),\n running: status?.running ?? summary.running,\n runningSubagentCount: runningChildCount(list, summary.id, statuses),\n ...(pendingInteraction === undefined\n ? {}\n : { pendingInteraction }),\n completed: status?.completionUnread === true,\n archived: archived.has(summary.id),\n ...match === undefined ? {} : { snippet: match.snippet },\n }\n }),\n hasMore: content.hasMore || ordered.length > limit,\n }\n}\n\n/** Normalize separators for comparison without interpreting POSIX backslashes as separators. */\nfunction folderPath(path: string): string {\n const windows = /^[A-Za-z]:[/\\\\]/.test(path) || path.startsWith('\\\\\\\\')\n return (windows ? path.replaceAll('\\\\', '/') : path).replace(/\\/+$/, '')\n}\n\n/**\n * Find the nearest registered ancestor, excluding the Workspace directory itself.\n * Paths use Host spelling; matching is case-sensitive, like Workspace identity.\n * @param path - Workspace directory.\n * @param parents - registered Workspace directory paths.\n * @returns the owning parent path, or undefined when no parent contains the Workspace.\n */\nexport function owningParentFolder(path: string, parents: readonly string[]): string | undefined {\n const child = folderPath(path)\n let owner: string | undefined\n let length = -1\n for (const parent of parents) {\n const root = folderPath(parent)\n if (root.length > length && child !== root && child.startsWith(`${root}/`)) {\n owner = parent\n length = root.length\n }\n }\n return owner\n}\n","/**\n * The workspace browser's viewing store: the session-list grouping mode,\n * persisted across reloads. Module level exports the factory only (a\n * module-level handle would pin the store identity across plugin reloads);\n * register() receives the factory and the browser derives its PropsStore\n * share from the return type.\n */\nimport { defineStore, type EngineStoreHandle } from '@deepseek-ai/dsh-client-store'\nimport type { SessionListState } from '@deepseek-ai/dsh-api-session-controller/client'\nimport type { SessionId } from '@deepseek-ai/dsh-session/types'\nimport { reconcileManualOrder, type ArchivedFilter, type SessionRowState } from './tree.ts'\n\n/** Browser-local order account for the hierarchy-free flat Session list. */\nexport const FLAT_SESSION_ORDER_KEY = '__flat_session_order__'\n\n/** Session-list grouping mode: sibling Workspace sections, a Workspace tree, or one flat list. */\nexport type SessionGroupBy = 'workspace' | 'workspace-tree' | 'flat'\n/** Session order: saved manual positions or current recency. */\nexport type SessionOrderBy = 'manual' | 'updated'\n\n/** Workspace browser viewing state persisted across surface remounts and reloads. */\ntype WorkspaceViewState = {\n groupBy: SessionGroupBy\n orderBy: SessionOrderBy\n /** Explicit group expansion keyed by Workspace identity, including descendants in tree mode. */\n groupExpansion: Record<string, boolean>\n /** Saved manual order per Workspace group plus the browser-local flat-list account. */\n sessionOrderByAccount: Record<string, string[]>\n /** Archived-row visibility; omitted in pre-filter v5 snapshots and read as 'default'. */\n archivedFilter?: ArchivedFilter\n}\n\ntype SessionOrderSource = {\n members: Readonly<Record<string, readonly SessionId[]>>\n summaries: SessionListState['byId']\n rowState: Pick<SessionRowState, 'pinnedSessionIds' | 'archivedSessionIds'>\n}\n\n/**\n * Annotation twin of the actions literal below (the export needs a declared\n * return type); drift fails assignability at the defineStore call.\n */\ntype WorkspaceViewActions = {\n setGroupBy: (draft: WorkspaceViewState, mode: SessionGroupBy) => void\n setOrderBy: (\n draft: WorkspaceViewState,\n mode: SessionOrderBy,\n initialOrders: Readonly<Record<string, readonly string[]>>,\n ) => void\n setGroupExpanded: (draft: WorkspaceViewState, key: string, expanded: boolean) => void\n retainAccountKeys: (draft: WorkspaceViewState, workspaceKeys: readonly string[]) => void\n syncSessionOrders: (\n draft: WorkspaceViewState,\n orders: Readonly<Record<string, readonly string[]>>,\n ) => void\n setSessionOrder: (\n draft: WorkspaceViewState,\n accountKey: string,\n order: readonly string[],\n initialOrders: Readonly<Record<string, readonly string[]>>,\n ) => void\n pinSessionOrder: (\n draft: WorkspaceViewState,\n sessionId: string,\n accountKeys: readonly string[],\n source: SessionOrderSource,\n ) => void\n setArchivedFilter: (draft: WorkspaceViewState, filter: ArchivedFilter) => void\n}\n\n/** Copy read-only projections into the persisted mutable store representation. */\nfunction copySessionOrders(\n orders: Readonly<Record<string, readonly string[]>>,\n): Record<string, string[]> {\n return Object.fromEntries(Object.entries(orders).map(([key, order]) => [key, [...order]]))\n}\n\n/**\n * Create the workspace browser viewing store handle.\n * @returns the store handle (spec + type + identity + factory in one).\n */\nexport function createWorkspaceViewStore(): EngineStoreHandle<WorkspaceViewState, WorkspaceViewActions> {\n return defineStore({\n init: (): WorkspaceViewState => ({\n groupBy: 'workspace',\n orderBy: 'updated',\n groupExpansion: {},\n sessionOrderByAccount: {},\n archivedFilter: 'default',\n }),\n persist: 'dsh.workspace.view.v5',\n actions: {\n setGroupBy: (d, mode: SessionGroupBy) => { d.groupBy = mode },\n setOrderBy: (d, mode: SessionOrderBy, initialOrders) => {\n if (mode === d.orderBy) return\n d.sessionOrderByAccount = mode === 'manual' ? copySessionOrders(initialOrders) : {}\n d.orderBy = mode\n },\n setGroupExpanded: (d, key: string, expanded: boolean) => { d.groupExpansion[key] = expanded },\n retainAccountKeys: (d, workspaceKeys: readonly string[]) => {\n const retained = new Set(workspaceKeys)\n d.groupExpansion = Object.fromEntries(\n Object.entries(d.groupExpansion).filter(([key]) => retained.has(key)),\n )\n d.sessionOrderByAccount = Object.fromEntries(\n Object.entries(d.sessionOrderByAccount).filter(([key]) => retained.has(key)),\n )\n delete (d as WorkspaceViewState & { sessionUpdatedAtByAccount?: unknown }).sessionUpdatedAtByAccount\n },\n syncSessionOrders: (d, orders) => {\n if (d.orderBy !== 'manual') return\n Object.assign(d.sessionOrderByAccount, copySessionOrders(orders))\n },\n setSessionOrder: (d, accountKey, order, initialOrders) => {\n if (d.orderBy === 'updated') d.sessionOrderByAccount = copySessionOrders(initialOrders)\n else Object.assign(d.sessionOrderByAccount, copySessionOrders(initialOrders))\n d.orderBy = 'manual'\n d.sessionOrderByAccount[accountKey] = [...order]\n },\n pinSessionOrder: (d, sessionId, accountKeys, source) => {\n const selected = new Set(accountKeys)\n d.sessionOrderByAccount = Object.fromEntries(Object.entries(source.members).map(([key, members]) => {\n const order = reconcileManualOrder(members, d.sessionOrderByAccount[key], source.summaries, source.rowState)\n return [key, selected.has(key) ? [sessionId, ...order.filter(id => id !== sessionId)] : order]\n }))\n },\n setArchivedFilter: (d, filter: ArchivedFilter) => { d.archivedFilter = filter },\n },\n })\n}\n\n/** The bound write set of one viewing-store instance (what the UiWorkspace service drives). */\nexport type WorkspaceViewStoreActions = ReturnType<ReturnType<typeof createWorkspaceViewStore>['create']>['actions']\n","/**\n * The complete account memberships a Pin order write reconciles against,\n * derived from the same Host snapshots the browser orders by, so the\n * UiWorkspace service can complete the write without the browser in the loop.\n */\nimport type { SessionListState } from '@deepseek-ai/dsh-api-session-controller/client'\nimport type { WorkspaceView } from '@deepseek-ai/dsh-api-workspace-controller/client'\nimport type { SessionId } from '@deepseek-ai/dsh-session/types'\nimport { FLAT_SESSION_ORDER_KEY } from './stores.ts'\nimport { owningGroupKey, sessionMemberIds, type SessionRowState, UNGROUPED_KEY } from './tree.ts'\n\n/** What `pinSessionOrder` reconciles a pinned Session's accounts against. */\nexport interface PinOrderSource {\n members: Readonly<Record<string, readonly SessionId[]>>\n summaries: SessionListState['byId']\n rowState: Pick<SessionRowState, 'pinnedSessionIds' | 'archivedSessionIds'>\n}\n\n/**\n * Every account's complete membership: each Workspace, Ungrouped, and the flat list.\n * @param workspaces - current Host Workspaces.\n * @param list - current Session list snapshot.\n * @param rowState - registry-global pin and archive sets.\n * @returns the order source for one pin write.\n */\nexport function pinOrderSource(\n workspaces: readonly WorkspaceView[],\n list: SessionListState,\n rowState: PinOrderSource['rowState'],\n): PinOrderSource {\n const accounted = new Set(workspaces.flatMap(workspace => workspace.sessionIds))\n return {\n members: Object.fromEntries([\n ...workspaces.map(workspace => [workspace.workspaceId, workspace.sessionIds] as const),\n [UNGROUPED_KEY, list.ids.filter(id => list.byId[id] !== undefined && !accounted.has(id))],\n [FLAT_SESSION_ORDER_KEY, sessionMemberIds(list)],\n ]),\n summaries: list.byId,\n rowState,\n }\n}\n\n/**\n * The accounts a pinned Session leads: its group (or Ungrouped) and the flat list.\n * @param workspaces - current Host Workspaces.\n * @param sessionId - the Session being pinned.\n * @returns the account keys `pinSessionOrder` fronts.\n */\nexport function pinOrderAccounts(workspaces: readonly WorkspaceView[], sessionId: SessionId): readonly string[] {\n return [owningGroupKey(workspaces, sessionId), FLAT_SESSION_ORDER_KEY]\n}\n","/** Workspace archive and directory UI capability. */\n\nimport { Service, type Context } from '@deepseek-ai/cordis'\nimport type { ClientRemote, DirectoryListing, RemoteFailure } from '@deepseek-ai/dsh-api-remotes/client'\nimport type {\n ISessions,\n SessionCreateError,\n SessionReference,\n SessionTarget,\n SessionListState,\n} from '@deepseek-ai/dsh-api-session-controller/client'\nimport { createSnapshotStore } from '@deepseek-ai/dsh-client-store'\nimport type { SubagentAddress } from '@deepseek-ai/dsh-subagent/client'\nimport type {\n IWorkspaces, WorkspaceId, WorkspaceSnapshot, WorkspaceView,\n} from '@deepseek-ai/dsh-api-workspace-controller/client'\nimport type { SessionId } from '@deepseek-ai/dsh-session/types'\nimport type {} from '@deepseek-ai/dsh-client-ui-layout/client'\nimport type { RowToast } from './contract/slots.ts'\nimport { pinOrderAccounts, pinOrderSource } from './pin-order.ts'\nimport type { WorkspaceViewStoreActions } from './stores.ts'\n\ninterface MainSelection {\n readonly sessionId?: SessionId\n readonly subagentAddress?: SubagentAddress\n}\n\n/** Workspace archive and directory operations consumed by Client UI domains. */\nexport interface UiWorkspace {\n /**\n * Select a Session and show its Conversation as one UI navigation action.\n * @param target - known Session identity or durable direct-parent subagent address to display.\n */\n openSession(target: SessionTarget): void\n /**\n * Connect a Workspace and open its Session unless a later navigation supersedes it.\n * @param workspaceId - target Workspace.\n * @param beforeOpen - optional synchronous preparation for the selected Session,\n * skipped after supersession; a throw aborts the open and releases the retained reference.\n * @returns completion; a superseded request may create a Session but does not open it.\n * @throws on failure; a refused creation is also shown through the Workspace\n * notice unless a later navigation or disposal superseded the request.\n */\n openWorkspace(workspaceId: WorkspaceId, beforeOpen?: (sessionId: SessionId) => void): Promise<void>\n /**\n * Fork a Session without changing the current selection.\n * @param sessionId - source Session.\n * @param onCreated - observer before the optional child-title update.\n * @returns the child SessionId after creation and inherited-title increment.\n */\n forkSession(sessionId: SessionId, onCreated?: (childId: SessionId) => void): Promise<SessionId>\n /**\n * Resolve the reusable or newly created blank Session for a Workspace.\n * @param workspaceId - target Workspace.\n * @returns a Session already addressable through the Session Controller.\n */\n connectWorkspace(workspaceId: WorkspaceId): Promise<SessionId>\n /**\n * Start a New Session flow and navigate to its Session; a creation the Host\n * refuses is shown through the Workspace notice and leaves the selection as it was.\n * @param workspaceId - explicit target; absent inherits the current or most recent Workspace.\n */\n startSession(workspaceId?: WorkspaceId): void\n /**\n * Archive a Session and clear it when it is the current selection.\n * @param sessionId - Session to archive.\n * @param options - `stopActivity` asks the Host to stop the Session's running work instead of refusing.\n */\n archiveSession(sessionId: SessionId, options?: { readonly stopActivity?: boolean }): Promise<void>\n /**\n * Unarchive a Session, restoring it to its recorded Workspace position.\n * @param sessionId - Session to unarchive.\n */\n unarchiveSession(sessionId: SessionId): Promise<void>\n /**\n * Pin a Session on the Host, then lead it in its accounts' saved orders\n * (its Workspace group or Ungrouped, and the flat list). The order write\n * reads the memberships current at completion, so reorders that landed\n * while the Host call was pending keep their positions.\n * @param sessionId - Session to pin.\n */\n pinSession(sessionId: SessionId): Promise<void>\n /**\n * Unpin a Session on the Host; saved positions stay as they are.\n * @param sessionId - Session to unpin.\n */\n unpinSession(sessionId: SessionId): Promise<void>\n /**\n * Open the Host-native directory picker.\n * @returns the selected directory, or null when cancelled.\n */\n pickDirectory(): Promise<string | null>\n /**\n * List one Host directory level.\n * @param path - directory path; absent selects the Host home.\n * @param signal - cancellation for a superseded scan.\n * @returns directory entries and breadcrumb ancestry.\n */\n listDirectory(path?: string, signal?: AbortSignal): Promise<DirectoryListing>\n /**\n * Create a child directory.\n * @param path - existing parent directory.\n * @param name - child directory name.\n * @returns created absolute path.\n */\n createDirectory(path: string, name: string): Promise<string>\n}\n\ndeclare module '@deepseek-ai/cordis' {\n interface Context {\n /** Cross-Controller Workspace navigation and directory UI capability. */\n uiWorkspace: UiWorkspace\n }\n}\n\n/** Structured directory failure exposed to directory UI consumers. */\nexport class DirectoryBrowseError extends Error {\n override readonly name = 'DirectoryBrowseError'\n\n /** @param rpcError - Host directory business failure. */\n constructor(readonly rpcError: RemoteFailure) {\n super(`directory browse failed: ${rpcError.code}: ${rpcError.message}`)\n }\n}\n\n/** Implements Workspace archive and directory UI operations. */\nclass UiWorkspaceService extends Service implements UiWorkspace {\n private readonly connecting = new Map<WorkspaceId, Promise<SessionId>>()\n private readonly lifetime = new AbortController()\n private readonly selection = createSnapshotStore<MainSelection>(\n {}, { persist: { name: 'dsh.sessions.current' } },\n )\n private mainReference: SessionReference | undefined\n\n /**\n * @param ctx - Client root Context.\n * @param directoryPicker - the directory-picking Remote namespace.\n * @param workspaces - pure Workspace Controller.\n * @param sessions - pure Session Controller.\n * @param view - the browser's viewing-store write set (one instance shared with its registration).\n * @param notify - show one notice through the Workspace notice channel.\n */\n constructor(\n ctx: Context,\n private readonly directoryPicker: ClientRemote['directoryPicker'],\n private readonly workspaces: IWorkspaces,\n private readonly sessions: ISessions,\n private readonly view: Pick<WorkspaceViewStoreActions, 'pinSessionOrder'>,\n private readonly notify: (toast: RowToast) => void,\n ) {\n super(ctx, 'uiWorkspace')\n ctx.effect(() => {\n const stop = this.watchNavigation()\n return () => {\n stop()\n this.lifetime.abort()\n const reference = this.mainReference\n this.mainReference = undefined\n reference?.release()\n }\n }, 'ui-workspace: Workspace navigation policy')\n }\n\n async connectWorkspace(workspaceId: WorkspaceId): Promise<SessionId> {\n const workspace = this.workspaces.list.getSnapshot().items\n .find(item => item.workspaceId === workspaceId)\n if (workspace === undefined) {\n throw new Error(`uiWorkspace.connectWorkspace: unknown workspace ${workspaceId}`)\n }\n const inflight = this.connecting.get(workspaceId)\n if (inflight !== undefined) return inflight\n\n const attempt = this.reuseOrCreateBlank(workspace)\n .finally(() => { this.connecting.delete(workspaceId) })\n this.connecting.set(workspaceId, attempt)\n return attempt\n }\n\n private reuseOrCreateBlank(workspace: WorkspaceView): Promise<SessionId> {\n const archived = this.workspaces.list.getSnapshot().archivedSessionIds\n const sessions = this.sessions.list.getSnapshot()\n for (const id of sessions.ids) {\n const summary = sessions.byId[id]\n if (summary === undefined || !summary.blank || summary.cwd !== workspace.path\n || !workspace.sessionIds.includes(id) || archived.includes(id)) continue\n return this.reuseBlank(workspace.workspaceId, id)\n }\n return this.sessions.create({ workspaceId: workspace.workspaceId })\n }\n\n private async reuseBlank(workspaceId: WorkspaceId, sessionId: SessionId): Promise<SessionId> {\n try {\n return await this.sessions.create({ workspaceId, sessionId })\n } catch (error: unknown) {\n if (sessionCreateErrorOf(error)?.rpcError.code !== 'session/writer-held') throw error\n return this.sessions.create({ workspaceId })\n }\n }\n\n openSession(target: SessionTarget): void {\n this.replaceMain(target, this.lifetime.signal, 'reveal')\n }\n\n async openWorkspace(workspaceId: WorkspaceId, beforeOpen?: (sessionId: SessionId) => void): Promise<void> {\n const navigation = AbortSignal.any([this.ctx.layout.beginNavigation(), this.lifetime.signal])\n let sessionId: SessionId\n try {\n sessionId = await this.connectWorkspace(workspaceId)\n } catch (error: unknown) {\n // Reported here, not in connectWorkspace: startup restoration calls that\n // directly and stays console-only.\n if (!navigation.aborted) this.notify({ kind: 'createFailed', message: creationFailureMessage(error) })\n throw error\n }\n if (navigation.aborted) return\n this.replaceMain(sessionId, navigation, 'reveal', beforeOpen)\n }\n\n async forkSession(sessionId: SessionId, onCreated?: (childId: SessionId) => void): Promise<SessionId> {\n return this.sessions.fork({ sessionId, increaseTitle: true, ...onCreated === undefined ? {} : { onCreated } })\n }\n\n startSession(workspaceId?: WorkspaceId): void {\n const workspace = this.workspaces.list.getSnapshot()\n const sessions = this.sessions.list.getSnapshot()\n const current = this.mainReference?.sessionId\n const currentWorkspaceId = current === undefined\n ? undefined\n : workspace.items.find(item => item.sessionIds.includes(current))?.workspaceId\n const recent = workspace.phase === 'ready' && sessions.phase === 'ready'\n ? recentWorkspace(workspace.items, sessions.byId)\n : undefined\n const target = workspaceId ?? currentWorkspaceId ?? recent\n if (target === undefined) {\n this.clearMain()\n return\n }\n void this.openWorkspace(target).catch(\n (reason: unknown) => { console.warn('new session failed:', reason) },\n )\n }\n\n async archiveSession(sessionId: SessionId, options: { readonly stopActivity?: boolean } = {}): Promise<void> {\n await this.workspaces.archiveSession(sessionId, options)\n if (this.mainReference?.sessionId === sessionId) this.clearMain()\n }\n\n async unarchiveSession(sessionId: SessionId): Promise<void> {\n await this.workspaces.unarchiveSession(sessionId)\n }\n\n async pinSession(sessionId: SessionId): Promise<void> {\n await this.workspaces.pinSession(sessionId)\n const { items, pinnedSessionIds, archivedSessionIds } = this.workspaces.list.getSnapshot()\n this.view.pinSessionOrder(\n sessionId,\n pinOrderAccounts(items, sessionId),\n pinOrderSource(items, this.sessions.list.getSnapshot(), { pinnedSessionIds, archivedSessionIds }),\n )\n }\n\n async unpinSession(sessionId: SessionId): Promise<void> {\n await this.workspaces.unpinSession(sessionId)\n }\n\n async pickDirectory(): Promise<string | null> {\n const result = await this.directoryPicker.pick()\n if (!result.ok) throw new Error(`directory picker failed: ${result.error.message}`)\n return result.value\n }\n\n async listDirectory(path?: string, signal?: AbortSignal): Promise<DirectoryListing> {\n const result = await this.directoryPicker.list(path, signal)\n if (!result.ok) throw new DirectoryBrowseError(result.error)\n return result.value\n }\n\n async createDirectory(path: string, name: string): Promise<string> {\n const result = await this.directoryPicker.createDirectory(path, name)\n if (!result.ok) throw new DirectoryBrowseError(result.error)\n return result.value\n }\n\n private watchNavigation(): () => void {\n let initial: 'waiting' | 'connecting' | 'done' = 'waiting'\n const reconcile = (): void => {\n if (this.lifetime.signal.aborted) return\n if (this.clearArchivedCurrent()) return\n if (initial !== 'waiting') return\n const workspace = this.workspaces.list.getSnapshot()\n const sessions = this.sessions.list.getSnapshot()\n if (workspace.phase !== 'ready' || sessions.phase !== 'ready') return\n if (this.mainReference !== undefined) {\n initial = 'done'\n return\n }\n initial = 'connecting'\n void this.restoreSelection(workspace, sessions).then(\n () => { initial = 'done' },\n (reason: unknown) => {\n if (this.lifetime.signal.aborted) return\n initial = 'waiting'\n console.warn('initial Session restoration failed:', reason)\n },\n )\n }\n\n const disposeWorkspaces = this.workspaces.list.subscribe(reconcile)\n const disposeSessions = this.sessions.list.subscribe(reconcile)\n reconcile()\n return () => {\n this.lifetime.abort()\n disposeSessions()\n disposeWorkspaces()\n }\n }\n\n private async restoreSelection(workspaces: WorkspaceSnapshot, sessions: SessionListState): Promise<void> {\n const saved = this.selection.getSnapshot()\n if (saved.subagentAddress !== undefined) {\n this.replaceMain(saved.subagentAddress, this.lifetime.signal, 'preserve')\n return\n }\n const summary = saved.sessionId === undefined ? undefined : sessions.byId[saved.sessionId]\n const workspace = summary === undefined ? undefined\n : workspaces.items.find(item => item.sessionIds.includes(summary.id))\n if (summary !== undefined && (!summary.blank || workspace === undefined)) {\n this.replaceMain(summary.id, this.lifetime.signal, 'preserve')\n return\n }\n const navigation = AbortSignal.any([this.ctx.layout.beginNavigation(), this.lifetime.signal])\n let sessionId: SessionId | undefined\n if (summary !== undefined && workspace !== undefined && summary.cwd === workspace.path\n && !workspaces.archivedSessionIds.includes(summary.id)) {\n sessionId = await this.reuseBlank(workspace.workspaceId, summary.id)\n }\n let target = workspace?.workspaceId ?? recentWorkspace(workspaces.items, sessions.byId)\n if (target === undefined && workspaces.items.length === 0 && sessions.ids.length === 0) {\n const prepared = await this.initializeDefaultWorkspace(navigation)\n if (navigation.aborted) return\n target = prepared?.workspaceId\n }\n if (sessionId === undefined && target !== undefined) sessionId = await this.connectWorkspace(target)\n if (sessionId !== undefined && !navigation.aborted) {\n this.replaceMain(sessionId, navigation, 'preserve')\n }\n }\n\n private async initializeDefaultWorkspace(signal: AbortSignal): Promise<WorkspaceView | undefined> {\n try {\n return await this.workspaces.initializeDefault(signal)\n } catch (_error: unknown) {\n if (!signal.aborted) this.notify({ kind: 'defaultWorkspaceFailed' })\n return undefined\n }\n }\n\n /** @returns true when an archived current selection was cleared. */\n private clearArchivedCurrent(): boolean {\n const current = this.mainReference?.sessionId\n if (current === undefined\n || !this.workspaces.list.getSnapshot().archivedSessionIds.includes(current)) return false\n this.clearMain()\n return true\n }\n\n private clearMain(): void {\n const previous = this.mainReference\n this.mainReference = undefined\n this.selection.set({})\n previous?.release()\n this.ctx.layout.selectPanel(null)\n }\n\n private replaceMain(\n target: SessionTarget,\n signal: AbortSignal,\n panel: 'reveal' | 'preserve',\n beforeOpen?: (sessionId: SessionId) => void,\n ): void {\n signal.throwIfAborted()\n const reference = this.sessions.retain(target, { source: 'mainView' })\n try {\n signal.throwIfAborted()\n beforeOpen?.(reference.sessionId)\n if (signal.aborted) {\n reference.release()\n return\n }\n const subagentAddress = typeof target === 'string'\n ? this.sessions.subagentAddress(reference.sessionId)\n : target\n this.selection.set({\n sessionId: reference.sessionId,\n ...(subagentAddress === undefined ? {} : { subagentAddress }),\n })\n } catch (error: unknown) {\n reference.release()\n throw error\n }\n const previous = this.mainReference\n this.mainReference = reference\n previous?.release()\n if (panel === 'reveal') this.ctx.layout.selectPanel(null)\n }\n\n}\n\n/**\n * `error` as the Session Controller's creation failure, or undefined when it\n * is not one. Client plugin bundles do not share error-class identity, so the\n * name decides.\n */\nfunction sessionCreateErrorOf(error: unknown): SessionCreateError | undefined {\n return error instanceof Error && error.name === 'SessionCreateError' ? error as SessionCreateError : undefined\n}\n\n/**\n * The words a failed Session creation is reported in: a Host refusal keeps its\n * stable code and message; any other failure keeps its own message.\n */\nfunction creationFailureMessage(error: unknown): string {\n const refused = sessionCreateErrorOf(error)\n if (refused !== undefined) return `${refused.rpcError.code}: ${refused.rpcError.message}`\n return error instanceof Error ? error.message : String(error)\n}\n\n/** Stable tie-breaking follows Host Workspace order. */\nfunction recentWorkspace(\n workspaces: readonly WorkspaceView[],\n sessions: SessionListState['byId'],\n): WorkspaceId | undefined {\n let selected: WorkspaceId | undefined\n let selectedTime = Number.NEGATIVE_INFINITY\n for (const workspace of workspaces) {\n let latest = Number.NEGATIVE_INFINITY\n for (const sessionId of workspace.sessionIds) {\n const session = sessions[sessionId]\n if (session !== undefined) latest = Math.max(latest, session.updatedAt)\n }\n if (latest === Number.NEGATIVE_INFINITY) latest = Date.parse(workspace.createdAt)\n if (selected === undefined || latest > selectedTime) {\n selected = workspace.workspaceId\n selectedTime = latest\n }\n }\n return selected\n}\n\nexport { UiWorkspaceService }\n","function r(e){var t,f,n=\"\";if(\"string\"==typeof e||\"number\"==typeof e)n+=e;else if(\"object\"==typeof e)if(Array.isArray(e)){var o=e.length;for(t=0;t<o;t++)e[t]&&(f=r(e[t]))&&(n&&(n+=\" \"),n+=f)}else for(f in e)e[f]&&(n&&(n+=\" \"),n+=f);return n}export function clsx(){for(var e,t,f=0,n=\"\",o=arguments.length;f<o;f++)(e=arguments[f])&&(t=r(e))&&(n&&(n+=\" \"),n+=t);return n}export default clsx;","/**\n * Fixed first-use Workspace naming, shared by the Host that creates the\n * directory and by browser consumers that label the resulting row. A pure fold\n * with no imports, so client bundles inline it instead of requesting a\n * module-table row this package does not publish.\n * @module @deepseek-ai/dsh-api-workspace-controller/default-workspace\n */\n/**\n * Leaf directory name of the first-use Workspace under\n * `<Documents>/deepseek-harness`. Language-neutral, so one installation keeps\n * one on-disk path across language switches. The registry derives the initial\n * title from this same segment, which is the title\n * {@link workspaceDisplayTitle} recognizes as automatic.\n */\nexport const DEFAULT_WORKSPACE_DIRECTORY = 'default-workspace';\n/**\n * The text one Workspace is labeled with. A Workspace still carrying the\n * automatic first-use title reads as the caller's localized default name; every\n * other title reads verbatim in every language. A title the user typed as\n * exactly {@link DEFAULT_WORKSPACE_DIRECTORY} is labeled as the default too;\n * nothing else depends on the distinction.\n * @param title - stored Workspace title.\n * @param localizedDefault - the default Workspace name in the active language.\n * @returns the title to display.\n */\nexport function workspaceDisplayTitle(title, localizedDefault) {\n return title === DEFAULT_WORKSPACE_DIRECTORY ? localizedDefault : title;\n}\n//# sourceMappingURL=default-workspace.js.map","/**\n * Fork-owned: aggregated live-status computation for collapsed workspace groups.\n *\n * Extracted from `tree.ts` so the upstream diff surface is minimal — the\n * vendored file only needs one import line and one field assignment to wire\n * the badge aggregation in. Everything fork-specific lives here.\n *\n * ## 本模块不认识任何具体状态源\n *\n * 它只统计宿主自己的行级事实(进行中 / 待审批 / 计划待审 / 等待回答 / 已完成 /\n * 子智能体);外部状态一律经 `./facets.ts` 的协议折成 {@link FacetFold}。\n *\n * 这不是洁癖:此前这里为定时任务与等待评审各写了一组具名字段和一套查表,于是提供方\n * 新增字段时本插件的本地类型一无所知,信息**静默丢失**(不报错、测试也不红,见\n * CHANGELOG 0.2.3 第一条)。把语义留在拥有它的那一侧,这类漂移才结构上不可能发生。\n *\n * @module\n */\nimport type { AnyFacet, AnyFacetFold, RegisteredFacet } from './facets.ts'\nimport { defaultMergeFold } from './facets.ts'\nimport type { GroupNode, SessionNode } from './tree.ts'\n\n// ── Aggregated status ──\n\n/**\n * Aggregated live-session counts for one group, computed over all members so a\n * folded folder row can hint at hidden activity.\n */\nexport interface GroupLiveStatus {\n /** Members currently running. */\n running: number\n /** Members awaiting tool approval. */\n approval: number\n /** Members awaiting plan review. */\n planReview: number\n /** Members awaiting a question answer. */\n question: number\n /** Members finished and not yet opened (the green \"done\" reminder). */\n done: number\n /** Running direct children across members. */\n subagents: number\n /**\n * 外部状态源的折果,按 facet id 索引,只含**有贡献**的来源(`count > 0`)。\n *\n * 这里刻意没有 `scheduled*` / `waitingReview*` 这类具名字段:徽标一旦为某个来源开\n * 一个字段,就等于把别人家的语义焊进自己的类型,新增来源就得改本插件。\n * `FacetFold.data` 的形状只有该来源自己读。\n */\n facets: ReadonlyMap<string, FacetEntry>\n}\n\n/**\n * 一个来源在**这一组**上的折果,连同它自己的 facet。\n *\n * 带上 facet 是为了让渲染(文案、图标、脉冲)与多层合并(`facet.merge`)都不必再回\n * 登记面查表——也就不需要任何模块级状态。\n */\nexport interface FacetEntry {\n facet: AnyFacet\n fold: AnyFacetFold\n}\n\n/** 空折果表:让哨兵的引用跨渲染稳定。 */\nconst EMPTY_FACETS: ReadonlyMap<string, FacetEntry> = new Map()\n\n/**\n * Zero-valued sentinel for {@link GroupLiveStatus}.\n *\n * Used when a group has nothing to report. Kept as a frozen constant so the\n * reference is stable across renders — `Object.is` comparisons in React selectors\n * never trigger spurious re-renders on it.\n */\nexport const EMPTY_LIVE_STATUS: GroupLiveStatus = Object.freeze({\n running: 0, approval: 0, planReview: 0, question: 0, done: 0, subagents: 0,\n facets: EMPTY_FACETS,\n}) as GroupLiveStatus\n\n/**\n * 合并两份分组折果:本插件自己的计数相加,外部状态来源**按 facet 各自合并**。\n *\n * 用于多层聚合:折叠的父文件夹要覆盖整棵子树,而子树里每一层都已各自折过一遍。\n * `FacetFold.data` 怎么合归该 facet 自己决定,本模块从不解释。\n */\nexport function mergeLiveStatus(a: GroupLiveStatus, b: GroupLiveStatus): GroupLiveStatus {\n return {\n running: a.running + b.running,\n approval: a.approval + b.approval,\n planReview: a.planReview + b.planReview,\n question: a.question + b.question,\n done: a.done + b.done,\n subagents: a.subagents + b.subagents,\n facets: mergeFacets(a.facets, b.facets),\n }\n}\n\n/** 按 facet id 合并两侧折果;只有一侧有的来源原样带过。 */\nfunction mergeFacets(\n a: ReadonlyMap<string, FacetEntry>,\n b: ReadonlyMap<string, FacetEntry>,\n): ReadonlyMap<string, FacetEntry> {\n if (a.size === 0) return b\n if (b.size === 0) return a\n const merged = new Map<string, FacetEntry>(a)\n for (const [id, entry] of b) {\n const own = merged.get(id)\n // 合并规则由该来源自己声明;缺省只加数量、取更紧急的色档、脉冲取或。\n // 合并后仍沿用先登记那一份的 facet 引用:两侧本就是同一个来源。\n merged.set(id, own === undefined\n ? entry\n : { facet: own.facet, fold: own.facet.merge?.(own.fold, entry.fold) ?? defaultMergeFold(own.fold, entry.fold) })\n }\n return merged\n}\n\n// ── Main computation ──\n\n/**\n * Fold every member row of a group into counts so a collapsed folder can hint at\n * hidden live sessions. Mirrors the session-row status priority (pending\n * outranks running outranks completed) at the counting level; labels resolve with\n * locale at render time.\n *\n * @param nodes - member rows of the group.\n * @param sessionIds - the same members' Session ids (facets address their own data by id).\n * @param facets - the registered status sources to fold over this group.\n * @param now - one clock reading for the whole pass, so sibling facets cannot disagree\n * about which deadlines are still ahead.\n */\nexport function summarizeGroupStatus(\n nodes: readonly SessionNode[],\n sessionIds: readonly string[],\n facets: readonly RegisteredFacet[] = [],\n now: number = Date.now(),\n): GroupLiveStatus {\n let running = 0\n let approval = 0\n let planReview = 0\n let question = 0\n let done = 0\n let subagents = 0\n // #25②:这一段曾与 `rows/Rows.tsx` 的 `sessionStatuses()` 各写一份优先级,两处结果不同\n // (pending 会话漏算子智能体;未运行但已完成 + 有运行中子智能体时两处判断相反)。计数\n // 判据仍在本模块(徽标只需要五个数字),但**语义以行内为准**:行内 pending 会同时给出\n // subagents,未运行且有 subagents 时不承认 completed。下面的分支刻意照抄那两条规则,\n // 不是另立一套「徽标自己的优先级」。\n for (const n of nodes) {\n if (n.blank || n.archived) continue\n const hasSubagents = n.runningSubagentCount > 0\n // 行内:pending 与 subagents 可并存(Rows.tsx `[pending, subagents]`),故不 `continue`。\n if (n.pendingInteraction === 'approval') { approval += 1; subagents += n.runningSubagentCount; continue }\n if (n.pendingInteraction === 'plan-review') { planReview += 1; subagents += n.runningSubagentCount; continue }\n if (n.pendingInteraction === 'question') { question += 1; subagents += n.runningSubagentCount; continue }\n if (n.running) { running += 1; subagents += n.runningSubagentCount; continue }\n // 行内:subagents 优先于 completed(`if (subagents !== undefined) return [subagents]`)。\n if (hasSubagents) { subagents += n.runningSubagentCount; continue }\n if (n.completed) done += 1\n }\n\n // 外部来源逐个折。一个来源坏了不该带塌整只徽标:快照读失败按「此刻没有数据」处理,\n // 折叠抛错则跳过该来源——两者都不往渲染管线里扩散。\n const folded = new Map<string, FacetEntry>()\n for (const { facet } of facets) {\n let snapshot: unknown\n try {\n snapshot = facet.getSnapshot()\n } catch {\n snapshot = undefined\n }\n try {\n const result = facet.fold(snapshot, sessionIds, now)\n // `count <= 0` 的来源不进表:数字、图标、文案、显隐判定都当它不存在。\n if (result !== undefined && result.count > 0) folded.set(facet.id, { facet, fold: result })\n } catch {\n /* 同上:这个来源此刻不参与徽标 */\n }\n }\n\n return { running, approval, planReview, question, done, subagents, facets: folded }\n}\n\n/**\n * Measure each group's own members, as the input to {@link aggregateGroupStatuses}.\n *\n * Every group is measured, expanded ones included. A folder row shows no badge while\n * it is expanded, but its sessions still need attention and a collapsed ancestor must\n * keep counting them — so expansion is a rendering fact, never an input to the\n * aggregation. Short-circuiting expanded groups to `EMPTY_LIVE_STATUS` (the shape this\n * had before the tree-wide aggregator existed, harmless while nothing aggregated) makes\n * every collapsed parent undercount by the size of its expanded descendants.\n *\n * @param groups - derived groups, each with its member rows already populated.\n * @param facets - registered sources, already filtered by the visibility settings.\n * @param now - one clock reading shared by every group in the pass.\n */\nexport function directStatusesForGroups(\n groups: readonly { key: string; sessions: readonly SessionNode[] }[],\n facets: readonly RegisteredFacet[] = [],\n now: number = Date.now(),\n): Map<string, GroupLiveStatus> {\n const map = new Map<string, GroupLiveStatus>()\n for (const group of groups) {\n map.set(group.key, summarizeGroupStatus(\n group.sessions, group.sessions.map(s => s.id), facets, now,\n ))\n }\n return map\n}\n\n/**\n * Fold every group's DIRECT status up the workspace tree, so a collapsed folder\n * counts every descendant session. A group's own row shows no badge while it is\n * expanded, but its sessions still need attention and its collapsed ancestor must\n * keep counting them — so the walk never depends on a group's expanded state.\n *\n * @param direct - each group's own-member status, keyed by group key.\n * @param childrenByParent - the rendered tree: parent key (`undefined` = roots) → children.\n * @returns aggregated status per group key: own members plus the whole subtree.\n */\nexport function aggregateGroupStatuses(\n direct: ReadonlyMap<string, GroupLiveStatus>,\n childrenByParent: ReadonlyMap<string | undefined, readonly { key: string }[]>,\n): Map<string, GroupLiveStatus> {\n const aggregated = new Map<string, GroupLiveStatus>()\n // Parentage comes from path-prefix matching, so a self- or mutual-parent edge is\n // representable; without this guard the fold would recurse forever and hang the sidebar.\n const visiting = new Set<string>()\n const fold = (key: string): GroupLiveStatus => {\n const cached = aggregated.get(key)\n if (cached !== undefined) return cached\n if (visiting.has(key)) return direct.get(key) ?? EMPTY_LIVE_STATUS\n visiting.add(key)\n let total = direct.get(key) ?? EMPTY_LIVE_STATUS\n for (const child of childrenByParent.get(key) ?? []) {\n total = mergeLiveStatus(total, fold(child.key))\n }\n visiting.delete(key)\n aggregated.set(key, total)\n return total\n }\n // Every listed child is folded, not just the roots: an unreachable group would\n // otherwise be missing from the map and lose its badge.\n for (const children of childrenByParent.values()) {\n for (const child of children) fold(child.key)\n }\n return aggregated\n}\n\n/**\n * A group row whose badge input is resolved: its own members plus its whole subtree.\n *\n * `GroupNode.liveStatus` is optional only because upstream never fills it — this\n * package's aggregator is the sole producer. Typing a rendered row as\n * `StatusedGroupNode` is what turns \"a row that skipped the aggregator\" into a compile\n * error instead of a folder that silently lost its badge, which is how the PR #10\n * regression reached main.\n */\nexport interface StatusedGroupNode extends GroupNode {\n liveStatus: GroupLiveStatus\n}\n\n/**\n * Attach each group's subtree-wide status, in derivation order. This is the producer\n * the sidebar renders from.\n *\n * Expanded groups carry their status too: their own row draws no badge (a decision\n * inside `groupLiveBadge`), but a collapsed ancestor still has to count them, so\n * expansion never suppresses the measurement.\n *\n * @param groups - derived rows, in the order they render.\n * @param direct - each group's own-member status, from {@link directStatusesForGroups}.\n * @param childrenByParent - the rendered tree: parent key (`undefined` = roots) → children.\n */\nexport function withAggregatedStatus(\n groups: readonly GroupNode[],\n direct: ReadonlyMap<string, GroupLiveStatus>,\n childrenByParent: ReadonlyMap<string | undefined, readonly GroupNode[]>,\n): StatusedGroupNode[] {\n const aggregated = aggregateGroupStatuses(direct, childrenByParent)\n // A group missing from the fold has neither measured members nor listed children,\n // so it is idle rather than unknown.\n return groups.map(group => ({ ...group, liveStatus: aggregated.get(group.key) ?? EMPTY_LIVE_STATUS }))\n}\n","/**\n * 按用户设置筛掉不参与折叠的状态来源。\n *\n * 单独成文是因为它属于**徽标自身**的可见性规则,而不是某个来源的适配:来源只在\n * `facet.settingKey` 上声明\"我受哪个开关管\",开关的语义与过滤时机归本插件。\n *\n * 过滤发生在**折叠之前**而不是渲染阶段:徽标数字、图标、`aria-label`、悬停明细与\n * \"要不要画徽标\"因此天然同源。放到渲染阶段会出现\"label 里有、计数里没有\",而那正是\n * 徽标最容易被怀疑撒谎的地方。\n *\n * @module dsh-group-status/client/facet-visibility\n */\nimport { facetVisibleBySettings, type ResolvedBadgeSettings } from './badge-settings.ts'\nimport type { RegisteredFacet } from './facets.ts'\n\n/** 筛出设置允许显示的登记项;顺序保持登记面的顺序(已按 `order` 排好)。 */\nexport function visibleFacets(\n entries: readonly RegisteredFacet[],\n settings: ResolvedBadgeSettings,\n): RegisteredFacet[] {\n return entries.filter(entry => facetVisibleBySettings(settings, entry.facet.settingKey))\n}\n","/**\n * Fork-owned: the **wording** of a folded group's aggregated status.\n *\n * Split out of `rows/GroupBadge.tsx` for one concrete reason: that file imports the\n * host icon set, and a published `…/client` bundle's `require` graph only resolves\n * inside the DSH app (see `vitest.config.ts`, exclusion reason (b)). Keeping these\n * functions free of runtime imports is what lets the badge behaviour be tested at all\n * instead of being asserted by a screenshot nobody re-runs.\n *\n * 本模块**不认识任何具体状态源**:外部状态一律经 `./facets.ts` 的协议进来,文案、图标、\n * 脉冲都由该状态的所有者声明,本模块只管排布顺序与分隔符。\n *\n * @module\n */\nimport type { ReactNode } from 'react'\nimport type { WorkspaceBrowserProps } from './contract/slots.ts'\nimport type { FacetEntry, GroupLiveStatus } from './group-status.ts'\nimport type { ResolvedBadgeSettings } from './badge-settings.ts'\n\n/** The standard locale seat, prop-passed from the browser root (type-only import). */\ntype RowTranslate = WorkspaceBrowserProps['t']\n\n/** 一条悬停明细:一个状态点(或来源自己的图标)加它的文案。 */\nexport interface HoverStatusLine {\n state: 'warning' | 'ongoing' | 'done'\n text: string\n /** #24:来源自己交的图标(已含色档)。宿主会话状态没有它,仍用三档 `StateDot`。 */\n glyph?: ReactNode\n}\n\n/**\n * 把侧栏行的翻译位交给 facet。\n *\n * 这里有一次**故意的放宽**:协议的 `t` 收任意字符串键,而行位只收本插件 `workspace`\n * 命名空间的键。放宽是安全的——宿主 locale 服务对未注册的键一律**原样回显键名**(不是\n * 抛错),所以外来 facet 传了自己命名空间的键,最坏读出的是那串键名而不是崩渲染。\n * 要正确本地化,provider 应当闭包自己的翻译函数、忽略这里传入的 `t`。\n */\nfunction asFacetTranslate(t: RowTranslate): (key: string, options?: Record<string, string | number>) => string {\n return (key, options) => t(key as never, options as never)\n}\n\n/** 该 facet 贡献进徽标数字的条数。 */\nexport function facetCountTotal(s: GroupLiveStatus): number {\n let total = 0\n for (const entry of s.facets.values()) total += entry.fold.count\n return total\n}\n\n/**\n * 每个外部状态来源的那句话,按登记顺序。\n *\n * facet 没实现 `label` 时**不能**退化成 `2 dsh-later.schedule` 这种读法,所以给一句\n * 通用措辞兜底:只说有几个来源在响,具体语义等该来源自己补文案。\n */\nexport function facetLines(s: GroupLiveStatus, t: RowTranslate, now: number): string[] {\n const translate = asFacetTranslate(t)\n const lines: string[] = []\n for (const entry of s.facets.values()) {\n const text = entry.facet.label?.(entry.fold, { now, t: translate })\n lines.push(text === undefined || text === '' ? `${entry.fold.count} ${t('status.needsAttention')}` : text)\n }\n return lines\n}\n\n/**\n * Accessible label for a folded group's aggregated status, reusing the\n * session-row locale keys so both surfaces read identically.\n *\n * 按设置过滤:**关掉的外部来源根本不在折果里**(`WorkspaceBrowser` 折叠前就按\n * `facet.settingKey` 过滤了登记面),所以这里不必再判设置,`aria-label` 与徽标视觉\n * 天然一致;宿主的行级状态仍按设置逐项过滤。\n */\nexport function groupLiveLabel(\n s: GroupLiveStatus,\n t: RowTranslate,\n settings: ResolvedBadgeSettings,\n now: number = Date.now(),\n): string {\n const parts: string[] = []\n if (settings.showPendingInBadge) {\n if (s.approval > 0) parts.push(`${s.approval} ${t('status.waitingApproval')}`)\n if (s.planReview > 0) parts.push(`${s.planReview} ${t('status.planReview')}`)\n if (s.question > 0) parts.push(`${s.question} ${t('status.waitingAnswer')}`)\n }\n if (settings.showRunningInBadge) {\n if (s.running > 0) parts.push(`${s.running} ${t('status.running')}`)\n if (s.subagents > 0) {\n parts.push(t(s.subagents === 1 ? 'status.subagentsRunning.one' : 'status.subagentsRunning.other', { n: s.subagents }))\n }\n }\n parts.push(...facetLines(s, t, now))\n if (settings.showCompletedInBadge && s.done > 0) parts.push(`${s.done} ${t('status.completed')}`)\n return parts.join(' · ')\n}\n\n/**\n * 每个外部状态来源的明细行,**带它自己的图标**(#24)。\n *\n * 徽标侧画的是 provider 交出的、已含色档的元素(`rows/GroupBadge.tsx` 的 `facetGlyph`),\n * 明细侧此前只画一个统一的 `StateDot`,于是同一条状态、同一次悬停里,徽标是红色沙漏、\n * 明细是黄点——同一行的两个视图各说一套。宿主 `StateDot` 只有 warning / ongoing / done\n * 三档、没有 error 档,所以色档**只能**由来源自己的图标表达,这也是本函数存在的理由。\n *\n * provider 没交图标时退回通用点(与徽标侧同一套兜底),陌生来源仍然可见。\n *\n * @returns 明细行;`glyph` 为 `undefined` 表示该行用 `StateDot` 渲染。\n */\nexport function facetDetailLines(s: GroupLiveStatus, t: RowTranslate, now: number): HoverStatusLine[] {\n const translate = asFacetTranslate(t)\n const lines: HoverStatusLine[] = []\n for (const entry of s.facets.values()) {\n const raw = entry.facet.label?.(entry.fold, { now, t: translate })\n const text = raw === undefined || raw === '' ? `${entry.fold.count} ${t('status.needsAttention')}` : raw\n lines.push({ state: 'warning', text, glyph: facetGlyph(entry, t, now) })\n }\n return lines\n}\n\n/**\n * Build the status detail lines for the workspace hover card.\n *\n * Extracted so `WorkspaceHoverContent` in `Rows.tsx` only needs to map the returned\n * array — the fork-specific status→line logic lives here.\n *\n * 按设置过滤:关掉的来源不出现在明细行里;`showHoverDetails=false` 时整段返回空。\n * 明细行的顺序与徽标**完全一致**(外部来源排在会话状态之后、已完成之前):两处顺序\n * 不一样会让人怀疑它们是两套事实。\n */\nexport function hoverStatusLines(\n status: GroupLiveStatus | undefined,\n t: RowTranslate,\n settings: ResolvedBadgeSettings,\n now: number = Date.now(),\n): HoverStatusLine[] {\n const lines: HoverStatusLine[] = []\n if (status === undefined || !settings.showHoverDetails) return lines\n if (settings.showPendingInBadge) {\n if (status.approval > 0) lines.push({ state: 'warning', text: `${status.approval} ${t('status.waitingApproval')}` })\n if (status.planReview > 0) lines.push({ state: 'warning', text: `${status.planReview} ${t('status.planReview')}` })\n if (status.question > 0) lines.push({ state: 'warning', text: `${status.question} ${t('status.waitingAnswer')}` })\n }\n if (settings.showRunningInBadge) {\n if (status.running > 0) lines.push({ state: 'ongoing', text: `${status.running} ${t('status.running')}` })\n if (status.subagents > 0) {\n lines.push({\n state: 'ongoing',\n text: t(status.subagents === 1 ? 'status.subagentsRunning.one' : 'status.subagentsRunning.other', { n: status.subagents }),\n })\n }\n }\n // #24:外部来源的明细行改用来源自己的图标(已含色档),与徽标同源。宿主的三档点仍用在\n // 宿主会话状态上——那些档位本就是宿主的语义,色档无处可失。\n lines.push(...facetDetailLines(status, t, now))\n if (settings.showCompletedInBadge && status.done > 0) lines.push({ state: 'done', text: `${status.done} ${t('status.completed')}` })\n return lines\n}\n\n/**\n * 某一条外部来源的元素该带哪只 class(#22)。\n *\n * 脉冲判据仍由各 facet 自己声明(`FacetFold.pulse`),但**作用对象必须下沉到声明它的那个\n * 元素**。此前 `groupBadgeIsUrgent()` 只返回一个整徽标的布尔值、class 加在容器上,于是同组\n * 里任何一家声明 `pulse: true` 都会让别家本该静止的图标跟着呼吸:`pulse: false` 是否生效,\n * 取决于同组里恰好有没有别人开了闪。判断交出去了,作用对象没交出去——这是修过一次的回归\n * (见下)。\n *\n * 保留这条历史的原因写在所有者那边:dsh-gitea-dispatch 把 `overdue` 画成**静止**(其\n * `lib/waiting-glyph.js`:「超时后停动画:静止即不再期待」),且它只代表 CI 窗口到期、\n * 不代表评审失败。同一条等待在行内静止、在父级闪动,就是同一事实的两种说法。\n */\nexport function facetPulseClass(entry: FacetEntry, urgentClass: string): string | undefined {\n return entry.fold.pulse ? urgentClass : undefined\n}\n\n/**\n * 一个来源的图标。\n *\n * 归 provider 画(`facet.renderIcon`):「这个状态长什么样」是它的知识。没实现时本插件\n * 按色档退回一个通用点(见 `rows/GroupBadge.tsx`),保证陌生来源仍然可见、只是朴素。\n */\nexport function facetGlyph(entry: FacetEntry, t: RowTranslate, now: number): ReactNode {\n return entry.facet.renderIcon?.(entry.fold, { now, t: asFacetTranslate(t) })\n}\n","/**\n * Fork-owned: aggregated status badge for collapsed workspace groups.\n *\n * Extracted from `Rows.tsx` so the upstream diff surface is minimal — the\n * vendored file only needs one import and one `<GroupBadge />` call to wire\n * the badge in. Everything fork-specific lives here.\n *\n * The **wording** lives in `../badge-labels.ts`: this file imports the host icon set,\n * whose `require` graph only resolves inside the DSH app, so anything kept here is\n * untestable in this repository.\n *\n * 本文件也**不为任何具体状态源写分支**:外部来源的图标、色档、脉冲、文案都随 facet\n * 一起进来,这里只按登记顺序把它们排进徽标。\n *\n * @module\n */\nimport type { ReactNode } from 'react'\nimport { StateDot } from '@deepseek-ai/dsh-client-ui-primitives'\nimport type { WorkspaceBrowserProps } from '../contract/slots.ts'\nimport type { GroupNode } from '../tree.ts'\nimport type { ResolvedBadgeSettings } from '../badge-settings.ts'\nimport { facetCountTotal, facetGlyph, facetPulseClass, groupLiveLabel } from '../badge-labels.ts'\nimport css from './Rows.module.css'\n\nexport { facetCountTotal, facetGlyph, facetPulseClass, groupLiveLabel, hoverStatusLines } from '../badge-labels.ts'\n\n/** The standard locale seat, prop-passed from the browser root. */\ntype RowTranslate = WorkspaceBrowserProps['t']\n\n// ── Badge ──\n\n/**\n * Aggregated live-status badge for a folded folder row. Dots reuse StateDot so\n * colors match session rows (warning = pending, ongoing = running, done = completed).\n * Renders nothing while expanded or when nothing is pending/active/completed or any\n * status source reports a contribution.\n *\n * Count matches the dots: host-side sessions plus every registered facet's own count.\n *\n * `settings` 按来源过滤:关掉的来源不画点、不计数、不进 aria-label、不参与「是否显示\n * 徽标」的判断。会话行自身的状态点不受影响:那是行级状态,不是分组提示。**外部**来源的\n * 过滤发生在折叠之前(`WorkspaceBrowser` 按 `facet.settingKey` 筛登记面),所以到这里\n * 的折果已经是\"该显示的\",label 与视觉不可能各说一套。\n *\n * `now` 缺省取渲染时刻(与 `WorkspaceBrowser` 为相对时间读的时钟同一姿态):文案里的\n * 剩余时长以此计算,只在提供方 store 通知时随渲染更新。\n */\nexport function groupLiveBadge(\n group: GroupNode,\n t: RowTranslate,\n settings: ResolvedBadgeSettings,\n now: number = Date.now(),\n): ReactNode {\n const s = group.liveStatus\n if (group.expanded || s === undefined) return null\n const pending = settings.showPendingInBadge ? s.approval + s.planReview + s.question : 0\n const active = settings.showRunningInBadge ? s.running + s.subagents : 0\n const completed = settings.showCompletedInBadge ? s.done : 0\n const facetTotal = facetCountTotal(s)\n // 只在有 pending / active / 已完成 / 任一外部来源有贡献时显示徽标\n if (pending === 0 && active === 0 && completed === 0 && facetTotal === 0) return null\n const label = groupLiveLabel(s, t, settings, now)\n const dots: ReactNode[] = []\n if (pending > 0) dots.push(<StateDot key=\"warn\" state=\"warning\" />)\n if (active > 0) dots.push(<StateDot key=\"run\" state=\"ongoing\" />)\n // #25①:点行顺序此前是 pending → active → **done** → facet,而明细(`hoverStatusLines`)\n // 是 pending → active → **facet** → done,两处相反;而 `badge-labels.ts` 的注释声称两者\n // 「完全一致」,括号里写的还正是明细那一种。此处按明细对齐(facet 排在 done 之前),\n // 注释与实现从此同一条来源。\n // 外部来源的相对次序由 facet.order 决定(谁更该被看见,来源自己排)。\n // CSS module 的类型把 class 声明为可能 undefined,这里只在真的闪时才求值。\n const urgentClass = css.groupBadgeUrgent ?? ''\n for (const entry of s.facets.values()) {\n const glyph = facetGlyph(entry, t, now)\n const pulseClass = facetPulseClass(entry, urgentClass) || undefined\n dots.push(glyph === undefined\n // provider 没画图标时退回通用点:陌生来源仍然可见,只是朴素。宿主只有三档状态点,\n // 没有 error 档,所以 info 之外的色档都落到 warning 点上。\n ? <StateDot key={entry.facet.id} state={entry.fold.tone === 'info' ? 'ongoing' : 'warning'} />\n // #22:脉冲 class 加在**这一枚元素**上,不是整只徽标。同组里别家开闪不该让\n // `pulse: false` 的来源跟着呼吸——那条约定不能依赖邻居的开关。\n : <span key={entry.facet.id} className={pulseClass}>{glyph}</span>)\n }\n if (completed > 0) dots.push(<StateDot key=\"done\" state=\"done\" />)\n // 数字 = 待审批 + 进行中(含子智能体)+ 已完成 + 各外部来源自己报的条数。\n // #25②:「含子智能体」此前是**空头承诺**——`summarizeGroupStatus` 在 pending 分支里\n // `continue` 掉了 `subagents += n.runningSubagentCount`,行内却给两个点。计数判据已\n // 改成与 `Rows.tsx` 的 `sessionStatuses()` 同一套规则,这条注释现在才成立。\n // P2-3: 上限 99+,避免大项目组徽标过宽。\n // P3-3: 低于 countThreshold 时省略数字(点已表达\"有东西\");设置项可调。\n const count = pending + active + completed + facetTotal\n const countLabel = count > 99 ? '99+' : count >= settings.countThreshold ? String(count) : ''\n // #22:徽标**容器**不再带脉冲 class——脉冲是\"某个来源的元素该闪\",不是整只徽标该闪。\n return (\n <span className={css.groupBadge} role=\"img\" aria-label={label} title={label}>\n {dots}\n {countLabel && <span className={css.groupBadgeCount}>{countLabel}</span>}\n </span>\n )\n}\n","/**\n * Workspace browser tree row components (figma Cell set 14:3080): pure presentational —\n * all data and callbacks arrive via props. Hover swaps (folder->chevron,\n * time->ellipsis, action buttons) are CSS-only, and a session row's clipped\n * title marquees programmatically while the row is hovered. Workspace row\n * menus are visual-only except Rename/Delete. A Session row's \"...\" menu and\n * its hover buttons are the `sidebar.workspaces.session.menu.item` and\n * `sidebar.workspaces.session.row.action` lists, rendered through the\n * browser's `renderSlot` with the menu's open state as the occurrence's hook\n * context; this package's own actions are entries like any plugin's. The\n * session and workspace hover cards are suppressed while a menu is open.\n */\nimport { useEffect, useMemo, useRef, useState } from 'react'\nimport type { RefObject } from 'react'\nimport clsx from 'clsx'\nimport type { PropsRenderSlots } from '@deepseek-ai/dsh-client-ui-slots'\nimport {\n HoverCard, IconArchiveOutlineRegular, IconEditOutlineRegular,\n IconEllipsisOutlineRegular, IconFolderCloseRegular, IconFolderOpenRegular,\n IconNewChatOutlineRegular, IconPinFillRegular, IconTrashOutlineRegular,\n IconTriangleRightFillRegular, IconUnarchiveOutlineRegular, Menu, relativeTime, StateDot, Tooltip,\n} from '@deepseek-ai/dsh-client-ui-primitives'\nimport type { ShortcutCatalogEntry } from '@deepseek-ai/dsh-client-shortcuts/client'\nimport type { StateDotState } from '@deepseek-ai/dsh-client-ui-primitives'\nimport { abbreviateHomePath } from '@deepseek-ai/dsh-util-workspace-path'\nimport type { MenuOpenState, WorkspaceBrowserProps } from '../contract/slots.ts'\nimport type { GroupLiveStatus, GroupNode, SearchResultNode, SessionNode } from '../tree.ts'\nimport { groupLiveBadge, hoverStatusLines } from './GroupBadge.tsx'\nimport css from './Rows.module.css'\n\n/** The standard locale seat, prop-passed from the browser root. */\ntype RowTranslate = WorkspaceBrowserProps['t']\n\n/**\n * Child-seat renderer threaded from the browser root: the row's action lists,\n * its leading decoration, and its hover-card section. The leading seat is\n * rendered only while the row's primary state is idle, so a status dot and a\n * leading occupant never share the row; the hover seat only while the row's\n * card is open.\n */\ntype RowRenderSlots = PropsRenderSlots<\n | 'sidebar.workspaces.session.menu.item'\n | 'sidebar.workspaces.session.row.action'\n | 'sidebar.session.row.leading'\n | 'sidebar.session.row.hover'\n>['renderSlot']\n\n/** Row display title: blank rows show the localized New Session label. */\nfunction displayTitle(node: SessionNode, t: RowTranslate): string {\n return node.blank ? t('session.new') : (node.title || t('session.untitled'))\n}\n\n/* Overflow this small hides no meaningful tail; scrolling for it reads as an\n accidental jitter, so the title stays put. */\nconst MIN_TITLE_REVEAL_PX = 8\n\n/* Marquee travel speed: slow enough to read the text as it passes. */\nconst TITLE_MARQUEE_PX_PER_MS = 0.03\n\n/**\n * Place the title's scroll position and publish the stylesheet's fade-mask\n * hooks: `data-scrolled` while the title has left its start (left fade) and\n * `data-clipped` while text remains beyond the right edge (right fade).\n * @param title - the row's clipping title element.\n * @param left - scroll offset in CSS pixels.\n * @param range - the title's maximum scroll offset in CSS pixels.\n */\nfunction placeTitle(title: HTMLSpanElement, left: number, range: number): void {\n // jsdom implements no scrollTo; the lane's direct assignment is instant there\n // anyway, so both paths land on the same position.\n if (typeof title.scrollTo === 'function') title.scrollTo({ left, behavior: 'instant' })\n else title.scrollLeft = left\n if (left > 0) title.dataset.scrolled = ''\n else delete title.dataset.scrolled\n if (left < range) title.dataset.clipped = ''\n else delete title.dataset.clipped\n}\n\n/**\n * Return the title to its resting state: scrolled to the start with both fade\n * masks off, so the resting ellipsis renders at full strength.\n * @param title - the row's clipping title element.\n */\nfunction restTitle(title: HTMLSpanElement): void {\n if (typeof title.scrollTo === 'function') title.scrollTo({ left: 0, behavior: 'instant' })\n else title.scrollLeft = 0\n delete title.dataset.scrolled\n delete title.dataset.clipped\n}\n\n/**\n * Marquee a title wider than its one-line cell while its row is hovered: the\n * title clips its own text, so entering crawls it at a constant speed until the\n * far edge (a fork's incremented title, for example) is in view, then rests\n * there under the pointer. Overflow of at most {@link MIN_TITLE_REVEAL_PX}\n * stays put — a barely-clipped title moving a few pixels reads as jitter, not a\n * reveal. Leaving returns the title to the start in one step, because the\n * resting ellipsis and the narrowed cell would otherwise meet the text while it\n * travelled back. Reduced motion jumps to the far edge instead of crawling.\n * @param title - ref to the row's clipping title element.\n * @returns stable pointer enter/leave handlers for the row.\n */\nfunction useTitleMarquee(title: RefObject<HTMLSpanElement | null>): { enter: () => void; leave: () => void } {\n const frame = useRef(0)\n useEffect(() => () => { cancelAnimationFrame(frame.current) }, [])\n return useMemo(() => ({\n enter: (): void => {\n /* v8 ignore next -- defensive: the title span renders unconditionally. */\n if (title.current === null) return\n const element = title.current\n const range = element.scrollWidth - element.clientWidth\n if (range <= MIN_TITLE_REVEAL_PX) return\n if (window.matchMedia('(prefers-reduced-motion: reduce)').matches) {\n placeTitle(element, range, range)\n return\n }\n cancelAnimationFrame(frame.current)\n let previous: number | undefined\n let position = 0\n const step = (now: DOMHighResTimeStamp): void => {\n position += previous === undefined ? 0 : (now - previous) * TITLE_MARQUEE_PX_PER_MS\n previous = now\n placeTitle(element, Math.min(position, range), range)\n if (position < range) frame.current = requestAnimationFrame(step)\n }\n frame.current = requestAnimationFrame(step)\n },\n leave: (): void => {\n cancelAnimationFrame(frame.current)\n /* v8 ignore next -- defensive: the title span renders unconditionally. */\n if (title.current === null) return\n restTitle(title.current)\n },\n }), [title])\n}\n\n/** Localized compact relative time (\"刚刚\"/\"5分钟\" in zh, \"now\"/\"5min\" in en). */\nfunction timeLabel(updatedAt: number, now: number, t: RowTranslate): string {\n const { unit, n } = relativeTime(updatedAt, now)\n return unit === 'now' ? t('time.now') : t(`time.${unit}`, { n })\n}\n\n/** Hover-card variant: distances wrap in the ago template; the now bucket stays bare (no \"now ago\"). */\nfunction hoverTimeLabel(updatedAt: number, now: number, t: RowTranslate): string {\n const { unit, n } = relativeTime(updatedAt, now)\n return unit === 'now' ? t('time.now') : t('time.ago', { t: t(`time.${unit}`, { n }) })\n}\n\n/**\n * Absolute creation time through the dictionary's date template (the message\n * clock pattern): `toLocaleString` would follow the browser language, not the\n * app locale, and produce mixed-language text after a switch.\n */\nfunction createdLabel(createdAt: number, t: RowTranslate): string {\n const d = new Date(createdAt)\n const pad2 = (v: number): string => String(v).padStart(2, '0')\n const date = t('date.ymd', { y: d.getFullYear(), m: d.getMonth() + 1, d: d.getDate() })\n return t('hover.created', { time: `${date} ${pad2(d.getHours())}:${pad2(d.getMinutes())}` })\n}\n\n// groupLiveBadge and groupLiveLabel are fork-owned — imported from ./GroupBadge.tsx.\n\n/** Hover-card body: workspace title, display directory path, absolute creation time. */\nfunction WorkspaceHoverContent({ label, cwd, createdAt, status, settings, now, t }: {\n label: string\n cwd: string | undefined\n createdAt: number\n /** Aggregated member status, supplied only while the group is folded. */\n status: GroupLiveStatus | undefined\n /** 徽标设置:悬停明细按来源过滤;`showHoverDetails=false` 时整段为空。 */\n settings: import('../badge-settings.ts').ResolvedBadgeSettings\n /** #25④:与徽标同一个时钟读数。 */\n now: number\n t: RowTranslate\n}) {\n // Fork-owned: status detail lines computed by GroupBadge.tsx.\n const lines = hoverStatusLines(status, t, settings, now)\n return (\n <div className={css.hoverContent}>\n <div className={css.hoverTitle}>{label}</div>\n <div className={css.hoverPath}>{cwd}</div>\n <div className={css.hoverTime}>{createdLabel(createdAt, t)}</div>\n {lines.map(line => (\n <div className={css.hoverStatus} key={line.text}>\n {/* #24:外部来源用它自己交的图标(已含色档),与徽标同源;宿主会话状态没有\n glyph,仍走三档 StateDot。 */}\n {line.glyph ?? <StateDot state={line.state} />}\n <span>{line.text}</span>\n </div>\n ))}\n </div>\n )\n}\n\n/**\n * Row drag wiring supplied by the tree owner. `drop` reports the half of the\n * row where the pointer released so the owner can resolve an insert anchor.\n */\nexport interface RowDragProps {\n /** Start dragging this row. */\n start: () => void\n /** A compatible row drag is in flight. */\n active: boolean\n /** Current marker on this row: insert line above, below, or none. */\n marker: 'before' | 'after' | null\n /** Report the hovered half while a compatible drag passes over this row. */\n hover: (half: 'before' | 'after') => void\n drop: (half: 'before' | 'after') => void\n end: () => void\n}\n\n/** Drag lifecycle owned by a workspace row; its enclosing group owns hit testing. */\ninterface WorkspaceRowDragProps {\n start: () => void\n end: () => void\n}\n\n/** Pointer-position half of a row (insert line above or below). */\nfunction rowHalf(e: { clientY: number; currentTarget: HTMLElement }): 'before' | 'after' {\n const rect = e.currentTarget.getBoundingClientRect()\n return e.clientY < rect.top + rect.height / 2 ? 'before' : 'after'\n}\n\n/**\n * Project (workspace) header row: folder + title;\n * hover reveals the chevron and create button, and dwelling on a real\n * Workspace shows its hover card (the ungrouped bucket has none).\n * `containsCurrent` arrives on the node (derivation fact, no renderer scan).\n * @param props.group - derived group node.\n * @param props.containsCurrentDescendant - highlight an ancestor even when its subtree is collapsed.\n * @param props.onToggle - expand/collapse the group.\n * @param props.onCreate - start a frontend Session inside this Workspace.\n * @param props.drag - optional workspace-row drag wiring.\n * @param props.home - host account home for POSIX hover-path abbreviation.\n * @param props.t - the browser root's locale seat.\n * @returns the row element.\n */\nexport function ProjectRowItem({ group, containsCurrentDescendant = false, onToggle, onCreate, actions, drag, home, newShortcut, settings, now, t }: {\n group: GroupNode\n newShortcut?: ShortcutCatalogEntry | undefined\n containsCurrentDescendant?: boolean\n onToggle: () => void\n onCreate: () => void\n /** Real-Workspace actions; absent for the ungrouped bucket (no menu shown). */\n actions?: { rename: () => void; delete: () => void } | undefined\n /** Present only for real Workspace rows in the grouped view. */\n drag?: WorkspaceRowDragProps | undefined\n /** Host account home; POSIX home-rooted hover paths display as `~`. */\n home?: string | undefined\n /** 徽标设置:各来源显隐、悬停明细、数字样式。 */\n settings: import('../badge-settings.ts').ResolvedBadgeSettings\n /** #25④:一次渲染一个时钟读数。徽标文案、aria-label 与悬停明细共用它,否则跨分钟\n * 边界时同一行的徽标与明细会给出相差一分钟的两个答案。缺省仅供直接构造该组件的\n * 测试使用,生产路径由 WorkspaceBrowser 统一传入。 */\n now?: number | undefined\n t: RowTranslate\n}) {\n const row = group\n // The ungrouped bucket has no workspace title: its label is dictionary copy.\n const label = row.workspaceId === undefined ? t('group.ungrouped') : row.label\n const active = containsCurrentDescendant || (group.expanded && group.containsCurrent)\n const [menuOpen, setMenuOpen] = useState(false)\n const workspaceMenuItems = [\n { id: 'rename', label: t('rename'), icon: <IconEditOutlineRegular /> },\n { id: 'delete', label: t('delete.workspace'), icon: <IconTrashOutlineRegular />, danger: true },\n ]\n const ownRow = (\n <div\n className={clsx(css.projectRow, menuOpen && css.menuOpen)}\n data-row-key={`workspace:${group.key}`}\n role=\"treeitem\"\n aria-expanded={row.expanded}\n onClick={onToggle}\n draggable={drag !== undefined}\n onDragStart={drag === undefined\n ? undefined\n : (e) => {\n e.dataTransfer.effectAllowed = 'move'\n e.dataTransfer.setData('text/plain', row.key)\n drag.start()\n }}\n onDragEnd={drag?.end}\n >\n <span className={clsx(css.slot, css.folder, active && css.folderActive)}>\n {row.expanded ? <IconFolderOpenRegular /> : <IconFolderCloseRegular />}\n </span>\n <span className={clsx(css.slot, css.chevron)}>\n <IconTriangleRightFillRegular className={clsx(css.arrow, row.expanded && css.arrowOpen)} />\n </span>\n <span className={css.projectText}>\n <span className={css.title}>{label}</span>\n </span>\n {groupLiveBadge(group, t, settings, now)}\n <span className={css.rowActions}>\n {actions !== undefined && (\n <Menu\n open={menuOpen}\n onClose={() => { setMenuOpen(false) }}\n items={workspaceMenuItems}\n onSelect={(id) => {\n setMenuOpen(false)\n // Unknown ids leave before the dispatch: a future menu row must\n // not inherit the destructive branch as an else fallback.\n /* v8 ignore next -- Menu can emit only the rename and delete rows supplied above. */\n if (id !== 'rename' && id !== 'delete') return\n if (id === 'rename') actions.rename()\n else actions.delete()\n }}\n portal\n closeOnPointerLeave\n anchor={(\n <button\n type=\"button\"\n className={css.iconButton}\n aria-label={t('actions.workspace.aria', { name: label })}\n onClick={(e) => { e.stopPropagation(); setMenuOpen(v => !v) }}\n >\n <IconEllipsisOutlineRegular />\n </button>\n )}\n />\n )}\n <Tooltip label={t('actions.newSession')} shortcutKeys={newShortcut?.keys} side=\"bottom\" align=\"end\" delayMs={500}>\n <button\n type=\"button\"\n className={css.iconButton}\n aria-keyshortcuts={newShortcut?.aria}\n aria-label={t('actions.newSession.aria', { name: label })}\n onClick={(e) => { e.stopPropagation(); onCreate() }}\n >\n <IconNewChatOutlineRegular />\n </button>\n </Tooltip>\n </span>\n </div>\n )\n // The ungrouped bucket has no backing Workspace: no card to show.\n if (row.createdAt === undefined) return ownRow\n return (\n <HoverCard\n anchor={ownRow}\n content={<WorkspaceHoverContent\n label={row.label}\n cwd={row.cwd === undefined ? undefined : abbreviateHomePath(row.cwd, home)}\n createdAt={row.createdAt}\n status={row.expanded ? undefined : row.liveStatus}\n settings={settings}\n now={now ?? Date.now()}\n t={t}\n />}\n openDelayMs={800}\n disabled={menuOpen}\n copyText={row.cwd}\n copyLabel={t('copy')}\n copiedLabel={t('hover.copied')}\n />\n )\n}\n\n/* v8 ignore next 3 -- closed-union backstop; only reached if the status is forged */\nfunction assertNever(value: never): never {\n throw new Error(`unknown pending interaction: ${String(value)}`)\n}\n\ninterface SessionStatus {\n state: StateDotState\n label: string\n /** Compact text that replaces the Session row's update time. */\n trailingLabel?: string\n}\n\n/**\n * Session status presentation; pending interaction is primary and live activity\n * outranks completion reminders.\n */\nfunction sessionStatuses(\n node: Pick<SessionNode, 'pendingInteraction' | 'running' | 'runningSubagentCount' | 'completed'>,\n t: RowTranslate,\n): readonly [SessionStatus, ...SessionStatus[]] {\n const subagents: SessionStatus | undefined = node.runningSubagentCount === 0\n ? undefined\n : {\n state: 'ongoing',\n label: t(\n node.runningSubagentCount === 1\n ? 'status.subagentsRunning.one'\n : 'status.subagentsRunning.other',\n { n: node.runningSubagentCount },\n ),\n }\n let pending: SessionStatus | undefined\n switch (node.pendingInteraction) {\n case 'approval':\n pending = {\n state: 'warning',\n label: t('status.waitingApproval'),\n trailingLabel: t('status.compact.approval'),\n }\n break\n case 'plan-review':\n pending = {\n state: 'warning',\n label: t('status.planReview'),\n trailingLabel: t('status.compact.planReview'),\n }\n break\n case 'question':\n pending = {\n state: 'warning',\n label: t('status.waitingAnswer'),\n trailingLabel: t('status.compact.answer'),\n }\n break\n case undefined: break\n /* v8 ignore next -- closed PendingInteractionStatus union */\n default: return assertNever(node.pendingInteraction)\n }\n if (pending !== undefined) return subagents === undefined ? [pending] : [pending, subagents]\n if (node.running) {\n const primary: SessionStatus = { state: 'ongoing', label: t('status.running') }\n return subagents === undefined ? [primary] : [primary, subagents]\n }\n if (subagents !== undefined) return [subagents]\n if (node.completed) return [{ state: 'done', label: t('status.completed') }]\n return [{ state: 'idle', label: t('status.idle') }]\n}\n\n/** Primary status dot plus every status's screen-reader label, shared by the search and session rows. */\nfunction SessionStatusDots({ statuses }: { statuses: readonly [SessionStatus, ...SessionStatus[]] }) {\n return (\n <>\n <StateDot state={statuses[0].state} />\n {statuses.map(status => (\n <span className={css.visuallyHidden} key={status.label}>{status.label}</span>\n ))}\n </>\n )\n}\n\n/** Non-interactive pinned-row marker; the enclosing row remains the only action. */\nfunction PinnedIndicator({ t }: { t: RowTranslate }) {\n const label = t('row.pinned')\n return (\n <span className={css.pinIndicator} role=\"img\" aria-label={label} title={label}>\n <IconPinFillRegular size={14} />\n </span>\n )\n}\n\n/**\n * Hover-card body: full title, relative time, the Session's own scheduled-task\n * section, and every relevant live status. The task section sits above the\n * status lines so they stay the card's trailing status line.\n */\nfunction SessionHoverContent({ node, now, renderSlot, t }: {\n node: SessionNode\n now: number\n renderSlot: RowRenderSlots\n t: RowTranslate\n}) {\n // On archived rows the archived line already says the session is inactive,\n // so resting statuses (idle/completed) drop; live activity still shows.\n const statuses = sessionStatuses(node, t)\n .filter(status => !(node.archived && (status.state === 'done' || status.state === 'idle')))\n return (\n <div className={css.hoverContent}>\n <div className={css.hoverTitle}>{displayTitle(node, t)}</div>\n {/* Same placeholder rule as the row's trailing cell: no timestamp\n before the first prompt. */}\n {!node.blank && <div className={css.hoverTime}>{hoverTimeLabel(node.updatedAt, now, t)}</div>}\n {renderSlot('sidebar.session.row.hover', { sessionId: node.id })}\n {statuses.map(status => (\n <div className={css.hoverStatus} key={status.label}>\n <StateDot state={status.state} />\n <span>{status.label}</span>\n </div>\n ))}\n {node.archived && (\n <div className={clsx(css.hoverStatus, css.hoverArchived)}>\n <IconArchiveOutlineRegular size={14} />\n <span>{t('row.archived')}</span>\n </div>\n )}\n </div>\n )\n}\n\n/**\n * One flat search result: title, Workspace context, and optional content\n * excerpt. Search navigation opens the session only; it does not address an\n * event inside the conversation. Archived rows carry a hover unarchive\n * button, because search is where the filter surfaces them for recovery.\n * @param props.result - merged local/content search row.\n * @param props.currentId - selected session id.\n * @param props.onOpen - open the selected session.\n * @param props.onUnarchive - unarchive an archived result row.\n * @param props.t - Workspace-browser translation seat.\n * @returns the result row.\n */\nexport function SearchResultItem({ result, currentId, onOpen, onUnarchive, t }: {\n result: SearchResultNode\n currentId: string | undefined\n onOpen: (id: SearchResultNode['id']) => void\n onUnarchive: (id: SearchResultNode['id']) => void\n t: RowTranslate\n}) {\n const selected = result.id === currentId\n const statuses = sessionStatuses(result, t)\n const primaryStatus = statuses[0]\n return (\n <div\n className={clsx(css.searchResultRow, selected && css.selected, result.archived && css.archived)}\n role=\"treeitem\"\n aria-selected={selected}\n aria-description={result.archived ? t('toast.archivedNotOpenable') : undefined}\n onClick={() => { onOpen(result.id) }}\n >\n <span className={css.searchResultHeading}>\n {/* Like session rows, the leading slot owns every row marker; on\n archived rows it stays blank — the grayed row carries the\n archived look. */}\n <span className={css.slot}>\n {!result.archived && primaryStatus.state !== 'idle' && (\n <SessionStatusDots statuses={statuses} />\n )}\n </span>\n <span className={css.searchResultTitle}>{result.title || t('session.untitled')}</span>\n {result.archived && (\n <span className={css.rowActions}>\n <Tooltip label={t('actions.unarchive')} side=\"bottom\" align=\"end\" delayMs={500}>\n <button\n type=\"button\"\n className={css.iconButton}\n aria-label={t('menu.unarchiveSession')}\n onClick={(e) => { e.stopPropagation(); onUnarchive(result.id) }}\n >\n <IconUnarchiveOutlineRegular size={14} />\n </button>\n </Tooltip>\n </span>\n )}\n </span>\n <span className={css.searchResultMeta}>\n <span className={css.searchResultWorkspace}>{result.workspace || t('group.ungrouped')}</span>\n {result.snippet !== undefined && (\n <span className={css.searchResultSnippet}>{result.snippet}</span>\n )}\n </span>\n </div>\n )\n}\n\n/**\n * One top-level 32px session row: leading 16px cell (status dot, or the\n * leading seat while the row's primary state is idle), title, relative time or\n * compact pending label, and the row actions menu. A row that owns a state dot\n * keeps that cell and renders no seat, so an ambient automation mark never\n * appears beside the row's own state dot. An archived row keeps the cell blank:\n * neither marker renders there, and its live status stays on the hover card.\n * @param props.node - derived session node.\n * @param props.currentId - selected session id (row highlight).\n * @param props.now - epoch ms for relative-time formatting.\n * @param props.onOpen - open a session by id.\n * @param props.onRenameRequest - open the rename dialog from a title double-click (id + current title).\n * @param props.renderSlot - child-seat renderer for the row's action lists\n * (`sidebar.workspaces.session.menu.item` / `sidebar.workspaces.session.row.action`),\n * its leading decoration, and its hover-card section.\n * @param props.onReveal - scroll this row into view after search navigation, then acknowledge it.\n * @param props.drag - optional row-drag target wiring; blank rows cannot start a drag.\n * @param props.t - the browser root's locale seat.\n * @returns the session row.\n */\nexport function SessionNodeItem({\n node, currentId, now, onOpen, onRenameRequest, renderSlot, onReveal, drag, t,\n}: {\n node: SessionNode\n currentId: string | undefined\n now: number\n onOpen: (id: SessionNode['id']) => void\n /** Open the rename dialog from a title double-click (id + current title). */\n onRenameRequest: (id: SessionNode['id'], currentTitle: string) => void\n /** Scroll this row into view after search navigation, then acknowledge it. */\n onReveal?: (() => void) | undefined\n /** Present on reorderable-list rows so every row can remain a drop target. */\n drag?: RowDragProps | undefined\n t: RowTranslate\n} & PropsRenderSlots<\n | 'sidebar.workspaces.session.menu.item'\n | 'sidebar.workspaces.session.row.action'\n | 'sidebar.session.row.leading'\n | 'sidebar.session.row.hover'\n>) {\n const row = node\n const title = displayTitle(node, t)\n const selected = node.id === currentId\n const statuses = sessionStatuses(node, t)\n const primaryStatus = statuses[0]\n const showStatus = primaryStatus.state !== 'idle'\n // Archived rows hold their in-place grayed slot, so manual reorder cannot\n // move them. Pinned rows drag within the pinned block: the browser gates\n // their drop targets to fellow pinned rows.\n const draggable = drag !== undefined && !row.blank && !row.archived\n const [menuOpen, setMenuOpen] = useState(false)\n // The menu's open state, bound into the row entries' `useMenuOpenState` hook.\n const menuOpenState = useMemo((): MenuOpenState => [menuOpen, setMenuOpen], [menuOpen])\n const rowRef = useRef<HTMLDivElement>(null)\n const titleRef = useRef<HTMLSpanElement>(null)\n const marquee = useTitleMarquee(titleRef)\n useEffect(() => {\n if (onReveal === undefined) return\n rowRef.current?.scrollIntoView({ block: 'nearest' })\n onReveal()\n }, [onReveal])\n // Figma session cell: pad 8, status slot 16, then a 4px title gap.\n const ownRow = (\n <div\n ref={rowRef}\n data-row-key={`session:${node.id}`}\n className={clsx(\n css.sessionRow, selected && css.selected, menuOpen && css.menuOpen,\n row.archived && css.archived,\n drag?.marker === 'before' && css.dropBefore, drag?.marker === 'after' && css.dropAfter,\n )}\n role=\"treeitem\"\n aria-selected={selected}\n aria-description={row.archived ? t('toast.archivedNotOpenable') : undefined}\n onClick={() => { onOpen(node.id) }}\n onPointerEnter={marquee.enter}\n onPointerLeave={marquee.leave}\n draggable={draggable}\n onDragStart={!draggable\n ? undefined\n : (e) => {\n e.dataTransfer.effectAllowed = 'move'\n e.dataTransfer.setData('text/plain', node.id)\n drag.start()\n }}\n onDragEnd={!draggable ? undefined : drag.end}\n onDragOver={drag === undefined\n ? undefined\n : (e) => {\n if (!drag.active) return\n e.preventDefault()\n e.dataTransfer.dropEffect = 'move'\n drag.hover(rowHalf(e))\n }}\n onDrop={drag === undefined\n ? undefined\n : (e) => {\n if (!drag.active) return\n e.preventDefault()\n drag.drop(rowHalf(e))\n }}\n >\n {/* Pending interaction and own or descendant activity outrank the\n finished-but-unviewed reminder, which returns after activity stops\n and is cleared by opening the session. Archived rows keep the slot\n blank — the grayed row carries the archived look — and their live\n status stays on the hover card only. */}\n <span className={css.slot}>\n {!row.archived && !row.blank && (showStatus\n ? <SessionStatusDots statuses={statuses} />\n : renderSlot('sidebar.session.row.leading', { sessionId: node.id }))}\n </span>\n <span\n ref={titleRef}\n className={css.title}\n onDoubleClick={row.blank\n ? undefined\n : (e) => { e.stopPropagation(); onRenameRequest(node.id, row.title) }}\n >\n {title}\n </span>\n {/* A blank New Session row is a provisional placeholder: nothing has\n happened in it yet, so a \"now\" timestamp and the row verbs\n (rename/fork/archive) would all act on content that does not\n exist — both trailing cells stay off until the first prompt. */}\n {!row.blank && (\n <span\n className={css.time}\n aria-hidden={primaryStatus.trailingLabel === undefined ? undefined : true}\n >\n {primaryStatus.trailingLabel ?? timeLabel(row.updatedAt, now, t)}\n </span>\n )}\n {/* Trails the time so the marker occupies the same right-edge cell as\n the hover pin button that replaces it. */}\n {row.pinned && !row.archived && <PinnedIndicator t={t} />}\n {/* The strip's clicks stay in the strip: the trigger and every\n row.action entry act without also opening the row, so an entry's\n button needs no propagation handling of its own. */}\n {!row.blank && (\n <span className={css.rowActions} onClick={(e) => { e.stopPropagation() }}>\n <Menu\n open={menuOpen}\n onClose={() => { setMenuOpen(false) }}\n portal\n closeOnPointerLeave\n anchor={(\n <button\n type=\"button\"\n className={css.iconButton}\n aria-label={t('actions.session.aria', { name: title })}\n onClick={() => { setMenuOpen(v => !v) }}\n >\n <IconEllipsisOutlineRegular />\n </button>\n )}\n >\n {renderSlot(\n 'sidebar.workspaces.session.menu.item',\n { sessionId: node.id, displayTitle: row.title },\n { hookContext: menuOpenState },\n )}\n </Menu>\n {renderSlot('sidebar.workspaces.session.row.action', { sessionId: node.id, displayTitle: row.title })}\n </span>\n )}\n </div>\n )\n return (\n <HoverCard\n anchor={ownRow}\n content={<SessionHoverContent node={node} now={now} renderSlot={renderSlot} t={t} />}\n openDelayMs={800}\n disabled={menuOpen || drag?.active === true}\n copyText={row.blank || row.title === '' ? undefined : row.title}\n copyLabel={t('copy')}\n copiedLabel={t('hover.copied')}\n />\n )\n}\n","/** React-commit-driven movement and entry/exit fades for the sidebar's keyed rows. */\nimport { Component, createRef, type ReactNode } from 'react'\nimport css from './AnimatedRows.module.css'\n\nconst ROW_FADE_MS = 100\nconst ROW_GLIDE_MS = 200\n\ninterface AnimatedRowsProps {\n children: ReactNode\n className: string\n label: string\n /** Unique DOM-order keys matching the rendered data-row-key attributes. */\n rowKeys: readonly string[]\n ready: boolean\n /** Changes that replace the view or reveal hidden rows settle immediately. */\n resetKey: string\n}\n\ninterface RowPosition {\n element: HTMLElement\n rect: DOMRect\n opacity: number\n}\n\ninterface RowSnapshot {\n positions: Map<string, RowPosition>\n removed: Map<string, RowPosition>\n}\n\nfunction sameRows(previous: AnimatedRowsProps, next: AnimatedRowsProps): boolean {\n return previous.rowKeys.length === next.rowKeys.length\n && previous.rowKeys.every((key, index) => key === next.rowKeys[index])\n}\n\nfunction intersects(row: DOMRect, viewport: DOMRect): boolean {\n return row.bottom > viewport.top && row.top < viewport.bottom\n && row.right > viewport.left && row.left < viewport.right\n}\n\n/**\n * Animates keyed sidebar rows only when their rendered membership or order changes.\n * Motion starts after the first pointer or keyboard input inside the mounted list.\n * The parent supplies a positioned container for the inert exit overlay.\n */\nexport class AnimatedRows extends Component<AnimatedRowsProps> {\n private armed = false\n private readonly list = createRef<HTMLDivElement>()\n private readonly overlay = createRef<HTMLDivElement>()\n private readonly movements = new Map<HTMLElement, Animation>()\n private readonly exits = new Map<string, { element: HTMLElement; animation: Animation }>()\n\n override getSnapshotBeforeUpdate(previous: AnimatedRowsProps): RowSnapshot | null {\n const list = this.list.current\n if (!this.armed || sameRows(previous, this.props) || previous.resetKey !== this.props.resetKey\n || !previous.ready || !this.props.ready || list === null\n || typeof list.animate !== 'function'\n || window.matchMedia('(prefers-reduced-motion: reduce)').matches) return null\n\n const viewport = list.getBoundingClientRect()\n const positions = this.readPositions()\n const nextKeys = new Set(this.props.rowKeys)\n const removed = new Map<string, RowPosition>()\n for (const [key, row] of positions) {\n if (nextKeys.has(key) || !intersects(row.rect, viewport)) continue\n const clone = row.element.cloneNode(true) as HTMLElement\n clone.removeAttribute('data-row-key')\n clone.inert = true\n clone.style.setProperty(\n '--dsh-workspace-indent', getComputedStyle(row.element).getPropertyValue('--dsh-workspace-indent'),\n )\n removed.set(key, { ...row, element: clone })\n }\n return { positions, removed }\n }\n\n override componentDidUpdate(previous: AnimatedRowsProps, _state: unknown, snapshot: RowSnapshot | null): void {\n if (snapshot === null) {\n if (!sameRows(previous, this.props) || previous.resetKey !== this.props.resetKey\n || previous.ready !== this.props.ready) this.clear()\n return\n }\n\n this.cancelMovements()\n const list = this.list.current as HTMLDivElement\n const overlay = this.overlay.current as HTMLDivElement\n const viewport = list.getBoundingClientRect()\n const origin = overlay.getBoundingClientRect()\n const positions = this.readPositions()\n\n for (const [key, row] of positions) {\n this.removeExit(key)\n const previousRow = snapshot.positions.get(key)\n if (!intersects(row.rect, viewport)\n && (previousRow === undefined || !intersects(previousRow.rect, viewport))) continue\n if (previousRow === undefined) {\n this.move(row.element, [{ opacity: 0 }, { opacity: 1 }], ROW_FADE_MS)\n continue\n }\n const dx = previousRow.rect.left - row.rect.left\n const dy = previousRow.rect.top - row.rect.top\n if (dx === 0 && dy === 0 && previousRow.opacity === 1) continue\n this.move(row.element, [\n { transform: `translate(${String(dx)}px, ${String(dy)}px)`, opacity: previousRow.opacity },\n { transform: 'translate(0, 0)', opacity: 1 },\n ], ROW_GLIDE_MS)\n }\n\n for (const [key, row] of snapshot.removed) {\n const { element } = row\n this.removeExit(key)\n Object.assign(element.style, {\n position: 'absolute', margin: '0', transform: 'none', boxSizing: 'border-box',\n left: `${String(row.rect.left - origin.left)}px`,\n top: `${String(row.rect.top - origin.top)}px`,\n width: `${String(row.rect.width)}px`, height: `${String(row.rect.height)}px`,\n })\n overlay.append(element)\n const animation = element.animate([{ opacity: row.opacity }, { opacity: 0 }], {\n duration: ROW_FADE_MS, easing: 'ease-out', fill: 'forwards',\n })\n this.exits.set(key, { element, animation })\n animation.onfinish = () => { this.removeExit(key) }\n }\n }\n\n override componentWillUnmount(): void {\n this.clear()\n }\n\n private readPositions(): Map<string, RowPosition> {\n const list = this.list.current as HTMLDivElement\n const rows = list.querySelectorAll<HTMLElement>('[data-row-key]')\n return new Map(Array.from(rows, element => [element.dataset.rowKey as string, {\n element,\n rect: element.getBoundingClientRect(),\n opacity: this.movements.has(element) ? Number(getComputedStyle(element).opacity) : 1,\n }]))\n }\n\n private move(element: HTMLElement, keyframes: Keyframe[], duration: number): void {\n const animation = element.animate(keyframes, { duration, easing: 'ease-out' })\n this.movements.set(element, animation)\n animation.onfinish = () => { this.movements.delete(element); animation.cancel() }\n }\n\n private cancelMovements(): void {\n for (const animation of this.movements.values()) {\n animation.onfinish = null\n animation.cancel()\n }\n this.movements.clear()\n }\n\n private removeExit(key: string): void {\n const exit = this.exits.get(key)\n if (exit === undefined) return\n exit.animation.onfinish = null\n exit.animation.cancel()\n exit.element.remove()\n this.exits.delete(key)\n }\n\n private clear(): void {\n this.cancelMovements()\n for (const key of this.exits.keys()) this.removeExit(key)\n }\n\n override render(): ReactNode {\n return <>\n <div\n ref={this.list}\n className={this.props.className}\n role=\"tree\"\n aria-label={this.props.label}\n onPointerDownCapture={() => { this.armed = true }}\n onKeyDownCapture={() => { this.armed = true }}\n >\n {this.props.children}\n </div>\n <div ref={this.overlay} className={css.exits} aria-hidden=\"true\" />\n </>\n }\n}\n","/**\n * Workspace pick/add flow. WorkspacePickFlow is the reusable core (menu +\n * path error dialog) consumed directly by WorkspaceBrowser (same package) and\n * wrapped by WorkspacePicker for the conversation empty-state slot\n * registration. Directory picking itself lives in the composed flow package's\n * slot occupant (see the contract module doc): this core only opens the flow,\n * adopts the picked path, and owns the error surface. Adding a workspace has\n * exactly one route — pick a host directory, new or existing — because the\n * occupant's own create-folder affordance already covers creating one.\n */\nimport type { ReactNode, RefObject } from 'react'\nimport { useCallback, useEffect, useState } from 'react'\nimport {\n Button, IconFolderCloseRegular, IconPlusOutlineRegular, Menu, Modal, type MenuEntry,\n} from '@deepseek-ai/dsh-client-ui-primitives'\nimport type {\n WorkspaceId, WorkspaceSnapshot, WorkspaceView,\n} from '@deepseek-ai/dsh-api-workspace-controller/client'\nimport { workspaceDisplayTitle } from '@deepseek-ai/dsh-api-workspace-controller/default-workspace'\nimport type { SnapshotSelectorHook } from '@deepseek-ai/dsh-client-ui-slots'\nimport type { DirectoryFlowOwnerProps, WorkspacePickerProps } from './contract/slots.ts'\nimport css from './WorkspacePicker.module.css'\n\nconst ADD_WORKSPACE = '::add-workspace'\n\n/** Core flow props: the owner supplies popover control and pick semantics. */\nexport interface WorkspacePickFlowProps {\n /** The standard locale seat, forwarded by whichever slot entry hosts the flow. */\n t: WorkspacePickerProps['t']\n /** Popover visibility (anchor button toggle state, owner-local). */\n open: boolean\n /** The anchor button element — the popover's placement anchor. */\n anchorRef?: RefObject<HTMLElement | null> | undefined\n /** Selector hook over the workspace list (framework standard hook). */\n useWorkspaces: <S>(selector: (state: WorkspaceSnapshot) => S) => S\n /** Adopt a picked host directory as a real Workspace. */\n createWorkspace: (input: { path: string }) => Promise<WorkspaceView>\n /** Bound occupancy selector hook for this surface's directory-flow hole (empty leaves the surface with no add action). */\n useDirectoryFlow: SnapshotSelectorHook<boolean>\n /** Render this surface's directory-flow hole with the owner conversation (the entry's narrowed renderSlot). */\n renderDirectoryFlow: (owner: DirectoryFlowOwnerProps) => ReactNode\n /** A real Workspace was picked or created. */\n onPick: (workspaceId: WorkspaceId) => void\n /** Close the popover (outside click / Escape / post-pick). */\n onClose: () => void\n /** Report the picking interaction and adoption occupancy. */\n onBusyChange?: (busy: boolean) => void\n /** Only offer the add action, hide existing workspaces. */\n addOnly?: boolean\n /** Menu opening direction relative to the anchor. */\n side?: 'bottom' | 'top' | 'right'\n /** Currently active workspace (trailing check in the picker list). */\n selectedId?: WorkspaceId | undefined\n}\n\n/**\n * Render the pick menu plus the adoption error dialog.\n * @param props - owner-controlled flow props.\n * @returns menu + dialog elements.\n */\nexport function WorkspacePickFlow({\n t,\n open,\n anchorRef,\n useWorkspaces,\n createWorkspace,\n useDirectoryFlow,\n renderDirectoryFlow,\n onPick,\n onClose,\n addOnly = false,\n onBusyChange,\n side = 'bottom',\n selectedId,\n}: WorkspacePickFlowProps) {\n const workspaceSnapshot = useWorkspaces(state => state)\n const workspaces = workspaceSnapshot.items\n const getAnchorRect = useCallback(\n () => anchorRef?.current?.getBoundingClientRect() ?? null,\n [anchorRef],\n )\n const [errorOpen, setErrorOpen] = useState(false)\n const [modalError, setModalError] = useState<string | null>(null)\n const [flowOpen, setFlowOpen] = useState(false)\n const [pickingFolder, setPickingFolder] = useState(false)\n // One picking interaction at a time: while the flow is open (native chooser\n // pending, browse dialog up) or its pick is being adopted, every other\n // menu action stays disabled — a late outcome must not race a concurrent\n // selection or adoption.\n const flowBusy = flowOpen || pickingFolder\n useEffect(() => { onBusyChange?.(flowBusy) }, [flowBusy, onBusyChange])\n\n // The occupied hole gates the picking affordance: with no composed flow the\n // entry simply is not there (the seam's documented no-flow default). The\n // framework-bound hook keeps occupancy live: flow plugins activate (and\n // HMR-reload) independently of this menu's renders.\n const flowAvailable = useDirectoryFlow(occupied => occupied)\n // An occupant that unloads mid-interaction leaves nobody to cancel: an\n // open flow over an empty hole withdraws so the menu actions come back.\n // flowOpen is a dependency because the flow can also OPEN over an already\n // empty hole (Choose again after the occupant unloaded with the error\n // dialog up) — that transition must snap back too, not just occupancy loss.\n useEffect(() => {\n if (flowOpen && !flowAvailable) setFlowOpen(false)\n }, [flowOpen, flowAvailable])\n const addEntries: MenuEntry[] = flowAvailable\n ? [{ id: ADD_WORKSPACE, label: t('menu.addWorkspace'), icon: <IconPlusOutlineRegular size={16} />, disabled: flowBusy }]\n : []\n // With workspaces listed, the add action pins below the scroll region\n // (divider + always visible); otherwise it IS the menu.\n const pinAdd = !addOnly && workspaces.length > 0\n const items: MenuEntry[] = pinAdd\n ? workspaces.map(workspace => ({\n id: workspace.workspaceId,\n label: workspaceDisplayTitle(workspace.title, t('workspace.defaultName')),\n icon: <IconFolderCloseRegular size={16} />,\n disabled: flowBusy,\n }))\n : addEntries\n // Nothing listed and nothing to add with (a composition that mounts this\n // package without any directory-picker): an empty popover would claim a\n // choice that does not exist, so the anchor gesture shows nothing at all.\n const menuIsEmpty = items.length === 0\n\n const closeModal = (): void => {\n setErrorOpen(false)\n setModalError(null)\n }\n\n /** Adopt a picked directory; failures land in the folder-error dialog (Choose again reopens the flow). */\n const adoptDirectory = (path: string): Promise<void> =>\n createWorkspace({ path }).then((workspace) => {\n setFlowOpen(false)\n onPick(workspace.workspaceId)\n }).catch((reason: unknown) => {\n setModalError(reason instanceof Error ? reason.message : String(reason))\n setFlowOpen(false)\n setErrorOpen(true)\n })\n\n const openDirectoryFlow = useCallback((): void => {\n onClose()\n setErrorOpen(false)\n setModalError(null)\n setFlowOpen(true)\n }, [onClose])\n\n // A menu exists to disambiguate between targets. With no workspaces listed\n // and the add action the only entry left, the anchor gesture IS that action:\n // a one-row popover would cost a click and offer nothing to choose between.\n // The owner's open request is consumed the same way selecting the entry\n // would consume it (close the popover, raise the flow). An empty list is\n // only final once the baseline lands — until then the menu stays up with its\n // loading status instead of jumping into a flow the arriving list would have\n // made unnecessary; the add-only surface lists nothing and never waits.\n const listSettled = addOnly || workspaceSnapshot.phase === 'ready'\n const addIsTheOnlyEntry = !pinAdd && listSettled && addEntries.length === 1\n // `flowBusy` gates this exactly as it disables the equivalent menu entry: a\n // pick still being adopted owns the surface until it settles.\n useEffect(() => {\n if (open && addIsTheOnlyEntry && !flowBusy) openDirectoryFlow()\n }, [open, addIsTheOnlyEntry, flowBusy, openDirectoryFlow])\n\n /** Owner side of the flow conversation: adopt keeps the flow open (busy) until the Host answers. */\n const flowOwner: DirectoryFlowOwnerProps = {\n open: flowOpen,\n busy: pickingFolder,\n onPicked: (path) => {\n setPickingFolder(true)\n void adoptDirectory(path).finally(() => { setPickingFolder(false) })\n },\n onCancel: () => { setFlowOpen(false) },\n onError: (message) => {\n setFlowOpen(false)\n setModalError(message)\n setErrorOpen(true)\n },\n }\n\n const handleSelect = (id: string): void => {\n if (id === ADD_WORKSPACE) {\n openDirectoryFlow()\n return\n }\n onPick(id as WorkspaceId)\n }\n\n return (\n <>\n <Menu\n open={open && !addIsTheOnlyEntry && !menuIsEmpty}\n anchor={null}\n items={items}\n {...pinAdd ? { footer: addEntries } : {}}\n selectedId={selectedId}\n onSelect={handleSelect}\n onClose={onClose}\n side={side}\n portal\n getAnchorRect={getAnchorRect}\n />\n {open && !addIsTheOnlyEntry && !menuIsEmpty && workspaceSnapshot.phase === 'pending' && <div className={css.menuStatus} role=\"status\">{t('picker.loading')}</div>}\n {renderDirectoryFlow(flowOwner)}\n <Modal\n open={errorOpen}\n onClose={closeModal}\n closeLabel={t('close')}\n title={t('folderError.title')}\n footer={(\n <>\n <Button variant=\"outline\" className={css.modalAction} onClick={closeModal}>{t('cancel')}</Button>\n {/* Retrying needs an occupant to serve the flow; without one the\n * button would open a flow nobody can answer or cancel. */}\n <Button variant=\"primary\" className={css.modalAction} disabled={!flowAvailable} onClick={openDirectoryFlow}>{t('folderError.retry')}</Button>\n </>\n )}\n >\n <div className={css.modalError} role=\"alert\">{modalError}</div>\n </Modal>\n </>\n )\n}\n\n/**\n * The conversation empty-state registration: adapts the owner share to the\n * core flow (all state and semantics live in the flow / the owner).\n * @param props - empty-state slot props (owner share + injected creation callback).\n * @returns the flow element.\n */\nexport function WorkspacePicker({\n open,\n anchorRef,\n useWorkspaces,\n selectedId,\n onPick,\n onClose,\n createWorkspace,\n useDirectoryFlow,\n renderSlot,\n t,\n}: WorkspacePickerProps) {\n return (\n <WorkspacePickFlow\n t={t}\n open={open}\n anchorRef={anchorRef}\n useWorkspaces={useWorkspaces}\n createWorkspace={createWorkspace}\n useDirectoryFlow={useDirectoryFlow}\n renderDirectoryFlow={owner => renderSlot('conversation.hero.workspace.directoryFlow', owner)}\n selectedId={selectedId}\n onPick={onPick}\n onClose={onClose}\n />\n )\n}\n","/**\n * The workspace/session browsing region filling the sidebar shell's\n * `sidebar.workspaces` hole: section header (title + view options + add\n * workspace), search, the grouped tree or flat list, and the workspace\n * dialogs. Wide state renders the full browser; rail state renders the two\n * region icons (search / add workspace) as 36px controls on the shell's shared\n * rail entry path, each requesting expansion through the owner share. Adding\n * is the header button's one action, so it raises the directory flow with no\n * menu in between; the flow and its error dialog live in WorkspacePicker\n * (same package — direct composition, no slot between them). A Session row's\n * \"...\" menu and hover buttons are the `sidebar.workspaces.session.menu.item`\n * and `sidebar.workspaces.session.row.action` lists rendered through this\n * entry's `renderSlot`; the actions in them, this package's own included,\n * are slot entries with their own behavior, so this component threads no\n * action callbacks and hosts no action surface.\n */\nimport { type CSSProperties, type ReactNode, useEffect, useMemo, useRef, useState, useSyncExternalStore } from 'react'\nimport clsx from 'clsx'\nimport {\n Button, IconArchiveCheckOutlineRegular, IconArchiveOffOutlineRegular, IconArchiveOutlineRegular,\n IconChevronsUpDownOutlineRegular, IconClockOutlineRegular, IconCloseFillRegular,\n IconFlatListOutlineRegular, IconFolderCloseRegular, IconProjectAddOutlineRegular,\n IconQueueOutlineRegular, IconSearchOutlineRegular, IconSlidersTwoOutlineRegular,\n IconWorkspaceTreeOutlineRegular, Menu, Modal, Toast, Tooltip,\n} from '@deepseek-ai/dsh-client-ui-primitives'\nimport type {\n SessionListState, SessionSearchResultItem,\n} from '@deepseek-ai/dsh-api-session-controller/client'\nimport type { WorkspaceId, WorkspaceView } from '@deepseek-ai/dsh-api-workspace-controller/client'\nimport { workspaceDisplayTitle } from '@deepseek-ai/dsh-api-workspace-controller/default-workspace'\n\n\n\nimport type { SessionId } from '@deepseek-ai/dsh-session/types'\nimport type { PropsRenderSlots } from '@deepseek-ai/dsh-client-ui-slots'\nimport type { WorkspaceBrowserProps } from '../contract/slots.ts'\nimport type { ArchivedFilter, GroupNode, SessionNode, SessionOrderBy, SessionRowState } from '../tree.ts'\nimport {\n deriveFlat, deriveGroups, deriveSearchResults, orderByRecency, owningGroupKey, owningParentFolder,\n pinCurrentBlank, reconcileManualOrder, sessionMemberIds, UNGROUPED_KEY,\n} from '../tree.ts'\nimport { directStatusesForGroups, withAggregatedStatus, type StatusedGroupNode } from '../group-status.ts'\nimport { facetStore } from '../facet-store.ts'\nimport { visibleFacets } from '../facet-visibility.ts'\nimport { ProjectRowItem, SearchResultItem, SessionNodeItem } from './Rows.tsx'\nimport { AnimatedRows } from './AnimatedRows.tsx'\nimport { FLAT_SESSION_ORDER_KEY, type SessionGroupBy } from '../stores.ts'\nimport { WorkspacePickFlow } from '../WorkspacePicker.tsx'\nimport css from './WorkspaceBrowser.module.css'\n\n// 外部状态来源:**本文件不认识任何具体插件**。运行时只有登记面(`../facets.ts`)与\n// 它背后的存储订阅;谁想让自己的状态进折叠徽标,就按协议注册一个 facet\n// (`docs/facet-protocol.md`)。现有两家已各自注册,本插件不再代管任何来源。\n//\n// 这里只订阅一次外部存储并读一个版本号,与 facet 数量无关,所以增删来源不会改变\n// hook 调用序列(那正是逐个调 provider hook 的写法做不到的)。\nconst facetsStore = facetStore()\n\n/**\n * Column slide length (--ds-transition-duration-slow): rail-search focus waits it out —\n * focus() forces a synchronous layout and would jank the slide.\n */\nconst EXPAND_SLIDE_MS = 300\n/** Pause between the latest keystroke and a Host content-search request. */\nconst SEARCH_DEBOUNCE_MS = 250\n/** `session.search` wire bound, measured in JavaScript UTF-16 code units. */\nconst SEARCH_QUERY_MAX_CODE_UNITS = 500\n/** Idle Session rows visible per Workspace before the local overflow control. */\nconst COLLAPSED_SESSION_LIMIT = 5\n\n/** Keep provisional and running rows outside the idle-session quota, including parents with running children. */\nfunction collapsedSessionRows(sessions: readonly SessionNode[], limit = COLLAPSED_SESSION_LIMIT): {\n rows: readonly SessionNode[]\n hiddenCount: number\n} {\n let idleCount = 0\n const rows = sessions.filter((session) => {\n if (session.blank || session.running || session.runningSubagentCount > 0) return true\n if (idleCount >= limit) return false\n idleCount += 1\n return true\n })\n return { rows, hiddenCount: sessions.length - rows.length }\n}\n\n/** Keep controlled input and RPC payload inside the session.search wire contract. */\nfunction sanitizeSearchQuery(value: string): string {\n const withoutNul = value.replaceAll('\\0', '')\n if (withoutNul.length <= SEARCH_QUERY_MAX_CODE_UNITS) return withoutNul\n let end = SEARCH_QUERY_MAX_CODE_UNITS\n const last = withoutNul.charCodeAt(end - 1)\n const next = withoutNul.charCodeAt(end)\n if (last >= 0xD800 && last <= 0xDBFF && next >= 0xDC00 && next <= 0xDFFF) end--\n return withoutNul.slice(0, end)\n}\n\n/**\n * Accept the native drag at document level while a row drag is active: row\n * hover still owns the insertion marker, and releasing outside the list must\n * not be rendered as a rejected drop before dragend commits that last marker.\n */\nfunction useNativeDragAcceptance(active: boolean): void {\n useEffect(() => {\n if (!active) return\n const acceptDrag = (event: DragEvent): void => {\n event.preventDefault()\n if (event.dataTransfer !== null) event.dataTransfer.dropEffect = 'move'\n }\n const acceptDrop = (event: DragEvent): void => { event.preventDefault() }\n document.addEventListener('dragover', acceptDrag)\n document.addEventListener('drop', acceptDrop)\n return () => {\n document.removeEventListener('dragover', acceptDrag)\n document.removeEventListener('drop', acceptDrop)\n }\n }, [active])\n}\n\n/** Grouping, ordering, and archived-filter menu; own open state so it resets with the wide chrome. */\nfunction ViewOptionsMenu({ groupBy, orderBy, archivedFilter, onGroupPick, onOrderPick, onArchivedFilterPick, t }: {\n groupBy: SessionGroupBy\n orderBy: SessionOrderBy\n archivedFilter: ArchivedFilter\n onGroupPick: (mode: SessionGroupBy) => void\n onOrderPick: (mode: SessionOrderBy) => void\n onArchivedFilterPick: (filter: ArchivedFilter) => void\n t: WorkspaceBrowserProps['t']\n}) {\n const [open, setOpen] = useState(false)\n return (\n <Menu\n open={open}\n onClose={() => { setOpen(false) }}\n items={[\n { type: 'label' as const, id: 'group-by', text: t('groupBy.label') },\n { id: 'workspace', label: t('groupBy.workspace'), icon: <IconFolderCloseRegular /> },\n { id: 'workspace-tree', label: t('groupBy.workspaceTree'), icon: <IconWorkspaceTreeOutlineRegular /> },\n { id: 'flat', label: t('groupBy.flat'), icon: <IconFlatListOutlineRegular /> },\n { type: 'separator' as const, id: 'order-by-separator' },\n { type: 'label' as const, id: 'order-by', text: t('orderBy.label') },\n { id: 'manual', label: t('orderBy.manual'), icon: <IconChevronsUpDownOutlineRegular /> },\n { id: 'updated', label: t('orderBy.updated'), icon: <IconClockOutlineRegular /> },\n { type: 'separator' as const, id: 'archived-filter-separator' },\n { type: 'label' as const, id: 'filter-by', text: t('filterBy.label') },\n { id: 'hide-archived', label: t('viewOptions.hideArchived'), icon: <IconArchiveOffOutlineRegular /> },\n { id: 'show-archived', label: t('viewOptions.showArchived'), icon: <IconQueueOutlineRegular /> },\n { id: 'only-archived', label: t('viewOptions.onlyArchived'), icon: <IconArchiveCheckOutlineRegular /> },\n ]}\n selectedIds={[\n groupBy,\n orderBy,\n { default: 'hide-archived', show: 'show-archived', only: 'only-archived' }[archivedFilter],\n ]}\n onSelect={(id) => {\n if (id === 'workspace' || id === 'workspace-tree' || id === 'flat') onGroupPick(id)\n else if (id === 'manual' || id === 'updated') onOrderPick(id)\n else if (id === 'hide-archived') onArchivedFilterPick('default')\n else if (id === 'show-archived') onArchivedFilterPick('show')\n else if (id === 'only-archived') onArchivedFilterPick('only')\n setOpen(false)\n }}\n align=\"end\"\n dense\n listClassName={css.viewOptionsMenu}\n // Portal: the section header clips overflow, so an in-place list would\n // be cut off at the header's bounds.\n portal\n anchor={(\n <Tooltip label={t('viewOptions.label')} side=\"bottom\" delayMs={500}>\n <button\n type=\"button\"\n className={clsx(css.iconButton, css.wide)}\n aria-label={t('viewOptions.label')}\n onClick={() => { setOpen(v => !v) }}\n >\n <IconSlidersTwoOutlineRegular />\n </button>\n </Tooltip>\n )}\n />\n )\n}\n\n/** In-flight root-row drag: source identity plus the current insert marker. */\ninterface DragState {\n /** Workspace id, or {@link UNGROUPED_KEY} for the browser-local loose-session account. */\n accountKey: string\n sessionId: SessionNode['id']\n /** Source row was pinned at drag start; drop targets share the pinned block. */\n pinned: boolean\n /** Row the marker sits on and which half (insert above/below it). */\n over: { id: SessionNode['id']; half: 'before' | 'after' } | null\n}\n\n/** Apply a visible drop to the complete account without removing hidden members. */\nfunction sessionDragOrder(\n order: readonly SessionId[],\n rows: readonly SessionNode[],\n drag: DragState,\n over: NonNullable<DragState['over']>,\n): SessionId[] | undefined {\n const source = rows.find(row => row.id === drag.sessionId)\n const target = rows.find(row => row.id === over.id)\n if (source === undefined || target === undefined || source.blank\n || source.pinned !== drag.pinned || target.pinned !== drag.pinned\n || source.id === target.id || !order.includes(source.id)) return\n const section = rows.filter(row => row.pinned === drag.pinned)\n const sourceIndex = section.findIndex(row => row.id === source.id)\n const withoutSource = section.filter(row => row.id !== source.id)\n const insertAt = withoutSource.findIndex(row => row.id === target.id) + (over.half === 'after' ? 1 : 0)\n if (insertAt === sourceIndex) return\n const next = order.filter(id => id !== source.id)\n const targetIndex = next.indexOf(target.id)\n if (targetIndex === -1) return\n next.splice(targetIndex + (over.half === 'after' ? 1 : 0), 0, source.id)\n return pinCurrentBlank(next, rows.find(row => row.blank)?.id)\n}\n\n/** In-flight Workspace-row drag: source identity plus the current marker. */\ninterface WorkspaceDragState {\n workspaceId: WorkspaceId\n over: { id: WorkspaceId; half: 'before' | 'after' } | null\n}\n\n/** Resolve an insertion side across the Workspace header, descendants, and Sessions. */\nfunction workspaceGroupHalf(e: { clientY: number; currentTarget: HTMLElement }): 'before' | 'after' {\n const rect = e.currentTarget.getBoundingClientRect()\n return e.clientY < rect.top + rect.height / 2 ? 'before' : 'after'\n}\n\ntype SessionTreeProps = Pick<\n WorkspaceBrowserProps,\n 'useSessionStatus' | 'startSession' | 'open'\n | 'insertWorkspaceBefore' | 't' | 'usePanelInfo' | 'useBadgeSettings'\n> & PropsRenderSlots<\n | 'sidebar.workspaces.session.menu.item'\n | 'sidebar.workspaces.session.row.action'\n | 'sidebar.session.row.leading'\n | 'sidebar.session.row.hover'\n> & {\n shortcuts: readonly import('@deepseek-ai/dsh-client-shortcuts/client').ShortcutCatalogEntry[]\n /** Always-mounted Session list snapshot. */\n list: SessionListState\n /** Host account home for POSIX hover-path abbreviation. */\n home?: string | undefined\n /** Workspaces in Host group order with browser-projected Session order. */\n workspaces: readonly WorkspaceView[]\n /** Browser-projected order for Sessions outside every Workspace. */\n ungroupedSessionIds: readonly SessionId[]\n /** Whether the current Workspace stream has a complete Host baseline. */\n workspaceReady: boolean\n /** Grouping, ordering, and filter changes replace the view without row motion. */\n animationResetKey: string\n /** Nest Workspaces under their nearest registered ancestors. */\n nestWorkspaces: boolean\n /** Explicit persisted group expansion, including descendants in tree mode. */\n groupExpansion: Readonly<Record<string, boolean>>\n /** Persist one Workspace group's expansion. */\n setGroupExpanded: (key: string, expanded: boolean) => void\n /** Save a drag order and select Manual. */\n setSessionOrder: (accountKey: string, order: readonly string[]) => void\n /** Registry-global pin and archive sets plus the archived-visibility choice. */\n rowState: SessionRowState\n /** Switch the archived filter back to the default hide-archived view. */\n onLeaveArchivedOnly: () => void\n /** Open the browser-owned rename dialog for a real Workspace group. */\n onRenameRequest: (workspaceId: WorkspaceId, currentTitle: string) => void\n /** Open the browser-owned delete-confirmation dialog for a real Workspace group. */\n onDeleteRequest: (workspaceId: WorkspaceId, currentTitle: string) => void\n /** Open the rename dialog from a row title double-click. */\n onSessionRenameRequest: (sessionId: SessionNode['id'], currentTitle: string) => void\n /** One Session chosen from search that must be exposed and scrolled into view. */\n revealSessionId?: SessionId | undefined\n /** Acknowledge that the chosen Session row has been revealed. */\n onSessionRevealed: (sessionId: SessionId) => void\n}\n\n/** The list-empty placeholder — a glyph over the text; the archived-only view names its filter and offers the way back. */\nfunction EmptySessions({ rowState, onLeaveArchivedOnly, t }: Pick<SessionTreeProps, 'rowState' | 'onLeaveArchivedOnly' | 't'>) {\n const archivedOnly = rowState.archivedFilter === 'only'\n return (\n <div className={css.emptyState} data-row-key=\"empty\">\n {archivedOnly ? <IconArchiveOutlineRegular size={24} /> : <IconQueueOutlineRegular size={24} />}\n <div>{archivedOnly ? t('empty.noneArchived') : t('empty.none')}</div>\n {archivedOnly && (\n <button type=\"button\" className={css.emptyAction} onClick={onLeaveArchivedOnly}>\n {t('empty.viewOthers')}\n </button>\n )}\n </div>\n )\n}\n\n/** The scrolling session tree; unmounting drops the sessions subscription and local row limits. */\nfunction SessionTree({\n list, useSessionStatus, startSession, open, workspaces, ungroupedSessionIds,\n rowState, onLeaveArchivedOnly,\n workspaceReady, animationResetKey, usePanelInfo,\n onRenameRequest, onDeleteRequest, onSessionRenameRequest,\n renderSlot,\n insertWorkspaceBefore,\n nestWorkspaces, groupExpansion, setGroupExpanded,\n setSessionOrder, home, t,\n revealSessionId, onSessionRevealed, shortcuts, useBadgeSettings,\n}: SessionTreeProps) {\n const panelActive = usePanelInfo(info => info.activePanelId !== null)\n // 徽标设置:各来源显隐、悬停明细、数字样式。\n const badgeSettings = useBadgeSettings(settings => settings)\n const statuses = useSessionStatus(s => s)\n // 外部状态:一次订阅覆盖所有来源,版本号变即重渲染。`getVersion` 返回 number,\n // 引用天然稳定,不会像\"每次新建一个快照对象\"那样把订阅打成死循环(React #185)。\n useSyncExternalStore(facetsStore.subscribe, facetsStore.getVersion, facetsStore.getServerVersion)\n // 关掉的来源在**折叠之前**就筛掉:数字、图标、aria-label、悬停明细与\"要不要画徽标\"\n // 因此同源,不会出现在 label 里有、计数里没有的情况。\n const facets = useMemo(\n () => visibleFacets(facetsStore.list(), badgeSettings),\n [badgeSettings],\n )\n const current = panelActive\n ? undefined\n : Object.values(list.byId).find(session => (session.retainedBy.mainView ?? 0) > 0)?.id\n const revealGroup = revealSessionId === undefined || !workspaceReady\n ? undefined\n : owningGroupKey(workspaces, revealSessionId)\n const [sessionLimits, setSessionLimits] = useState<Readonly<Record<string, number>>>({})\n // Transient drag marker state; the selected mode owns the resulting order.\n const [drag, setDrag] = useState<DragState | null>(null)\n const sessionDropCommitted = useRef(false)\n const [workspaceDrag, setWorkspaceDrag] = useState<WorkspaceDragState | null>(null)\n const workspaceDropCommitted = useRef(false)\n const nativeDragActive = drag !== null || workspaceDrag !== null\n useNativeDragAcceptance(nativeDragActive)\n const currentGroup = current === undefined || !workspaceReady\n ? undefined\n : owningGroupKey(workspaces, current)\n useEffect(() => {\n if (current === undefined || currentGroup === undefined || Object.hasOwn(groupExpansion, currentGroup)) return\n setGroupExpanded(currentGroup, true)\n }, [current, currentGroup, setGroupExpanded, groupExpansion])\n const parents = useMemo(() => {\n if (!nestWorkspaces) return new Map<string, WorkspaceId | undefined>()\n const keysByPath = new Map(workspaces.map(workspace => [workspace.path, workspace.workspaceId]))\n const paths = [...keysByPath.keys()]\n return new Map<string, WorkspaceId | undefined>(workspaces.map((workspace) => {\n const path = owningParentFolder(workspace.path, paths)\n return [workspace.workspaceId, path === undefined ? undefined : keysByPath.get(path)]\n }))\n }, [nestWorkspaces, workspaces])\n const currentAncestors = useMemo(() => {\n const keys = new Set<string>()\n for (let key = currentGroup === undefined ? undefined : parents.get(currentGroup); key !== undefined; key = parents.get(key)) {\n keys.add(key)\n }\n return keys\n }, [currentGroup, parents])\n const expandedGroups = useMemo(() => {\n const ancestorKeys = new Set<string | undefined>(parents.values())\n return [...workspaces.map(workspace => workspace.workspaceId), UNGROUPED_KEY]\n .filter(key => groupExpansion[key] ?? ancestorKeys.has(key))\n }, [groupExpansion, parents, workspaces])\n const groups = useMemo(\n () => deriveGroups(list, workspaces, rowState, statuses, {\n expandedGroups,\n ungroupedOrder: ungroupedSessionIds,\n }),\n [list, workspaces, rowState, statuses, expandedGroups, ungroupedSessionIds],\n )\n useEffect(() => {\n for (let key = revealGroup; key !== undefined; key = parents.get(key)) {\n if (groupExpansion[key] === false || (key === revealGroup && groupExpansion[key] !== true)) {\n setGroupExpanded(key, true)\n }\n }\n }, [groupExpansion, parents, revealGroup, setGroupExpanded])\n useEffect(() => {\n if (revealSessionId === undefined || revealGroup === undefined) return\n const group = groups.find(candidate => candidate.key === revealGroup)\n if (group === undefined || !group.expanded || !group.sessions.some(row => row.id === revealSessionId)) return\n if (collapsedSessionRows(group.sessions).rows.some(row => row.id === revealSessionId)) return\n setSessionLimits(limits => limits[revealGroup] === Infinity ? limits : { ...limits, [revealGroup]: Infinity })\n }, [groups, revealGroup, revealSessionId])\n const now = Date.now()\n const commitSessionDrag = (activeDrag: DragState, over: NonNullable<DragState['over']>): void => {\n if (sessionDropCommitted.current) return\n sessionDropCommitted.current = true\n setDrag(null)\n const group = groups.find(candidate => candidate.key === activeDrag.accountKey)\n if (group === undefined) return\n if (over.id === activeDrag.sessionId) return\n const accountSessionIds = activeDrag.accountKey === UNGROUPED_KEY\n ? ungroupedSessionIds\n : workspaces.find(workspace => workspace.workspaceId === activeDrag.accountKey)?.sessionIds\n if (accountSessionIds === undefined) return\n const renderedSessions = collapsedSessionRows(group.sessions, sessionLimits[group.key]).rows\n const nextOrder = sessionDragOrder(accountSessionIds, renderedSessions, activeDrag, over)\n if (nextOrder !== undefined) setSessionOrder(activeDrag.accountKey, nextOrder)\n }\n const commitWorkspaceDrag = (\n activeDrag: WorkspaceDragState,\n over: NonNullable<WorkspaceDragState['over']>,\n ): void => {\n if (workspaceDropCommitted.current) return\n workspaceDropCommitted.current = true\n setWorkspaceDrag(null)\n const owner = parents.get(activeDrag.workspaceId)\n const siblings = workspaces.filter(workspace => parents.get(workspace.workspaceId) === owner)\n const rowIndex = siblings.findIndex(workspace => workspace.workspaceId === over.id)\n if (rowIndex === -1) return\n const anchor = over.half === 'before' ? over.id : siblings[rowIndex + 1]?.workspaceId\n if (anchor === activeDrag.workspaceId) return\n const sourceIndex = siblings.findIndex(workspace => workspace.workspaceId === activeDrag.workspaceId)\n const anchorIndex = anchor === undefined\n ? siblings.length\n : siblings.findIndex(workspace => workspace.workspaceId === anchor)\n if (sourceIndex !== -1 && (anchorIndex === sourceIndex || anchorIndex === sourceIndex + 1)) return\n insertWorkspaceBefore(activeDrag.workspaceId, anchor).catch((reason: unknown) => {\n console.warn('workspace reorder rejected:', reason)\n })\n }\n // Build tree structure from original groups (for aggregation traversal)\n const childrenByParentForAggregation = useMemo(() => {\n const rendered = new Set(groups.map(group => group.key))\n const children = new Map<string | undefined, GroupNode[]>()\n for (const group of groups) {\n let parent = parents.get(group.key)\n while (parent !== undefined && !rendered.has(parent)) parent = parents.get(parent)\n const siblings = children.get(parent)\n if (siblings === undefined) children.set(parent, [group])\n else siblings.push(group)\n }\n return children\n }, [groups, parents])\n\n // Fork-owned: each group's DIRECT member status — the input to the tree-wide\n // aggregation below. deriveGroups stopped computing liveStatus (PR #10 moved it\n // out), so this map is the aggregator's only data source. Expanded groups are\n // measured too; see directStatusesForGroups.\n const directStatusByGroup = useMemo(\n () => directStatusesForGroups(groups, facets, now),\n // `now` 刻意不进依赖:它是渲染期的时钟读数,唯一影响的是\"哪些截止还算将来\"。\n // 提供方的 store 到点会通知,需要新答案的那次渲染本来就带着新的 `now` 发生。\n [groups, facets],\n )\n\n // Multi-level aggregation: a collapsed folder's badge covers its own members plus\n // every descendant group's, at any depth. Every row comes back measured, so the\n // render path can never see an unresolved liveStatus.\n const groupsWithAggregatedStatus = useMemo(\n () => withAggregatedStatus(groups, directStatusByGroup, childrenByParentForAggregation),\n [groups, directStatusByGroup, childrenByParentForAggregation],\n )\n\n // Rebuild tree structure with aggregated groups (for rendering)\n const childrenByParent = useMemo(() => {\n const rendered = new Set(groupsWithAggregatedStatus.map(group => group.key))\n const children = new Map<string | undefined, StatusedGroupNode[]>()\n for (const group of groupsWithAggregatedStatus) {\n // The archived-only view drops empty groups, so an ancestor may be\n // absent; nest under the nearest rendered one.\n let parent = parents.get(group.key)\n while (parent !== undefined && !rendered.has(parent)) parent = parents.get(parent)\n const siblings = children.get(parent)\n if (siblings === undefined) children.set(parent, [group])\n else siblings.push(group)\n }\n return children\n }, [groupsWithAggregatedStatus, parents])\n\n const rootGroups = childrenByParent.get(undefined) ?? []\n const workspaceDropAtListStart = rootGroups[0]?.workspaceId !== undefined\n && workspaceDrag?.over?.id === rootGroups[0].workspaceId\n && workspaceDrag.over.half === 'before'\n\n const rowKeys: string[] = groupsWithAggregatedStatus.length === 0 ? ['empty'] : []\n const renderGroup = (group: StatusedGroupNode, depth: number): ReactNode => {\n const workspaceId = group.workspaceId\n const children = childrenByParent.get(group.key) ?? []\n const compatibleDrag = workspaceDrag !== null && parents.get(workspaceDrag.workspaceId) === parents.get(group.key)\n const collapsed = collapsedSessionRows(group.sessions)\n const visible = collapsedSessionRows(group.sessions, sessionLimits[group.key])\n const sessionsExpanded = visible.hiddenCount === 0\n rowKeys.push(`workspace:${group.key}`)\n const childRows = group.expanded ? children.map(child => renderGroup(child, depth + 1)) : []\n const sessions = visible.rows\n for (const node of sessions) rowKeys.push(`session:${node.id}`)\n if (collapsed.hiddenCount > 0) rowKeys.push(`overflow:${group.key}`)\n const workspaceMarker = workspaceId !== undefined && workspaceDrag?.over?.id === workspaceId\n ? workspaceDrag.over.half\n : null\n const workspaceDragProps = workspaceId === undefined ? undefined : {\n start: () => {\n workspaceDropCommitted.current = false\n setWorkspaceDrag({ workspaceId, over: null })\n },\n end: () => {\n if (workspaceDrag?.over !== null && workspaceDrag?.over !== undefined) {\n commitWorkspaceDrag(workspaceDrag, workspaceDrag.over)\n } else {\n setWorkspaceDrag(null)\n }\n workspaceDropCommitted.current = false\n },\n }\n const hoverWorkspace = workspaceId === undefined || !compatibleDrag\n ? undefined\n : (half: 'before' | 'after') => {\n setWorkspaceDrag(active => active === null\n ? active\n : { ...active, over: { id: workspaceId, half } })\n }\n const dropWorkspace = workspaceId === undefined || !compatibleDrag\n ? undefined\n : (half: 'before' | 'after') => {\n commitWorkspaceDrag(workspaceDrag, { id: workspaceId, half })\n }\n // group arrives from groupsWithAggregatedStatus: collapsed groups already\n // carry the bottom-up aggregated liveStatus (direct + all descendants).\n return (\n // Group section: header, descendant Workspaces, and own Session rows. The\n // inter-group breathing room is the section's own margin\n // (WorkspaceBrowser.module.css).\n <div\n key={group.key}\n style={{ '--dsh-workspace-indent': `${depth * 12}px` } as CSSProperties}\n className={clsx(\n css.groupSection,\n workspaceMarker === 'before' && css.workspaceDropBefore,\n workspaceMarker === 'after' && css.workspaceDropAfter,\n )}\n onDragOver={workspaceDrag === null\n ? undefined\n : (e) => {\n e.preventDefault()\n if (hoverWorkspace === undefined && parents.get(group.key) !== undefined) return\n e.stopPropagation()\n if (hoverWorkspace === undefined) {\n e.dataTransfer.dropEffect = 'none'\n if (workspaceDrag.over !== null) setWorkspaceDrag({ ...workspaceDrag, over: null })\n } else {\n e.dataTransfer.dropEffect = 'move'\n hoverWorkspace(workspaceGroupHalf(e))\n }\n }}\n onDrop={workspaceDrag === null\n ? undefined\n : (e) => {\n e.preventDefault()\n if (dropWorkspace === undefined && parents.get(group.key) !== undefined) return\n e.stopPropagation()\n if (dropWorkspace === undefined) {\n workspaceDropCommitted.current = true\n setWorkspaceDrag(null)\n } else {\n dropWorkspace(workspaceGroupHalf(e))\n }\n }}\n >\n <ProjectRowItem\n newShortcut={shortcuts.find(row => row.id === 'session.new')}\n group={group}\n containsCurrentDescendant={currentAncestors.has(group.key)}\n home={home}\n settings={badgeSettings}\n now={now}\n t={t}\n onToggle={() => {\n if (group.expanded) {\n setSessionLimits(limits => ({ ...limits, [group.key]: COLLAPSED_SESSION_LIMIT }))\n }\n setGroupExpanded(group.key, !group.expanded)\n }}\n onCreate={() => {\n if (group.workspaceId !== undefined) {\n setGroupExpanded(group.key, true)\n startSession(group.workspaceId)\n }\n }}\n drag={workspaceDragProps}\n actions={group.workspaceId === undefined\n ? undefined\n : {\n rename: () => {\n /* v8 ignore next -- narrowing guard: the actions object exists only for real-workspace groups. */\n if (group.workspaceId !== undefined) onRenameRequest(group.workspaceId, group.label)\n },\n delete: () => {\n /* v8 ignore next -- narrowing guard: the actions object exists only for real-workspace groups. */\n if (group.workspaceId !== undefined) onDeleteRequest(group.workspaceId, group.label)\n },\n }}\n />\n {childRows.length > 0 && (\n <div role=\"group\">\n {childRows}\n </div>\n )}\n {group.expanded && sessions.map((node) => {\n // Session drag never leaves its browser-local account, and pinned\n // rows reorder only within their leading pinned block.\n const sameGroupDrag = drag !== null && drag.accountKey === group.key\n const compatibleTarget = sameGroupDrag && drag.pinned === node.pinned\n const normalizeHalf = (half: 'before' | 'after'): 'before' | 'after' =>\n node.blank ? 'after' : half\n const dragProps = {\n start: () => {\n sessionDropCommitted.current = false\n setDrag({ accountKey: group.key, sessionId: node.id, pinned: node.pinned, over: null })\n },\n active: compatibleTarget,\n marker: sameGroupDrag && drag.over?.id === node.id ? drag.over.half : null,\n hover: (half: 'before' | 'after') => {\n /* v8 ignore next -- narrowing guard: Rows gates hover on `active`, which is false while the drag state is null. */\n setDrag(d => (d === null ? d : {\n ...d, over: { id: node.id, half: normalizeHalf(half) },\n }))\n },\n drop: (half: 'before' | 'after') => {\n /* v8 ignore next -- narrowing guard: Rows gates drop on `active`, which is false while the drag state is null. */\n if (drag === null) return\n commitSessionDrag(drag, { id: node.id, half: normalizeHalf(half) })\n },\n end: () => {\n if (drag?.over !== null && drag?.over !== undefined) commitSessionDrag(drag, drag.over)\n else setDrag(null)\n sessionDropCommitted.current = false\n },\n }\n return (\n <SessionNodeItem\n key={node.id}\n node={node}\n currentId={current}\n now={now}\n onOpen={open}\n onRenameRequest={onSessionRenameRequest}\n renderSlot={renderSlot}\n onReveal={node.id === revealSessionId && group.key === revealGroup\n ? () => { onSessionRevealed(node.id) }\n : undefined}\n drag={dragProps}\n t={t}\n />\n )\n })}\n {group.expanded && collapsed.hiddenCount > 0 && (\n <button\n type=\"button\"\n className={css.sessionOverflowButton}\n data-row-key={`overflow:${group.key}`}\n aria-expanded={sessionsExpanded}\n onClick={() => {\n setSessionLimits(limits => ({\n ...limits,\n [group.key]: sessionsExpanded\n ? COLLAPSED_SESSION_LIMIT\n : visible.hiddenCount <= COLLAPSED_SESSION_LIMIT\n ? Infinity\n : (limits[group.key] ?? COLLAPSED_SESSION_LIMIT) + COLLAPSED_SESSION_LIMIT,\n }))\n }}\n >\n {sessionsExpanded\n ? t('sessions.collapse')\n : t('sessions.expand', { n: visible.hiddenCount })}\n </button>\n )}\n </div>\n )\n }\n\n const groupRows = rootGroups.map(group => renderGroup(group, 0))\n return (\n <div className={clsx(css.treeBody, css.wide)}>\n {workspaceDropAtListStart && <span className={css.listTopDropIndicator} aria-hidden=\"true\" />}\n <AnimatedRows\n className={clsx(css.list, workspaceDropAtListStart && css.listTopDropActive)}\n label={t('section.sessions')}\n rowKeys={rowKeys}\n ready={list.phase === 'ready' && workspaceReady && !nativeDragActive}\n // Fork-owned: upstream also mixes `sessionLimits` into this key so that\n // revealing hidden rows settles instantly. But folding a group writes\n // sessionLimits too (reset to COLLAPSED_SESSION_LIMIT), which silently\n // suppressed the row fade-out on every collapse. Keep only the\n // view-replacement key so collapse/expand still animates.\n resetKey={animationResetKey}\n >\n {groupsWithAggregatedStatus.length === 0 && (\n <EmptySessions rowState={rowState} onLeaveArchivedOnly={onLeaveArchivedOnly} t={t} />\n )}\n {groupRows}\n </AnimatedRows>\n <span className={css.fade} />\n </div>\n )\n}\n\n/** The flat \"In one list\" body: every session is one draggable top-level row. */\nfunction FlatList({\n list, sessionIds, rowState, onLeaveArchivedOnly, useSessionStatus, open, onSessionRenameRequest,\n usePanelInfo, setSessionOrder, workspaceReady, animationResetKey,\n revealSessionId, onSessionRevealed, renderSlot, t,\n}: Pick<\n SessionTreeProps,\n | 'useSessionStatus'\n | 'open'\n | 'onSessionRenameRequest'\n | 'renderSlot'\n | 'usePanelInfo'\n | 'setSessionOrder'\n | 'workspaceReady'\n | 'animationResetKey'\n | 'revealSessionId'\n | 'onSessionRevealed'\n | 'rowState'\n | 'onLeaveArchivedOnly'\n | 't'\n> & {\n list: SessionListState\n sessionIds: readonly SessionId[]\n}) {\n const panelActive = usePanelInfo(info => info.activePanelId !== null)\n const statuses = useSessionStatus(s => s)\n const rows = useMemo(\n () => deriveFlat(list, sessionIds, rowState, statuses),\n [list, sessionIds, rowState, statuses],\n )\n const [drag, setDrag] = useState<DragState | null>(null)\n const dropCommitted = useRef(false)\n useNativeDragAcceptance(drag !== null)\n const currentId = panelActive\n ? undefined\n : Object.values(list.byId).find(session => (session.retainedBy.mainView ?? 0) > 0)?.id\n const commitDrag = (activeDrag: DragState, over: NonNullable<DragState['over']>): void => {\n if (dropCommitted.current) return\n dropCommitted.current = true\n setDrag(null)\n const nextOrder = sessionDragOrder(sessionIds, rows, activeDrag, over)\n if (nextOrder !== undefined) setSessionOrder(FLAT_SESSION_ORDER_KEY, nextOrder)\n }\n const now = Date.now()\n return (\n <div className={clsx(css.treeBody, css.wide)}>\n <AnimatedRows\n className={clsx(css.list, css.flatList)}\n label={t('section.sessions')}\n rowKeys={rows.length === 0 ? ['empty'] : rows.map(row => `session:${row.id}`)}\n ready={list.phase === 'ready' && workspaceReady && drag === null}\n resetKey={animationResetKey}\n >\n {rows.length === 0 && (\n <EmptySessions rowState={rowState} onLeaveArchivedOnly={onLeaveArchivedOnly} t={t} />\n )}\n {rows.map((node) => {\n const active = drag !== null && drag.pinned === node.pinned\n const normalizeHalf = (half: 'before' | 'after'): 'before' | 'after' =>\n node.blank ? 'after' : half\n return (\n <SessionNodeItem\n key={node.id}\n node={node}\n currentId={currentId}\n now={now}\n onOpen={open}\n onRenameRequest={onSessionRenameRequest}\n renderSlot={renderSlot}\n onReveal={node.id === revealSessionId\n ? () => { onSessionRevealed(node.id) }\n : undefined}\n drag={{\n start: () => {\n dropCommitted.current = false\n setDrag({ accountKey: FLAT_SESSION_ORDER_KEY, sessionId: node.id, pinned: node.pinned, over: null })\n },\n active,\n marker: active && drag.over?.id === node.id ? drag.over.half : null,\n hover: (half) => {\n setDrag(current => current === null ? current : {\n ...current, over: { id: node.id, half: normalizeHalf(half) },\n })\n },\n drop: (half) => {\n if (drag !== null) commitDrag(drag, { id: node.id, half: normalizeHalf(half) })\n },\n end: () => {\n if (drag?.over !== null && drag?.over !== undefined) commitDrag(drag, drag.over)\n else setDrag(null)\n dropCommitted.current = false\n },\n }}\n t={t}\n />\n )\n })}\n </AnimatedRows>\n <span className={css.fade} />\n </div>\n )\n}\n\ninterface RemoteSearchState {\n query: string\n status: 'idle' | 'loading' | 'ready' | 'error'\n items: readonly SessionSearchResultItem[]\n hasMore: boolean\n}\n\n/** Flat search body: local metadata matches plus the current Host result page. */\nfunction SearchResults({\n useSessions,\n useSessionStatus,\n open,\n onUnarchive,\n workspaces,\n archivedSessionIds,\n archivedFilter,\n query,\n remote,\n resultLimit,\n usePanelInfo,\n t,\n}: Pick<WorkspaceBrowserProps, 'useSessions' | 'useSessionStatus' | 'open' | 't' | 'usePanelInfo'> & {\n workspaces: readonly WorkspaceView[]\n archivedSessionIds: readonly SessionNode['id'][]\n /** Search matches follow the archived filter selected for the list. */\n archivedFilter: ArchivedFilter\n /** Unarchive an archived result row in place. */\n onUnarchive: (id: SessionNode['id']) => void\n query: string\n remote: RemoteSearchState\n resultLimit: number\n}) {\n const panelActive = usePanelInfo(info => info.activePanelId !== null)\n const list = useSessions(s => s)\n const statuses = useSessionStatus(s => s)\n const currentRemote = remote.query === query\n ? remote\n : { query, status: 'loading' as const, items: [], hasMore: false }\n const results = useMemo(\n () => deriveSearchResults(\n list,\n workspaces,\n query,\n archivedSessionIds,\n archivedFilter,\n statuses,\n currentRemote,\n resultLimit,\n ),\n [list, workspaces, query, archivedSessionIds, archivedFilter, statuses, currentRemote, resultLimit],\n )\n const pending = currentRemote.status === 'loading'\n const currentId = panelActive\n ? undefined\n : Object.values(list.byId).find(session => (session.retainedBy.mainView ?? 0) > 0)?.id\n\n return (\n <div className={clsx(css.treeBody, css.wide)}>\n <div className={css.list}>\n <div className={css.searchTree} role=\"tree\" aria-label={t('search.results.aria')}>\n {results.items.map(result => (\n <SearchResultItem\n key={result.id}\n result={result}\n currentId={currentId}\n onOpen={open}\n onUnarchive={onUnarchive}\n t={t}\n />\n ))}\n </div>\n {pending && (\n /* Two skeleton rows on an empty list, one when local matches already\n show and only the content hits are outstanding. */\n <div role=\"status\" aria-label={t('search.pending')}>\n {(results.items.length === 0 ? [0, 1] : [0]).map(i => (\n <div key={i} className={css.skeletonRow} aria-hidden=\"true\">\n <span className={css.skeletonDot} />\n <span className={css.skeletonBars}>\n <span className={css.skeletonBar} />\n <span className={clsx(css.skeletonBar, css.skeletonBarWide)} />\n </span>\n </div>\n ))}\n </div>\n )}\n {!pending && results.items.length === 0 && (\n <div className={css.empty}>{t('search.noMatches')}</div>\n )}\n {results.hasMore && (\n <div className={css.searchStatus}>\n {t('search.hasMore', { n: resultLimit })}\n </div>\n )}\n </div>\n <span className={css.fade} />\n </div>\n )\n}\n\n/**\n * Render the browsing region.\n * @param props - composed slot props (shell owner share + store + injected actions).\n * @returns the region element tree.\n */\nexport function WorkspaceBrowser({\n wide,\n usePanelInfo,\n expandSidebar,\n useSessions,\n useSessionStatus,\n useWorkspaces,\n useStore,\n actions,\n startSession,\n open,\n requestSessionRename,\n notifyArchivedNotOpenable,\n renameWorkspace,\n deleteWorkspace,\n insertWorkspaceBefore,\n unarchiveSession,\n createWorkspace,\n searchSessions,\n searchResultLimit,\n useDirectoryFlow,\n useHostInfo,\n useShortcuts,\n useWorkspaceShortcuts,\n useBadgeSettings,\n requestSearch,\n requestAddWorkspace,\n closeAddWorkspace,\n setDirectoryBusy,\n dismissForkError,\n renderSlot,\n t,\n}: WorkspaceBrowserProps) {\n const home = useHostInfo(info => info.home)\n const shortcuts = useShortcuts(rows => rows)\n const searchShortcut = shortcuts.find(row => row.id === 'session.search')\n const addShortcut = shortcuts.find(row => row.id === 'workspace.add')\n const shortcutState = useWorkspaceShortcuts(state => state)\n // Ordering remains live while the rail or search replaces the list body.\n const list = useSessions(state => state)\n const storedWorkspaces = useWorkspaces(state => state.items)\n // The resolved name, not `t`, is the memo dependency: the bound seat keeps\n // its identity across a language switch.\n const defaultWorkspaceName = t('workspace.defaultName')\n const workspaces = useMemo(\n () => storedWorkspaces.map(workspace => ({\n ...workspace,\n title: workspaceDisplayTitle(workspace.title, defaultWorkspaceName),\n })),\n [storedWorkspaces, defaultWorkspaceName],\n )\n const workspacePhase = useWorkspaces(state => state.phase)\n const workspaceStreamState = useWorkspaces(state => state.state)\n const archivedSessionIds = useWorkspaces(state => state.archivedSessionIds)\n const pinnedSessionIds = useWorkspaces(state => state.pinnedSessionIds)\n // Live occupancy of this surface's directory-flow hole (the same source the\n // flow reads): a composition without a picking affordance can add nothing.\n const directoryFlowAvailable = useDirectoryFlow(occupied => occupied)\n const groupBy = useStore(s => s.groupBy)\n const orderBy = useStore(s => s.orderBy)\n // Persisted view blobs written before the archived filter existed rehydrate\n // without the field; they read as the default hide-archived view.\n const archivedFilter = useStore(s => s.archivedFilter ?? 'default')\n const groupExpansion = useStore(s => s.groupExpansion)\n const sessionOrderByAccount = useStore(s => s.sessionOrderByAccount)\n // Archived sessions are not openable: the row stays visible under the\n // filter but a click explains instead of navigating.\n const guardedOpen = (sessionId: SessionId): void => {\n if (archivedSessionIds.includes(sessionId)) {\n notifyArchivedNotOpenable()\n return\n }\n open(sessionId)\n }\n const leaveArchivedOnly = (): void => { actions.setArchivedFilter('default') }\n const workspaceReady = workspacePhase === 'ready' && workspaceStreamState !== 'loading'\n const mainSessionId = Object.values(list.byId)\n .find(session => (session.retainedBy.mainView ?? 0) > 0)?.id\n const currentBlank = mainSessionId !== undefined && list.byId[mainSessionId]?.blank === true\n ? mainSessionId\n : undefined\n const ungroupedMemberIds = useMemo(() => {\n const accounted = new Set(workspaces.flatMap(workspace => workspace.sessionIds))\n return list.ids.filter(id => list.byId[id] !== undefined && !accounted.has(id))\n }, [list, workspaces])\n const orderState = useMemo(\n () => ({ pinnedSessionIds, archivedSessionIds }),\n [archivedSessionIds, pinnedSessionIds],\n )\n const rowState = useMemo<SessionRowState>(\n () => ({ ...orderState, archivedFilter }),\n [orderState, archivedFilter],\n )\n const flatMemberIds = useMemo(() => sessionMemberIds(list), [list])\n const orderedWorkspaces = useMemo(() => workspaces.map((workspace) => {\n const memberIds = workspace.sessionIds\n const baseOrder = orderBy === 'updated'\n ? orderByRecency(memberIds, list.byId)\n : reconcileManualOrder(memberIds, sessionOrderByAccount[workspace.workspaceId], list.byId, orderState)\n return {\n ...workspace,\n sessionIds: pinCurrentBlank(\n baseOrder,\n currentBlank !== undefined && memberIds.includes(currentBlank) ? currentBlank : undefined,\n ),\n }\n }), [currentBlank, list.byId, orderBy, orderState, sessionOrderByAccount, workspaces])\n const orderedUngroupedSessionIds = useMemo(() => {\n const baseOrder = orderBy === 'updated'\n ? orderByRecency(ungroupedMemberIds, list.byId)\n : reconcileManualOrder(ungroupedMemberIds, sessionOrderByAccount[UNGROUPED_KEY], list.byId, orderState)\n return pinCurrentBlank(\n baseOrder,\n currentBlank !== undefined && ungroupedMemberIds.includes(currentBlank) ? currentBlank : undefined,\n )\n }, [currentBlank, list.byId, orderBy, orderState, sessionOrderByAccount, ungroupedMemberIds])\n const orderedFlatSessionIds = useMemo(() => {\n const baseOrder = orderBy === 'updated'\n ? orderByRecency(flatMemberIds, list.byId)\n : reconcileManualOrder(flatMemberIds, sessionOrderByAccount[FLAT_SESSION_ORDER_KEY], list.byId, orderState)\n return pinCurrentBlank(\n baseOrder,\n currentBlank !== undefined && flatMemberIds.includes(currentBlank) ? currentBlank : undefined,\n )\n }, [currentBlank, flatMemberIds, list.byId, orderBy, orderState, sessionOrderByAccount])\n const activeSessionOrders = useMemo<Readonly<Record<string, readonly SessionId[]>>>(() => Object.fromEntries([\n ...orderedWorkspaces.map(workspace => [workspace.workspaceId, workspace.sessionIds] as const),\n [UNGROUPED_KEY, orderedUngroupedSessionIds] as const,\n [FLAT_SESSION_ORDER_KEY, orderedFlatSessionIds] as const,\n ]), [orderedFlatSessionIds, orderedUngroupedSessionIds, orderedWorkspaces])\n useEffect(() => {\n if (workspacePhase !== 'ready') return\n actions.retainAccountKeys([\n UNGROUPED_KEY,\n FLAT_SESSION_ORDER_KEY,\n ...workspaces.map(workspace => workspace.workspaceId),\n ])\n }, [actions.retainAccountKeys, workspacePhase, workspaces])\n useEffect(() => {\n if (list.phase !== 'ready' || workspaceReady || orderBy !== 'manual' || currentBlank === undefined) return\n // A first prompt can end blank pinning before the Workspace baseline arrives.\n // Preserve saved members until that baseline can establish departures.\n const changed: Record<string, readonly string[]> = {}\n for (const [key, ids] of Object.entries(activeSessionOrders)) {\n if (key !== FLAT_SESSION_ORDER_KEY && workspacePhase !== 'ready') continue\n const saved = sessionOrderByAccount[key] ?? []\n if (ids[0] !== currentBlank || saved[0] === currentBlank) continue\n changed[key] = [currentBlank, ...saved.filter(id => id !== currentBlank)]\n }\n if (Object.keys(changed).length > 0) actions.syncSessionOrders(changed)\n }, [\n actions.syncSessionOrders,\n activeSessionOrders,\n currentBlank,\n list.phase,\n orderBy,\n sessionOrderByAccount,\n workspacePhase,\n workspaceReady,\n ])\n useEffect(() => {\n if (list.phase !== 'ready' || !workspaceReady || orderBy !== 'manual' || currentBlank === undefined) return\n const moved = Object.entries(activeSessionOrders).some(([key, ids]) =>\n ids[0] === currentBlank && sessionOrderByAccount[key]?.[0] !== currentBlank)\n if (moved) actions.syncSessionOrders(activeSessionOrders)\n }, [\n actions.syncSessionOrders,\n activeSessionOrders,\n currentBlank,\n list.phase,\n orderBy,\n sessionOrderByAccount,\n workspaceReady,\n ])\n const saveSessionOrder = (accountKey: string, order: readonly string[]): void => {\n actions.setSessionOrder(accountKey, order, activeSessionOrders)\n }\n // The query outlives the tree and the input (both wide-only) so collapsing\n // does not silently drop an in-progress filter.\n const [query, setQuery] = useState('')\n const [searchExpanded, setSearchExpanded] = useState(false)\n const [revealSessionId, setRevealSessionId] = useState<SessionId | undefined>(undefined)\n const normalizedQuery = sanitizeSearchQuery(query).trim()\n const [remoteSearch, setRemoteSearch] = useState<RemoteSearchState>({\n query: '',\n status: 'idle',\n items: [],\n hasMore: false,\n })\n const searchRoot = useRef<HTMLDivElement | null>(null)\n const searchInput = useRef<HTMLInputElement | null>(null)\n // Section-header + opens the picker menu (same popover in wide and rail\n // states; the menu anchors on this button).\n const wsPickerOpen = shortcutState.addRequested\n const wsPlusRef = useRef<HTMLButtonElement>(null)\n const composingRef = useRef(false)\n\n const openSearchResult = (sessionId: SessionId): void => {\n if (archivedSessionIds.includes(sessionId)) {\n notifyArchivedNotOpenable()\n return\n }\n setRevealSessionId(sessionId)\n setQuery('')\n setSearchExpanded(false)\n open(sessionId)\n }\n const acknowledgeSessionReveal = (sessionId: SessionId): void => {\n setRevealSessionId(current => current === sessionId ? undefined : current)\n }\n useEffect(() => {\n if (normalizedQuery !== '') setRevealSessionId(undefined)\n }, [normalizedQuery])\n\n // Rail search = expand + land in the search box: the flag arms before the\n // expand request; once the shell flips wide the input mounts and takes focus.\n const [searchOnExpand, setSearchOnExpand] = useState(false)\n useEffect(() => {\n if (wide && searchOnExpand) {\n const timer = window.setTimeout(() => {\n searchInput.current?.focus({ preventScroll: true })\n setSearchOnExpand(false)\n }, EXPAND_SLIDE_MS)\n return () => { window.clearTimeout(timer) }\n }\n }, [wide, searchOnExpand])\n useEffect(() => {\n if (shortcutState.searchRequest === 0) return\n closeAddWorkspace()\n setSearchExpanded(true)\n if (!wide) {\n setSearchOnExpand(true)\n expandSidebar()\n } else searchInput.current?.focus({ preventScroll: true })\n }, [shortcutState.searchRequest])\n\n useEffect(() => {\n if (!wide || !searchExpanded || searchOnExpand) return\n searchInput.current?.focus({ preventScroll: true })\n }, [wide, searchExpanded, searchOnExpand])\n\n // Outside-click dismissal stays off while the rail gesture is in flight\n // (searchOnExpand): the rail click flips the shell wide and mounts this\n // listener during its own dispatch, then keeps bubbling to document with\n // the now-unmounted rail button as its target — outside searchRoot, so the\n // listener would dismiss the search that click just opened.\n useEffect(() => {\n if (!wide || !searchExpanded || searchOnExpand) return\n const onClick = (event: MouseEvent): void => {\n if (!(event.target instanceof Node) || searchRoot.current?.contains(event.target) === true) return\n searchInput.current?.blur()\n if (normalizedQuery !== '') return\n setSearchExpanded(false)\n }\n document.addEventListener('click', onClick)\n return () => { document.removeEventListener('click', onClick) }\n }, [normalizedQuery, wide, searchExpanded, searchOnExpand])\n\n useEffect(() => {\n if (normalizedQuery === '') {\n setRemoteSearch({ query: '', status: 'idle', items: [], hasMore: false })\n return\n }\n const controller = new AbortController()\n setRemoteSearch({\n query: normalizedQuery,\n status: 'loading',\n items: [],\n hasMore: false,\n })\n const timer = window.setTimeout(() => {\n searchSessions(normalizedQuery, controller.signal).then((result) => {\n if (controller.signal.aborted) return\n setRemoteSearch({\n query: normalizedQuery,\n status: 'ready',\n items: result.items,\n hasMore: result.hasMore,\n })\n }).catch(() => {\n if (controller.signal.aborted) return\n setRemoteSearch({\n query: normalizedQuery,\n status: 'error',\n items: [],\n hasMore: false,\n })\n })\n }, SEARCH_DEBOUNCE_MS)\n return () => {\n window.clearTimeout(timer)\n controller.abort()\n }\n }, [normalizedQuery, searchSessions])\n\n // Rename dialog (browser-owned so it outlives row unmounts during collapse).\n // The stored title decides whether confirming is a real rename; the draft is\n // seeded with the label on screen. They differ for a Workspace still\n // carrying its automatic title, so confirming the prefill pins that name.\n const [renameTarget, setRenameTarget] = useState<{ workspaceId: WorkspaceId; storedTitle: string } | null>(null)\n const [renameDraft, setRenameDraft] = useState('')\n const [renaming, setRenaming] = useState(false)\n const [renameError, setRenameError] = useState<string | null>(null)\n const renameTrimmed = renameDraft.trim()\n // Self is excluded by identity, not by title: the draft is seeded with the\n // localized label, which for an automatically titled Workspace equals its\n // own displayed title without being a conflict with itself.\n const renameDuplicate = renameTarget !== null && renameTrimmed !== ''\n && workspaces.some(w => w.workspaceId !== renameTarget.workspaceId && w.title === renameTrimmed)\n const renameBlocked = renaming || renameTrimmed === ''\n || renameTarget === null || renameTrimmed === renameTarget.storedTitle || renameDuplicate\n const closeRename = () => {\n if (renaming) return\n setRenameTarget(null)\n setRenameError(null)\n }\n const confirmRename = () => {\n if (renameBlocked) return\n setRenaming(true)\n setRenameError(null)\n renameWorkspace(renameTarget.workspaceId, renameTrimmed).then(() => {\n setRenaming(false)\n setRenameTarget(null)\n }).catch((reason: unknown) => {\n setRenaming(false)\n setRenameError(reason instanceof Error ? reason.message : String(reason))\n })\n }\n\n // The search results' restore button; the row actions own the rest of the\n // Session verbs as slot entries.\n const onSessionUnarchive = (sessionId: SessionNode['id']) => {\n unarchiveSession(sessionId).catch((reason: unknown) => {\n console.warn('session unarchive rejected:', reason)\n })\n }\n\n // Delete dialog is separate from the row so a successful removal can\n // unmount that row without tearing down the in-flight confirmation state.\n const [deleteTarget, setDeleteTarget] = useState<{ workspaceId: WorkspaceId; title: string } | null>(null)\n const [deleting, setDeleting] = useState(false)\n const [deleteCommittedId, setDeleteCommittedId] = useState<WorkspaceId | null>(null)\n const [deleteError, setDeleteError] = useState<string | null>(null)\n useEffect(() => {\n if (deleteCommittedId === null\n || workspaces.some(workspace => workspace.workspaceId === deleteCommittedId)) return\n setDeleting(false)\n setDeleteCommittedId(null)\n setDeleteTarget(null)\n }, [deleteCommittedId, workspaces])\n const closeDelete = () => {\n if (deleting) return\n setDeleteTarget(null)\n setDeleteError(null)\n }\n const confirmDelete = () => {\n /* v8 ignore next -- the Modal is absent without a target and its button is disabled while deleting. */\n if (deleting || deleteTarget === null) return\n setDeleting(true)\n setDeleteCommittedId(null)\n setDeleteError(null)\n deleteWorkspace(deleteTarget.workspaceId).then(() => {\n // Keep the confirmation pending until this component has rendered the\n // committed list projection without the deleted id. Closing earlier\n // exposes one stale React frame to the next Create Workspace gesture.\n setDeleteCommittedId(deleteTarget.workspaceId)\n }).catch((reason: unknown) => {\n setDeleting(false)\n setDeleteError(reason instanceof Error ? reason.message : String(reason))\n })\n }\n\n return (\n <div className={clsx(css.root, !wide && css.rail)}>\n <div className={css.sectionHeader}>\n {wide && (\n <span className={clsx(css.sectionLabel, css.wide, searchExpanded && css.sectionLabelHidden)}>\n {groupBy === 'flat' ? t('section.sessions') : t('section.workspaces')}\n </span>\n )}\n {wide && (\n <div className={clsx(css.searchSlot, searchExpanded && css.searchSlotExpanded)}>\n <div\n ref={searchRoot}\n className={clsx(css.search, searchExpanded && css.searchExpanded)}\n onClick={() => {\n closeAddWorkspace()\n setSearchExpanded(true)\n searchInput.current?.focus()\n }}\n >\n <Tooltip label={t('search')} shortcutKeys={searchShortcut?.keys} side=\"bottom\" delayMs={500} disabled={searchExpanded}>\n <button\n type=\"button\"\n className={css.searchButton}\n aria-label={t('search.sessions.aria')}\n aria-keyshortcuts={searchShortcut?.aria}\n aria-expanded={searchExpanded}\n onClick={() => {\n requestSearch()\n }}\n >\n <IconSearchOutlineRegular size={searchExpanded ? 11 : 14} />\n </button>\n </Tooltip>\n <input\n ref={searchInput}\n className={css.searchInput}\n type=\"text\"\n placeholder={t('search.placeholder')}\n maxLength={SEARCH_QUERY_MAX_CODE_UNITS}\n value={query}\n tabIndex={searchExpanded ? 0 : -1}\n onChange={(e) => { setQuery(sanitizeSearchQuery(e.target.value)) }}\n onKeyDown={(e) => {\n if (e.key !== 'Escape') return\n setQuery('')\n setSearchExpanded(false)\n }}\n />\n {searchExpanded && (\n <button\n type=\"button\"\n className={css.clearButton}\n aria-label={t('search.clear')}\n onClick={(e) => {\n e.stopPropagation()\n setQuery('')\n setSearchExpanded(false)\n }}\n >\n <IconCloseFillRegular />\n </button>\n )}\n </div>\n </div>\n )}\n <div className={clsx(css.headerActions, wide && searchExpanded && css.headerActionsHidden)}>\n {wide && (\n <ViewOptionsMenu\n groupBy={groupBy}\n orderBy={orderBy}\n archivedFilter={archivedFilter}\n onGroupPick={actions.setGroupBy}\n onOrderPick={(mode) => { actions.setOrderBy(mode, activeSessionOrders) }}\n onArchivedFilterPick={actions.setArchivedFilter}\n t={t}\n />\n )}\n {/* Adding is the button's one action, so a composition with no\n picking affordance has nothing to offer here: the region hides the\n button rather than leaving a dead one in the header. */}\n {directoryFlowAvailable && (\n <Tooltip label={t('workspace.add')} shortcutKeys={addShortcut?.keys} side=\"bottom\" delayMs={500}>\n <button\n ref={wsPlusRef}\n type=\"button\"\n className={css.iconButton}\n aria-label={t('workspace.add')}\n aria-keyshortcuts={addShortcut?.aria}\n onClick={() => {\n requestAddWorkspace()\n }}\n >\n <IconProjectAddOutlineRegular size={wide ? 16 : 18} />\n </button>\n </Tooltip>\n )}\n </div>\n {/* Add flow + its error dialog (same package — direct composition). */}\n <WorkspacePickFlow\n t={t}\n open={wsPickerOpen}\n anchorRef={wsPlusRef}\n useWorkspaces={useWorkspaces}\n createWorkspace={createWorkspace}\n useDirectoryFlow={useDirectoryFlow}\n renderDirectoryFlow={owner => renderSlot('sidebar.workspaces.directoryFlow', owner)}\n addOnly\n onBusyChange={setDirectoryBusy}\n side=\"right\"\n onPick={(workspaceId) => {\n closeAddWorkspace()\n startSession(workspaceId)\n }}\n onClose={() => { closeAddWorkspace() }}\n />\n </div>\n\n {/* The collapsed rail keeps search as its own 36px control. */}\n {!wide && <div className={css.search}>\n <Tooltip label={t('search')} shortcutKeys={searchShortcut?.keys}>\n <button\n type=\"button\"\n className={css.searchButton}\n aria-label={t('search.sessions.aria')}\n aria-keyshortcuts={searchShortcut?.aria}\n onClick={() => {\n requestSearch()\n }}\n >\n <IconSearchOutlineRegular size={18} />\n </button>\n </Tooltip>\n </div>}\n\n {/* Always-mounted seat keeps the region's flex slot while the list\n itself is wide-only. */}\n <div className={css.listArea}>\n {wide && (normalizedQuery !== ''\n ? (\n <SearchResults\n usePanelInfo={usePanelInfo}\n useSessions={useSessions}\n useSessionStatus={useSessionStatus}\n open={openSearchResult}\n onUnarchive={onSessionUnarchive}\n workspaces={workspaces}\n archivedSessionIds={archivedSessionIds}\n archivedFilter={archivedFilter}\n query={normalizedQuery}\n remote={remoteSearch}\n resultLimit={searchResultLimit}\n t={t}\n />\n )\n : groupBy === 'flat'\n ? (\n <FlatList\n usePanelInfo={usePanelInfo}\n list={list}\n sessionIds={orderedFlatSessionIds}\n rowState={rowState}\n onLeaveArchivedOnly={leaveArchivedOnly}\n workspaceReady={workspaceReady}\n animationResetKey={`${groupBy}/${orderBy}/${archivedFilter}`}\n useSessionStatus={useSessionStatus}\n open={guardedOpen}\n onSessionRenameRequest={requestSessionRename}\n renderSlot={renderSlot}\n setSessionOrder={saveSessionOrder}\n revealSessionId={revealSessionId}\n onSessionRevealed={acknowledgeSessionReveal}\n t={t}\n />\n )\n : (\n <SessionTree\n usePanelInfo={usePanelInfo}\n useBadgeSettings={useBadgeSettings}\n list={list}\n shortcuts={shortcuts}\n useSessionStatus={useSessionStatus}\n onSessionRenameRequest={requestSessionRename}\n renderSlot={renderSlot}\n workspaces={orderedWorkspaces}\n ungroupedSessionIds={orderedUngroupedSessionIds}\n workspaceReady={workspaceReady}\n nestWorkspaces={groupBy === 'workspace-tree'}\n animationResetKey={`${groupBy}/${orderBy}/${archivedFilter}`}\n groupExpansion={groupExpansion}\n setGroupExpanded={actions.setGroupExpanded}\n setSessionOrder={saveSessionOrder}\n rowState={rowState}\n onLeaveArchivedOnly={leaveArchivedOnly}\n startSession={startSession}\n open={guardedOpen}\n insertWorkspaceBefore={insertWorkspaceBefore}\n revealSessionId={revealSessionId}\n onSessionRevealed={acknowledgeSessionReveal}\n home={home}\n t={t}\n onRenameRequest={(workspaceId, displayTitle) => {\n setRenameTarget({\n workspaceId,\n storedTitle: storedWorkspaces.find(w => w.workspaceId === workspaceId)?.title ?? displayTitle,\n })\n setRenameDraft(displayTitle)\n setRenameError(null)\n }}\n onDeleteRequest={(workspaceId, title) => {\n setDeleteTarget({ workspaceId, title })\n setDeleteError(null)\n }}\n />\n ))}\n </div>\n\n <Modal\n open={renameTarget !== null}\n onClose={closeRename}\n closeLabel={t('close')}\n title={t('rename.workspace.title')}\n footer={(\n <>\n <Button variant=\"outline\" disabled={renaming} onClick={closeRename}>{t('cancel')}</Button>\n <Button variant=\"primary\" disabled={renameBlocked} onClick={confirmRename}>{t('rename')}</Button>\n </>\n )}\n >\n <input\n className={css.renameInput}\n value={renameDraft}\n aria-label={t('field.workspaceName')}\n data-modal-autofocus\n disabled={renaming}\n onFocus={(e) => { e.target.select() }}\n onChange={(e) => { setRenameDraft(e.target.value); setRenameError(null) }}\n onCompositionStart={() => { composingRef.current = true }}\n onCompositionEnd={() => { composingRef.current = false }}\n onKeyDown={(e) => {\n if (e.key === 'Enter' && !composingRef.current) {\n e.preventDefault()\n confirmRename()\n }\n }}\n />\n {renameDuplicate && (\n <div className={css.renameError} role=\"alert\">{t('conflict.named', { name: renameTrimmed })}</div>\n )}\n {renameError !== null && <div className={css.renameError} role=\"alert\">{renameError}</div>}\n </Modal>\n\n <Modal\n open={deleteTarget !== null}\n onClose={closeDelete}\n closeLabel={t('close')}\n title={t('delete.workspace')}\n {...deleteTarget === null\n ? {}\n : { description: t('delete.desc', { name: deleteTarget.title }) }}\n footer={(\n <>\n <Button variant=\"outline\" disabled={deleting} onClick={closeDelete}>{t('cancel')}</Button>\n <Button\n variant=\"outline\"\n className={css.deleteAction}\n disabled={deleting}\n onClick={confirmDelete}\n >\n {t('delete.workspace')}\n </Button>\n </>\n )}\n >\n {deleting && <div className={css.deleteStatus} role=\"status\">{t('delete.pending')}</div>}\n {deleteError !== null && <div className={css.renameError} role=\"alert\">{deleteError}</div>}\n </Modal>\n {shortcutState.forkError !== null && <Toast key={shortcutState.forkError.seq}\n text={t(shortcutState.forkError.reason === 'unavailable' ? 'shortcut.noCompletedTurn' : 'shortcut.forkFailed')}\n onDone={dismissForkError} />}\n </div>\n )\n}\n","/**\n * The archive action: a `sidebar.workspaces.session.menu.item` row and a\n * `sidebar.workspaces.session.row.action` button over one injected behavior,\n * plus the `shell.overlay` dialog that confirms stopping a Session's running\n * work before archiving it. The same entries restore an archived row; the\n * notice a successful archive raises and the diagnostics for Host rejections\n * live in the injected callbacks, not here.\n */\nimport { useState } from 'react'\nimport type { SessionActivity } from '@deepseek-ai/dsh-api-workspace-controller/client'\n// Type-only: the family keys each provider merges; a key this program did not compile takes the generic line.\nimport type {} from '@deepseek-ai/dsh-agent/types'\nimport type {} from '@deepseek-ai/dsh-jobs/view'\nimport type {} from '@deepseek-ai/dsh-schedule/client'\nimport type {} from '@deepseek-ai/dsh-subagent/client'\nimport {\n Button, IconArchiveOutlineRegular, IconUnarchiveOutlineRegular, MenuItemButton, Modal, Tooltip,\n} from '@deepseek-ai/dsh-client-ui-primitives'\nimport type {\n ArchiveSessionInjected, SessionArchiveConfirmInjected, SessionArchiveConfirmProps, SessionArchiveConfirmRequest,\n SessionMenuItemProps, SessionRowActionProps,\n} from '../contract/slots.ts'\nimport css from '../rows/Rows.module.css'\nimport browserCss from '../rows/WorkspaceBrowser.module.css'\n\n/**\n * Menu row (order 400): archive, or restore an archived row.\n * @param props - owner share, the archive share, and the menu open state.\n * @returns the row.\n */\nexport function ArchiveSessionMenuItem({\n sessionId, useArchived, useMenuOpenState, useShortcuts, archiveSession, unarchiveSession, t,\n}: SessionMenuItemProps<ArchiveSessionInjected>) {\n const [, setMenuOpen] = useMenuOpenState()\n const shortcut = useShortcuts(rows => rows.find(row => row.id === 'session.archive'))\n const archived = useArchived(set => set.has(sessionId))\n return (\n <MenuItemButton\n shortcut={archived ? undefined : shortcut}\n icon={archived ? <IconUnarchiveOutlineRegular size={14} /> : <IconArchiveOutlineRegular size={14} />}\n onSelect={() => {\n setMenuOpen(false)\n ;(archived ? unarchiveSession : archiveSession)(sessionId)\n }}\n >\n {t(archived ? 'menu.unarchiveSession' : 'menu.archiveSession')}\n </MenuItemButton>\n )\n}\n\n/**\n * Hover button (order 100): archive, or restore an archived row.\n * @param props - owner share and the archive share.\n * @returns the button.\n */\nexport function ArchiveSessionRowButton({\n sessionId, useArchived, archiveSession, unarchiveSession, t,\n}: SessionRowActionProps<ArchiveSessionInjected>) {\n const archived = useArchived(set => set.has(sessionId))\n return (\n <Tooltip label={t(archived ? 'actions.unarchive' : 'actions.archive')} side=\"bottom\" align=\"end\" delayMs={500}>\n <button\n type=\"button\"\n className={css.iconButton}\n aria-label={t(archived ? 'menu.unarchiveSession' : 'menu.archiveSession')}\n onClick={() => { (archived ? unarchiveSession : archiveSession)(sessionId) }}\n >\n {archived ? <IconUnarchiveOutlineRegular size={14} /> : <IconArchiveOutlineRegular size={14} />}\n </button>\n </Tooltip>\n )\n}\n\n/**\n * The `shell.overlay` entry: nothing while no confirmation is pending,\n * otherwise one dialog per request (keyed by the Session). Confirming asks\n * the Host to stop the listed work and archive; cancelling leaves the\n * Session running and visible.\n * @param props - the request hook, its settlement, the stop-and-archive hop, and the locale seat.\n * @returns the open dialog, or null.\n */\nexport function SessionArchiveConfirmDialog({\n useArchiveRequest, settleSessionArchive, stopAndArchiveSession, t,\n}: SessionArchiveConfirmProps) {\n const request = useArchiveRequest(pending => pending)\n if (request === null) return null\n return (\n <ArchiveConfirmForm\n key={request.sessionId}\n request={request}\n stopAndArchiveSession={stopAndArchiveSession}\n onSettle={settleSessionArchive}\n t={t}\n />\n )\n}\n\n/** One request's dialog: in-flight and error state die with it. */\nfunction ArchiveConfirmForm({ request, stopAndArchiveSession, onSettle, t }: {\n request: SessionArchiveConfirmRequest\n stopAndArchiveSession: SessionArchiveConfirmInjected['stopAndArchiveSession']\n onSettle: () => void\n t: SessionArchiveConfirmProps['t']\n}) {\n const [archiving, setArchiving] = useState(false)\n const [error, setError] = useState<string | null>(null)\n const close = () => {\n if (archiving) return\n onSettle()\n }\n const confirm = () => {\n setArchiving(true)\n setError(null)\n stopAndArchiveSession(request.sessionId).then(() => {\n setArchiving(false)\n onSettle()\n }).catch((reason: unknown) => {\n setArchiving(false)\n setError(reason instanceof Error ? reason.message : String(reason))\n })\n }\n return (\n <Modal\n open\n onClose={close}\n closeLabel={t('close')}\n title={t('archive.confirm.title')}\n description={t('archive.confirm.desc', { title: request.displayTitle })}\n footer={(\n <>\n <Button variant=\"outline\" disabled={archiving} onClick={close}>{t('cancel')}</Button>\n <Button\n variant=\"outline\"\n className={browserCss.deleteAction}\n disabled={archiving}\n onClick={confirm}\n >\n {t('archive.confirm.action')}\n </Button>\n </>\n )}\n >\n <ul className={browserCss.archiveActivity} aria-label={t('archive.confirm.activity')}>\n {request.activity.map((entry, index) => (\n <li key={`${entry.kind}-${String(index)}`}>{activityLine(entry, t)}</li>\n ))}\n </ul>\n {archiving && <div className={browserCss.deleteStatus} role=\"status\">{t('archive.confirm.pending')}</div>}\n {error !== null && <div className={browserCss.renameError} role=\"alert\">{error}</div>}\n </Modal>\n )\n}\n\n/**\n * One family's line: its count and the items' labels (ids when a family\n * carries no label). A family this dictionary does not know — a provider\n * merged into the kind map — falls through to the generic line.\n */\nfunction activityLine(entry: SessionActivity, t: SessionArchiveConfirmProps['t']): string {\n const items = entry.items ?? []\n const n = items.length\n const names = items.map(item => item.label ?? item.id).join(t('archive.confirm.listSeparator'))\n const plural = n === 1 ? 'one' : 'other'\n switch (entry.kind) {\n case 'turn': return t('archive.confirm.turn')\n case 'subagent': return t(`archive.confirm.subagents.${plural}`, { n, names })\n case 'job': return t(`archive.confirm.jobs.${plural}`, { n, names })\n case 'schedule': return t(`archive.confirm.schedules.${plural}`, { n, names })\n default: return t(`archive.confirm.other.${plural}`, { kind: entry.kind, n })\n }\n}\n","/** Derived observable sources for the row actions' injected hooks. */\nimport type { HostObservable } from '@deepseek-ai/dsh-client-ui-slots'\n\n/**\n * Project one observable into another, recomputing only when the source\n * snapshot changes identity, so consumers that select from the projection\n * (a Set lookup per row) never rebuild it per read.\n * @param source - the observable to project.\n * @param project - pure projection of one source snapshot.\n * @returns the projected observable, subscribing through the source.\n */\nexport function derive<S, T>(source: HostObservable<S>, project: (snapshot: S) => T): HostObservable<T> {\n let seen: S | undefined\n let value: T | undefined\n return {\n getSnapshot: () => {\n const snapshot = source.getSnapshot()\n if (value === undefined || snapshot !== seen) {\n seen = snapshot\n value = project(snapshot)\n }\n return value\n },\n subscribe: listener => source.subscribe(listener),\n }\n}\n","/** The fork action: one `sidebar.workspaces.session.menu.item` row. */\nimport { IconBranchOutlineRegular, MenuItemButton } from '@deepseek-ai/dsh-client-ui-primitives'\nimport type { ForkSessionInjected, SessionMenuItemProps } from '../contract/slots.ts'\n\n/**\n * Menu row (order 300): fork at the Session's last completed turn; the child\n * arrives through the Host list beside its source.\n * @param props - owner share, menu open state, and the fork share.\n * @returns the row.\n */\nexport function ForkSessionMenuItem({\n sessionId, useMenuOpenState, useShortcuts, forkSession, t,\n}: SessionMenuItemProps<ForkSessionInjected>) {\n const [, setMenuOpen] = useMenuOpenState()\n const shortcut = useShortcuts(rows => rows.find(row => row.id === 'session.fork'))\n return (\n <MenuItemButton\n shortcut={shortcut}\n icon={<IconBranchOutlineRegular />}\n onSelect={() => {\n setMenuOpen(false)\n forkSession(sessionId)\n }}\n >\n {t('menu.fork')}\n </MenuItemButton>\n )\n}\n","/**\n * The pin action: a `sidebar.workspaces.session.menu.item` row and a\n * `sidebar.workspaces.session.row.action` button over one injected behavior.\n * Pin and archive are mutually exclusive on the Host, so the action reads both\n * sets and does not offer itself on an archived row; what a pin does beyond\n * the Host call (fronting the Session in its saved orders, the failure\n * notice) lives in the injected callbacks, not here.\n */\nimport {\n IconPinFillRegular, IconPinOutlineRegular, MenuItemButton, Tooltip,\n} from '@deepseek-ai/dsh-client-ui-primitives'\nimport type { PinSessionInjected, SessionMenuItemProps, SessionRowActionProps } from '../contract/slots.ts'\nimport css from '../rows/Rows.module.css'\n\ntype PinState = Pick<SessionMenuItemProps<PinSessionInjected>, 'sessionId' | 'usePinned' | 'useArchived'>\n\n/** The row's pin and archive membership, one Set lookup each. */\nfunction usePinState({ sessionId, usePinned, useArchived }: PinState) {\n return {\n pinned: usePinned(pinned => pinned.has(sessionId)),\n archived: useArchived(archived => archived.has(sessionId)),\n }\n}\n\n/**\n * Menu row (order 100): pin or unpin by the row's current state; absent on archived rows.\n * @param props - owner share, the pin share, and the menu open state.\n * @returns the row, or null for an archived Session.\n */\nexport function PinSessionMenuItem(props: SessionMenuItemProps<PinSessionInjected>) {\n const { sessionId, useMenuOpenState, pinSession, unpinSession, t } = props\n const [, setMenuOpen] = useMenuOpenState()\n const { pinned, archived } = usePinState(props)\n if (archived) return null\n return (\n <MenuItemButton\n icon={pinned ? <IconPinFillRegular /> : <IconPinOutlineRegular />}\n onSelect={() => {\n setMenuOpen(false)\n ;(pinned ? unpinSession : pinSession)(sessionId)\n }}\n >\n {t(pinned ? 'menu.unpinSession' : 'menu.pinSession')}\n </MenuItemButton>\n )\n}\n\n/**\n * Hover button (order 200, rightmost: it lands where the rest-state pin marker sits); absent on archived rows.\n * @param props - owner share and the pin share.\n * @returns the button, or null for an archived Session.\n */\nexport function PinSessionRowButton(props: SessionRowActionProps<PinSessionInjected>) {\n const { sessionId, pinSession, unpinSession, t } = props\n const { pinned, archived } = usePinState(props)\n if (archived) return null\n return (\n <Tooltip label={t(pinned ? 'actions.unpin' : 'actions.pin')} side=\"bottom\" align=\"end\" delayMs={500}>\n <button\n type=\"button\"\n className={css.iconButton}\n aria-label={t(pinned ? 'menu.unpinSession' : 'menu.pinSession')}\n onClick={() => { (pinned ? unpinSession : pinSession)(sessionId) }}\n >\n {pinned ? <IconPinFillRegular size={14} /> : <IconPinOutlineRegular size={14} />}\n </button>\n </Tooltip>\n )\n}\n","/**\n * The rename action: a `sidebar.workspaces.session.menu.item` row that raises\n * the rename request, and the `shell.overlay` dialog entry that answers it.\n * The dialog lives outside the row menu because the row unmounts with the\n * menu; the browser raises the same request from a title double-click.\n */\nimport { useRef, useState } from 'react'\nimport { Button, IconEditOutlineRegular, MenuItemButton, Modal } from '@deepseek-ai/dsh-client-ui-primitives'\nimport type {\n RenameSessionInjected, SessionMenuItemProps, SessionRenameDialogInjected, SessionRenameDialogProps, SessionRenameTarget,\n} from '../contract/slots.ts'\nimport css from '../rows/WorkspaceBrowser.module.css'\n\n/**\n * Menu row (order 200): ask for the rename dialog, seeded with the row's current title.\n * @param props - owner share, menu open state, and the rename share.\n * @returns the row.\n */\nexport function RenameSessionMenuItem({\n sessionId, displayTitle, useMenuOpenState, useShortcuts, requestSessionRename, t,\n}: SessionMenuItemProps<RenameSessionInjected>) {\n const [, setMenuOpen] = useMenuOpenState()\n const shortcut = useShortcuts(rows => rows.find(row => row.id === 'session.rename'))\n return (\n <MenuItemButton\n shortcut={shortcut}\n icon={<IconEditOutlineRegular />}\n onSelect={() => {\n setMenuOpen(false)\n requestSessionRename(sessionId, displayTitle)\n }}\n >\n {t('rename')}\n </MenuItemButton>\n )\n}\n\n/**\n * The `shell.overlay` entry: nothing while no rename is requested, otherwise\n * one dialog per request (keyed by the Session, so a new request starts a\n * fresh draft). Sessions have no client-side name-conflict rule (the host\n * normalizes), and unlike Workspace rename an unchanged title is NOT\n * blocked. An unnamed Session starts with an empty draft and requires a name.\n * @param props - the request hook, its settlement, the rename hop, and the locale seat.\n * @returns the open dialog, or null.\n */\nexport function SessionRenameDialog({ useRenameRequest, settleSessionRename, renameSession, t }: SessionRenameDialogProps) {\n const request = useRenameRequest(pending => pending)\n if (request === null) return null\n return (\n <RenameForm\n key={request.sessionId}\n request={request}\n renameSession={renameSession}\n onSettle={settleSessionRename}\n t={t}\n />\n )\n}\n\n/** One request's dialog: the draft seeds from the request on mount; in-flight and error state die with it. */\nfunction RenameForm({ request, renameSession, onSettle, t }: {\n request: SessionRenameTarget\n renameSession: SessionRenameDialogInjected['renameSession']\n onSettle: () => void\n t: SessionRenameDialogProps['t']\n}) {\n const [draft, setDraft] = useState(request.currentTitle)\n const [renaming, setRenaming] = useState(false)\n const [error, setError] = useState<string | null>(null)\n // IME composition: Enter that commits a composition must not submit.\n const composingRef = useRef(false)\n const trimmed = draft.trim()\n const blocked = renaming || trimmed === ''\n const close = () => {\n if (renaming) return\n onSettle()\n }\n const confirm = () => {\n if (blocked) return\n setRenaming(true)\n setError(null)\n renameSession(request.sessionId, trimmed).then(() => {\n setRenaming(false)\n onSettle()\n }).catch((reason: unknown) => {\n setRenaming(false)\n setError(reason instanceof Error ? reason.message : String(reason))\n })\n }\n return (\n <Modal\n open\n onClose={close}\n closeLabel={t('close')}\n title={t('rename.session.title')}\n footer={(\n <>\n <Button variant=\"outline\" disabled={renaming} onClick={close}>{t('cancel')}</Button>\n <Button variant=\"primary\" disabled={blocked} onClick={confirm}>{t('rename')}</Button>\n </>\n )}\n >\n <input\n className={css.renameInput}\n value={draft}\n aria-label={t('field.sessionName')}\n data-modal-autofocus\n disabled={renaming}\n onFocus={(e) => { e.target.select() }}\n onChange={(e) => { setDraft(e.target.value); setError(null) }}\n onCompositionStart={() => { composingRef.current = true }}\n onCompositionEnd={() => { composingRef.current = false }}\n onKeyDown={(e) => {\n if (e.key === 'Enter' && !composingRef.current) {\n e.preventDefault()\n confirm()\n }\n }}\n />\n {error !== null && <div className={css.renameError} role=\"alert\">{error}</div>}\n </Modal>\n )\n}\n","/**\n * The `shell.overlay` entry for Workspace and Session notices.\n * One notice is visible at a time; a parent rerender does not extend its hold.\n */\nimport { IconWarningOutlineRegular, Toast } from '@deepseek-ai/dsh-client-ui-primitives'\nimport { assertNever } from '@deepseek-ai/dsh-util-values'\nimport type { RowToastProps, RowToastState } from '../contract/slots.ts'\n\n/**\n * Hold for the notices that take longer to read than a one-line warning: the\n * actionable archived notice (two buttons to react to) and a refused Session\n * creation, which quotes the Host's reason.\n */\nconst LONG_TOAST_HOLD_MS = 6000\n\n/**\n * Render the current notice: the archived and stopped-and-archived notices\n * with their undo action — plus the show-archived action while archived rows\n * are hidden — on a 6 s hold, a refused Session creation with the Host's\n * reason on the same hold, or a plain warning for a failed pin, an archived\n * row that was clicked, or default Workspace creation.\n * @param props - the notice hook, the shared viewing store, the notice dismissal, the two archived-notice actions, and the locale seat.\n * @returns the notice on display, or null.\n */\nexport function RowActionToast({ useToast, useStore, dismissToast, undoArchive, showArchived, t }: RowToastProps) {\n const toast = useToast(current => current)\n const archivedRowsVisible = useStore(state => (state.archivedFilter ?? 'default') !== 'default')\n if (toast === null) return null\n if (toast.kind === 'archived' || toast.kind === 'stoppedAndArchived') {\n const { sessionId } = toast\n return (\n <Toast\n key={`toast-${String(toast.seq)}`}\n text={t(toast.kind === 'archived' ? 'toast.archived' : 'toast.stoppedAndArchived')}\n tone=\"success\"\n holdMs={LONG_TOAST_HOLD_MS}\n actions={[\n { label: t('toast.archivedUndo'), onClick: () => { dismissToast(); undoArchive(sessionId) } },\n ...archivedRowsVisible ? [] : [\n { prefix: t('toast.archivedOr'), label: t('toast.archivedFilter'), onClick: () => { dismissToast(); showArchived() } },\n ],\n ]}\n onDone={dismissToast}\n />\n )\n }\n if (toast.kind === 'createFailed') {\n return (\n <Toast\n key={`toast-${String(toast.seq)}`}\n text={t('toast.createFailed', { message: toast.message })}\n icon={<IconWarningOutlineRegular />}\n holdMs={LONG_TOAST_HOLD_MS}\n onDone={dismissToast}\n />\n )\n }\n return (\n <Toast\n key={`toast-${String(toast.seq)}`}\n text={plainNoticeText(toast, t)}\n icon={<IconWarningOutlineRegular />}\n onDone={dismissToast}\n />\n )\n}\n\n/** The copy of one plain warning, keyed by the notice kind the union closes over. */\nfunction plainNoticeText(\n toast: Exclude<RowToastState, { kind: 'archived' | 'stoppedAndArchived' | 'createFailed' }>,\n t: RowToastProps['t'],\n): string {\n switch (toast.kind) {\n case 'pinFailed': return t('toast.pinFailed')\n case 'unpinFailed': return t('toast.unpinFailed')\n case 'defaultWorkspaceFailed': return t('defaultWorkspace.failed')\n case 'archivedNotOpenable': return t('toast.archivedNotOpenable')\n /* v8 ignore next 2 -- closed-union backstop; only reached if a notice kind is forged */\n default:\n return assertNever(toast)\n }\n}\n","/**\n * `workspace` namespace dictionaries: the browsing region (section header,\n * search, tree rows, dialogs) and the pick/add flow. Runtime failure\n * messages (wire error strings) pass through untranslated by policy.\n */\n\n/** Simplified Chinese dictionary (the key-set source of truth). */\nexport const zh = {\n 'defaultWorkspace.failed': '无法创建默认工作区,请通过“选择工作区”选择文件夹',\n 'group.ungrouped': '未分组',\n 'session.new': '新会话',\n 'session.untitled': '未命名',\n 'shortcut.noSession': '请先选择一个会话',\n 'shortcut.noPicker': '目录选择器不可用',\n 'shortcut.directoryBusy': '正在选择或添加工作区',\n 'shortcut.noCompletedTurn': '当前会话没有已结束的轮次',\n 'shortcut.forkFailed': '无法分叉会话,请重试',\n 'section.workspaces': '工作区',\n 'section.sessions': '会话',\n 'viewOptions.label': '视图选项',\n 'groupBy.label': '分组方式',\n 'groupBy.workspace': '按工作区',\n 'groupBy.workspaceTree': '按工作区树',\n 'groupBy.flat': '单列表',\n 'orderBy.label': '排序方式',\n 'orderBy.manual': '手动排序',\n 'orderBy.updated': '最近更新',\n 'filterBy.label': '筛选会话',\n 'viewOptions.hideArchived': '隐藏已归档',\n 'viewOptions.showArchived': '全部对话(显示已归档)',\n 'viewOptions.onlyArchived': '仅显示已归档',\n 'sessions.expand': '展开其余 {n} 个会话',\n 'sessions.collapse': '收起',\n 'empty.none': '暂无会话',\n 'empty.noneArchived': '暂无已归档会话',\n 'empty.viewOthers': '查看其他会话',\n 'empty.noMatches': '无匹配结果',\n 'workspace.add': '添加工作区',\n 'search.sessions.aria': '搜索会话',\n 'search.placeholder': '搜索会话名称',\n 'search.clear': '清除搜索',\n 'search.results.aria': '搜索结果',\n 'search.pending': '正在搜索会话历史…',\n 'search.noMatches': '无匹配会话',\n 'search.hasMore': '仅显示前 {n} 条结果,请缩小搜索范围。',\n 'menu.addWorkspace': '添加工作区…',\n 'picker.loading': '正在加载工作区…',\n 'conflict.named': '已存在名为“{name}”的工作区。',\n 'folderError.title': '无法打开文件夹',\n 'folderError.retry': '重新选择',\n 'rename': '重命名',\n 'rename.workspace.title': '重命名工作区',\n 'rename.session.title': '重命名会话',\n 'field.workspaceName': '工作区名称',\n 'field.sessionName': '会话名称',\n 'delete.workspace': '删除工作区',\n 'delete.desc': '将把“{name}”从工作区列表中移除。文件夹与会话记录会保留,其会话将显示在“未分组”下。',\n 'delete.pending': '正在删除工作区…',\n 'menu.fork': '分叉会话',\n 'menu.archiveSession': '归档会话',\n 'menu.unarchiveSession': '取消归档',\n 'menu.pinSession': '置顶会话',\n 'menu.unpinSession': '取消置顶',\n 'row.archived': '已归档',\n 'row.pinned': '已置顶',\n 'toast.archivedNotOpenable': '已归档对话暂时无法查看,请取消归档后查看',\n 'toast.archived': '会话已归档,可',\n 'toast.stoppedAndArchived': '已停止并归档,可',\n 'archive.confirm.title': '停止并归档此会话?',\n 'archive.confirm.desc': '“{title}”仍有正在进行的工作。归档会先停止这些工作;之后可在侧栏筛选“全部对话(显示已归档)”中恢复会话,被停止的工作不会自动继续。',\n 'archive.confirm.activity': '将被停止的工作',\n 'archive.confirm.turn': '进行中的回合',\n 'archive.confirm.subagents.one': '{n} 个运行中的子智能体:{names}',\n 'archive.confirm.subagents.other': '{n} 个运行中的子智能体:{names}',\n 'archive.confirm.jobs.one': '{n} 个后台任务:{names}',\n 'archive.confirm.jobs.other': '{n} 个后台任务:{names}',\n 'archive.confirm.schedules.one': '{n} 条定时提醒:{names}',\n 'archive.confirm.schedules.other': '{n} 条定时提醒:{names}',\n 'archive.confirm.other.one': '{n} 项其他工作({kind})',\n 'archive.confirm.other.other': '{n} 项其他工作({kind})',\n 'archive.confirm.listSeparator': '、',\n 'archive.confirm.action': '停止并归档',\n 'archive.confirm.pending': '正在停止并归档…',\n 'toast.archivedUndo': '撤销',\n 'toast.archivedOr': '或',\n 'toast.archivedFilter': '筛选已归档会话',\n 'toast.pinFailed': '置顶失败,请稍后重试',\n 'toast.unpinFailed': '取消置顶失败,请稍后重试',\n 'toast.createFailed': '新建会话失败:{message}',\n 'sessions.count.one': '{n} 个会话',\n 'sessions.count.other': '{n} 个会话',\n 'actions.workspace.aria': '工作区“{name}”的操作',\n 'actions.session.aria': '会话“{name}”的操作',\n 'actions.archive': '归档会话',\n 'actions.unarchive': '取消归档',\n 'actions.pin': '置顶会话',\n 'actions.unpin': '取消置顶',\n 'actions.newSession': '新会话',\n 'actions.newSession.aria': '在“{name}”中新建会话',\n 'status.running': '进行中',\n 'status.subagentsRunning.one': '{n} 个子智能体运行中',\n 'status.subagentsRunning.other': '{n} 个子智能体运行中',\n 'status.idle': '空闲',\n 'status.waitingApproval': '等待审批',\n 'status.planReview': '计划待审',\n 'status.waitingAnswer': '等待回答',\n 'status.compact.approval': '待审批',\n 'status.compact.planReview': '计划待审',\n 'status.compact.answer': '待回答',\n 'status.needsAttention': '需要关注',\n 'status.completed': '已完成',\n 'hover.created': '创建于 {time}',\n 'hover.copied': '已复制',\n 'date.ymd': '{y}年{m}月{d}日',\n 'time.now': '刚刚',\n 'time.minutes': '{n}分钟',\n 'time.hours': '{n}小时',\n 'time.days': '{n}天',\n 'time.months': '{n}个月',\n 'time.years': '{n}年',\n 'time.ago': '{t}前',\n 'settings.badge.section': '折叠徽标',\n 'settings.badge.showRunning': '显示「进行中」转圈',\n 'settings.badge.showRunningHint': '关闭后,进行中的会话(含子智能体)不再画转圈,也不再计入折叠徽标的数字与悬停明细。',\n 'settings.badge.showPending': '显示「待审批」黄点',\n 'settings.badge.showPendingHint': '关闭后,等待审批 / 计划评审 / 等待回答的会话不再画黄点,也不再计入折叠徽标的数字与悬停明细。',\n 'settings.badge.showCompleted': '显示「已完成」绿点',\n 'settings.badge.showCompletedHint': '关闭后,「已完成」的会话不再画绿点,也不再计入折叠徽标的数字与悬停明细。会话行自身的绿点不受影响。',\n 'settings.badge.showScheduled': '显示「定时任务」时钟',\n 'settings.badge.showScheduledHint': '关闭后,带定时提醒的会话(来自 dsh-later)不再画时钟图标,也不再计入折叠徽标的数字与悬停明细。',\n 'settings.badge.showWaitingReview': '显示「等待评审」沙漏',\n 'settings.badge.showWaitingReviewHint': '关闭后,等待代码评审的会话(来自 dsh-gitea-dispatch)不再画沙漏图标,也不再计入折叠徽标的数字与悬停明细。',\n 'settings.hover.section': '悬停明细',\n 'settings.hover.showDetails': '显示状态明细行',\n 'settings.hover.showDetailsHint': '关闭后,悬停卡只显示工作区标题、路径和创建时间——不再显示聚合状态明细行。',\n 'settings.count.section': '数字显示',\n 'settings.count.threshold': '数字显示阈值',\n 'settings.count.thresholdHint': '数量 >= 此值时才在徽标上显示数字。默认 2(即 count=1 时省略,因为状态点已表达\"有东西\")。设为 1 则始终显示。',\n 'settings.save': '保存',\n 'settings.saving': '保存中…',\n 'settings.saveFailed': '本部署没有接受这些值,已保留供你修改。',\n 'settings.readOnly': '本部署的设置为只读。',\n 'settings.unavailable': '该插件当前未加载,暂时无法配置。',\n} satisfies Record<string, string>\n\n/** The workspace namespace key union. */\nexport type WorkspaceKey = keyof typeof zh\n\n/** English dictionary, checked complete against the zh key set. */\nexport const en = {\n 'defaultWorkspace.failed': 'Unable to create default workspace. Use Choose workspace to select a folder.',\n 'group.ungrouped': 'Ungrouped',\n 'session.new': 'New Session',\n 'session.untitled': 'Untitled',\n 'shortcut.noSession': 'Select a session first',\n 'shortcut.noPicker': 'Directory picker unavailable',\n 'shortcut.directoryBusy': 'Selecting or adding a workspace',\n 'shortcut.noCompletedTurn': 'This session has no completed turn',\n 'shortcut.forkFailed': 'Could not fork the session. Try again.',\n 'section.workspaces': 'Workspaces',\n 'section.sessions': 'Sessions',\n 'viewOptions.label': 'View options',\n 'groupBy.label': 'Group by',\n 'groupBy.workspace': 'WorkSpace',\n 'groupBy.workspaceTree': 'Workspace Tree',\n 'groupBy.flat': 'In one list',\n 'orderBy.label': 'Order by',\n 'orderBy.manual': 'Manual',\n 'orderBy.updated': 'Last updated',\n 'filterBy.label': 'Filter sessions',\n 'viewOptions.hideArchived': 'Hide archived',\n 'viewOptions.showArchived': 'All conversations (show archived)',\n 'viewOptions.onlyArchived': 'Archived only',\n 'sessions.expand': 'Show {n} more sessions',\n 'sessions.collapse': 'Show less',\n 'empty.none': 'No sessions yet',\n 'empty.noneArchived': 'No archived sessions yet',\n 'empty.viewOthers': 'View other sessions',\n 'empty.noMatches': 'No matches',\n 'workspace.add': 'Add workspace',\n 'search.sessions.aria': 'Search sessions',\n 'search.placeholder': 'Search session names',\n 'search.clear': 'Clear search',\n 'search.results.aria': 'Search results',\n 'search.pending': 'Searching session history…',\n 'search.noMatches': 'No matching sessions',\n 'search.hasMore': 'Showing the first {n} results. Narrow your search.',\n 'menu.addWorkspace': 'Add workspace…',\n 'picker.loading': 'Loading workspaces…',\n 'conflict.named': 'A workspace named “{name}” already exists.',\n 'folderError.title': 'Couldn’t open folder',\n 'folderError.retry': 'Choose again',\n 'rename': 'Rename',\n 'rename.workspace.title': 'Rename workspace',\n 'rename.session.title': 'Rename session',\n 'field.workspaceName': 'Workspace name',\n 'field.sessionName': 'Session name',\n 'delete.workspace': 'Delete workspace',\n 'delete.desc': 'This removes “{name}” from the workspace list. The folder and session logs will be kept. Its sessions will appear under Ungrouped.',\n 'delete.pending': 'Deleting workspace…',\n 'menu.fork': 'Fork session',\n 'menu.archiveSession': 'Archive session',\n 'menu.unarchiveSession': 'Unarchive session',\n 'menu.pinSession': 'Pin session',\n 'menu.unpinSession': 'Unpin session',\n 'row.archived': 'Archived',\n 'row.pinned': 'Pinned',\n 'toast.archivedNotOpenable': 'Archived sessions cannot be opened. Unarchive it to view.',\n 'toast.archived': 'Session archived. You can ',\n 'toast.stoppedAndArchived': 'Session stopped and archived. You can ',\n 'archive.confirm.title': 'Stop and archive this session?',\n 'archive.confirm.desc': '“{title}” still has work in progress. Archiving stops it first; you can restore the session later from the “All conversations (show archived)” filter in the sidebar, and the stopped work will not resume on its own.',\n 'archive.confirm.activity': 'Work that will be stopped',\n 'archive.confirm.turn': 'The turn in progress',\n 'archive.confirm.subagents.one': '{n} running subagent: {names}',\n 'archive.confirm.subagents.other': '{n} running subagents: {names}',\n 'archive.confirm.jobs.one': '{n} background job: {names}',\n 'archive.confirm.jobs.other': '{n} background jobs: {names}',\n 'archive.confirm.schedules.one': '{n} scheduled reminder: {names}',\n 'archive.confirm.schedules.other': '{n} scheduled reminders: {names}',\n 'archive.confirm.other.one': '{n} other item of work ({kind})',\n 'archive.confirm.other.other': '{n} other items of work ({kind})',\n 'archive.confirm.listSeparator': ', ',\n 'archive.confirm.action': 'Stop and archive',\n 'archive.confirm.pending': 'Stopping and archiving…',\n 'toast.archivedUndo': 'undo',\n 'toast.archivedOr': ' or ',\n 'toast.archivedFilter': 'filter archived sessions',\n 'toast.pinFailed': 'Pin failed. Try again later.',\n 'toast.unpinFailed': 'Unpin failed. Try again later.',\n 'toast.createFailed': 'New session failed: {message}',\n 'sessions.count.one': '{n} session',\n 'sessions.count.other': '{n} sessions',\n 'actions.workspace.aria': 'Workspace actions for {name}',\n 'actions.session.aria': 'Session actions for {name}',\n 'actions.archive': 'Archive',\n 'actions.unarchive': 'Unarchive',\n 'actions.pin': 'Pin',\n 'actions.unpin': 'Unpin',\n 'actions.newSession': 'New session',\n 'actions.newSession.aria': 'New session in {name}',\n 'status.running': 'Running',\n 'status.subagentsRunning.one': '{n} subagent running',\n 'status.subagentsRunning.other': '{n} subagents running',\n 'status.idle': 'Idle',\n 'status.waitingApproval': 'Waiting for approval',\n 'status.planReview': 'Plan awaiting review',\n 'status.waitingAnswer': 'Waiting for answer',\n 'status.compact.approval': 'Approval',\n 'status.compact.planReview': 'Plan review',\n 'status.compact.answer': 'Answer',\n 'status.needsAttention': 'Needs attention',\n 'status.completed': 'Completed',\n 'hover.created': 'Created {time}',\n 'hover.copied': 'Copied',\n 'date.ymd': '{y}-{m}-{d}',\n 'time.now': 'now',\n 'time.minutes': '{n}min',\n 'time.hours': '{n}h',\n 'time.days': '{n}d',\n 'time.months': '{n}mo',\n 'time.years': '{n}y',\n 'time.ago': '{t} ago',\n 'settings.badge.section': 'Collapsed badge',\n 'settings.badge.showRunning': 'Show the running dot',\n 'settings.badge.showRunningHint': 'When off, running Sessions (and subagents) stop drawing the spinning dot and drop out of the collapsed badge count and its hover details.',\n 'settings.badge.showPending': 'Show the pending dot',\n 'settings.badge.showPendingHint': 'When off, Sessions waiting for approval / plan review / answer stop drawing the yellow dot and drop out of the collapsed badge count and its hover details.',\n 'settings.badge.showCompleted': 'Show the completed dot',\n 'settings.badge.showCompletedHint': 'When off, completed Sessions stop drawing the dot and drop out of the collapsed badge count and its hover details. The Session row\\'s own dot is unaffected.',\n 'settings.badge.showScheduled': 'Show the scheduled icon',\n 'settings.badge.showScheduledHint': 'When off, Sessions with scheduled reminders (from dsh-later) stop drawing the clock icon and drop out of the collapsed badge count and its hover details.',\n 'settings.badge.showWaitingReview': 'Show the waiting-for-review icon',\n 'settings.badge.showWaitingReviewHint': 'When off, Sessions waiting for code review (from dsh-gitea-dispatch) stop drawing the hourglass icon and drop out of the collapsed badge count and its hover details.',\n 'settings.hover.section': 'Hover details',\n 'settings.hover.showDetails': 'Show status detail lines',\n 'settings.hover.showDetailsHint': 'When off, the hover card shows only the workspace title, path, and creation time — no aggregated status lines.',\n 'settings.count.section': 'Count display',\n 'settings.count.threshold': 'Count display threshold',\n 'settings.count.thresholdHint': 'The count is shown on the badge only when the total is >= this value. Default 2 (omits the count when it equals 1 — the dots already convey \"something is happening\"). Set to 1 to always show.',\n 'settings.save': 'Save',\n 'settings.saving': 'Saving…',\n 'settings.saveFailed': 'The deployment did not accept these values; they were left for you to correct.',\n 'settings.readOnly': 'This deployment stores settings read-only.',\n 'settings.unavailable': 'This plugin is not loaded, so it cannot be configured right now.',\n} satisfies Record<WorkspaceKey, string>\n","/**\n * Workspace plugin, browser half. Two registrations: WorkspaceBrowser fills\n * the sidebar shell's `sidebar.workspaces` hole (the whole browsing region),\n * and WorkspacePicker fills the conversation hero's picker hole\n * (`conversation.hero.workspace` — both hero forms). Both read real Host\n * Workspaces through the global useWorkspaces hook, and each declares its\n * own `single` directory-flow child hole for the composed picker package's\n * client half. WorkspaceBrowser additionally declares the two Session row\n * action lists, and this apply registers the shipped actions — pin, rename,\n * fork, archive — into them the way any client plugin would, each with its\n * own behavior, plus the rename dialog and the row-action notice into\n * `shell.overlay` (see the contract module doc). It also declares two\n * Session-row seats: the leading decoration a row renders only while its own\n * primary state is idle, and the section the row's hover card renders between\n * its relative time and its trailing status line. Export discipline:\n * packages/client/AGENTS.md.\n */\nimport type {} from '@deepseek-ai/dsh-client-product-analytics/client'\nimport type { Context } from '@deepseek-ai/cordis'\nimport type { RemoteHostFacts } from '@deepseek-ai/dsh-api-remotes/client'\nimport type { ISessions } from '@deepseek-ai/dsh-api-session-controller/client'\nimport type {\n IWorkspaces, SessionActivity, WorkspaceArchiveError, WorkspaceSnapshot,\n} from '@deepseek-ai/dsh-api-workspace-controller/client'\nimport { createSnapshotStore } from '@deepseek-ai/dsh-client-store'\nimport type { HostObservable, SnapshotSelectorHook } from '@deepseek-ai/dsh-client-ui-slots'\nimport type { SessionId } from '@deepseek-ai/dsh-session/types'\n// Type-only: pulls the Controller service merges.\nimport type {} from '@deepseek-ai/dsh-api-session-controller/client'\nimport type {} from '@deepseek-ai/dsh-api-workspace-controller/client'\n// Type-only: pulls the locale plugin's Context merge (ctx.locale).\nimport type {} from '@deepseek-ai/dsh-client-locale/client'\n// Type-only: pulls the SlotRegistry service merge (ctx.slots).\nimport type {} from '@deepseek-ai/dsh-client-ui-renderer/client'\nimport type {} from '@deepseek-ai/dsh-client-ui-layout/client'\n// Type-only: pulls the Session root standard-hook merge.\nimport type {} from '@deepseek-ai/dsh-client-ui-session/client'\n// Type-only:插件页卡片的官方设置表单契约(运行时由 `configForms` 服务提供)。\nimport type { SettingsFormScope } from '@deepseek-ai/dsh-client-ui-primitives'\nimport {\n type ArchiveSessionInjected, type ForkSessionInjected, menuOpenStateFactory, type PinSessionInjected,\n type SessionArchiveConfirmInjected, type SessionArchiveConfirmRequest,\n type RenameSessionInjected, type RowToast, type RowToastInjected, type RowToastState, type SessionRenameDialogInjected,\n type WorkspaceBrowserInjected, type WorkspacePickerInjected,\n} from './contract/slots.ts'\nimport { createWorkspaceShortcutControls, installWorkspaceShortcuts } from './shortcuts.ts'\nimport { createBadgeSettingsSource, ENTRY_ID, type ResolvedBadgeSettings } from './badge-settings.ts'\nimport { disposeFacetStore } from './facet-store.ts'\nimport { BadgeSettingsCard } from './BadgeSettingsCard.tsx'\nimport { UiWorkspaceService } from './navigation.ts'\nimport { createWorkspaceViewStore } from './stores.ts'\nimport { WorkspaceBrowser } from './rows/WorkspaceBrowser.tsx'\nimport { ArchiveSessionMenuItem, ArchiveSessionRowButton, SessionArchiveConfirmDialog } from './session-actions/ArchiveSession.tsx'\nimport { derive } from './session-actions/derived.ts'\nimport { ForkSessionMenuItem } from './session-actions/ForkSession.tsx'\nimport { PinSessionMenuItem, PinSessionRowButton } from './session-actions/PinSession.tsx'\nimport { RenameSessionMenuItem, SessionRenameDialog } from './session-actions/RenameSession.tsx'\nimport { RowActionToast } from './session-actions/RowActionToast.tsx'\nimport { WorkspacePicker } from './WorkspacePicker.tsx'\nimport { en, zh, type WorkspaceKey } from './locales.ts'\n\nexport type { UiWorkspace } from './navigation.ts'\nexport type {\n DirectoryFlowOwnerProps, DirectoryFlowSlotName, DirectoryPickingHooks, DirectoryPickingInjected,\n MenuOpenState, RowToast, SessionRenameTarget, SessionRowOwnerProps, UseMenuOpenState, WorkspaceBrowserInjected,\n SessionRowScheduleOwnerProps,\n WorkspaceBrowserProps,\n WorkspacePickerInjected, WorkspacePickerProps,\n} from './contract/slots.ts'\nexport type { WorkspaceKey } from './locales.ts'\n\ndeclare module '@deepseek-ai/dsh-client-ui-slots' {\n interface GlobalStandardProps {\n /** Selector hook over the pure Workspace Controller snapshot. */\n useWorkspaces: SnapshotSelectorHook<WorkspaceSnapshot>\n /** Selector hook over this plugin's own settings face (badge preferences). */\n useBadgeSettings: SnapshotSelectorHook<ResolvedBadgeSettings>\n }\n\n interface LocaleNamespaceMap {\n /** The workspace browsing region and pick/create flow copy. */\n workspace: WorkspaceKey\n }\n}\n\ndeclare module '@deepseek-ai/dsh-api-session-controller/client' {\n interface SessionReferenceSourceMap {\n workspaceOperation: unknown\n }\n}\n\n/** Dictionary namespace owned by this plugin. */\nconst NS = 'workspace'\n\n/**\n * `configForms` 服务的最小结构面(宿主 `@deepseek-ai/dsh-client-ui-settings` 的\n * 一部分)。此处按结构声明而非导入该包:本插件不需要设置页的其余能力,窄化的\n * 形状让服务缺席时降级为一个 `undefined` 检查而非编译期依赖。\n *\n * `get` 的返回类型直接用官方 `SettingsFormScope`:那就是 `configForms.get(条目 id)`\n * 的运行时形状(`getSnapshot` / `subscribe` / `mutate`),设置卡片(官方\n * `SettingsFormModel`)要的也正是它,因此不需要本地复刻一份契约。\n *\n * `whileServed` 可选:它在 0.1.7 settings rewrite 一代才有,用于「宿主仍在服务该\n * 条目命名空间时」维持一段注册。缺席时只跳过插件页卡片,折叠徽标的读通道照常。\n */\ninterface ConfigFormsLike {\n get(entryId: string): SettingsFormScope<Record<string, unknown>>\n whileServed?(\n entryIds: readonly string[],\n register: (served: ReadonlySet<string>) => () => void,\n ): () => void\n}\n\n/** 插件详情页配置表单的槽位名(按包名寻址;契约见 `plugin-manager-slot.d.ts`)。 */\nconst CONFIG_CARD_SLOT = 'plugins.bundle.config'\n\n/**\n * 插件管理器分发 `plugins.bundle.config` 用的键 = **包名**(不是条目 id)。\n * 本包的补丁把行 id 也写成同名,但两者是不同概念,别改成 ENTRY_ID 的引用。\n */\nconst CONFIG_CARD_KEY = 'dsh-group-status'\n\n/**\n * Required services (cordis fiber inject). The target slots are declared by\n * the ui-sidebar / ui-conversation applies, whose activation order relative\n * to this one is NOT constrained: dsh.client.inject edges are informational\n * (loading/prefetch metadata, never apply sequencing) and neither owner\n * provides a waitable service. apply therefore depends on each slot\n * declaration through `slots.inject()` instead of assuming order.\n */\n/**\n * ── 跨插件公共 API:分组状态 facet 协议 ─────────────────────────────\n *\n * 任何插件想让自己的状态进**折叠分组**的徽标,就 `require('dsh-group-status/client')`\n * 拿这三个符号注册一个 facet;本插件不认识它,也不为它改代码:\n *\n * ```ts\n * const gs = require('dsh-group-status/client')\n * const unregister = gs?.registerGroupStatusFacet?.({\n * protocol: gs.GROUP_STATUS_FACET_PROTOCOL_VERSION,\n * id: 'my-plugin.review', // '<包名>.<状态名>',全局唯一\n * subscribe: store.subscribe, // 外部存储面,不要求 React hook\n * getSnapshot: store.getSnapshot,\n * fold: (snapshot, sessionIds, now) => ({ count, tone, pulse, data }),\n * merge: (a, b) => ({ ... }), // 多层文件夹怎么合并你的折果\n * label: (fold, { now }) => '等待评审(剩 3分钟) · #15',\n * renderIcon: (fold) => h('svg', …), // 图标归你,本插件只负责摆放\n * })\n * ctx.effect(() => () => unregister?.(), 'my-plugin: group-status facet')\n * ```\n *\n * 完整契约、版本规则与为什么是这个方向见 `docs/facet-protocol.md`。\n */\nexport {\n GROUP_STATUS_FACET_PROTOCOL_VERSION, FACET_TONE_RANK, registerGroupStatusFacet,\n registry as groupStatusFacetRegistry,\n} from './facets.ts'\nexport type {\n AnyFacet, AnyFacetFold, FacetFold, FacetOrigin, FacetRenderContext,\n FacetRegistration, FacetRejection, FacetTone, GroupStatusFacet, Unregister,\n} from './facets.ts'\n\nexport const inject = [\n 'slots', 'sessions', 'workspaces', 'locale', 'remote', 'remote.directoryPicker', 'layout', 'shortcuts',\n]\n\n/**\n * Register the browser and picker once their slot declarations are on the\n * ledger. Inject factories return plain callbacks; data reads use the\n * framework's global hooks.\n * @param ctx - client root context.\n */\nexport function apply(ctx: Context): void {\n const sessions = ctx.get('sessions') as ISessions\n const workspaces = ctx.get('workspaces') as IWorkspaces\n // One viewing-store instance, created here as ui-layout does for its layout\n // store: the browser declares the handle, and the UiWorkspace service writes\n // view order through the same instance the renderer hands the browser.\n const viewHandle = createWorkspaceViewStore()\n const viewInstance = viewHandle.create()\n const viewStore: typeof viewHandle = { ...viewHandle, create: () => viewInstance }\n const rowToast = createSnapshotStore<RowToastState | null>(null)\n let toastSeq = 0\n const notify = (toast: RowToast): void => { rowToast.set({ ...toast, seq: ++toastSeq }) }\n const uiWorkspace = new UiWorkspaceService(\n ctx, ctx.remote.directoryPicker, workspaces, sessions, viewInstance.actions, notify,\n )\n ctx.slots.provideRoot({ hooks: { workspaces: workspaces.list } })\n ctx.effect(() => ctx.locale.register(NS, { zh, en }), 'ui-workspace: dictionaries')\n\n // 外部状态来源只有一张登记面(`facets.ts`):本插件不认识任何具体插件,也不代任何\n // 插件登记。释放单例存储即可,来源自己的 facet 由它们的插件生命周期负责注销。\n ctx.effect(() => () => disposeFacetStore(), 'ui-workspace: status facets')\n const shortcutControls = createWorkspaceShortcutControls()\n\n // 折叠徽标的显示偏好(`showCompletedInBadge`)。\n //\n // 源先挂上(**恒在**,值先是默认):标准 props 的 hook 调用顺序必须稳定,晚挂或\n // 摘掉 `useBadgeSettings` 都会改变顺序而崩渲染。设置面随后经 `ctx.inject` 接入,\n // 只改源的值,不改源的存亡。\n const badgeSettings = createBadgeSettingsSource()\n ctx.slots.provideRoot({ hooks: { badgeSettings } })\n\n // 等宿主设置服务就绪——**非阻塞**:`ctx.inject` 是嵌套插件,服务永不到达也只是设置\n // 读不到(回落默认),本插件其余功能不受影响。这里不直接用 `ctx.get` 读:服务可能在\n // 本插件之后才注册,那时读到的 undefined 会永久生效(设置被静默忽略直到刷新)。\n //\n // 寻址键是**条目 id**(`cordis.patch.yml` 的 `id: dsh-group-status`),不是 settings\n // namespace——宿主 `describe()` 的 `ns` 即条目 id。\n ctx.inject(['configForms'], (configCtx) => {\n const forms = configCtx.get('configForms') as ConfigFormsLike | undefined\n if (forms === undefined || typeof forms.get !== 'function') return\n // 同一份官方设置表单既喂折叠徽标(只读快照),也喂插件页卡片(读写)。\n const scope = forms.get(ENTRY_ID)\n if (scope === undefined) return\n badgeSettings.publish(scope.getSnapshot())\n configCtx.effect(\n () => scope.subscribe(() => { badgeSettings.publish(scope.getSnapshot()) }),\n 'dsh-group-status: badge settings',\n )\n\n // 插件详情页(插件 → dsh-group-status)的配置表单。宿主把 `Config` 投影成\n // 上面这份表单,但页面要插件自己注册卡片才画得出来——没有这段,设置项在\n // GUI 里不存在(README 的「设置项」一节描述的就是这张卡片)。\n //\n // 键取**包名**(插件管理器按包名分发该槽位),寻址的表单仍是上面同一份 scope,\n // 于是卡片与折叠徽标永远读同一个值。\n //\n // `whileServed` 盯住条目命名空间:宿主不再服务该条目时连卡片一起注销,避免\n // 留下一张点开即空的表单。`bind` 是必需的:它是类原型方法,内部读写\n // `this.mirror`,取下来裸调用会丢接收者。\n const whileServed = forms.whileServed?.bind(forms)\n if (whileServed === undefined) return\n configCtx.effect(\n () => whileServed([ENTRY_ID], () => ctx.slots.inject(CONFIG_CARD_SLOT, () =>\n ctx.slots.register(\n {\n name: CONFIG_CARD_SLOT,\n key: CONFIG_CARD_KEY,\n locale: NS,\n inject: () => ({ scope }),\n },\n BadgeSettingsCard,\n ))),\n 'dsh-group-status: plugins-page card',\n )\n })\n\n const searchSessions: WorkspaceBrowserInjected['searchSessions'] = async (query, signal) => {\n const result = await sessions.search(query, signal)\n if (!result.ok) throw new Error(result.error.message)\n return result.value\n }\n\n // Stable per-surface occupancy sources (the renderer's hook cache keys by\n // source identity): true while the surface's directory-flow hole is filled.\n const flowSource = (hole: 'sidebar.workspaces.directoryFlow' | 'conversation.hero.workspace.directoryFlow'): HostObservable<boolean> => ({\n getSnapshot: () => ctx.slots.entries(hole).length > 0,\n subscribe: listener => ctx.slots.subscribe(hole, listener),\n })\n const browserFlowSource = flowSource('sidebar.workspaces.directoryFlow')\n const hostInfo: HostObservable<RemoteHostFacts> = {\n getSnapshot: () => ctx.remote.$host,\n subscribe: listener => ctx.on('connection/reset', listener),\n }\n const pickerFlowSource = flowSource('conversation.hero.workspace.directoryFlow')\n const openSession: WorkspaceBrowserInjected['open'] = (sessionId) => {\n uiWorkspace.openSession(sessionId)\n }\n // Registry-global sets as Sets, rebuilt only when the Workspace snapshot changes.\n const pinnedSet = derive(workspaces.list, snapshot => new Set<SessionId>(snapshot.pinnedSessionIds))\n const archivedSet = derive(workspaces.list, snapshot => new Set<SessionId>(snapshot.archivedSessionIds))\n // Plugin-private facts the row actions and their overlay surfaces share:\n // the pending rename request and the notice on display. Each business\n // writes through its own injected callback and the surface reads through\n // its bound hook.\n const renameRequest = derive(shortcutControls.state, state => state.renameTarget)\n const archiveRequest = createSnapshotStore<SessionArchiveConfirmRequest | null>(null)\n const requestSessionRename = shortcutControls.rename\n const unarchiveSession = (sessionId: SessionId): void => {\n uiWorkspace.unarchiveSession(sessionId).catch((reason: unknown) => {\n console.warn('session unarchive rejected:', reason)\n })\n }\n const renameSession: SessionRenameDialogInjected['renameSession'] = async (sessionId, title) => {\n const result = await sessions.using(\n sessionId,\n { source: 'workspaceOperation' },\n reference => reference.binding.session.rename(title),\n )\n if (!result.ok) throw new Error(result.error.message)\n }\n const pinInjected = (): PinSessionInjected => ({\n hooks: { pinned: pinnedSet, archived: archivedSet },\n // Pin failures surface as a notice: nothing else on the surface moves, so\n // a silent failure would read as a dead action.\n pinSession: (sessionId) => {\n uiWorkspace.pinSession(sessionId).catch(() => { notify({ kind: 'pinFailed' }) })\n },\n unpinSession: (sessionId) => {\n uiWorkspace.unpinSession(sessionId).catch(() => { notify({ kind: 'unpinFailed' }) })\n },\n })\n const archiveInjected = (): ArchiveSessionInjected => ({\n hooks: { archived: archivedSet },\n // Archive preserves the log and the account position, so a quiet Session\n // needs no confirmation; the notice offers undo and the archived filter.\n // The Host's refusal for running work is the one case that asks first:\n // the confirmation names that work and offers to stop it.\n archiveSession: (sessionId) => {\n uiWorkspace.archiveSession(sessionId).then(() => {\n notify({ kind: 'archived', sessionId })\n }).catch((reason: unknown) => {\n const activity = activeSessionRefusal(reason)\n if (activity === undefined) {\n console.warn('session archive rejected:', reason)\n return\n }\n const displayTitle = sessions.list.getSnapshot().byId[sessionId]?.displayTitle ?? sessionId\n archiveRequest.set({ sessionId, displayTitle, activity })\n })\n },\n unarchiveSession,\n })\n installWorkspaceShortcuts(ctx, uiWorkspace, shortcutControls, archiveInjected().archiveSession)\n const archiveConfirmInjected = (): SessionArchiveConfirmInjected => ({\n hooks: { archiveRequest },\n settleSessionArchive: () => { archiveRequest.set(null) },\n stopAndArchiveSession: async (sessionId) => {\n await uiWorkspace.archiveSession(sessionId, { stopActivity: true })\n notify({ kind: 'stoppedAndArchived', sessionId })\n },\n })\n const forkInjected = (): ForkSessionInjected => ({\n forkSession: (sessionId) => {\n uiWorkspace.forkSession(sessionId, (childId) => {\n ctx.get('productAnalytics')?.track('branch_session_click', { session_id: childId, parent_session_id: sessionId, click_position: 'sidebar' })\n }).catch(() => {\n // Fork or child-title failure leaves the list as it was.\n })\n },\n })\n const renameInjected = (): RenameSessionInjected => ({ requestSessionRename })\n const renameDialogInjected = (): SessionRenameDialogInjected => ({\n hooks: { renameRequest },\n settleSessionRename: shortcutControls.closeRename,\n renameSession,\n })\n const rowToastInjected = (): RowToastInjected => ({\n hooks: { toast: rowToast },\n dismissToast: () => { rowToast.set(null) },\n undoArchive: unarchiveSession,\n showArchived: () => { viewInstance.actions.setArchivedFilter('show') },\n })\n const browserInjected = (): WorkspaceBrowserInjected => ({\n // Explicit group actions keep their target; unscoped New Session inherits\n // the current Session Workspace before the recent-Workspace fallback.\n startSession: (workspaceId) => { uiWorkspace.startSession(workspaceId) },\n open: openSession,\n searchSessions,\n searchResultLimit: sessions.searchResultLimit,\n requestSessionRename,\n notifyArchivedNotOpenable: () => { notify({ kind: 'archivedNotOpenable' }) },\n renameWorkspace: async (workspaceId, title) => { await workspaces.rename(workspaceId, title) },\n deleteWorkspace: async (workspaceId) => { await workspaces.delete(workspaceId) },\n insertWorkspaceBefore: async (workspaceId, beforeWorkspaceId) => {\n await workspaces.insertBefore(workspaceId, beforeWorkspaceId)\n },\n unarchiveSession: async (sessionId) => { await uiWorkspace.unarchiveSession(sessionId) },\n createWorkspace: input => workspaces.create(input),\n requestSearch: shortcutControls.search,\n requestAddWorkspace: shortcutControls.add,\n closeAddWorkspace: shortcutControls.closeAdd,\n setDirectoryBusy: shortcutControls.directoryBusy,\n dismissForkError: shortcutControls.dismissForkError,\n hooks: { directoryFlow: browserFlowSource, hostInfo, workspaceShortcuts: shortcutControls.state, shortcuts: ctx.shortcuts.catalog },\n })\n const pickerInjected = (): WorkspacePickerInjected => ({\n createWorkspace: input => workspaces.create(input),\n hooks: { directoryFlow: pickerFlowSource },\n })\n // Each registration declares its owned children in the same call; slot\n // injection follows both the owner and declaration HMR lifetimes.\n ctx.slots.inject('sidebar.workspaces', () => ctx.slots.register(\n {\n name: 'sidebar.workspaces',\n children: {\n 'sidebar.workspaces.directoryFlow': { kind: 'single', scope: 'root' },\n // Every row entry reads the menu's open state through a hook bound\n // from the row's render occurrence (the owner passes the state pair\n // as hookContext).\n 'sidebar.workspaces.session.menu.item': {\n kind: 'list', scope: 'root', inject: { hooks: { menuOpenState: menuOpenStateFactory, shortcuts: ctx.shortcuts.catalog } },\n },\n 'sidebar.workspaces.session.row.action': { kind: 'list', scope: 'root' },\n 'sidebar.session.row.leading': { kind: 'list', scope: 'root' },\n 'sidebar.session.row.hover': { kind: 'list', scope: 'root' },\n },\n store: viewStore,\n inject: browserInjected,\n locale: NS,\n },\n WorkspaceBrowser,\n ))\n // The shipped row actions take the same route as a plugin's: `slots.inject`\n // waits for the browser registration above to declare each list, and the\n // entries leave with it. Orders step by 100 so a plugin entry can land\n // between them.\n ctx.slots.inject('sidebar.workspaces.session.menu.item', function* () {\n yield ctx.slots.register({ name: 'sidebar.workspaces.session.menu.item', id: 'pin', order: 100, locale: NS, inject: pinInjected }, PinSessionMenuItem)\n yield ctx.slots.register({ name: 'sidebar.workspaces.session.menu.item', id: 'rename', order: 200, locale: NS, inject: renameInjected }, RenameSessionMenuItem)\n yield ctx.slots.register({ name: 'sidebar.workspaces.session.menu.item', id: 'fork', order: 300, locale: NS, inject: forkInjected }, ForkSessionMenuItem)\n yield ctx.slots.register({ name: 'sidebar.workspaces.session.menu.item', id: 'archive', order: 400, locale: NS, inject: archiveInjected }, ArchiveSessionMenuItem)\n })\n ctx.slots.inject('sidebar.workspaces.session.row.action', function* () {\n yield ctx.slots.register({ name: 'sidebar.workspaces.session.row.action', id: 'archive', order: 100, locale: NS, inject: archiveInjected }, ArchiveSessionRowButton)\n yield ctx.slots.register({ name: 'sidebar.workspaces.session.row.action', id: 'pin', order: 200, locale: NS, inject: pinInjected }, PinSessionRowButton)\n })\n // The surfaces the actions raise live in the frame-wide layer: they must\n // outlive the row menu the action sat in.\n ctx.slots.inject('shell.overlay', function* () {\n yield ctx.slots.register({\n name: 'shell.overlay', id: 'workspace.session-rename', locale: NS, inject: renameDialogInjected,\n }, SessionRenameDialog)\n yield ctx.slots.register({\n name: 'shell.overlay', id: 'workspace.session-archive', locale: NS, inject: archiveConfirmInjected,\n }, SessionArchiveConfirmDialog)\n // The toast shares the browser's viewing store: it reads the archived\n // filter to drop the archived notice's filter action once rows are visible.\n yield ctx.slots.register({\n name: 'shell.overlay', id: 'workspace.row-toast', locale: NS, store: viewStore, inject: rowToastInjected,\n }, RowActionToast)\n })\n ctx.slots.inject('conversation.hero.workspace', () => ctx.slots.register(\n {\n name: 'conversation.hero.workspace',\n children: { 'conversation.hero.workspace.directoryFlow': { kind: 'single', scope: 'root' } },\n inject: pickerInjected,\n locale: NS,\n },\n WorkspacePicker,\n ))\n}\n\n/**\n * The activity a Host `workspace/session-active` refusal reported, or nothing\n * for any other failure. The class identity check goes by name: client plugin\n * bundles do not share error-class identity.\n */\nfunction activeSessionRefusal(reason: unknown): readonly SessionActivity[] | undefined {\n if (!(reason instanceof Error) || reason.name !== 'WorkspaceArchiveError') return undefined\n const { rpcError } = reason as WorkspaceArchiveError\n return rpcError.code === 'workspace/session-active' ? rpcError.details.activity : undefined\n}\n"],"ignoreList":[7,8,13,14],"mappings":"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"}
|