dsh-brief-sidebar 0.9.1 → 0.9.2

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/lib/client.js.map CHANGED
@@ -1 +1 @@
1
- {"version":3,"file":"client.js","names":["STATUS_KEY","NO_SUBSCRIBE","ABSENT","useMemo","useCallback","useSyncExternalStore","useMemo","SECTION_STYLE","HEADER_STYLE","LIST_STYLE","ROW_STYLE","createElement","CHEVRON_STYLE","createElement","SECTION_STYLE","HEADER_STYLE","LIST_STYLE","ROW_STYLE","TAG_STYLE","createElement","useState","isCounter","SECTION_STYLE","HEADER_STYLE","LIST_STYLE","ROW_STYLE","NAME_STYLE","FOOTER_STYLE","EMPTY_STYLE","createElement","isCounter","NO_SUBSCRIBE","useMemo","useCallback","useSyncExternalStore","SECTION_STYLE","HEADER_STYLE","LIST_STYLE","ROW_STYLE","TITLE_STYLE","META_STYLE","BODY_STYLE","EMPTY_STYLE","createElement","TYPE_STYLE","BODY_STYLE","SCENARIO_STYLE","FOOTER_STYLE","createElement","HEADER_STYLE","HINT_STYLE","ROW_STYLE","createElement","useState","useRef","useCallback","createElement","createElement","useState","useSyncExternalStore","useCallback","createElement"],"sources":["../src/client/brief/board.ts","../src/client/use-projection.ts","../src/client/brief/use-todos.ts","../src/client/TodoBoardTab.tsx","../src/projection/keys.ts","../src/client/file-open.ts","../src/client/summary/deliverables.ts","../src/client/summary/FoldToggle.tsx","../src/client/locales.ts","../src/client/summary/DeliverablesSection.tsx","../src/client/summary/skill-usage.ts","../src/client/summary/SkillUsageSection.tsx","../src/client/summary/memory-slots.ts","../src/client/scope-face.ts","../src/client/summary/use-config-flag.ts","../src/client/summary/MemorySlotsSection.tsx","../src/client/summary/memory-recall.ts","../src/client/summary/recall-feedback.ts","../src/client/summary/RecallBubble.tsx","../src/client/summary/MemoryRecallSection.tsx","../src/client/SummaryTab.tsx","../src/client/native-sidebar.tsx","../src/client/BriefIcon.tsx","../src/client/brief/dock-shadow.tsx","../src/client/settings-card.tsx","../src/client/index.tsx"],"sourcesContent":["/**\r\n * The `todos` projection — reading and classifying it.\r\n *\r\n * The Host computes this projection (`dsh-tool-todo` registers the key) and\r\n * pushes finished whole values; the client never folds it. This module is the\r\n * read side of that contract and is deliberately PURE — no React, no context,\r\n * no IO — so the mapping can be tested directly.\r\n */\r\n/** The projection's three-state lifecycle (`TodoItem` in `dsh-tool-todo`). */\r\nexport type TodoStatus = 'pending' | 'in_progress' | 'completed'\r\n\r\n/** One entry of the `todos` projection. */\r\nexport interface TodoItem {\r\n readonly content: string\r\n readonly status: TodoStatus\r\n}\r\n\r\nconst STATUSES: readonly TodoStatus[] = ['pending', 'in_progress', 'completed']\r\n\r\n/** Locale key per status. Kept here so this module owns the vocabulary. */\r\nconst STATUS_KEY: Record<TodoStatus, string> = {\r\n pending: 'status.pending',\r\n in_progress: 'status.inProgress',\r\n completed: 'status.completed',\r\n}\r\n\r\n/** Locale key for one status label. */\r\nexport function statusKey(status: TodoStatus): string {\r\n return STATUS_KEY[status]\r\n}\r\n\r\n/**\r\n * Narrow a raw projection value into a todo list.\r\n *\r\n * Three outcomes are kept apart on purpose, mirroring the store's own contract:\r\n * - `undefined` — the capability is ABSENT (no session, the host unit is\r\n * unmounted, or no baseline/frame has carried the key yet);\r\n * - `[]` — the projection is present and the list is empty (`null` on the wire);\r\n * - a list — real entries.\r\n *\r\n * A malformed entry is dropped rather than thrown on: the projection is a\r\n * trusted Host value, but a shape drift must not blank the whole board.\r\n *\r\n * @param value - the raw `unknown` snapshot of the `todos` face.\r\n * @returns the validated list, or `undefined` when the capability is absent.\r\n */\r\nexport function readTodos(value: unknown): readonly TodoItem[] | undefined {\r\n if (value === null) return []\r\n if (!Array.isArray(value)) return undefined\r\n\r\n const items: TodoItem[] = []\r\n for (const raw of value) {\r\n if (raw === null || typeof raw !== 'object') continue\r\n const { content, status } = raw as { content?: unknown; status?: unknown }\r\n if (typeof content !== 'string') continue\r\n if (typeof status !== 'string' || !isStatus(status)) continue\r\n items.push({ content, status })\r\n }\r\n return items\r\n}\r\n\r\n/** Whether a string is one of the three lifecycle values. */\r\nfunction isStatus(value: string): value is TodoStatus {\r\n return (STATUSES as readonly string[]).includes(value)\r\n}\r\n\r\n/** Per-status counts over one list. */\r\nexport interface TodoCounts {\r\n readonly total: number\r\n readonly completed: number\r\n readonly inProgress: number\r\n readonly pending: number\r\n}\r\n\r\n/** Count a todo list by status. */\r\nexport function countTodos(todos: readonly TodoItem[]): TodoCounts {\r\n let completed = 0\r\n let inProgress = 0\r\n let pending = 0\r\n for (const item of todos) {\r\n if (item.status === 'completed') completed += 1\r\n else if (item.status === 'in_progress') inProgress += 1\r\n else pending += 1\r\n }\r\n return { total: todos.length, completed, inProgress, pending }\r\n}\r\n\r\n/** How many entries are not finished — the tab badge. */\r\nexport function unfinishedCount(todos: readonly TodoItem[]): number {\r\n const counts = countTodos(todos)\r\n return counts.inProgress + counts.pending\r\n}\r\n\r\n/**\r\n * The one-line progress summary, composed from parts so no interpolation\r\n * machinery is needed (the locale binder is a plain key → string lookup).\r\n * Mirrors the official dock's own label.\r\n */\r\nexport function progressLine(counts: TodoCounts, t: (key: string) => string): string {\r\n const parts = [`${t('status.completed')} ${counts.completed}/${counts.total}`]\r\n if (counts.inProgress > 0) parts.push(`${t('status.inProgress')} ${counts.inProgress}`)\r\n if (counts.pending > 0) parts.push(`${t('status.pending')} ${counts.pending}`)\r\n return parts.join(' · ')\r\n}\r\n","/**\r\n * Reading a live session projection from the client Session Controller.\r\n *\r\n * better-sidebar tab bodies are NOT rendered inside a DSH slot, so the\r\n * framework's `useProjection` standard prop is not available to them. The\r\n * equivalent face is reachable directly: the client Session Controller is a\r\n * cordis service on the root context, and each session binding exposes its\r\n * projections store (`SessionFace.projections.faceOf(key)`), which is the very\r\n * observable `useProjection` resolves. Since it is a bare\r\n * `{ getSnapshot, subscribe }` source, `useSyncExternalStore` binds it as-is —\r\n * no local mirror, no folding, and the value reference only changes when the\r\n * Host pushes a frame.\r\n *\r\n * Everything here is resolved defensively: a host without the Session\r\n * Controller, or a session that is not open any more, degrades to \"capability\r\n * absent\" (undefined) rather than throwing inside a render.\r\n *\r\n * This module is key-agnostic; the per-projection knowledge (which key, how to\r\n * narrow the raw value) lives with the feature modules that call it.\r\n */\r\nimport { useCallback, useMemo, useSyncExternalStore } from 'react'\r\nimport type { Context } from '@deepseek-ai/cordis'\r\n\r\n/** Structural view of a projection face (`ObservableSnapshot<unknown>`). */\r\nexport interface ProjectionFace {\r\n getSnapshot(): unknown\r\n subscribe(listener: () => void): () => void\r\n}\r\n\r\n/** Structural view of one session binding's projection store. */\r\nexport interface ProjectionsLike {\r\n faceOf(key: string): ProjectionFace\r\n}\r\n\r\n/** Structural view of the client Session Controller face this plugin uses. */\r\nexport interface SessionsLike {\r\n binding(id: string): { readonly session: { readonly projections: ProjectionsLike } } | undefined\r\n}\r\n\r\n/** A no-op unsubscribe, kept as one identity so effects never thrash. */\r\nconst NO_SUBSCRIBE = (): void => {}\r\n\r\n/** A source that never has a value — the absent-capability face. */\r\nconst ABSENT: ProjectionFace = { getSnapshot: () => undefined, subscribe: () => NO_SUBSCRIBE }\r\n\r\n/**\r\n * Whether a value really is a projection face.\r\n *\r\n * The store contract promises an identity-stable face for every key, so this\r\n * never fires against a healthy host. It exists because the fallback is worse\r\n * than the check: `useSyncExternalStore` would throw on a face-less key, and a\r\n * thrown render is a blank sidebar rather than a diagnosable \"unavailable\".\r\n */\r\nfunction isFace(value: unknown): value is ProjectionFace {\r\n if (value === null || typeof value !== 'object') return false\r\n const face = value as Partial<ProjectionFace>\r\n return typeof face.getSnapshot === 'function' && typeof face.subscribe === 'function'\r\n}\r\n\r\n/**\r\n * Resolve one projection face for one session.\r\n *\r\n * `ctx.get('sessions')` is the safe accessor (a direct `ctx.sessions` read can\r\n * throw on a context that does not carry the service yet).\r\n *\r\n * @param ctx - the client root context handed to the tab body.\r\n * @param sessionId - the tab's session scope; undefined means \"no session\".\r\n * @param key - the projection key to resolve.\r\n * @returns the projection face, or {@link ABSENT} when unreachable.\r\n */\r\nexport function resolveFace(ctx: Context | undefined, sessionId: string | undefined, key: string): ProjectionFace {\r\n if (ctx === undefined || sessionId === undefined) return ABSENT\r\n const sessions = ctx.get('sessions') as SessionsLike | undefined\r\n if (sessions === undefined || typeof sessions.binding !== 'function') return ABSENT\r\n\r\n const binding = sessions.binding(sessionId)\r\n const projections = binding?.session?.projections\r\n if (projections === undefined || typeof projections.faceOf !== 'function') return ABSENT\r\n\r\n const face: unknown = projections.faceOf(key)\r\n return isFace(face) ? face : ABSENT\r\n}\r\n\r\n/**\r\n * Read one frame of a projection without subscribing.\r\n *\r\n * The one-shot sibling of {@link useProjectionValue}, for consumers that are\r\n * not React components — the tab badge is a plain function called on every\r\n * tab-bar render, so it must neither hold a subscription nor allocate one.\r\n *\r\n * @param ctx - the client root context.\r\n * @param sessionId - the session whose projection is read.\r\n * @param key - the projection key to read.\r\n * @returns the raw snapshot: `undefined` while the capability is absent; the\r\n * semantics of any other value belong to the projection's own contract.\r\n */\r\nexport function projectionSnapshot(ctx: Context | undefined, sessionId: string | undefined, key: string): unknown {\r\n return resolveFace(ctx, sessionId, key).getSnapshot()\r\n}\r\n\r\n/**\r\n * Subscribe to one session projection by key.\r\n *\r\n * @param ctx - the client root context.\r\n * @param sessionId - the session whose projection is shown.\r\n * @param key - the projection key to subscribe to.\r\n * @returns the raw snapshot value, identity-stable across frames the host did\r\n * not change. Narrowing is the caller's job.\r\n */\r\nexport function useProjectionValue(ctx: Context | undefined, sessionId: string | undefined, key: string): unknown {\r\n const face = useMemo(() => resolveFace(ctx, sessionId, key), [ctx, sessionId, key])\r\n\r\n const subscribe = useCallback((listener: () => void) => face.subscribe(listener), [face])\r\n const getSnapshot = useCallback(() => face.getSnapshot(), [face])\r\n\r\n return useSyncExternalStore(subscribe, getSnapshot, getSnapshot)\r\n}\r\n","/**\r\n * Reading the live `todos` projection — the thin, todo-specific wrapper around\r\n * the generic face resolver (`../use-projection`). The projection key is\r\n * registered by `dsh-tool-todo`; the host pushes finished whole values and the\r\n * client never folds it. Narrowing lives in `./board` (`readTodos`).\r\n */\r\nimport { useMemo } from 'react'\r\nimport type { Context } from '@deepseek-ai/cordis'\r\nimport { readTodos } from './board'\r\nimport type { TodoItem } from './board'\r\nimport { useProjectionValue } from '../use-projection'\r\n\r\n/** The projection key registered by `dsh-tool-todo`. */\r\nexport const TODOS_KEY = 'todos'\r\n\r\n/**\r\n * Subscribe to one session's todo list.\r\n *\r\n * @param ctx - the client root context.\r\n * @param sessionId - the session whose projection is shown.\r\n * @returns the list, `[]` for a present-but-empty projection, or `undefined`\r\n * while the capability is absent.\r\n */\r\nexport function useTodos(ctx: Context | undefined, sessionId: string | undefined): readonly TodoItem[] | undefined {\r\n const raw = useProjectionValue(ctx, sessionId, TODOS_KEY)\r\n return useMemo(() => readTodos(raw), [raw])\r\n}\r\n","/**\r\n * The progress section: the `todos` projection drawn as one part of the\r\n * summary tab.\r\n *\r\n * The official composer-band panel is shadowed by this plugin (see\r\n * `brief/dock-shadow.tsx`), so the projection is read here and rendered as an\r\n * ordinary React view — no Canvas, no cross-package dependency. The full-height\r\n * shell and the scroll container live on the summary tab (`../SummaryTab`);\r\n * this component renders only its own slice and is the one section whose\r\n * absent state must stay VISIBLE: the official dock is hidden while this\r\n * plugin is mounted, so \"unavailable\" is a statement the reader needs.\r\n *\r\n * Colours come from `--dsw-alias-*` tokens only (skin contract), and the status\r\n * palette uses tokens that actually exist in the shipping theme:\r\n * `state-success-primary` / `state-business-primary` / `label-tertiary`.\r\n */\r\nimport { createElement } from 'react'\r\nimport type { CSSProperties, ReactNode } from 'react'\r\nimport type { Context } from '@deepseek-ai/cordis'\r\nimport { countTodos, progressLine, statusKey } from './brief/board'\r\nimport type { TodoItem, TodoStatus } from './brief/board'\r\nimport { useTodos } from './brief/use-todos'\r\n\r\n/** The session scope better-sidebar hands a tab body. */\r\nexport interface TodoScope {\r\n readonly sessionId?: string\r\n}\r\n\r\nexport interface TodoSectionProps {\r\n /** The DSH locale lookup, passed down from `apply`. */\r\n t: (key: string) => string\r\n /** The client root context (the tab body's only way to reach services). */\r\n ctx?: Context\r\n /** The session this tab is scoped to. */\r\n scope?: TodoScope\r\n}\r\n\r\n/** Status → token colour for the pill's text and border. */\r\nconst STATUS_COLOR: Record<TodoStatus, string> = {\r\n completed: 'var(--dsw-alias-state-success-primary)',\r\n in_progress: 'var(--dsw-alias-state-business-primary)',\r\n pending: 'var(--dsw-alias-label-tertiary)',\r\n}\r\n\r\nconst SECTION_STYLE: CSSProperties = {\r\n flexShrink: 0,\r\n borderBottom: '1px solid var(--dsw-alias-border-secondary)',\r\n}\r\n\r\nconst HEADER_STYLE: CSSProperties = {\r\n padding: '10px 12px 0',\r\n color: 'var(--dsw-alias-label-secondary)',\r\n fontSize: 12,\r\n fontWeight: 600,\r\n}\r\n\r\nconst PROGRESS_STYLE: CSSProperties = {\r\n padding: '6px 12px 10px',\r\n color: 'var(--dsw-alias-label-secondary)',\r\n fontSize: 12,\r\n}\r\n\r\nconst LIST_STYLE: CSSProperties = {\r\n listStyle: 'none',\r\n margin: 0,\r\n padding: '6px 0',\r\n display: 'flex',\r\n flexDirection: 'column',\r\n}\r\n\r\nconst ROW_STYLE: CSSProperties = {\r\n display: 'flex',\r\n alignItems: 'flex-start',\r\n gap: 8,\r\n padding: '6px 12px',\r\n}\r\n\r\n/** Pill style, coloured per status. */\r\nfunction pillStyle(status: TodoStatus): CSSProperties {\r\n return {\r\n flexShrink: 0,\r\n color: STATUS_COLOR[status],\r\n border: `1px solid ${STATUS_COLOR[status]}`,\r\n borderRadius: 999,\r\n padding: '0 6px',\r\n fontSize: 11,\r\n lineHeight: '16px',\r\n whiteSpace: 'nowrap',\r\n }\r\n}\r\n\r\n/** Task text: finished entries read as done, the working one as active. */\r\nfunction contentStyle(status: TodoStatus): CSSProperties {\r\n return {\r\n minWidth: 0,\r\n overflowWrap: 'anywhere',\r\n color:\r\n status === 'completed'\r\n ? 'var(--dsw-alias-label-tertiary)'\r\n : status === 'in_progress'\r\n ? 'var(--dsw-alias-label-primary)'\r\n : 'var(--dsw-alias-label-secondary)',\r\n textDecoration: status === 'completed' ? 'line-through' : 'none',\r\n }\r\n}\r\n\r\n/** Centred message block used by every non-list state. */\r\nexport function Notice(props: { title: string; detail?: string }): ReactNode {\r\n return (\r\n <div\r\n style={{\r\n margin: '0 auto',\r\n padding: 24,\r\n maxWidth: 460,\r\n textAlign: 'center',\r\n color: 'var(--dsw-alias-label-tertiary)',\r\n lineHeight: 1.7,\r\n fontSize: 12,\r\n }}\r\n >\r\n <div style={{ marginBottom: 6, color: 'var(--dsw-alias-label-secondary)' }}>{props.title}</div>\r\n {props.detail === undefined ? null : <div>{props.detail}</div>}\r\n </div>\r\n )\r\n}\r\n\r\n/** One task row. */\r\nfunction TodoRow(props: { item: TodoItem; t: (key: string) => string }): ReactNode {\r\n const { item, t } = props\r\n return createElement(\r\n 'li',\r\n { style: ROW_STYLE },\r\n createElement('span', { style: pillStyle(item.status) }, t(statusKey(item.status))),\r\n createElement('span', { style: contentStyle(item.status) }, item.content),\r\n )\r\n}\r\n\r\n/**\r\n * The progress section. The subscription is unconditional (a plain listener,\r\n * not IO); the three-state contract of the projection is preserved verbatim.\r\n * @param props - translation, client context, session scope.\r\n */\r\nexport function TodoSection(props: TodoSectionProps): ReactNode {\r\n const { t, ctx, scope } = props\r\n\r\n const todos = useTodos(ctx, scope?.sessionId)\r\n\r\n if (todos === undefined) {\r\n // `undefined` is the store's \"capability absent\": no session, or the host's\r\n // todo unit is unmounted. Say so rather than showing an empty board.\r\n return createElement(\r\n 'div',\r\n { style: SECTION_STYLE, 'data-dsh-brief-sidebar': 'progress-section' },\r\n createElement('div', { style: HEADER_STYLE }, t('section.progress')),\r\n createElement(Notice, { title: t('board.unavailable'), detail: t('board.unavailableHint') }),\r\n )\r\n }\r\n\r\n if (todos.length === 0) {\r\n return createElement(\r\n 'div',\r\n { style: SECTION_STYLE, 'data-dsh-brief-sidebar': 'progress-section' },\r\n createElement('div', { style: HEADER_STYLE }, t('section.progress')),\r\n createElement(Notice, { title: t('board.empty'), detail: t('board.emptyHint') }),\r\n )\r\n }\r\n\r\n const counts = countTodos(todos)\r\n\r\n return createElement(\r\n 'div',\r\n { style: SECTION_STYLE, 'data-dsh-brief-sidebar': 'progress-section' },\r\n createElement('div', { style: HEADER_STYLE }, t('section.progress')),\r\n createElement('div', { style: PROGRESS_STYLE }, progressLine(counts, t)),\r\n createElement(\r\n 'ul',\r\n { style: LIST_STYLE },\r\n todos.map((item, index) => createElement(TodoRow, { key: `${index}:${item.content}`, item, t })),\r\n ),\r\n )\r\n}\r\n\r\n/**\r\n * Backwards-compatible alias for the pre-summary export name. The component\r\n * no longer owns the full-height shell — that moved to `SummaryTab` — so the\r\n * alias exists only to keep import sites honest during the transition.\r\n */\r\nexport const TodoBoardTab = TodoSection\r\n","/**\r\n * The projection keys this plugin contributes to the session-projection\r\n * registry, and their wire views.\r\n *\r\n * The key is namespaced with the plugin name on purpose: the registry refuses\r\n * to share a key across differing `stateVersion`s, so a collision with a\r\n * future host-side deliverables unit would be a hard load error, not a silent\r\n * shadow. The view type is declared structurally (the plugin has no compile\r\n * dependency on `@deepseek-ai/dsh-session-projection`); the registry accepts\r\n * any string key at runtime.\r\n */\r\n\r\n/** The projection key registered by this plugin's host half. */\r\nexport const DELIVERABLES_KEY = 'dshSummaryDeliverables'\r\n\r\n/**\r\n * The second key: which skills this session actually loaded (the host's `skill`\r\n * tool, read off `tool/call.arguments`). Namespaced for the same reason as\r\n * {@link DELIVERABLES_KEY} — the registry hard-fails on a shared key with a\r\n * differing `stateVersion`, so a future host-side skill unit must not be able\r\n * to collide silently.\r\n */\r\nexport const SKILL_USAGE_KEY = 'dshSummarySkillUsage'\r\n\r\n/** Client view of the produced-file fold (JSON-safe). */\r\nexport interface DeliverablesView {\r\n /** Paths produced in the latest turn, first-seen order (capped). */\r\n readonly latest: {\r\n readonly turn: number\r\n readonly paths: readonly string[]\r\n } | null\r\n /** Distinct produced paths session-wide, most-recent-first (capped). */\r\n readonly sessionPaths: readonly string[]\r\n /** Distinct produced paths session-wide, uncapped — the truthful total. */\r\n readonly sessionTotal: number\r\n}\r\n\r\n/** One loaded skill in the wire view. */\r\nexport interface SkillUsageEntryView {\r\n /** The skill name exactly as the model passed it to the `skill` tool. */\r\n readonly name: string\r\n /** Successful loads of this skill this session. */\r\n readonly count: number\r\n /** Turn whose call last advanced this tally. */\r\n readonly lastTurn: number\r\n}\r\n\r\n/** Client view of the skill-usage fold (JSON-safe). */\r\nexport interface SkillUsageView {\r\n /** Skills loaded in the latest turn; `null` before the first `turn/start`. */\r\n readonly latest: { readonly turn: number; readonly names: readonly string[] } | null\r\n /** Distinct loaded skills, most recently used first (capped). */\r\n readonly session: readonly SkillUsageEntryView[]\r\n /** Distinct loaded skills session-wide — may exceed `session.length`. */\r\n readonly sessionTotal: number\r\n /** Successful skill loads session-wide. */\r\n readonly callTotal: number\r\n}\r\n","/**\r\n * Opening a produced file's preview in the right Sidebar — the same channel\r\n * the conversation flow uses for its produced-file chips and inline mentions\r\n * (ui-chat `openFile` → `ctx.sidebarRight.openResource` with a\r\n * `dsh-resource://file/…` address).\r\n *\r\n * The address grammar is ported verbatim from the harness's browser-safe\r\n * `@deepseek-ai/dsh-util-workspace-path` (`file-address.ts` / `index.ts`),\r\n * because the plugin does not compile against that package: a relative path,\r\n * or an absolute path inside the session's workspace, is addressed under the\r\n * session's scope (`dsh-resource://file/session/<id>/<path>`); an absolute\r\n * path elsewhere keeps its absolute spelling in the same session's address.\r\n * Which tab type claims the address is the Sidebar's decision, not ours.\r\n *\r\n * The `sidebarRight` service is consumed structurally and treated as OPTIONAL:\r\n * where it is absent the section renders plain rows instead of links, the same\r\n * graceful degradation as the deliverables projection itself.\r\n */\r\nimport type { Context } from '@deepseek-ai/cordis'\r\n\r\n/** Structural view of the right-Sidebar service this plugin needs. */\r\nexport interface SidebarRightLike {\r\n openResource(url: string, options?: { params?: { line?: number } }): void\r\n}\r\n\r\n/** Structural view of the sessions service slice the opener reads. */\r\ninterface SessionsListLike {\r\n list?: { getSnapshot(): { byId?: Record<string, { cwd?: string }> } }\r\n}\r\n\r\n/** The address scheme every file resource opens with. */\r\nconst FILE_ADDRESS_PREFIX = 'dsh-resource://file/'\r\n\r\n/** Whether a path uses a Windows drive or UNC prefix. */\r\nfunction isWindowsStylePath(value: string): boolean {\r\n return /^[A-Za-z]:[/\\\\]/.test(value) || value.startsWith('\\\\\\\\')\r\n}\r\n\r\n/**\r\n * Whether a path is absolute in either spelling the Host accepts: POSIX (`/a/b`)\r\n * or Windows drive or UNC.\r\n */\r\nexport function isAbsoluteWorkspacePath(path: string): boolean {\r\n return path.startsWith('/') || isWindowsStylePath(path)\r\n}\r\n\r\n/** Component-encode one id or path segment, keeping `:` literal for drive letters. */\r\nfunction encodeSegment(segment: string): string {\r\n return encodeURIComponent(segment).replace(/%3A/gi, ':')\r\n}\r\n\r\n/** Encode a `/`-separated path segment by segment. */\r\nfunction encodePath(path: string): string {\r\n return path.split('/').map(encodeSegment).join('/')\r\n}\r\n\r\n/**\r\n * Build the address of a file read through one Session.\r\n * @param sessionId - the Session whose Host workspace resolves the path.\r\n * @param path - absolute or workspace-relative path; backslashes are normalized\r\n * to `/`, and leading `./` prefixes are dropped.\r\n */\r\nfunction sessionFileAddress(sessionId: string, path: string): string {\r\n const normalized = path.replace(/\\\\/g, '/').replace(/^(?:\\.\\/)+/, '')\r\n return `${FILE_ADDRESS_PREFIX}session/${encodeSegment(sessionId)}/${encodePath(normalized)}`\r\n}\r\n\r\n/**\r\n * The address for a path as a caller holds it.\r\n * @param sessionId - the Session the path is read in.\r\n * @param cwd - that Session's workspace root, when known.\r\n * @param path - absolute or workspace-relative path, in either separator spelling.\r\n */\r\nexport function fileAddressFor(sessionId: string, cwd: string | undefined, path: string): string {\r\n const normalized = path.replace(/\\\\/g, '/')\r\n if (!isAbsoluteWorkspacePath(normalized)) return sessionFileAddress(sessionId, normalized)\r\n const root = cwd === undefined ? '' : cwd.replace(/\\\\/g, '/').replace(/\\/+$/, '')\r\n if (root !== '' && normalized === root) return sessionFileAddress(sessionId, '')\r\n if (root !== '' && normalized.startsWith(`${root}/`)) {\r\n return sessionFileAddress(sessionId, normalized.slice(root.length + 1))\r\n }\r\n return sessionFileAddress(sessionId, normalized)\r\n}\r\n\r\n/**\r\n * Build a sidebar file opener for one session, or `undefined` when the\r\n * environment cannot open previews (no `sidebarRight` service, no session).\r\n * The cwd is re-read per call inside the opener, so a workspace switch between\r\n * renders is picked up on the next click.\r\n *\r\n * @param ctx - the client root context.\r\n * @param sessionId - the session whose workspace resolves paths.\r\n * @returns an opener that routes a produced path to the Sidebar preview.\r\n */\r\nexport function sidebarFileOpener(\r\n ctx: Context | undefined,\r\n sessionId: string | undefined,\r\n): ((path: string) => void) | undefined {\r\n if (ctx === undefined || sessionId === undefined) return undefined\r\n const bar = ctx.get('sidebarRight') as SidebarRightLike | undefined\r\n if (bar === undefined || typeof bar.openResource !== 'function') return undefined\r\n\r\n return (path: string) => {\r\n const sessions = ctx.get('sessions') as SessionsListLike | undefined\r\n const cwd = sessions?.list?.getSnapshot?.().byId?.[sessionId]?.cwd\r\n bar.openResource(fileAddressFor(sessionId, cwd, path))\r\n }\r\n}\r\n","/**\r\n * The `dshSummaryDeliverables` projection — reading and classifying it.\r\n *\r\n * The Host computes this projection (this plugin's own node half registers the\r\n * unit) and pushes finished whole values; the client never folds it. This\r\n * module is the read side of that contract and is deliberately PURE — no\r\n * React, no context, no IO — so the narrowing and the codeplan classification\r\n * can be tested directly.\r\n */\r\nimport type { DeliverablesView } from '../../projection/keys'\r\n\r\n/**\r\n * Narrow a raw projection value into a deliverables view.\r\n *\r\n * Two outcomes are kept apart on purpose, mirroring the store's contract:\r\n * - `undefined` — the capability is ABSENT (the host half never registered —\r\n * e.g. an older composition — or no frame carried the key yet);\r\n * - a view — the projection is live. A view with `latest: null` and\r\n * `sessionTotal: 0` IS the empty state; the fold starts publishing as soon\r\n * as the unit registers, so \"present but empty\" is a real value here, not a\r\n * sentinel.\r\n *\r\n * @param value - the raw `unknown` snapshot of the deliverables face.\r\n * @returns the validated view, or `undefined` when the capability is absent.\r\n */\r\nexport function readDeliverables(value: unknown): DeliverablesView | undefined {\r\n if (value === null || typeof value !== 'object' || Array.isArray(value)) return undefined\r\n const raw = value as { latest?: unknown; sessionPaths?: unknown; sessionTotal?: unknown }\r\n if (raw.latest === undefined || raw.sessionPaths === undefined || raw.sessionTotal === undefined) {\r\n return undefined\r\n }\r\n if (!isBucket(raw.latest) || !Array.isArray(raw.sessionPaths) || typeof raw.sessionTotal !== 'number') {\r\n return undefined\r\n }\r\n const paths = raw.sessionPaths.filter((path): path is string => typeof path === 'string')\r\n return {\r\n latest: raw.latest === null ? null : { turn: raw.latest.turn, paths: raw.latest.paths },\r\n sessionPaths: paths,\r\n sessionTotal: raw.sessionTotal,\r\n }\r\n}\r\n\r\n/** Whether a value is a well-formed latest-turn bucket (or explicitly null). */\r\nfunction isBucket(value: unknown): value is { turn: number; paths: readonly string[] } | null {\r\n if (value === null) return true\r\n if (typeof value !== 'object') return false\r\n const bucket = value as { turn?: unknown; paths?: unknown }\r\n return typeof bucket.turn === 'number' && Array.isArray(bucket.paths)\r\n}\r\n\r\n/**\r\n * The path prefix that identifies a codeplan artifact. The codeplan skill\r\n * writes its four fixed artifacts under `$workspace\\.agents\\plans\\<任务名>\\`;\r\n * produced paths may spell the separators either way.\r\n */\r\nconst CODEPLAN_SEGMENT = '.agents/plans/'\r\n\r\n/**\r\n * Normalize path separators so one spelling of the codeplan prefix matches.\r\n * Only classification uses this; the displayed path keeps the tool's exact\r\n * spelling.\r\n */\r\nfunction normalized(path: string): string {\r\n return path.replaceAll('\\\\', '/')\r\n}\r\n\r\n/** Whether a produced path is a codeplan artifact. */\r\nexport function isCodeplanPath(path: string): boolean {\r\n return normalized(path).includes(CODEPLAN_SEGMENT)\r\n}\r\n\r\n/**\r\n * Split a codeplan path into its task name and file name.\r\n *\r\n * @param path - a produced path; need not actually be a codeplan artifact.\r\n * @returns task and file names, or `null` when the path is not under the\r\n * codeplan plans directory (or names no file beneath the task folder).\r\n */\r\nexport function splitCodeplanPath(path: string): { task: string; file: string } | null {\r\n const marker = normalized(path).indexOf(CODEPLAN_SEGMENT)\r\n if (marker < 0) return null\r\n const rest = normalized(path).slice(marker + CODEPLAN_SEGMENT.length)\r\n const slash = rest.indexOf('/')\r\n if (slash <= 0 || slash === rest.length - 1) return null\r\n return { task: rest.slice(0, slash), file: rest.slice(slash + 1) }\r\n}\r\n\r\n/** The final path segment, under either separator. */\r\nexport function basename(path: string): string {\r\n const normalizedPath = normalized(path)\r\n const slash = normalizedPath.lastIndexOf('/')\r\n return slash < 0 ? normalizedPath : normalizedPath.slice(slash + 1)\r\n}\r\n\r\n/**\r\n * 历史文件 = 全会话去重路径 − 本回合活跃路径。\r\n *\r\n * 分隔符归一化后比较(`a\\b` 与 `a/b` 视为同一路径),保持 sessionPaths 自带的\r\n * \"最近在前\"顺序;活跃路径一个都不出现——分层契约:活跃的已在上方列表里,\r\n * 折叠区只收\"更早改过的文件\"。\r\n */\r\nexport function historyPaths(sessionPaths: readonly string[], latestPaths: readonly string[]): string[] {\r\n const active = new Set(latestPaths.map(normalized))\r\n return sessionPaths.filter((path) => !active.has(normalized(path)))\r\n}\r\n","/**\r\n * The two group chrome pieces the summary sections share: a counted group\r\n * title, and the toggle that folds a group away.\r\n *\r\n * Extracted because the deliverables section (本回合 / 更早改动) and the recall\r\n * section (活跃召回 / 其余历史召回) now fold a history group the same way. Two\r\n * private copies of the same button would drift the first time either section\r\n * touches padding — and the whole point of the split is that a reader can tell\r\n * \"what is live now\" from \"what the session also contains\" without learning a\r\n * different layout per section.\r\n *\r\n * Colours come from `--dsw-alias-*` tokens only (skin contract, enforced by\r\n * `tests/purity.spec.ts`).\r\n */\r\nimport { createElement } from 'react'\r\nimport type { CSSProperties, ReactNode } from 'react'\r\n\r\n/** Section-level title under the section header: quieter, same left gutter. */\r\nconst GROUP_HEADER_STYLE: CSSProperties = {\r\n padding: '8px 12px 0',\r\n color: 'var(--dsw-alias-label-tertiary)',\r\n fontSize: 11,\r\n fontWeight: 600,\r\n}\r\n\r\n/** The fold switch: full-width hit area, tertiary text, chevron at the end. */\r\nconst TOGGLE_STYLE: CSSProperties = {\r\n background: 'none',\r\n border: 'none',\r\n font: 'inherit',\r\n fontSize: 12,\r\n color: 'var(--dsw-alias-label-tertiary)',\r\n cursor: 'pointer',\r\n display: 'flex',\r\n alignItems: 'center',\r\n gap: 4,\r\n padding: '6px 12px',\r\n textAlign: 'left',\r\n width: 'calc(100% - 24px)',\r\n}\r\n\r\n/** The note beside a folded group (e.g. how many the capped list left out). */\r\nconst CAPTION_STYLE: CSSProperties = {\r\n padding: '0 12px 6px',\r\n color: 'var(--dsw-alias-label-tertiary)',\r\n fontSize: 11,\r\n lineHeight: '16px',\r\n}\r\n\r\nconst CHEVRON_STYLE = (open: boolean): CSSProperties => ({\r\n flexShrink: 0,\r\n transition: 'transform 0.16s',\r\n transform: open ? 'rotate(180deg)' : 'none',\r\n})\r\n\r\n/**\r\n * A counted group title. Renders nothing when the group is empty — an empty\r\n * \"活跃召回 · 0\" line would ask the reader to explain a heading rather than read\r\n * a fact.\r\n * @param props - already-interpolated text, plus an optional DOM marker.\r\n */\r\nexport function GroupHeader(props: { text: string; marker?: string }): ReactNode {\r\n if (props.text.length === 0) return null\r\n return createElement(\r\n 'div',\r\n {\r\n style: GROUP_HEADER_STYLE,\r\n 'data-dsh-brief-sidebar': props.marker ?? 'group-header',\r\n },\r\n props.text,\r\n )\r\n}\r\n\r\n/**\r\n * The fold switch. `marker` is what tests (and the browser probe) click, so it\r\n * belongs to the component rather than to either caller's markup.\r\n * @param props - label, current state, DOM marker, click handler.\r\n */\r\nexport function FoldToggle(props: {\r\n label: string\r\n open: boolean\r\n marker: string\r\n onToggle(): void\r\n}): ReactNode {\r\n const { label, open, marker } = props\r\n return createElement(\r\n 'button',\r\n {\r\n type: 'button',\r\n 'aria-expanded': open,\r\n style: TOGGLE_STYLE,\r\n 'data-dsh-brief-sidebar': marker,\r\n onClick: () => { props.onToggle() },\r\n },\r\n label,\r\n createElement(\r\n 'svg',\r\n { width: 10, height: 10, viewBox: '0 0 16 16', 'aria-hidden': true, style: CHEVRON_STYLE(open) },\r\n createElement('path', {\r\n d: 'M4 6l4 4 4-4',\r\n fill: 'none',\r\n stroke: 'currentColor',\r\n strokeWidth: 1.5,\r\n strokeLinecap: 'round',\r\n strokeLinejoin: 'round',\r\n }),\r\n ),\r\n )\r\n}\r\n\r\n/** A quiet caption under a group, used for the \"the list is capped\" note. */\r\nexport function GroupCaption(props: { text: string; marker: string }): ReactNode {\r\n return createElement('div', { style: CAPTION_STYLE, 'data-dsh-brief-sidebar': props.marker }, props.text)\r\n}\r\n","/**\n * Plugin-owned i18n dictionaries.\n *\n * Consumer plugins must NOT reach into better-sidebar's internal `t()` or its\n * `betterSidebar` dictionary namespace, so this plugin registers its own\n * namespace through the DSH `locale` service. `dsh-brief-sidebar` is outside the\n * `LocaleNamespaceMap` merge table, which is exactly what the untyped\n * `register(ns, dicts)` overload is for — but the dictionaries themselves stay\n * strictly paired: `zh` is the key-set source of truth and every other language\n * (`en`, plus the fr/de/it/ru/es pack) is typed as\n * `Record<keyof typeof zh, string>`, so a missing or extra key is a COMPILE\n * error rather than a runtime fallback to the raw key.\n *\n * Every key referenced anywhere in `src/**` must exist in both dictionaries;\n * `tests/purity.spec.ts` asserts that, so a typo in a `t('…')` call cannot\n * ship as an untranslated literal.\n */\n\n/** The namespace owned by this plugin (own vocabulary, own lifecycle). */\nexport const NS = 'dsh-brief-sidebar'\n\n/** Simplified Chinese dictionary — the key-set source of truth. */\nexport const zh = {\n 'tab.title': '概要',\n 'tab.desc': '当前会话的任务、产物与规划文件(只读)',\n 'section.progress': '进展',\n 'section.deliverables': '产物',\n 'board.empty': '当前没有任务',\n 'board.emptyHint': '模型调用 todo_write 之后,任务会出现在这里。',\n 'board.unavailable': '任务暂不可用',\n 'board.unavailableHint': '这个会话还没有收到 todo 数据;宿主推来第一帧后会自动显示。',\n 'status.pending': '待处理',\n 'status.inProgress': '进行中',\n 'status.completed': '已完成',\n 'deliverables.empty': '本回合暂无改动文件',\n 'deliverables.emptyHint': '会话里成功写入或修改文件后,它们会实时出现在这里。',\n 'deliverables.history': '更早改动的文件 · {count}',\n 'deliverables.currentTurn': '本回合改动 · {count}',\n 'deliverables.historyCapped': '(会话共 {total} 个文件,列表已截断)',\n 'deliverable.codeplanTag': '规划',\n 'section.memorySlots': '记忆',\n 'slots.empty': '当前没有激活的记忆槽位',\n 'slots.emptyHint': '当 dsh-prime-memory 激活记忆槽位后,它们会实时出现在这里。',\n 'slots.openCount': '开启 {count} 个槽位',\n 'slots.status.open': '生效中',\n 'slots.status.done': '已完成',\n 'slots.status.dropped': '已弃置',\n 'slots.status.expired': '已过期',\n 'section.memoryRecall': '本会话召回',\n 'recall.empty': '本会话还没有召回到记忆',\n 'recall.count': '注入 {count} 条 · 被摘要取代的已折叠(清空会话才清除)',\n 'recall.rateHint': '点选一条后可标注:0–5 相关度;-1 声明过时并退场(可恢复)',\n 'recall.obsolete': '声明过时',\n 'recall.obsoleteConfirm': '确认退场?',\n 'recall.obsoleted': '已判过时',\n 'recall.rated': '已评 {count} 分',\n 'recall.failed': '标注失败:',\n 'recall.obsoleteWhy': '声明过时后,该记忆退场(可恢复),下一轮会告知模型',\n 'recall.strikeHint': ';判过时的条目会一直保留在列表里并划上删除线(清空会话才移除)',\n 'recall.supersededHidden': '已隐藏 {count} 条被摘要取代的旧召回(正文已不在上下文)',\n 'recall.activeGroup': '活跃召回 · {count}',\n 'recall.historyGroup': '其余历史召回 · {count}',\n 'recall.supersededTag': '已被摘要取代',\n 'recall.noBody': '(本帧没有这条记忆的全文)',\n 'section.skillUsage': '技能引用',\n 'skillUsage.empty': '本会话还没载入过技能',\n 'skillUsage.emptyHint': '模型用 skill 工具载入技能后,技能名会实时出现在这里。',\n 'skillUsage.uses': '{count} 次',\n 'skillUsage.count': '载入 {count} 次 · {total} 个技能',\n 'skillUsage.latestTag': '本轮',\n 'settings.title': '概要侧栏',\n 'settings.desc': '右侧栏概要 tab 的分区开关(只读展示)。',\n 'settings.memorySlots': '记忆槽位分区',\n 'settings.memorySlotsHint': '开启后,概要 tab 在进展与产物之下显示 dsh-prime-memory 的激活记忆槽位(只读)。',\n 'settings.memoryRecall': '本会话召回分区',\n 'settings.memoryRecallHint': '开启后,概要 tab 显示本会话已注入的记忆,并可标注相关度(0–5;-1 声明过时并退场)。被摘要取代的条目会自动折叠。',\n 'settings.unavailable': '配置面不可用,记忆分区按默认「开」处理。',\n 'settings.readonly': '当前配置只读,无法在此修改。',\n}\n\n/** The key union: what a `t('…')` call may name inside this namespace. */\nexport type BriefKey = keyof typeof zh\n\n/** English dictionary, checked complete against the zh key set. */\nexport const en: Record<BriefKey, string> = {\n 'tab.title': 'Summary',\n 'tab.desc': 'Tasks, produced files and plan artifacts of this session (read-only)',\n 'section.progress': 'Progress',\n 'section.deliverables': 'Produced files',\n 'board.empty': 'No tasks yet',\n 'board.emptyHint': 'Tasks show up here once the model calls todo_write.',\n 'board.unavailable': 'Tasks unavailable',\n 'board.unavailableHint':\n 'This session has not received any todo data yet; the board fills in on the first frame.',\n 'status.pending': 'Pending',\n 'status.inProgress': 'In progress',\n 'status.completed': 'Done',\n 'deliverables.empty': 'No files changed in this turn',\n 'deliverables.emptyHint': 'Files written or edited successfully in the session appear here live.',\n 'deliverables.history': 'Earlier changes · {count}',\n 'deliverables.currentTurn': 'This turn · {count}',\n 'deliverables.historyCapped': '(the session produced {total} files; the list is capped)',\n 'deliverable.codeplanTag': 'Plan',\n 'section.memorySlots': 'Memory',\n 'slots.empty': 'No active memory slots',\n 'slots.emptyHint': 'Slots appear here live once dsh-prime-memory activates them.',\n 'slots.openCount': '{count} slots open',\n 'slots.status.open': 'Open',\n 'slots.status.done': 'Done',\n 'slots.status.dropped': 'Dropped',\n 'slots.status.expired': 'Expired',\n 'section.memoryRecall': 'Session recall',\n 'recall.empty': 'No memories recalled in this session yet',\n 'recall.count': '{count} injected · superseded ones folded after compaction (cleared only on /clear)',\n 'recall.rateHint': 'Select a memory to mark it: 0–5 relevance; -1 declares it obsolete and retires it (restorable).',\n 'recall.obsolete': 'Obsolete',\n 'recall.obsoleteConfirm': 'Retire it?',\n 'recall.obsoleted': 'Marked obsolete',\n 'recall.rated': 'Rated {count}/5',\n 'recall.failed': 'Mark failed: ',\n 'recall.obsoleteWhy': 'Declaring it obsolete retires the record (restorable) and tells the model next turn',\n 'recall.strikeHint': '; an entry you mark obsolete stays listed, struck through (removed only when you clear the session)',\n 'recall.supersededHidden': '{count} older recalls hidden — their text was replaced by a summary',\n 'recall.activeGroup': 'Active recalls · {count}',\n 'recall.historyGroup': 'Earlier recalls · {count}',\n 'recall.supersededTag': 'replaced by summary',\n 'recall.noBody': '(this frame carries no full body for this record)',\n 'section.skillUsage': 'Skill references',\n 'skillUsage.empty': 'No skills loaded in this session',\n 'skillUsage.emptyHint': 'Skills appear here as soon as the model loads one with the skill tool.',\n 'skillUsage.uses': '{count}x',\n 'skillUsage.count': '{count} loads - {total} skills',\n 'skillUsage.latestTag': 'this turn',\n 'settings.title': 'Brief sidebar',\n 'settings.desc': 'Section switches for the summary tab in the right sidebar (read-only views).',\n 'settings.memorySlots': 'Memory slots section',\n 'settings.memorySlotsHint': 'When on, the summary tab lists the active memory slots from dsh-prime-memory beneath progress and produced files (read-only).',\n 'settings.memoryRecall': 'Session recall section',\n 'settings.memoryRecallHint': 'When on, the Summary tab lists the memories injected this session and lets you rate them (0–5; -1 declares one obsolete and retires it). Entries a summary replaced are folded away.',\n 'settings.unavailable': 'The config face is unavailable; the memory section falls back to its default (on).',\n 'settings.readonly': 'This config is read-only here; edits are not available.',\n}\n\n/** Japanese dictionary, checked complete against the zh key set. */\nexport const ja: Record<BriefKey, string> = {\n 'tab.title': '概要',\n 'tab.desc': 'このセッションのタスク・成果物・計画ファイル(読み取り専用)',\n 'section.progress': '進行状況',\n 'section.deliverables': '成果物',\n 'board.empty': '現在タスクはありません',\n 'board.emptyHint': 'モデルが todo_write を呼び出すと、タスクがここに表示されます。',\n 'board.unavailable': 'タスクを利用できません',\n 'board.unavailableHint':\n 'このセッションはまだ todo データを受信していません。ホストが最初のフレームを送ると自動的に表示されます。',\n 'status.pending': '未対応',\n 'status.inProgress': '進行中',\n 'status.completed': '完了',\n 'deliverables.empty': 'このターンで変更されたファイルはありません',\n 'deliverables.emptyHint': 'セッションでファイルの書き込み・変更が成功すると、ここにリアルタイムで表示されます。',\n 'deliverables.history': '以前の変更 · {count}',\n 'deliverables.currentTurn': 'このターン · {count}',\n 'deliverables.historyCapped': '(セッション全体で {total} ファイル、一覧は上限で省略)',\n 'deliverable.codeplanTag': '計画',\n 'section.memorySlots': 'メモリ',\n 'slots.empty': 'アクティブなメモリスロットはありません',\n 'slots.emptyHint': 'dsh-prime-memory がスロットをアクティブにすると、ここにリアルタイムで表示されます。',\n 'slots.openCount': '有効なスロット: {count} 件',\n 'slots.status.open': '有効',\n 'slots.status.done': '完了',\n 'slots.status.dropped': '破棄',\n 'slots.status.expired': '期限切れ',\n 'section.memoryRecall': 'このセッションの想起',\n 'recall.empty': 'このセッションではまだ記憶を想起していません',\n 'recall.count': '{count} 件を注入 · 要約に置き換わった分は折りたたみ(/clear でのみ消去)',\n 'recall.rateHint': '行を選ぶと採点できます:0–5 関連度;-1 は「古い」と宣言して退場(復元可)。',\n 'recall.obsolete': '古いと宣言',\n 'recall.obsoleteConfirm': '退場させますか?',\n 'recall.obsoleted': '古いと判定済み',\n 'recall.rated': '{count} 点',\n 'recall.failed': '採点に失敗:',\n 'recall.obsoleteWhy': '古いと宣言すると記録は退場(復元可)、次のターンでモデルに伝わります',\n 'recall.strikeHint': ';古いと宣言した項目は取り消し線のまま一覧に保持されます(セッションをクリアすると消えます)',\n 'recall.supersededHidden': '要約に置き換わった旧召回 {count} 件を非表示(本文はコンテキストにない)',\n 'recall.activeGroup': 'アクティブな想起 · {count}',\n 'recall.historyGroup': 'その他の履歴想起 · {count}',\n 'recall.supersededTag': '要約に置換済み',\n 'recall.noBody': 'このフレームには全文が含まれていない',\n 'section.skillUsage': 'スキル参照',\n 'skillUsage.empty': 'このセッションではスキルを読み込んでいません',\n 'skillUsage.emptyHint': 'モデルが skill ツールでスキルを読み込むと、ここにリアルタイムで表示されます。',\n 'skillUsage.uses': '{count} 回',\n 'skillUsage.count': '読み込み {count} 回 · スキル {total} 件',\n 'skillUsage.latestTag': 'このターン',\n 'settings.title': '概要サイドバー',\n 'settings.desc': '右サイドバー概要タブのセクション表示切り替え(読み取り専用)。',\n 'settings.memorySlots': 'メモリスロットセクション',\n 'settings.memorySlotsHint': 'オンにすると、概要タブの進行状況と成果物の下に dsh-prime-memory のアクティブなメモリスロット(読み取り専用)が表示されます。',\n 'settings.memoryRecall': 'セッション想起のセクション',\n 'settings.memoryRecallHint': '有効にすると概要タブに本セッションで注入された記憶を表示し、関連度(0–5、-1 は陳腐化を宣言して退場)を付けられます。要約に置き換わった項目は自動で折りたたまれます。',\n 'settings.unavailable': '設定画面を利用できません。メモリセクションは既定(オン)で動作します。',\n 'settings.readonly': 'この設定はここでは読み取り専用のため変更できません。',\n}\n\n/** Korean dictionary, checked complete against the zh key set. */\nexport const ko: Record<BriefKey, string> = {\n 'tab.title': '요약',\n 'tab.desc': '현재 세션의 작업, 산출물 및 계획 파일(읽기 전용)',\n 'section.progress': '진행 상황',\n 'section.deliverables': '산출물',\n 'board.empty': '현재 작업이 없습니다',\n 'board.emptyHint': '모델이 todo_write를 호출하면 작업이 여기에 표시됩니다.',\n 'board.unavailable': '작업을 사용할 수 없습니다',\n 'board.unavailableHint':\n '이 세션은 아직 todo 데이터를 받지 못했습니다. 호스트가 첫 프레임을 보내면 자동으로 표시됩니다.',\n 'status.pending': '대기 중',\n 'status.inProgress': '진행 중',\n 'status.completed': '완료',\n 'deliverables.empty': '이번 턴에 변경된 파일이 없습니다',\n 'deliverables.emptyHint': '세션에서 파일을 성공적으로 작성하거나 수정하면 여기에 실시간으로 표시됩니다.',\n 'deliverables.history': '이전 변경 사항 · {count}',\n 'deliverables.currentTurn': '이번 턴 · {count}',\n 'deliverables.historyCapped': '(세션 전체 {total}개 파일, 목록은 잘림)',\n 'deliverable.codeplanTag': '계획',\n 'section.memorySlots': '메모리',\n 'slots.empty': '활성화된 메모리 슬롯이 없습니다',\n 'slots.emptyHint': 'dsh-prime-memory가 슬롯을 활성화하면 여기에 실시간으로 표시됩니다.',\n 'slots.openCount': '열린 슬롯: {count}개',\n 'slots.status.open': '활성',\n 'slots.status.done': '완료',\n 'slots.status.dropped': '폐기',\n 'slots.status.expired': '만료',\n 'section.memoryRecall': '이 세션 회상',\n 'recall.empty': '이 세션에서는 아직 기억을 회상하지 않았습니다',\n 'recall.count': '{count}건 주입 · 요약으로 대체된 항목은 접힘(/clear 시에만 삭제)',\n 'recall.rateHint': '항목을 선택하면 평가할 수 있습니다: 0–5 관련도; -1은 오래된 것으로 선언하여 삭제(복원 가능).',\n 'recall.obsolete': '오래됨 선언',\n 'recall.obsoleteConfirm': '삭제할까요?',\n 'recall.obsoleted': '오래된 것으로 판정됨',\n 'recall.rated': '{count}점 평가됨',\n 'recall.failed': '평가 실패: ',\n 'recall.obsoleteWhy': '낡음으로 선언하면 기록이 퇴장하며(복원 가능), 다음 턴에서 모델에 알립니다',\n 'recall.strikeHint': ';낡음으로 선언한 항목은 취소선 상태로 목록에 계속 표시됩니다(세션을 비우면 제거)',\n 'recall.supersededHidden': '요약으로 대체된 이전 회수 {count}건 숨김(본문이 컨텍스트에 없음)',\n 'recall.activeGroup': '활성 회상 · {count}',\n 'recall.historyGroup': '나머지 이전 회상 · {count}',\n 'recall.supersededTag': '요약에 대체됨',\n 'recall.noBody': '이 프레임에는 이 기록의 전문이 없습니다',\n 'section.skillUsage': '스킬 참조',\n 'skillUsage.empty': '이 세션에서 스킬을 불러오지 않았습니다',\n 'skillUsage.emptyHint': '모델이 skill 도구로 스킬을 불러오면 여기에 즉시 표시됩니다.',\n 'skillUsage.uses': '{count}회',\n 'skillUsage.count': '불러오기 {count}회 · 스킬 {total}개',\n 'skillUsage.latestTag': '이 턴',\n 'settings.title': '요약 사이드바',\n 'settings.desc': '오른쪽 사이드바 요약 탭의 섹션 표시 전환(읽기 전용).',\n 'settings.memorySlots': '메모리 슬롯 섹션',\n 'settings.memorySlotsHint': '켜면 요약 탭의 진행 상황과 산출물 아래에 dsh-prime-memory의 활성 메모리 슬롯(읽기 전용)이 표시됩니다.',\n 'settings.memoryRecall': '세션 회상 섹션',\n 'settings.memoryRecallHint': '켜면 요약 탭에 이번 세션에서 주입된 기억을 표시하고 관련도(0–5, -1은 노후 선언 후 퇴장)를 매길 수 있습니다. 요약으로 대체된 항목은 자동으로 접힙니다.',\n 'settings.unavailable': '설정 화면을 사용할 수 없어 메모리 섹션은 기본값(켜짐)으로 동작합니다.',\n 'settings.readonly': '이 설정은 여기서 읽기 전용이므로 변경할 수 없습니다.',\n}\n\n/** French dictionary, checked complete against the zh key set. */\nexport const fr: Record<BriefKey, string> = {\n 'tab.title': 'Résumé',\n 'tab.desc': 'Tâches, fichiers produits et plans de la session (lecture seule)',\n 'section.progress': 'Avancement',\n 'section.deliverables': 'Fichiers produits',\n 'board.empty': 'Aucune tâche pour le moment',\n 'board.emptyHint': 'Les tâches apparaissent ici dès que le modèle appelle todo_write.',\n 'board.unavailable': 'Tâches indisponibles',\n 'board.unavailableHint':\n 'Cette session n’a pas encore reçu de données todo ; le tableau se remplit dès la première trame.',\n 'status.pending': 'En attente',\n 'status.inProgress': 'En cours',\n 'status.completed': 'Terminé',\n 'deliverables.empty': 'Aucun fichier modifié à ce tour',\n 'deliverables.emptyHint': 'Les fichiers écrits ou modifiés dans la session apparaissent ici en direct.',\n 'deliverables.history': 'Modifications antérieures · {count}',\n 'deliverables.currentTurn': 'Ce tour-ci · {count}',\n 'deliverables.historyCapped': '(la session a produit {total} fichiers ; la liste est tronquée)',\n 'deliverable.codeplanTag': 'Plan',\n 'section.memorySlots': 'Mémoire',\n 'slots.empty': 'Aucun emplacement mémoire actif',\n 'slots.emptyHint': 'Les emplacements apparaissent ici en direct dès que dsh-prime-memory les active.',\n 'slots.openCount': '{count} emplacements ouverts',\n 'slots.status.open': 'Actif',\n 'slots.status.done': 'Terminé',\n 'slots.status.dropped': 'Abandonné',\n 'slots.status.expired': 'Expiré',\n 'section.memoryRecall': 'Rappel de la session',\n 'recall.empty': 'Aucun souvenir rappelé dans cette session',\n 'recall.count': '{count} injectés · les remplacés par un résumé sont repliés après compression (effacés par /clear)',\n 'recall.rateHint': 'Sélectionnez un souvenir pour le noter : 0–5 pertinence ; -1 le déclare obsolète et le retire (récupérable).',\n 'recall.obsolete': 'Obsolète',\n 'recall.obsoleteConfirm': 'Le retirer ?',\n 'recall.obsoleted': 'Déclaré obsolète',\n 'recall.rated': 'Noté {count}/5',\n 'recall.failed': 'Échec de la note : ',\n 'recall.obsoleteWhy': 'Déclarer obsolète retire l’enregistrement (récupérable) et prévient le modèle au tour suivant',\n 'recall.strikeHint': ' ; une entrée déclarée obsolète reste listée, barrée (retirée uniquement quand vous videz la session)',\n 'recall.supersededHidden': '{count} anciens rappels masqués — leur texte a été remplacé par un résumé',\n 'recall.activeGroup': 'Rappels actifs · {count}',\n 'recall.historyGroup': 'Rappels antérieurs · {count}',\n 'recall.supersededTag': 'remplacé par le résumé',\n 'recall.noBody': '(aucun texte complet pour cette entrée dans cette trame)',\n 'section.skillUsage': 'Références de compétences',\n 'skillUsage.empty': 'Aucune compétence chargée dans cette session',\n 'skillUsage.emptyHint': 'Les compétences apparaissent ici dès que le modèle en charge une avec l’outil skill.',\n 'skillUsage.uses': '{count}×',\n 'skillUsage.count': '{count} chargements · {total} compétences',\n 'skillUsage.latestTag': 'ce tour',\n 'settings.title': 'Barre latérale Résumé',\n 'settings.desc': 'Interrupteurs des sections de l’onglet Résumé de la barre latérale (lecture seule).',\n 'settings.memorySlots': 'Section des emplacements mémoire',\n 'settings.memorySlotsHint': 'Une fois activé, l’onglet Résumé liste les emplacements mémoire actifs de dsh-prime-memory sous l’avancement et les fichiers produits (lecture seule).',\n 'settings.memoryRecall': 'Section rappel de session',\n 'settings.memoryRecallHint': 'Actif, onglet Résumé : liste les souvenirs injectés dans cette session et permet de les noter (0–5 ; -1 déclare obsolète et retire). Les entrées remplacées par un résumé sont repliées.',\n 'settings.unavailable': 'Le canal de configuration est indisponible ; la section mémoire revient à sa valeur par défaut (activée).',\n 'settings.readonly': 'Cette configuration est en lecture seule ici ; aucune modification possible.',\n}\n\n/** German dictionary, checked complete against the zh key set. */\nexport const de: Record<BriefKey, string> = {\n 'tab.title': 'Übersicht',\n 'tab.desc': 'Aufgaben, erzeugte Dateien und Pläne dieser Sitzung (schreibgeschützt)',\n 'section.progress': 'Fortschritt',\n 'section.deliverables': 'Erzeugte Dateien',\n 'board.empty': 'Noch keine Aufgaben',\n 'board.emptyHint': 'Aufgaben erscheinen hier, sobald das Modell todo_write aufruft.',\n 'board.unavailable': 'Aufgaben nicht verfügbar',\n 'board.unavailableHint':\n 'Diese Sitzung hat noch keine Todo-Daten erhalten; das Board füllt sich mit dem ersten Frame.',\n 'status.pending': 'Ausstehend',\n 'status.inProgress': 'In Bearbeitung',\n 'status.completed': 'Fertig',\n 'deliverables.empty': 'Keine Dateien in diesem Durchgang geändert',\n 'deliverables.emptyHint': 'In der Sitzung erfolgreich geschriebene oder geänderte Dateien erscheinen hier live.',\n 'deliverables.history': 'Frühere Änderungen · {count}',\n 'deliverables.currentTurn': 'Dieser Durchlauf · {count}',\n 'deliverables.historyCapped': '(die Sitzung erzeugte {total} Dateien; die Liste ist gekürzt)',\n 'deliverable.codeplanTag': 'Plan',\n 'section.memorySlots': 'Gedächtnis',\n 'slots.empty': 'Keine aktiven Speicherplätze',\n 'slots.emptyHint': 'Sobald dsh-prime-memory Slots aktiviert, erscheinen sie hier in Echtzeit.',\n 'slots.openCount': '{count} Slots offen',\n 'slots.status.open': 'Offen',\n 'slots.status.done': 'Erledigt',\n 'slots.status.dropped': 'Verworfen',\n 'slots.status.expired': 'Abgelaufen',\n 'section.memoryRecall': 'Sitzungserinnerung',\n 'recall.empty': 'In dieser Sitzung wurden noch keine Erinnerungen geholt',\n 'recall.count': '{count} eingefügt · die durch eine Zusammenfassung ersetzten sind nach der Komprimierung eingeklappt (bei /clear gelöscht)',\n 'recall.rateHint': 'Ein Eintrag auswählen zum Bewerten: 0–5 Relevanz; -1 erklärt ihn für veraltet und entfernt ihn (wiederherstellbar).',\n 'recall.obsolete': 'Veraltet',\n 'recall.obsoleteConfirm': 'Entfernen?',\n 'recall.obsoleted': 'Als veraltet markiert',\n 'recall.rated': 'Bewertet {count}/5',\n 'recall.failed': 'Bewertung fehlgeschlagen: ',\n 'recall.obsoleteWhy': 'Als veraltet erklären versetzt den Eintrag in den Ruhestand (wiederherstellbar) und informiert das Modell in der nächsten Runde',\n 'recall.strikeHint': '; ein als veraltet markierter Eintrag bleibt durchgestrichen in der Liste (erst beim Leeren der Sitzung entfernt)',\n 'recall.supersededHidden': '{count} ältere Treffer ausgeblendet — ihr Text wurde durch eine Zusammenfassung ersetzt',\n 'recall.activeGroup': 'Aktive Abrufe · {count}',\n 'recall.historyGroup': 'Weitere Abrufe · {count}',\n 'recall.supersededTag': 'durch Zusammenfassung ersetzt',\n 'recall.noBody': '(dieser Rahmen enthält keinen vollständigen Text für diesen Eintrag)',\n 'section.skillUsage': 'Skill-Referenzen',\n 'skillUsage.empty': 'In dieser Sitzung wurden keine Skills geladen',\n 'skillUsage.emptyHint': 'Skills erscheinen hier, sobald das Modell einen über das skill-Werkzeug lädt.',\n 'skillUsage.uses': '{count}x',\n 'skillUsage.count': '{count} Ladungen · {total} Skills',\n 'skillUsage.latestTag': 'diese Runde',\n 'settings.title': 'Übersicht-Seitenleiste',\n 'settings.desc': 'Schalter für die Abschnitte des Übersicht-Tabs in der rechten Seitenleiste (schreibgeschützt).',\n 'settings.memorySlots': 'Speicherplätze-Abschnitt',\n 'settings.memorySlotsHint': 'Ist der Schalter eingeschaltet, listet der Übersicht-Tab die aktiven Speicherplätze aus dsh-prime-memory unter Fortschritt und erzeugten Dateien auf (schreibgeschützt).',\n 'settings.memoryRecall': 'Bereich Sitzungserinnerung',\n 'settings.memoryRecallHint': 'Aktiv: Der Tab „Zusammenfassung“ listet die in dieser Sitzung eingefügten Erinnerungen und erlaubt Bewertungen (0–5; -1 erklärt für veraltet und entfernt). Durch eine Zusammenfassung ersetzte Einträge werden eingeklappt.',\n 'settings.unavailable': 'Die Konfigurationsoberfläche ist nicht verfügbar; der Gedächtnis-Abschnitt fällt auf den Standard (ein) zurück.',\n 'settings.readonly': 'Diese Konfiguration ist hier schreibgeschützt; Änderungen sind nicht möglich.',\n}\n\n/** Italian dictionary, checked complete against the zh key set. */\nexport const it: Record<BriefKey, string> = {\n 'tab.title': 'Riepilogo',\n 'tab.desc': 'Attività, file prodotti e piani di questa sessione (sola lettura)',\n 'section.progress': 'Avanzamento',\n 'section.deliverables': 'File prodotti',\n 'board.empty': 'Nessuna attività per ora',\n 'board.emptyHint': 'Le attività appaiono qui quando il modello chiama todo_write.',\n 'board.unavailable': 'Attività non disponibili',\n 'board.unavailableHint':\n 'Questa sessione non ha ancora ricevuto dati todo; la bacheca si riempirà al primo frame.',\n 'status.pending': 'In attesa',\n 'status.inProgress': 'In corso',\n 'status.completed': 'Completato',\n 'deliverables.empty': 'Nessun file modificato in questo turno',\n 'deliverables.emptyHint': 'I file scritti o modificati nella sessione appaiono qui in tempo reale.',\n 'deliverables.history': 'Modifiche precedenti · {count}',\n 'deliverables.currentTurn': 'Questo turno · {count}',\n 'deliverables.historyCapped': '(la sessione ha prodotto {total} file; l’elenco è troncato)',\n 'deliverable.codeplanTag': 'Piano',\n 'section.memorySlots': 'Memoria',\n 'slots.empty': 'Nessuno slot di memoria attivo',\n 'slots.emptyHint': 'Gli slot appaiono qui in tempo reale quando dsh-prime-memory li attiva.',\n 'slots.openCount': '{count} slot aperti',\n 'slots.status.open': 'Attivo',\n 'slots.status.done': 'Completato',\n 'slots.status.dropped': 'Scartato',\n 'slots.status.expired': 'Scaduto',\n 'section.memoryRecall': 'Richiamo della sessione',\n 'recall.empty': 'Nessun ricordo richiamato in questa sessione',\n 'recall.count': '{count} inseriti · quelli sostituiti da un riassunto sono ripiegati dopo la compressione (rimossi con /clear)',\n 'recall.rateHint': 'Seleziona un ricordo per valutarlo: 0–5 pertinenza; -1 lo dichiara obsoleto e lo ritira (ripristinabile).',\n 'recall.obsolete': 'Obsoleto',\n 'recall.obsoleteConfirm': 'Ritirarlo?',\n 'recall.obsoleted': 'Dichiarato obsoleto',\n 'recall.rated': 'Valutato {count}/5',\n 'recall.failed': 'Valutazione non riuscita: ',\n 'recall.obsoleteWhy': 'Dichiararlo obsoleto congeda il record (ripristinabile) e avvisa il modello al turno successivo',\n 'recall.strikeHint': '; una voce dichiarata obsoleta resta elencata, barrata (rimossa solo svuotando la sessione)',\n 'recall.supersededHidden': '{count} vecchi richiami nascosti — il testo è stato sostituito da un riassunto',\n 'recall.activeGroup': 'Richiami attivi · {count}',\n 'recall.historyGroup': 'Richiami precedenti · {count}',\n 'recall.supersededTag': 'sostituito dal riassunto',\n 'recall.noBody': '(questo frame non contiene il testo completo di questa voce)',\n 'section.skillUsage': 'Riferimenti alle skill',\n 'skillUsage.empty': 'Nessuna skill caricata in questa sessione',\n 'skillUsage.emptyHint': 'Le skill compaiono qui quando il modello ne carica una con il tool skill.',\n 'skillUsage.uses': '{count}x',\n 'skillUsage.count': '{count} caricamenti · {total} skill',\n 'skillUsage.latestTag': 'questo giro',\n 'settings.title': 'Barra laterale Riepilogo',\n 'settings.desc': 'Interruttori delle sezioni della scheda Riepilogo nella barra laterale destra (sola lettura).',\n 'settings.memorySlots': 'Sezione slot di memoria',\n 'settings.memorySlotsHint': 'Quando attivo, la scheda Riepilogo elenca gli slot di memoria attivi di dsh-prime-memory sotto avanzamento e file prodotti (sola lettura).',\n 'settings.memoryRecall': 'Sezione richiamo sessione',\n 'settings.memoryRecallHint': 'Attivo: la scheda Riepilogo elenca i ricordi inseriti in questa sessione e consente di valutarli (0–5; -1 dichiara obsoleto e ritira). Le voci sostituite da un riassunto vengono ripiegate.',\n 'settings.unavailable': 'La superficie di configurazione non è disponibile; la sezione memoria torna al valore predefinito (attivo).',\n 'settings.readonly': 'Questa configurazione è in sola lettura qui; non è possibile modificarla.',\n}\n\n/** Russian dictionary, checked complete against the zh key set. */\nexport const ru: Record<BriefKey, string> = {\n 'tab.title': 'Сводка',\n 'tab.desc': 'Задачи, созданные файлы и планы этой сессии (только чтение)',\n 'section.progress': 'Ход работы',\n 'section.deliverables': 'Созданные файлы',\n 'board.empty': 'Задач пока нет',\n 'board.emptyHint': 'Задачи появятся здесь, когда модель вызовет todo_write.',\n 'board.unavailable': 'Задачи недоступны',\n 'board.unavailableHint':\n 'Эта сессия ещё не получила данные todo; доска заполнится после первого кадра.',\n 'status.pending': 'Ожидает',\n 'status.inProgress': 'В работе',\n 'status.completed': 'Готово',\n 'deliverables.empty': 'За этот ход файлы не менялись',\n 'deliverables.emptyHint': 'Успешно записанные или изменённые файлы появляются здесь в реальном времени.',\n 'deliverables.history': 'Более ранние изменения · {count}',\n 'deliverables.currentTurn': 'Этот ход · {count}',\n 'deliverables.historyCapped': '(в сессии всего {total} файлов; список усечён)',\n 'deliverable.codeplanTag': 'План',\n 'section.memorySlots': 'Память',\n 'slots.empty': 'Активных слотов памяти нет',\n 'slots.emptyHint': 'Как только dsh-prime-memory активирует слоты, они появляются здесь в реальном времени.',\n 'slots.openCount': 'Открытых слотов: {count}',\n 'slots.status.open': 'Активен',\n 'slots.status.done': 'Завершён',\n 'slots.status.dropped': 'Отброшен',\n 'slots.status.expired': 'Истёк',\n 'section.memoryRecall': 'Воспоминания сессии',\n 'recall.empty': 'В этой сессии воспоминания ещё не вызывались',\n 'recall.count': 'Вставлено {count} · заменённые кратким изложением свёрнуты после сжатия (удаляются при /clear)',\n 'recall.rateHint': 'Выберите запись, чтобы оценить: 0–5 релевантность; -1 объявляет её устаревшей и убирает (восстановимо).',\n 'recall.obsolete': 'Устарело',\n 'recall.obsoleteConfirm': 'Убрать?',\n 'recall.obsoleted': 'Объявлено устаревшим',\n 'recall.rated': 'Оценка {count}/5',\n 'recall.failed': 'Ошибка оценки: ',\n 'recall.obsoleteWhy': 'Объявить устаревшим значит снимает запись восстанавлимо и сообщает модель на следующем ходе',\n 'recall.strikeHint': '; помеченная как устаревшая запись остаётся в списке, зачёркнутой (удаляется только при очистке сессии)',\n 'recall.supersededHidden': 'Скрыто старых воспоминаний: {count} — их текст заменён кратким изложением',\n 'recall.activeGroup': 'Активные вызовы · {count}',\n 'recall.historyGroup': 'Прочие прежние вызовы · {count}',\n 'recall.supersededTag': 'заменено сводкой',\n 'recall.noBody': 'В этом кадре нет полного текста этой записи',\n 'section.skillUsage': 'Отсылки к скиллам',\n 'skillUsage.empty': 'В этой сессии скиллы не загружались',\n 'skillUsage.emptyHint': 'Скиллы появятся здесь, как только модель загрузит их через инструмент skill.',\n 'skillUsage.uses': '{count} раз',\n 'skillUsage.count': 'Загрузок: {count} · скиллов: {total}',\n 'skillUsage.latestTag': 'этот ход',\n 'settings.title': 'Боковая панель «Сводка»',\n 'settings.desc': 'Переключатели разделов вкладки «Сводка» на правой панели (только чтение).',\n 'settings.memorySlots': 'Раздел слотов памяти',\n 'settings.memorySlotsHint': 'Когда включено, вкладка «Сводка» показывает активные слоты памяти из dsh-prime-memory под ходом работы и созданными файлами (только чтение).',\n 'settings.memoryRecall': 'Раздел Воспоминания сессии',\n 'settings.memoryRecallHint': 'Включено: вкладка «Сводка» показывает вставленные в этой сессии воспоминания и позволяет оценить их (0–5; -1 объявляет устаревшим и выводит из обращения). Заменённые кратким изложением записи сворачиваются.',\n 'settings.unavailable': 'Панель конфигурации недоступна; раздел памяти работает по умолчанию (включён).',\n 'settings.readonly': 'Эта конфигурация здесь только для чтения; изменить её нельзя.',\n}\n\n/** Spanish dictionary, checked complete against the zh key set. */\nexport const es: Record<BriefKey, string> = {\n 'tab.title': 'Resumen',\n 'tab.desc': 'Tareas, archivos generados y planes de esta sesión (solo lectura)',\n 'section.progress': 'Avance',\n 'section.deliverables': 'Archivos generados',\n 'board.empty': 'Aún no hay tareas',\n 'board.emptyHint': 'Las tareas aparecen aquí cuando el modelo llama a todo_write.',\n 'board.unavailable': 'Tareas no disponibles',\n 'board.unavailableHint':\n 'Esta sesión aún no ha recibido datos de tareas; el tablero se llena con el primer fotograma.',\n 'status.pending': 'Pendiente',\n 'status.inProgress': 'En curso',\n 'status.completed': 'Hecho',\n 'deliverables.empty': 'Ningún archivo modificado en este turno',\n 'deliverables.emptyHint': 'Los archivos escritos o editados en la sesión aparecen aquí en directo.',\n 'deliverables.history': 'Cambios anteriores · {count}',\n 'deliverables.currentTurn': 'Este turno · {count}',\n 'deliverables.historyCapped': '(la sesión produjo {total} archivos; la lista está truncada)',\n 'deliverable.codeplanTag': 'Plan',\n 'section.memorySlots': 'Memoria',\n 'slots.empty': 'No hay ranuras de memoria activas',\n 'slots.emptyHint': 'Las ranuras aparecen aquí en directo en cuanto dsh-prime-memory las active.',\n 'slots.openCount': '{count} ranuras abiertas',\n 'slots.status.open': 'Activa',\n 'slots.status.done': 'Hecha',\n 'slots.status.dropped': 'Descartada',\n 'slots.status.expired': 'Caducada',\n 'section.memoryRecall': 'Recuerdo de la sesión',\n 'recall.empty': 'Aún no se ha recuperado ningún recuerdo en esta sesión',\n 'recall.count': '{count} insertados · los reemplazados por un resumen se pliegan tras comprimir (se borran con /clear)',\n 'recall.rateHint': 'Selecciona un recuerdo para puntuarlo: 0–5 relevancia; -1 lo declara obsoleto y lo retira (recuperable).',\n 'recall.obsolete': 'Obsoleto',\n 'recall.obsoleteConfirm': '¿Retirarlo?',\n 'recall.obsoleted': 'Declarado obsoleto',\n 'recall.rated': 'Puntuado {count}/5',\n 'recall.failed': 'Error al puntuar: ',\n 'recall.obsoleteWhy': 'Declararlo obsoleto retira el registro (recuperable) y avisa al modelo en el turno siguiente',\n 'recall.strikeHint': '; una entrada marcada como obsoleta sigue en la lista, tachada (se retira solo al vaciar la sesión)',\n 'recall.supersededHidden': '{count} recuerdos antiguos ocultos — su texto fue reemplazado por un resumen',\n 'recall.activeGroup': 'Recuerdos activos · {count}',\n 'recall.historyGroup': 'Recuerdos anteriores · {count}',\n 'recall.supersededTag': 'reemplazado por el resumen',\n 'recall.noBody': '(este fotograma no trae el texto completo de este registro)',\n 'section.skillUsage': 'Referencias de skills',\n 'skillUsage.empty': 'Esta sesión no ha cargado ningún skill',\n 'skillUsage.emptyHint': 'Los skills aparecerán aquí en cuanto el modelo cargue uno con la herramienta skill.',\n 'skillUsage.uses': '{count}x',\n 'skillUsage.count': '{count} cargas · {total} skills',\n 'skillUsage.latestTag': 'este turno',\n 'settings.title': 'Barra lateral Resumen',\n 'settings.desc': 'Interruptores de las secciones de la pestaña Resumen en la barra lateral derecha (solo lectura).',\n 'settings.memorySlots': 'Sección de ranuras de memoria',\n 'settings.memorySlotsHint': 'Al activarla, la pestaña Resumen enumera las ranuras de memoria activas de dsh-prime-memory bajo el avance y los archivos generados (solo lectura).',\n 'settings.memoryRecall': 'Sección de recuerdo de sesión',\n 'settings.memoryRecallHint': 'Activado: la pestaña Resumen lista los recuerdos inyectados en esta sesión y permite puntuarlos (0–5; -1 declara obsoleto y retira). Las entradas reemplazadas por un resumen se pliegan.',\n 'settings.unavailable': 'La superficie de configuración no está disponible; la sección de memoria vuelve a su valor por defecto (activada).',\n 'settings.readonly': 'Esta configuración es de solo lectura aquí; no se puede modificar.',\n}\n\n/**\n * All locales in the shape the locale service consumes. Registered in ONE call:\n * the registry rejects a duplicate `(namespace, locale)` pair and the\n * per-locale form would leave a half-registered namespace if a later call\n * threw. `zh`/`en` are the host built-ins; the fr/de/it/ru/es pack rides the\n * same map form (every id is a valid BCP 47-style tag, so the registry accepts\n * it as-is).\n */\nexport const dictionaries: Record<string, Record<string, string>> = {\n zh,\n en,\n ja,\n ko,\n fr,\n de,\n it,\n ru,\n es,\n}\n\n/**\n * Expand the one `{count}` placeholder the deliverables totals line uses. The\n * locale binder is a plain key → string lookup (no interpolation machinery),\n * mirroring how `progressLine` composes its summary from parts.\n */\nexport function expandCount(template: string, count: number): string {\n return template.replace('{count}', String(count))\n}\n\n/**\n * Fill a `{total}` placeholder — the counter that says how many there really\n * are, as opposed to how many the (capped) list shows.\n */\nexport function expandTotal(template: string, total: number): string {\n return template.replace('{total}', String(total))\n}\n","/**\r\n * The deliverables section: the `dshSummaryDeliverables` projection drawn as\r\n * one part of the summary tab.\r\n *\r\n * Unlike the progress section this is an OPTIONAL capability: where the host\r\n * half never registered the unit (older composition, key absent), the section\r\n * hides entirely — absence is not an error state here, and the official\r\n * \"本次产出\" row in the conversation flow still covers the turn-end view.\r\n * When the projection is live, the latest turn's produced paths update\r\n * mid-turn: every successful mutation result publishes a frame, so the reader\r\n * sees files appear while the turn is still running, which is exactly the gap\r\n * the official turn-tail row has.\r\n *\r\n * Codeplan artifacts (paths under `.agents/plans/<任务名>/`) are ordinary\r\n * produced entries — they are marked with a pill, not split into a separate\r\n * section.\r\n *\r\n * Colours come from `--dsw-alias-*` tokens only (skin contract).\r\n */\r\nimport { createElement } from 'react'\r\nimport { useState } from 'react'\r\nimport type { CSSProperties, ReactNode } from 'react'\r\nimport type { Context } from '@deepseek-ai/cordis'\r\nimport { DELIVERABLES_KEY } from '../../projection/keys'\r\nimport { useProjectionValue } from '../use-projection'\r\nimport { sidebarFileOpener } from '../file-open'\r\nimport { basename, historyPaths, readDeliverables, splitCodeplanPath } from './deliverables'\r\nimport { GroupCaption, GroupHeader, FoldToggle } from './FoldToggle'\r\nimport { expandCount, expandTotal } from '../locales'\r\n\r\nexport interface DeliverablesSectionProps {\r\n /** The DSH locale lookup, passed down from `apply`. */\r\n t: (key: string) => string\r\n /** The client root context (the tab body's only way to reach services). */\r\n ctx?: Context\r\n /** The session this tab is scoped to. */\r\n scope?: { readonly sessionId?: string }\r\n}\r\n\r\nconst SECTION_STYLE: CSSProperties = {\r\n flexShrink: 0,\r\n borderBottom: '1px solid var(--dsw-alias-border-secondary)',\r\n}\r\n\r\nconst HEADER_STYLE: CSSProperties = {\r\n padding: '10px 12px 0',\r\n color: 'var(--dsw-alias-label-secondary)',\r\n fontSize: 12,\r\n fontWeight: 600,\r\n}\r\n\r\nconst LIST_STYLE: CSSProperties = {\r\n listStyle: 'none',\r\n margin: 0,\r\n padding: '6px 0',\r\n display: 'flex',\r\n flexDirection: 'column',\r\n}\r\n\r\nconst ROW_STYLE: CSSProperties = {\r\n display: 'flex',\r\n alignItems: 'flex-start',\r\n gap: 8,\r\n padding: '6px 12px',\r\n}\r\n\r\nconst PATH_STYLE: CSSProperties = {\r\n minWidth: 0,\r\n overflowWrap: 'anywhere',\r\n color: 'var(--dsw-alias-label-secondary)',\r\n}\r\n\r\n/** Row-as-button reset: the row itself is the click target, content unchanged. */\r\nconst BUTTON_STYLE: CSSProperties = {\r\n ...PATH_STYLE,\r\n background: 'none',\r\n border: 'none',\r\n font: 'inherit',\r\n fontSize: 'inherit',\r\n color: 'var(--dsw-alias-label-secondary)',\r\n padding: 0,\r\n textAlign: 'left',\r\n cursor: 'pointer',\r\n}\r\n\r\n/** The codeplan pill: same form as the status pills, tertiary emphasis. */\r\nconst TAG_STYLE: CSSProperties = {\r\n flexShrink: 0,\r\n color: 'var(--dsw-alias-label-tertiary)',\r\n border: '1px solid var(--dsw-alias-label-tertiary)',\r\n borderRadius: 999,\r\n padding: '0 6px',\r\n fontSize: 11,\r\n lineHeight: '16px',\r\n whiteSpace: 'nowrap',\r\n}\r\n\r\n/**\r\n * One produced-file row. When the sidebar opener is available the row is a\r\n * button that routes the path to the Sidebar preview (the same channel the\r\n * conversation's produced-file chips use); otherwise it degrades to a plain\r\n * span. A codeplan artifact carries the pill either way.\r\n */\r\nfunction PathRow(props: {\r\n path: string\r\n t: (key: string) => string\r\n open?: (path: string) => void\r\n}): ReactNode {\r\n const { path, t, open } = props\r\n const plan = splitCodeplanPath(path)\r\n const title = plan === null ? path : `${t('deliverable.codeplanTag')}: ${plan.task} · ${path}`\r\n const label = basename(path)\r\n const content = plan === null ? null : createElement('span', { style: TAG_STYLE }, t('deliverable.codeplanTag'))\r\n if (open === undefined) {\r\n return createElement(\r\n 'li',\r\n { style: ROW_STYLE },\r\n content,\r\n createElement('span', { style: PATH_STYLE, title }, label),\r\n )\r\n }\r\n return createElement(\r\n 'li',\r\n { style: ROW_STYLE },\r\n content,\r\n createElement('button', { style: BUTTON_STYLE, title, onClick: () => { open(path) } }, label),\r\n )\r\n}\r\n\r\n/**\r\n * The deliverables section. The subscription is unconditional (a plain\r\n * listener, not IO).\r\n *\r\n * 分层:本回合改动(latest)与全会话更早改动分成两组各自计数——前者直列,后者\r\n * 折叠在开关行后面(与活跃文件按归一化路径去重),展开后是与活跃区相同的可点击\r\n * 文件行。列表有上限时,开关行说折叠区条数、附注说会话真数,两个数不混为一谈。\r\n * @param props - translation, client context, session scope.\r\n */\r\nexport function DeliverablesSection(props: DeliverablesSectionProps): ReactNode {\r\n const { t, ctx, scope } = props\r\n const [historyOpen, setHistoryOpen] = useState(false)\r\n\r\n const view = readDeliverables(useProjectionValue(ctx, scope?.sessionId, DELIVERABLES_KEY))\r\n\r\n // Capability absent — the optional unit never registered. Hide, don't nag.\r\n if (view === undefined) return null\r\n\r\n // Optional click-to-preview: rows degrade to plain text where the sidebar\r\n // opener is absent (the opener resolves the session cwd per click).\r\n const open = sidebarFileOpener(ctx, scope?.sessionId)\r\n\r\n const latestPaths = view.latest?.paths ?? []\r\n const history = historyPaths(view.sessionPaths, latestPaths)\r\n\r\n if (latestPaths.length === 0 && view.sessionTotal === 0) {\r\n return createElement(\r\n 'div',\r\n { style: SECTION_STYLE, 'data-dsh-brief-sidebar': 'deliverables-section' },\r\n createElement('div', { style: HEADER_STYLE }, t('section.deliverables')),\r\n createElement(\r\n 'div',\r\n {\r\n style: {\r\n margin: '0 auto',\r\n padding: 24,\r\n maxWidth: 460,\r\n textAlign: 'center',\r\n color: 'var(--dsw-alias-label-tertiary)',\r\n lineHeight: 1.7,\r\n fontSize: 12,\r\n },\r\n },\r\n createElement('div', { style: { marginBottom: 6, color: 'var(--dsw-alias-label-secondary)' } }, t('deliverables.empty')),\r\n createElement('div', null, t('deliverables.emptyHint')),\r\n ),\r\n )\r\n }\r\n\r\n return createElement(\r\n 'div',\r\n { style: SECTION_STYLE, 'data-dsh-brief-sidebar': 'deliverables-section' },\r\n createElement('div', { style: HEADER_STYLE }, t('section.deliverables')),\r\n // 当前 turn 一组:只有真改过东西才起标题,否则“本回合改动 · 0”反而口舌。\r\n latestPaths.length > 0 && createElement(GroupHeader, {\r\n text: expandCount(t('deliverables.currentTurn'), latestPaths.length),\r\n marker: 'deliverables-current-group',\r\n }),\r\n createElement(\r\n 'ul',\r\n { style: LIST_STYLE },\r\n latestPaths.map(path => createElement(PathRow, { key: path, path, t, open })),\r\n ),\r\n history.length > 0 && createElement(FoldToggle, {\r\n label: expandCount(t('deliverables.history'), history.length),\r\n open: historyOpen,\r\n marker: 'deliverables-history-toggle',\r\n onToggle: () => { setHistoryOpen(current => !current) },\r\n }),\r\n // 列表有上限:开关行说的是折叠区收了多少条,附注说会话一共改过多少个。\r\n history.length > 0 && view.sessionTotal > view.sessionPaths.length && createElement(GroupCaption, {\r\n text: expandTotal(t('deliverables.historyCapped'), view.sessionTotal),\r\n marker: 'deliverables-history-capped',\r\n }),\r\n historyOpen && createElement(\r\n 'ul',\r\n { style: LIST_STYLE },\r\n history.map(path => createElement(PathRow, { key: path, path, t, open })),\r\n ),\r\n )\r\n}\r\n","/**\r\n * The `dshSummarySkillUsage` projection — reading it.\r\n *\r\n * The unit is registered by THIS plugin's host half (key `dshSummarySkillUsage`):\r\n * the skills this session actually loaded through the host's `skill` tool. It\r\n * answers a different question from `memorySlots`/`memoryRecall` — those say\r\n * what the model was *told*, this says which instruction packs it *pulled*.\r\n *\r\n * The module is deliberately PURE — no React, no context, no IO — so the\r\n * narrowing is testable directly, exactly like `deliverables.ts`.\r\n *\r\n * Reading discipline (the same three-way split every brief section uses):\r\n * - `undefined` = the capability is ABSENT (host half never registered, older\r\n * composition without the projection registry, or a frame drifted beyond\r\n * repair) → the section hides;\r\n * - `session: []` = the honest empty state (the `skill` tool exists on all six\r\n * supported lines; this session simply has not loaded anything yet);\r\n * - a malformed entry is dropped, never thrown — one bad row must not blank\r\n * the whole list.\r\n */\r\nimport { SKILL_USAGE_KEY } from '../../projection/keys'\r\nimport type { SkillUsageEntryView, SkillUsageView } from '../../projection/keys'\r\n\r\n/** The key this plugin's client half subscribes to (re-exported for callers). */\r\nexport { SKILL_USAGE_KEY }\r\n\r\n/** Whether a value is a non-negative safe integer (the view's counter shape). */\r\nfunction isCounter(value: unknown): value is number {\r\n return typeof value === 'number' && Number.isSafeInteger(value) && value >= 0\r\n}\r\n\r\n/** Narrow one skill tally; `undefined` = malformed, dropped. */\r\nfunction readEntry(value: unknown): SkillUsageEntryView | undefined {\r\n if (value === null || typeof value !== 'object' || Array.isArray(value)) return undefined\r\n const raw = value as Record<string, unknown>\r\n if (typeof raw['name'] !== 'string' || raw['name'].length === 0) return undefined\r\n if (!isCounter(raw['count']) || !isCounter(raw['lastTurn'])) return undefined\r\n return { name: raw['name'], count: raw['count'], lastTurn: raw['lastTurn'] }\r\n}\r\n\r\n/**\r\n * The latest-turn bucket, or `null` when it is absent OR drifted. A drifted\r\n * bucket only costs the \"本轮\" tag, so it degrades instead of voiding the view.\r\n */\r\nfunction readLatest(value: unknown): SkillUsageView['latest'] {\r\n if (value === null || typeof value !== 'object' || Array.isArray(value)) return null\r\n const raw = value as Record<string, unknown>\r\n if (!isCounter(raw['turn']) || !Array.isArray(raw['names'])) return null\r\n return { turn: raw['turn'], names: raw['names'].filter((n): n is string => typeof n === 'string' && n.length > 0) }\r\n}\r\n\r\n/**\r\n * Narrow a raw projection value into a skill-usage view.\r\n *\r\n * @param value - the raw `unknown` snapshot of the `dshSummarySkillUsage` face.\r\n * @returns the validated view, or `undefined` when the capability is absent.\r\n */\r\nexport function readSkillUsage(value: unknown): SkillUsageView | undefined {\r\n if (value === null || typeof value !== 'object' || Array.isArray(value)) return undefined\r\n const raw = value as Record<string, unknown>\r\n // The counters and the list are the contract; their drift means the frame was\r\n // written by a different shape than this reader speaks.\r\n if (!Array.isArray(raw['session'])) return undefined\r\n if (!isCounter(raw['sessionTotal']) || !isCounter(raw['callTotal'])) return undefined\r\n const session: SkillUsageEntryView[] = []\r\n for (const entry of raw['session']) {\r\n const narrowed = readEntry(entry)\r\n if (narrowed !== undefined) session.push(narrowed)\r\n }\r\n return { latest: readLatest(raw['latest']), session, sessionTotal: raw['sessionTotal'], callTotal: raw['callTotal'] }\r\n}\r\n\r\n/**\r\n * Fill both placeholders of a template. `expandCount` only speaks `{count}`, and\r\n * this section's footer carries a second number on purpose: the capped list\r\n * needs the truthful distinct total next to the load count.\r\n *\r\n * @param template - a locale string carrying `{count}` and/or `{total}`.\r\n * @param count - the `{count}` value.\r\n * @param total - the `{total}` value.\r\n * @returns the filled string.\r\n */\r\nexport function expandPair(template: string, count: number, total: number): string {\r\n return template.replace('{count}', String(count)).replace('{total}', String(total))\r\n}\r\n","/**\r\n * The skill-usage section: the `dshSummarySkillUsage` projection drawn as one\r\n * part of the summary tab.\r\n *\r\n * Where `MemoryRecallSection` answers \"what memories did the model see\", this\r\n * answers \"which instruction packs did it pull\" — the skills this session\r\n * loaded through the host's `skill` tool, with how often and when.\r\n *\r\n * Like the deliverables section this is an OPTIONAL capability on both sides:\r\n * no projection registry (or a host half that never registered the unit) means\r\n * the client reads capability absence and the section hides. No settings switch\r\n * gates it either — the list is a read-only fact about the session, not a\r\n * preference, and a section that only ever shows what already happened costs\r\n * nothing to leave on.\r\n *\r\n * Two contracts this row honours, both learned on the recall section:\r\n * - **no native `title` attribute** — it paints an unskinable tooltip that\r\n * overlaps the plugin's own bubble; nothing here needs one;\r\n * - **colours from `--dsw-alias-*` tokens only** (skin contract).\r\n */\r\nimport { createElement } from 'react'\r\nimport type { CSSProperties, ReactNode } from 'react'\r\nimport type { Context } from '@deepseek-ai/cordis'\r\nimport { SKILL_USAGE_KEY } from '../../projection/keys'\r\nimport { useProjectionValue } from '../use-projection'\r\nimport { expandPair, readSkillUsage } from './skill-usage'\r\n\r\nexport interface SkillUsageSectionProps {\r\n /** The DSH locale lookup, passed down from `apply`. */\r\n t: (key: string) => string\r\n /** The client root context (the tab body's only way to reach services). */\r\n ctx?: Context\r\n /** The session this tab is scoped to. */\r\n scope?: { readonly sessionId?: string }\r\n}\r\n\r\nconst SECTION_STYLE: CSSProperties = {\r\n flexShrink: 0,\r\n borderBottom: '1px solid var(--dsw-alias-border-secondary)',\r\n}\r\n\r\nconst HEADER_STYLE: CSSProperties = {\r\n padding: '10px 12px 0',\r\n color: 'var(--dsw-alias-label-secondary)',\r\n fontSize: 12,\r\n fontWeight: 600,\r\n}\r\n\r\nconst LIST_STYLE: CSSProperties = {\r\n listStyle: 'none',\r\n margin: 0,\r\n padding: '6px 0',\r\n display: 'flex',\r\n flexDirection: 'column',\r\n}\r\n\r\nconst ROW_STYLE: CSSProperties = {\r\n display: 'flex',\r\n alignItems: 'baseline',\r\n gap: 8,\r\n padding: '6px 12px',\r\n}\r\n\r\n/** The skill name: primary-ish but never the loudest thing in the row. */\r\nconst NAME_STYLE: CSSProperties = {\r\n minWidth: 0,\r\n overflowWrap: 'anywhere',\r\n color: 'var(--dsw-alias-label-secondary)',\r\n}\r\n\r\n/** The per-skill load tally, tertiary so the name stays the reading target. */\r\nconst COUNT_STYLE: CSSProperties = {\r\n flexShrink: 0,\r\n color: 'var(--dsw-alias-label-tertiary)',\r\n fontSize: 11,\r\n}\r\n\r\n/** The \"本轮\" pill: same form as the deliverables codeplan tag. */\r\nconst TAG_STYLE: CSSProperties = {\r\n flexShrink: 0,\r\n color: 'var(--dsw-alias-label-tertiary)',\r\n border: '1px solid var(--dsw-alias-label-tertiary)',\r\n borderRadius: 999,\r\n padding: '0 6px',\r\n fontSize: 11,\r\n lineHeight: '16px',\r\n whiteSpace: 'nowrap',\r\n}\r\n\r\nconst FOOTER_STYLE: CSSProperties = {\r\n padding: '0 12px 10px',\r\n color: 'var(--dsw-alias-label-tertiary)',\r\n fontSize: 11,\r\n}\r\n\r\nconst EMPTY_STYLE: CSSProperties = {\r\n margin: '0 auto',\r\n padding: 24,\r\n maxWidth: 460,\r\n textAlign: 'center',\r\n color: 'var(--dsw-alias-label-tertiary)',\r\n lineHeight: 1.7,\r\n fontSize: 12,\r\n}\r\n\r\n/**\r\n * The skill-usage section. The subscription is unconditional (a plain listener,\r\n * not IO); the view decides whether anything is drawn.\r\n *\r\n * @param props - translation, client context, session scope.\r\n */\r\nexport function SkillUsageSection(props: SkillUsageSectionProps): ReactNode {\r\n const { t, ctx, scope } = props\r\n\r\n const view = readSkillUsage(useProjectionValue(ctx, scope?.sessionId, SKILL_USAGE_KEY))\r\n\r\n // Capability absent — the optional unit never registered. Hide, don't nag.\r\n if (view === undefined) return null\r\n\r\n if (view.session.length === 0) {\r\n return createElement(\r\n 'div',\r\n { style: SECTION_STYLE, 'data-dsh-brief-sidebar': 'skill-usage-section' },\r\n createElement('div', { style: HEADER_STYLE }, t('section.skillUsage')),\r\n createElement(\r\n 'div',\r\n { style: EMPTY_STYLE },\r\n createElement('div', { style: { marginBottom: 6, color: 'var(--dsw-alias-label-secondary)' } }, t('skillUsage.empty')),\r\n createElement('div', null, t('skillUsage.emptyHint')),\r\n ),\r\n )\r\n }\r\n\r\n const latestNames = view.latest?.names ?? []\r\n\r\n return createElement(\r\n 'div',\r\n { style: SECTION_STYLE, 'data-dsh-brief-sidebar': 'skill-usage-section' },\r\n createElement('div', { style: HEADER_STYLE }, t('section.skillUsage')),\r\n createElement(\r\n 'ul',\r\n { style: LIST_STYLE },\r\n view.session.map(entry => createElement(\r\n 'li',\r\n { key: entry.name, style: ROW_STYLE, 'data-dsh-brief-sidebar': 'skill-usage-row' },\r\n createElement('span', { style: NAME_STYLE }, entry.name),\r\n createElement('span', { style: COUNT_STYLE }, expandPair(t('skillUsage.uses'), entry.count, entry.count)),\r\n latestNames.includes(entry.name) && createElement('span', { style: TAG_STYLE }, t('skillUsage.latestTag')),\r\n )),\r\n ),\r\n // 列表有上限,页脚说真数:加载次数与去重后的技能数各归各。\r\n createElement('div', { style: FOOTER_STYLE }, expandPair(t('skillUsage.count'), view.callTotal, view.sessionTotal)),\r\n )\r\n}\r\n","/**\r\n * The `memorySlots` projection — reading it.\r\n *\r\n * The projection unit is registered by `dsh-prime-memory` (key `memorySlots`,\r\n * wire view `{rev, count, openCount, slots[]}`); this plugin does NOT depend\r\n * on it — when the unit is not registered the client reads `undefined` from\r\n * `faceOf` and the section hides. This module is the read side of that\r\n * contract and is deliberately PURE — no React, no context, no IO — so the\r\n * narrowing can be tested directly.\r\n *\r\n * Forward compatibility: the shipped view carries `{id, title, kind, status,\r\n * priority}` only. A future prime-memory release may add `body`/`refs` to the\r\n * wire view (its projection plan keeps that door open); those fields are\r\n * narrowed opportunistically — present and well-formed → kept, absent or\r\n * malformed → dropped — so the section renders them without a brief-sidebar\r\n * change, and a malformed extra field can never blank the section.\r\n */\r\n\r\n/** The projection key `dsh-prime-memory` registers (its canonical constant). */\r\nexport const MEMORY_SLOTS_KEY = 'memorySlots'\r\n\r\n/** One slot of the wire view. */\r\nexport interface MemorySlotView {\r\n readonly id: string\r\n readonly title: string\r\n /** One of prime-memory's `SLOT_KINDS`: rule / todo / anchor / pointer. */\r\n readonly kind: string\r\n /** One of prime-memory's `SLOT_STATUSES`: open / done / dropped / expired. */\r\n readonly status: string\r\n /** 0–100; higher wins the activation competition. */\r\n readonly priority: number\r\n /** Slot body, once prime-memory exposes it on the wire (truncated at render). */\r\n readonly body?: string\r\n /** Reference targets, once prime-memory exposes them on the wire. */\r\n readonly refs?: readonly string[]\r\n /**\r\n * record_id 引用的展示解析(v0.5.0 契约:ref → `[type] 名称简述`),由\r\n * prime-memory 在投影帧构建时解析;路径/URL 类引用不产生条目。存在才收。\r\n */\r\n readonly refViews?: readonly SlotRefView[]\r\n}\r\n\r\n/** 一条 record_id 引用的展示解析(与 prime-memory 的 SlotRefView 同形)。 */\r\nexport interface SlotRefView {\r\n readonly ref: string\r\n readonly title: string\r\n}\r\n\r\n/** The whole wire view of one frame. */\r\nexport interface MemorySlotsView {\r\n readonly rev: number\r\n readonly count: number\r\n readonly openCount: number\r\n readonly slots: readonly MemorySlotView[]\r\n}\r\n\r\n/**\r\n * Narrow a raw projection value into a memory-slots view.\r\n *\r\n * Two outcomes are kept apart, mirroring the deliverables read side:\r\n * - `undefined` — the capability is ABSENT (prime-memory is not in the\r\n * composition, or no frame has carried the key yet), or the frame is\r\n * malformed beyond repair (a shape drift must not blank the whole tab);\r\n * - a view — the projection is live. A view with `slots: []` IS the empty\r\n * state: prime-memory publishes as soon as the unit registers, so \"present\r\n * but empty\" is a real value, not a sentinel.\r\n *\r\n * Malformed slot entries are dropped rather than thrown on (trusted-Host\r\n * value, defensive display), like `readTodos`.\r\n *\r\n * @param value - the raw `unknown` snapshot of the `memorySlots` face.\r\n * @returns the validated view, or `undefined` when the capability is absent.\r\n */\r\nexport function readSlots(value: unknown): MemorySlotsView | undefined {\r\n if (value === null || typeof value !== 'object' || Array.isArray(value)) return undefined\r\n const raw = value as Record<string, unknown>\r\n if (!isCounter(raw['rev']) || !isCounter(raw['count']) || !isCounter(raw['openCount'])) return undefined\r\n if (!Array.isArray(raw['slots'])) return undefined\r\n const slots: MemorySlotView[] = []\r\n for (const entry of raw['slots']) {\r\n const slot = readSlot(entry)\r\n if (slot !== undefined) slots.push(slot)\r\n }\r\n return { rev: raw['rev'], count: raw['count'], openCount: raw['openCount'], slots }\r\n}\r\n\r\n/** Whether a value is a non-negative safe integer (the view's counter shape). */\r\nfunction isCounter(value: unknown): value is number {\r\n return typeof value === 'number' && Number.isSafeInteger(value) && value >= 0\r\n}\r\n\r\n/** Narrow one slot entry; `undefined` = malformed, dropped. */\r\nfunction readSlot(value: unknown): MemorySlotView | undefined {\r\n if (value === null || typeof value !== 'object' || Array.isArray(value)) return undefined\r\n const raw = value as Record<string, unknown>\r\n if (typeof raw['id'] !== 'string' || raw['id'].length === 0) return undefined\r\n if (typeof raw['title'] !== 'string') return undefined\r\n if (typeof raw['kind'] !== 'string' || typeof raw['status'] !== 'string') return undefined\r\n if (typeof raw['priority'] !== 'number') return undefined\r\n const slot: { -readonly [K in keyof MemorySlotView]: MemorySlotView[K] } = {\r\n id: raw['id'],\r\n title: raw['title'],\r\n kind: raw['kind'],\r\n status: raw['status'],\r\n priority: raw['priority'],\r\n }\r\n if (typeof raw['body'] === 'string' && raw['body'].length > 0) slot.body = raw['body']\r\n if (Array.isArray(raw['refs'])) {\r\n const refs = raw['refs'].filter((ref): ref is string => typeof ref === 'string' && ref.length > 0)\r\n if (refs.length > 0) slot.refs = refs\r\n }\r\n if (Array.isArray(raw['refViews'])) {\r\n const views: SlotRefView[] = []\r\n for (const entry of raw['refViews']) {\r\n if (entry === null || typeof entry !== 'object' || Array.isArray(entry)) continue\r\n const view = entry as Record<string, unknown>\r\n if (typeof view['ref'] !== 'string' || view['ref'].length === 0) continue\r\n if (typeof view['title'] !== 'string' || view['title'].length === 0) continue\r\n views.push({ ref: view['ref'], title: view['title'] })\r\n }\r\n if (views.length > 0) slot.refViews = views\r\n }\r\n return slot\r\n}\r\n\r\n/** The body length at which the section truncates (full text rides the title tooltip). */\r\nexport const BODY_TRUNCATE_AT = 120\r\n\r\n/**\r\n * One-line truncation for a slot body. Already-short bodies pass through;\r\n * longer ones are cut at the limit with an ellipsis.\r\n */\r\nexport function truncateBody(body: string, limit = BODY_TRUNCATE_AT): string {\r\n const flat = body.replaceAll(/\\s+/g, ' ').trim()\r\n return flat.length <= limit ? flat : `${flat.slice(0, limit)}…`\r\n}\r\n","/**\r\n * Structural views of the `configForms` settings seam (DSH 0.1.7+).\r\n *\r\n * The settings card and the memory-section gate consume only these members of\r\n * the `ConfigForm` handle that `configForms.get(entryId)` returns, so the real\r\n * `@deepseek-ai/dsh-client-ui-settings/client` type graph is never imported —\r\n * the same reason `use-projection.ts` declares its own session faces and\r\n * `dock-shadow.tsx` its own slots face.\r\n *\r\n * `configForms` serves the STORED doc: a `.volatile()` field arrives as a\r\n * plain value here (the host unwraps the live refs before persistence), so\r\n * the client reads a plain config shape.\r\n */\r\n\r\n/** One snapshot of an entry's stored config. */\r\nexport interface SettingsScopeSnapshot<T> {\r\n status: 'loading' | 'ready' | 'unavailable'\r\n value: T | undefined\r\n revision: number | undefined\r\n /** Whether the current face may write (a read-only seat disables the controls). */\r\n writable: boolean\r\n}\r\n\r\n/** The `ConfigForm` handle face this plugin uses. */\r\nexport interface SettingsScope<T> {\r\n getSnapshot(): SettingsScopeSnapshot<T>\r\n subscribe(listener: () => void): () => void\r\n set(field: string, value: unknown): Promise<boolean>\r\n unset(field: string): Promise<boolean>\r\n}\r\n\r\n/** Structural view of the `configForms` cordis service, keyed by entry id. */\r\nexport interface ConfigFormsLike {\r\n get<T>(entryId: string): SettingsScope<T>\r\n}\r\n\r\n/**\r\n * This plugin's entry config, as the client reads it. Only the fields the\r\n * browser half consumes are declared; the schema (node half `Config`) owns\r\n * the full surface.\r\n */\r\nexport interface BriefClientConfig {\r\n /** Whether the summary tab renders the memory-slots section (default: off). */\r\n showMemorySlots?: boolean\r\n /** Whether the summary tab renders the session-recall section (default: on). */\r\n showMemoryRecall?: boolean\r\n}\r\n\r\n/**\r\n * The slots switch's default. Flipped to OFF alongside prime-memory's\r\n * `memoryRecall` projection: a hand-pinned resident convention is a real\r\n * feature, but listing it as a permanent card in the summary pane taught\r\n * users to read \"memory\" as \"resident\", which is the opposite of how recall\r\n * works. The section still only appears when the `memorySlots` projection\r\n * exists, and stays one click away for anyone who wants it back.\r\n */\r\nexport const DEFAULT_SHOW_MEMORY_SLOTS = false\r\n\r\n/** The session-recall switch's default (on: it is the honest memory view). */\r\nexport const DEFAULT_SHOW_MEMORY_RECALL = true\r\n\r\n/**\r\n * Resolve the switch from one snapshot (pure; testable). Any\r\n * cannot-answer shape falls back to {@link DEFAULT_SHOW_MEMORY_SLOTS}; an\r\n * explicit `false` is the only off.\r\n */\r\nexport function resolveShowMemorySlots(\r\n snapshot: SettingsScopeSnapshot<BriefClientConfig> | undefined,\r\n): boolean {\r\n if (snapshot === undefined || snapshot.status !== 'ready') return DEFAULT_SHOW_MEMORY_SLOTS\r\n return snapshot.value?.showMemorySlots === true\r\n}\r\n\r\n/**\r\n * Resolve the session-recall switch from one snapshot (pure; testable).\r\n * Any cannot-answer shape falls back to {@link DEFAULT_SHOW_MEMORY_RECALL};\r\n * an explicit `false` is the only off.\r\n */\r\nexport function resolveShowMemoryRecall(\r\n snapshot: SettingsScopeSnapshot<BriefClientConfig> | undefined,\r\n): boolean {\r\n if (snapshot === undefined || snapshot.status !== 'ready') return DEFAULT_SHOW_MEMORY_RECALL\r\n return snapshot.value?.showMemoryRecall !== false\r\n}\r\n","/**\r\n * The shared `configForms` subscription behind this plugin's section switches.\r\n *\r\n * Both memory sections (pinned slots / session recall) gate on one boolean of\r\n * this plugin's entry config. The plumbing — defensive scope resolution,\r\n * `useSyncExternalStore`, and a stable absent-snapshot — is identical, so it\r\n * lives here once; each section passes its own pure resolver, which is what\r\n * the unit tests pin.\r\n *\r\n * A host without `configForms` (or a scope still loading) degrades to the\r\n * resolver's default instead of throwing inside a render.\r\n */\r\nimport { useCallback, useMemo, useSyncExternalStore } from 'react'\r\nimport type { Context } from '@deepseek-ai/cordis'\r\nimport type { BriefClientConfig, ConfigFormsLike, SettingsScopeSnapshot } from '../scope-face'\r\n\r\n/**\r\n * The snapshot served while no config scope is reachable — every resolver\r\n * maps it to its own default.\r\n */\r\nconst ABSENT_SNAPSHOT: SettingsScopeSnapshot<BriefClientConfig> = {\r\n status: 'unavailable',\r\n value: undefined,\r\n revision: undefined,\r\n writable: false,\r\n}\r\n\r\n/** A no-op unsubscribe source, kept as one identity so the absent-scope\r\n * subscription never thrashes (a store contract requires a disposer). */\r\nconst NO_SUBSCRIBE = (): (() => void) => () => {}\r\n\r\n/**\r\n * Read one config switch, live.\r\n *\r\n * @param ctx - the client root context handed to the tab body.\r\n * @param resolve - pure snapshot → boolean resolver (owns the default).\r\n * @returns the resolved switch value.\r\n */\r\nexport function useConfigFlag(\r\n ctx: Context | undefined,\r\n resolve: (snapshot: SettingsScopeSnapshot<BriefClientConfig> | undefined) => boolean,\r\n): boolean {\r\n const scope = useMemo(() => {\r\n if (ctx === undefined) return undefined\r\n const configForms = ctx.get('configForms') as ConfigFormsLike | undefined\r\n if (configForms === undefined || typeof configForms.get !== 'function') return undefined\r\n return configForms.get<BriefClientConfig>('dsh-brief-sidebar')\r\n }, [ctx])\r\n\r\n const subscribe = useCallback(\r\n (listener: () => void) => scope?.subscribe(listener) ?? NO_SUBSCRIBE(),\r\n [scope],\r\n )\r\n const getSnapshot = useCallback(\r\n () => scope?.getSnapshot() ?? ABSENT_SNAPSHOT,\r\n [scope],\r\n )\r\n\r\n return resolve(useSyncExternalStore(subscribe, getSnapshot, getSnapshot))\r\n}\r\n","/**\r\n * The memory-slots section: the `memorySlots` projection drawn as the third\r\n * part of the summary tab (fixed last: 进展 → 产物 → 记忆).\r\n *\r\n * TWO gates, both fail-open to \"hidden\", so a host without dsh-prime-memory\r\n * paints nothing here:\r\n *\r\n * 1. **The switch.** This plugin's entry config (`configForms` → entry\r\n * `dsh-brief-sidebar`, field `showMemorySlots`, default OFF — the pinned\r\n * list moved out of the summary pane's way in favour of the session-recall\r\n * section). When the config face cannot answer (service absent, scope not\r\n * ready, field unset) the default applies — see `scope-face.ts`.\r\n * 2. **The capability.** The `memorySlots` projection must exist for the\r\n * session; `undefined` hides the section entirely, exactly like the\r\n * optional deliverables section.\r\n *\r\n * Colours come from `--dsw-alias-*` tokens only (skin contract, enforced by\r\n * `tests/purity.spec.ts`).\r\n */\r\nimport { createElement } from 'react'\r\nimport type { CSSProperties, ReactNode } from 'react'\r\nimport type { Context } from '@deepseek-ai/cordis'\r\nimport {\r\n MEMORY_SLOTS_KEY,\r\n readSlots,\r\n truncateBody,\r\n} from './memory-slots'\r\nimport type { MemorySlotView, MemorySlotsView } from './memory-slots'\r\nimport { resolveShowMemorySlots } from '../scope-face'\r\nimport { useConfigFlag } from './use-config-flag'\r\nimport { useProjectionValue } from '../use-projection'\r\nimport { expandCount } from '../locales'\r\n\r\nexport interface MemorySlotsSectionProps {\r\n /** The DSH locale lookup, passed down from `apply`. */\r\n t: (key: string) => string\r\n /** The client root context (the tab body's only way to reach services). */\r\n ctx?: Context\r\n /** The session this tab is scoped to. */\r\n scope?: { readonly sessionId?: string }\r\n}\r\n\r\nconst SECTION_STYLE: CSSProperties = {\r\n flexShrink: 0,\r\n borderBottom: '1px solid var(--dsw-alias-border-secondary)',\r\n}\r\n\r\nconst HEADER_STYLE: CSSProperties = {\r\n padding: '10px 12px 0',\r\n color: 'var(--dsw-alias-label-secondary)',\r\n fontSize: 12,\r\n fontWeight: 600,\r\n}\r\n\r\nconst LIST_STYLE: CSSProperties = {\r\n listStyle: 'none',\r\n margin: 0,\r\n padding: '6px 0',\r\n display: 'flex',\r\n flexDirection: 'column',\r\n}\r\n\r\nconst ROW_STYLE: CSSProperties = {\r\n display: 'flex',\r\n alignItems: 'flex-start',\r\n gap: 8,\r\n padding: '6px 12px',\r\n}\r\n\r\nconst TITLE_STYLE: CSSProperties = {\r\n minWidth: 0,\r\n overflowWrap: 'anywhere',\r\n color: 'var(--dsw-alias-label-secondary)',\r\n}\r\n\r\nconst META_STYLE: CSSProperties = {\r\n flexShrink: 0,\r\n color: 'var(--dsw-alias-label-tertiary)',\r\n fontSize: 11,\r\n lineHeight: '18px',\r\n whiteSpace: 'nowrap',\r\n}\r\n\r\n/** The kind pill: same form as the codeplan pill, tertiary emphasis. */\r\nconst KIND_STYLE: CSSProperties = {\r\n flexShrink: 0,\r\n color: 'var(--dsw-alias-label-tertiary)',\r\n border: '1px solid var(--dsw-alias-label-tertiary)',\r\n borderRadius: 999,\r\n padding: '0 6px',\r\n fontSize: 11,\r\n lineHeight: '16px',\r\n whiteSpace: 'nowrap',\r\n}\r\n\r\n/** The status pill: filled tint for an open slot, plain text otherwise. */\r\nconst STATUS_OPEN_STYLE: CSSProperties = {\r\n flexShrink: 0,\r\n color: 'var(--dsw-alias-label-primary)',\r\n border: '1px solid var(--dsw-alias-label-secondary)',\r\n borderRadius: 999,\r\n padding: '0 6px',\r\n fontSize: 11,\r\n lineHeight: '16px',\r\n whiteSpace: 'nowrap',\r\n}\r\n\r\nconst STATUS_SETTLED_STYLE: CSSProperties = {\r\n ...STATUS_OPEN_STYLE,\r\n color: 'var(--dsw-alias-label-tertiary)',\r\n border: '1px solid var(--dsw-alias-label-tertiary)',\r\n}\r\n\r\nconst BODY_STYLE: CSSProperties = {\r\n margin: 0,\r\n minWidth: 0,\r\n overflowWrap: 'anywhere',\r\n color: 'var(--dsw-alias-label-tertiary)',\r\n fontSize: 12,\r\n lineHeight: '18px',\r\n}\r\n\r\nconst REFS_STYLE: CSSProperties = {\r\n ...BODY_STYLE,\r\n fontSize: 11,\r\n}\r\n\r\nconst TOTAL_STYLE: CSSProperties = {\r\n padding: '6px 12px 10px',\r\n color: 'var(--dsw-alias-label-tertiary)',\r\n fontSize: 12,\r\n}\r\n\r\nconst EMPTY_STYLE: CSSProperties = {\r\n margin: '0 auto',\r\n padding: 24,\r\n maxWidth: 460,\r\n textAlign: 'center',\r\n color: 'var(--dsw-alias-label-tertiary)',\r\n lineHeight: 1.7,\r\n fontSize: 12,\r\n}\r\n\r\n/** Locale key per known slot status; unknown statuses fall back to the raw wire value. */\r\nconst STATUS_KEY: Record<string, string> = {\r\n open: 'slots.status.open',\r\n done: 'slots.status.done',\r\n dropped: 'slots.status.dropped',\r\n expired: 'slots.status.expired',\r\n}\r\n\r\n/**\r\n * One slot row: kind pill, title (full body rides the tooltip), status pill,\r\n * priority; body line underneath when the wire view carries it; refs as\r\n * resolved 名称简述 (record_id → title) with the raw refs on the tooltip, or\r\n * raw refs when the host has not resolved them.\r\n */\r\nfunction SlotRow(props: { slot: MemorySlotView; t: (key: string) => string }): ReactNode {\r\n const { slot, t } = props\r\n const statusLabel = STATUS_KEY[slot.status] === undefined ? slot.status : t(STATUS_KEY[slot.status])\r\n const title = slot.body === undefined ? slot.title : `${slot.title} — ${slot.body}`\r\n const refsLine = slot.refViews !== undefined\r\n ? slot.refViews.map((view) => view.title).join(' · ')\r\n : slot.refs !== undefined\r\n ? slot.refs.join(' · ')\r\n : undefined\r\n return createElement(\r\n 'li',\r\n { style: ROW_STYLE },\r\n createElement('span', { style: KIND_STYLE }, slot.kind),\r\n createElement(\r\n 'div',\r\n { style: { minWidth: 0, flex: '1 1 auto', display: 'flex', flexDirection: 'column', gap: 2 } },\r\n createElement('span', { style: TITLE_STYLE, title }, slot.title),\r\n slot.body !== undefined && createElement('p', { style: BODY_STYLE }, truncateBody(slot.body)),\r\n refsLine !== undefined\r\n && createElement(\r\n 'p',\r\n {\r\n style: REFS_STYLE,\r\n title: slot.refs !== undefined ? slot.refs.join('\\n') : undefined,\r\n },\r\n refsLine,\r\n ),\r\n ),\r\n createElement('span', { style: META_STYLE }, `P${slot.priority}`),\r\n createElement(\r\n 'span',\r\n { style: slot.status === 'open' ? STATUS_OPEN_STYLE : STATUS_SETTLED_STYLE },\r\n statusLabel,\r\n ),\r\n )\r\n}\r\n\r\n/**\r\n * Subscribe to this plugin's entry config and resolve the slots switch.\r\n * Plumbing lives in `use-config-flag`; the default (off) lives in the resolver.\r\n *\r\n * @param ctx - the client root context handed to the tab body.\r\n * @returns whether the memory-slots section may render at all.\r\n */\r\nexport function useShowMemorySlots(ctx: Context | undefined): boolean {\r\n return useConfigFlag(ctx, resolveShowMemorySlots)\r\n}\r\n\r\n/**\r\n * The memory-slots section. Both hooks run unconditionally (a conditional\r\n * hook order would break the moment the switch flips); the switch only\r\n * decides whether the resolved view paints.\r\n * @param props - translation, client context, session scope.\r\n */\r\nexport function MemorySlotsSection(props: MemorySlotsSectionProps): ReactNode {\r\n const { t, ctx, scope } = props\r\n\r\n const show = useShowMemorySlots(ctx)\r\n const view: MemorySlotsView | undefined = readSlots(\r\n useProjectionValue(ctx, scope?.sessionId, MEMORY_SLOTS_KEY),\r\n )\r\n\r\n // Switched off at the settings faces — the section is willed away, not\r\n // empty (an empty state would claim prime-memory answered when the user\r\n // simply closed the section).\r\n if (show === false) return null\r\n\r\n // Capability absent (prime-memory not in the composition, no frame yet) —\r\n // hide, don't nag; the memory panel remains the write surface.\r\n if (view === undefined) return null\r\n\r\n if (view.slots.length === 0) {\r\n return createElement(\r\n 'div',\r\n { style: SECTION_STYLE, 'data-dsh-brief-sidebar': 'memory-slots-section' },\r\n createElement('div', { style: HEADER_STYLE }, t('section.memorySlots')),\r\n createElement(\r\n 'div',\r\n { style: EMPTY_STYLE },\r\n createElement('div', { style: { marginBottom: 6, color: 'var(--dsw-alias-label-secondary)' } }, t('slots.empty')),\r\n createElement('div', null, t('slots.emptyHint')),\r\n ),\r\n )\r\n }\r\n\r\n return createElement(\r\n 'div',\r\n { style: SECTION_STYLE, 'data-dsh-brief-sidebar': 'memory-slots-section' },\r\n createElement('div', { style: HEADER_STYLE }, t('section.memorySlots')),\r\n createElement(\r\n 'ul',\r\n { style: LIST_STYLE },\r\n view.slots.map(slot => createElement(SlotRow, { key: slot.id, slot, t })),\r\n ),\r\n createElement(\r\n 'div',\r\n { style: TOTAL_STYLE },\r\n expandCount(t('slots.openCount'), view.openCount),\r\n ),\r\n )\r\n}\r\n","/**\r\n * The `memoryRecall` projection — reading it.\r\n *\r\n * The projection unit is registered by `dsh-prime-memory` (key `memoryRecall`,\r\n * wire view `{rev, sessionId, count, items[]}`): the memories this session has\r\n * actually injected. Unlike\r\n * `memorySlots` (pinned, resident conventions written by hand), this set is\r\n * NOT resident — it is the at-a-glance answer to \"what did the model see\".\r\n * It survives compaction on purpose: `compact` only marks the entries whose\r\n * text left the context as `superseded` (and `/clear` empties the set), so a\r\n * retired row keeps its strike-through instead of vanishing.\r\n *\r\n * This plugin does NOT depend on prime-memory: with the unit unregistered the\r\n * client reads `undefined` from the face and the section hides. The module is\r\n * deliberately PURE — no React, no context, no IO — so the narrowing is\r\n * testable directly, exactly like `memory-slots.ts`.\r\n */\r\n\r\n/** The projection key `dsh-prime-memory` registers (its canonical constant). */\r\nexport const MEMORY_RECALL_KEY = 'memoryRecall'\r\n\r\n/** One recalled memory of the wire view. */\r\nexport interface MemoryRecallItem {\r\n readonly id: string\r\n /** prime-memory's memory type: work_fact / work_method / episodic / … */\r\n readonly type: string\r\n /** First line of the record body (prime-memory truncates for the wire). */\r\n readonly title: string\r\n /** 0–100, the record's own priority. */\r\n readonly priority: number\r\n /** \"When should this surface\" phrases, once prime-memory exposes them. */\r\n readonly scenario?: readonly string[]\r\n /**\r\n * The last mark a HUMAN put on this record: `-1` (declared obsolete) or\r\n * `0..5` (relevance). Absent means never rated — which is NOT the same as\r\n * a zero. prime-memory publishes it on the `memoryRecall` view so the row\r\n * can show the existing mark without a second round-trip.\r\n */\r\n readonly rating?: number\r\n /**\r\n * The record body, whitespace-trimmed and capped by prime-memory. The hover\r\n * bubble reads it straight off the frame — no second round-trip. Absent on\r\n * frames published before that field existed, so the row falls back to\r\n * `title` and the bubble says it has no body.\r\n */\r\n readonly body?: string\r\n /**\r\n * prime-memory says this record has been retired (soft-deleted). It stays in\r\n * the list because its text is still part of what the model saw — and because\r\n * the retirement is the human's verdict; the row just draws a strike-through.\r\n * Absent means alive.\r\n */\r\n readonly retired?: boolean\r\n /**\r\n * The text of this recall has been replaced by a compaction summary, so it is\r\n * no longer in the model's context. Orthogonal to `retired` (both can be set).\r\n * The section hides these by default and reports the count in its footer;\r\n * a retired row is the exception and stays visible. Absent means still in context.\r\n */\r\n readonly superseded?: boolean\r\n}\r\n\r\n/** The whole wire view of one frame. */\r\nexport interface MemoryRecallView {\r\n readonly rev: number\r\n readonly sessionId: string\r\n /** Total recalled-and-alive count; `items` may be a capped prefix of it. */\r\n readonly count: number\r\n /** Most recently injected first. */\r\n readonly items: readonly MemoryRecallItem[]\r\n}\r\n\r\n/** Whether a value is a non-negative safe integer (the view's counter shape). */\r\nfunction isCounter(value: unknown): value is number {\r\n return typeof value === 'number' && Number.isSafeInteger(value) && value >= 0\r\n}\r\n\r\n/** Narrow one item entry; `undefined` = malformed, dropped. */\r\nfunction readItem(value: unknown): MemoryRecallItem | undefined {\r\n if (value === null || typeof value !== 'object' || Array.isArray(value)) return undefined\r\n const raw = value as Record<string, unknown>\r\n if (typeof raw['id'] !== 'string' || raw['id'].length === 0) return undefined\r\n if (typeof raw['type'] !== 'string' || typeof raw['title'] !== 'string') return undefined\r\n if (typeof raw['priority'] !== 'number') return undefined\r\n const item: { -readonly [K in keyof MemoryRecallItem]: MemoryRecallItem[K] } = {\r\n id: raw['id'],\r\n type: raw['type'],\r\n title: raw['title'],\r\n priority: raw['priority'],\r\n }\r\n if (Array.isArray(raw['scenario'])) {\r\n const phrases = raw['scenario'].filter((s): s is string => typeof s === 'string' && s.length > 0)\r\n if (phrases.length > 0) item.scenario = phrases\r\n }\r\n // A drifted rating (non-number, or outside the -1..5 domain) is dropped\r\n // rather than trusted: the row then simply looks unrated.\r\n const rating = raw['rating']\r\n if (typeof rating === 'number' && Number.isInteger(rating) && rating >= -1 && rating <= 5) item.rating = rating\r\n // A non-string body is dropped rather than trusted: the bubble then says so.\r\n if (typeof raw['body'] === 'string') item.body = raw['body']\r\n // Only true is written; anything else reads back as absent (= alive).\r\n if (raw['retired'] === true) item.retired = true\r\n // Same discipline for the compaction marker: absent means \"still in context\".\r\n if (raw['superseded'] === true) item.superseded = true\r\n return item\r\n}\r\n\r\n/**\r\n * Narrow a raw projection value into a recall view.\r\n *\r\n * `undefined` means the capability is ABSENT (prime-memory not in the\r\n * composition, or no frame carried the key) or the frame drifted beyond repair;\r\n * a view with `items: []` IS the honest empty state (prime-memory publishes as\r\n * soon as the unit registers). Malformed items are dropped, never thrown on.\r\n *\r\n * @param value - the raw `unknown` snapshot of the `memoryRecall` face.\r\n * @returns the validated view, or `undefined` when the capability is absent.\r\n */\r\nexport function readRecall(value: unknown): MemoryRecallView | undefined {\r\n if (value === null || typeof value !== 'object' || Array.isArray(value)) return undefined\r\n const raw = value as Record<string, unknown>\r\n if (!isCounter(raw['rev']) || !isCounter(raw['count'])) return undefined\r\n if (typeof raw['sessionId'] !== 'string') return undefined\r\n if (!Array.isArray(raw['items'])) return undefined\r\n const items: MemoryRecallItem[] = []\r\n for (const entry of raw['items']) {\r\n const item = readItem(entry)\r\n if (item !== undefined) items.push(item)\r\n }\r\n return { rev: raw['rev'], sessionId: raw['sessionId'], count: raw['count'], items }\r\n}\r\n","/**\r\n * The write channel back into `dsh-prime-memory`: rating one recalled memory.\r\n *\r\n * This is the FIRST write this plugin performs, and deliberately the only one.\r\n * Reading goes through the host's projection face (`memoryRecall`); there is no\r\n * projection for writes, so the mark travels over prime-memory's own client RPC\r\n * route — `POST /dsh-memory/rpc/<method>`, the same envelope its panel uses.\r\n * That is a cross-plugin HTTP contract, so everything that makes it safe to\r\n * hold lives here:\r\n *\r\n * - **Optional by construction.** A composition without dsh-prime-memory, or an\r\n * older one without this endpoint, answers 404/405. That is reported as\r\n * `absent`, and the section stops offering the control instead of failing on\r\n * every click.\r\n * - **No invented semantics.** `-1` and `0..5` are prime-memory's domain; this\r\n * module refuses anything else locally so a bad click cannot reach the server.\r\n * - **Nothing is optimistic about retirement.** The caller only hides a row\r\n * after the server confirms `retired` — a lost request must not silently\r\n * remove a memory from view.\r\n *\r\n * `fetch` is injected so the parse and the status mapping are testable without\r\n * a browser.\r\n */\r\n\r\n/** The route prime-memory's server half registers for its client RPC surface. */\r\nexport const RECALL_FEEDBACK_ROUTE = '/dsh-memory/rpc/recall-feedback'\r\n\r\n/** A relevance mark (`0..5`) or `-1` = \"this is obsolete\", prime-memory's domain. */\r\nexport const FEEDBACK_SCORES = [-1, 0, 1, 2, 3, 4, 5] as const\r\nexport type FeedbackScore = (typeof FEEDBACK_SCORES)[number]\r\n\r\n/** Whether a value is a score this plugin is allowed to send. */\r\nexport function isFeedbackScore(value: unknown): value is FeedbackScore {\r\n return typeof value === 'number' && (FEEDBACK_SCORES as readonly number[]).includes(value)\r\n}\r\n\r\n/** How long to wait before giving up on one click. */\r\nexport const FEEDBACK_TIMEOUT_MS = 8_000\r\n\r\n/**\r\n * Outcome of one rating attempt.\r\n *\r\n * `absent` is NOT an error to show the user — it means the capability is not\r\n * there (prime-memory missing or older), and the caller should stop offering\r\n * the control. `rejected` carries prime-memory's own reason (e.g. \"this memory\r\n * is no longer in the session's recall set\"), which is worth surfacing.\r\n */\r\nexport type FeedbackOutcome =\r\n | {\r\n readonly status: 'sent'\r\n readonly retired: boolean\r\n readonly announced: boolean\r\n readonly mean: number\r\n readonly rated: number\r\n }\r\n | { readonly status: 'rejected'; readonly reason: string }\r\n | { readonly status: 'absent' }\r\n | { readonly status: 'transport'; readonly reason: string }\r\n\r\n/** The minimal fetch shape this module needs (global `fetch` satisfies it). */\r\nexport interface FeedbackFetch {\r\n (url: string, init: {\r\n method: 'POST'\r\n headers: Record<string, string>\r\n body: string\r\n signal?: AbortSignal\r\n }): Promise<{\r\n readonly ok: boolean\r\n readonly status: number\r\n json(): Promise<unknown>\r\n }>\r\n}\r\n\r\nexport interface FeedbackRequest {\r\n readonly sessionId: string\r\n readonly id: string\r\n readonly score: FeedbackScore\r\n}\r\n\r\n/** Whether a status code means \"no such route\" rather than \"the call failed\". */\r\nfunction isAbsentStatus(status: number): boolean {\r\n return status === 404 || status === 405 || status === 501\r\n}\r\n\r\n/** The host's RpcResult envelope, narrowed enough to read the two branches. */\r\nfunction parseEnvelope(value: unknown): { ok: true; value: Record<string, unknown> } | { ok: false; reason: string } | undefined {\r\n if (value === null || typeof value !== 'object' || Array.isArray(value)) return undefined\r\n const raw = value as Record<string, unknown>\r\n if (raw['ok'] === true && raw['value'] !== null && typeof raw['value'] === 'object') {\r\n return { ok: true, value: raw['value'] as Record<string, unknown> }\r\n }\r\n if (raw['ok'] === false) {\r\n const err = raw['error']\r\n const message = err !== null && typeof err === 'object'\r\n ? (err as Record<string, unknown>)['message']\r\n : undefined\r\n return { ok: false, reason: typeof message === 'string' && message.length > 0 ? message : 'rejected' }\r\n }\r\n return undefined\r\n}\r\n\r\nfunction num(value: unknown): number {\r\n return typeof value === 'number' && Number.isFinite(value) ? value : 0\r\n}\r\n\r\n/**\r\n * Send one rating.\r\n *\r\n * Never throws: every failure mode comes back as a discriminated outcome, so a\r\n * click cannot break the render.\r\n */\r\nexport async function sendRecallFeedback(\r\n fetchImpl: FeedbackFetch | undefined,\r\n request: FeedbackRequest,\r\n): Promise<FeedbackOutcome> {\r\n if (typeof fetchImpl !== 'function') return { status: 'absent' }\r\n if (request.sessionId.length === 0 || request.id.length === 0) {\r\n return { status: 'rejected', reason: 'missing-session-or-id' }\r\n }\r\n if (!isFeedbackScore(request.score)) return { status: 'rejected', reason: 'invalid-score' }\r\n\r\n const abort = typeof AbortController === 'function' ? new AbortController() : undefined\r\n const timer = abort === undefined\r\n ? undefined\r\n : setTimeout(() => { abort.abort() }, FEEDBACK_TIMEOUT_MS)\r\n try {\r\n const response = await fetchImpl(RECALL_FEEDBACK_ROUTE, {\r\n method: 'POST',\r\n headers: { 'content-type': 'application/json' },\r\n body: JSON.stringify({ sessionId: request.sessionId, id: request.id, score: request.score }),\r\n ...(abort === undefined ? {} : { signal: abort.signal }),\r\n })\r\n if (!response.ok) {\r\n return isAbsentStatus(response.status)\r\n ? { status: 'absent' }\r\n : { status: 'transport', reason: `HTTP ${response.status}` }\r\n }\r\n let envelope: unknown\r\n try {\r\n envelope = await response.json()\r\n } catch {\r\n return { status: 'transport', reason: 'unparseable-response' }\r\n }\r\n const parsed = parseEnvelope(envelope)\r\n if (parsed === undefined) return { status: 'transport', reason: 'unexpected-envelope' }\r\n if (parsed.ok === false) return { status: 'rejected', reason: parsed.reason }\r\n const value = parsed.value\r\n const rating = value['rating'] !== null && typeof value['rating'] === 'object'\r\n ? value['rating'] as Record<string, unknown>\r\n : {}\r\n return {\r\n status: 'sent',\r\n retired: value['retired'] === true,\r\n announced: value['announced'] === true,\r\n mean: num(rating['mean']),\r\n rated: num(rating['rated']),\r\n }\r\n } catch (err) {\r\n const aborted = err instanceof Error && (err.name === 'AbortError' || err.name === 'TimeoutError')\r\n return { status: 'transport', reason: aborted ? 'timeout' : (err instanceof Error ? err.message : 'network') }\r\n } finally {\r\n if (timer !== undefined) clearTimeout(timer)\r\n }\r\n}\r\n","/**\r\n * The hover bubble for one recalled memory — the whole body, straight off the\r\n * projection frame, no second round-trip.\r\n *\r\n * Two shapes are load-bearing here:\r\n *\r\n * - **Stateless.** The section owns when a bubble opens and which row it shows;\r\n * this only draws what it is handed. No hooks, no buttons, no timers.\r\n * - **`position: fixed`.** The summary tab body is `overflow: auto`, so a box\r\n * absolutely positioned inside a row gets clipped by the scroller's border as\r\n * soon as the row sits near an edge. Fixed positioning plus `bubblePos`\r\n * clamping keeps the bubble inside the viewport instead, and anchored to the\r\n * row's *left* so it never lands on the list it describes.\r\n *\r\n * `pointerEvents: 'none'` is not decoration: a bubble that captures the mouse\r\n * would strand the very row it hovers over and leave the section unable to\r\n * receive the click that selects it.\r\n *\r\n * Colours come from `--dsw-alias-*` tokens only (skin contract, asserted by\r\n * `tests/purity.spec.ts`). There is no shadow token in that family, so the\r\n * bubble separates from the list by border and background layer rather than by\r\n * elevation — a literal `box-shadow` colour would break the contract.\r\n */\r\nimport { createElement } from 'react'\r\nimport type { CSSProperties, ReactNode } from 'react'\r\nimport type { MemoryRecallItem } from './memory-recall'\r\nimport { expandCount } from '../locales'\r\n\r\n/** Bubble box size, mirrored by `bubblePos`'s defaults (keep the two in sync). */\r\nconst BUBBLE_W = 360\r\nconst BUBBLE_H = 220\r\n/** Viewport gutter kept on every side when clamping. */\r\nconst EDGE = 8\r\n\r\n/**\r\n * Clamp the bubble into the viewport.\r\n *\r\n * It opens to the **left** of the row on purpose. The sidebar is right-docked\r\n * and only a few hundred pixels wide, so the old \"anchor + 8\" placement dropped\r\n * the box straight onto the row it came from — covering that row's rating strip\r\n * (the bubble is click-transparent, so the buttons stayed clickable *under* it:\r\n * blind-clicking a score is not an option). Opening left puts the text over the\r\n * chat area and leaves the whole list readable.\r\n *\r\n * Order of preference: left of the row → right of the row (only when the row\r\n * sits so far left that the box would run off the window) → clamped inside the\r\n * viewport. Pure and total.\r\n *\r\n * @param r - the hovered row's rect (`top`/`left`/`right` are read).\r\n * @param vw - viewport width (`window.innerWidth`).\r\n * @param vh - viewport height (`window.innerHeight`).\r\n * @param w - bubble width.\r\n * @param h - bubble height.\r\n * @returns fixed-position coordinates for the bubble.\r\n */\r\nexport function bubblePos(\r\n r: { top: number; left: number; right?: number },\r\n vw: number,\r\n vh: number,\r\n w = BUBBLE_W,\r\n h = BUBBLE_H,\r\n): { top: number; left: number } {\r\n const right = r.right ?? r.left\r\n const preferred = r.left - w - EDGE\r\n const fallback = right + EDGE\r\n const roomOnLeft = preferred >= EDGE\r\n const roomOnRight = fallback + w <= vw - EDGE\r\n const unplaced = Math.min(preferred, fallback)\r\n const left = roomOnLeft\r\n ? preferred\r\n : roomOnRight\r\n ? fallback\r\n : unplaced\r\n return {\r\n left: Math.max(EDGE, Math.min(left, vw - w - EDGE)),\r\n top: Math.max(EDGE, Math.min(r.top, vh - h - EDGE)),\r\n }\r\n}\r\n\r\nconst BUBBLE_STYLE: CSSProperties = {\r\n position: 'fixed',\r\n pointerEvents: 'none',\r\n zIndex: 1000,\r\n maxWidth: BUBBLE_W,\r\n maxHeight: '45vh',\r\n overflow: 'hidden',\r\n padding: '8px 10px',\r\n borderRadius: 6,\r\n background: 'var(--dsw-alias-bg-layer-3)',\r\n border: '1px solid var(--dsw-alias-border-l2)',\r\n color: 'var(--dsw-alias-label-primary)',\r\n fontSize: 12,\r\n lineHeight: '17px',\r\n}\r\n\r\nconst TYPE_STYLE: CSSProperties = {\r\n display: 'inline-block',\r\n marginBottom: 4,\r\n color: 'var(--dsw-alias-label-tertiary)',\r\n border: '1px solid var(--dsw-alias-label-tertiary)',\r\n borderRadius: 999,\r\n padding: '0 6px',\r\n fontSize: 11,\r\n lineHeight: '16px',\r\n}\r\n\r\nconst BODY_STYLE: CSSProperties = {\r\n minWidth: 0,\r\n overflowWrap: 'anywhere',\r\n whiteSpace: 'pre-wrap',\r\n color: 'var(--dsw-alias-label-primary)',\r\n}\r\n\r\nconst SCENARIO_STYLE: CSSProperties = {\r\n marginTop: 4,\r\n minWidth: 0,\r\n overflowWrap: 'anywhere',\r\n color: 'var(--dsw-alias-label-tertiary)',\r\n fontSize: 11,\r\n lineHeight: '16px',\r\n}\r\n\r\nconst FOOTER_STYLE: CSSProperties = {\r\n marginTop: 4,\r\n color: 'var(--dsw-alias-label-tertiary)',\r\n fontSize: 11,\r\n lineHeight: '16px',\r\n}\r\n\r\n/** A retired record stays readable in the bubble, just marked. */\r\nconst STALE_BODY_STYLE: CSSProperties = { ...BODY_STYLE, textDecoration: 'line-through' }\r\n\r\n/**\r\n * The bubble itself.\r\n *\r\n * @param props - the item to show, the clamped coordinates, and the lookup.\r\n * @returns the bubble element.\r\n */\r\nexport function RecallBubble(props: {\r\n item: MemoryRecallItem\r\n pos: { top: number; left: number }\r\n t: (key: string) => string\r\n}): ReactNode {\r\n const { item, pos, t } = props\r\n const scenario = item.scenario === undefined ? undefined : item.scenario.join(' · ')\r\n const stale = item.retired === true\r\n const rated = item.rating !== undefined && Number.isInteger(item.rating) && item.rating >= 0 && item.rating <= 5\r\n const foot = [\r\n `P${item.priority}`,\r\n rated ? expandCount(t('recall.rated'), item.rating) : undefined,\r\n stale ? t('recall.obsoleted') : undefined,\r\n ].filter((s): s is string => s !== undefined).join(' · ')\r\n return createElement(\r\n 'div',\r\n {\r\n style: { ...BUBBLE_STYLE, top: pos.top, left: pos.left },\r\n 'data-dsh-brief-sidebar': 'recall-bubble',\r\n role: 'tooltip',\r\n },\r\n createElement('span', { style: TYPE_STYLE }, item.type),\r\n createElement(\r\n 'div',\r\n { style: stale ? STALE_BODY_STYLE : BODY_STYLE },\r\n // No body on this frame (an older prime-memory): say so rather than\r\n // quietly showing only the first line as if it were everything.\r\n item.body ?? `${item.title}\\n${t('recall.noBody')}`,\r\n ),\r\n scenario !== undefined && createElement('div', { style: SCENARIO_STYLE }, scenario),\r\n createElement('div', { style: FOOTER_STYLE }, foot),\r\n )\r\n}\r\n","/**\r\n * The session-recall section: what this session actually injected, drawn as a\r\n * part of the summary tab — and now annotatable.\r\n *\r\n * Where `MemorySlotsSection` lists hand-pinned resident conventions (written\r\n * once, injected every turn), this one answers a different question: **which\r\n * memories did the model see this session, and which are still in context**.\r\n * The set is not resident — it is relevance recall. Compaction does NOT drop\r\n * entries: prime-memory marks the ones whose text a summary replaced as\r\n * `superseded`, and this section hides those (the footer keeps the count).\r\n * Retired rows are the exception and stay visible. Only `/clear` empties the list.\r\n *\r\n * TWO gates, both fail-open to \"hidden\", mirroring the slots section:\r\n *\r\n * 1. **The switch.** This plugin's entry config (`configForms` → field\r\n * `showMemoryRecall`, default on).\r\n * 2. **The capability.** The `memoryRecall` projection must exist for the\r\n * session; `undefined` hides the section entirely — a composition without\r\n * dsh-prime-memory paints nothing here.\r\n *\r\n * Rating is a THIRD gate, and it fails open the same way: the mark goes back to\r\n * prime-memory over its client RPC route (`recall-feedback.ts`). A composition\r\n * whose prime-memory predates that endpoint answers 404, and the section falls\r\n * back to the read-only list it used to be — no per-click error, no dead button.\r\n *\r\n * What the marks mean (prime-memory owns the semantics, this only offers them):\r\n * - `0..5` — how relevant this recall actually was. Aggregated; it does NOT\r\n * rewrite any ranking on its own.\r\n * - `-1` — \"this memory is obsolete\": prime-memory retires the record (soft\r\n * delete, restorable from its panel) and tells the model next turn. That is\r\n * why it takes a second confirming click and says so on the button.\r\n *\r\n * A retired row does NOT leave this list: the retirement is the human's verdict\r\n * on that memory, so the row stays, struck through and unselectable, until the\r\n * session is cleared. A `superseded` row (its text was replaced by a summary, so\r\n * it is no longer in context) IS hidden, with the count kept in the footer.\r\n * Hovering a row opens one bubble with the whole body (`RecallBubble`)\r\n * — the row itself is clamped to two lines and the sidebar is narrow.\r\n *\r\n * Colours come from `--dsw-alias-*` tokens only (skin contract, enforced by\r\n * `tests/purity.spec.ts`).\r\n */\r\nimport { createElement } from 'react'\r\nimport { useCallback, useEffect, useRef, useState } from 'react'\r\nimport type { CSSProperties, ReactNode } from 'react'\r\nimport type { Context } from '@deepseek-ai/cordis'\r\nimport { MEMORY_RECALL_KEY, readRecall } from './memory-recall'\r\nimport type { MemoryRecallItem, MemoryRecallView } from './memory-recall'\r\nimport { FEEDBACK_SCORES, sendRecallFeedback } from './recall-feedback'\r\nimport type { FeedbackFetch, FeedbackScore } from './recall-feedback'\r\nimport { RecallBubble, bubblePos } from './RecallBubble'\r\nimport { resolveShowMemoryRecall } from '../scope-face'\r\nimport { useConfigFlag } from './use-config-flag'\r\nimport { useProjectionValue } from '../use-projection'\r\nimport { expandCount } from '../locales'\r\nimport { FoldToggle, GroupHeader } from './FoldToggle'\r\n\r\nexport interface MemoryRecallSectionProps {\r\n /** The DSH locale lookup, passed down from `apply`. */\r\n t: (key: string) => string\r\n /** The client root context (the tab body's only way to reach services). */\r\n ctx?: Context\r\n /** The session this tab is scoped to. */\r\n scope?: { readonly sessionId?: string }\r\n /**\r\n * The transport for rating. Defaults to the page's `fetch`; injectable so the\r\n * click path is testable without a browser.\r\n */\r\n fetchImpl?: FeedbackFetch\r\n}\r\n\r\nconst SECTION_STYLE: CSSProperties = {\r\n flexShrink: 0,\r\n borderBottom: '1px solid var(--dsw-alias-border-secondary)',\r\n}\r\n\r\nconst HEADER_STYLE: CSSProperties = {\r\n padding: '10px 12px 0',\r\n color: 'var(--dsw-alias-label-secondary)',\r\n fontSize: 12,\r\n fontWeight: 600,\r\n}\r\n\r\nconst HINT_STYLE: CSSProperties = {\r\n padding: '2px 12px 0',\r\n color: 'var(--dsw-alias-label-tertiary)',\r\n fontSize: 11,\r\n lineHeight: '15px',\r\n}\r\n\r\nconst LIST_STYLE: CSSProperties = {\r\n listStyle: 'none',\r\n margin: 0,\r\n padding: '6px 0',\r\n display: 'flex',\r\n flexDirection: 'column',\r\n}\r\n\r\nconst ROW_STYLE: CSSProperties = {\r\n display: 'flex',\r\n alignItems: 'flex-start',\r\n gap: 8,\r\n padding: '6px 12px',\r\n}\r\n\r\n/** Selected row: one hairline of accent, no colour literal (skin contract). */\r\nconst ROW_SELECTED_STYLE: CSSProperties = {\r\n ...ROW_STYLE,\r\n background: 'var(--dsw-alias-fill-quaternary)',\r\n}\r\n\r\n/** The type pill: same form as the slot kind pill, tertiary emphasis. */\r\nconst TYPE_STYLE: CSSProperties = {\r\n flexShrink: 0,\r\n color: 'var(--dsw-alias-label-tertiary)',\r\n border: '1px solid var(--dsw-alias-label-tertiary)',\r\n borderRadius: 999,\r\n padding: '0 6px',\r\n fontSize: 11,\r\n lineHeight: '16px',\r\n whiteSpace: 'nowrap',\r\n}\r\n\r\nconst TITLE_STYLE: CSSProperties = {\r\n minWidth: 0,\r\n color: 'var(--dsw-alias-label-secondary)',\r\n // Two lines, always the same height whatever the body says — the row keeps\r\n // its shape and the whole text rides the hover bubble instead.\r\n display: '-webkit-box',\r\n WebkitLineClamp: 2,\r\n WebkitBoxOrient: 'vertical',\r\n overflow: 'hidden',\r\n fontSize: 12,\r\n lineHeight: '17px',\r\n}\r\n\r\n/**\r\n * Struck-through text for a retired row. Colour drops to tertiary because a\r\n * dead entry must not compete with a live one for the eye.\r\n */\r\nconst STRIKE_STYLE: CSSProperties = {\r\n textDecoration: 'line-through',\r\n color: 'var(--dsw-alias-label-tertiary)',\r\n}\r\n\r\nconst SCENARIO_STYLE: CSSProperties = {\r\n margin: 0,\r\n minWidth: 0,\r\n overflowWrap: 'anywhere',\r\n color: 'var(--dsw-alias-label-tertiary)',\r\n fontSize: 11,\r\n lineHeight: '16px',\r\n}\r\n\r\nconst META_STYLE: CSSProperties = {\r\n flexShrink: 0,\r\n color: 'var(--dsw-alias-label-tertiary)',\r\n fontSize: 11,\r\n lineHeight: '18px',\r\n whiteSpace: 'nowrap',\r\n}\r\n\r\nconst FOOTER_STYLE: CSSProperties = {\r\n padding: '6px 12px 10px',\r\n color: 'var(--dsw-alias-label-tertiary)',\r\n fontSize: 12,\r\n}\r\n\r\nconst EMPTY_STYLE: CSSProperties = {\r\n margin: '0 auto',\r\n padding: 24,\r\n maxWidth: 460,\r\n textAlign: 'center',\r\n color: 'var(--dsw-alias-label-tertiary)',\r\n lineHeight: 1.7,\r\n fontSize: 12,\r\n}\r\n\r\nconst STRIP_STYLE: CSSProperties = {\r\n display: 'flex',\r\n flexWrap: 'wrap',\r\n gap: 4,\r\n marginTop: 4,\r\n}\r\n\r\nconst SCORE_BUTTON_STYLE: CSSProperties = {\r\n minWidth: 24,\r\n padding: '0 5px',\r\n height: 20,\r\n fontSize: 11,\r\n lineHeight: '18px',\r\n color: 'var(--dsw-alias-label-secondary)',\r\n background: 'none',\r\n border: '1px solid var(--dsw-alias-border-secondary)',\r\n borderRadius: 4,\r\n cursor: 'pointer',\r\n}\r\n\r\n/** The chosen mark: same box, filled so it survives a re-render without colour literals. */\r\nconst SCORE_ACTIVE_STYLE: CSSProperties = {\r\n ...SCORE_BUTTON_STYLE,\r\n border: '1px solid var(--dsw-alias-label-secondary)',\r\n color: 'var(--dsw-alias-label-primary)',\r\n}\r\n\r\n/** `-1` reads as an action, not a score: text instead of a number. */\r\nconst OBSOLETE_BUTTON_STYLE: CSSProperties = {\r\n ...SCORE_BUTTON_STYLE,\r\n minWidth: 0,\r\n whiteSpace: 'nowrap',\r\n}\r\n\r\nconst OBSOLETE_ARMED_STYLE: CSSProperties = {\r\n ...OBSOLETE_BUTTON_STYLE,\r\n border: '1px solid var(--dsw-alias-border-color-danger)',\r\n color: 'var(--dsw-alias-label-primary)',\r\n fontWeight: 600,\r\n}\r\n\r\nconst MARK_STYLE: CSSProperties = {\r\n marginTop: 2,\r\n color: 'var(--dsw-alias-label-tertiary)',\r\n fontSize: 11,\r\n lineHeight: '15px',\r\n}\r\n\r\nconst ERROR_STYLE: CSSProperties = {\r\n marginTop: 2,\r\n color: 'var(--dsw-alias-label-secondary)',\r\n fontSize: 11,\r\n lineHeight: '15px',\r\n overflowWrap: 'anywhere',\r\n}\r\n\r\n/**\r\n * The rating strip of one selected row: `-1` (two-step) plus `0..5`.\r\n *\r\n * Exported for tests — the section itself only mounts it for the selected row,\r\n * and a static render never has one selected.\r\n *\r\n * **Every click here must stop propagating.** The strip lives INSIDE the row,\r\n * and the row's own `onClick` toggles the selection — so an un-stopped click\r\n * deselects the row, this strip unmounts mid-gesture, and the `-1` button's\r\n * armed \"确认退场?\" state is rendered on a node that is already gone. That is\r\n * the whole \"按了没反应、也没有删除线\" report: the request was never sent, the\r\n * confirmation was never shown, the control simply vanished on the first press.\r\n * @param props - labels, current mark, and the click handlers.\r\n */\r\nexport function RatingStrip(props: {\r\n current: number | undefined\r\n pending: boolean\r\n armed: boolean\r\n obsoleteLabel: string\r\n confirmLabel: string\r\n whyLabel: string\r\n onScore(score: FeedbackScore): void\r\n}): ReactNode {\r\n const { current, pending, armed } = props\r\n // Clicks landing on the strip's gaps/padding count too: anything inside here\r\n // belongs to the strip, not to the row beneath it.\r\n const swallow = (e: { stopPropagation(): void }): void => { e.stopPropagation() }\r\n return createElement(\r\n 'div',\r\n {\r\n style: STRIP_STYLE,\r\n onClick: swallow,\r\n 'data-dsh-brief-sidebar': 'recall-rating-strip',\r\n },\r\n createElement(\r\n 'button',\r\n {\r\n type: 'button',\r\n style: armed ? OBSOLETE_ARMED_STYLE : OBSOLETE_BUTTON_STYLE,\r\n disabled: pending,\r\n // Before arming the tooltip explains the consequence; after, it asks.\r\n title: armed ? props.confirmLabel : props.whyLabel,\r\n onClick: (e: { stopPropagation(): void }) => {\r\n e.stopPropagation()\r\n props.onScore(-1)\r\n },\r\n },\r\n armed ? props.confirmLabel : props.obsoleteLabel,\r\n ),\r\n ...FEEDBACK_SCORES.filter(s => s >= 0).map(score => createElement(\r\n 'button',\r\n {\r\n key: score,\r\n type: 'button',\r\n style: current === score ? SCORE_ACTIVE_STYLE : SCORE_BUTTON_STYLE,\r\n disabled: pending,\r\n 'aria-pressed': current === score,\r\n onClick: (e: { stopPropagation(): void }) => {\r\n e.stopPropagation()\r\n props.onScore(score)\r\n },\r\n },\r\n String(score),\r\n )),\r\n )\r\n}\r\n\r\n/**\r\n * One recalled memory: type pill, first two lines of the body, its own\r\n * priority, and — once selected and still alive — the rating strip. Hovering\r\n * opens the bubble with the whole text; a retired row is struck through and\r\n * cannot be selected (there is nothing left to mark on a record prime-memory\r\n * has already retired).\r\n */\r\nfunction RecallRow(props: {\r\n item: MemoryRecallItem\r\n selected: boolean\r\n stale: boolean\r\n wasSuperseded: boolean\r\n pending: boolean\r\n armed: boolean\r\n mark: number | undefined\r\n error: string | undefined\r\n rating: boolean\r\n t: (key: string) => string\r\n onSelect(): void\r\n onScore(score: FeedbackScore): void\r\n onEnter(el: HTMLElement): void\r\n onLeave(): void\r\n}): ReactNode {\r\n const { item, selected, stale, wasSuperseded, mark, error, t } = props\r\n const scenario = item.scenario === undefined ? undefined : item.scenario.join(' · ')\r\n const markText = mark === undefined\r\n ? undefined\r\n : mark === -1\r\n ? t('recall.obsoleted')\r\n : expandCount(t('recall.rated'), mark)\r\n // A row prime-memory already retired but the human did not mark in this view\r\n // still needs the caption; when `mark === -1` the line above says the same\r\n // thing, so the two are mutually exclusive rather than doubled.\r\n const staleText = stale && mark !== -1 ? t('recall.obsoleted') : undefined\r\n const selectable = props.rating && !stale\r\n const titleStyle = stale ? { ...TITLE_STYLE, ...STRIKE_STYLE } : TITLE_STYLE\r\n return createElement(\r\n 'li',\r\n {\r\n style: selected && props.rating ? ROW_SELECTED_STYLE : ROW_STYLE,\r\n onClick: selectable ? props.onSelect : undefined,\r\n onMouseEnter: (e: { currentTarget: unknown }) => {\r\n const el = e.currentTarget\r\n if (el instanceof HTMLElement) props.onEnter(el)\r\n },\r\n onMouseLeave: () => { props.onLeave() },\r\n },\r\n createElement('span', { style: TYPE_STYLE }, item.type),\r\n createElement(\r\n 'div',\r\n { style: { minWidth: 0, flex: '1 1 auto', display: 'flex', flexDirection: 'column', gap: 2 } },\r\n createElement(\r\n 'span',\r\n // 不给原生 `title`:那会在泡泡之外再多一个宿主自己的深色提示框,两者内容重叠、\r\n // 样式不受皮肤契约管,反而把泡泡遮住。全文与使用场景现在都由 `RecallBubble` 承载。\r\n { style: titleStyle },\r\n item.title,\r\n ),\r\n scenario !== undefined && createElement(\r\n 'p',\r\n { style: stale ? { ...SCENARIO_STYLE, ...STRIKE_STYLE } : SCENARIO_STYLE },\r\n scenario,\r\n ),\r\n staleText !== undefined && createElement('span', { style: MARK_STYLE }, staleText),\r\n // “正文已被摘要取代”是行自己的事实,得写在行上:否则展开历史组后,\r\n // 读者只能靠位置猜哪一行不在上下文里。\r\n wasSuperseded && createElement(\r\n 'span',\r\n { style: TYPE_STYLE, 'data-dsh-brief-sidebar': 'recall-superseded-tag' },\r\n t('recall.supersededTag'),\r\n ),\r\n markText !== undefined && createElement('span', { style: MARK_STYLE }, markText),\r\n error !== undefined && createElement(\r\n 'span',\r\n { style: ERROR_STYLE },\r\n `${t('recall.failed')}${error}`,\r\n ),\r\n selected && !stale && props.rating && createElement(RatingStrip, {\r\n current: mark,\r\n pending: props.pending,\r\n armed: props.armed,\r\n obsoleteLabel: t('recall.obsolete'),\r\n confirmLabel: t('recall.obsoleteConfirm'),\r\n whyLabel: t('recall.obsoleteWhy'),\r\n onScore: props.onScore,\r\n }),\r\n ),\r\n createElement('span', { style: META_STYLE }, `P${item.priority}`),\r\n )\r\n}\r\n\r\n/** How long the `-1` button stays armed before reverting to its plain label. */\r\nconst ARM_WINDOW_MS = 5_000\r\n\r\n/** Delay before a hover opens its bubble (ms) — swiping past rows must not paint. */\r\nconst HOVER_DELAY_MS = 150\r\n\r\n/**\r\n * The session-recall section. All hooks run unconditionally (a conditional hook\r\n * order would break the moment the switch flips); the gates only decide whether\r\n * the resolved view paints and whether rows are clickable.\r\n * @param props - translation, client context, session scope, transport.\r\n */\r\nexport function MemoryRecallSection(props: MemoryRecallSectionProps): ReactNode {\r\n const { t, ctx, scope } = props\r\n const [selectedId, setSelectedId] = useState<string | undefined>(undefined)\r\n const [marks, setMarks] = useState<Record<string, number>>({})\r\n // Rows the human just marked obsolete in THIS view. prime-memory's `retired`\r\n // covers the ones retired earlier; these two sets union into \"draw a strike\".\r\n const [staleIds, setStaleIds] = useState<readonly string[]>([])\r\n const [hover, setHover] = useState<{ id: string; top: number; left: number; right: number } | undefined>(undefined)\r\n const pendingHover = useRef<ReturnType<typeof setTimeout> | null>(null)\r\n const [pendingId, setPendingId] = useState<string | undefined>(undefined)\r\n const [errors, setErrors] = useState<Record<string, string>>({})\r\n const [armed, setArmed] = useState(false)\r\n // Flipped once by a 404: the composition's prime-memory cannot take marks,\r\n // so the section goes back to being the plain read-only list it was.\r\n const [writeAbsent, setWriteAbsent] = useState(false)\r\n // 历史召回组默认折叠:它们已不在上下文里,但仍属于“本会话见过什么”的一部分。\r\n const [historyOpen, setHistoryOpen] = useState(false)\r\n\r\n const show = useConfigFlag(ctx, resolveShowMemoryRecall)\r\n const view: MemoryRecallView | undefined = readRecall(\r\n useProjectionValue(ctx, scope?.sessionId, MEMORY_RECALL_KEY),\r\n )\r\n\r\n const sessionId = scope?.sessionId ?? ''\r\n const rating = writeAbsent === false && sessionId.length > 0\r\n\r\n const rate = useCallback((id: string, score: FeedbackScore): void => {\r\n if (score === -1 && armed === false) {\r\n // Retirement is destructive-ish (soft delete + a notice to the model):\r\n // the first click only arms the button.\r\n setArmed(true)\r\n setTimeout(() => { setArmed(false) }, ARM_WINDOW_MS)\r\n return\r\n }\r\n if (pendingId !== undefined) return\r\n setArmed(false)\r\n setPendingId(id)\r\n const impl: FeedbackFetch | undefined = props.fetchImpl\r\n ?? (typeof fetch === 'function' ? (fetch as unknown as FeedbackFetch) : undefined)\r\n void sendRecallFeedback(impl, { sessionId, id, score }).then(outcome => {\r\n setPendingId(undefined)\r\n if (outcome.status === 'sent') {\r\n setMarks(current => ({ ...current, [id]: score }))\r\n setErrors(current => {\r\n const next = { ...current }\r\n delete next[id]\r\n return next\r\n })\r\n if (score === -1) setStaleIds(current => (current.includes(id) ? current : [...current, id]))\r\n setHover(undefined)\r\n if (score !== -1) setSelectedId(undefined)\r\n } else if (outcome.status === 'absent') {\r\n setWriteAbsent(true)\r\n setSelectedId(undefined)\r\n } else {\r\n setErrors(current => ({ ...current, [id]: outcome.reason }))\r\n }\r\n })\r\n }, [armed, pendingId, props.fetchImpl, sessionId])\r\n\r\n const onSelect = useCallback((id: string): void => {\r\n setArmed(false)\r\n setSelectedId(current => (current === id ? undefined : id))\r\n }, [])\r\n\r\n // One bubble at a time, and it opens on a delay: sweeping the mouse down the\r\n // list must not paint a bubble for every row it passes.\r\n const onEnter = useCallback((id: string, el: HTMLElement): void => {\r\n if (pendingHover.current !== null) clearTimeout(pendingHover.current)\r\n const rect = el.getBoundingClientRect()\r\n pendingHover.current = setTimeout(() => {\r\n pendingHover.current = null\r\n // The whole rect travels, not just its origin: `bubblePos` needs the row's\r\n // RIGHT edge to place the box outside the sidebar instead of on top of it.\r\n setHover({ id, top: rect.top, left: rect.left, right: rect.right })\r\n }, HOVER_DELAY_MS)\r\n }, [])\r\n\r\n const onLeave = useCallback((): void => {\r\n if (pendingHover.current !== null) {\r\n clearTimeout(pendingHover.current)\r\n pendingHover.current = null\r\n }\r\n setHover(undefined)\r\n }, [])\r\n\r\n // Unmounting mid-sweep would otherwise leave a timer that sets state on a\r\n // dead section.\r\n useEffect(() => () => {\r\n if (pendingHover.current !== null) clearTimeout(pendingHover.current)\r\n }, [])\r\n\r\n // Switched off at the settings faces — willed away, not empty.\r\n if (show === false) return null\r\n\r\n // Capability absent (prime-memory not in the composition, no frame yet).\r\n if (view === undefined) return null\r\n\r\n // Retired rows stay: that mark is the human's verdict, and the model did see them.\r\n // A `superseded` row is different — its text is no longer in context — so it is\r\n // hidden, and the footer reports the count so nothing disappears silently.\r\n const isStale = (item: MemoryRecallItem): boolean => item.retired === true || staleIds.includes(item.id)\r\n // 两组按“正文还在不在上下文”分:活跃 = 未取代(或被退场的例外,裁决凭证必须留下);\r\n // 其余历史 = 被摘要取代且未被裁决退场的,它们收进开关后面而不是只报个计数。\r\n const rows = view.items.filter(item => item.superseded !== true || item.retired === true)\r\n const historyRows = view.items.filter(item => item.superseded === true && item.retired !== true)\r\n const hidden = historyRows.length\r\n\r\n if (rows.length === 0) {\r\n return createElement(\r\n 'div',\r\n { style: SECTION_STYLE, 'data-dsh-brief-sidebar': 'memory-recall-section' },\r\n createElement('div', { style: HEADER_STYLE }, t('section.memoryRecall')),\r\n createElement(\r\n 'div',\r\n {\r\n style: EMPTY_STYLE,\r\n // 隐藏数为 0 时是真正的空态;否则这是“本轮确实召回过、但正文已被摘要替换”的告知。\r\n ...(hidden > 0 ? { 'data-dsh-brief-sidebar': 'recall-superseded-note' } : {}),\r\n },\r\n hidden > 0 ? expandCount(t('recall.supersededHidden'), hidden) : t('recall.empty'),\r\n ),\r\n // 空态下历史组仍要能展开:否则“全都被取代”的会话永远读不到自己召回过什么。\r\n historyRows.length > 0 && createElement(FoldToggle, {\r\n label: expandCount(t('recall.historyGroup'), historyRows.length),\r\n open: historyOpen,\r\n marker: 'recall-history-toggle',\r\n onToggle: () => { setHistoryOpen(current => !current) },\r\n }),\r\n historyOpen && createElement(\r\n 'ul',\r\n { style: LIST_STYLE },\r\n historyRows.map(item => createElement(RecallRow, {\r\n key: item.id,\r\n item,\r\n selected: false,\r\n stale: isStale(item),\r\n wasSuperseded: true,\r\n pending: false,\r\n armed: false,\r\n mark: undefined,\r\n error: undefined,\r\n rating: false,\r\n t,\r\n onSelect: () => {},\r\n onScore: () => {},\r\n onEnter: () => {},\r\n onLeave: () => {},\r\n })),\r\n ),\r\n )\r\n }\r\n\r\n return createElement(\r\n 'div',\r\n { style: SECTION_STYLE, 'data-dsh-brief-sidebar': 'memory-recall-section' },\r\n createElement('div', { style: HEADER_STYLE }, t('section.memoryRecall')),\r\n rating && createElement('div', { style: HINT_STYLE }, `${t('recall.rateHint')}${t('recall.strikeHint')}`),\r\n // 活跃组计数只说“仍在上下文”的那些,注入总数归页脚,两个数各说各的。\r\n rows.length > 0 && createElement(GroupHeader, {\r\n text: expandCount(t('recall.activeGroup'), rows.length),\r\n marker: 'recall-active-group',\r\n }),\r\n createElement(\r\n 'ul',\r\n { style: LIST_STYLE },\r\n rows.map(item => createElement(RecallRow, {\r\n key: item.id,\r\n item,\r\n selected: selectedId === item.id,\r\n stale: isStale(item),\r\n wasSuperseded: item.superseded === true,\r\n pending: pendingId === item.id,\r\n armed: armed && selectedId === item.id,\r\n mark: marks[item.id] ?? item.rating,\r\n error: errors[item.id],\r\n rating,\r\n t,\r\n onSelect: () => { onSelect(item.id) },\r\n onScore: (score: FeedbackScore) => { rate(item.id, score) },\r\n onEnter: (el: HTMLElement) => { onEnter(item.id, el) },\r\n onLeave,\r\n })),\r\n ),\r\n historyRows.length > 0 && createElement(FoldToggle, {\r\n label: expandCount(t('recall.historyGroup'), historyRows.length),\r\n open: historyOpen,\r\n marker: 'recall-history-toggle',\r\n onToggle: () => { setHistoryOpen(current => !current) },\r\n }),\r\n historyOpen && createElement(\r\n 'ul',\r\n { style: LIST_STYLE },\r\n historyRows.map(item => createElement(RecallRow, {\r\n key: item.id,\r\n item,\r\n // 历史行不开评分:退场与相关度都是对“还在上下文里的那条”的裁决,\r\n // 正文已被取代的行再标一次也不会回到上下文,只会让人以为还能救。\r\n selected: false,\r\n stale: isStale(item),\r\n wasSuperseded: true,\r\n pending: false,\r\n armed: false,\r\n mark: undefined,\r\n error: undefined,\r\n rating: false,\r\n t,\r\n onSelect: () => {},\r\n onScore: () => {},\r\n onEnter: () => {},\r\n onLeave: () => {},\r\n })),\r\n ),\r\n createElement(\r\n 'div',\r\n { style: FOOTER_STYLE },\r\n expandCount(t('recall.count'), view.count),\r\n hidden > 0 && createElement(\r\n 'div',\r\n { 'data-dsh-brief-sidebar': 'recall-superseded-note' },\r\n expandCount(t('recall.supersededHidden'), hidden),\r\n ),\r\n ),\r\n // The single bubble of this section. `typeof window` guard keeps a\r\n // non-DOM render (tests, SSR) from ever reaching the viewport maths.\r\n hover !== undefined && typeof window !== 'undefined'\r\n && (() => {\r\n const item = view.items.find(i => i.id === hover.id)\r\n if (item === undefined) return null\r\n return createElement(RecallBubble, {\r\n item,\r\n pos: bubblePos(hover, window.innerWidth, window.innerHeight),\r\n t,\r\n })\r\n })(),\r\n )\r\n}\r\n","/**\r\n * The summary tab body: the session's at-a-glance state, composed of sections.\r\n *\r\n * Section order: 进展 (the todos board) → 产物 (produced files, codeplan\r\n * artifacts marked inline) → 技能引用 (which skills this session loaded) →\r\n * 本会话召回 (what prime-memory injected into this session and compaction has\r\n * not overwritten) → 记忆槽位 (hand-pinned resident conventions, off by default).\r\n * Each section owns its own data chain and its own gating contract; this\r\n * component owns only the shell.\r\n *\r\n * Two better-sidebar contracts are honoured:\r\n *\r\n * 1. **Height contract.** The tab body mounts inside a full-height column flex\r\n * host whose `.paneBody` is a definite-height BLOCK scroll container. The\r\n * root declares `height: 100%` + `min-height: 0`, and the scrolling element\r\n * is an inner div — not the root. Sections are non-scrolling slices with a\r\n * bottom border; the inner div scrolls them all.\r\n * 2. **`visible` pause.** Nothing is drawn while the tab is not the active\r\n * one, so a hidden tab does not re-render on every projection frame.\r\n */\r\nimport { createElement } from 'react'\r\nimport type { CSSProperties, ReactNode } from 'react'\r\nimport type { Context } from '@deepseek-ai/cordis'\r\nimport { TodoSection } from './TodoBoardTab'\r\nimport type { TodoScope } from './TodoBoardTab'\r\nimport { DeliverablesSection } from './summary/DeliverablesSection'\r\nimport { SkillUsageSection } from './summary/SkillUsageSection'\r\nimport { MemorySlotsSection } from './summary/MemorySlotsSection'\r\nimport { MemoryRecallSection } from './summary/MemoryRecallSection'\r\n\r\nexport interface SummaryTabProps {\r\n /** The DSH locale lookup, passed down from `apply`. */\r\n t: (key: string) => string\r\n /** The client root context (the tab body's only way to reach services). */\r\n ctx?: Context\r\n /** The session this tab is scoped to. */\r\n scope?: TodoScope\r\n /** Whether the tab is the active one AND the panel is open. */\r\n visible?: boolean\r\n}\r\n\r\nconst ROOT_STYLE: CSSProperties = {\r\n display: 'flex',\r\n flexDirection: 'column',\r\n height: '100%',\r\n minHeight: 0,\r\n background: 'var(--dsw-alias-bg-layer-1)',\r\n color: 'var(--dsw-alias-label-primary)',\r\n font: 'inherit',\r\n fontSize: 13,\r\n}\r\n\r\nconst SCROLL_STYLE: CSSProperties = { flex: 1, minHeight: 0, overflow: 'auto' }\r\n\r\n/**\r\n * The summary tab.\r\n * @param props - translation, client context, session scope, visibility.\r\n */\r\nexport function SummaryTab(props: SummaryTabProps): ReactNode {\r\n const { t, ctx, scope, visible = true } = props\r\n\r\n // A hidden tab renders NOTHING — not even the shell — so it never\r\n // re-renders on a projection frame while it is off screen.\r\n if (!visible) return null\r\n\r\n return createElement(\r\n 'div',\r\n { style: ROOT_STYLE, 'data-dsh-brief-sidebar': 'board' },\r\n createElement('div', { style: SCROLL_STYLE },\r\n createElement(TodoSection, { key: 'progress', t, ctx, scope }),\r\n createElement(DeliverablesSection, { key: 'deliverables', t, ctx, scope }),\r\n // 技能引用:本会话通过宿主 `skill` 工具载入过哪些技能(`dshSummarySkillUsage`\r\n // 投影,本插件自己的 host 半注册)。与记忆两栏正交:这里讲“拉过哪些说明书”,\r\n // 下面两栏讲“模型看到了哪些记忆”。只读,无开关,投影缺席即整段隐藏。\r\n createElement(SkillUsageSection, { key: 'skill-usage', t, ctx, scope }),\r\n // 本会话召回(固定最底):入口开关(configForms `showMemoryRecall`,默认开)\r\n // 与能力存在(dsh-prime-memory 的 `memoryRecall` 投影)缺一即整段隐藏。\r\n // 这是\"模型此刻看到哪些记忆\"的诚实视图:非常驻,压缩后即清空。\r\n createElement(MemoryRecallSection, { key: 'memory-recall', t, ctx, scope }),\r\n // 记忆槽位分区:手动 pin 的常驻约定(`memorySlots` 投影),默认关。\r\n createElement(MemorySlotsSection, { key: 'memory-slots', t, ctx, scope }),\r\n ),\r\n )\r\n}\r\n","/**\r\n * Native right-sidebar path: register the board tab directly into the DSH\r\n * host's own sidebar, with NO better-sidebar in sight. Available on host\r\n * generations that ship `dsh-client-ui-sidebar-right` (0.1.5+; verified by\r\n * slot-declaration forensics on 0.1.5-rc.3, 0.1.7-rc.2 and 0.2.0-rc.2).\r\n *\r\n * The host opens a tab type through a two-stage registration, and this module\r\n * copies better-sidebar's own native bridge EXACTLY — that plugin is the\r\n * shipped, field-proof consumer of the same seats:\r\n *\r\n * 1. Stage one, \"what the type IS\": `ctx.sidebarRightTabs.register({id, kind,\r\n * title, guide})` (a `SidebarRightTabDefinition`; page type — no `patterns`,\r\n * opened by kind). The returned disposer lives in our effect.\r\n * 2. Stage two, \"what the body draws\": a keyed registration under\r\n * `sidebar.right.pane.tab` whose `key` is the definition's `id`. The inject\r\n * callback receives the session id; everything else (our `t`, the root\r\n * `ctx`) rides a closure, and `SummaryTab` reads session data through\r\n * `ctx.get('sessions')` exactly as it does under better-sidebar.\r\n *\r\n * Degradations versus the better-sidebar path, accepted deliberately:\r\n * - no badge — the native chip has no badge affordance; the unfinished count\r\n * still shows inside the tab body.\r\n * - no `visible` pause — the host unmounts inactive bodies (`keepMounted`\r\n * defaults to false), which subsumes it.\r\n * - the open affordance is the guide-page capsule (`guide[]`), not a rail icon.\r\n *\r\n * Everything is read through `ctx.get` structural probes: the services are\r\n * absent on ≤0.1.2 hosts, so the caller must treat `undefined` as \"no native\r\n * surface\" and stay inert rather than crash. No import from\r\n * `@deepseek-ai/dsh-client-ui-sidebar-right` — a browser-only plugin keeps zero\r\n * build-time coupling to host internals, mirroring `use-projection.ts`.\r\n */\r\nimport type { ReactNode } from 'react'\r\nimport type { Context } from '@deepseek-ai/cordis'\r\nimport type { SlotsLike } from './brief/dock-shadow'\r\nimport { SummaryTab } from './SummaryTab'\r\n\r\n/** One guide-page capsule contributed by our type (structural `SidebarRightGuideEntry`). */\r\ninterface NativeGuideEntry {\r\n readonly id: string\r\n readonly order: number\r\n readonly title: () => string\r\n readonly description?: () => string\r\n}\r\n\r\n/** Stage-one shape (structural `SidebarRightTabDefinition`; only the page-type fields). */\r\ninterface NativeTabDefinition {\r\n readonly id: string\r\n readonly kind: string\r\n readonly title: (address: string) => string\r\n readonly guide?: readonly NativeGuideEntry[]\r\n}\r\n\r\n/** `ctx.sidebarRightTabs` — the only method we call. */\r\ninterface NativeTabRegistryLike {\r\n register(definition: NativeTabDefinition): () => void\r\n}\r\n\r\nexport type { NativeTabRegistryLike }\r\n\r\n/** The keyed seat a tab type registers its body under. */\r\nconst PANE_TAB_SEAT = 'sidebar.right.pane.tab'\r\n\r\n/**\r\n * Whether this host exposes the native right-sidebar tab system at all.\r\n *\r\n * Both services must answer: the registry stages the type, and a future\r\n * \"open from a button\" affordance goes through the controller face.\r\n * @param ctx - the client root context.\r\n */\r\nexport function nativeSidebarAvailable(ctx: Context): boolean {\r\n const registry = ctx.get('sidebarRightTabs') as NativeTabRegistryLike | undefined\r\n const controller = ctx.get('sidebarRight') as unknown\r\n return (\r\n registry !== undefined &&\r\n typeof registry.register === 'function' &&\r\n controller !== undefined &&\r\n ctx.get('slots') !== undefined\r\n )\r\n}\r\n\r\n/**\r\n * Register the board as a native right-sidebar tab type.\r\n *\r\n * The registry arrives as a parameter, read from the deferred `ctx.inject`\r\n * scope in `apply` — the 0.1.7+ strict-proxy ctx refuses a root `ctx.get`\r\n * of an undeclared service, so reaching for `sidebarRightTabs` from the root\r\n * context is what made the native seat silently no-op on 0.1.7 (the \"cannot\r\n * register directly\" observation). better-sidebar's own native bridge reads\r\n * it the same way: from the inject callback's scope.\r\n *\r\n * @param ctx - the client root context (for the declared `slots` service).\r\n * @param registry - the host tab-type registry from the injected scope.\r\n * @param deps - the stable ids and the translator from `apply`.\r\n * @returns a disposer that unregisters the seat first, then the type (the\r\n * registry refuses opens for a type whose body is already gone).\r\n */\r\nexport function registerNativeBoardTab(\r\n ctx: Context,\r\n registry: NativeTabRegistryLike | undefined,\r\n deps: { id: string; kind: string; order: number; t: (key: string) => string },\r\n): () => void {\r\n const slots = ctx.get('slots') as SlotsLike | undefined\r\n if (registry === undefined || typeof registry.register !== 'function' || slots === undefined) {\r\n return (): void => {}\r\n }\r\n\r\n // Stage 1: the type. Page kind — opened from the guide capsule by `kind`.\r\n const disposeType = registry.register({\r\n id: deps.id,\r\n kind: deps.kind,\r\n title: () => deps.t('tab.title'),\r\n guide: [\r\n {\r\n id: deps.id,\r\n order: deps.order,\r\n title: () => deps.t('tab.title'),\r\n description: () => deps.t('tab.desc'),\r\n },\r\n ],\r\n })\r\n\r\n // Stage 2: the body, keyed under the definition's own id. The payload\r\n // mirrors better-sidebar's `TabComponentProps` fields that SummaryTab reads;\r\n // `visible` is pinned true because the host unmounts hidden bodies anyway.\r\n const disposeSeat = slots.inject(PANE_TAB_SEAT, () =>\r\n slots.register(\r\n {\r\n name: PANE_TAB_SEAT,\r\n key: deps.id,\r\n inject: (sessionId: string) => ({\r\n t: deps.t,\r\n ctx,\r\n scope: { sessionId },\r\n visible: true,\r\n }),\r\n },\r\n SummaryTab as unknown as (props: unknown) => ReactNode,\r\n ),\r\n )\r\n\r\n return (): void => {\r\n try {\r\n disposeSeat()\r\n } finally {\r\n disposeType()\r\n }\r\n }\r\n}\r\n","/**\r\n * Tab glyph for the task board.\r\n *\r\n * Skin contract: plugin-drawn glyphs take their colour from the `--dsw-alias-*`\r\n * tokens — no colour literals anywhere in this file.\r\n */\r\nimport type { ReactNode } from 'react'\r\n\r\n/**\r\n * A checklist mark: three rows with ticks and text rails — the same status\r\n * vocabulary the board paints.\r\n * @param size - square edge in px (the host passes its own tab-icon size).\r\n */\r\nexport function BriefIcon(size: number): ReactNode {\r\n return (\r\n <svg\r\n width={size}\r\n height={size}\r\n viewBox=\"0 0 16 16\"\r\n fill=\"none\"\r\n aria-hidden=\"true\"\r\n focusable=\"false\"\r\n style={{ display: 'block', flex: 'none' }}\r\n >\r\n <rect\r\n x={1.6}\r\n y={2.4}\r\n width={12.8}\r\n height={11.2}\r\n rx={2}\r\n stroke=\"var(--dsw-alias-label-tertiary)\"\r\n strokeWidth={1.2}\r\n />\r\n <path\r\n d=\"M4.2 6.1l1 1 1.8-2\"\r\n stroke=\"var(--dsw-alias-state-success-primary)\"\r\n strokeWidth={1.3}\r\n strokeLinecap=\"round\"\r\n strokeLinejoin=\"round\"\r\n />\r\n <path\r\n d=\"M4.2 10.6l1 1 1.8-2\"\r\n stroke=\"var(--dsw-alias-label-tertiary)\"\r\n strokeWidth={1.3}\r\n strokeLinecap=\"round\"\r\n strokeLinejoin=\"round\"\r\n />\r\n <path\r\n d=\"M8.4 6.4h4M8.4 10.9h4\"\r\n stroke=\"var(--dsw-alias-label-tertiary)\"\r\n strokeWidth={1.2}\r\n strokeLinecap=\"round\"\r\n />\r\n </svg>\r\n )\r\n}\r\n","/**\r\n * Hiding the official todo dock.\r\n *\r\n * `conversation.input.dock` is a LIST slot, and its cells are keyed by each\r\n * entry's `id`. The slot core keeps one live entry per cell — entries are\r\n * sorted by `priority` ascending (then by `order`) and the first live entry of\r\n * a cell is the one the outlet renders, so a SECOND registration with the same\r\n * `id` at a LOWER priority shadows the first. The official todo entry\r\n * (`conversation-todo-dock` in `dsh-client-ui-conversation`) registers\r\n * `{ id: 'todo', order: 0 }` with the default priority 0, so\r\n * `{ id: 'todo', priority: -1 }` wins the cell and the official panel never\r\n * renders while this plugin is mounted.\r\n *\r\n * This is the same mechanism `dsh-input-traffic` uses on the sibling `queue`\r\n * cell (`{ id: 'queue', priority: -1 }`), so it is a proven seam on this host\r\n * generation, not a guess.\r\n *\r\n * Binding to a built-in id is a real coupling: if upstream renames the cell,\r\n * the shadow silently stops winning and the official dock simply reappears\r\n * (fail-open — the data is still shown, just twice). `slots.inject` is used\r\n * rather than a bare `register` because the slot is declared by a built-in\r\n * entry whose lifetime we do not control: `inject` waits for the declaration\r\n * and re-installs the entry if the declaration is ever recreated.\r\n *\r\n * Renders nothing on purpose: the todo UI now lives in this plugin's sidebar\r\n * tab. Return a summary chip here instead to keep a one-line entry point in the\r\n * composer band.\r\n */\r\nimport type { ReactNode } from 'react'\r\nimport type { Context } from '@deepseek-ai/cordis'\r\n\r\n/** The built-in cell id of the official todo dock. */\r\nexport const TODO_CELL_ID = 'todo'\r\n\r\n/** Lower than the built-in's default 0 — the winner of the `todo` cell. */\r\nexport const TODO_SHADOW_PRIORITY = -1\r\n\r\n/** Structural view of the client slots service (avoids a second type graph). */\r\nexport interface SlotsLike {\r\n inject(key: string, callback: () => (() => void) | undefined): () => void\r\n register(options: Record<string, unknown>, component: (props: unknown) => ReactNode): () => void\r\n}\r\n\r\n/** The replacement entry: deliberately empty. */\r\nfunction TodoDockShadow(): ReactNode {\r\n return null\r\n}\r\n\r\n/**\r\n * Register the shadowing entry.\r\n *\r\n * The caller wraps this in `ctx.effect(...)` so the returned disposer rides the\r\n * plugin fiber: unloading the plugin restores the official dock.\r\n *\r\n * @param ctx - the client root context.\r\n * @returns the disposer, or undefined when the slots service is unreachable.\r\n */\r\nexport function registerTodoDockShadow(ctx: Context): (() => void) | undefined {\r\n const slots = ctx.get('slots') as SlotsLike | undefined\r\n if (slots === undefined || typeof slots.inject !== 'function') return undefined\r\n\r\n return slots.inject('conversation.input.dock', () =>\r\n slots.register(\r\n {\r\n name: 'conversation.input.dock',\r\n id: TODO_CELL_ID,\r\n order: 0,\r\n priority: TODO_SHADOW_PRIORITY,\r\n registrant: 'dsh-brief-sidebar',\r\n },\r\n TodoDockShadow,\r\n ),\r\n )\r\n}\r\n","/**\r\n * BriefSettingsCard — the brief-sidebar settings card.\r\n *\r\n * One component mounted at TWO seats, fed by the SAME inject factory (one\r\n * source of truth, the dsh-thinking-levels arrangement):\r\n *\r\n * - the plugin-family settings section (「起子插件设置」, the `settings.section`\r\n * entry dsh-thinking-levels registers; this plugin contributes its card to\r\n * the `dsh-family.tab` child slot — the inject idles harmlessly when the\r\n * family section is absent);\r\n * - the Plugins-page configuration card (`plugins.bundle.config`, keyed by\r\n * the package name, rendered on the bundle's detail page).\r\n *\r\n * The card binds this plugin's entry config through the `configForms` service\r\n * and renders the fields the summary tab reads. Every change commits\r\n * immediately through the scope (no staged form), so a flip applies to the\r\n * open summary tab on its next render.\r\n *\r\n * The `t` binder is injected by the factory (the same closure the tab uses) —\r\n * the card does not rely on the framework's locale props, so it renders the\r\n * active language on every host generation. Kept dependency-free beyond\r\n * react: inline styles over `--dsw-alias-*` tokens only (no CSS modules, no\r\n * hex/rgba literals — the purity spec enforces the token contract).\r\n */\r\nimport { useCallback, useState, useSyncExternalStore } from 'react'\r\nimport { createElement } from 'react'\r\nimport type { CSSProperties, ChangeEvent, ReactNode } from 'react'\r\nimport type { BriefClientConfig, SettingsScope, SettingsScopeSnapshot } from './scope-face'\r\nimport { resolveShowMemoryRecall, resolveShowMemorySlots } from './scope-face'\r\n\r\n/** A no-op unsubscribe source, kept as one identity so effects never thrash. */\r\nconst NO_SUBSCRIBE = (): (() => void) => () => {}\r\n\r\n/** The snapshot served while no scope is reachable. */\r\nconst ABSENT: SettingsScopeSnapshot<BriefClientConfig> = {\r\n status: 'unavailable',\r\n value: undefined,\r\n revision: undefined,\r\n writable: false,\r\n}\r\n\r\n/** Injected face: the entry scope, plus the plugin's own binder. */\r\nexport interface BriefSettingsCardInjected {\r\n /** `configForms.get('dsh-brief-sidebar')` — may be unavailable on odd hosts. */\r\n scope?: SettingsScope<BriefClientConfig>\r\n /** The plugin's locale binder (applied-time closure over the locale service). */\r\n t: (key: string) => string\r\n}\r\n\r\nexport type BriefSettingsCardProps = BriefSettingsCardInjected\r\n\r\n/* ── shared row styling (inline; keeps the client bundle CSS-free) ──────── */\r\n\r\nconst CARD_STYLE: CSSProperties = {\r\n border: '1px solid var(--dsw-alias-border-l2)',\r\n background: 'var(--dsw-alias-bg-layer-3)',\r\n borderRadius: 12,\r\n transition: 'border-color 0.16s, background 0.16s',\r\n}\r\n\r\nconst HEADER_STYLE: CSSProperties = {\r\n appearance: 'none',\r\n width: '100%',\r\n font: 'inherit',\r\n color: 'inherit',\r\n textAlign: 'left',\r\n cursor: 'pointer',\r\n background: 'none',\r\n border: 0,\r\n borderRadius: 12,\r\n display: 'flex',\r\n alignItems: 'center',\r\n gap: 12,\r\n padding: '14px 16px',\r\n}\r\n\r\nconst HEADER_TEXT_STYLE: CSSProperties = { flex: '1 1 0%', minWidth: 0 }\r\n\r\nconst NAME_STYLE: CSSProperties = {\r\n fontSize: 14,\r\n fontWeight: 600,\r\n color: 'var(--dsw-alias-label-primary)',\r\n}\r\n\r\nconst DESC_STYLE: CSSProperties = {\r\n color: 'var(--dsw-alias-label-tertiary)',\r\n fontSize: 13,\r\n lineHeight: 1.5,\r\n}\r\n\r\nconst CHEVRON_STYLE = (open: boolean): CSSProperties => ({\r\n color: 'var(--dsw-alias-label-tertiary)',\r\n flex: '0 0 auto',\r\n transition: 'transform 0.16s',\r\n transform: open ? 'rotate(180deg)' : 'none',\r\n})\r\n\r\nconst BODY_STYLE: CSSProperties = { padding: '12px 16px' }\r\n\r\nconst ROW_STYLE: CSSProperties = {\r\n display: 'flex',\r\n alignItems: 'flex-start',\r\n justifyContent: 'space-between',\r\n gap: 12,\r\n padding: '8px 0',\r\n fontSize: 13,\r\n lineHeight: '20px',\r\n}\r\n\r\nconst ROW_TEXT_STYLE: CSSProperties = {\r\n display: 'flex',\r\n flexDirection: 'column',\r\n gap: 4,\r\n minWidth: 0,\r\n}\r\n\r\nconst LABEL_STYLE: CSSProperties = { margin: 0, color: 'var(--dsw-alias-label-primary)' }\r\n\r\nconst HINT_STYLE: CSSProperties = {\r\n margin: 0,\r\n fontSize: 12,\r\n lineHeight: '18px',\r\n color: 'var(--dsw-alias-label-tertiary)',\r\n}\r\n\r\nconst SWITCH_STYLE: CSSProperties = { flexShrink: 0, margin: 0, cursor: 'pointer' }\r\n\r\n/**\r\n * One switch row: label + hint on the left, checkbox on the right. Extracted\r\n * because the card now binds two sections (session recall / pinned slots).\r\n */\r\nfunction FlagRow(props: {\r\n id: string\r\n label: string\r\n hint: string\r\n checked: boolean\r\n disabled: boolean\r\n onToggle(next: boolean): void\r\n}): ReactNode {\r\n return createElement(\r\n 'div',\r\n { style: ROW_STYLE },\r\n createElement(\r\n 'div',\r\n { style: ROW_TEXT_STYLE },\r\n createElement('label', { htmlFor: props.id, style: LABEL_STYLE }, props.label),\r\n createElement('p', { style: HINT_STYLE }, props.hint),\r\n ),\r\n createElement('input', {\r\n id: props.id,\r\n type: 'checkbox',\r\n checked: props.checked,\r\n disabled: props.disabled,\r\n style: SWITCH_STYLE,\r\n onChange: (event: ChangeEvent<HTMLInputElement>) => { props.onToggle(event.currentTarget.checked) },\r\n }),\r\n )\r\n}\r\n\r\n/**\r\n * The settings card body. `scope` is optional on purpose: the inject factory\r\n * always provides it, but a host whose `configForms` face degrades must not\r\n * crash the settings page — the card renders the unavailable note and keeps\r\n * its header.\r\n */\r\nexport function BriefSettingsCard(props: BriefSettingsCardProps): ReactNode {\r\n const { t, scope } = props\r\n const [open, setOpen] = useState(true)\r\n\r\n const snapshot: SettingsScopeSnapshot<BriefClientConfig> | undefined = useSyncExternalStore(\r\n useCallback((listener: () => void) => scope?.subscribe(listener) ?? NO_SUBSCRIBE(), [scope]),\r\n useCallback(() => scope?.getSnapshot() ?? ABSENT, [scope]),\r\n useCallback(() => scope?.getSnapshot() ?? ABSENT, [scope]),\r\n )\r\n const unavailable = scope === undefined || snapshot.status === 'unavailable'\r\n const readonly = unavailable || !snapshot.writable\r\n // Defaults come from the same resolvers the sections use — one source of truth.\r\n const slotsChecked = resolveShowMemorySlots(snapshot)\r\n const recallChecked = resolveShowMemoryRecall(snapshot)\r\n\r\n return createElement(\r\n 'div',\r\n { style: CARD_STYLE, 'data-dsh-brief-sidebar': 'settings-card' },\r\n createElement(\r\n 'button',\r\n { type: 'button', 'aria-expanded': open, style: HEADER_STYLE, onClick: () => { setOpen(current => !current) } },\r\n createElement(\r\n 'span',\r\n { style: HEADER_TEXT_STYLE },\r\n createElement('div', { style: NAME_STYLE }, t('settings.title')),\r\n createElement('div', { style: DESC_STYLE }, t('settings.desc')),\r\n ),\r\n createElement(\r\n 'svg',\r\n { width: 16, height: 16, viewBox: '0 0 16 16', 'aria-hidden': true, style: CHEVRON_STYLE(open) },\r\n createElement('path', {\r\n d: 'M4 6l4 4 4-4',\r\n fill: 'none',\r\n stroke: 'currentColor',\r\n strokeWidth: 1.5,\r\n strokeLinecap: 'round',\r\n strokeLinejoin: 'round',\r\n }),\r\n ),\r\n ),\r\n open && createElement(\r\n 'div',\r\n { style: BODY_STYLE },\r\n unavailable\r\n ? createElement('p', { style: HINT_STYLE }, t('settings.unavailable'))\r\n : createElement(\r\n 'div',\r\n { style: { display: 'flex', flexDirection: 'column', gap: 12 } },\r\n createElement(FlagRow, {\r\n key: 'recall',\r\n id: 'dsh-brief-sidebar-show-memory-recall',\r\n label: t('settings.memoryRecall'),\r\n hint: t('settings.memoryRecallHint'),\r\n checked: recallChecked,\r\n disabled: readonly,\r\n onToggle: (next: boolean) => { void scope?.set('showMemoryRecall', next) },\r\n }),\r\n createElement(FlagRow, {\r\n key: 'slots',\r\n id: 'dsh-brief-sidebar-show-memory-slots',\r\n label: t('settings.memorySlots'),\r\n hint: t('settings.memorySlotsHint'),\r\n checked: slotsChecked,\r\n disabled: readonly,\r\n onToggle: (next: boolean) => { void scope?.set('showMemorySlots', next) },\r\n }),\r\n ),\r\n !unavailable && !snapshot.writable && createElement('p', { style: HINT_STYLE }, t('settings.readonly')),\r\n ),\r\n )\r\n}\r\n","/**\r\n * Browser half: the task board tab, plus the shadow that hides the official\r\n * composer-band todo panel.\r\n *\r\n * Registration order matters and is deliberate:\r\n *\r\n * 1. **Dictionaries first.** Every later registration can render translated\r\n * copy, and a dictionary that lands after the first paint would show raw\r\n * keys for a frame.\r\n * 2. **Sidebar surface, deferred.** The board needs a sidebar to live in:\r\n * better-sidebar when it is installed (richer: badge + rail icon), else the\r\n * host's own right-sidebar tab system (0.1.5+ `sidebarRightTabs` +\r\n * `sidebar.right.pane.tab`). Both are acquired through the deferred\r\n * `ctx.inject` because neither service is ordered against this apply —\r\n * an immediate `ctx.get` was the 0.1.2 inert bug. With neither — ≤0.1.2\r\n * hosts without better-sidebar — the plugin stays sidebar-inert: the\r\n * official panel keeps rendering and the shadow never installs.\r\n * 3. **Shadow the official dock.** Deliberately BEFORE the tab registration:\r\n * the panel is the only other carrier of the list, so the replacement has to\r\n * exist in the same activation.\r\n * 4. **Register the tab.**\r\n * 5. **Register the settings cards.** The memory-section switch gets TWO\r\n * faces from ONE component + ONE inject factory: a card in the plugin-family\r\n * settings section (「起子插件设置」, hosted by dsh-thinking-levels) and the\r\n * Plugins-page configuration card. `configForms` resolves through a\r\n * deferred inject (the service may start after apply — the same lateness\r\n * the composer model panel in dsh-thinking-levels guards against); on a\r\n * host without it the cards never register and the section gate falls back\r\n * to its default (on).\r\n *\r\n * Every registration rides `ctx.effect(fn, label)` so its disposer is revoked on\r\n * fiber teardown (HMR / disable), which is also what makes the shadow\r\n * reversible: unload the plugin and the official dock renders again. The\r\n * settings cards are the family-proven exception: they ride the deferred\r\n * `configForms` inject whose disposers are not held (same as\r\n * dsh-thinking-levels' composer panel registration).\r\n *\r\n * Contract notes for the two surfaces touched here:\r\n * - better-sidebar tabs are hosted by DSH's native right Sidebar, so the tab\r\n * body receives `TabComponentProps` (`ctx` + `scope` + `visible`) and NOT the\r\n * framework's session-scoped slot props.\r\n * - `conversation.input.dock` is the DSH slot the official todo panel occupies;\r\n * see `brief/dock-shadow.tsx` for why a lower priority wins the cell.\r\n */\r\nimport { createElement } from 'react'\r\nimport type { ReactNode } from 'react'\r\nimport type { Context } from '@deepseek-ai/cordis'\r\nimport type { BetterSidebarService, TabComponentProps } from 'dsh-better-sidebar/client/service'\r\nimport { registerNativeBoardTab } from './native-sidebar'\r\nimport type { NativeTabRegistryLike } from './native-sidebar'\r\nimport { SummaryTab } from './SummaryTab'\r\nimport { BriefIcon } from './BriefIcon'\r\nimport { NS, dictionaries } from './locales'\r\nimport { readTodos, unfinishedCount } from './brief/board'\r\nimport { registerTodoDockShadow } from './brief/dock-shadow'\r\nimport type { SlotsLike } from './brief/dock-shadow'\r\nimport { TODOS_KEY } from './brief/use-todos'\r\nimport { projectionSnapshot } from './use-projection'\r\nimport { BriefSettingsCard } from './settings-card'\r\nimport type { BriefSettingsCardProps } from './settings-card'\r\nimport type { BriefClientConfig, ConfigFormsLike } from './scope-face'\r\n\r\n/**\r\n * Tab type id. Package-prefixed so it cannot collide with a built-in type.\r\n * Unchanged since the 0.1.0 board tab: the summary tab REPLACES the board tab\r\n * in place, so an opened or pinned tab survives the upgrade.\r\n */\r\nexport const TAB_ID = 'dsh-brief-sidebar:board'\r\n\r\n/**\r\n * Tab kind on the native host-sidebar path (`openTab`/guide dispatch key).\r\n * Only the native registration uses it; better-sidebar keeps addressing the\r\n * tab by {@link TAB_ID}.\r\n */\r\nexport const TAB_KIND = 'brief-board'\r\n\r\n/**\r\n * Position in the host's new-tab guide.\r\n *\r\n * Built-ins on this host generation sit at editor 10 / git 20 / subagent 30 /\r\n * sidechat 35 / terminal 40 / browser 50. 15 places a per-session task board\r\n * right after the editor, which is where a reader looks for session state.\r\n */\r\nexport const TAB_ORDER = 15\r\n\r\n/** Services required before `apply` runs. */\r\n// Generation-neutral list only: betterSidebar/locale ride ctx.get soft-reads in\r\n// apply (both absent on 0.1.0/0.1.1 — declaring them pends the whole client\r\n// entry, web boot refuses to render; playbook §1).\r\n// betterSidebar 经 ctx.get 软读(缺席 inert);locale 全线 rc 皆在(0.1.0-rc.2 起)。\r\n// 第三方插件服务不入顶层 inject——缺席格 entry 永久 pending,web boot 拒渲染整树。\r\nexport const inject = ['slots', 'locale']\r\n\r\n/**\r\n * Structural view of the DSH locale service — only the two members this plugin\r\n * calls. Declared locally on purpose: importing the real type would pull the\r\n * whole client type graph into a browser-only plugin for two signatures.\r\n */\r\ninterface LocaleLike {\r\n register(ns: string, dicts: Record<string, Record<string, string>>): () => void\r\n bind(ns: string): (key: string) => string\r\n}\r\n\r\n/**\r\n * An effect body must return a disposer (cordis rejects `undefined` with a\r\n * `TypeError`), so a path that could not register anything returns this no-op\r\n * instead of nothing.\r\n */\r\nconst NOOP = (): void => {}\r\n\r\n/** Console prefix for the environment probe and registration attribution. */\r\nconst LOG = '[dsh-brief-sidebar]'\r\n\r\n/**\r\n * Run a registration thunk, attributing a thrown failure to the console\r\n * instead of the cordis effect void (a bare throw inside `ctx.effect` leaves\r\n * the field reader with an empty sidebar and no clue which arm died).\r\n */\r\nfunction guarded(label: string, run: () => (() => void) | undefined | void): () => void {\r\n try {\r\n const dispose = run()\r\n return typeof dispose === 'function' ? (dispose as () => void) : NOOP\r\n } catch (error) {\r\n console.error(`${LOG} ${label} failed`, error)\r\n return NOOP\r\n }\r\n}\r\n\r\n/**\r\n * Browser-face apply.\r\n *\r\n * @param ctx - the client root context.\r\n */\r\nexport function apply(ctx: Context): void {\r\n // 1. Plugin-owned dictionaries, in one registration.\r\n const locale: LocaleLike | undefined = ctx.get('locale')\r\n if (locale !== undefined) {\r\n ctx.effect(() => locale.register(NS, dictionaries), 'dsh-brief-sidebar: dictionaries')\r\n }\r\n\r\n /**\r\n * Translate one of our keys. `bind` returns a cached function that reads the\r\n * ACTIVE locale at call time, so a language switch needs no re-apply; an\r\n * unknown namespace or key falls back to the key itself rather than throwing\r\n * inside a render.\r\n */\r\n const t = (key: string): string => {\r\n if (locale === undefined) return key\r\n try {\r\n return locale.bind(NS)(key) || key\r\n } catch {\r\n return key\r\n }\r\n }\r\n\r\n // 2. Sidebar surface, acquired DEFERRED. better-sidebar is a third-party\r\n // plugin with no ordering guarantee against us, and the native tab\r\n // registry is a host service that can publish after this apply too — an\r\n // immediate `ctx.get` misses either one and stays inert forever (the\r\n // 0.1.2 field failure). Both arms ride the deferred optional\r\n // `ctx.inject` (the browser-cdp / configForms precedent). The host\r\n // registry usually wins the race on 0.1.5+ (it publishes before the\r\n // third-party sidebar), so the state is NOT a one-shot latch: when\r\n // better-sidebar arrives after a native seat, it HANDS OVER — the\r\n // native registration is released and the board re-seats on the bar,\r\n // which is the rail and manager the user actually sees (the 0.1.5\r\n // \"invisible tab\" failure was a native seat under a sidebar UI that\r\n // replaced the official rail). On a bare native host (0.1.7 farm cell)\r\n // no handover ever fires.\r\n let surface: 'none' | 'bar' | 'native' = 'none'\r\n let shadowDone = false\r\n let nativeDisposer: (() => void) | undefined\r\n\r\n /** Hide the official composer-band panel (reversible on unload), once. */\r\n const shadowDock = (): void => {\r\n if (shadowDone) return\r\n shadowDone = true\r\n ctx.effect(() => registerTodoDockShadow(ctx) ?? NOOP, 'dsh-brief-sidebar: dock shadow')\r\n }\r\n\r\n const registerOnBar = (bar: BetterSidebarService): void => {\r\n if (surface === 'bar') return\r\n if (surface === 'native') {\r\n const release = nativeDisposer\r\n nativeDisposer = undefined\r\n try {\r\n release?.()\r\n } catch { /* a half-torn-down native seat must not block the handover */ }\r\n console.info(`${LOG} surface=bar (handed over from native)`)\r\n } else {\r\n console.info(`${LOG} surface=bar`)\r\n }\r\n surface = 'bar'\r\n shadowDock()\r\n ctx.effect(\r\n () =>\r\n guarded('registerTab', () =>\r\n bar.registerTab({\r\n id: TAB_ID,\r\n title: () => t('tab.title'),\r\n description: () => t('tab.desc'),\r\n icon: (size: number) => BriefIcon(size),\r\n order: TAB_ORDER,\r\n // Shorthand for `dedupeKey: () => id`: reopening focuses the existing tab.\r\n single: true,\r\n /**\r\n * Unfinished count on the tab strip. Called on every tab-bar render, so\r\n * it reads one snapshot and allocates no subscription; a completed list\r\n * shows no badge at all.\r\n */\r\n badge: (badgeCtx, badgeScope) => {\r\n const todos = readTodos(projectionSnapshot(badgeCtx, badgeScope.sessionId, TODOS_KEY))\r\n if (todos === undefined) return null\r\n const pending = unfinishedCount(todos)\r\n return pending > 0 ? pending : null\r\n },\r\n component: (props: TabComponentProps) =>\r\n createElement(SummaryTab, {\r\n t,\r\n ctx: props.ctx,\r\n scope: props.scope,\r\n visible: props.visible,\r\n }),\r\n }),\r\n ),\r\n 'dsh-brief-sidebar: tab',\r\n )\r\n }\r\n\r\n const registerOnNative = (registry: NativeTabRegistryLike | undefined): void => {\r\n if (surface !== 'none') return\r\n surface = 'native'\r\n console.info(`${LOG} surface=native`)\r\n shadowDock()\r\n ctx.effect(\r\n () => {\r\n nativeDisposer = guarded('native tab', () => registerNativeBoardTab(ctx, registry, { id: TAB_ID, kind: TAB_KIND, order: TAB_ORDER, t }))\r\n return () => {\r\n nativeDisposer = undefined\r\n }\r\n },\r\n 'dsh-brief-sidebar: native tab',\r\n )\r\n }\r\n\r\n // Arm 1: better-sidebar, immediate read first (the common case where the\r\n // sidebar started before us), deferred retry otherwise.\r\n let bar: BetterSidebarService | undefined\r\n try {\r\n bar = ctx.get('betterSidebar')\r\n } catch {\r\n bar = undefined\r\n }\r\n if (bar !== undefined) {\r\n registerOnBar(bar)\r\n } else {\r\n ;(ctx as unknown as {\r\n inject: (deps: string[], cb: (scope: { betterSidebar?: BetterSidebarService }) => void) => void\r\n }).inject(['betterSidebar'], (scope) => {\r\n if (scope.betterSidebar !== undefined) registerOnBar(scope.betterSidebar)\r\n })\r\n }\r\n\r\n // Arm 2: the host's own tab registry (0.1.5+). Never fires on ≤0.1.2. The\r\n // registry is read from the INJECTED scope — a root ctx.get of this\r\n // undeclared service is denied by the strict proxy (the 0.1.7 silent no-op).\r\n ;(ctx as unknown as {\r\n inject: (deps: string[], cb: (scope: { sidebarRightTabs?: NativeTabRegistryLike }) => void) => void\r\n }).inject(['sidebarRightTabs'], (scope) => {\r\n registerOnNative(scope.sidebarRightTabs)\r\n })\r\n\r\n // 5. The settings cards (see the module doc): ONE component + ONE inject\r\n // factory at TWO seats. The entry ids follow the family convention —\r\n // `dsh-family.tab` contributors key by short id (session-guard →\r\n // 'session-guard'), `plugins.bundle.config` keys by package name.\r\n // `configForms` rides a deferred inject: the service lives in the\r\n // settings module, which may start after this apply; the callback simply\r\n // never fires on a host without it (the gate then reads its default).\r\n const slots = ctx.get('slots') as SlotsLike | undefined\r\n ;(ctx as unknown as {\r\n inject: (deps: string[], cb: (scope: { configForms?: ConfigFormsLike }) => void) => void\r\n }).inject(['configForms'], (scope) => {\r\n const configForms = scope.configForms\r\n if (slots === undefined || configForms === undefined || typeof configForms.get !== 'function') return\r\n\r\n /** Same face for both seats: the entry scope plus the applied-time binder. */\r\n const injectFactory = (): BriefSettingsCardProps => ({\r\n t,\r\n scope: configForms.get<BriefClientConfig>('dsh-brief-sidebar'),\r\n })\r\n /** The slot core hands the component `unknown` props (registry typing). */\r\n const component = BriefSettingsCard as unknown as (props: unknown) => ReactNode\r\n\r\n slots.inject('dsh-family.tab', () =>\r\n slots.register(\r\n {\r\n name: 'dsh-family.tab',\r\n id: 'brief-sidebar',\r\n order: 30,\r\n label: () => t('settings.title'),\r\n inject: injectFactory,\r\n },\r\n component,\r\n ),\r\n )\r\n slots.inject('plugins.bundle.config', () =>\r\n slots.register(\r\n {\r\n name: 'plugins.bundle.config',\r\n key: 'dsh-brief-sidebar',\r\n inject: injectFactory,\r\n },\r\n component,\r\n ),\r\n )\r\n })\r\n\r\n // One-line environment snapshot: what this apply could see at mount time.\r\n // Cross-reference with the `surface=` line to tell \"arm never fired\" from\r\n // \"arm fired and registration threw\" (guarded logs that part).\r\n try {\r\n let nativeTabsAtApply = false\r\n try {\r\n nativeTabsAtApply = ctx.get('sidebarRightTabs') !== undefined\r\n } catch {\r\n nativeTabsAtApply = false /* strict proxy denies the undeclared read */\r\n }\r\n console.info(`${LOG} env ${JSON.stringify({\r\n locale: locale !== undefined,\r\n barAtApply: bar !== undefined,\r\n nativeTabsAtApply,\r\n })}`)\r\n } catch { /* console may be absent in a stripped host */ }\r\n}\r\n"],"mappings":"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"}
1
+ {"version":3,"file":"client.js","names":["STATUS_KEY","NO_SUBSCRIBE","ABSENT","useMemo","useCallback","useSyncExternalStore","useMemo","SECTION_STYLE","HEADER_STYLE","LIST_STYLE","ROW_STYLE","createElement","CHEVRON_STYLE","createElement","SECTION_STYLE","HEADER_STYLE","LIST_STYLE","ROW_STYLE","TAG_STYLE","createElement","useState","isCounter","SECTION_STYLE","HEADER_STYLE","LIST_STYLE","ROW_STYLE","NAME_STYLE","FOOTER_STYLE","EMPTY_STYLE","useState","createElement","isCounter","NO_SUBSCRIBE","useMemo","useCallback","useSyncExternalStore","SECTION_STYLE","HEADER_STYLE","LIST_STYLE","ROW_STYLE","TITLE_STYLE","META_STYLE","BODY_STYLE","EMPTY_STYLE","createElement","TYPE_STYLE","BODY_STYLE","SCENARIO_STYLE","FOOTER_STYLE","createElement","HEADER_STYLE","HINT_STYLE","ROW_STYLE","createElement","useState","useRef","useCallback","createElement","createElement","useState","useSyncExternalStore","useCallback","createElement"],"sources":["../src/client/brief/board.ts","../src/client/use-projection.ts","../src/client/brief/use-todos.ts","../src/client/TodoBoardTab.tsx","../src/projection/keys.ts","../src/client/file-open.ts","../src/client/summary/deliverables.ts","../src/client/summary/FoldToggle.tsx","../src/client/locales.ts","../src/client/summary/DeliverablesSection.tsx","../src/client/summary/skill-usage.ts","../src/client/summary/SkillUsageSection.tsx","../src/client/summary/memory-slots.ts","../src/client/scope-face.ts","../src/client/summary/use-config-flag.ts","../src/client/summary/MemorySlotsSection.tsx","../src/client/summary/memory-recall.ts","../src/client/summary/recall-feedback.ts","../src/client/summary/RecallBubble.tsx","../src/client/summary/MemoryRecallSection.tsx","../src/client/SummaryTab.tsx","../src/client/native-sidebar.tsx","../src/client/BriefIcon.tsx","../src/client/brief/dock-shadow.tsx","../src/client/settings-card.tsx","../src/client/index.tsx"],"sourcesContent":["/**\r\n * The `todos` projection — reading and classifying it.\r\n *\r\n * The Host computes this projection (`dsh-tool-todo` registers the key) and\r\n * pushes finished whole values; the client never folds it. This module is the\r\n * read side of that contract and is deliberately PURE — no React, no context,\r\n * no IO — so the mapping can be tested directly.\r\n */\r\n/** The projection's three-state lifecycle (`TodoItem` in `dsh-tool-todo`). */\r\nexport type TodoStatus = 'pending' | 'in_progress' | 'completed'\r\n\r\n/** One entry of the `todos` projection. */\r\nexport interface TodoItem {\r\n readonly content: string\r\n readonly status: TodoStatus\r\n}\r\n\r\nconst STATUSES: readonly TodoStatus[] = ['pending', 'in_progress', 'completed']\r\n\r\n/** Locale key per status. Kept here so this module owns the vocabulary. */\r\nconst STATUS_KEY: Record<TodoStatus, string> = {\r\n pending: 'status.pending',\r\n in_progress: 'status.inProgress',\r\n completed: 'status.completed',\r\n}\r\n\r\n/** Locale key for one status label. */\r\nexport function statusKey(status: TodoStatus): string {\r\n return STATUS_KEY[status]\r\n}\r\n\r\n/**\r\n * Narrow a raw projection value into a todo list.\r\n *\r\n * Three outcomes are kept apart on purpose, mirroring the store's own contract:\r\n * - `undefined` — the capability is ABSENT (no session, the host unit is\r\n * unmounted, or no baseline/frame has carried the key yet);\r\n * - `[]` — the projection is present and the list is empty (`null` on the wire);\r\n * - a list — real entries.\r\n *\r\n * A malformed entry is dropped rather than thrown on: the projection is a\r\n * trusted Host value, but a shape drift must not blank the whole board.\r\n *\r\n * @param value - the raw `unknown` snapshot of the `todos` face.\r\n * @returns the validated list, or `undefined` when the capability is absent.\r\n */\r\nexport function readTodos(value: unknown): readonly TodoItem[] | undefined {\r\n if (value === null) return []\r\n if (!Array.isArray(value)) return undefined\r\n\r\n const items: TodoItem[] = []\r\n for (const raw of value) {\r\n if (raw === null || typeof raw !== 'object') continue\r\n const { content, status } = raw as { content?: unknown; status?: unknown }\r\n if (typeof content !== 'string') continue\r\n if (typeof status !== 'string' || !isStatus(status)) continue\r\n items.push({ content, status })\r\n }\r\n return items\r\n}\r\n\r\n/** Whether a string is one of the three lifecycle values. */\r\nfunction isStatus(value: string): value is TodoStatus {\r\n return (STATUSES as readonly string[]).includes(value)\r\n}\r\n\r\n/** Per-status counts over one list. */\r\nexport interface TodoCounts {\r\n readonly total: number\r\n readonly completed: number\r\n readonly inProgress: number\r\n readonly pending: number\r\n}\r\n\r\n/** Count a todo list by status. */\r\nexport function countTodos(todos: readonly TodoItem[]): TodoCounts {\r\n let completed = 0\r\n let inProgress = 0\r\n let pending = 0\r\n for (const item of todos) {\r\n if (item.status === 'completed') completed += 1\r\n else if (item.status === 'in_progress') inProgress += 1\r\n else pending += 1\r\n }\r\n return { total: todos.length, completed, inProgress, pending }\r\n}\r\n\r\n/** How many entries are not finished — the tab badge. */\r\nexport function unfinishedCount(todos: readonly TodoItem[]): number {\r\n const counts = countTodos(todos)\r\n return counts.inProgress + counts.pending\r\n}\r\n\r\n/**\r\n * The one-line progress summary, composed from parts so no interpolation\r\n * machinery is needed (the locale binder is a plain key → string lookup).\r\n * Mirrors the official dock's own label.\r\n */\r\nexport function progressLine(counts: TodoCounts, t: (key: string) => string): string {\r\n const parts = [`${t('status.completed')} ${counts.completed}/${counts.total}`]\r\n if (counts.inProgress > 0) parts.push(`${t('status.inProgress')} ${counts.inProgress}`)\r\n if (counts.pending > 0) parts.push(`${t('status.pending')} ${counts.pending}`)\r\n return parts.join(' · ')\r\n}\r\n","/**\r\n * Reading a live session projection from the client Session Controller.\r\n *\r\n * better-sidebar tab bodies are NOT rendered inside a DSH slot, so the\r\n * framework's `useProjection` standard prop is not available to them. The\r\n * equivalent face is reachable directly: the client Session Controller is a\r\n * cordis service on the root context, and each session binding exposes its\r\n * projections store (`SessionFace.projections.faceOf(key)`), which is the very\r\n * observable `useProjection` resolves. Since it is a bare\r\n * `{ getSnapshot, subscribe }` source, `useSyncExternalStore` binds it as-is —\r\n * no local mirror, no folding, and the value reference only changes when the\r\n * Host pushes a frame.\r\n *\r\n * Everything here is resolved defensively: a host without the Session\r\n * Controller, or a session that is not open any more, degrades to \"capability\r\n * absent\" (undefined) rather than throwing inside a render.\r\n *\r\n * This module is key-agnostic; the per-projection knowledge (which key, how to\r\n * narrow the raw value) lives with the feature modules that call it.\r\n */\r\nimport { useCallback, useMemo, useSyncExternalStore } from 'react'\r\nimport type { Context } from '@deepseek-ai/cordis'\r\n\r\n/** Structural view of a projection face (`ObservableSnapshot<unknown>`). */\r\nexport interface ProjectionFace {\r\n getSnapshot(): unknown\r\n subscribe(listener: () => void): () => void\r\n}\r\n\r\n/** Structural view of one session binding's projection store. */\r\nexport interface ProjectionsLike {\r\n faceOf(key: string): ProjectionFace\r\n}\r\n\r\n/** Structural view of the client Session Controller face this plugin uses. */\r\nexport interface SessionsLike {\r\n binding(id: string): { readonly session: { readonly projections: ProjectionsLike } } | undefined\r\n}\r\n\r\n/** A no-op unsubscribe, kept as one identity so effects never thrash. */\r\nconst NO_SUBSCRIBE = (): void => {}\r\n\r\n/** A source that never has a value — the absent-capability face. */\r\nconst ABSENT: ProjectionFace = { getSnapshot: () => undefined, subscribe: () => NO_SUBSCRIBE }\r\n\r\n/**\r\n * Whether a value really is a projection face.\r\n *\r\n * The store contract promises an identity-stable face for every key, so this\r\n * never fires against a healthy host. It exists because the fallback is worse\r\n * than the check: `useSyncExternalStore` would throw on a face-less key, and a\r\n * thrown render is a blank sidebar rather than a diagnosable \"unavailable\".\r\n */\r\nfunction isFace(value: unknown): value is ProjectionFace {\r\n if (value === null || typeof value !== 'object') return false\r\n const face = value as Partial<ProjectionFace>\r\n return typeof face.getSnapshot === 'function' && typeof face.subscribe === 'function'\r\n}\r\n\r\n/**\r\n * Resolve one projection face for one session.\r\n *\r\n * `ctx.get('sessions')` is the safe accessor (a direct `ctx.sessions` read can\r\n * throw on a context that does not carry the service yet).\r\n *\r\n * @param ctx - the client root context handed to the tab body.\r\n * @param sessionId - the tab's session scope; undefined means \"no session\".\r\n * @param key - the projection key to resolve.\r\n * @returns the projection face, or {@link ABSENT} when unreachable.\r\n */\r\nexport function resolveFace(ctx: Context | undefined, sessionId: string | undefined, key: string): ProjectionFace {\r\n if (ctx === undefined || sessionId === undefined) return ABSENT\r\n const sessions = ctx.get('sessions') as SessionsLike | undefined\r\n if (sessions === undefined || typeof sessions.binding !== 'function') return ABSENT\r\n\r\n const binding = sessions.binding(sessionId)\r\n const projections = binding?.session?.projections\r\n if (projections === undefined || typeof projections.faceOf !== 'function') return ABSENT\r\n\r\n const face: unknown = projections.faceOf(key)\r\n return isFace(face) ? face : ABSENT\r\n}\r\n\r\n/**\r\n * Read one frame of a projection without subscribing.\r\n *\r\n * The one-shot sibling of {@link useProjectionValue}, for consumers that are\r\n * not React components — the tab badge is a plain function called on every\r\n * tab-bar render, so it must neither hold a subscription nor allocate one.\r\n *\r\n * @param ctx - the client root context.\r\n * @param sessionId - the session whose projection is read.\r\n * @param key - the projection key to read.\r\n * @returns the raw snapshot: `undefined` while the capability is absent; the\r\n * semantics of any other value belong to the projection's own contract.\r\n */\r\nexport function projectionSnapshot(ctx: Context | undefined, sessionId: string | undefined, key: string): unknown {\r\n return resolveFace(ctx, sessionId, key).getSnapshot()\r\n}\r\n\r\n/**\r\n * Subscribe to one session projection by key.\r\n *\r\n * @param ctx - the client root context.\r\n * @param sessionId - the session whose projection is shown.\r\n * @param key - the projection key to subscribe to.\r\n * @returns the raw snapshot value, identity-stable across frames the host did\r\n * not change. Narrowing is the caller's job.\r\n */\r\nexport function useProjectionValue(ctx: Context | undefined, sessionId: string | undefined, key: string): unknown {\r\n const face = useMemo(() => resolveFace(ctx, sessionId, key), [ctx, sessionId, key])\r\n\r\n const subscribe = useCallback((listener: () => void) => face.subscribe(listener), [face])\r\n const getSnapshot = useCallback(() => face.getSnapshot(), [face])\r\n\r\n return useSyncExternalStore(subscribe, getSnapshot, getSnapshot)\r\n}\r\n","/**\r\n * Reading the live `todos` projection — the thin, todo-specific wrapper around\r\n * the generic face resolver (`../use-projection`). The projection key is\r\n * registered by `dsh-tool-todo`; the host pushes finished whole values and the\r\n * client never folds it. Narrowing lives in `./board` (`readTodos`).\r\n */\r\nimport { useMemo } from 'react'\r\nimport type { Context } from '@deepseek-ai/cordis'\r\nimport { readTodos } from './board'\r\nimport type { TodoItem } from './board'\r\nimport { useProjectionValue } from '../use-projection'\r\n\r\n/** The projection key registered by `dsh-tool-todo`. */\r\nexport const TODOS_KEY = 'todos'\r\n\r\n/**\r\n * Subscribe to one session's todo list.\r\n *\r\n * @param ctx - the client root context.\r\n * @param sessionId - the session whose projection is shown.\r\n * @returns the list, `[]` for a present-but-empty projection, or `undefined`\r\n * while the capability is absent.\r\n */\r\nexport function useTodos(ctx: Context | undefined, sessionId: string | undefined): readonly TodoItem[] | undefined {\r\n const raw = useProjectionValue(ctx, sessionId, TODOS_KEY)\r\n return useMemo(() => readTodos(raw), [raw])\r\n}\r\n","/**\r\n * The progress section: the `todos` projection drawn as one part of the\r\n * summary tab.\r\n *\r\n * The official composer-band panel is shadowed by this plugin (see\r\n * `brief/dock-shadow.tsx`), so the projection is read here and rendered as an\r\n * ordinary React view — no Canvas, no cross-package dependency. The full-height\r\n * shell and the scroll container live on the summary tab (`../SummaryTab`);\r\n * this component renders only its own slice and is the one section whose\r\n * absent state must stay VISIBLE: the official dock is hidden while this\r\n * plugin is mounted, so \"unavailable\" is a statement the reader needs.\r\n *\r\n * Colours come from `--dsw-alias-*` tokens only (skin contract), and the status\r\n * palette uses tokens that actually exist in the shipping theme:\r\n * `state-success-primary` / `state-business-primary` / `label-tertiary`.\r\n */\r\nimport { createElement } from 'react'\r\nimport type { CSSProperties, ReactNode } from 'react'\r\nimport type { Context } from '@deepseek-ai/cordis'\r\nimport { countTodos, progressLine, statusKey } from './brief/board'\r\nimport type { TodoItem, TodoStatus } from './brief/board'\r\nimport { useTodos } from './brief/use-todos'\r\n\r\n/** The session scope better-sidebar hands a tab body. */\r\nexport interface TodoScope {\r\n readonly sessionId?: string\r\n}\r\n\r\nexport interface TodoSectionProps {\r\n /** The DSH locale lookup, passed down from `apply`. */\r\n t: (key: string) => string\r\n /** The client root context (the tab body's only way to reach services). */\r\n ctx?: Context\r\n /** The session this tab is scoped to. */\r\n scope?: TodoScope\r\n}\r\n\r\n/** Status → token colour for the pill's text and border. */\r\nconst STATUS_COLOR: Record<TodoStatus, string> = {\r\n completed: 'var(--dsw-alias-state-success-primary)',\r\n in_progress: 'var(--dsw-alias-state-business-primary)',\r\n pending: 'var(--dsw-alias-label-tertiary)',\r\n}\r\n\r\nconst SECTION_STYLE: CSSProperties = {\r\n flexShrink: 0,\r\n borderBottom: '1px solid var(--dsw-alias-border-secondary)',\r\n}\r\n\r\nconst HEADER_STYLE: CSSProperties = {\r\n padding: '10px 12px 0',\r\n color: 'var(--dsw-alias-label-secondary)',\r\n fontSize: 12,\r\n fontWeight: 600,\r\n}\r\n\r\nconst PROGRESS_STYLE: CSSProperties = {\r\n padding: '6px 12px 10px',\r\n color: 'var(--dsw-alias-label-secondary)',\r\n fontSize: 12,\r\n}\r\n\r\nconst LIST_STYLE: CSSProperties = {\r\n listStyle: 'none',\r\n margin: 0,\r\n padding: '6px 0',\r\n display: 'flex',\r\n flexDirection: 'column',\r\n}\r\n\r\nconst ROW_STYLE: CSSProperties = {\r\n display: 'flex',\r\n alignItems: 'flex-start',\r\n gap: 8,\r\n padding: '6px 12px',\r\n}\r\n\r\n/** Pill style, coloured per status. */\r\nfunction pillStyle(status: TodoStatus): CSSProperties {\r\n return {\r\n flexShrink: 0,\r\n color: STATUS_COLOR[status],\r\n border: `1px solid ${STATUS_COLOR[status]}`,\r\n borderRadius: 999,\r\n padding: '0 6px',\r\n fontSize: 11,\r\n lineHeight: '16px',\r\n whiteSpace: 'nowrap',\r\n }\r\n}\r\n\r\n/** Task text: finished entries read as done, the working one as active. */\r\nfunction contentStyle(status: TodoStatus): CSSProperties {\r\n return {\r\n minWidth: 0,\r\n overflowWrap: 'anywhere',\r\n color:\r\n status === 'completed'\r\n ? 'var(--dsw-alias-label-tertiary)'\r\n : status === 'in_progress'\r\n ? 'var(--dsw-alias-label-primary)'\r\n : 'var(--dsw-alias-label-secondary)',\r\n textDecoration: status === 'completed' ? 'line-through' : 'none',\r\n }\r\n}\r\n\r\n/** Centred message block used by every non-list state. */\r\nexport function Notice(props: { title: string; detail?: string }): ReactNode {\r\n return (\r\n <div\r\n style={{\r\n margin: '0 auto',\r\n padding: 24,\r\n maxWidth: 460,\r\n textAlign: 'center',\r\n color: 'var(--dsw-alias-label-tertiary)',\r\n lineHeight: 1.7,\r\n fontSize: 12,\r\n }}\r\n >\r\n <div style={{ marginBottom: 6, color: 'var(--dsw-alias-label-secondary)' }}>{props.title}</div>\r\n {props.detail === undefined ? null : <div>{props.detail}</div>}\r\n </div>\r\n )\r\n}\r\n\r\n/** One task row. */\r\nfunction TodoRow(props: { item: TodoItem; t: (key: string) => string }): ReactNode {\r\n const { item, t } = props\r\n return createElement(\r\n 'li',\r\n { style: ROW_STYLE },\r\n createElement('span', { style: pillStyle(item.status) }, t(statusKey(item.status))),\r\n createElement('span', { style: contentStyle(item.status) }, item.content),\r\n )\r\n}\r\n\r\n/**\r\n * The progress section. The subscription is unconditional (a plain listener,\r\n * not IO); the three-state contract of the projection is preserved verbatim.\r\n * @param props - translation, client context, session scope.\r\n */\r\nexport function TodoSection(props: TodoSectionProps): ReactNode {\r\n const { t, ctx, scope } = props\r\n\r\n const todos = useTodos(ctx, scope?.sessionId)\r\n\r\n if (todos === undefined) {\r\n // `undefined` is the store's \"capability absent\": no session, or the host's\r\n // todo unit is unmounted. Say so rather than showing an empty board.\r\n return createElement(\r\n 'div',\r\n { style: SECTION_STYLE, 'data-dsh-brief-sidebar': 'progress-section' },\r\n createElement('div', { style: HEADER_STYLE }, t('section.progress')),\r\n createElement(Notice, { title: t('board.unavailable'), detail: t('board.unavailableHint') }),\r\n )\r\n }\r\n\r\n if (todos.length === 0) {\r\n return createElement(\r\n 'div',\r\n { style: SECTION_STYLE, 'data-dsh-brief-sidebar': 'progress-section' },\r\n createElement('div', { style: HEADER_STYLE }, t('section.progress')),\r\n createElement(Notice, { title: t('board.empty'), detail: t('board.emptyHint') }),\r\n )\r\n }\r\n\r\n const counts = countTodos(todos)\r\n\r\n return createElement(\r\n 'div',\r\n { style: SECTION_STYLE, 'data-dsh-brief-sidebar': 'progress-section' },\r\n createElement('div', { style: HEADER_STYLE }, t('section.progress')),\r\n createElement('div', { style: PROGRESS_STYLE }, progressLine(counts, t)),\r\n createElement(\r\n 'ul',\r\n { style: LIST_STYLE },\r\n todos.map((item, index) => createElement(TodoRow, { key: `${index}:${item.content}`, item, t })),\r\n ),\r\n )\r\n}\r\n\r\n/**\r\n * Backwards-compatible alias for the pre-summary export name. The component\r\n * no longer owns the full-height shell — that moved to `SummaryTab` — so the\r\n * alias exists only to keep import sites honest during the transition.\r\n */\r\nexport const TodoBoardTab = TodoSection\r\n","/**\r\n * The projection keys this plugin contributes to the session-projection\r\n * registry, and their wire views.\r\n *\r\n * The key is namespaced with the plugin name on purpose: the registry refuses\r\n * to share a key across differing `stateVersion`s, so a collision with a\r\n * future host-side deliverables unit would be a hard load error, not a silent\r\n * shadow. The view type is declared structurally (the plugin has no compile\r\n * dependency on `@deepseek-ai/dsh-session-projection`); the registry accepts\r\n * any string key at runtime.\r\n */\r\n\r\n/** The projection key registered by this plugin's host half. */\r\nexport const DELIVERABLES_KEY = 'dshSummaryDeliverables'\r\n\r\n/**\r\n * The second key: which skills this session actually loaded (the host's `skill`\r\n * tool, read off `tool/call.arguments`). Namespaced for the same reason as\r\n * {@link DELIVERABLES_KEY} — the registry hard-fails on a shared key with a\r\n * differing `stateVersion`, so a future host-side skill unit must not be able\r\n * to collide silently.\r\n */\r\nexport const SKILL_USAGE_KEY = 'dshSummarySkillUsage'\r\n\r\n/** Client view of the produced-file fold (JSON-safe). */\r\nexport interface DeliverablesView {\r\n /** Paths produced in the latest turn, first-seen order (capped). */\r\n readonly latest: {\r\n readonly turn: number\r\n readonly paths: readonly string[]\r\n } | null\r\n /** Distinct produced paths session-wide, most-recent-first (capped). */\r\n readonly sessionPaths: readonly string[]\r\n /** Distinct produced paths session-wide, uncapped — the truthful total. */\r\n readonly sessionTotal: number\r\n}\r\n\r\n/** One loaded skill in the wire view. */\r\nexport interface SkillUsageEntryView {\r\n /** The skill name exactly as the model passed it to the `skill` tool. */\r\n readonly name: string\r\n /** Successful loads of this skill this session. */\r\n readonly count: number\r\n /** Turn whose call last advanced this tally. */\r\n readonly lastTurn: number\r\n}\r\n\r\n/** Client view of the skill-usage fold (JSON-safe). */\r\nexport interface SkillUsageView {\r\n /** Skills referenced in the latest turn; `null` before the first `turn/start`. */\r\n readonly latest: { readonly turn: number; readonly names: readonly string[] } | null\r\n /** Distinct referenced skills, most recently used first (capped). */\r\n readonly session: readonly SkillUsageEntryView[]\r\n /** Distinct referenced skills session-wide — may exceed `session.length`. */\r\n readonly sessionTotal: number\r\n /** Successful references session-wide, both channels included. */\r\n readonly callTotal: number\r\n /**\r\n * The skills this session was OFFERED, per its latest catalog frame (capped).\r\n * Available is not referenced: the model may never use any of these.\r\n */\r\n readonly available: readonly string[]\r\n /** How many entries that frame published — may exceed `available.length`. */\r\n readonly availableCount: number\r\n}\r\n","/**\r\n * Opening a produced file's preview in the right Sidebar — the same channel\r\n * the conversation flow uses for its produced-file chips and inline mentions\r\n * (ui-chat `openFile` → `ctx.sidebarRight.openResource` with a\r\n * `dsh-resource://file/…` address).\r\n *\r\n * The address grammar is ported verbatim from the harness's browser-safe\r\n * `@deepseek-ai/dsh-util-workspace-path` (`file-address.ts` / `index.ts`),\r\n * because the plugin does not compile against that package: a relative path,\r\n * or an absolute path inside the session's workspace, is addressed under the\r\n * session's scope (`dsh-resource://file/session/<id>/<path>`); an absolute\r\n * path elsewhere keeps its absolute spelling in the same session's address.\r\n * Which tab type claims the address is the Sidebar's decision, not ours.\r\n *\r\n * The `sidebarRight` service is consumed structurally and treated as OPTIONAL:\r\n * where it is absent the section renders plain rows instead of links, the same\r\n * graceful degradation as the deliverables projection itself.\r\n */\r\nimport type { Context } from '@deepseek-ai/cordis'\r\n\r\n/** Structural view of the right-Sidebar service this plugin needs. */\r\nexport interface SidebarRightLike {\r\n openResource(url: string, options?: { params?: { line?: number } }): void\r\n}\r\n\r\n/** Structural view of the sessions service slice the opener reads. */\r\ninterface SessionsListLike {\r\n list?: { getSnapshot(): { byId?: Record<string, { cwd?: string }> } }\r\n}\r\n\r\n/** The address scheme every file resource opens with. */\r\nconst FILE_ADDRESS_PREFIX = 'dsh-resource://file/'\r\n\r\n/** Whether a path uses a Windows drive or UNC prefix. */\r\nfunction isWindowsStylePath(value: string): boolean {\r\n return /^[A-Za-z]:[/\\\\]/.test(value) || value.startsWith('\\\\\\\\')\r\n}\r\n\r\n/**\r\n * Whether a path is absolute in either spelling the Host accepts: POSIX (`/a/b`)\r\n * or Windows drive or UNC.\r\n */\r\nexport function isAbsoluteWorkspacePath(path: string): boolean {\r\n return path.startsWith('/') || isWindowsStylePath(path)\r\n}\r\n\r\n/** Component-encode one id or path segment, keeping `:` literal for drive letters. */\r\nfunction encodeSegment(segment: string): string {\r\n return encodeURIComponent(segment).replace(/%3A/gi, ':')\r\n}\r\n\r\n/** Encode a `/`-separated path segment by segment. */\r\nfunction encodePath(path: string): string {\r\n return path.split('/').map(encodeSegment).join('/')\r\n}\r\n\r\n/**\r\n * Build the address of a file read through one Session.\r\n * @param sessionId - the Session whose Host workspace resolves the path.\r\n * @param path - absolute or workspace-relative path; backslashes are normalized\r\n * to `/`, and leading `./` prefixes are dropped.\r\n */\r\nfunction sessionFileAddress(sessionId: string, path: string): string {\r\n const normalized = path.replace(/\\\\/g, '/').replace(/^(?:\\.\\/)+/, '')\r\n return `${FILE_ADDRESS_PREFIX}session/${encodeSegment(sessionId)}/${encodePath(normalized)}`\r\n}\r\n\r\n/**\r\n * The address for a path as a caller holds it.\r\n * @param sessionId - the Session the path is read in.\r\n * @param cwd - that Session's workspace root, when known.\r\n * @param path - absolute or workspace-relative path, in either separator spelling.\r\n */\r\nexport function fileAddressFor(sessionId: string, cwd: string | undefined, path: string): string {\r\n const normalized = path.replace(/\\\\/g, '/')\r\n if (!isAbsoluteWorkspacePath(normalized)) return sessionFileAddress(sessionId, normalized)\r\n const root = cwd === undefined ? '' : cwd.replace(/\\\\/g, '/').replace(/\\/+$/, '')\r\n if (root !== '' && normalized === root) return sessionFileAddress(sessionId, '')\r\n if (root !== '' && normalized.startsWith(`${root}/`)) {\r\n return sessionFileAddress(sessionId, normalized.slice(root.length + 1))\r\n }\r\n return sessionFileAddress(sessionId, normalized)\r\n}\r\n\r\n/**\r\n * Build a sidebar file opener for one session, or `undefined` when the\r\n * environment cannot open previews (no `sidebarRight` service, no session).\r\n * The cwd is re-read per call inside the opener, so a workspace switch between\r\n * renders is picked up on the next click.\r\n *\r\n * @param ctx - the client root context.\r\n * @param sessionId - the session whose workspace resolves paths.\r\n * @returns an opener that routes a produced path to the Sidebar preview.\r\n */\r\nexport function sidebarFileOpener(\r\n ctx: Context | undefined,\r\n sessionId: string | undefined,\r\n): ((path: string) => void) | undefined {\r\n if (ctx === undefined || sessionId === undefined) return undefined\r\n const bar = ctx.get('sidebarRight') as SidebarRightLike | undefined\r\n if (bar === undefined || typeof bar.openResource !== 'function') return undefined\r\n\r\n return (path: string) => {\r\n const sessions = ctx.get('sessions') as SessionsListLike | undefined\r\n const cwd = sessions?.list?.getSnapshot?.().byId?.[sessionId]?.cwd\r\n bar.openResource(fileAddressFor(sessionId, cwd, path))\r\n }\r\n}\r\n","/**\r\n * The `dshSummaryDeliverables` projection — reading and classifying it.\r\n *\r\n * The Host computes this projection (this plugin's own node half registers the\r\n * unit) and pushes finished whole values; the client never folds it. This\r\n * module is the read side of that contract and is deliberately PURE — no\r\n * React, no context, no IO — so the narrowing and the codeplan classification\r\n * can be tested directly.\r\n */\r\nimport type { DeliverablesView } from '../../projection/keys'\r\n\r\n/**\r\n * Narrow a raw projection value into a deliverables view.\r\n *\r\n * Two outcomes are kept apart on purpose, mirroring the store's contract:\r\n * - `undefined` — the capability is ABSENT (the host half never registered —\r\n * e.g. an older composition — or no frame carried the key yet);\r\n * - a view — the projection is live. A view with `latest: null` and\r\n * `sessionTotal: 0` IS the empty state; the fold starts publishing as soon\r\n * as the unit registers, so \"present but empty\" is a real value here, not a\r\n * sentinel.\r\n *\r\n * @param value - the raw `unknown` snapshot of the deliverables face.\r\n * @returns the validated view, or `undefined` when the capability is absent.\r\n */\r\nexport function readDeliverables(value: unknown): DeliverablesView | undefined {\r\n if (value === null || typeof value !== 'object' || Array.isArray(value)) return undefined\r\n const raw = value as { latest?: unknown; sessionPaths?: unknown; sessionTotal?: unknown }\r\n if (raw.latest === undefined || raw.sessionPaths === undefined || raw.sessionTotal === undefined) {\r\n return undefined\r\n }\r\n if (!isBucket(raw.latest) || !Array.isArray(raw.sessionPaths) || typeof raw.sessionTotal !== 'number') {\r\n return undefined\r\n }\r\n const paths = raw.sessionPaths.filter((path): path is string => typeof path === 'string')\r\n return {\r\n latest: raw.latest === null ? null : { turn: raw.latest.turn, paths: raw.latest.paths },\r\n sessionPaths: paths,\r\n sessionTotal: raw.sessionTotal,\r\n }\r\n}\r\n\r\n/** Whether a value is a well-formed latest-turn bucket (or explicitly null). */\r\nfunction isBucket(value: unknown): value is { turn: number; paths: readonly string[] } | null {\r\n if (value === null) return true\r\n if (typeof value !== 'object') return false\r\n const bucket = value as { turn?: unknown; paths?: unknown }\r\n return typeof bucket.turn === 'number' && Array.isArray(bucket.paths)\r\n}\r\n\r\n/**\r\n * The path prefix that identifies a codeplan artifact. The codeplan skill\r\n * writes its four fixed artifacts under `$workspace\\.agents\\plans\\<任务名>\\`;\r\n * produced paths may spell the separators either way.\r\n */\r\nconst CODEPLAN_SEGMENT = '.agents/plans/'\r\n\r\n/**\r\n * Normalize path separators so one spelling of the codeplan prefix matches.\r\n * Only classification uses this; the displayed path keeps the tool's exact\r\n * spelling.\r\n */\r\nfunction normalized(path: string): string {\r\n return path.replaceAll('\\\\', '/')\r\n}\r\n\r\n/** Whether a produced path is a codeplan artifact. */\r\nexport function isCodeplanPath(path: string): boolean {\r\n return normalized(path).includes(CODEPLAN_SEGMENT)\r\n}\r\n\r\n/**\r\n * Split a codeplan path into its task name and file name.\r\n *\r\n * @param path - a produced path; need not actually be a codeplan artifact.\r\n * @returns task and file names, or `null` when the path is not under the\r\n * codeplan plans directory (or names no file beneath the task folder).\r\n */\r\nexport function splitCodeplanPath(path: string): { task: string; file: string } | null {\r\n const marker = normalized(path).indexOf(CODEPLAN_SEGMENT)\r\n if (marker < 0) return null\r\n const rest = normalized(path).slice(marker + CODEPLAN_SEGMENT.length)\r\n const slash = rest.indexOf('/')\r\n if (slash <= 0 || slash === rest.length - 1) return null\r\n return { task: rest.slice(0, slash), file: rest.slice(slash + 1) }\r\n}\r\n\r\n/** The final path segment, under either separator. */\r\nexport function basename(path: string): string {\r\n const normalizedPath = normalized(path)\r\n const slash = normalizedPath.lastIndexOf('/')\r\n return slash < 0 ? normalizedPath : normalizedPath.slice(slash + 1)\r\n}\r\n\r\n/**\r\n * 历史文件 = 全会话去重路径 − 本回合活跃路径。\r\n *\r\n * 分隔符归一化后比较(`a\\b` 与 `a/b` 视为同一路径),保持 sessionPaths 自带的\r\n * \"最近在前\"顺序;活跃路径一个都不出现——分层契约:活跃的已在上方列表里,\r\n * 折叠区只收\"更早改过的文件\"。\r\n */\r\nexport function historyPaths(sessionPaths: readonly string[], latestPaths: readonly string[]): string[] {\r\n const active = new Set(latestPaths.map(normalized))\r\n return sessionPaths.filter((path) => !active.has(normalized(path)))\r\n}\r\n","/**\r\n * The two group chrome pieces the summary sections share: a counted group\r\n * title, and the toggle that folds a group away.\r\n *\r\n * Extracted because the deliverables section (本回合 / 更早改动) and the recall\r\n * section (活跃召回 / 其余历史召回) now fold a history group the same way. Two\r\n * private copies of the same button would drift the first time either section\r\n * touches padding — and the whole point of the split is that a reader can tell\r\n * \"what is live now\" from \"what the session also contains\" without learning a\r\n * different layout per section.\r\n *\r\n * Colours come from `--dsw-alias-*` tokens only (skin contract, enforced by\r\n * `tests/purity.spec.ts`).\r\n */\r\nimport { createElement } from 'react'\r\nimport type { CSSProperties, ReactNode } from 'react'\r\n\r\n/** Section-level title under the section header: quieter, same left gutter. */\r\nconst GROUP_HEADER_STYLE: CSSProperties = {\r\n padding: '8px 12px 0',\r\n color: 'var(--dsw-alias-label-tertiary)',\r\n fontSize: 11,\r\n fontWeight: 600,\r\n}\r\n\r\n/** The fold switch: full-width hit area, tertiary text, chevron at the end. */\r\nconst TOGGLE_STYLE: CSSProperties = {\r\n background: 'none',\r\n border: 'none',\r\n font: 'inherit',\r\n fontSize: 12,\r\n color: 'var(--dsw-alias-label-tertiary)',\r\n cursor: 'pointer',\r\n display: 'flex',\r\n alignItems: 'center',\r\n gap: 4,\r\n padding: '6px 12px',\r\n textAlign: 'left',\r\n width: 'calc(100% - 24px)',\r\n}\r\n\r\n/** The note beside a folded group (e.g. how many the capped list left out). */\r\nconst CAPTION_STYLE: CSSProperties = {\r\n padding: '0 12px 6px',\r\n color: 'var(--dsw-alias-label-tertiary)',\r\n fontSize: 11,\r\n lineHeight: '16px',\r\n}\r\n\r\nconst CHEVRON_STYLE = (open: boolean): CSSProperties => ({\r\n flexShrink: 0,\r\n transition: 'transform 0.16s',\r\n transform: open ? 'rotate(180deg)' : 'none',\r\n})\r\n\r\n/**\r\n * A counted group title. Renders nothing when the group is empty — an empty\r\n * \"活跃召回 · 0\" line would ask the reader to explain a heading rather than read\r\n * a fact.\r\n * @param props - already-interpolated text, plus an optional DOM marker.\r\n */\r\nexport function GroupHeader(props: { text: string; marker?: string }): ReactNode {\r\n if (props.text.length === 0) return null\r\n return createElement(\r\n 'div',\r\n {\r\n style: GROUP_HEADER_STYLE,\r\n 'data-dsh-brief-sidebar': props.marker ?? 'group-header',\r\n },\r\n props.text,\r\n )\r\n}\r\n\r\n/**\r\n * The fold switch. `marker` is what tests (and the browser probe) click, so it\r\n * belongs to the component rather than to either caller's markup.\r\n * @param props - label, current state, DOM marker, click handler.\r\n */\r\nexport function FoldToggle(props: {\r\n label: string\r\n open: boolean\r\n marker: string\r\n onToggle(): void\r\n}): ReactNode {\r\n const { label, open, marker } = props\r\n return createElement(\r\n 'button',\r\n {\r\n type: 'button',\r\n 'aria-expanded': open,\r\n style: TOGGLE_STYLE,\r\n 'data-dsh-brief-sidebar': marker,\r\n onClick: () => { props.onToggle() },\r\n },\r\n label,\r\n createElement(\r\n 'svg',\r\n { width: 10, height: 10, viewBox: '0 0 16 16', 'aria-hidden': true, style: CHEVRON_STYLE(open) },\r\n createElement('path', {\r\n d: 'M4 6l4 4 4-4',\r\n fill: 'none',\r\n stroke: 'currentColor',\r\n strokeWidth: 1.5,\r\n strokeLinecap: 'round',\r\n strokeLinejoin: 'round',\r\n }),\r\n ),\r\n )\r\n}\r\n\r\n/** A quiet caption under a group, used for the \"the list is capped\" note. */\r\nexport function GroupCaption(props: { text: string; marker: string }): ReactNode {\r\n return createElement('div', { style: CAPTION_STYLE, 'data-dsh-brief-sidebar': props.marker }, props.text)\r\n}\r\n","/**\n * Plugin-owned i18n dictionaries.\n *\n * Consumer plugins must NOT reach into better-sidebar's internal `t()` or its\n * `betterSidebar` dictionary namespace, so this plugin registers its own\n * namespace through the DSH `locale` service. `dsh-brief-sidebar` is outside the\n * `LocaleNamespaceMap` merge table, which is exactly what the untyped\n * `register(ns, dicts)` overload is for — but the dictionaries themselves stay\n * strictly paired: `zh` is the key-set source of truth and every other language\n * (`en`, plus the fr/de/it/ru/es pack) is typed as\n * `Record<keyof typeof zh, string>`, so a missing or extra key is a COMPILE\n * error rather than a runtime fallback to the raw key.\n *\n * Every key referenced anywhere in `src/**` must exist in both dictionaries;\n * `tests/purity.spec.ts` asserts that, so a typo in a `t('…')` call cannot\n * ship as an untranslated literal.\n */\n\n/** The namespace owned by this plugin (own vocabulary, own lifecycle). */\nexport const NS = 'dsh-brief-sidebar'\n\n/** Simplified Chinese dictionary — the key-set source of truth. */\nexport const zh = {\n 'tab.title': '概要',\n 'tab.desc': '当前会话的任务、产物与规划文件(只读)',\n 'section.progress': '进展',\n 'section.deliverables': '产物',\n 'board.empty': '当前没有任务',\n 'board.emptyHint': '模型调用 todo_write 之后,任务会出现在这里。',\n 'board.unavailable': '任务暂不可用',\n 'board.unavailableHint': '这个会话还没有收到 todo 数据;宿主推来第一帧后会自动显示。',\n 'status.pending': '待处理',\n 'status.inProgress': '进行中',\n 'status.completed': '已完成',\n 'deliverables.empty': '本回合暂无改动文件',\n 'deliverables.emptyHint': '会话里成功写入或修改文件后,它们会实时出现在这里。',\n 'deliverables.history': '更早改动的文件 · {count}',\n 'deliverables.currentTurn': '本回合改动 · {count}',\n 'deliverables.historyCapped': '(会话共 {total} 个文件,列表已截断)',\n 'deliverable.codeplanTag': '规划',\n 'section.memorySlots': '记忆',\n 'slots.empty': '当前没有激活的记忆槽位',\n 'slots.emptyHint': '当 dsh-prime-memory 激活记忆槽位后,它们会实时出现在这里。',\n 'slots.openCount': '开启 {count} 个槽位',\n 'slots.status.open': '生效中',\n 'slots.status.done': '已完成',\n 'slots.status.dropped': '已弃置',\n 'slots.status.expired': '已过期',\n 'section.memoryRecall': '本会话召回',\n 'recall.empty': '本会话还没有召回到记忆',\n 'recall.count': '注入 {count} 条 · 被摘要取代的已折叠(清空会话才清除)',\n 'recall.rateHint': '点选一条后可标注:0–5 相关度;-1 声明过时并退场(可恢复)',\n 'recall.obsolete': '声明过时',\n 'recall.obsoleteConfirm': '确认退场?',\n 'recall.obsoleted': '已判过时',\n 'recall.rated': '已评 {count} 分',\n 'recall.failed': '标注失败:',\n 'recall.obsoleteWhy': '声明过时后,该记忆退场(可恢复),下一轮会告知模型',\n 'recall.strikeHint': ';判过时的条目会一直保留在列表里并划上删除线(清空会话才移除)',\n 'recall.supersededHidden': '已隐藏 {count} 条被摘要取代的旧召回(正文已不在上下文)',\n 'recall.activeGroup': '活跃召回 · {count}',\n 'recall.historyGroup': '其余历史召回 · {count}',\n 'recall.supersededTag': '已被摘要取代',\n 'recall.noBody': '(本帧没有这条记忆的全文)',\n 'section.skillUsage': '技能引用',\n 'skillUsage.empty': '本会话还没载入过技能',\n 'skillUsage.emptyHint': '模型用 skill 工具载入、或你直接点用某个技能后,技能名会实时出现在这里。',\n 'skillUsage.uses': '{count} 次',\n 'skillUsage.count': '载入 {count} 次 · {total} 个技能',\n 'skillUsage.latestTag': '本轮',\n 'skillUsage.invokedGroup': '已引用 · {count}',\n 'skillUsage.availableGroup': '本会话可用 · {count}',\n 'skillUsage.availableCapped': '(可用清单共 {count} 条,列表已截断)',\n 'settings.title': '概要侧栏',\n 'settings.desc': '右侧栏概要 tab 的分区开关(只读展示)。',\n 'settings.memorySlots': '记忆槽位分区',\n 'settings.memorySlotsHint': '开启后,概要 tab 在进展与产物之下显示 dsh-prime-memory 的激活记忆槽位(只读)。',\n 'settings.memoryRecall': '本会话召回分区',\n 'settings.memoryRecallHint': '开启后,概要 tab 显示本会话已注入的记忆,并可标注相关度(0–5;-1 声明过时并退场)。被摘要取代的条目会自动折叠。',\n 'settings.unavailable': '配置面不可用,记忆分区按默认「开」处理。',\n 'settings.readonly': '当前配置只读,无法在此修改。',\n}\n\n/** The key union: what a `t('…')` call may name inside this namespace. */\nexport type BriefKey = keyof typeof zh\n\n/** English dictionary, checked complete against the zh key set. */\nexport const en: Record<BriefKey, string> = {\n 'tab.title': 'Summary',\n 'tab.desc': 'Tasks, produced files and plan artifacts of this session (read-only)',\n 'section.progress': 'Progress',\n 'section.deliverables': 'Produced files',\n 'board.empty': 'No tasks yet',\n 'board.emptyHint': 'Tasks show up here once the model calls todo_write.',\n 'board.unavailable': 'Tasks unavailable',\n 'board.unavailableHint':\n 'This session has not received any todo data yet; the board fills in on the first frame.',\n 'status.pending': 'Pending',\n 'status.inProgress': 'In progress',\n 'status.completed': 'Done',\n 'deliverables.empty': 'No files changed in this turn',\n 'deliverables.emptyHint': 'Files written or edited successfully in the session appear here live.',\n 'deliverables.history': 'Earlier changes · {count}',\n 'deliverables.currentTurn': 'This turn · {count}',\n 'deliverables.historyCapped': '(the session produced {total} files; the list is capped)',\n 'deliverable.codeplanTag': 'Plan',\n 'section.memorySlots': 'Memory',\n 'slots.empty': 'No active memory slots',\n 'slots.emptyHint': 'Slots appear here live once dsh-prime-memory activates them.',\n 'slots.openCount': '{count} slots open',\n 'slots.status.open': 'Open',\n 'slots.status.done': 'Done',\n 'slots.status.dropped': 'Dropped',\n 'slots.status.expired': 'Expired',\n 'section.memoryRecall': 'Session recall',\n 'recall.empty': 'No memories recalled in this session yet',\n 'recall.count': '{count} injected · superseded ones folded after compaction (cleared only on /clear)',\n 'recall.rateHint': 'Select a memory to mark it: 0–5 relevance; -1 declares it obsolete and retires it (restorable).',\n 'recall.obsolete': 'Obsolete',\n 'recall.obsoleteConfirm': 'Retire it?',\n 'recall.obsoleted': 'Marked obsolete',\n 'recall.rated': 'Rated {count}/5',\n 'recall.failed': 'Mark failed: ',\n 'recall.obsoleteWhy': 'Declaring it obsolete retires the record (restorable) and tells the model next turn',\n 'recall.strikeHint': '; an entry you mark obsolete stays listed, struck through (removed only when you clear the session)',\n 'recall.supersededHidden': '{count} older recalls hidden — their text was replaced by a summary',\n 'recall.activeGroup': 'Active recalls · {count}',\n 'recall.historyGroup': 'Earlier recalls · {count}',\n 'recall.supersededTag': 'replaced by summary',\n 'recall.noBody': '(this frame carries no full body for this record)',\n 'section.skillUsage': 'Skill references',\n 'skillUsage.empty': 'No skills loaded in this session',\n 'skillUsage.emptyHint': 'Skills show up here once the model loads one with the `skill` tool, or you invoke one directly.',\n 'skillUsage.uses': '{count}x',\n 'skillUsage.count': '{count} loads - {total} skills',\n 'skillUsage.latestTag': 'this turn',\n 'skillUsage.invokedGroup': 'Referenced · {count}',\n 'skillUsage.availableGroup': 'Available this session · {count}',\n 'skillUsage.availableCapped': '({count} skills in the catalog; the list is capped)',\n 'settings.title': 'Brief sidebar',\n 'settings.desc': 'Section switches for the summary tab in the right sidebar (read-only views).',\n 'settings.memorySlots': 'Memory slots section',\n 'settings.memorySlotsHint': 'When on, the summary tab lists the active memory slots from dsh-prime-memory beneath progress and produced files (read-only).',\n 'settings.memoryRecall': 'Session recall section',\n 'settings.memoryRecallHint': 'When on, the Summary tab lists the memories injected this session and lets you rate them (0–5; -1 declares one obsolete and retires it). Entries a summary replaced are folded away.',\n 'settings.unavailable': 'The config face is unavailable; the memory section falls back to its default (on).',\n 'settings.readonly': 'This config is read-only here; edits are not available.',\n}\n\n/** Japanese dictionary, checked complete against the zh key set. */\nexport const ja: Record<BriefKey, string> = {\n 'tab.title': '概要',\n 'tab.desc': 'このセッションのタスク・成果物・計画ファイル(読み取り専用)',\n 'section.progress': '進行状況',\n 'section.deliverables': '成果物',\n 'board.empty': '現在タスクはありません',\n 'board.emptyHint': 'モデルが todo_write を呼び出すと、タスクがここに表示されます。',\n 'board.unavailable': 'タスクを利用できません',\n 'board.unavailableHint':\n 'このセッションはまだ todo データを受信していません。ホストが最初のフレームを送ると自動的に表示されます。',\n 'status.pending': '未対応',\n 'status.inProgress': '進行中',\n 'status.completed': '完了',\n 'deliverables.empty': 'このターンで変更されたファイルはありません',\n 'deliverables.emptyHint': 'セッションでファイルの書き込み・変更が成功すると、ここにリアルタイムで表示されます。',\n 'deliverables.history': '以前の変更 · {count}',\n 'deliverables.currentTurn': 'このターン · {count}',\n 'deliverables.historyCapped': '(セッション全体で {total} ファイル、一覧は上限で省略)',\n 'deliverable.codeplanTag': '計画',\n 'section.memorySlots': 'メモリ',\n 'slots.empty': 'アクティブなメモリスロットはありません',\n 'slots.emptyHint': 'dsh-prime-memory がスロットをアクティブにすると、ここにリアルタイムで表示されます。',\n 'slots.openCount': '有効なスロット: {count} 件',\n 'slots.status.open': '有効',\n 'slots.status.done': '完了',\n 'slots.status.dropped': '破棄',\n 'slots.status.expired': '期限切れ',\n 'section.memoryRecall': 'このセッションの想起',\n 'recall.empty': 'このセッションではまだ記憶を想起していません',\n 'recall.count': '{count} 件を注入 · 要約に置き換わった分は折りたたみ(/clear でのみ消去)',\n 'recall.rateHint': '行を選ぶと採点できます:0–5 関連度;-1 は「古い」と宣言して退場(復元可)。',\n 'recall.obsolete': '古いと宣言',\n 'recall.obsoleteConfirm': '退場させますか?',\n 'recall.obsoleted': '古いと判定済み',\n 'recall.rated': '{count} 点',\n 'recall.failed': '採点に失敗:',\n 'recall.obsoleteWhy': '古いと宣言すると記録は退場(復元可)、次のターンでモデルに伝わります',\n 'recall.strikeHint': ';古いと宣言した項目は取り消し線のまま一覧に保持されます(セッションをクリアすると消えます)',\n 'recall.supersededHidden': '要約に置き換わった旧召回 {count} 件を非表示(本文はコンテキストにない)',\n 'recall.activeGroup': 'アクティブな想起 · {count}',\n 'recall.historyGroup': 'その他の履歴想起 · {count}',\n 'recall.supersededTag': '要約に置換済み',\n 'recall.noBody': 'このフレームには全文が含まれていない',\n 'section.skillUsage': 'スキル参照',\n 'skillUsage.empty': 'このセッションではスキルを読み込んでいません',\n 'skillUsage.emptyHint': 'モデルが skill ツールで読み込むか、あなたがスキルを直接起動すると、ここにリアルタイムで表示されます。',\n 'skillUsage.uses': '{count} 回',\n 'skillUsage.count': '読み込み {count} 回 · スキル {total} 件',\n 'skillUsage.latestTag': 'このターン',\n 'skillUsage.invokedGroup': '参照済み · {count}',\n 'skillUsage.availableGroup': 'このセッションで利用可能 · {count}',\n 'skillUsage.availableCapped': '(カタログは全 {count} 件、一覧は上限で省略)',\n 'settings.title': '概要サイドバー',\n 'settings.desc': '右サイドバー概要タブのセクション表示切り替え(読み取り専用)。',\n 'settings.memorySlots': 'メモリスロットセクション',\n 'settings.memorySlotsHint': 'オンにすると、概要タブの進行状況と成果物の下に dsh-prime-memory のアクティブなメモリスロット(読み取り専用)が表示されます。',\n 'settings.memoryRecall': 'セッション想起のセクション',\n 'settings.memoryRecallHint': '有効にすると概要タブに本セッションで注入された記憶を表示し、関連度(0–5、-1 は陳腐化を宣言して退場)を付けられます。要約に置き換わった項目は自動で折りたたまれます。',\n 'settings.unavailable': '設定画面を利用できません。メモリセクションは既定(オン)で動作します。',\n 'settings.readonly': 'この設定はここでは読み取り専用のため変更できません。',\n}\n\n/** Korean dictionary, checked complete against the zh key set. */\nexport const ko: Record<BriefKey, string> = {\n 'tab.title': '요약',\n 'tab.desc': '현재 세션의 작업, 산출물 및 계획 파일(읽기 전용)',\n 'section.progress': '진행 상황',\n 'section.deliverables': '산출물',\n 'board.empty': '현재 작업이 없습니다',\n 'board.emptyHint': '모델이 todo_write를 호출하면 작업이 여기에 표시됩니다.',\n 'board.unavailable': '작업을 사용할 수 없습니다',\n 'board.unavailableHint':\n '이 세션은 아직 todo 데이터를 받지 못했습니다. 호스트가 첫 프레임을 보내면 자동으로 표시됩니다.',\n 'status.pending': '대기 중',\n 'status.inProgress': '진행 중',\n 'status.completed': '완료',\n 'deliverables.empty': '이번 턴에 변경된 파일이 없습니다',\n 'deliverables.emptyHint': '세션에서 파일을 성공적으로 작성하거나 수정하면 여기에 실시간으로 표시됩니다.',\n 'deliverables.history': '이전 변경 사항 · {count}',\n 'deliverables.currentTurn': '이번 턴 · {count}',\n 'deliverables.historyCapped': '(세션 전체 {total}개 파일, 목록은 잘림)',\n 'deliverable.codeplanTag': '계획',\n 'section.memorySlots': '메모리',\n 'slots.empty': '활성화된 메모리 슬롯이 없습니다',\n 'slots.emptyHint': 'dsh-prime-memory가 슬롯을 활성화하면 여기에 실시간으로 표시됩니다.',\n 'slots.openCount': '열린 슬롯: {count}개',\n 'slots.status.open': '활성',\n 'slots.status.done': '완료',\n 'slots.status.dropped': '폐기',\n 'slots.status.expired': '만료',\n 'section.memoryRecall': '이 세션 회상',\n 'recall.empty': '이 세션에서는 아직 기억을 회상하지 않았습니다',\n 'recall.count': '{count}건 주입 · 요약으로 대체된 항목은 접힘(/clear 시에만 삭제)',\n 'recall.rateHint': '항목을 선택하면 평가할 수 있습니다: 0–5 관련도; -1은 오래된 것으로 선언하여 삭제(복원 가능).',\n 'recall.obsolete': '오래됨 선언',\n 'recall.obsoleteConfirm': '삭제할까요?',\n 'recall.obsoleted': '오래된 것으로 판정됨',\n 'recall.rated': '{count}점 평가됨',\n 'recall.failed': '평가 실패: ',\n 'recall.obsoleteWhy': '낡음으로 선언하면 기록이 퇴장하며(복원 가능), 다음 턴에서 모델에 알립니다',\n 'recall.strikeHint': ';낡음으로 선언한 항목은 취소선 상태로 목록에 계속 표시됩니다(세션을 비우면 제거)',\n 'recall.supersededHidden': '요약으로 대체된 이전 회수 {count}건 숨김(본문이 컨텍스트에 없음)',\n 'recall.activeGroup': '활성 회상 · {count}',\n 'recall.historyGroup': '나머지 이전 회상 · {count}',\n 'recall.supersededTag': '요약에 대체됨',\n 'recall.noBody': '이 프레임에는 이 기록의 전문이 없습니다',\n 'section.skillUsage': '스킬 참조',\n 'skillUsage.empty': '이 세션에서 스킬을 불러오지 않았습니다',\n 'skillUsage.emptyHint': '모델이 skill 도구로 불러오거나 당신이 스킬을 직접 실행하면 여기에 실시간으로 나타납니다.',\n 'skillUsage.uses': '{count}회',\n 'skillUsage.count': '불러오기 {count}회 · 스킬 {total}개',\n 'skillUsage.latestTag': '이 턴',\n 'skillUsage.invokedGroup': '참조됨 · {count}',\n 'skillUsage.availableGroup': '이 세션에서 사용 가능 · {count}',\n 'skillUsage.availableCapped': '(카탈로그 전체 {count}개, 목록은 잘림)',\n 'settings.title': '요약 사이드바',\n 'settings.desc': '오른쪽 사이드바 요약 탭의 섹션 표시 전환(읽기 전용).',\n 'settings.memorySlots': '메모리 슬롯 섹션',\n 'settings.memorySlotsHint': '켜면 요약 탭의 진행 상황과 산출물 아래에 dsh-prime-memory의 활성 메모리 슬롯(읽기 전용)이 표시됩니다.',\n 'settings.memoryRecall': '세션 회상 섹션',\n 'settings.memoryRecallHint': '켜면 요약 탭에 이번 세션에서 주입된 기억을 표시하고 관련도(0–5, -1은 노후 선언 후 퇴장)를 매길 수 있습니다. 요약으로 대체된 항목은 자동으로 접힙니다.',\n 'settings.unavailable': '설정 화면을 사용할 수 없어 메모리 섹션은 기본값(켜짐)으로 동작합니다.',\n 'settings.readonly': '이 설정은 여기서 읽기 전용이므로 변경할 수 없습니다.',\n}\n\n/** French dictionary, checked complete against the zh key set. */\nexport const fr: Record<BriefKey, string> = {\n 'tab.title': 'Résumé',\n 'tab.desc': 'Tâches, fichiers produits et plans de la session (lecture seule)',\n 'section.progress': 'Avancement',\n 'section.deliverables': 'Fichiers produits',\n 'board.empty': 'Aucune tâche pour le moment',\n 'board.emptyHint': 'Les tâches apparaissent ici dès que le modèle appelle todo_write.',\n 'board.unavailable': 'Tâches indisponibles',\n 'board.unavailableHint':\n 'Cette session n’a pas encore reçu de données todo ; le tableau se remplit dès la première trame.',\n 'status.pending': 'En attente',\n 'status.inProgress': 'En cours',\n 'status.completed': 'Terminé',\n 'deliverables.empty': 'Aucun fichier modifié à ce tour',\n 'deliverables.emptyHint': 'Les fichiers écrits ou modifiés dans la session apparaissent ici en direct.',\n 'deliverables.history': 'Modifications antérieures · {count}',\n 'deliverables.currentTurn': 'Ce tour-ci · {count}',\n 'deliverables.historyCapped': '(la session a produit {total} fichiers ; la liste est tronquée)',\n 'deliverable.codeplanTag': 'Plan',\n 'section.memorySlots': 'Mémoire',\n 'slots.empty': 'Aucun emplacement mémoire actif',\n 'slots.emptyHint': 'Les emplacements apparaissent ici en direct dès que dsh-prime-memory les active.',\n 'slots.openCount': '{count} emplacements ouverts',\n 'slots.status.open': 'Actif',\n 'slots.status.done': 'Terminé',\n 'slots.status.dropped': 'Abandonné',\n 'slots.status.expired': 'Expiré',\n 'section.memoryRecall': 'Rappel de la session',\n 'recall.empty': 'Aucun souvenir rappelé dans cette session',\n 'recall.count': '{count} injectés · les remplacés par un résumé sont repliés après compression (effacés par /clear)',\n 'recall.rateHint': 'Sélectionnez un souvenir pour le noter : 0–5 pertinence ; -1 le déclare obsolète et le retire (récupérable).',\n 'recall.obsolete': 'Obsolète',\n 'recall.obsoleteConfirm': 'Le retirer ?',\n 'recall.obsoleted': 'Déclaré obsolète',\n 'recall.rated': 'Noté {count}/5',\n 'recall.failed': 'Échec de la note : ',\n 'recall.obsoleteWhy': 'Déclarer obsolète retire l’enregistrement (récupérable) et prévient le modèle au tour suivant',\n 'recall.strikeHint': ' ; une entrée déclarée obsolète reste listée, barrée (retirée uniquement quand vous videz la session)',\n 'recall.supersededHidden': '{count} anciens rappels masqués — leur texte a été remplacé par un résumé',\n 'recall.activeGroup': 'Rappels actifs · {count}',\n 'recall.historyGroup': 'Rappels antérieurs · {count}',\n 'recall.supersededTag': 'remplacé par le résumé',\n 'recall.noBody': '(aucun texte complet pour cette entrée dans cette trame)',\n 'section.skillUsage': 'Références de compétences',\n 'skillUsage.empty': 'Aucune compétence chargée dans cette session',\n 'skillUsage.emptyHint': 'Les compétences apparaissent ici dès que le modèle en charge une via l’outil `skill`, ou quand vous en lancez une directement.',\n 'skillUsage.uses': '{count}×',\n 'skillUsage.count': '{count} chargements · {total} compétences',\n 'skillUsage.latestTag': 'ce tour',\n 'skillUsage.invokedGroup': 'Référencées · {count}',\n 'skillUsage.availableGroup': 'Disponibles dans cette session · {count}',\n 'skillUsage.availableCapped': '({count} compétences au catalogue ; la liste est tronquée)',\n 'settings.title': 'Barre latérale Résumé',\n 'settings.desc': 'Interrupteurs des sections de l’onglet Résumé de la barre latérale (lecture seule).',\n 'settings.memorySlots': 'Section des emplacements mémoire',\n 'settings.memorySlotsHint': 'Une fois activé, l’onglet Résumé liste les emplacements mémoire actifs de dsh-prime-memory sous l’avancement et les fichiers produits (lecture seule).',\n 'settings.memoryRecall': 'Section rappel de session',\n 'settings.memoryRecallHint': 'Actif, onglet Résumé : liste les souvenirs injectés dans cette session et permet de les noter (0–5 ; -1 déclare obsolète et retire). Les entrées remplacées par un résumé sont repliées.',\n 'settings.unavailable': 'Le canal de configuration est indisponible ; la section mémoire revient à sa valeur par défaut (activée).',\n 'settings.readonly': 'Cette configuration est en lecture seule ici ; aucune modification possible.',\n}\n\n/** German dictionary, checked complete against the zh key set. */\nexport const de: Record<BriefKey, string> = {\n 'tab.title': 'Übersicht',\n 'tab.desc': 'Aufgaben, erzeugte Dateien und Pläne dieser Sitzung (schreibgeschützt)',\n 'section.progress': 'Fortschritt',\n 'section.deliverables': 'Erzeugte Dateien',\n 'board.empty': 'Noch keine Aufgaben',\n 'board.emptyHint': 'Aufgaben erscheinen hier, sobald das Modell todo_write aufruft.',\n 'board.unavailable': 'Aufgaben nicht verfügbar',\n 'board.unavailableHint':\n 'Diese Sitzung hat noch keine Todo-Daten erhalten; das Board füllt sich mit dem ersten Frame.',\n 'status.pending': 'Ausstehend',\n 'status.inProgress': 'In Bearbeitung',\n 'status.completed': 'Fertig',\n 'deliverables.empty': 'Keine Dateien in diesem Durchgang geändert',\n 'deliverables.emptyHint': 'In der Sitzung erfolgreich geschriebene oder geänderte Dateien erscheinen hier live.',\n 'deliverables.history': 'Frühere Änderungen · {count}',\n 'deliverables.currentTurn': 'Dieser Durchlauf · {count}',\n 'deliverables.historyCapped': '(die Sitzung erzeugte {total} Dateien; die Liste ist gekürzt)',\n 'deliverable.codeplanTag': 'Plan',\n 'section.memorySlots': 'Gedächtnis',\n 'slots.empty': 'Keine aktiven Speicherplätze',\n 'slots.emptyHint': 'Sobald dsh-prime-memory Slots aktiviert, erscheinen sie hier in Echtzeit.',\n 'slots.openCount': '{count} Slots offen',\n 'slots.status.open': 'Offen',\n 'slots.status.done': 'Erledigt',\n 'slots.status.dropped': 'Verworfen',\n 'slots.status.expired': 'Abgelaufen',\n 'section.memoryRecall': 'Sitzungserinnerung',\n 'recall.empty': 'In dieser Sitzung wurden noch keine Erinnerungen geholt',\n 'recall.count': '{count} eingefügt · die durch eine Zusammenfassung ersetzten sind nach der Komprimierung eingeklappt (bei /clear gelöscht)',\n 'recall.rateHint': 'Ein Eintrag auswählen zum Bewerten: 0–5 Relevanz; -1 erklärt ihn für veraltet und entfernt ihn (wiederherstellbar).',\n 'recall.obsolete': 'Veraltet',\n 'recall.obsoleteConfirm': 'Entfernen?',\n 'recall.obsoleted': 'Als veraltet markiert',\n 'recall.rated': 'Bewertet {count}/5',\n 'recall.failed': 'Bewertung fehlgeschlagen: ',\n 'recall.obsoleteWhy': 'Als veraltet erklären versetzt den Eintrag in den Ruhestand (wiederherstellbar) und informiert das Modell in der nächsten Runde',\n 'recall.strikeHint': '; ein als veraltet markierter Eintrag bleibt durchgestrichen in der Liste (erst beim Leeren der Sitzung entfernt)',\n 'recall.supersededHidden': '{count} ältere Treffer ausgeblendet — ihr Text wurde durch eine Zusammenfassung ersetzt',\n 'recall.activeGroup': 'Aktive Abrufe · {count}',\n 'recall.historyGroup': 'Weitere Abrufe · {count}',\n 'recall.supersededTag': 'durch Zusammenfassung ersetzt',\n 'recall.noBody': '(dieser Rahmen enthält keinen vollständigen Text für diesen Eintrag)',\n 'section.skillUsage': 'Skill-Referenzen',\n 'skillUsage.empty': 'In dieser Sitzung wurden keine Skills geladen',\n 'skillUsage.emptyHint': 'Skills erscheinen hier, sobald das Modell einen über das `skill`-Tool lädt oder du einen direkt aufrufst.',\n 'skillUsage.uses': '{count}x',\n 'skillUsage.count': '{count} Ladungen · {total} Skills',\n 'skillUsage.latestTag': 'diese Runde',\n 'skillUsage.invokedGroup': 'Referenziert · {count}',\n 'skillUsage.availableGroup': 'In dieser Sitzung verfügbar · {count}',\n 'skillUsage.availableCapped': '({count} Skills im Katalog; die Liste ist gekürzt)',\n 'settings.title': 'Übersicht-Seitenleiste',\n 'settings.desc': 'Schalter für die Abschnitte des Übersicht-Tabs in der rechten Seitenleiste (schreibgeschützt).',\n 'settings.memorySlots': 'Speicherplätze-Abschnitt',\n 'settings.memorySlotsHint': 'Ist der Schalter eingeschaltet, listet der Übersicht-Tab die aktiven Speicherplätze aus dsh-prime-memory unter Fortschritt und erzeugten Dateien auf (schreibgeschützt).',\n 'settings.memoryRecall': 'Bereich Sitzungserinnerung',\n 'settings.memoryRecallHint': 'Aktiv: Der Tab „Zusammenfassung“ listet die in dieser Sitzung eingefügten Erinnerungen und erlaubt Bewertungen (0–5; -1 erklärt für veraltet und entfernt). Durch eine Zusammenfassung ersetzte Einträge werden eingeklappt.',\n 'settings.unavailable': 'Die Konfigurationsoberfläche ist nicht verfügbar; der Gedächtnis-Abschnitt fällt auf den Standard (ein) zurück.',\n 'settings.readonly': 'Diese Konfiguration ist hier schreibgeschützt; Änderungen sind nicht möglich.',\n}\n\n/** Italian dictionary, checked complete against the zh key set. */\nexport const it: Record<BriefKey, string> = {\n 'tab.title': 'Riepilogo',\n 'tab.desc': 'Attività, file prodotti e piani di questa sessione (sola lettura)',\n 'section.progress': 'Avanzamento',\n 'section.deliverables': 'File prodotti',\n 'board.empty': 'Nessuna attività per ora',\n 'board.emptyHint': 'Le attività appaiono qui quando il modello chiama todo_write.',\n 'board.unavailable': 'Attività non disponibili',\n 'board.unavailableHint':\n 'Questa sessione non ha ancora ricevuto dati todo; la bacheca si riempirà al primo frame.',\n 'status.pending': 'In attesa',\n 'status.inProgress': 'In corso',\n 'status.completed': 'Completato',\n 'deliverables.empty': 'Nessun file modificato in questo turno',\n 'deliverables.emptyHint': 'I file scritti o modificati nella sessione appaiono qui in tempo reale.',\n 'deliverables.history': 'Modifiche precedenti · {count}',\n 'deliverables.currentTurn': 'Questo turno · {count}',\n 'deliverables.historyCapped': '(la sessione ha prodotto {total} file; l’elenco è troncato)',\n 'deliverable.codeplanTag': 'Piano',\n 'section.memorySlots': 'Memoria',\n 'slots.empty': 'Nessuno slot di memoria attivo',\n 'slots.emptyHint': 'Gli slot appaiono qui in tempo reale quando dsh-prime-memory li attiva.',\n 'slots.openCount': '{count} slot aperti',\n 'slots.status.open': 'Attivo',\n 'slots.status.done': 'Completato',\n 'slots.status.dropped': 'Scartato',\n 'slots.status.expired': 'Scaduto',\n 'section.memoryRecall': 'Richiamo della sessione',\n 'recall.empty': 'Nessun ricordo richiamato in questa sessione',\n 'recall.count': '{count} inseriti · quelli sostituiti da un riassunto sono ripiegati dopo la compressione (rimossi con /clear)',\n 'recall.rateHint': 'Seleziona un ricordo per valutarlo: 0–5 pertinenza; -1 lo dichiara obsoleto e lo ritira (ripristinabile).',\n 'recall.obsolete': 'Obsoleto',\n 'recall.obsoleteConfirm': 'Ritirarlo?',\n 'recall.obsoleted': 'Dichiarato obsoleto',\n 'recall.rated': 'Valutato {count}/5',\n 'recall.failed': 'Valutazione non riuscita: ',\n 'recall.obsoleteWhy': 'Dichiararlo obsoleto congeda il record (ripristinabile) e avvisa il modello al turno successivo',\n 'recall.strikeHint': '; una voce dichiarata obsoleta resta elencata, barrata (rimossa solo svuotando la sessione)',\n 'recall.supersededHidden': '{count} vecchi richiami nascosti — il testo è stato sostituito da un riassunto',\n 'recall.activeGroup': 'Richiami attivi · {count}',\n 'recall.historyGroup': 'Richiami precedenti · {count}',\n 'recall.supersededTag': 'sostituito dal riassunto',\n 'recall.noBody': '(questo frame non contiene il testo completo di questa voce)',\n 'section.skillUsage': 'Riferimenti alle skill',\n 'skillUsage.empty': 'Nessuna skill caricata in questa sessione',\n 'skillUsage.emptyHint': 'Le skill compaiono qui quando il modello ne carica una con il tool `skill` o quando ne avvii una direttamente.',\n 'skillUsage.uses': '{count}x',\n 'skillUsage.count': '{count} caricamenti · {total} skill',\n 'skillUsage.latestTag': 'questo giro',\n 'skillUsage.invokedGroup': 'Referenziate · {count}',\n 'skillUsage.availableGroup': 'Disponibili in questa sessione · {count}',\n 'skillUsage.availableCapped': '({count} skill nel catalogo; l’elenco è troncato)',\n 'settings.title': 'Barra laterale Riepilogo',\n 'settings.desc': 'Interruttori delle sezioni della scheda Riepilogo nella barra laterale destra (sola lettura).',\n 'settings.memorySlots': 'Sezione slot di memoria',\n 'settings.memorySlotsHint': 'Quando attivo, la scheda Riepilogo elenca gli slot di memoria attivi di dsh-prime-memory sotto avanzamento e file prodotti (sola lettura).',\n 'settings.memoryRecall': 'Sezione richiamo sessione',\n 'settings.memoryRecallHint': 'Attivo: la scheda Riepilogo elenca i ricordi inseriti in questa sessione e consente di valutarli (0–5; -1 dichiara obsoleto e ritira). Le voci sostituite da un riassunto vengono ripiegate.',\n 'settings.unavailable': 'La superficie di configurazione non è disponibile; la sezione memoria torna al valore predefinito (attivo).',\n 'settings.readonly': 'Questa configurazione è in sola lettura qui; non è possibile modificarla.',\n}\n\n/** Russian dictionary, checked complete against the zh key set. */\nexport const ru: Record<BriefKey, string> = {\n 'tab.title': 'Сводка',\n 'tab.desc': 'Задачи, созданные файлы и планы этой сессии (только чтение)',\n 'section.progress': 'Ход работы',\n 'section.deliverables': 'Созданные файлы',\n 'board.empty': 'Задач пока нет',\n 'board.emptyHint': 'Задачи появятся здесь, когда модель вызовет todo_write.',\n 'board.unavailable': 'Задачи недоступны',\n 'board.unavailableHint':\n 'Эта сессия ещё не получила данные todo; доска заполнится после первого кадра.',\n 'status.pending': 'Ожидает',\n 'status.inProgress': 'В работе',\n 'status.completed': 'Готово',\n 'deliverables.empty': 'За этот ход файлы не менялись',\n 'deliverables.emptyHint': 'Успешно записанные или изменённые файлы появляются здесь в реальном времени.',\n 'deliverables.history': 'Более ранние изменения · {count}',\n 'deliverables.currentTurn': 'Этот ход · {count}',\n 'deliverables.historyCapped': '(в сессии всего {total} файлов; список усечён)',\n 'deliverable.codeplanTag': 'План',\n 'section.memorySlots': 'Память',\n 'slots.empty': 'Активных слотов памяти нет',\n 'slots.emptyHint': 'Как только dsh-prime-memory активирует слоты, они появляются здесь в реальном времени.',\n 'slots.openCount': 'Открытых слотов: {count}',\n 'slots.status.open': 'Активен',\n 'slots.status.done': 'Завершён',\n 'slots.status.dropped': 'Отброшен',\n 'slots.status.expired': 'Истёк',\n 'section.memoryRecall': 'Воспоминания сессии',\n 'recall.empty': 'В этой сессии воспоминания ещё не вызывались',\n 'recall.count': 'Вставлено {count} · заменённые кратким изложением свёрнуты после сжатия (удаляются при /clear)',\n 'recall.rateHint': 'Выберите запись, чтобы оценить: 0–5 релевантность; -1 объявляет её устаревшей и убирает (восстановимо).',\n 'recall.obsolete': 'Устарело',\n 'recall.obsoleteConfirm': 'Убрать?',\n 'recall.obsoleted': 'Объявлено устаревшим',\n 'recall.rated': 'Оценка {count}/5',\n 'recall.failed': 'Ошибка оценки: ',\n 'recall.obsoleteWhy': 'Объявить устаревшим значит снимает запись восстанавлимо и сообщает модель на следующем ходе',\n 'recall.strikeHint': '; помеченная как устаревшая запись остаётся в списке, зачёркнутой (удаляется только при очистке сессии)',\n 'recall.supersededHidden': 'Скрыто старых воспоминаний: {count} — их текст заменён кратким изложением',\n 'recall.activeGroup': 'Активные вызовы · {count}',\n 'recall.historyGroup': 'Прочие прежние вызовы · {count}',\n 'recall.supersededTag': 'заменено сводкой',\n 'recall.noBody': 'В этом кадре нет полного текста этой записи',\n 'section.skillUsage': 'Отсылки к скиллам',\n 'skillUsage.empty': 'В этой сессии скиллы не загружались',\n 'skillUsage.emptyHint': 'Навыки появятся здесь, когда модель загрузит их через инструмент `skill` или вы вызовете навык напрямую.',\n 'skillUsage.uses': '{count} раз',\n 'skillUsage.count': 'Загрузок: {count} · скиллов: {total}',\n 'skillUsage.latestTag': 'этот ход',\n 'skillUsage.invokedGroup': 'Использованы · {count}',\n 'skillUsage.availableGroup': 'Доступны в этой сессии · {count}',\n 'skillUsage.availableCapped': '({count} навыков в каталоге; список усечён)',\n 'settings.title': 'Боковая панель «Сводка»',\n 'settings.desc': 'Переключатели разделов вкладки «Сводка» на правой панели (только чтение).',\n 'settings.memorySlots': 'Раздел слотов памяти',\n 'settings.memorySlotsHint': 'Когда включено, вкладка «Сводка» показывает активные слоты памяти из dsh-prime-memory под ходом работы и созданными файлами (только чтение).',\n 'settings.memoryRecall': 'Раздел Воспоминания сессии',\n 'settings.memoryRecallHint': 'Включено: вкладка «Сводка» показывает вставленные в этой сессии воспоминания и позволяет оценить их (0–5; -1 объявляет устаревшим и выводит из обращения). Заменённые кратким изложением записи сворачиваются.',\n 'settings.unavailable': 'Панель конфигурации недоступна; раздел памяти работает по умолчанию (включён).',\n 'settings.readonly': 'Эта конфигурация здесь только для чтения; изменить её нельзя.',\n}\n\n/** Spanish dictionary, checked complete against the zh key set. */\nexport const es: Record<BriefKey, string> = {\n 'tab.title': 'Resumen',\n 'tab.desc': 'Tareas, archivos generados y planes de esta sesión (solo lectura)',\n 'section.progress': 'Avance',\n 'section.deliverables': 'Archivos generados',\n 'board.empty': 'Aún no hay tareas',\n 'board.emptyHint': 'Las tareas aparecen aquí cuando el modelo llama a todo_write.',\n 'board.unavailable': 'Tareas no disponibles',\n 'board.unavailableHint':\n 'Esta sesión aún no ha recibido datos de tareas; el tablero se llena con el primer fotograma.',\n 'status.pending': 'Pendiente',\n 'status.inProgress': 'En curso',\n 'status.completed': 'Hecho',\n 'deliverables.empty': 'Ningún archivo modificado en este turno',\n 'deliverables.emptyHint': 'Los archivos escritos o editados en la sesión aparecen aquí en directo.',\n 'deliverables.history': 'Cambios anteriores · {count}',\n 'deliverables.currentTurn': 'Este turno · {count}',\n 'deliverables.historyCapped': '(la sesión produjo {total} archivos; la lista está truncada)',\n 'deliverable.codeplanTag': 'Plan',\n 'section.memorySlots': 'Memoria',\n 'slots.empty': 'No hay ranuras de memoria activas',\n 'slots.emptyHint': 'Las ranuras aparecen aquí en directo en cuanto dsh-prime-memory las active.',\n 'slots.openCount': '{count} ranuras abiertas',\n 'slots.status.open': 'Activa',\n 'slots.status.done': 'Hecha',\n 'slots.status.dropped': 'Descartada',\n 'slots.status.expired': 'Caducada',\n 'section.memoryRecall': 'Recuerdo de la sesión',\n 'recall.empty': 'Aún no se ha recuperado ningún recuerdo en esta sesión',\n 'recall.count': '{count} insertados · los reemplazados por un resumen se pliegan tras comprimir (se borran con /clear)',\n 'recall.rateHint': 'Selecciona un recuerdo para puntuarlo: 0–5 relevancia; -1 lo declara obsoleto y lo retira (recuperable).',\n 'recall.obsolete': 'Obsoleto',\n 'recall.obsoleteConfirm': '¿Retirarlo?',\n 'recall.obsoleted': 'Declarado obsoleto',\n 'recall.rated': 'Puntuado {count}/5',\n 'recall.failed': 'Error al puntuar: ',\n 'recall.obsoleteWhy': 'Declararlo obsoleto retira el registro (recuperable) y avisa al modelo en el turno siguiente',\n 'recall.strikeHint': '; una entrada marcada como obsoleta sigue en la lista, tachada (se retira solo al vaciar la sesión)',\n 'recall.supersededHidden': '{count} recuerdos antiguos ocultos — su texto fue reemplazado por un resumen',\n 'recall.activeGroup': 'Recuerdos activos · {count}',\n 'recall.historyGroup': 'Recuerdos anteriores · {count}',\n 'recall.supersededTag': 'reemplazado por el resumen',\n 'recall.noBody': '(este fotograma no trae el texto completo de este registro)',\n 'section.skillUsage': 'Referencias de skills',\n 'skillUsage.empty': 'Esta sesión no ha cargado ningún skill',\n 'skillUsage.emptyHint': 'Las skills aparecen aquí cuando el modelo carga una con la herramienta `skill` o cuando invocas una directamente.',\n 'skillUsage.uses': '{count}x',\n 'skillUsage.count': '{count} cargas · {total} skills',\n 'skillUsage.latestTag': 'este turno',\n 'skillUsage.invokedGroup': 'Referenciadas · {count}',\n 'skillUsage.availableGroup': 'Disponibles en esta sesión · {count}',\n 'skillUsage.availableCapped': '({count} skills en el catálogo; la lista está truncada)',\n 'settings.title': 'Barra lateral Resumen',\n 'settings.desc': 'Interruptores de las secciones de la pestaña Resumen en la barra lateral derecha (solo lectura).',\n 'settings.memorySlots': 'Sección de ranuras de memoria',\n 'settings.memorySlotsHint': 'Al activarla, la pestaña Resumen enumera las ranuras de memoria activas de dsh-prime-memory bajo el avance y los archivos generados (solo lectura).',\n 'settings.memoryRecall': 'Sección de recuerdo de sesión',\n 'settings.memoryRecallHint': 'Activado: la pestaña Resumen lista los recuerdos inyectados en esta sesión y permite puntuarlos (0–5; -1 declara obsoleto y retira). Las entradas reemplazadas por un resumen se pliegan.',\n 'settings.unavailable': 'La superficie de configuración no está disponible; la sección de memoria vuelve a su valor por defecto (activada).',\n 'settings.readonly': 'Esta configuración es de solo lectura aquí; no se puede modificar.',\n}\n\n/**\n * All locales in the shape the locale service consumes. Registered in ONE call:\n * the registry rejects a duplicate `(namespace, locale)` pair and the\n * per-locale form would leave a half-registered namespace if a later call\n * threw. `zh`/`en` are the host built-ins; the fr/de/it/ru/es pack rides the\n * same map form (every id is a valid BCP 47-style tag, so the registry accepts\n * it as-is).\n */\nexport const dictionaries: Record<string, Record<string, string>> = {\n zh,\n en,\n ja,\n ko,\n fr,\n de,\n it,\n ru,\n es,\n}\n\n/**\n * Expand the one `{count}` placeholder the deliverables totals line uses. The\n * locale binder is a plain key → string lookup (no interpolation machinery),\n * mirroring how `progressLine` composes its summary from parts.\n */\nexport function expandCount(template: string, count: number): string {\n return template.replace('{count}', String(count))\n}\n\n/**\n * Fill a `{total}` placeholder — the counter that says how many there really\n * are, as opposed to how many the (capped) list shows.\n */\nexport function expandTotal(template: string, total: number): string {\n return template.replace('{total}', String(total))\n}\n","/**\r\n * The deliverables section: the `dshSummaryDeliverables` projection drawn as\r\n * one part of the summary tab.\r\n *\r\n * Unlike the progress section this is an OPTIONAL capability: where the host\r\n * half never registered the unit (older composition, key absent), the section\r\n * hides entirely — absence is not an error state here, and the official\r\n * \"本次产出\" row in the conversation flow still covers the turn-end view.\r\n * When the projection is live, the latest turn's produced paths update\r\n * mid-turn: every successful mutation result publishes a frame, so the reader\r\n * sees files appear while the turn is still running, which is exactly the gap\r\n * the official turn-tail row has.\r\n *\r\n * Codeplan artifacts (paths under `.agents/plans/<任务名>/`) are ordinary\r\n * produced entries — they are marked with a pill, not split into a separate\r\n * section.\r\n *\r\n * Colours come from `--dsw-alias-*` tokens only (skin contract).\r\n */\r\nimport { createElement } from 'react'\r\nimport { useState } from 'react'\r\nimport type { CSSProperties, ReactNode } from 'react'\r\nimport type { Context } from '@deepseek-ai/cordis'\r\nimport { DELIVERABLES_KEY } from '../../projection/keys'\r\nimport { useProjectionValue } from '../use-projection'\r\nimport { sidebarFileOpener } from '../file-open'\r\nimport { basename, historyPaths, readDeliverables, splitCodeplanPath } from './deliverables'\r\nimport { GroupCaption, GroupHeader, FoldToggle } from './FoldToggle'\r\nimport { expandCount, expandTotal } from '../locales'\r\n\r\nexport interface DeliverablesSectionProps {\r\n /** The DSH locale lookup, passed down from `apply`. */\r\n t: (key: string) => string\r\n /** The client root context (the tab body's only way to reach services). */\r\n ctx?: Context\r\n /** The session this tab is scoped to. */\r\n scope?: { readonly sessionId?: string }\r\n}\r\n\r\nconst SECTION_STYLE: CSSProperties = {\r\n flexShrink: 0,\r\n borderBottom: '1px solid var(--dsw-alias-border-secondary)',\r\n}\r\n\r\nconst HEADER_STYLE: CSSProperties = {\r\n padding: '10px 12px 0',\r\n color: 'var(--dsw-alias-label-secondary)',\r\n fontSize: 12,\r\n fontWeight: 600,\r\n}\r\n\r\nconst LIST_STYLE: CSSProperties = {\r\n listStyle: 'none',\r\n margin: 0,\r\n padding: '6px 0',\r\n display: 'flex',\r\n flexDirection: 'column',\r\n}\r\n\r\nconst ROW_STYLE: CSSProperties = {\r\n display: 'flex',\r\n alignItems: 'flex-start',\r\n gap: 8,\r\n padding: '6px 12px',\r\n}\r\n\r\nconst PATH_STYLE: CSSProperties = {\r\n minWidth: 0,\r\n overflowWrap: 'anywhere',\r\n color: 'var(--dsw-alias-label-secondary)',\r\n}\r\n\r\n/** Row-as-button reset: the row itself is the click target, content unchanged. */\r\nconst BUTTON_STYLE: CSSProperties = {\r\n ...PATH_STYLE,\r\n background: 'none',\r\n border: 'none',\r\n font: 'inherit',\r\n fontSize: 'inherit',\r\n color: 'var(--dsw-alias-label-secondary)',\r\n padding: 0,\r\n textAlign: 'left',\r\n cursor: 'pointer',\r\n}\r\n\r\n/** The codeplan pill: same form as the status pills, tertiary emphasis. */\r\nconst TAG_STYLE: CSSProperties = {\r\n flexShrink: 0,\r\n color: 'var(--dsw-alias-label-tertiary)',\r\n border: '1px solid var(--dsw-alias-label-tertiary)',\r\n borderRadius: 999,\r\n padding: '0 6px',\r\n fontSize: 11,\r\n lineHeight: '16px',\r\n whiteSpace: 'nowrap',\r\n}\r\n\r\n/**\r\n * One produced-file row. When the sidebar opener is available the row is a\r\n * button that routes the path to the Sidebar preview (the same channel the\r\n * conversation's produced-file chips use); otherwise it degrades to a plain\r\n * span. A codeplan artifact carries the pill either way.\r\n */\r\nfunction PathRow(props: {\r\n path: string\r\n t: (key: string) => string\r\n open?: (path: string) => void\r\n}): ReactNode {\r\n const { path, t, open } = props\r\n const plan = splitCodeplanPath(path)\r\n const title = plan === null ? path : `${t('deliverable.codeplanTag')}: ${plan.task} · ${path}`\r\n const label = basename(path)\r\n const content = plan === null ? null : createElement('span', { style: TAG_STYLE }, t('deliverable.codeplanTag'))\r\n if (open === undefined) {\r\n return createElement(\r\n 'li',\r\n { style: ROW_STYLE },\r\n content,\r\n createElement('span', { style: PATH_STYLE, title }, label),\r\n )\r\n }\r\n return createElement(\r\n 'li',\r\n { style: ROW_STYLE },\r\n content,\r\n createElement('button', { style: BUTTON_STYLE, title, onClick: () => { open(path) } }, label),\r\n )\r\n}\r\n\r\n/**\r\n * The deliverables section. The subscription is unconditional (a plain\r\n * listener, not IO).\r\n *\r\n * 分层:本回合改动(latest)与全会话更早改动分成两组各自计数——前者直列,后者\r\n * 折叠在开关行后面(与活跃文件按归一化路径去重),展开后是与活跃区相同的可点击\r\n * 文件行。列表有上限时,开关行说折叠区条数、附注说会话真数,两个数不混为一谈。\r\n * @param props - translation, client context, session scope.\r\n */\r\nexport function DeliverablesSection(props: DeliverablesSectionProps): ReactNode {\r\n const { t, ctx, scope } = props\r\n const [historyOpen, setHistoryOpen] = useState(false)\r\n\r\n const view = readDeliverables(useProjectionValue(ctx, scope?.sessionId, DELIVERABLES_KEY))\r\n\r\n // Capability absent — the optional unit never registered. Hide, don't nag.\r\n if (view === undefined) return null\r\n\r\n // Optional click-to-preview: rows degrade to plain text where the sidebar\r\n // opener is absent (the opener resolves the session cwd per click).\r\n const open = sidebarFileOpener(ctx, scope?.sessionId)\r\n\r\n const latestPaths = view.latest?.paths ?? []\r\n const history = historyPaths(view.sessionPaths, latestPaths)\r\n\r\n if (latestPaths.length === 0 && view.sessionTotal === 0) {\r\n return createElement(\r\n 'div',\r\n { style: SECTION_STYLE, 'data-dsh-brief-sidebar': 'deliverables-section' },\r\n createElement('div', { style: HEADER_STYLE }, t('section.deliverables')),\r\n createElement(\r\n 'div',\r\n {\r\n style: {\r\n margin: '0 auto',\r\n padding: 24,\r\n maxWidth: 460,\r\n textAlign: 'center',\r\n color: 'var(--dsw-alias-label-tertiary)',\r\n lineHeight: 1.7,\r\n fontSize: 12,\r\n },\r\n },\r\n createElement('div', { style: { marginBottom: 6, color: 'var(--dsw-alias-label-secondary)' } }, t('deliverables.empty')),\r\n createElement('div', null, t('deliverables.emptyHint')),\r\n ),\r\n )\r\n }\r\n\r\n return createElement(\r\n 'div',\r\n { style: SECTION_STYLE, 'data-dsh-brief-sidebar': 'deliverables-section' },\r\n createElement('div', { style: HEADER_STYLE }, t('section.deliverables')),\r\n // 当前 turn 一组:只有真改过东西才起标题,否则“本回合改动 · 0”反而口舌。\r\n latestPaths.length > 0 && createElement(GroupHeader, {\r\n text: expandCount(t('deliverables.currentTurn'), latestPaths.length),\r\n marker: 'deliverables-current-group',\r\n }),\r\n createElement(\r\n 'ul',\r\n { style: LIST_STYLE },\r\n latestPaths.map(path => createElement(PathRow, { key: path, path, t, open })),\r\n ),\r\n history.length > 0 && createElement(FoldToggle, {\r\n label: expandCount(t('deliverables.history'), history.length),\r\n open: historyOpen,\r\n marker: 'deliverables-history-toggle',\r\n onToggle: () => { setHistoryOpen(current => !current) },\r\n }),\r\n // 列表有上限:开关行说的是折叠区收了多少条,附注说会话一共改过多少个。\r\n history.length > 0 && view.sessionTotal > view.sessionPaths.length && createElement(GroupCaption, {\r\n text: expandTotal(t('deliverables.historyCapped'), view.sessionTotal),\r\n marker: 'deliverables-history-capped',\r\n }),\r\n historyOpen && createElement(\r\n 'ul',\r\n { style: LIST_STYLE },\r\n history.map(path => createElement(PathRow, { key: path, path, t, open })),\r\n ),\r\n )\r\n}\r\n","/**\r\n * The `dshSummarySkillUsage` projection — reading it.\r\n *\r\n * The unit is registered by THIS plugin's host half (key `dshSummarySkillUsage`):\r\n * the skills this session actually loaded through the host's `skill` tool. It\r\n * answers a different question from `memorySlots`/`memoryRecall` — those say\r\n * what the model was *told*, this says which instruction packs it *pulled*.\r\n *\r\n * The module is deliberately PURE — no React, no context, no IO — so the\r\n * narrowing is testable directly, exactly like `deliverables.ts`.\r\n *\r\n * Reading discipline (the same three-way split every brief section uses):\r\n * - `undefined` = the capability is ABSENT (host half never registered, older\r\n * composition without the projection registry, or a frame drifted beyond\r\n * repair) → the section hides;\r\n * - `session: []` = the honest empty state (the `skill` tool exists on all six\r\n * supported lines; this session simply has not loaded anything yet);\r\n * - a malformed entry is dropped, never thrown — one bad row must not blank\r\n * the whole list.\r\n */\r\nimport { SKILL_USAGE_KEY } from '../../projection/keys'\r\nimport type { SkillUsageEntryView, SkillUsageView } from '../../projection/keys'\r\n\r\n/** The key this plugin's client half subscribes to (re-exported for callers). */\r\nexport { SKILL_USAGE_KEY }\r\n\r\n/** Whether a value is a non-negative safe integer (the view's counter shape). */\r\nfunction isCounter(value: unknown): value is number {\r\n return typeof value === 'number' && Number.isSafeInteger(value) && value >= 0\r\n}\r\n\r\n/** Narrow one skill tally; `undefined` = malformed, dropped. */\r\nfunction readEntry(value: unknown): SkillUsageEntryView | undefined {\r\n if (value === null || typeof value !== 'object' || Array.isArray(value)) return undefined\r\n const raw = value as Record<string, unknown>\r\n if (typeof raw['name'] !== 'string' || raw['name'].length === 0) return undefined\r\n if (!isCounter(raw['count']) || !isCounter(raw['lastTurn'])) return undefined\r\n return { name: raw['name'], count: raw['count'], lastTurn: raw['lastTurn'] }\r\n}\r\n\r\n/**\r\n * The latest-turn bucket, or `null` when it is absent OR drifted. A drifted\r\n * bucket only costs the \"本轮\" tag, so it degrades instead of voiding the view.\r\n */\r\nfunction readLatest(value: unknown): SkillUsageView['latest'] {\r\n if (value === null || typeof value !== 'object' || Array.isArray(value)) return null\r\n const raw = value as Record<string, unknown>\r\n if (!isCounter(raw['turn']) || !Array.isArray(raw['names'])) return null\r\n return { turn: raw['turn'], names: raw['names'].filter((n): n is string => typeof n === 'string' && n.length > 0) }\r\n}\r\n\r\n/**\r\n * The available-skill list of a frame, or `[]` when the frame carries none.\r\n *\r\n * Absent-by-age is the important case: a host half older than this reader\r\n * publishes no `available` field at all, and that must NOT void the whole view\r\n * — the session's references are still true. Only a drifted (non-array) value\r\n * reads as \"nothing known\", never as \"nothing available\".\r\n */\r\nfunction readAvailable(value: unknown): readonly string[] {\r\n if (!Array.isArray(value)) return []\r\n return value.filter((n): n is string => typeof n === 'string' && n.length > 0)\r\n}\r\n\r\n/**\r\n * Narrow a raw projection value into a skill-usage view.\r\n *\r\n * @param value - the raw `unknown` snapshot of the `dshSummarySkillUsage` face.\r\n * @returns the validated view, or `undefined` when the capability is absent.\r\n */\r\nexport function readSkillUsage(value: unknown): SkillUsageView | undefined {\r\n if (value === null || typeof value !== 'object' || Array.isArray(value)) return undefined\r\n const raw = value as Record<string, unknown>\r\n // The counters and the list are the contract; their drift means the frame was\r\n // written by a different shape than this reader speaks.\r\n if (!Array.isArray(raw['session'])) return undefined\r\n if (!isCounter(raw['sessionTotal']) || !isCounter(raw['callTotal'])) return undefined\r\n const session: SkillUsageEntryView[] = []\r\n for (const entry of raw['session']) {\r\n const narrowed = readEntry(entry)\r\n if (narrowed !== undefined) session.push(narrowed)\r\n }\r\n const available = readAvailable(raw['available'])\r\n // The count rides with the list; without a list there is no count to trust.\r\n const availableCount = available.length === 0 ? 0 : (isCounter(raw['availableCount']) ? raw['availableCount'] : available.length)\r\n return {\r\n latest: readLatest(raw['latest']),\r\n session,\r\n sessionTotal: raw['sessionTotal'],\r\n callTotal: raw['callTotal'],\r\n available,\r\n availableCount,\r\n }\r\n}\r\n\r\n/**\r\n * The available list minus the names already shown as referenced.\r\n *\r\n * One skill must not occupy a row in both groups: the reference row is the\r\n * stronger fact, and a duplicate under \"available\" would read as \"the model\r\n * had a choice it didn't make\".\r\n *\r\n * @param available - the session's current catalog names, in catalog order.\r\n * @param referenced - names the fold counted as loaded or invoked.\r\n * @returns the remaining catalog names, order preserved.\r\n */\r\nexport function availableExcept(available: readonly string[], referenced: readonly string[]): string[] {\r\n const seen = new Set(referenced)\r\n return available.filter(name => !seen.has(name))\r\n}\r\n\r\n/**\r\n * Fill both placeholders of a template. `expandCount` only speaks `{count}`, and\r\n * this section's footer carries a second number on purpose: the capped list\r\n * needs the truthful distinct total next to the load count.\r\n *\r\n * @param template - a locale string carrying `{count}` and/or `{total}`.\r\n * @param count - the `{count}` value.\r\n * @param total - the `{total}` value.\r\n * @returns the filled string.\r\n */\r\nexport function expandPair(template: string, count: number, total: number): string {\r\n return template.replace('{count}', String(count)).replace('{total}', String(total))\r\n}\r\n","/**\r\n * The skill-usage section: the `dshSummarySkillUsage` projection drawn as one\r\n * part of the summary tab.\r\n *\r\n * Where `MemoryRecallSection` answers \"what memories did the model see\", this\r\n * answers \"which instruction packs entered the context, and which ones were on\r\n * the menu\". Two groups, deliberately not merged:\r\n *\r\n * - **已引用** — the skill's instructions reached the conversation, either\r\n * because the model called the `skill` tool or because the user invoked it\r\n * directly (the host then injects `<skill_content>` and tells the model not\r\n * to call the tool — reading only the tool would miss over half of those\r\n * sessions, measured on 250 real ones).\r\n * - **本会话可用** — the session's current catalog. Available is NOT used: the\r\n * model may never touch any of these, so it is collapsed behind a counted\r\n * toggle and never mixed into the reference rows.\r\n *\r\n * Like the deliverables section this is an OPTIONAL capability on both sides:\r\n * no projection registry (or a host half that never registered the unit) means\r\n * the client reads capability absence and the section hides. No settings switch\r\n * gates it either — the list is a read-only fact about the session, not a\r\n * preference.\r\n *\r\n * Two contracts this row honours, both learned on the recall section:\r\n * - **no native `title` attribute** — it paints an unskinable tooltip that\r\n * overlaps the plugin's own bubble; nothing here needs one;\r\n * - **colours from `--dsw-alias-*` tokens only** (skin contract).\r\n */\r\nimport { createElement } from 'react'\r\nimport { useState } from 'react'\r\nimport type { CSSProperties, ReactNode } from 'react'\r\nimport type { Context } from '@deepseek-ai/cordis'\r\nimport { SKILL_USAGE_KEY } from '../../projection/keys'\r\nimport { useProjectionValue } from '../use-projection'\r\nimport { availableExcept, expandPair, readSkillUsage } from './skill-usage'\r\nimport { GroupCaption, GroupHeader, FoldToggle } from './FoldToggle'\r\nimport { expandCount } from '../locales'\r\n\r\nexport interface SkillUsageSectionProps {\r\n /** The DSH locale lookup, passed down from `apply`. */\r\n t: (key: string) => string\r\n /** The client root context (the tab body's only way to reach services). */\r\n ctx?: Context\r\n /** The session this tab is scoped to. */\r\n scope?: { readonly sessionId?: string }\r\n}\r\n\r\nconst SECTION_STYLE: CSSProperties = {\r\n flexShrink: 0,\r\n borderBottom: '1px solid var(--dsw-alias-border-secondary)',\r\n}\r\n\r\nconst HEADER_STYLE: CSSProperties = {\r\n padding: '10px 12px 0',\r\n color: 'var(--dsw-alias-label-secondary)',\r\n fontSize: 12,\r\n fontWeight: 600,\r\n}\r\n\r\nconst LIST_STYLE: CSSProperties = {\r\n listStyle: 'none',\r\n margin: 0,\r\n padding: '6px 0',\r\n display: 'flex',\r\n flexDirection: 'column',\r\n}\r\n\r\nconst ROW_STYLE: CSSProperties = {\r\n display: 'flex',\r\n alignItems: 'baseline',\r\n gap: 8,\r\n padding: '6px 12px',\r\n}\r\n\r\n/** The skill name: primary-ish but never the loudest thing in the row. */\r\nconst NAME_STYLE: CSSProperties = {\r\n minWidth: 0,\r\n overflowWrap: 'anywhere',\r\n color: 'var(--dsw-alias-label-secondary)',\r\n}\r\n\r\n/** The per-skill load tally, tertiary so the name stays the reading target. */\r\nconst COUNT_STYLE: CSSProperties = {\r\n flexShrink: 0,\r\n color: 'var(--dsw-alias-label-tertiary)',\r\n fontSize: 11,\r\n}\r\n\r\n/** The \"本轮\" pill: same form as the deliverables codeplan tag. */\r\nconst TAG_STYLE: CSSProperties = {\r\n flexShrink: 0,\r\n color: 'var(--dsw-alias-label-tertiary)',\r\n border: '1px solid var(--dsw-alias-label-tertiary)',\r\n borderRadius: 999,\r\n padding: '0 6px',\r\n fontSize: 11,\r\n lineHeight: '16px',\r\n whiteSpace: 'nowrap',\r\n}\r\n\r\nconst FOOTER_STYLE: CSSProperties = {\r\n padding: '0 12px 10px',\r\n color: 'var(--dsw-alias-label-tertiary)',\r\n fontSize: 11,\r\n}\r\n\r\nconst EMPTY_STYLE: CSSProperties = {\r\n margin: '0 auto',\r\n padding: 24,\r\n maxWidth: 460,\r\n textAlign: 'center',\r\n color: 'var(--dsw-alias-label-tertiary)',\r\n lineHeight: 1.7,\r\n fontSize: 12,\r\n}\r\n\r\n/**\r\n * The skill-usage section. The subscription is unconditional (a plain listener,\r\n * not IO); the view decides whether anything is drawn.\r\n *\r\n * @param props - translation, client context, session scope.\r\n */\r\nexport function SkillUsageSection(props: SkillUsageSectionProps): ReactNode {\r\n const { t, ctx, scope } = props\r\n const [availableOpen, setAvailableOpen] = useState(false)\r\n\r\n const view = readSkillUsage(useProjectionValue(ctx, scope?.sessionId, SKILL_USAGE_KEY))\r\n\r\n // Capability absent — the optional unit never registered. Hide, don't nag.\r\n if (view === undefined) return null\r\n\r\n const referenced = view.session.map(entry => entry.name)\r\n // 可用组只列未被引用的那些:同一个技能不该占两行。\r\n const rest = availableExcept(view.available, referenced)\r\n const latestNames = view.latest?.names ?? []\r\n\r\n return createElement(\r\n 'div',\r\n { style: SECTION_STYLE, 'data-dsh-brief-sidebar': 'skill-usage-section' },\r\n createElement('div', { style: HEADER_STYLE }, t('section.skillUsage')),\r\n view.session.length === 0 && createElement(\r\n 'div',\r\n { style: EMPTY_STYLE },\r\n createElement('div', { style: { marginBottom: 6, color: 'var(--dsw-alias-label-secondary)' } }, t('skillUsage.empty')),\r\n createElement('div', null, t('skillUsage.emptyHint')),\r\n ),\r\n view.session.length > 0 && createElement(GroupHeader, {\r\n text: expandCount(t('skillUsage.invokedGroup'), view.session.length),\r\n marker: 'skill-usage-invoked-group',\r\n }),\r\n createElement(\r\n 'ul',\r\n { style: LIST_STYLE },\r\n view.session.map(entry => createElement(\r\n 'li',\r\n { key: entry.name, style: ROW_STYLE, 'data-dsh-brief-sidebar': 'skill-usage-row' },\r\n createElement('span', { style: NAME_STYLE }, entry.name),\r\n createElement('span', { style: COUNT_STYLE }, expandPair(t('skillUsage.uses'), entry.count, entry.count)),\r\n latestNames.includes(entry.name) && createElement('span', { style: TAG_STYLE }, t('skillUsage.latestTag')),\r\n )),\r\n ),\r\n rest.length > 0 && createElement(FoldToggle, {\r\n label: expandCount(t('skillUsage.availableGroup'), rest.length),\r\n open: availableOpen,\r\n marker: 'skill-usage-available-toggle',\r\n onToggle: () => { setAvailableOpen(current => !current) },\r\n }),\r\n // 清单有上限:开关行说收了多少个名字,附注说这一帧真发了多少。\r\n rest.length > 0 && view.availableCount > view.available.length && createElement(GroupCaption, {\r\n text: expandCount(t('skillUsage.availableCapped'), view.availableCount),\r\n marker: 'skill-usage-available-capped',\r\n }),\r\n availableOpen && createElement(\r\n 'ul',\r\n { style: LIST_STYLE },\r\n rest.map(name => createElement(\r\n 'li',\r\n { key: name, style: ROW_STYLE, 'data-dsh-brief-sidebar': 'skill-usage-available-row' },\r\n createElement('span', { style: NAME_STYLE }, name),\r\n )),\r\n ),\r\n // 列表有上限,页脚说真数:加载次数与去重后的技能数各归各。\r\n view.session.length > 0 && createElement('div', { style: FOOTER_STYLE }, expandPair(t('skillUsage.count'), view.callTotal, view.sessionTotal)),\r\n )\r\n}\r\n","/**\r\n * The `memorySlots` projection — reading it.\r\n *\r\n * The projection unit is registered by `dsh-prime-memory` (key `memorySlots`,\r\n * wire view `{rev, count, openCount, slots[]}`); this plugin does NOT depend\r\n * on it — when the unit is not registered the client reads `undefined` from\r\n * `faceOf` and the section hides. This module is the read side of that\r\n * contract and is deliberately PURE — no React, no context, no IO — so the\r\n * narrowing can be tested directly.\r\n *\r\n * Forward compatibility: the shipped view carries `{id, title, kind, status,\r\n * priority}` only. A future prime-memory release may add `body`/`refs` to the\r\n * wire view (its projection plan keeps that door open); those fields are\r\n * narrowed opportunistically — present and well-formed → kept, absent or\r\n * malformed → dropped — so the section renders them without a brief-sidebar\r\n * change, and a malformed extra field can never blank the section.\r\n */\r\n\r\n/** The projection key `dsh-prime-memory` registers (its canonical constant). */\r\nexport const MEMORY_SLOTS_KEY = 'memorySlots'\r\n\r\n/** One slot of the wire view. */\r\nexport interface MemorySlotView {\r\n readonly id: string\r\n readonly title: string\r\n /** One of prime-memory's `SLOT_KINDS`: rule / todo / anchor / pointer. */\r\n readonly kind: string\r\n /** One of prime-memory's `SLOT_STATUSES`: open / done / dropped / expired. */\r\n readonly status: string\r\n /** 0–100; higher wins the activation competition. */\r\n readonly priority: number\r\n /** Slot body, once prime-memory exposes it on the wire (truncated at render). */\r\n readonly body?: string\r\n /** Reference targets, once prime-memory exposes them on the wire. */\r\n readonly refs?: readonly string[]\r\n /**\r\n * record_id 引用的展示解析(v0.5.0 契约:ref → `[type] 名称简述`),由\r\n * prime-memory 在投影帧构建时解析;路径/URL 类引用不产生条目。存在才收。\r\n */\r\n readonly refViews?: readonly SlotRefView[]\r\n}\r\n\r\n/** 一条 record_id 引用的展示解析(与 prime-memory 的 SlotRefView 同形)。 */\r\nexport interface SlotRefView {\r\n readonly ref: string\r\n readonly title: string\r\n}\r\n\r\n/** The whole wire view of one frame. */\r\nexport interface MemorySlotsView {\r\n readonly rev: number\r\n readonly count: number\r\n readonly openCount: number\r\n readonly slots: readonly MemorySlotView[]\r\n}\r\n\r\n/**\r\n * Narrow a raw projection value into a memory-slots view.\r\n *\r\n * Two outcomes are kept apart, mirroring the deliverables read side:\r\n * - `undefined` — the capability is ABSENT (prime-memory is not in the\r\n * composition, or no frame has carried the key yet), or the frame is\r\n * malformed beyond repair (a shape drift must not blank the whole tab);\r\n * - a view — the projection is live. A view with `slots: []` IS the empty\r\n * state: prime-memory publishes as soon as the unit registers, so \"present\r\n * but empty\" is a real value, not a sentinel.\r\n *\r\n * Malformed slot entries are dropped rather than thrown on (trusted-Host\r\n * value, defensive display), like `readTodos`.\r\n *\r\n * @param value - the raw `unknown` snapshot of the `memorySlots` face.\r\n * @returns the validated view, or `undefined` when the capability is absent.\r\n */\r\nexport function readSlots(value: unknown): MemorySlotsView | undefined {\r\n if (value === null || typeof value !== 'object' || Array.isArray(value)) return undefined\r\n const raw = value as Record<string, unknown>\r\n if (!isCounter(raw['rev']) || !isCounter(raw['count']) || !isCounter(raw['openCount'])) return undefined\r\n if (!Array.isArray(raw['slots'])) return undefined\r\n const slots: MemorySlotView[] = []\r\n for (const entry of raw['slots']) {\r\n const slot = readSlot(entry)\r\n if (slot !== undefined) slots.push(slot)\r\n }\r\n return { rev: raw['rev'], count: raw['count'], openCount: raw['openCount'], slots }\r\n}\r\n\r\n/** Whether a value is a non-negative safe integer (the view's counter shape). */\r\nfunction isCounter(value: unknown): value is number {\r\n return typeof value === 'number' && Number.isSafeInteger(value) && value >= 0\r\n}\r\n\r\n/** Narrow one slot entry; `undefined` = malformed, dropped. */\r\nfunction readSlot(value: unknown): MemorySlotView | undefined {\r\n if (value === null || typeof value !== 'object' || Array.isArray(value)) return undefined\r\n const raw = value as Record<string, unknown>\r\n if (typeof raw['id'] !== 'string' || raw['id'].length === 0) return undefined\r\n if (typeof raw['title'] !== 'string') return undefined\r\n if (typeof raw['kind'] !== 'string' || typeof raw['status'] !== 'string') return undefined\r\n if (typeof raw['priority'] !== 'number') return undefined\r\n const slot: { -readonly [K in keyof MemorySlotView]: MemorySlotView[K] } = {\r\n id: raw['id'],\r\n title: raw['title'],\r\n kind: raw['kind'],\r\n status: raw['status'],\r\n priority: raw['priority'],\r\n }\r\n if (typeof raw['body'] === 'string' && raw['body'].length > 0) slot.body = raw['body']\r\n if (Array.isArray(raw['refs'])) {\r\n const refs = raw['refs'].filter((ref): ref is string => typeof ref === 'string' && ref.length > 0)\r\n if (refs.length > 0) slot.refs = refs\r\n }\r\n if (Array.isArray(raw['refViews'])) {\r\n const views: SlotRefView[] = []\r\n for (const entry of raw['refViews']) {\r\n if (entry === null || typeof entry !== 'object' || Array.isArray(entry)) continue\r\n const view = entry as Record<string, unknown>\r\n if (typeof view['ref'] !== 'string' || view['ref'].length === 0) continue\r\n if (typeof view['title'] !== 'string' || view['title'].length === 0) continue\r\n views.push({ ref: view['ref'], title: view['title'] })\r\n }\r\n if (views.length > 0) slot.refViews = views\r\n }\r\n return slot\r\n}\r\n\r\n/** The body length at which the section truncates (full text rides the title tooltip). */\r\nexport const BODY_TRUNCATE_AT = 120\r\n\r\n/**\r\n * One-line truncation for a slot body. Already-short bodies pass through;\r\n * longer ones are cut at the limit with an ellipsis.\r\n */\r\nexport function truncateBody(body: string, limit = BODY_TRUNCATE_AT): string {\r\n const flat = body.replaceAll(/\\s+/g, ' ').trim()\r\n return flat.length <= limit ? flat : `${flat.slice(0, limit)}…`\r\n}\r\n","/**\r\n * Structural views of the `configForms` settings seam (DSH 0.1.7+).\r\n *\r\n * The settings card and the memory-section gate consume only these members of\r\n * the `ConfigForm` handle that `configForms.get(entryId)` returns, so the real\r\n * `@deepseek-ai/dsh-client-ui-settings/client` type graph is never imported —\r\n * the same reason `use-projection.ts` declares its own session faces and\r\n * `dock-shadow.tsx` its own slots face.\r\n *\r\n * `configForms` serves the STORED doc: a `.volatile()` field arrives as a\r\n * plain value here (the host unwraps the live refs before persistence), so\r\n * the client reads a plain config shape.\r\n */\r\n\r\n/** One snapshot of an entry's stored config. */\r\nexport interface SettingsScopeSnapshot<T> {\r\n status: 'loading' | 'ready' | 'unavailable'\r\n value: T | undefined\r\n revision: number | undefined\r\n /** Whether the current face may write (a read-only seat disables the controls). */\r\n writable: boolean\r\n}\r\n\r\n/** The `ConfigForm` handle face this plugin uses. */\r\nexport interface SettingsScope<T> {\r\n getSnapshot(): SettingsScopeSnapshot<T>\r\n subscribe(listener: () => void): () => void\r\n set(field: string, value: unknown): Promise<boolean>\r\n unset(field: string): Promise<boolean>\r\n}\r\n\r\n/** Structural view of the `configForms` cordis service, keyed by entry id. */\r\nexport interface ConfigFormsLike {\r\n get<T>(entryId: string): SettingsScope<T>\r\n}\r\n\r\n/**\r\n * This plugin's entry config, as the client reads it. Only the fields the\r\n * browser half consumes are declared; the schema (node half `Config`) owns\r\n * the full surface.\r\n */\r\nexport interface BriefClientConfig {\r\n /** Whether the summary tab renders the memory-slots section (default: off). */\r\n showMemorySlots?: boolean\r\n /** Whether the summary tab renders the session-recall section (default: on). */\r\n showMemoryRecall?: boolean\r\n}\r\n\r\n/**\r\n * The slots switch's default. Flipped to OFF alongside prime-memory's\r\n * `memoryRecall` projection: a hand-pinned resident convention is a real\r\n * feature, but listing it as a permanent card in the summary pane taught\r\n * users to read \"memory\" as \"resident\", which is the opposite of how recall\r\n * works. The section still only appears when the `memorySlots` projection\r\n * exists, and stays one click away for anyone who wants it back.\r\n */\r\nexport const DEFAULT_SHOW_MEMORY_SLOTS = false\r\n\r\n/** The session-recall switch's default (on: it is the honest memory view). */\r\nexport const DEFAULT_SHOW_MEMORY_RECALL = true\r\n\r\n/**\r\n * Resolve the switch from one snapshot (pure; testable). Any\r\n * cannot-answer shape falls back to {@link DEFAULT_SHOW_MEMORY_SLOTS}; an\r\n * explicit `false` is the only off.\r\n */\r\nexport function resolveShowMemorySlots(\r\n snapshot: SettingsScopeSnapshot<BriefClientConfig> | undefined,\r\n): boolean {\r\n if (snapshot === undefined || snapshot.status !== 'ready') return DEFAULT_SHOW_MEMORY_SLOTS\r\n return snapshot.value?.showMemorySlots === true\r\n}\r\n\r\n/**\r\n * Resolve the session-recall switch from one snapshot (pure; testable).\r\n * Any cannot-answer shape falls back to {@link DEFAULT_SHOW_MEMORY_RECALL};\r\n * an explicit `false` is the only off.\r\n */\r\nexport function resolveShowMemoryRecall(\r\n snapshot: SettingsScopeSnapshot<BriefClientConfig> | undefined,\r\n): boolean {\r\n if (snapshot === undefined || snapshot.status !== 'ready') return DEFAULT_SHOW_MEMORY_RECALL\r\n return snapshot.value?.showMemoryRecall !== false\r\n}\r\n","/**\r\n * The shared `configForms` subscription behind this plugin's section switches.\r\n *\r\n * Both memory sections (pinned slots / session recall) gate on one boolean of\r\n * this plugin's entry config. The plumbing — defensive scope resolution,\r\n * `useSyncExternalStore`, and a stable absent-snapshot — is identical, so it\r\n * lives here once; each section passes its own pure resolver, which is what\r\n * the unit tests pin.\r\n *\r\n * A host without `configForms` (or a scope still loading) degrades to the\r\n * resolver's default instead of throwing inside a render.\r\n */\r\nimport { useCallback, useMemo, useSyncExternalStore } from 'react'\r\nimport type { Context } from '@deepseek-ai/cordis'\r\nimport type { BriefClientConfig, ConfigFormsLike, SettingsScopeSnapshot } from '../scope-face'\r\n\r\n/**\r\n * The snapshot served while no config scope is reachable — every resolver\r\n * maps it to its own default.\r\n */\r\nconst ABSENT_SNAPSHOT: SettingsScopeSnapshot<BriefClientConfig> = {\r\n status: 'unavailable',\r\n value: undefined,\r\n revision: undefined,\r\n writable: false,\r\n}\r\n\r\n/** A no-op unsubscribe source, kept as one identity so the absent-scope\r\n * subscription never thrashes (a store contract requires a disposer). */\r\nconst NO_SUBSCRIBE = (): (() => void) => () => {}\r\n\r\n/**\r\n * Read one config switch, live.\r\n *\r\n * @param ctx - the client root context handed to the tab body.\r\n * @param resolve - pure snapshot → boolean resolver (owns the default).\r\n * @returns the resolved switch value.\r\n */\r\nexport function useConfigFlag(\r\n ctx: Context | undefined,\r\n resolve: (snapshot: SettingsScopeSnapshot<BriefClientConfig> | undefined) => boolean,\r\n): boolean {\r\n const scope = useMemo(() => {\r\n if (ctx === undefined) return undefined\r\n const configForms = ctx.get('configForms') as ConfigFormsLike | undefined\r\n if (configForms === undefined || typeof configForms.get !== 'function') return undefined\r\n return configForms.get<BriefClientConfig>('dsh-brief-sidebar')\r\n }, [ctx])\r\n\r\n const subscribe = useCallback(\r\n (listener: () => void) => scope?.subscribe(listener) ?? NO_SUBSCRIBE(),\r\n [scope],\r\n )\r\n const getSnapshot = useCallback(\r\n () => scope?.getSnapshot() ?? ABSENT_SNAPSHOT,\r\n [scope],\r\n )\r\n\r\n return resolve(useSyncExternalStore(subscribe, getSnapshot, getSnapshot))\r\n}\r\n","/**\r\n * The memory-slots section: the `memorySlots` projection drawn as the third\r\n * part of the summary tab (fixed last: 进展 → 产物 → 记忆).\r\n *\r\n * TWO gates, both fail-open to \"hidden\", so a host without dsh-prime-memory\r\n * paints nothing here:\r\n *\r\n * 1. **The switch.** This plugin's entry config (`configForms` → entry\r\n * `dsh-brief-sidebar`, field `showMemorySlots`, default OFF — the pinned\r\n * list moved out of the summary pane's way in favour of the session-recall\r\n * section). When the config face cannot answer (service absent, scope not\r\n * ready, field unset) the default applies — see `scope-face.ts`.\r\n * 2. **The capability.** The `memorySlots` projection must exist for the\r\n * session; `undefined` hides the section entirely, exactly like the\r\n * optional deliverables section.\r\n *\r\n * Colours come from `--dsw-alias-*` tokens only (skin contract, enforced by\r\n * `tests/purity.spec.ts`).\r\n */\r\nimport { createElement } from 'react'\r\nimport type { CSSProperties, ReactNode } from 'react'\r\nimport type { Context } from '@deepseek-ai/cordis'\r\nimport {\r\n MEMORY_SLOTS_KEY,\r\n readSlots,\r\n truncateBody,\r\n} from './memory-slots'\r\nimport type { MemorySlotView, MemorySlotsView } from './memory-slots'\r\nimport { resolveShowMemorySlots } from '../scope-face'\r\nimport { useConfigFlag } from './use-config-flag'\r\nimport { useProjectionValue } from '../use-projection'\r\nimport { expandCount } from '../locales'\r\n\r\nexport interface MemorySlotsSectionProps {\r\n /** The DSH locale lookup, passed down from `apply`. */\r\n t: (key: string) => string\r\n /** The client root context (the tab body's only way to reach services). */\r\n ctx?: Context\r\n /** The session this tab is scoped to. */\r\n scope?: { readonly sessionId?: string }\r\n}\r\n\r\nconst SECTION_STYLE: CSSProperties = {\r\n flexShrink: 0,\r\n borderBottom: '1px solid var(--dsw-alias-border-secondary)',\r\n}\r\n\r\nconst HEADER_STYLE: CSSProperties = {\r\n padding: '10px 12px 0',\r\n color: 'var(--dsw-alias-label-secondary)',\r\n fontSize: 12,\r\n fontWeight: 600,\r\n}\r\n\r\nconst LIST_STYLE: CSSProperties = {\r\n listStyle: 'none',\r\n margin: 0,\r\n padding: '6px 0',\r\n display: 'flex',\r\n flexDirection: 'column',\r\n}\r\n\r\nconst ROW_STYLE: CSSProperties = {\r\n display: 'flex',\r\n alignItems: 'flex-start',\r\n gap: 8,\r\n padding: '6px 12px',\r\n}\r\n\r\nconst TITLE_STYLE: CSSProperties = {\r\n minWidth: 0,\r\n overflowWrap: 'anywhere',\r\n color: 'var(--dsw-alias-label-secondary)',\r\n}\r\n\r\nconst META_STYLE: CSSProperties = {\r\n flexShrink: 0,\r\n color: 'var(--dsw-alias-label-tertiary)',\r\n fontSize: 11,\r\n lineHeight: '18px',\r\n whiteSpace: 'nowrap',\r\n}\r\n\r\n/** The kind pill: same form as the codeplan pill, tertiary emphasis. */\r\nconst KIND_STYLE: CSSProperties = {\r\n flexShrink: 0,\r\n color: 'var(--dsw-alias-label-tertiary)',\r\n border: '1px solid var(--dsw-alias-label-tertiary)',\r\n borderRadius: 999,\r\n padding: '0 6px',\r\n fontSize: 11,\r\n lineHeight: '16px',\r\n whiteSpace: 'nowrap',\r\n}\r\n\r\n/** The status pill: filled tint for an open slot, plain text otherwise. */\r\nconst STATUS_OPEN_STYLE: CSSProperties = {\r\n flexShrink: 0,\r\n color: 'var(--dsw-alias-label-primary)',\r\n border: '1px solid var(--dsw-alias-label-secondary)',\r\n borderRadius: 999,\r\n padding: '0 6px',\r\n fontSize: 11,\r\n lineHeight: '16px',\r\n whiteSpace: 'nowrap',\r\n}\r\n\r\nconst STATUS_SETTLED_STYLE: CSSProperties = {\r\n ...STATUS_OPEN_STYLE,\r\n color: 'var(--dsw-alias-label-tertiary)',\r\n border: '1px solid var(--dsw-alias-label-tertiary)',\r\n}\r\n\r\nconst BODY_STYLE: CSSProperties = {\r\n margin: 0,\r\n minWidth: 0,\r\n overflowWrap: 'anywhere',\r\n color: 'var(--dsw-alias-label-tertiary)',\r\n fontSize: 12,\r\n lineHeight: '18px',\r\n}\r\n\r\nconst REFS_STYLE: CSSProperties = {\r\n ...BODY_STYLE,\r\n fontSize: 11,\r\n}\r\n\r\nconst TOTAL_STYLE: CSSProperties = {\r\n padding: '6px 12px 10px',\r\n color: 'var(--dsw-alias-label-tertiary)',\r\n fontSize: 12,\r\n}\r\n\r\nconst EMPTY_STYLE: CSSProperties = {\r\n margin: '0 auto',\r\n padding: 24,\r\n maxWidth: 460,\r\n textAlign: 'center',\r\n color: 'var(--dsw-alias-label-tertiary)',\r\n lineHeight: 1.7,\r\n fontSize: 12,\r\n}\r\n\r\n/** Locale key per known slot status; unknown statuses fall back to the raw wire value. */\r\nconst STATUS_KEY: Record<string, string> = {\r\n open: 'slots.status.open',\r\n done: 'slots.status.done',\r\n dropped: 'slots.status.dropped',\r\n expired: 'slots.status.expired',\r\n}\r\n\r\n/**\r\n * One slot row: kind pill, title (full body rides the tooltip), status pill,\r\n * priority; body line underneath when the wire view carries it; refs as\r\n * resolved 名称简述 (record_id → title) with the raw refs on the tooltip, or\r\n * raw refs when the host has not resolved them.\r\n */\r\nfunction SlotRow(props: { slot: MemorySlotView; t: (key: string) => string }): ReactNode {\r\n const { slot, t } = props\r\n const statusLabel = STATUS_KEY[slot.status] === undefined ? slot.status : t(STATUS_KEY[slot.status])\r\n const title = slot.body === undefined ? slot.title : `${slot.title} — ${slot.body}`\r\n const refsLine = slot.refViews !== undefined\r\n ? slot.refViews.map((view) => view.title).join(' · ')\r\n : slot.refs !== undefined\r\n ? slot.refs.join(' · ')\r\n : undefined\r\n return createElement(\r\n 'li',\r\n { style: ROW_STYLE },\r\n createElement('span', { style: KIND_STYLE }, slot.kind),\r\n createElement(\r\n 'div',\r\n { style: { minWidth: 0, flex: '1 1 auto', display: 'flex', flexDirection: 'column', gap: 2 } },\r\n createElement('span', { style: TITLE_STYLE, title }, slot.title),\r\n slot.body !== undefined && createElement('p', { style: BODY_STYLE }, truncateBody(slot.body)),\r\n refsLine !== undefined\r\n && createElement(\r\n 'p',\r\n {\r\n style: REFS_STYLE,\r\n title: slot.refs !== undefined ? slot.refs.join('\\n') : undefined,\r\n },\r\n refsLine,\r\n ),\r\n ),\r\n createElement('span', { style: META_STYLE }, `P${slot.priority}`),\r\n createElement(\r\n 'span',\r\n { style: slot.status === 'open' ? STATUS_OPEN_STYLE : STATUS_SETTLED_STYLE },\r\n statusLabel,\r\n ),\r\n )\r\n}\r\n\r\n/**\r\n * Subscribe to this plugin's entry config and resolve the slots switch.\r\n * Plumbing lives in `use-config-flag`; the default (off) lives in the resolver.\r\n *\r\n * @param ctx - the client root context handed to the tab body.\r\n * @returns whether the memory-slots section may render at all.\r\n */\r\nexport function useShowMemorySlots(ctx: Context | undefined): boolean {\r\n return useConfigFlag(ctx, resolveShowMemorySlots)\r\n}\r\n\r\n/**\r\n * The memory-slots section. Both hooks run unconditionally (a conditional\r\n * hook order would break the moment the switch flips); the switch only\r\n * decides whether the resolved view paints.\r\n * @param props - translation, client context, session scope.\r\n */\r\nexport function MemorySlotsSection(props: MemorySlotsSectionProps): ReactNode {\r\n const { t, ctx, scope } = props\r\n\r\n const show = useShowMemorySlots(ctx)\r\n const view: MemorySlotsView | undefined = readSlots(\r\n useProjectionValue(ctx, scope?.sessionId, MEMORY_SLOTS_KEY),\r\n )\r\n\r\n // Switched off at the settings faces — the section is willed away, not\r\n // empty (an empty state would claim prime-memory answered when the user\r\n // simply closed the section).\r\n if (show === false) return null\r\n\r\n // Capability absent (prime-memory not in the composition, no frame yet) —\r\n // hide, don't nag; the memory panel remains the write surface.\r\n if (view === undefined) return null\r\n\r\n if (view.slots.length === 0) {\r\n return createElement(\r\n 'div',\r\n { style: SECTION_STYLE, 'data-dsh-brief-sidebar': 'memory-slots-section' },\r\n createElement('div', { style: HEADER_STYLE }, t('section.memorySlots')),\r\n createElement(\r\n 'div',\r\n { style: EMPTY_STYLE },\r\n createElement('div', { style: { marginBottom: 6, color: 'var(--dsw-alias-label-secondary)' } }, t('slots.empty')),\r\n createElement('div', null, t('slots.emptyHint')),\r\n ),\r\n )\r\n }\r\n\r\n return createElement(\r\n 'div',\r\n { style: SECTION_STYLE, 'data-dsh-brief-sidebar': 'memory-slots-section' },\r\n createElement('div', { style: HEADER_STYLE }, t('section.memorySlots')),\r\n createElement(\r\n 'ul',\r\n { style: LIST_STYLE },\r\n view.slots.map(slot => createElement(SlotRow, { key: slot.id, slot, t })),\r\n ),\r\n createElement(\r\n 'div',\r\n { style: TOTAL_STYLE },\r\n expandCount(t('slots.openCount'), view.openCount),\r\n ),\r\n )\r\n}\r\n","/**\r\n * The `memoryRecall` projection — reading it.\r\n *\r\n * The projection unit is registered by `dsh-prime-memory` (key `memoryRecall`,\r\n * wire view `{rev, sessionId, count, items[]}`): the memories this session has\r\n * actually injected. Unlike\r\n * `memorySlots` (pinned, resident conventions written by hand), this set is\r\n * NOT resident — it is the at-a-glance answer to \"what did the model see\".\r\n * It survives compaction on purpose: `compact` only marks the entries whose\r\n * text left the context as `superseded` (and `/clear` empties the set), so a\r\n * retired row keeps its strike-through instead of vanishing.\r\n *\r\n * This plugin does NOT depend on prime-memory: with the unit unregistered the\r\n * client reads `undefined` from the face and the section hides. The module is\r\n * deliberately PURE — no React, no context, no IO — so the narrowing is\r\n * testable directly, exactly like `memory-slots.ts`.\r\n */\r\n\r\n/** The projection key `dsh-prime-memory` registers (its canonical constant). */\r\nexport const MEMORY_RECALL_KEY = 'memoryRecall'\r\n\r\n/** One recalled memory of the wire view. */\r\nexport interface MemoryRecallItem {\r\n readonly id: string\r\n /** prime-memory's memory type: work_fact / work_method / episodic / … */\r\n readonly type: string\r\n /** First line of the record body (prime-memory truncates for the wire). */\r\n readonly title: string\r\n /** 0–100, the record's own priority. */\r\n readonly priority: number\r\n /** \"When should this surface\" phrases, once prime-memory exposes them. */\r\n readonly scenario?: readonly string[]\r\n /**\r\n * The last mark a HUMAN put on this record: `-1` (declared obsolete) or\r\n * `0..5` (relevance). Absent means never rated — which is NOT the same as\r\n * a zero. prime-memory publishes it on the `memoryRecall` view so the row\r\n * can show the existing mark without a second round-trip.\r\n */\r\n readonly rating?: number\r\n /**\r\n * The record body, whitespace-trimmed and capped by prime-memory. The hover\r\n * bubble reads it straight off the frame — no second round-trip. Absent on\r\n * frames published before that field existed, so the row falls back to\r\n * `title` and the bubble says it has no body.\r\n */\r\n readonly body?: string\r\n /**\r\n * prime-memory says this record has been retired (soft-deleted). It stays in\r\n * the list because its text is still part of what the model saw — and because\r\n * the retirement is the human's verdict; the row just draws a strike-through.\r\n * Absent means alive.\r\n */\r\n readonly retired?: boolean\r\n /**\r\n * The text of this recall has been replaced by a compaction summary, so it is\r\n * no longer in the model's context. Orthogonal to `retired` (both can be set).\r\n * The section hides these by default and reports the count in its footer;\r\n * a retired row is the exception and stays visible. Absent means still in context.\r\n */\r\n readonly superseded?: boolean\r\n}\r\n\r\n/** The whole wire view of one frame. */\r\nexport interface MemoryRecallView {\r\n readonly rev: number\r\n readonly sessionId: string\r\n /** Total recalled-and-alive count; `items` may be a capped prefix of it. */\r\n readonly count: number\r\n /** Most recently injected first. */\r\n readonly items: readonly MemoryRecallItem[]\r\n}\r\n\r\n/** Whether a value is a non-negative safe integer (the view's counter shape). */\r\nfunction isCounter(value: unknown): value is number {\r\n return typeof value === 'number' && Number.isSafeInteger(value) && value >= 0\r\n}\r\n\r\n/** Narrow one item entry; `undefined` = malformed, dropped. */\r\nfunction readItem(value: unknown): MemoryRecallItem | undefined {\r\n if (value === null || typeof value !== 'object' || Array.isArray(value)) return undefined\r\n const raw = value as Record<string, unknown>\r\n if (typeof raw['id'] !== 'string' || raw['id'].length === 0) return undefined\r\n if (typeof raw['type'] !== 'string' || typeof raw['title'] !== 'string') return undefined\r\n if (typeof raw['priority'] !== 'number') return undefined\r\n const item: { -readonly [K in keyof MemoryRecallItem]: MemoryRecallItem[K] } = {\r\n id: raw['id'],\r\n type: raw['type'],\r\n title: raw['title'],\r\n priority: raw['priority'],\r\n }\r\n if (Array.isArray(raw['scenario'])) {\r\n const phrases = raw['scenario'].filter((s): s is string => typeof s === 'string' && s.length > 0)\r\n if (phrases.length > 0) item.scenario = phrases\r\n }\r\n // A drifted rating (non-number, or outside the -1..5 domain) is dropped\r\n // rather than trusted: the row then simply looks unrated.\r\n const rating = raw['rating']\r\n if (typeof rating === 'number' && Number.isInteger(rating) && rating >= -1 && rating <= 5) item.rating = rating\r\n // A non-string body is dropped rather than trusted: the bubble then says so.\r\n if (typeof raw['body'] === 'string') item.body = raw['body']\r\n // Only true is written; anything else reads back as absent (= alive).\r\n if (raw['retired'] === true) item.retired = true\r\n // Same discipline for the compaction marker: absent means \"still in context\".\r\n if (raw['superseded'] === true) item.superseded = true\r\n return item\r\n}\r\n\r\n/**\r\n * Narrow a raw projection value into a recall view.\r\n *\r\n * `undefined` means the capability is ABSENT (prime-memory not in the\r\n * composition, or no frame carried the key) or the frame drifted beyond repair;\r\n * a view with `items: []` IS the honest empty state (prime-memory publishes as\r\n * soon as the unit registers). Malformed items are dropped, never thrown on.\r\n *\r\n * @param value - the raw `unknown` snapshot of the `memoryRecall` face.\r\n * @returns the validated view, or `undefined` when the capability is absent.\r\n */\r\nexport function readRecall(value: unknown): MemoryRecallView | undefined {\r\n if (value === null || typeof value !== 'object' || Array.isArray(value)) return undefined\r\n const raw = value as Record<string, unknown>\r\n if (!isCounter(raw['rev']) || !isCounter(raw['count'])) return undefined\r\n if (typeof raw['sessionId'] !== 'string') return undefined\r\n if (!Array.isArray(raw['items'])) return undefined\r\n const items: MemoryRecallItem[] = []\r\n for (const entry of raw['items']) {\r\n const item = readItem(entry)\r\n if (item !== undefined) items.push(item)\r\n }\r\n return { rev: raw['rev'], sessionId: raw['sessionId'], count: raw['count'], items }\r\n}\r\n","/**\r\n * The write channel back into `dsh-prime-memory`: rating one recalled memory.\r\n *\r\n * This is the FIRST write this plugin performs, and deliberately the only one.\r\n * Reading goes through the host's projection face (`memoryRecall`); there is no\r\n * projection for writes, so the mark travels over prime-memory's own client RPC\r\n * route — `POST /dsh-memory/rpc/<method>`, the same envelope its panel uses.\r\n * That is a cross-plugin HTTP contract, so everything that makes it safe to\r\n * hold lives here:\r\n *\r\n * - **Optional by construction.** A composition without dsh-prime-memory, or an\r\n * older one without this endpoint, answers 404/405. That is reported as\r\n * `absent`, and the section stops offering the control instead of failing on\r\n * every click.\r\n * - **No invented semantics.** `-1` and `0..5` are prime-memory's domain; this\r\n * module refuses anything else locally so a bad click cannot reach the server.\r\n * - **Nothing is optimistic about retirement.** The caller only hides a row\r\n * after the server confirms `retired` — a lost request must not silently\r\n * remove a memory from view.\r\n *\r\n * `fetch` is injected so the parse and the status mapping are testable without\r\n * a browser.\r\n */\r\n\r\n/** The route prime-memory's server half registers for its client RPC surface. */\r\nexport const RECALL_FEEDBACK_ROUTE = '/dsh-memory/rpc/recall-feedback'\r\n\r\n/** A relevance mark (`0..5`) or `-1` = \"this is obsolete\", prime-memory's domain. */\r\nexport const FEEDBACK_SCORES = [-1, 0, 1, 2, 3, 4, 5] as const\r\nexport type FeedbackScore = (typeof FEEDBACK_SCORES)[number]\r\n\r\n/** Whether a value is a score this plugin is allowed to send. */\r\nexport function isFeedbackScore(value: unknown): value is FeedbackScore {\r\n return typeof value === 'number' && (FEEDBACK_SCORES as readonly number[]).includes(value)\r\n}\r\n\r\n/** How long to wait before giving up on one click. */\r\nexport const FEEDBACK_TIMEOUT_MS = 8_000\r\n\r\n/**\r\n * Outcome of one rating attempt.\r\n *\r\n * `absent` is NOT an error to show the user — it means the capability is not\r\n * there (prime-memory missing or older), and the caller should stop offering\r\n * the control. `rejected` carries prime-memory's own reason (e.g. \"this memory\r\n * is no longer in the session's recall set\"), which is worth surfacing.\r\n */\r\nexport type FeedbackOutcome =\r\n | {\r\n readonly status: 'sent'\r\n readonly retired: boolean\r\n readonly announced: boolean\r\n readonly mean: number\r\n readonly rated: number\r\n }\r\n | { readonly status: 'rejected'; readonly reason: string }\r\n | { readonly status: 'absent' }\r\n | { readonly status: 'transport'; readonly reason: string }\r\n\r\n/** The minimal fetch shape this module needs (global `fetch` satisfies it). */\r\nexport interface FeedbackFetch {\r\n (url: string, init: {\r\n method: 'POST'\r\n headers: Record<string, string>\r\n body: string\r\n signal?: AbortSignal\r\n }): Promise<{\r\n readonly ok: boolean\r\n readonly status: number\r\n json(): Promise<unknown>\r\n }>\r\n}\r\n\r\nexport interface FeedbackRequest {\r\n readonly sessionId: string\r\n readonly id: string\r\n readonly score: FeedbackScore\r\n}\r\n\r\n/** Whether a status code means \"no such route\" rather than \"the call failed\". */\r\nfunction isAbsentStatus(status: number): boolean {\r\n return status === 404 || status === 405 || status === 501\r\n}\r\n\r\n/** The host's RpcResult envelope, narrowed enough to read the two branches. */\r\nfunction parseEnvelope(value: unknown): { ok: true; value: Record<string, unknown> } | { ok: false; reason: string } | undefined {\r\n if (value === null || typeof value !== 'object' || Array.isArray(value)) return undefined\r\n const raw = value as Record<string, unknown>\r\n if (raw['ok'] === true && raw['value'] !== null && typeof raw['value'] === 'object') {\r\n return { ok: true, value: raw['value'] as Record<string, unknown> }\r\n }\r\n if (raw['ok'] === false) {\r\n const err = raw['error']\r\n const message = err !== null && typeof err === 'object'\r\n ? (err as Record<string, unknown>)['message']\r\n : undefined\r\n return { ok: false, reason: typeof message === 'string' && message.length > 0 ? message : 'rejected' }\r\n }\r\n return undefined\r\n}\r\n\r\nfunction num(value: unknown): number {\r\n return typeof value === 'number' && Number.isFinite(value) ? value : 0\r\n}\r\n\r\n/**\r\n * Send one rating.\r\n *\r\n * Never throws: every failure mode comes back as a discriminated outcome, so a\r\n * click cannot break the render.\r\n */\r\nexport async function sendRecallFeedback(\r\n fetchImpl: FeedbackFetch | undefined,\r\n request: FeedbackRequest,\r\n): Promise<FeedbackOutcome> {\r\n if (typeof fetchImpl !== 'function') return { status: 'absent' }\r\n if (request.sessionId.length === 0 || request.id.length === 0) {\r\n return { status: 'rejected', reason: 'missing-session-or-id' }\r\n }\r\n if (!isFeedbackScore(request.score)) return { status: 'rejected', reason: 'invalid-score' }\r\n\r\n const abort = typeof AbortController === 'function' ? new AbortController() : undefined\r\n const timer = abort === undefined\r\n ? undefined\r\n : setTimeout(() => { abort.abort() }, FEEDBACK_TIMEOUT_MS)\r\n try {\r\n const response = await fetchImpl(RECALL_FEEDBACK_ROUTE, {\r\n method: 'POST',\r\n headers: { 'content-type': 'application/json' },\r\n body: JSON.stringify({ sessionId: request.sessionId, id: request.id, score: request.score }),\r\n ...(abort === undefined ? {} : { signal: abort.signal }),\r\n })\r\n if (!response.ok) {\r\n return isAbsentStatus(response.status)\r\n ? { status: 'absent' }\r\n : { status: 'transport', reason: `HTTP ${response.status}` }\r\n }\r\n let envelope: unknown\r\n try {\r\n envelope = await response.json()\r\n } catch {\r\n return { status: 'transport', reason: 'unparseable-response' }\r\n }\r\n const parsed = parseEnvelope(envelope)\r\n if (parsed === undefined) return { status: 'transport', reason: 'unexpected-envelope' }\r\n if (parsed.ok === false) return { status: 'rejected', reason: parsed.reason }\r\n const value = parsed.value\r\n const rating = value['rating'] !== null && typeof value['rating'] === 'object'\r\n ? value['rating'] as Record<string, unknown>\r\n : {}\r\n return {\r\n status: 'sent',\r\n retired: value['retired'] === true,\r\n announced: value['announced'] === true,\r\n mean: num(rating['mean']),\r\n rated: num(rating['rated']),\r\n }\r\n } catch (err) {\r\n const aborted = err instanceof Error && (err.name === 'AbortError' || err.name === 'TimeoutError')\r\n return { status: 'transport', reason: aborted ? 'timeout' : (err instanceof Error ? err.message : 'network') }\r\n } finally {\r\n if (timer !== undefined) clearTimeout(timer)\r\n }\r\n}\r\n","/**\r\n * The hover bubble for one recalled memory — the whole body, straight off the\r\n * projection frame, no second round-trip.\r\n *\r\n * Two shapes are load-bearing here:\r\n *\r\n * - **Stateless.** The section owns when a bubble opens and which row it shows;\r\n * this only draws what it is handed. No hooks, no buttons, no timers.\r\n * - **`position: fixed`.** The summary tab body is `overflow: auto`, so a box\r\n * absolutely positioned inside a row gets clipped by the scroller's border as\r\n * soon as the row sits near an edge. Fixed positioning plus `bubblePos`\r\n * clamping keeps the bubble inside the viewport instead, and anchored to the\r\n * row's *left* so it never lands on the list it describes.\r\n *\r\n * `pointerEvents: 'none'` is not decoration: a bubble that captures the mouse\r\n * would strand the very row it hovers over and leave the section unable to\r\n * receive the click that selects it.\r\n *\r\n * Colours come from `--dsw-alias-*` tokens only (skin contract, asserted by\r\n * `tests/purity.spec.ts`). There is no shadow token in that family, so the\r\n * bubble separates from the list by border and background layer rather than by\r\n * elevation — a literal `box-shadow` colour would break the contract.\r\n */\r\nimport { createElement } from 'react'\r\nimport type { CSSProperties, ReactNode } from 'react'\r\nimport type { MemoryRecallItem } from './memory-recall'\r\nimport { expandCount } from '../locales'\r\n\r\n/** Bubble box size, mirrored by `bubblePos`'s defaults (keep the two in sync). */\r\nconst BUBBLE_W = 360\r\nconst BUBBLE_H = 220\r\n/** Viewport gutter kept on every side when clamping. */\r\nconst EDGE = 8\r\n\r\n/**\r\n * Clamp the bubble into the viewport.\r\n *\r\n * It opens to the **left** of the row on purpose. The sidebar is right-docked\r\n * and only a few hundred pixels wide, so the old \"anchor + 8\" placement dropped\r\n * the box straight onto the row it came from — covering that row's rating strip\r\n * (the bubble is click-transparent, so the buttons stayed clickable *under* it:\r\n * blind-clicking a score is not an option). Opening left puts the text over the\r\n * chat area and leaves the whole list readable.\r\n *\r\n * Order of preference: left of the row → right of the row (only when the row\r\n * sits so far left that the box would run off the window) → clamped inside the\r\n * viewport. Pure and total.\r\n *\r\n * @param r - the hovered row's rect (`top`/`left`/`right` are read).\r\n * @param vw - viewport width (`window.innerWidth`).\r\n * @param vh - viewport height (`window.innerHeight`).\r\n * @param w - bubble width.\r\n * @param h - bubble height.\r\n * @returns fixed-position coordinates for the bubble.\r\n */\r\nexport function bubblePos(\r\n r: { top: number; left: number; right?: number },\r\n vw: number,\r\n vh: number,\r\n w = BUBBLE_W,\r\n h = BUBBLE_H,\r\n): { top: number; left: number } {\r\n const right = r.right ?? r.left\r\n const preferred = r.left - w - EDGE\r\n const fallback = right + EDGE\r\n const roomOnLeft = preferred >= EDGE\r\n const roomOnRight = fallback + w <= vw - EDGE\r\n const unplaced = Math.min(preferred, fallback)\r\n const left = roomOnLeft\r\n ? preferred\r\n : roomOnRight\r\n ? fallback\r\n : unplaced\r\n return {\r\n left: Math.max(EDGE, Math.min(left, vw - w - EDGE)),\r\n top: Math.max(EDGE, Math.min(r.top, vh - h - EDGE)),\r\n }\r\n}\r\n\r\nconst BUBBLE_STYLE: CSSProperties = {\r\n position: 'fixed',\r\n pointerEvents: 'none',\r\n zIndex: 1000,\r\n maxWidth: BUBBLE_W,\r\n maxHeight: '45vh',\r\n overflow: 'hidden',\r\n padding: '8px 10px',\r\n borderRadius: 6,\r\n background: 'var(--dsw-alias-bg-layer-3)',\r\n border: '1px solid var(--dsw-alias-border-l2)',\r\n color: 'var(--dsw-alias-label-primary)',\r\n fontSize: 12,\r\n lineHeight: '17px',\r\n}\r\n\r\nconst TYPE_STYLE: CSSProperties = {\r\n display: 'inline-block',\r\n marginBottom: 4,\r\n color: 'var(--dsw-alias-label-tertiary)',\r\n border: '1px solid var(--dsw-alias-label-tertiary)',\r\n borderRadius: 999,\r\n padding: '0 6px',\r\n fontSize: 11,\r\n lineHeight: '16px',\r\n}\r\n\r\nconst BODY_STYLE: CSSProperties = {\r\n minWidth: 0,\r\n overflowWrap: 'anywhere',\r\n whiteSpace: 'pre-wrap',\r\n color: 'var(--dsw-alias-label-primary)',\r\n}\r\n\r\nconst SCENARIO_STYLE: CSSProperties = {\r\n marginTop: 4,\r\n minWidth: 0,\r\n overflowWrap: 'anywhere',\r\n color: 'var(--dsw-alias-label-tertiary)',\r\n fontSize: 11,\r\n lineHeight: '16px',\r\n}\r\n\r\nconst FOOTER_STYLE: CSSProperties = {\r\n marginTop: 4,\r\n color: 'var(--dsw-alias-label-tertiary)',\r\n fontSize: 11,\r\n lineHeight: '16px',\r\n}\r\n\r\n/** A retired record stays readable in the bubble, just marked. */\r\nconst STALE_BODY_STYLE: CSSProperties = { ...BODY_STYLE, textDecoration: 'line-through' }\r\n\r\n/**\r\n * The bubble itself.\r\n *\r\n * @param props - the item to show, the clamped coordinates, and the lookup.\r\n * @returns the bubble element.\r\n */\r\nexport function RecallBubble(props: {\r\n item: MemoryRecallItem\r\n pos: { top: number; left: number }\r\n t: (key: string) => string\r\n}): ReactNode {\r\n const { item, pos, t } = props\r\n const scenario = item.scenario === undefined ? undefined : item.scenario.join(' · ')\r\n const stale = item.retired === true\r\n const rated = item.rating !== undefined && Number.isInteger(item.rating) && item.rating >= 0 && item.rating <= 5\r\n const foot = [\r\n `P${item.priority}`,\r\n rated ? expandCount(t('recall.rated'), item.rating) : undefined,\r\n stale ? t('recall.obsoleted') : undefined,\r\n ].filter((s): s is string => s !== undefined).join(' · ')\r\n return createElement(\r\n 'div',\r\n {\r\n style: { ...BUBBLE_STYLE, top: pos.top, left: pos.left },\r\n 'data-dsh-brief-sidebar': 'recall-bubble',\r\n role: 'tooltip',\r\n },\r\n createElement('span', { style: TYPE_STYLE }, item.type),\r\n createElement(\r\n 'div',\r\n { style: stale ? STALE_BODY_STYLE : BODY_STYLE },\r\n // No body on this frame (an older prime-memory): say so rather than\r\n // quietly showing only the first line as if it were everything.\r\n item.body ?? `${item.title}\\n${t('recall.noBody')}`,\r\n ),\r\n scenario !== undefined && createElement('div', { style: SCENARIO_STYLE }, scenario),\r\n createElement('div', { style: FOOTER_STYLE }, foot),\r\n )\r\n}\r\n","/**\r\n * The session-recall section: what this session actually injected, drawn as a\r\n * part of the summary tab — and now annotatable.\r\n *\r\n * Where `MemorySlotsSection` lists hand-pinned resident conventions (written\r\n * once, injected every turn), this one answers a different question: **which\r\n * memories did the model see this session, and which are still in context**.\r\n * The set is not resident — it is relevance recall. Compaction does NOT drop\r\n * entries: prime-memory marks the ones whose text a summary replaced as\r\n * `superseded`, and this section hides those (the footer keeps the count).\r\n * Retired rows are the exception and stay visible. Only `/clear` empties the list.\r\n *\r\n * TWO gates, both fail-open to \"hidden\", mirroring the slots section:\r\n *\r\n * 1. **The switch.** This plugin's entry config (`configForms` → field\r\n * `showMemoryRecall`, default on).\r\n * 2. **The capability.** The `memoryRecall` projection must exist for the\r\n * session; `undefined` hides the section entirely — a composition without\r\n * dsh-prime-memory paints nothing here.\r\n *\r\n * Rating is a THIRD gate, and it fails open the same way: the mark goes back to\r\n * prime-memory over its client RPC route (`recall-feedback.ts`). A composition\r\n * whose prime-memory predates that endpoint answers 404, and the section falls\r\n * back to the read-only list it used to be — no per-click error, no dead button.\r\n *\r\n * What the marks mean (prime-memory owns the semantics, this only offers them):\r\n * - `0..5` — how relevant this recall actually was. Aggregated; it does NOT\r\n * rewrite any ranking on its own.\r\n * - `-1` — \"this memory is obsolete\": prime-memory retires the record (soft\r\n * delete, restorable from its panel) and tells the model next turn. That is\r\n * why it takes a second confirming click and says so on the button.\r\n *\r\n * A retired row does NOT leave this list: the retirement is the human's verdict\r\n * on that memory, so the row stays, struck through and unselectable, until the\r\n * session is cleared. A `superseded` row (its text was replaced by a summary, so\r\n * it is no longer in context) IS hidden, with the count kept in the footer.\r\n * Hovering a row opens one bubble with the whole body (`RecallBubble`)\r\n * — the row itself is clamped to two lines and the sidebar is narrow.\r\n *\r\n * Colours come from `--dsw-alias-*` tokens only (skin contract, enforced by\r\n * `tests/purity.spec.ts`).\r\n */\r\nimport { createElement } from 'react'\r\nimport { useCallback, useEffect, useRef, useState } from 'react'\r\nimport type { CSSProperties, ReactNode } from 'react'\r\nimport type { Context } from '@deepseek-ai/cordis'\r\nimport { MEMORY_RECALL_KEY, readRecall } from './memory-recall'\r\nimport type { MemoryRecallItem, MemoryRecallView } from './memory-recall'\r\nimport { FEEDBACK_SCORES, sendRecallFeedback } from './recall-feedback'\r\nimport type { FeedbackFetch, FeedbackScore } from './recall-feedback'\r\nimport { RecallBubble, bubblePos } from './RecallBubble'\r\nimport { resolveShowMemoryRecall } from '../scope-face'\r\nimport { useConfigFlag } from './use-config-flag'\r\nimport { useProjectionValue } from '../use-projection'\r\nimport { expandCount } from '../locales'\r\nimport { FoldToggle, GroupHeader } from './FoldToggle'\r\n\r\nexport interface MemoryRecallSectionProps {\r\n /** The DSH locale lookup, passed down from `apply`. */\r\n t: (key: string) => string\r\n /** The client root context (the tab body's only way to reach services). */\r\n ctx?: Context\r\n /** The session this tab is scoped to. */\r\n scope?: { readonly sessionId?: string }\r\n /**\r\n * The transport for rating. Defaults to the page's `fetch`; injectable so the\r\n * click path is testable without a browser.\r\n */\r\n fetchImpl?: FeedbackFetch\r\n}\r\n\r\nconst SECTION_STYLE: CSSProperties = {\r\n flexShrink: 0,\r\n borderBottom: '1px solid var(--dsw-alias-border-secondary)',\r\n}\r\n\r\nconst HEADER_STYLE: CSSProperties = {\r\n padding: '10px 12px 0',\r\n color: 'var(--dsw-alias-label-secondary)',\r\n fontSize: 12,\r\n fontWeight: 600,\r\n}\r\n\r\nconst HINT_STYLE: CSSProperties = {\r\n padding: '2px 12px 0',\r\n color: 'var(--dsw-alias-label-tertiary)',\r\n fontSize: 11,\r\n lineHeight: '15px',\r\n}\r\n\r\nconst LIST_STYLE: CSSProperties = {\r\n listStyle: 'none',\r\n margin: 0,\r\n padding: '6px 0',\r\n display: 'flex',\r\n flexDirection: 'column',\r\n}\r\n\r\nconst ROW_STYLE: CSSProperties = {\r\n display: 'flex',\r\n alignItems: 'flex-start',\r\n gap: 8,\r\n padding: '6px 12px',\r\n}\r\n\r\n/** Selected row: one hairline of accent, no colour literal (skin contract). */\r\nconst ROW_SELECTED_STYLE: CSSProperties = {\r\n ...ROW_STYLE,\r\n background: 'var(--dsw-alias-fill-quaternary)',\r\n}\r\n\r\n/** The type pill: same form as the slot kind pill, tertiary emphasis. */\r\nconst TYPE_STYLE: CSSProperties = {\r\n flexShrink: 0,\r\n color: 'var(--dsw-alias-label-tertiary)',\r\n border: '1px solid var(--dsw-alias-label-tertiary)',\r\n borderRadius: 999,\r\n padding: '0 6px',\r\n fontSize: 11,\r\n lineHeight: '16px',\r\n whiteSpace: 'nowrap',\r\n}\r\n\r\nconst TITLE_STYLE: CSSProperties = {\r\n minWidth: 0,\r\n color: 'var(--dsw-alias-label-secondary)',\r\n // Two lines, always the same height whatever the body says — the row keeps\r\n // its shape and the whole text rides the hover bubble instead.\r\n display: '-webkit-box',\r\n WebkitLineClamp: 2,\r\n WebkitBoxOrient: 'vertical',\r\n overflow: 'hidden',\r\n fontSize: 12,\r\n lineHeight: '17px',\r\n}\r\n\r\n/**\r\n * Struck-through text for a retired row. Colour drops to tertiary because a\r\n * dead entry must not compete with a live one for the eye.\r\n */\r\nconst STRIKE_STYLE: CSSProperties = {\r\n textDecoration: 'line-through',\r\n color: 'var(--dsw-alias-label-tertiary)',\r\n}\r\n\r\nconst SCENARIO_STYLE: CSSProperties = {\r\n margin: 0,\r\n minWidth: 0,\r\n overflowWrap: 'anywhere',\r\n color: 'var(--dsw-alias-label-tertiary)',\r\n fontSize: 11,\r\n lineHeight: '16px',\r\n}\r\n\r\nconst META_STYLE: CSSProperties = {\r\n flexShrink: 0,\r\n color: 'var(--dsw-alias-label-tertiary)',\r\n fontSize: 11,\r\n lineHeight: '18px',\r\n whiteSpace: 'nowrap',\r\n}\r\n\r\nconst FOOTER_STYLE: CSSProperties = {\r\n padding: '6px 12px 10px',\r\n color: 'var(--dsw-alias-label-tertiary)',\r\n fontSize: 12,\r\n}\r\n\r\nconst EMPTY_STYLE: CSSProperties = {\r\n margin: '0 auto',\r\n padding: 24,\r\n maxWidth: 460,\r\n textAlign: 'center',\r\n color: 'var(--dsw-alias-label-tertiary)',\r\n lineHeight: 1.7,\r\n fontSize: 12,\r\n}\r\n\r\nconst STRIP_STYLE: CSSProperties = {\r\n display: 'flex',\r\n flexWrap: 'wrap',\r\n gap: 4,\r\n marginTop: 4,\r\n}\r\n\r\nconst SCORE_BUTTON_STYLE: CSSProperties = {\r\n minWidth: 24,\r\n padding: '0 5px',\r\n height: 20,\r\n fontSize: 11,\r\n lineHeight: '18px',\r\n color: 'var(--dsw-alias-label-secondary)',\r\n background: 'none',\r\n border: '1px solid var(--dsw-alias-border-secondary)',\r\n borderRadius: 4,\r\n cursor: 'pointer',\r\n}\r\n\r\n/** The chosen mark: same box, filled so it survives a re-render without colour literals. */\r\nconst SCORE_ACTIVE_STYLE: CSSProperties = {\r\n ...SCORE_BUTTON_STYLE,\r\n border: '1px solid var(--dsw-alias-label-secondary)',\r\n color: 'var(--dsw-alias-label-primary)',\r\n}\r\n\r\n/** `-1` reads as an action, not a score: text instead of a number. */\r\nconst OBSOLETE_BUTTON_STYLE: CSSProperties = {\r\n ...SCORE_BUTTON_STYLE,\r\n minWidth: 0,\r\n whiteSpace: 'nowrap',\r\n}\r\n\r\nconst OBSOLETE_ARMED_STYLE: CSSProperties = {\r\n ...OBSOLETE_BUTTON_STYLE,\r\n border: '1px solid var(--dsw-alias-border-color-danger)',\r\n color: 'var(--dsw-alias-label-primary)',\r\n fontWeight: 600,\r\n}\r\n\r\nconst MARK_STYLE: CSSProperties = {\r\n marginTop: 2,\r\n color: 'var(--dsw-alias-label-tertiary)',\r\n fontSize: 11,\r\n lineHeight: '15px',\r\n}\r\n\r\nconst ERROR_STYLE: CSSProperties = {\r\n marginTop: 2,\r\n color: 'var(--dsw-alias-label-secondary)',\r\n fontSize: 11,\r\n lineHeight: '15px',\r\n overflowWrap: 'anywhere',\r\n}\r\n\r\n/**\r\n * The rating strip of one selected row: `-1` (two-step) plus `0..5`.\r\n *\r\n * Exported for tests — the section itself only mounts it for the selected row,\r\n * and a static render never has one selected.\r\n *\r\n * **Every click here must stop propagating.** The strip lives INSIDE the row,\r\n * and the row's own `onClick` toggles the selection — so an un-stopped click\r\n * deselects the row, this strip unmounts mid-gesture, and the `-1` button's\r\n * armed \"确认退场?\" state is rendered on a node that is already gone. That is\r\n * the whole \"按了没反应、也没有删除线\" report: the request was never sent, the\r\n * confirmation was never shown, the control simply vanished on the first press.\r\n * @param props - labels, current mark, and the click handlers.\r\n */\r\nexport function RatingStrip(props: {\r\n current: number | undefined\r\n pending: boolean\r\n armed: boolean\r\n obsoleteLabel: string\r\n confirmLabel: string\r\n whyLabel: string\r\n onScore(score: FeedbackScore): void\r\n}): ReactNode {\r\n const { current, pending, armed } = props\r\n // Clicks landing on the strip's gaps/padding count too: anything inside here\r\n // belongs to the strip, not to the row beneath it.\r\n const swallow = (e: { stopPropagation(): void }): void => { e.stopPropagation() }\r\n return createElement(\r\n 'div',\r\n {\r\n style: STRIP_STYLE,\r\n onClick: swallow,\r\n 'data-dsh-brief-sidebar': 'recall-rating-strip',\r\n },\r\n createElement(\r\n 'button',\r\n {\r\n type: 'button',\r\n style: armed ? OBSOLETE_ARMED_STYLE : OBSOLETE_BUTTON_STYLE,\r\n disabled: pending,\r\n // Before arming the tooltip explains the consequence; after, it asks.\r\n title: armed ? props.confirmLabel : props.whyLabel,\r\n onClick: (e: { stopPropagation(): void }) => {\r\n e.stopPropagation()\r\n props.onScore(-1)\r\n },\r\n },\r\n armed ? props.confirmLabel : props.obsoleteLabel,\r\n ),\r\n ...FEEDBACK_SCORES.filter(s => s >= 0).map(score => createElement(\r\n 'button',\r\n {\r\n key: score,\r\n type: 'button',\r\n style: current === score ? SCORE_ACTIVE_STYLE : SCORE_BUTTON_STYLE,\r\n disabled: pending,\r\n 'aria-pressed': current === score,\r\n onClick: (e: { stopPropagation(): void }) => {\r\n e.stopPropagation()\r\n props.onScore(score)\r\n },\r\n },\r\n String(score),\r\n )),\r\n )\r\n}\r\n\r\n/**\r\n * One recalled memory: type pill, first two lines of the body, its own\r\n * priority, and — once selected and still alive — the rating strip. Hovering\r\n * opens the bubble with the whole text; a retired row is struck through and\r\n * cannot be selected (there is nothing left to mark on a record prime-memory\r\n * has already retired).\r\n */\r\nfunction RecallRow(props: {\r\n item: MemoryRecallItem\r\n selected: boolean\r\n stale: boolean\r\n wasSuperseded: boolean\r\n pending: boolean\r\n armed: boolean\r\n mark: number | undefined\r\n error: string | undefined\r\n rating: boolean\r\n t: (key: string) => string\r\n onSelect(): void\r\n onScore(score: FeedbackScore): void\r\n onEnter(el: HTMLElement): void\r\n onLeave(): void\r\n}): ReactNode {\r\n const { item, selected, stale, wasSuperseded, mark, error, t } = props\r\n const scenario = item.scenario === undefined ? undefined : item.scenario.join(' · ')\r\n const markText = mark === undefined\r\n ? undefined\r\n : mark === -1\r\n ? t('recall.obsoleted')\r\n : expandCount(t('recall.rated'), mark)\r\n // A row prime-memory already retired but the human did not mark in this view\r\n // still needs the caption; when `mark === -1` the line above says the same\r\n // thing, so the two are mutually exclusive rather than doubled.\r\n const staleText = stale && mark !== -1 ? t('recall.obsoleted') : undefined\r\n const selectable = props.rating && !stale\r\n const titleStyle = stale ? { ...TITLE_STYLE, ...STRIKE_STYLE } : TITLE_STYLE\r\n return createElement(\r\n 'li',\r\n {\r\n style: selected && props.rating ? ROW_SELECTED_STYLE : ROW_STYLE,\r\n onClick: selectable ? props.onSelect : undefined,\r\n onMouseEnter: (e: { currentTarget: unknown }) => {\r\n const el = e.currentTarget\r\n if (el instanceof HTMLElement) props.onEnter(el)\r\n },\r\n onMouseLeave: () => { props.onLeave() },\r\n },\r\n createElement('span', { style: TYPE_STYLE }, item.type),\r\n createElement(\r\n 'div',\r\n { style: { minWidth: 0, flex: '1 1 auto', display: 'flex', flexDirection: 'column', gap: 2 } },\r\n createElement(\r\n 'span',\r\n // 不给原生 `title`:那会在泡泡之外再多一个宿主自己的深色提示框,两者内容重叠、\r\n // 样式不受皮肤契约管,反而把泡泡遮住。全文与使用场景现在都由 `RecallBubble` 承载。\r\n { style: titleStyle },\r\n item.title,\r\n ),\r\n scenario !== undefined && createElement(\r\n 'p',\r\n { style: stale ? { ...SCENARIO_STYLE, ...STRIKE_STYLE } : SCENARIO_STYLE },\r\n scenario,\r\n ),\r\n staleText !== undefined && createElement('span', { style: MARK_STYLE }, staleText),\r\n // “正文已被摘要取代”是行自己的事实,得写在行上:否则展开历史组后,\r\n // 读者只能靠位置猜哪一行不在上下文里。\r\n wasSuperseded && createElement(\r\n 'span',\r\n { style: TYPE_STYLE, 'data-dsh-brief-sidebar': 'recall-superseded-tag' },\r\n t('recall.supersededTag'),\r\n ),\r\n markText !== undefined && createElement('span', { style: MARK_STYLE }, markText),\r\n error !== undefined && createElement(\r\n 'span',\r\n { style: ERROR_STYLE },\r\n `${t('recall.failed')}${error}`,\r\n ),\r\n selected && !stale && props.rating && createElement(RatingStrip, {\r\n current: mark,\r\n pending: props.pending,\r\n armed: props.armed,\r\n obsoleteLabel: t('recall.obsolete'),\r\n confirmLabel: t('recall.obsoleteConfirm'),\r\n whyLabel: t('recall.obsoleteWhy'),\r\n onScore: props.onScore,\r\n }),\r\n ),\r\n createElement('span', { style: META_STYLE }, `P${item.priority}`),\r\n )\r\n}\r\n\r\n/** How long the `-1` button stays armed before reverting to its plain label. */\r\nconst ARM_WINDOW_MS = 5_000\r\n\r\n/** Delay before a hover opens its bubble (ms) — swiping past rows must not paint. */\r\nconst HOVER_DELAY_MS = 150\r\n\r\n/**\r\n * The session-recall section. All hooks run unconditionally (a conditional hook\r\n * order would break the moment the switch flips); the gates only decide whether\r\n * the resolved view paints and whether rows are clickable.\r\n * @param props - translation, client context, session scope, transport.\r\n */\r\nexport function MemoryRecallSection(props: MemoryRecallSectionProps): ReactNode {\r\n const { t, ctx, scope } = props\r\n const [selectedId, setSelectedId] = useState<string | undefined>(undefined)\r\n const [marks, setMarks] = useState<Record<string, number>>({})\r\n // Rows the human just marked obsolete in THIS view. prime-memory's `retired`\r\n // covers the ones retired earlier; these two sets union into \"draw a strike\".\r\n const [staleIds, setStaleIds] = useState<readonly string[]>([])\r\n const [hover, setHover] = useState<{ id: string; top: number; left: number; right: number } | undefined>(undefined)\r\n const pendingHover = useRef<ReturnType<typeof setTimeout> | null>(null)\r\n const [pendingId, setPendingId] = useState<string | undefined>(undefined)\r\n const [errors, setErrors] = useState<Record<string, string>>({})\r\n const [armed, setArmed] = useState(false)\r\n // Flipped once by a 404: the composition's prime-memory cannot take marks,\r\n // so the section goes back to being the plain read-only list it was.\r\n const [writeAbsent, setWriteAbsent] = useState(false)\r\n // 历史召回组默认折叠:它们已不在上下文里,但仍属于“本会话见过什么”的一部分。\r\n const [historyOpen, setHistoryOpen] = useState(false)\r\n\r\n const show = useConfigFlag(ctx, resolveShowMemoryRecall)\r\n const view: MemoryRecallView | undefined = readRecall(\r\n useProjectionValue(ctx, scope?.sessionId, MEMORY_RECALL_KEY),\r\n )\r\n\r\n const sessionId = scope?.sessionId ?? ''\r\n const rating = writeAbsent === false && sessionId.length > 0\r\n\r\n const rate = useCallback((id: string, score: FeedbackScore): void => {\r\n if (score === -1 && armed === false) {\r\n // Retirement is destructive-ish (soft delete + a notice to the model):\r\n // the first click only arms the button.\r\n setArmed(true)\r\n setTimeout(() => { setArmed(false) }, ARM_WINDOW_MS)\r\n return\r\n }\r\n if (pendingId !== undefined) return\r\n setArmed(false)\r\n setPendingId(id)\r\n const impl: FeedbackFetch | undefined = props.fetchImpl\r\n ?? (typeof fetch === 'function' ? (fetch as unknown as FeedbackFetch) : undefined)\r\n void sendRecallFeedback(impl, { sessionId, id, score }).then(outcome => {\r\n setPendingId(undefined)\r\n if (outcome.status === 'sent') {\r\n setMarks(current => ({ ...current, [id]: score }))\r\n setErrors(current => {\r\n const next = { ...current }\r\n delete next[id]\r\n return next\r\n })\r\n if (score === -1) setStaleIds(current => (current.includes(id) ? current : [...current, id]))\r\n setHover(undefined)\r\n if (score !== -1) setSelectedId(undefined)\r\n } else if (outcome.status === 'absent') {\r\n setWriteAbsent(true)\r\n setSelectedId(undefined)\r\n } else {\r\n setErrors(current => ({ ...current, [id]: outcome.reason }))\r\n }\r\n })\r\n }, [armed, pendingId, props.fetchImpl, sessionId])\r\n\r\n const onSelect = useCallback((id: string): void => {\r\n setArmed(false)\r\n setSelectedId(current => (current === id ? undefined : id))\r\n }, [])\r\n\r\n // One bubble at a time, and it opens on a delay: sweeping the mouse down the\r\n // list must not paint a bubble for every row it passes.\r\n const onEnter = useCallback((id: string, el: HTMLElement): void => {\r\n if (pendingHover.current !== null) clearTimeout(pendingHover.current)\r\n const rect = el.getBoundingClientRect()\r\n pendingHover.current = setTimeout(() => {\r\n pendingHover.current = null\r\n // The whole rect travels, not just its origin: `bubblePos` needs the row's\r\n // RIGHT edge to place the box outside the sidebar instead of on top of it.\r\n setHover({ id, top: rect.top, left: rect.left, right: rect.right })\r\n }, HOVER_DELAY_MS)\r\n }, [])\r\n\r\n const onLeave = useCallback((): void => {\r\n if (pendingHover.current !== null) {\r\n clearTimeout(pendingHover.current)\r\n pendingHover.current = null\r\n }\r\n setHover(undefined)\r\n }, [])\r\n\r\n // Unmounting mid-sweep would otherwise leave a timer that sets state on a\r\n // dead section.\r\n useEffect(() => () => {\r\n if (pendingHover.current !== null) clearTimeout(pendingHover.current)\r\n }, [])\r\n\r\n // Switched off at the settings faces — willed away, not empty.\r\n if (show === false) return null\r\n\r\n // Capability absent (prime-memory not in the composition, no frame yet).\r\n if (view === undefined) return null\r\n\r\n // Retired rows stay: that mark is the human's verdict, and the model did see them.\r\n // A `superseded` row is different — its text is no longer in context — so it is\r\n // hidden, and the footer reports the count so nothing disappears silently.\r\n const isStale = (item: MemoryRecallItem): boolean => item.retired === true || staleIds.includes(item.id)\r\n // 两组按“正文还在不在上下文”分:活跃 = 未取代(或被退场的例外,裁决凭证必须留下);\r\n // 其余历史 = 被摘要取代且未被裁决退场的,它们收进开关后面而不是只报个计数。\r\n const rows = view.items.filter(item => item.superseded !== true || item.retired === true)\r\n const historyRows = view.items.filter(item => item.superseded === true && item.retired !== true)\r\n const hidden = historyRows.length\r\n\r\n if (rows.length === 0) {\r\n return createElement(\r\n 'div',\r\n { style: SECTION_STYLE, 'data-dsh-brief-sidebar': 'memory-recall-section' },\r\n createElement('div', { style: HEADER_STYLE }, t('section.memoryRecall')),\r\n createElement(\r\n 'div',\r\n {\r\n style: EMPTY_STYLE,\r\n // 隐藏数为 0 时是真正的空态;否则这是“本轮确实召回过、但正文已被摘要替换”的告知。\r\n ...(hidden > 0 ? { 'data-dsh-brief-sidebar': 'recall-superseded-note' } : {}),\r\n },\r\n hidden > 0 ? expandCount(t('recall.supersededHidden'), hidden) : t('recall.empty'),\r\n ),\r\n // 空态下历史组仍要能展开:否则“全都被取代”的会话永远读不到自己召回过什么。\r\n historyRows.length > 0 && createElement(FoldToggle, {\r\n label: expandCount(t('recall.historyGroup'), historyRows.length),\r\n open: historyOpen,\r\n marker: 'recall-history-toggle',\r\n onToggle: () => { setHistoryOpen(current => !current) },\r\n }),\r\n historyOpen && createElement(\r\n 'ul',\r\n { style: LIST_STYLE },\r\n historyRows.map(item => createElement(RecallRow, {\r\n key: item.id,\r\n item,\r\n selected: false,\r\n stale: isStale(item),\r\n wasSuperseded: true,\r\n pending: false,\r\n armed: false,\r\n mark: undefined,\r\n error: undefined,\r\n rating: false,\r\n t,\r\n onSelect: () => {},\r\n onScore: () => {},\r\n onEnter: () => {},\r\n onLeave: () => {},\r\n })),\r\n ),\r\n )\r\n }\r\n\r\n return createElement(\r\n 'div',\r\n { style: SECTION_STYLE, 'data-dsh-brief-sidebar': 'memory-recall-section' },\r\n createElement('div', { style: HEADER_STYLE }, t('section.memoryRecall')),\r\n rating && createElement('div', { style: HINT_STYLE }, `${t('recall.rateHint')}${t('recall.strikeHint')}`),\r\n // 活跃组计数只说“仍在上下文”的那些,注入总数归页脚,两个数各说各的。\r\n rows.length > 0 && createElement(GroupHeader, {\r\n text: expandCount(t('recall.activeGroup'), rows.length),\r\n marker: 'recall-active-group',\r\n }),\r\n createElement(\r\n 'ul',\r\n { style: LIST_STYLE },\r\n rows.map(item => createElement(RecallRow, {\r\n key: item.id,\r\n item,\r\n selected: selectedId === item.id,\r\n stale: isStale(item),\r\n wasSuperseded: item.superseded === true,\r\n pending: pendingId === item.id,\r\n armed: armed && selectedId === item.id,\r\n mark: marks[item.id] ?? item.rating,\r\n error: errors[item.id],\r\n rating,\r\n t,\r\n onSelect: () => { onSelect(item.id) },\r\n onScore: (score: FeedbackScore) => { rate(item.id, score) },\r\n onEnter: (el: HTMLElement) => { onEnter(item.id, el) },\r\n onLeave,\r\n })),\r\n ),\r\n historyRows.length > 0 && createElement(FoldToggle, {\r\n label: expandCount(t('recall.historyGroup'), historyRows.length),\r\n open: historyOpen,\r\n marker: 'recall-history-toggle',\r\n onToggle: () => { setHistoryOpen(current => !current) },\r\n }),\r\n historyOpen && createElement(\r\n 'ul',\r\n { style: LIST_STYLE },\r\n historyRows.map(item => createElement(RecallRow, {\r\n key: item.id,\r\n item,\r\n // 历史行不开评分:退场与相关度都是对“还在上下文里的那条”的裁决,\r\n // 正文已被取代的行再标一次也不会回到上下文,只会让人以为还能救。\r\n selected: false,\r\n stale: isStale(item),\r\n wasSuperseded: true,\r\n pending: false,\r\n armed: false,\r\n mark: undefined,\r\n error: undefined,\r\n rating: false,\r\n t,\r\n onSelect: () => {},\r\n onScore: () => {},\r\n onEnter: () => {},\r\n onLeave: () => {},\r\n })),\r\n ),\r\n createElement(\r\n 'div',\r\n { style: FOOTER_STYLE },\r\n expandCount(t('recall.count'), view.count),\r\n hidden > 0 && createElement(\r\n 'div',\r\n { 'data-dsh-brief-sidebar': 'recall-superseded-note' },\r\n expandCount(t('recall.supersededHidden'), hidden),\r\n ),\r\n ),\r\n // The single bubble of this section. `typeof window` guard keeps a\r\n // non-DOM render (tests, SSR) from ever reaching the viewport maths.\r\n hover !== undefined && typeof window !== 'undefined'\r\n && (() => {\r\n const item = view.items.find(i => i.id === hover.id)\r\n if (item === undefined) return null\r\n return createElement(RecallBubble, {\r\n item,\r\n pos: bubblePos(hover, window.innerWidth, window.innerHeight),\r\n t,\r\n })\r\n })(),\r\n )\r\n}\r\n","/**\r\n * The summary tab body: the session's at-a-glance state, composed of sections.\r\n *\r\n * Section order: 进展 (the todos board) → 产物 (produced files, codeplan\r\n * artifacts marked inline) → 技能引用 (which skills this session loaded) →\r\n * 本会话召回 (what prime-memory injected into this session and compaction has\r\n * not overwritten) → 记忆槽位 (hand-pinned resident conventions, off by default).\r\n * Each section owns its own data chain and its own gating contract; this\r\n * component owns only the shell.\r\n *\r\n * Two better-sidebar contracts are honoured:\r\n *\r\n * 1. **Height contract.** The tab body mounts inside a full-height column flex\r\n * host whose `.paneBody` is a definite-height BLOCK scroll container. The\r\n * root declares `height: 100%` + `min-height: 0`, and the scrolling element\r\n * is an inner div — not the root. Sections are non-scrolling slices with a\r\n * bottom border; the inner div scrolls them all.\r\n * 2. **`visible` pause.** Nothing is drawn while the tab is not the active\r\n * one, so a hidden tab does not re-render on every projection frame.\r\n */\r\nimport { createElement } from 'react'\r\nimport type { CSSProperties, ReactNode } from 'react'\r\nimport type { Context } from '@deepseek-ai/cordis'\r\nimport { TodoSection } from './TodoBoardTab'\r\nimport type { TodoScope } from './TodoBoardTab'\r\nimport { DeliverablesSection } from './summary/DeliverablesSection'\r\nimport { SkillUsageSection } from './summary/SkillUsageSection'\r\nimport { MemorySlotsSection } from './summary/MemorySlotsSection'\r\nimport { MemoryRecallSection } from './summary/MemoryRecallSection'\r\n\r\nexport interface SummaryTabProps {\r\n /** The DSH locale lookup, passed down from `apply`. */\r\n t: (key: string) => string\r\n /** The client root context (the tab body's only way to reach services). */\r\n ctx?: Context\r\n /** The session this tab is scoped to. */\r\n scope?: TodoScope\r\n /** Whether the tab is the active one AND the panel is open. */\r\n visible?: boolean\r\n}\r\n\r\nconst ROOT_STYLE: CSSProperties = {\r\n display: 'flex',\r\n flexDirection: 'column',\r\n height: '100%',\r\n minHeight: 0,\r\n background: 'var(--dsw-alias-bg-layer-1)',\r\n color: 'var(--dsw-alias-label-primary)',\r\n font: 'inherit',\r\n fontSize: 13,\r\n}\r\n\r\nconst SCROLL_STYLE: CSSProperties = { flex: 1, minHeight: 0, overflow: 'auto' }\r\n\r\n/**\r\n * The summary tab.\r\n * @param props - translation, client context, session scope, visibility.\r\n */\r\nexport function SummaryTab(props: SummaryTabProps): ReactNode {\r\n const { t, ctx, scope, visible = true } = props\r\n\r\n // A hidden tab renders NOTHING — not even the shell — so it never\r\n // re-renders on a projection frame while it is off screen.\r\n if (!visible) return null\r\n\r\n return createElement(\r\n 'div',\r\n { style: ROOT_STYLE, 'data-dsh-brief-sidebar': 'board' },\r\n createElement('div', { style: SCROLL_STYLE },\r\n createElement(TodoSection, { key: 'progress', t, ctx, scope }),\r\n createElement(DeliverablesSection, { key: 'deliverables', t, ctx, scope }),\r\n // 技能引用:本会话通过宿主 `skill` 工具载入过哪些技能(`dshSummarySkillUsage`\r\n // 投影,本插件自己的 host 半注册)。与记忆两栏正交:这里讲“拉过哪些说明书”,\r\n // 下面两栏讲“模型看到了哪些记忆”。只读,无开关,投影缺席即整段隐藏。\r\n createElement(SkillUsageSection, { key: 'skill-usage', t, ctx, scope }),\r\n // 本会话召回(固定最底):入口开关(configForms `showMemoryRecall`,默认开)\r\n // 与能力存在(dsh-prime-memory 的 `memoryRecall` 投影)缺一即整段隐藏。\r\n // 这是\"模型此刻看到哪些记忆\"的诚实视图:非常驻,压缩后即清空。\r\n createElement(MemoryRecallSection, { key: 'memory-recall', t, ctx, scope }),\r\n // 记忆槽位分区:手动 pin 的常驻约定(`memorySlots` 投影),默认关。\r\n createElement(MemorySlotsSection, { key: 'memory-slots', t, ctx, scope }),\r\n ),\r\n )\r\n}\r\n","/**\r\n * Native right-sidebar path: register the board tab directly into the DSH\r\n * host's own sidebar, with NO better-sidebar in sight. Available on host\r\n * generations that ship `dsh-client-ui-sidebar-right` (0.1.5+; verified by\r\n * slot-declaration forensics on 0.1.5-rc.3, 0.1.7-rc.2 and 0.2.0-rc.2).\r\n *\r\n * The host opens a tab type through a two-stage registration, and this module\r\n * copies better-sidebar's own native bridge EXACTLY — that plugin is the\r\n * shipped, field-proof consumer of the same seats:\r\n *\r\n * 1. Stage one, \"what the type IS\": `ctx.sidebarRightTabs.register({id, kind,\r\n * title, guide})` (a `SidebarRightTabDefinition`; page type — no `patterns`,\r\n * opened by kind). The returned disposer lives in our effect.\r\n * 2. Stage two, \"what the body draws\": a keyed registration under\r\n * `sidebar.right.pane.tab` whose `key` is the definition's `id`. The inject\r\n * callback receives the session id; everything else (our `t`, the root\r\n * `ctx`) rides a closure, and `SummaryTab` reads session data through\r\n * `ctx.get('sessions')` exactly as it does under better-sidebar.\r\n *\r\n * Degradations versus the better-sidebar path, accepted deliberately:\r\n * - no badge — the native chip has no badge affordance; the unfinished count\r\n * still shows inside the tab body.\r\n * - no `visible` pause — the host unmounts inactive bodies (`keepMounted`\r\n * defaults to false), which subsumes it.\r\n * - the open affordance is the guide-page capsule (`guide[]`), not a rail icon.\r\n *\r\n * Everything is read through `ctx.get` structural probes: the services are\r\n * absent on ≤0.1.2 hosts, so the caller must treat `undefined` as \"no native\r\n * surface\" and stay inert rather than crash. No import from\r\n * `@deepseek-ai/dsh-client-ui-sidebar-right` — a browser-only plugin keeps zero\r\n * build-time coupling to host internals, mirroring `use-projection.ts`.\r\n */\r\nimport type { ReactNode } from 'react'\r\nimport type { Context } from '@deepseek-ai/cordis'\r\nimport type { SlotsLike } from './brief/dock-shadow'\r\nimport { SummaryTab } from './SummaryTab'\r\n\r\n/** One guide-page capsule contributed by our type (structural `SidebarRightGuideEntry`). */\r\ninterface NativeGuideEntry {\r\n readonly id: string\r\n readonly order: number\r\n readonly title: () => string\r\n readonly description?: () => string\r\n}\r\n\r\n/** Stage-one shape (structural `SidebarRightTabDefinition`; only the page-type fields). */\r\ninterface NativeTabDefinition {\r\n readonly id: string\r\n readonly kind: string\r\n readonly title: (address: string) => string\r\n readonly guide?: readonly NativeGuideEntry[]\r\n}\r\n\r\n/** `ctx.sidebarRightTabs` — the only method we call. */\r\ninterface NativeTabRegistryLike {\r\n register(definition: NativeTabDefinition): () => void\r\n}\r\n\r\nexport type { NativeTabRegistryLike }\r\n\r\n/** The keyed seat a tab type registers its body under. */\r\nconst PANE_TAB_SEAT = 'sidebar.right.pane.tab'\r\n\r\n/**\r\n * Whether this host exposes the native right-sidebar tab system at all.\r\n *\r\n * Both services must answer: the registry stages the type, and a future\r\n * \"open from a button\" affordance goes through the controller face.\r\n * @param ctx - the client root context.\r\n */\r\nexport function nativeSidebarAvailable(ctx: Context): boolean {\r\n const registry = ctx.get('sidebarRightTabs') as NativeTabRegistryLike | undefined\r\n const controller = ctx.get('sidebarRight') as unknown\r\n return (\r\n registry !== undefined &&\r\n typeof registry.register === 'function' &&\r\n controller !== undefined &&\r\n ctx.get('slots') !== undefined\r\n )\r\n}\r\n\r\n/**\r\n * Register the board as a native right-sidebar tab type.\r\n *\r\n * The registry arrives as a parameter, read from the deferred `ctx.inject`\r\n * scope in `apply` — the 0.1.7+ strict-proxy ctx refuses a root `ctx.get`\r\n * of an undeclared service, so reaching for `sidebarRightTabs` from the root\r\n * context is what made the native seat silently no-op on 0.1.7 (the \"cannot\r\n * register directly\" observation). better-sidebar's own native bridge reads\r\n * it the same way: from the inject callback's scope.\r\n *\r\n * @param ctx - the client root context (for the declared `slots` service).\r\n * @param registry - the host tab-type registry from the injected scope.\r\n * @param deps - the stable ids and the translator from `apply`.\r\n * @returns a disposer that unregisters the seat first, then the type (the\r\n * registry refuses opens for a type whose body is already gone).\r\n */\r\nexport function registerNativeBoardTab(\r\n ctx: Context,\r\n registry: NativeTabRegistryLike | undefined,\r\n deps: { id: string; kind: string; order: number; t: (key: string) => string },\r\n): () => void {\r\n const slots = ctx.get('slots') as SlotsLike | undefined\r\n if (registry === undefined || typeof registry.register !== 'function' || slots === undefined) {\r\n return (): void => {}\r\n }\r\n\r\n // Stage 1: the type. Page kind — opened from the guide capsule by `kind`.\r\n const disposeType = registry.register({\r\n id: deps.id,\r\n kind: deps.kind,\r\n title: () => deps.t('tab.title'),\r\n guide: [\r\n {\r\n id: deps.id,\r\n order: deps.order,\r\n title: () => deps.t('tab.title'),\r\n description: () => deps.t('tab.desc'),\r\n },\r\n ],\r\n })\r\n\r\n // Stage 2: the body, keyed under the definition's own id. The payload\r\n // mirrors better-sidebar's `TabComponentProps` fields that SummaryTab reads;\r\n // `visible` is pinned true because the host unmounts hidden bodies anyway.\r\n const disposeSeat = slots.inject(PANE_TAB_SEAT, () =>\r\n slots.register(\r\n {\r\n name: PANE_TAB_SEAT,\r\n key: deps.id,\r\n inject: (sessionId: string) => ({\r\n t: deps.t,\r\n ctx,\r\n scope: { sessionId },\r\n visible: true,\r\n }),\r\n },\r\n SummaryTab as unknown as (props: unknown) => ReactNode,\r\n ),\r\n )\r\n\r\n return (): void => {\r\n try {\r\n disposeSeat()\r\n } finally {\r\n disposeType()\r\n }\r\n }\r\n}\r\n","/**\r\n * Tab glyph for the task board.\r\n *\r\n * Skin contract: plugin-drawn glyphs take their colour from the `--dsw-alias-*`\r\n * tokens — no colour literals anywhere in this file.\r\n */\r\nimport type { ReactNode } from 'react'\r\n\r\n/**\r\n * A checklist mark: three rows with ticks and text rails — the same status\r\n * vocabulary the board paints.\r\n * @param size - square edge in px (the host passes its own tab-icon size).\r\n */\r\nexport function BriefIcon(size: number): ReactNode {\r\n return (\r\n <svg\r\n width={size}\r\n height={size}\r\n viewBox=\"0 0 16 16\"\r\n fill=\"none\"\r\n aria-hidden=\"true\"\r\n focusable=\"false\"\r\n style={{ display: 'block', flex: 'none' }}\r\n >\r\n <rect\r\n x={1.6}\r\n y={2.4}\r\n width={12.8}\r\n height={11.2}\r\n rx={2}\r\n stroke=\"var(--dsw-alias-label-tertiary)\"\r\n strokeWidth={1.2}\r\n />\r\n <path\r\n d=\"M4.2 6.1l1 1 1.8-2\"\r\n stroke=\"var(--dsw-alias-state-success-primary)\"\r\n strokeWidth={1.3}\r\n strokeLinecap=\"round\"\r\n strokeLinejoin=\"round\"\r\n />\r\n <path\r\n d=\"M4.2 10.6l1 1 1.8-2\"\r\n stroke=\"var(--dsw-alias-label-tertiary)\"\r\n strokeWidth={1.3}\r\n strokeLinecap=\"round\"\r\n strokeLinejoin=\"round\"\r\n />\r\n <path\r\n d=\"M8.4 6.4h4M8.4 10.9h4\"\r\n stroke=\"var(--dsw-alias-label-tertiary)\"\r\n strokeWidth={1.2}\r\n strokeLinecap=\"round\"\r\n />\r\n </svg>\r\n )\r\n}\r\n","/**\r\n * Hiding the official todo dock.\r\n *\r\n * `conversation.input.dock` is a LIST slot, and its cells are keyed by each\r\n * entry's `id`. The slot core keeps one live entry per cell — entries are\r\n * sorted by `priority` ascending (then by `order`) and the first live entry of\r\n * a cell is the one the outlet renders, so a SECOND registration with the same\r\n * `id` at a LOWER priority shadows the first. The official todo entry\r\n * (`conversation-todo-dock` in `dsh-client-ui-conversation`) registers\r\n * `{ id: 'todo', order: 0 }` with the default priority 0, so\r\n * `{ id: 'todo', priority: -1 }` wins the cell and the official panel never\r\n * renders while this plugin is mounted.\r\n *\r\n * This is the same mechanism `dsh-input-traffic` uses on the sibling `queue`\r\n * cell (`{ id: 'queue', priority: -1 }`), so it is a proven seam on this host\r\n * generation, not a guess.\r\n *\r\n * Binding to a built-in id is a real coupling: if upstream renames the cell,\r\n * the shadow silently stops winning and the official dock simply reappears\r\n * (fail-open — the data is still shown, just twice). `slots.inject` is used\r\n * rather than a bare `register` because the slot is declared by a built-in\r\n * entry whose lifetime we do not control: `inject` waits for the declaration\r\n * and re-installs the entry if the declaration is ever recreated.\r\n *\r\n * Renders nothing on purpose: the todo UI now lives in this plugin's sidebar\r\n * tab. Return a summary chip here instead to keep a one-line entry point in the\r\n * composer band.\r\n */\r\nimport type { ReactNode } from 'react'\r\nimport type { Context } from '@deepseek-ai/cordis'\r\n\r\n/** The built-in cell id of the official todo dock. */\r\nexport const TODO_CELL_ID = 'todo'\r\n\r\n/** Lower than the built-in's default 0 — the winner of the `todo` cell. */\r\nexport const TODO_SHADOW_PRIORITY = -1\r\n\r\n/** Structural view of the client slots service (avoids a second type graph). */\r\nexport interface SlotsLike {\r\n inject(key: string, callback: () => (() => void) | undefined): () => void\r\n register(options: Record<string, unknown>, component: (props: unknown) => ReactNode): () => void\r\n}\r\n\r\n/** The replacement entry: deliberately empty. */\r\nfunction TodoDockShadow(): ReactNode {\r\n return null\r\n}\r\n\r\n/**\r\n * Register the shadowing entry.\r\n *\r\n * The caller wraps this in `ctx.effect(...)` so the returned disposer rides the\r\n * plugin fiber: unloading the plugin restores the official dock.\r\n *\r\n * @param ctx - the client root context.\r\n * @returns the disposer, or undefined when the slots service is unreachable.\r\n */\r\nexport function registerTodoDockShadow(ctx: Context): (() => void) | undefined {\r\n const slots = ctx.get('slots') as SlotsLike | undefined\r\n if (slots === undefined || typeof slots.inject !== 'function') return undefined\r\n\r\n return slots.inject('conversation.input.dock', () =>\r\n slots.register(\r\n {\r\n name: 'conversation.input.dock',\r\n id: TODO_CELL_ID,\r\n order: 0,\r\n priority: TODO_SHADOW_PRIORITY,\r\n registrant: 'dsh-brief-sidebar',\r\n },\r\n TodoDockShadow,\r\n ),\r\n )\r\n}\r\n","/**\r\n * BriefSettingsCard — the brief-sidebar settings card.\r\n *\r\n * One component mounted at TWO seats, fed by the SAME inject factory (one\r\n * source of truth, the dsh-thinking-levels arrangement):\r\n *\r\n * - the plugin-family settings section (「起子插件设置」, the `settings.section`\r\n * entry dsh-thinking-levels registers; this plugin contributes its card to\r\n * the `dsh-family.tab` child slot — the inject idles harmlessly when the\r\n * family section is absent);\r\n * - the Plugins-page configuration card (`plugins.bundle.config`, keyed by\r\n * the package name, rendered on the bundle's detail page).\r\n *\r\n * The card binds this plugin's entry config through the `configForms` service\r\n * and renders the fields the summary tab reads. Every change commits\r\n * immediately through the scope (no staged form), so a flip applies to the\r\n * open summary tab on its next render.\r\n *\r\n * The `t` binder is injected by the factory (the same closure the tab uses) —\r\n * the card does not rely on the framework's locale props, so it renders the\r\n * active language on every host generation. Kept dependency-free beyond\r\n * react: inline styles over `--dsw-alias-*` tokens only (no CSS modules, no\r\n * hex/rgba literals — the purity spec enforces the token contract).\r\n */\r\nimport { useCallback, useState, useSyncExternalStore } from 'react'\r\nimport { createElement } from 'react'\r\nimport type { CSSProperties, ChangeEvent, ReactNode } from 'react'\r\nimport type { BriefClientConfig, SettingsScope, SettingsScopeSnapshot } from './scope-face'\r\nimport { resolveShowMemoryRecall, resolveShowMemorySlots } from './scope-face'\r\n\r\n/** A no-op unsubscribe source, kept as one identity so effects never thrash. */\r\nconst NO_SUBSCRIBE = (): (() => void) => () => {}\r\n\r\n/** The snapshot served while no scope is reachable. */\r\nconst ABSENT: SettingsScopeSnapshot<BriefClientConfig> = {\r\n status: 'unavailable',\r\n value: undefined,\r\n revision: undefined,\r\n writable: false,\r\n}\r\n\r\n/** Injected face: the entry scope, plus the plugin's own binder. */\r\nexport interface BriefSettingsCardInjected {\r\n /** `configForms.get('dsh-brief-sidebar')` — may be unavailable on odd hosts. */\r\n scope?: SettingsScope<BriefClientConfig>\r\n /** The plugin's locale binder (applied-time closure over the locale service). */\r\n t: (key: string) => string\r\n}\r\n\r\nexport type BriefSettingsCardProps = BriefSettingsCardInjected\r\n\r\n/* ── shared row styling (inline; keeps the client bundle CSS-free) ──────── */\r\n\r\nconst CARD_STYLE: CSSProperties = {\r\n border: '1px solid var(--dsw-alias-border-l2)',\r\n background: 'var(--dsw-alias-bg-layer-3)',\r\n borderRadius: 12,\r\n transition: 'border-color 0.16s, background 0.16s',\r\n}\r\n\r\nconst HEADER_STYLE: CSSProperties = {\r\n appearance: 'none',\r\n width: '100%',\r\n font: 'inherit',\r\n color: 'inherit',\r\n textAlign: 'left',\r\n cursor: 'pointer',\r\n background: 'none',\r\n border: 0,\r\n borderRadius: 12,\r\n display: 'flex',\r\n alignItems: 'center',\r\n gap: 12,\r\n padding: '14px 16px',\r\n}\r\n\r\nconst HEADER_TEXT_STYLE: CSSProperties = { flex: '1 1 0%', minWidth: 0 }\r\n\r\nconst NAME_STYLE: CSSProperties = {\r\n fontSize: 14,\r\n fontWeight: 600,\r\n color: 'var(--dsw-alias-label-primary)',\r\n}\r\n\r\nconst DESC_STYLE: CSSProperties = {\r\n color: 'var(--dsw-alias-label-tertiary)',\r\n fontSize: 13,\r\n lineHeight: 1.5,\r\n}\r\n\r\nconst CHEVRON_STYLE = (open: boolean): CSSProperties => ({\r\n color: 'var(--dsw-alias-label-tertiary)',\r\n flex: '0 0 auto',\r\n transition: 'transform 0.16s',\r\n transform: open ? 'rotate(180deg)' : 'none',\r\n})\r\n\r\nconst BODY_STYLE: CSSProperties = { padding: '12px 16px' }\r\n\r\nconst ROW_STYLE: CSSProperties = {\r\n display: 'flex',\r\n alignItems: 'flex-start',\r\n justifyContent: 'space-between',\r\n gap: 12,\r\n padding: '8px 0',\r\n fontSize: 13,\r\n lineHeight: '20px',\r\n}\r\n\r\nconst ROW_TEXT_STYLE: CSSProperties = {\r\n display: 'flex',\r\n flexDirection: 'column',\r\n gap: 4,\r\n minWidth: 0,\r\n}\r\n\r\nconst LABEL_STYLE: CSSProperties = { margin: 0, color: 'var(--dsw-alias-label-primary)' }\r\n\r\nconst HINT_STYLE: CSSProperties = {\r\n margin: 0,\r\n fontSize: 12,\r\n lineHeight: '18px',\r\n color: 'var(--dsw-alias-label-tertiary)',\r\n}\r\n\r\nconst SWITCH_STYLE: CSSProperties = { flexShrink: 0, margin: 0, cursor: 'pointer' }\r\n\r\n/**\r\n * One switch row: label + hint on the left, checkbox on the right. Extracted\r\n * because the card now binds two sections (session recall / pinned slots).\r\n */\r\nfunction FlagRow(props: {\r\n id: string\r\n label: string\r\n hint: string\r\n checked: boolean\r\n disabled: boolean\r\n onToggle(next: boolean): void\r\n}): ReactNode {\r\n return createElement(\r\n 'div',\r\n { style: ROW_STYLE },\r\n createElement(\r\n 'div',\r\n { style: ROW_TEXT_STYLE },\r\n createElement('label', { htmlFor: props.id, style: LABEL_STYLE }, props.label),\r\n createElement('p', { style: HINT_STYLE }, props.hint),\r\n ),\r\n createElement('input', {\r\n id: props.id,\r\n type: 'checkbox',\r\n checked: props.checked,\r\n disabled: props.disabled,\r\n style: SWITCH_STYLE,\r\n onChange: (event: ChangeEvent<HTMLInputElement>) => { props.onToggle(event.currentTarget.checked) },\r\n }),\r\n )\r\n}\r\n\r\n/**\r\n * The settings card body. `scope` is optional on purpose: the inject factory\r\n * always provides it, but a host whose `configForms` face degrades must not\r\n * crash the settings page — the card renders the unavailable note and keeps\r\n * its header.\r\n */\r\nexport function BriefSettingsCard(props: BriefSettingsCardProps): ReactNode {\r\n const { t, scope } = props\r\n const [open, setOpen] = useState(true)\r\n\r\n const snapshot: SettingsScopeSnapshot<BriefClientConfig> | undefined = useSyncExternalStore(\r\n useCallback((listener: () => void) => scope?.subscribe(listener) ?? NO_SUBSCRIBE(), [scope]),\r\n useCallback(() => scope?.getSnapshot() ?? ABSENT, [scope]),\r\n useCallback(() => scope?.getSnapshot() ?? ABSENT, [scope]),\r\n )\r\n const unavailable = scope === undefined || snapshot.status === 'unavailable'\r\n const readonly = unavailable || !snapshot.writable\r\n // Defaults come from the same resolvers the sections use — one source of truth.\r\n const slotsChecked = resolveShowMemorySlots(snapshot)\r\n const recallChecked = resolveShowMemoryRecall(snapshot)\r\n\r\n return createElement(\r\n 'div',\r\n { style: CARD_STYLE, 'data-dsh-brief-sidebar': 'settings-card' },\r\n createElement(\r\n 'button',\r\n { type: 'button', 'aria-expanded': open, style: HEADER_STYLE, onClick: () => { setOpen(current => !current) } },\r\n createElement(\r\n 'span',\r\n { style: HEADER_TEXT_STYLE },\r\n createElement('div', { style: NAME_STYLE }, t('settings.title')),\r\n createElement('div', { style: DESC_STYLE }, t('settings.desc')),\r\n ),\r\n createElement(\r\n 'svg',\r\n { width: 16, height: 16, viewBox: '0 0 16 16', 'aria-hidden': true, style: CHEVRON_STYLE(open) },\r\n createElement('path', {\r\n d: 'M4 6l4 4 4-4',\r\n fill: 'none',\r\n stroke: 'currentColor',\r\n strokeWidth: 1.5,\r\n strokeLinecap: 'round',\r\n strokeLinejoin: 'round',\r\n }),\r\n ),\r\n ),\r\n open && createElement(\r\n 'div',\r\n { style: BODY_STYLE },\r\n unavailable\r\n ? createElement('p', { style: HINT_STYLE }, t('settings.unavailable'))\r\n : createElement(\r\n 'div',\r\n { style: { display: 'flex', flexDirection: 'column', gap: 12 } },\r\n createElement(FlagRow, {\r\n key: 'recall',\r\n id: 'dsh-brief-sidebar-show-memory-recall',\r\n label: t('settings.memoryRecall'),\r\n hint: t('settings.memoryRecallHint'),\r\n checked: recallChecked,\r\n disabled: readonly,\r\n onToggle: (next: boolean) => { void scope?.set('showMemoryRecall', next) },\r\n }),\r\n createElement(FlagRow, {\r\n key: 'slots',\r\n id: 'dsh-brief-sidebar-show-memory-slots',\r\n label: t('settings.memorySlots'),\r\n hint: t('settings.memorySlotsHint'),\r\n checked: slotsChecked,\r\n disabled: readonly,\r\n onToggle: (next: boolean) => { void scope?.set('showMemorySlots', next) },\r\n }),\r\n ),\r\n !unavailable && !snapshot.writable && createElement('p', { style: HINT_STYLE }, t('settings.readonly')),\r\n ),\r\n )\r\n}\r\n","/**\r\n * Browser half: the task board tab, plus the shadow that hides the official\r\n * composer-band todo panel.\r\n *\r\n * Registration order matters and is deliberate:\r\n *\r\n * 1. **Dictionaries first.** Every later registration can render translated\r\n * copy, and a dictionary that lands after the first paint would show raw\r\n * keys for a frame.\r\n * 2. **Sidebar surface, deferred.** The board needs a sidebar to live in:\r\n * better-sidebar when it is installed (richer: badge + rail icon), else the\r\n * host's own right-sidebar tab system (0.1.5+ `sidebarRightTabs` +\r\n * `sidebar.right.pane.tab`). Both are acquired through the deferred\r\n * `ctx.inject` because neither service is ordered against this apply —\r\n * an immediate `ctx.get` was the 0.1.2 inert bug. With neither — ≤0.1.2\r\n * hosts without better-sidebar — the plugin stays sidebar-inert: the\r\n * official panel keeps rendering and the shadow never installs.\r\n * 3. **Shadow the official dock.** Deliberately BEFORE the tab registration:\r\n * the panel is the only other carrier of the list, so the replacement has to\r\n * exist in the same activation.\r\n * 4. **Register the tab.**\r\n * 5. **Register the settings cards.** The memory-section switch gets TWO\r\n * faces from ONE component + ONE inject factory: a card in the plugin-family\r\n * settings section (「起子插件设置」, hosted by dsh-thinking-levels) and the\r\n * Plugins-page configuration card. `configForms` resolves through a\r\n * deferred inject (the service may start after apply — the same lateness\r\n * the composer model panel in dsh-thinking-levels guards against); on a\r\n * host without it the cards never register and the section gate falls back\r\n * to its default (on).\r\n *\r\n * Every registration rides `ctx.effect(fn, label)` so its disposer is revoked on\r\n * fiber teardown (HMR / disable), which is also what makes the shadow\r\n * reversible: unload the plugin and the official dock renders again. The\r\n * settings cards are the family-proven exception: they ride the deferred\r\n * `configForms` inject whose disposers are not held (same as\r\n * dsh-thinking-levels' composer panel registration).\r\n *\r\n * Contract notes for the two surfaces touched here:\r\n * - better-sidebar tabs are hosted by DSH's native right Sidebar, so the tab\r\n * body receives `TabComponentProps` (`ctx` + `scope` + `visible`) and NOT the\r\n * framework's session-scoped slot props.\r\n * - `conversation.input.dock` is the DSH slot the official todo panel occupies;\r\n * see `brief/dock-shadow.tsx` for why a lower priority wins the cell.\r\n */\r\nimport { createElement } from 'react'\r\nimport type { ReactNode } from 'react'\r\nimport type { Context } from '@deepseek-ai/cordis'\r\nimport type { BetterSidebarService, TabComponentProps } from 'dsh-better-sidebar/client/service'\r\nimport { registerNativeBoardTab } from './native-sidebar'\r\nimport type { NativeTabRegistryLike } from './native-sidebar'\r\nimport { SummaryTab } from './SummaryTab'\r\nimport { BriefIcon } from './BriefIcon'\r\nimport { NS, dictionaries } from './locales'\r\nimport { readTodos, unfinishedCount } from './brief/board'\r\nimport { registerTodoDockShadow } from './brief/dock-shadow'\r\nimport type { SlotsLike } from './brief/dock-shadow'\r\nimport { TODOS_KEY } from './brief/use-todos'\r\nimport { projectionSnapshot } from './use-projection'\r\nimport { BriefSettingsCard } from './settings-card'\r\nimport type { BriefSettingsCardProps } from './settings-card'\r\nimport type { BriefClientConfig, ConfigFormsLike } from './scope-face'\r\n\r\n/**\r\n * Tab type id. Package-prefixed so it cannot collide with a built-in type.\r\n * Unchanged since the 0.1.0 board tab: the summary tab REPLACES the board tab\r\n * in place, so an opened or pinned tab survives the upgrade.\r\n */\r\nexport const TAB_ID = 'dsh-brief-sidebar:board'\r\n\r\n/**\r\n * Tab kind on the native host-sidebar path (`openTab`/guide dispatch key).\r\n * Only the native registration uses it; better-sidebar keeps addressing the\r\n * tab by {@link TAB_ID}.\r\n */\r\nexport const TAB_KIND = 'brief-board'\r\n\r\n/**\r\n * Position in the host's new-tab guide.\r\n *\r\n * Built-ins on this host generation sit at editor 10 / git 20 / subagent 30 /\r\n * sidechat 35 / terminal 40 / browser 50. 15 places a per-session task board\r\n * right after the editor, which is where a reader looks for session state.\r\n */\r\nexport const TAB_ORDER = 15\r\n\r\n/** Services required before `apply` runs. */\r\n// Generation-neutral list only: betterSidebar/locale ride ctx.get soft-reads in\r\n// apply (both absent on 0.1.0/0.1.1 — declaring them pends the whole client\r\n// entry, web boot refuses to render; playbook §1).\r\n// betterSidebar 经 ctx.get 软读(缺席 inert);locale 全线 rc 皆在(0.1.0-rc.2 起)。\r\n// 第三方插件服务不入顶层 inject——缺席格 entry 永久 pending,web boot 拒渲染整树。\r\nexport const inject = ['slots', 'locale']\r\n\r\n/**\r\n * Structural view of the DSH locale service — only the two members this plugin\r\n * calls. Declared locally on purpose: importing the real type would pull the\r\n * whole client type graph into a browser-only plugin for two signatures.\r\n */\r\ninterface LocaleLike {\r\n register(ns: string, dicts: Record<string, Record<string, string>>): () => void\r\n bind(ns: string): (key: string) => string\r\n}\r\n\r\n/**\r\n * An effect body must return a disposer (cordis rejects `undefined` with a\r\n * `TypeError`), so a path that could not register anything returns this no-op\r\n * instead of nothing.\r\n */\r\nconst NOOP = (): void => {}\r\n\r\n/** Console prefix for the environment probe and registration attribution. */\r\nconst LOG = '[dsh-brief-sidebar]'\r\n\r\n/**\r\n * Run a registration thunk, attributing a thrown failure to the console\r\n * instead of the cordis effect void (a bare throw inside `ctx.effect` leaves\r\n * the field reader with an empty sidebar and no clue which arm died).\r\n */\r\nfunction guarded(label: string, run: () => (() => void) | undefined | void): () => void {\r\n try {\r\n const dispose = run()\r\n return typeof dispose === 'function' ? (dispose as () => void) : NOOP\r\n } catch (error) {\r\n console.error(`${LOG} ${label} failed`, error)\r\n return NOOP\r\n }\r\n}\r\n\r\n/**\r\n * Browser-face apply.\r\n *\r\n * @param ctx - the client root context.\r\n */\r\nexport function apply(ctx: Context): void {\r\n // 1. Plugin-owned dictionaries, in one registration.\r\n const locale: LocaleLike | undefined = ctx.get('locale')\r\n if (locale !== undefined) {\r\n ctx.effect(() => locale.register(NS, dictionaries), 'dsh-brief-sidebar: dictionaries')\r\n }\r\n\r\n /**\r\n * Translate one of our keys. `bind` returns a cached function that reads the\r\n * ACTIVE locale at call time, so a language switch needs no re-apply; an\r\n * unknown namespace or key falls back to the key itself rather than throwing\r\n * inside a render.\r\n */\r\n const t = (key: string): string => {\r\n if (locale === undefined) return key\r\n try {\r\n return locale.bind(NS)(key) || key\r\n } catch {\r\n return key\r\n }\r\n }\r\n\r\n // 2. Sidebar surface, acquired DEFERRED. better-sidebar is a third-party\r\n // plugin with no ordering guarantee against us, and the native tab\r\n // registry is a host service that can publish after this apply too — an\r\n // immediate `ctx.get` misses either one and stays inert forever (the\r\n // 0.1.2 field failure). Both arms ride the deferred optional\r\n // `ctx.inject` (the browser-cdp / configForms precedent). The host\r\n // registry usually wins the race on 0.1.5+ (it publishes before the\r\n // third-party sidebar), so the state is NOT a one-shot latch: when\r\n // better-sidebar arrives after a native seat, it HANDS OVER — the\r\n // native registration is released and the board re-seats on the bar,\r\n // which is the rail and manager the user actually sees (the 0.1.5\r\n // \"invisible tab\" failure was a native seat under a sidebar UI that\r\n // replaced the official rail). On a bare native host (0.1.7 farm cell)\r\n // no handover ever fires.\r\n let surface: 'none' | 'bar' | 'native' = 'none'\r\n let shadowDone = false\r\n let nativeDisposer: (() => void) | undefined\r\n\r\n /** Hide the official composer-band panel (reversible on unload), once. */\r\n const shadowDock = (): void => {\r\n if (shadowDone) return\r\n shadowDone = true\r\n ctx.effect(() => registerTodoDockShadow(ctx) ?? NOOP, 'dsh-brief-sidebar: dock shadow')\r\n }\r\n\r\n const registerOnBar = (bar: BetterSidebarService): void => {\r\n if (surface === 'bar') return\r\n if (surface === 'native') {\r\n const release = nativeDisposer\r\n nativeDisposer = undefined\r\n try {\r\n release?.()\r\n } catch { /* a half-torn-down native seat must not block the handover */ }\r\n console.info(`${LOG} surface=bar (handed over from native)`)\r\n } else {\r\n console.info(`${LOG} surface=bar`)\r\n }\r\n surface = 'bar'\r\n shadowDock()\r\n ctx.effect(\r\n () =>\r\n guarded('registerTab', () =>\r\n bar.registerTab({\r\n id: TAB_ID,\r\n title: () => t('tab.title'),\r\n description: () => t('tab.desc'),\r\n icon: (size: number) => BriefIcon(size),\r\n order: TAB_ORDER,\r\n // Shorthand for `dedupeKey: () => id`: reopening focuses the existing tab.\r\n single: true,\r\n /**\r\n * Unfinished count on the tab strip. Called on every tab-bar render, so\r\n * it reads one snapshot and allocates no subscription; a completed list\r\n * shows no badge at all.\r\n */\r\n badge: (badgeCtx, badgeScope) => {\r\n const todos = readTodos(projectionSnapshot(badgeCtx, badgeScope.sessionId, TODOS_KEY))\r\n if (todos === undefined) return null\r\n const pending = unfinishedCount(todos)\r\n return pending > 0 ? pending : null\r\n },\r\n component: (props: TabComponentProps) =>\r\n createElement(SummaryTab, {\r\n t,\r\n ctx: props.ctx,\r\n scope: props.scope,\r\n visible: props.visible,\r\n }),\r\n }),\r\n ),\r\n 'dsh-brief-sidebar: tab',\r\n )\r\n }\r\n\r\n const registerOnNative = (registry: NativeTabRegistryLike | undefined): void => {\r\n if (surface !== 'none') return\r\n surface = 'native'\r\n console.info(`${LOG} surface=native`)\r\n shadowDock()\r\n ctx.effect(\r\n () => {\r\n nativeDisposer = guarded('native tab', () => registerNativeBoardTab(ctx, registry, { id: TAB_ID, kind: TAB_KIND, order: TAB_ORDER, t }))\r\n return () => {\r\n nativeDisposer = undefined\r\n }\r\n },\r\n 'dsh-brief-sidebar: native tab',\r\n )\r\n }\r\n\r\n // Arm 1: better-sidebar, immediate read first (the common case where the\r\n // sidebar started before us), deferred retry otherwise.\r\n let bar: BetterSidebarService | undefined\r\n try {\r\n bar = ctx.get('betterSidebar')\r\n } catch {\r\n bar = undefined\r\n }\r\n if (bar !== undefined) {\r\n registerOnBar(bar)\r\n } else {\r\n ;(ctx as unknown as {\r\n inject: (deps: string[], cb: (scope: { betterSidebar?: BetterSidebarService }) => void) => void\r\n }).inject(['betterSidebar'], (scope) => {\r\n if (scope.betterSidebar !== undefined) registerOnBar(scope.betterSidebar)\r\n })\r\n }\r\n\r\n // Arm 2: the host's own tab registry (0.1.5+). Never fires on ≤0.1.2. The\r\n // registry is read from the INJECTED scope — a root ctx.get of this\r\n // undeclared service is denied by the strict proxy (the 0.1.7 silent no-op).\r\n ;(ctx as unknown as {\r\n inject: (deps: string[], cb: (scope: { sidebarRightTabs?: NativeTabRegistryLike }) => void) => void\r\n }).inject(['sidebarRightTabs'], (scope) => {\r\n registerOnNative(scope.sidebarRightTabs)\r\n })\r\n\r\n // 5. The settings cards (see the module doc): ONE component + ONE inject\r\n // factory at TWO seats. The entry ids follow the family convention —\r\n // `dsh-family.tab` contributors key by short id (session-guard →\r\n // 'session-guard'), `plugins.bundle.config` keys by package name.\r\n // `configForms` rides a deferred inject: the service lives in the\r\n // settings module, which may start after this apply; the callback simply\r\n // never fires on a host without it (the gate then reads its default).\r\n const slots = ctx.get('slots') as SlotsLike | undefined\r\n ;(ctx as unknown as {\r\n inject: (deps: string[], cb: (scope: { configForms?: ConfigFormsLike }) => void) => void\r\n }).inject(['configForms'], (scope) => {\r\n const configForms = scope.configForms\r\n if (slots === undefined || configForms === undefined || typeof configForms.get !== 'function') return\r\n\r\n /** Same face for both seats: the entry scope plus the applied-time binder. */\r\n const injectFactory = (): BriefSettingsCardProps => ({\r\n t,\r\n scope: configForms.get<BriefClientConfig>('dsh-brief-sidebar'),\r\n })\r\n /** The slot core hands the component `unknown` props (registry typing). */\r\n const component = BriefSettingsCard as unknown as (props: unknown) => ReactNode\r\n\r\n slots.inject('dsh-family.tab', () =>\r\n slots.register(\r\n {\r\n name: 'dsh-family.tab',\r\n id: 'brief-sidebar',\r\n order: 30,\r\n label: () => t('settings.title'),\r\n inject: injectFactory,\r\n },\r\n component,\r\n ),\r\n )\r\n slots.inject('plugins.bundle.config', () =>\r\n slots.register(\r\n {\r\n name: 'plugins.bundle.config',\r\n key: 'dsh-brief-sidebar',\r\n inject: injectFactory,\r\n },\r\n component,\r\n ),\r\n )\r\n })\r\n\r\n // One-line environment snapshot: what this apply could see at mount time.\r\n // Cross-reference with the `surface=` line to tell \"arm never fired\" from\r\n // \"arm fired and registration threw\" (guarded logs that part).\r\n try {\r\n let nativeTabsAtApply = false\r\n try {\r\n nativeTabsAtApply = ctx.get('sidebarRightTabs') !== undefined\r\n } catch {\r\n nativeTabsAtApply = false /* strict proxy denies the undeclared read */\r\n }\r\n console.info(`${LOG} env ${JSON.stringify({\r\n locale: locale !== undefined,\r\n barAtApply: bar !== undefined,\r\n nativeTabsAtApply,\r\n })}`)\r\n } catch { /* console may be absent in a stripped host */ }\r\n}\r\n"],"mappings":"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"}