{"version":3,"file":"client.inner.cjs","names":["useSyncExternalStore","useCallback","useRef","useState","useRef","Button","StateDot","useId","Switch","Input"],"sources":["../../dsh-plugin-kit/src/contracts.ts","../../dsh-plugin-kit/src/client-utils.ts","../../dsh-plugin-kit/src/model-menu.ts","../../dsh-plugin-kit/src/official-ui.ts","../src/contracts.ts","../src/idle.ts","../src/client.tsx"],"sourcesContent":["import type { ContextFormed } from '@deepseek-ai/dsh-llm'\n\n/** Public, browser-safe contracts. Host implementations stay in their owning packages. */\nexport type ProducerSourceKind = `plugin:${string}`\nexport type ProducerMessageSource = { kind: ProducerSourceKind; plugin: string } & ContextFormed\n\n/**\n * V4 sessions persist the producing extension in `kind`; the retired generic\n * `plugin` wrapper is not admitted. Each feature plugin declares its own kind.\n */\ndeclare module '@deepseek-ai/dsh-llm' {\n  interface MessageSourceMap {\n    [kind: ProducerSourceKind]: ProducerMessageSource\n  }\n}\n\nexport function producerMessageSource(plugin: string): ProducerMessageSource {\n  return { kind: `plugin:${plugin}`, plugin }\n}\n\n/** A concrete provider model. Features store this on their own settings page. */\nexport interface ModelRoute { provider: string; model: string; reasoningEffort?: string }\n\n/** @deprecated Legacy call shape. Features should call host `llm` directly. */\nexport type ModelRole = 'normal' | 'weak' | 'strong' | 'fantasy'\n/** @deprecated Legacy call shape. Features should call host `llm` directly. */\nexport type ModelTarget = { kind: 'role'; role: ModelRole } | { kind: 'session' } | ({ kind: 'model' } & ModelRoute)\n/** @deprecated Legacy call shape. Features should call host `llm` directly. */\nexport interface AiPolicy {\n  revision: number\n  roles: Partial<Record<ModelRole, ModelRoute>>\n  purposes: Record<string, ModelTarget>\n  limits: { concurrency: number; timeoutMs: number; maxInputChars: number; maxOutputTokens: number; maxAttempts: number }\n}\n/** @deprecated Legacy call shape. Features should call host `llm` directly. */\nexport interface PurposeSpec {\n  id: string\n  label: string\n  defaultTarget: ModelTarget\n  maxOutputTokens?: number\n  maxInputChars?: number\n  timeoutMs?: number\n}\n/** @deprecated Legacy call shape. Features should call host `llm` directly. */\nexport interface ResolvedRoute extends ModelRoute {\n  source: 'override' | 'purpose' | 'default'\n  target: ModelTarget\n  policyRevision: number\n  inheritedRole?: ModelRole\n}\n/** @deprecated Legacy call shape. Features should call host `llm` directly. */\nexport interface AuxiliaryRequest {\n  purpose: string\n  sessionId?: string\n  input: string\n  system: string\n  sourceVersion: string\n  contractVersion?: number\n  promptVersion?: string\n  schemaVersion?: string\n  override?: ModelTarget\n  signal?: AbortSignal\n  isCurrent?: () => boolean\n  priority?: 'interactive' | 'background'\n  insert?: { maxChars: number }\n}\n/** @deprecated Legacy call shape. Features should call host `llm` directly. */\nexport interface UsageReceipt {\n  id: string\n  plugin: string\n  purpose: string\n  sessionId?: string\n  sourceVersion: string\n  contractVersion?: number\n  promptVersion?: string\n  schemaVersion?: string\n  route?: ResolvedRoute\n  status: 'success' | 'failed' | 'cancelled' | 'superseded' | 'skipped'\n  attempts: number\n  inputTokens?: number\n  outputTokens?: number\n  cost: number | null\n  startedAt: number\n  finishedAt: number\n  error?: string\n}\n/** @deprecated Legacy call shape. Features should call host `llm` directly. */\nexport interface AuxiliaryResult { text: string; receipt: UsageReceipt }\n/** @deprecated Legacy call shape. Features should call host `llm` directly. */\nexport interface AiFeatureScope {\n  readonly plugin: string\n  readonly signal: AbortSignal\n  readonly active: boolean\n  registerPurpose(spec: PurposeSpec): () => void\n  run(request: AuxiliaryRequest): Promise<AuxiliaryResult>\n  dispose(): void\n}\n/** @deprecated Legacy call shape. Features should call host `llm` directly. */\nexport interface AiServices {\n  activate(plugin: string): AiFeatureScope\n  importPurposes(migrationId: string, defaults: Record<string, ModelTarget>, roles?: AiPolicy['roles']): Promise<AiPolicy>\n  getPolicy(): AiPolicy\n  updatePolicy(policy: Omit<AiPolicy, 'revision'>, expectedRevision: number): Promise<AiPolicy>\n  resolve(purpose: string, sessionId?: string, override?: ModelTarget): Promise<ResolvedRoute>\n  purposes(): Array<PurposeSpec & { plugin: string }>\n  usage(): UsageReceipt[]\n}\n\nexport type RpcResult<T = unknown> = { ok: true; value: T } | { ok: false; error: { code: string; message: string } }\nexport const CHAT_EVENTS_SLOT = 'dsh-editor.chat.events'\nexport interface EvidenceRef { sessionId: string; seq: number; kind: 'user' | 'tool' | 'turn' | 'manual'; excerpt?: string }\nexport interface TaskContract {\n  id: string\n  sessionId: string\n  sourceVersion: string\n  revision: number\n  goal: string\n  deliverables: string[]\n  inScope: string[]\n  outOfScope: string[]\n  constraints: string[]\n  acceptance: string[]\n  assumptions: string[]\n  questions: string[]\n  evidence: EvidenceRef[]\n  readiness: 'pending' | 'clear-request' | 'user-confirmed' | 'disclosed-assumptions' | 'cancelled' | 'stale'\n  updatedAt: number\n}\nexport interface TaskCheckpoint {\n  id: string\n  sessionId: string\n  sourceVersion: string\n  contractVersion?: number\n  fromSeq: number\n  toSeq: number\n  revision: number\n  status: 'running' | 'completed' | 'failed' | 'cancelled'\n  items: Array<{ label: string; state: 'pending' | 'verified' | 'failed'; evidence: EvidenceRef[] }>\n  constraints: string[]\n  nextAction: string\n  createdAt: number\n}\nexport type KnowledgeScope = { kind: 'global' } | { kind: 'project'; projectId: string }\nexport type KnowledgeKind = 'preference' | 'project-fact' | 'decision' | 'vocabulary' | 'activity' | 'lesson'\n/** Descriptive context, never an executable instruction or authorization. */\nexport interface ContextKnowledge {\n  subject: string\n  domain: string\n  key: string\n  aliases: string[]\n  observedAt: number\n  /** The user's own time expression, not an inferred completion date. */\n  eventTime?: string\n  activityStatus?: 'planned' | 'in-progress' | 'blocked' | 'paused' | 'completed' | 'cancelled' | 'unknown'\n}\n/** A scoped method. Observations remain candidates until explicitly accepted. */\nexport interface ProcedureKnowledge {\n  origin: 'instruction' | 'observation'\n  goal: string\n  when: string[]\n  steps: string[]\n  avoid: string[]\n  verify: string[]\n}\nexport interface MemoryRecord {\n  id: string\n  revision: number\n  scope: KnowledgeScope\n  kind: KnowledgeKind\n  status: 'candidate' | 'active' | 'rejected' | 'superseded' | 'revoked' | 'deleted'\n  title: string\n  content: string\n  tags: string[]\n  evidence: EvidenceRef[]\n  exceptions: string[]\n  source: 'user' | 'memory' | 'dream' | 'self-improvement'\n  context?: ContextKnowledge\n  procedure?: ProcedureKnowledge\n  createdAt: number\n  updatedAt: number\n  expiresAt?: number\n  supersedes?: string[]\n  /** Exact record revisions behind a derived candidate; revalidated on adoption. */\n  basis?: Array<{ id: string; revision: number }>\n}\nexport type NewMemoryRecord = Omit<MemoryRecord, 'id' | 'revision' | 'createdAt' | 'updatedAt'>\nexport interface MemoryQuery { scope: KnowledgeScope; query?: string; kinds?: KnowledgeKind[]; statuses?: MemoryRecord['status'][]; limit?: number }\nexport interface MemoryMutationOptions { signal?: AbortSignal; isCurrent?: () => boolean }\nexport interface MemoryService {\n  list(query: MemoryQuery): Promise<MemoryRecord[]>\n  create(record: NewMemoryRecord, options?: MemoryMutationOptions): Promise<MemoryRecord>\n  update(id: string, patch: Partial<Pick<MemoryRecord, 'title' | 'content' | 'tags' | 'exceptions' | 'status' | 'expiresAt'>>, expectedRevision: number, options?: MemoryMutationOptions): Promise<MemoryRecord>\n  /** Explicit user promotion, persisted atomically on the same record; preserves expiry and evidence. */\n  promoteToGlobal(id: string, expectedRevision: number, options?: MemoryMutationOptions): Promise<MemoryRecord>\n  remove(id: string, expectedRevision: number, options?: MemoryMutationOptions): Promise<void>\n  recall(query: MemoryQuery): Promise<MemoryRecord[]>\n}\n\n/**\n * The session creation metadata the host snapshots when it creates a delegated child\n * thread. Mirrors `CreateAgentOptions.meta` in `@deepseek-ai/dsh-agent`; it is durable\n * session data, so it survives a restart and needs no ancestry walk.\n */\nexport interface SubagentSessionLike {\n  readonly header?: {\n    readonly parentSession?: unknown\n    readonly origin?: unknown\n    readonly delegationDepth?: unknown\n  }\n}\n\n/**\n * True when `session` is a delegated child thread rather than a human-driven top-level\n * conversation.\n *\n * A message's `source.kind === 'user'` cannot answer this: a lead agent's dispatch prompt\n * is delivered as the child's own user message, so delegated work is indistinguishable\n * from a person typing once you only look at the message. Plugins use this to keep\n * automatic writes and derived model calls on top-level sessions.\n */\nexport function isSubagentSession(session: unknown): boolean {\n  const header = (session as SubagentSessionLike | null | undefined)?.header\n  if (!header || typeof header !== 'object') return false\n  return Boolean(header.parentSession)\n    || header.origin === 'subagent'\n    || Number(header.delegationDepth ?? 0) > 0\n}\n\n/** Project keys come only from the host-validated session directory, never client input. */\nexport function projectIdFromCwd(cwd: string | undefined): string | undefined {\n  if (typeof cwd !== 'string') return undefined\n  const normalized = cwd.trim().replaceAll('\\\\', '/')\n  if (!normalized) return undefined\n  return normalized === '/' || /^[A-Za-z]:\\/$/.test(normalized) ? normalized : normalized.replace(/\\/+$/, '')\n}\n","import { useCallback, useEffect, useRef, useSyncExternalStore } from 'react'\n\nexport interface NativeSurfaceClient {\n  sessions: {\n    binding?(sessionId: string): { eventSource: { subscribe(listener: () => void): () => void } } | undefined\n  }\n  uiWorkspace: { current?: { getSnapshot(): { sessionId: string } | undefined; subscribe(listener: () => void): () => void } }\n  uiSession: { adapter: { current: { getSnapshot(): { key?: string }; subscribe(listener: () => void): () => void } } }\n  locale: { getSnapshot(): { active: string }; subscribe(listener: () => void): () => void }\n  connection?: { generation?: { subscribe(listener: () => void): () => void } }\n}\n\n/** The Editor retains its manuscript session separately; native DSH exposes the main-view binding. */\nexport function selectedSessionId(client: Pick<NativeSurfaceClient, 'uiWorkspace' | 'uiSession'>): string {\n  const workspace = client.uiWorkspace?.current\n  return workspace\n    ? workspace.getSnapshot()?.sessionId ?? ''\n    : client.uiSession.adapter.current.getSnapshot().key ?? ''\n}\n\n/**\n * Owner props are data the host composed, never a Cordis context: reading an\n * undeclared property off one throws instead of returning undefined, which\n * would crash the slot entry and abdicate its cell for good. Tolerate a\n * throwing read so a mistaken prop degrades to \"not supplied\".\n */\nfunction read(source: unknown, key: string): unknown {\n  if (source === null || typeof source !== 'object') return undefined\n  try {\n    return (source as Record<string, unknown>)[key]\n  } catch {\n    return undefined\n  }\n}\n\nfunction readString(source: unknown, key: string): string | undefined {\n  const value = read(source, key)\n  return typeof value === 'string' ? value : undefined\n}\n\n/** Owner props win; native settings only supplies close, so resolve its selected session. */\nexport function useNativeSeat(client: NativeSurfaceClient, props?: unknown) {\n  const current = useSyncExternalStore(\n    useCallback((fn: () => void) => (client.uiWorkspace?.current ?? client.uiSession.adapter.current).subscribe(fn), [client]),\n    useCallback(() => selectedSessionId(client), [client]),\n    () => '',\n  )\n  const language = useSyncExternalStore(\n    useCallback((fn: () => void) => client.locale.subscribe(fn), [client]),\n    useCallback(() => client.locale.getSnapshot().active, [client]),\n    () => 'en',\n  )\n  const sessionId = readString(props, 'sessionId') ?? readString(read(props, 'owner'), 'sessionId') ?? current\n  const requestedLocale = read(props, 'locale') ?? read(read(props, 'owner'), 'locale') ?? language\n  return { sessionId, locale: (String(requestedLocale).startsWith('zh') ? 'zh' : 'en') as 'zh' | 'en',\n    hidden: read(props, 'hidden') === true || read(read(props, 'owner'), 'hidden') === true }\n}\n\n/** Refresh on native log boundaries/reconnect/focus. Read-only settling is bounded to an observed job. */\nexport function useFeatureRefresh(\n  client: NativeSurfaceClient, sessionId: string, refresh: () => void,\n  working = false, enabled = true,\n): void {\n  const refreshRef = useRef(refresh)\n  refreshRef.current = refresh\n  useEffect(() => {\n    if (!enabled) return\n    let timer: ReturnType<typeof setTimeout> | undefined\n    const queue = () => {\n      if (typeof document !== 'undefined' && document.visibilityState === 'hidden') return\n      clearTimeout(timer)\n      timer = setTimeout(() => refreshRef.current(), 150)\n    }\n    const source = sessionId ? client.sessions.binding?.(sessionId)?.eventSource : undefined\n    const stopEvents = source?.subscribe(queue)\n    const stopConnection = client.connection?.generation?.subscribe(queue)\n    const visibility = () => { if (document.visibilityState === 'visible') queue() }\n    window.addEventListener('focus', queue)\n    document.addEventListener('visibilitychange', visibility)\n    // Details are collapsed by default; opening an existing panel must get current state.\n    document.addEventListener('toggle', queue, true)\n    return () => {\n      clearTimeout(timer)\n      stopEvents?.(); stopConnection?.()\n      window.removeEventListener('focus', queue)\n      document.removeEventListener('visibilitychange', visibility)\n      document.removeEventListener('toggle', queue, true)\n    }\n  }, [client, sessionId, enabled])\n  useEffect(() => {\n    if (!enabled || !working) return\n    let delay = 250\n    const until = Date.now() + 300_000\n    let timer: ReturnType<typeof setTimeout>\n    const tick = () => {\n      if (Date.now() >= until) return\n      if (document.visibilityState !== 'hidden') refreshRef.current()\n      delay = Math.min(delay * 2, 2000)\n      timer = setTimeout(tick, delay)\n    }\n    timer = setTimeout(tick, delay)\n    return () => clearTimeout(timer)\n  }, [client, sessionId, working, enabled])\n}\n","/**\n * Shared plugin-page model menu.\n *\n * A feature plugin's own settings row exposes a model select. An empty\n * selection means the host default chat model for that feature's own call.\n *\n * Browser-safe and React-optional: pure helpers live here so hosts and clients\n * share one catalog contract without bundling React into the host build.\n */\nimport { useEffect, useState } from 'react'\nimport type { ModelRoute } from './contracts.ts'\n\n/** One selectable model. `efforts` are the advertised reasoning efforts. */\nexport interface ModelMenuChoice {\n  readonly provider: string\n  readonly model: string\n  readonly label: string\n  readonly efforts: ReadonlyArray<{ id: string; name: string }>\n}\n\n/** The stored selection. Empty provider/model means \"follow the default\". */\nexport type ModelMenuRoute = ModelRoute\n\n/** The catalog face this helper needs; stays structural so hosts may add more. */\nexport interface ModelCatalogClient {\n  readonly remote?: {\n    readonly session?: { readonly modelCatalog?: () => Promise<unknown> }\n  }\n}\n\nconst KEY_SEPARATOR = '\\u001f'\n\nexport function modelMenuChoiceKey(provider: string, model: string): string {\n  return provider && model ? `${provider}${KEY_SEPARATOR}${model}` : ''\n}\n\nexport function parseModelMenuChoiceKey(value: string): { provider: string; model: string } | undefined {\n  const index = value.indexOf(KEY_SEPARATOR)\n  if (index <= 0) return undefined\n  const provider = value.slice(0, index)\n  const model = value.slice(index + KEY_SEPARATOR.length)\n  if (!provider || !model) return undefined\n  return { provider, model }\n}\n\nfunction asRecord(value: unknown): Record<string, unknown> | undefined {\n  return value && typeof value === 'object' && !Array.isArray(value) ? value as Record<string, unknown> : undefined\n}\n\nfunction asText(value: unknown): string | undefined {\n  return typeof value === 'string' && value.trim() ? value.trim() : undefined\n}\n\nfunction parseEffort(value: unknown): { id: string; name: string } | undefined {\n  const row = asRecord(value)\n  const id = row ? asText(row.id) : undefined\n  if (!id) return undefined\n  return { id, name: row ? asText(row.name) ?? id : id }\n}\n\n/** Parse the host session catalog into flat choices, keeping a saved route selectable. */\nexport function parseModelMenuChoices(value: unknown, bound?: ModelMenuRoute): ModelMenuChoice[] {\n  const envelope = asRecord(value)\n  // Host remote calls resolve to a result envelope ({ ok, value }); older hosts\n  // and unit tests hand over the bare catalog. Accept both.\n  const root = (envelope && envelope.ok === true ? asRecord(envelope.value) : undefined) ?? envelope ?? {}\n  const groups = Array.isArray(root.groups) ? root.groups : []\n  const choices: ModelMenuChoice[] = []\n  for (const group of groups) {\n    const groupRow = asRecord(group)\n    const provider = groupRow ? asText(groupRow.id) : undefined\n    if (!provider || !groupRow || !Array.isArray(groupRow.models)) continue\n    const providerName = asText(groupRow.name) ?? provider\n    for (const entry of groupRow.models) {\n      const modelRow = asRecord(entry)\n      const model = modelRow ? asText(modelRow.id) : undefined\n      if (!model || !modelRow) continue\n      const name = asText(modelRow.name) ?? model\n      const reasoning = asRecord(modelRow.reasoning)\n      const efforts = reasoning && Array.isArray(reasoning.efforts)\n        ? reasoning.efforts.flatMap(effort => { const parsed = parseEffort(effort); return parsed ? [parsed] : [] })\n        : []\n      choices.push({ provider, model, label: `${providerName} / ${name}`, efforts })\n    }\n  }\n  if (bound?.provider && bound.model && !choices.some(item => item.provider === bound.provider && item.model === bound.model)) {\n    choices.push({ provider: bound.provider, model: bound.model, label: `${bound.provider} / ${bound.model}`, efforts: [] })\n  }\n  return choices\n}\n\n/** An empty saved route means no explicit model. */\nexport function modelMenuOverride(route: ModelMenuRoute | undefined): ModelRoute | undefined {\n  const provider = route?.provider?.trim()\n  const model = route?.model?.trim()\n  if (!provider || !model) return undefined\n  const effort = route?.reasoningEffort?.trim()\n  return effort ? { provider, model, reasoningEffort: effort } : { provider, model }\n}\n\nexport function normalizeModelMenuRoute(value: unknown): ModelMenuRoute {\n  const row = asRecord(value)\n  if (!row) return { provider: '', model: '' }\n  const provider = asText(row.provider) ?? ''\n  const model = asText(row.model) ?? ''\n  const effort = asText(row.reasoningEffort)\n  if (!provider || !model || provider.length > 250 || model.length > 250) return { provider: '', model: '' }\n  return effort && effort.length <= 80 ? { provider, model, reasoningEffort: effort } : { provider, model }\n}\n\n/** Load the host catalog once per mount and republish whenever it answers. */\nexport function useModelMenuChoices(client: ModelCatalogClient, bound?: ModelMenuRoute): ModelMenuChoice[] {\n  const [choices, setChoices] = useState<ModelMenuChoice[]>([])\n  useEffect(() => {\n    if (typeof document === 'undefined') return\n    let live = true\n    const load = () => {\n      void client.remote?.session?.modelCatalog?.()\n        ?.then(value => { if (live) setChoices(parseModelMenuChoices(value, bound)) })\n        .catch(() => { if (live) setChoices([]) })\n    }\n    load()\n    return () => { live = false }\n  }, [client, bound?.provider, bound?.model])\n  return choices\n}\n\n/** Reasoning-effort options for one choice; the saved value stays selectable. */\nexport function modelMenuEffortOptions(\n  choice: ModelMenuChoice | undefined,\n  current?: string,\n): Array<{ id: string; name: string }> {\n  const listed = (choice?.efforts ?? []).map(item => ({ ...item }))\n  if (current && !listed.some(item => item.id === current)) listed.push({ id: current, name: current })\n  return listed\n}\n","/**\n * Shared contract that keeps every plugin's browser-side UI on the official\n * DeepSeek Harness Web design language.\n *\n * Two rules produce that language, and both are load-bearing here:\n *\n * 1. Colour, radius, elevation and focus come from the host theme's real\n *    `--dsw-*` tokens, written under their own names. Plugins never invent a\n *    token, never alias the official ones behind a private palette (a private\n *    alias is just a second, diverging theme), and never carries a literal\n *    fallback — the host publishes light and dark, and a literal would pin one\n *    of them. The only non-colour custom properties used are the host's own\n *    content-font axis and frame clearance.\n *\n * 2. Anything the host already ships is used, not reimplemented. Controls come\n *    from `@deepseek-ai/dsh-client-ui-primitives` (`Button`, `Input`,\n *    `Checkbox`, `Switch`, `Tag`, `Pill`, `SegmentedControl`, `Menu`, `Modal`,\n *    `Tooltip`, `Toast`, `DisclosureRow`, `StateDot`, `PathLabel`, the settings\n *    form suite). This module only styles what primitives do not cover: page\n *    scaffolding, field layout, banners, empty states and scroll regions.\n *\n * The metrics below are transcribed from the primitives' own CSS modules so a\n * feature panel lines up pixel-for-pixel with a native one: the 14/22 body and\n * 13/20 compact type tiers, the 0.5px hairline scale, and the elevation family\n * that draws a surface's edge in its shadow (`border: 0`) instead of a border.\n */\n\n/**\n * Every `--dsw-*` token this repo is allowed to reference, grouped by role.\n *\n * Plugins may only colour through this list. It is exported so the guard test\n * can fail a build when a stylesheet reaches for anything else — the failure\n * mode this prevents is silent: an unknown token resolves to nothing, so a\n * border disappears or a label inherits the wrong colour with no error anywhere.\n */\nexport const OFFICIAL_THEME_TOKENS = {\n  /** Surfaces, from the page up to the topmost nested card. */\n  surface: [\n    '--dsw-alias-bg-base',\n    '--dsw-alias-bg-layer-1',\n    '--dsw-alias-bg-layer-2',\n    '--dsw-alias-bg-layer-3',\n    '--dsw-alias-bg-layer-4',\n    '--dsw-alias-bg-module-platform',\n    '--dsw-alias-bg-overlay',\n  ],\n  /** Hairlines. l1 is near-invisible on a menu surface, so menus use l2+. */\n  border: ['--dsw-alias-border-l1', '--dsw-alias-border-l2', '--dsw-alias-border-l3', '--dsw-alias-border-l4'],\n  /** Text. `caption` is menu shortcut text, `dimmed` is placeholder text. */\n  label: [\n    '--dsw-alias-label-primary',\n    '--dsw-alias-label-secondary',\n    '--dsw-alias-label-tertiary',\n    '--dsw-alias-label-caption',\n    '--dsw-alias-label-dimmed',\n    '--dsw-alias-label-error',\n    '--dsw-alias-label-primary-foreground',\n  ],\n  /** Interactive fills. The `-danger` hover belongs to destructive rows. */\n  interactive: [\n    '--dsw-alias-interactive-bg-hover',\n    '--dsw-alias-interactive-bg-active',\n    '--dsw-alias-interactive-bg-hover-danger',\n  ],\n  /** Accent and status. `business` is the focus ring's default colour. */\n  accent: [\n    '--dsw-alias-brand-primary',\n    '--dsw-alias-button-primary-fill',\n    '--dsw-alias-button-primary-hover',\n    '--dsw-alias-button-tool-bar-fill',\n    '--dsw-alias-button-tool-bar-hover',\n    '--dsw-alias-button-ghost-active-fill',\n    '--dsw-alias-button-ghost-active-border',\n  ],\n  state: [\n    '--dsw-alias-state-business-primary',\n    '--dsw-alias-state-success-primary',\n    '--dsw-alias-state-warn-primary',\n    '--dsw-alias-state-error-primary',\n    '--dsw-alias-state-idle-primary',\n  ],\n  /** Corner scale: sm 8, md 12, lg the large card, panel the modal. */\n  radius: ['--dsw-radius-sm', '--dsw-radius-md', '--dsw-radius-lg', '--dsw-radius-panel'],\n  /** An elevated surface draws its edge in the shadow, so it keeps border: 0. */\n  elevation: [\n    '--dsw-elevation-soft',\n    '--dsw-elevation-stroke',\n    '--dsw-elevation-stroke-color',\n    '--dsw-elevation-panel',\n    '--dsw-elevation-prominent',\n  ],\n  /** Floats, masks and scrollbars. */\n  overlay: [\n    '--dsw-menu-surface-fill',\n    '--dsw-menu-backdrop-filter',\n    '--dsw-mask-blur',\n    '--dsw-alias-bg-mask-1',\n    '--dsw-alias-menu-icon',\n    '--dsw-alias-scrollbar-bg-l2',\n    '--dsw-alias-scrollbar-hover-l2',\n    '--dsw-shadow-lv3',\n  ],\n  /** Motion, focus and type axis, published by the host rather than by a component. */\n  system: [\n    '--dsw-focus-ring-width',\n    '--dsw-focus-ring-color',\n    '--dsw-font-markdown-code-font-family',\n    '--ds-transition-duration',\n    '--ds-ease-in-out',\n    '--ds-font-family-code',\n    '--dsh-scrollbar-thumb',\n    '--dsh-scrollbar-thumb-hover',\n    '--dsh-content-font-size-secondary',\n    '--dsh-content-font-delta',\n    '--dsh-frame-top-clearance',\n  ],\n} as const\n\n/** Every official token name, flat. Used by the token guard test. */\nexport const OFFICIAL_THEME_TOKEN_NAMES: readonly string[] = Object.values(OFFICIAL_THEME_TOKENS).flat()\n\n/** The elevation steps a surface can be raised by, softest first. */\nexport type OfficialElevation = 'soft' | 'stroke' | 'panel' | 'prominent'\n\n/**\n * The host's focus ring shorthand, verbatim. Writing this per control is how\n * rings drift apart; a stylesheet that draws its own focus style should use\n * {@link officialFocus} instead. The colour fallback is the host's own default.\n */\nexport const OFFICIAL_FOCUS_RING =\n  'var(--dsw-focus-ring-width) solid var(--dsw-focus-ring-color, var(--dsw-alias-state-business-primary))'\n\n/**\n * A complete `outline` declaration at the official geometry. `offset` defaults\n * to the 2px the native controls use; the host's inline field rules sit at 1px\n * and a segmented tab pulls the ring inside itself at -2px.\n */\nexport function officialFocus(offset = '2px'): string {\n  return `outline: ${OFFICIAL_FOCUS_RING}; outline-offset: ${offset}`\n}\n\n/**\n * An elevated surface. The host draws a raised surface's edge inside its\n * shadow rather than as a border, so a card sets `border: 0` and takes the edge\n * from the elevation — which is also why its border stays off the alias-border\n * set that a flat, non-elevated rule would use.\n */\nexport function officialElevation(level: OfficialElevation): string {\n  return `border: 0; box-shadow: var(--dsw-elevation-${level})`\n}\n\n/**\n * An elevated surface whose edge should read as a specific hairline. Rebinding\n * the stroke colour is how a menu card picks l1 while a panel picks l3, without\n * the two growing apart by hand.\n */\nexport function officialStrokedElevation(level: OfficialElevation, color: string): string {\n  return `--dsw-elevation-stroke-color: ${color}; ${officialElevation(level)}`\n}\n\n/**\n * The shared stylesheet for a plugin UI, scoped under that plugin's root class.\n *\n * Scoping is what keeps this safe to always-bundle into every client: the rules\n * can only match inside the plugin's own subtree, so two plugins can both mount\n * `dsh-ui-card` without either styling the other's markup.\n *\n * Each recipe matches the root element *and* its descendants, because the\n * commonest arrangement is one element that is both — a surface that carries\n * the root class and `dsh-ui-card`, or a portaled dialog that is the root and\n * the `dsh-ui-surface`. A descendant-only scope would silently leave those\n * unstyled, with no error anywhere.\n *\n * A caveat worth knowing: `Modal` and `Menu` portal to `document.body`, so their\n * content leaves the plugin's subtree entirely. A portaled surface therefore\n * needs its own root class on an element inside the portal.\n *\n * Only patterns that primitives do not provide live here. If a control appears\n * below that `Button`/`Input`/`Switch`/`Tag`/`Menu` already covers, that is a\n * bug in this file: use the primitive and delete the recipe.\n */\nexport function officialUiCss(roots: string | readonly string[]): string {\n  // One plugin often mounts several unrelated surfaces (a settings seat, a chat\n  // card, a header menu), so the caller names every root. The rules below are\n  // nested under a single selector list and use `&`, which the browser expands\n  // per root — so one stylesheet covers all of them without duplicating itself.\n  const scope = (typeof roots === 'string' ? [roots] : roots).map(root => `.${root}`).join(', ')\n  const sheet = `\n/* Official DSH Web UI contract. Generated by @klarkxy/dsh-plugin-kit/official-ui.\n * Do not hand-edit the copy inside a plugin: change this module so every plugin\n * moves together. Scope: ${scope} */\n/* The scope rule below stays open for the whole sheet: every rule after it\n * nests with the parent selector, so one stylesheet can cover several unrelated\n * roots without leaking into a neighbouring plugin. Its closing brace is last. */\n${scope} {\n  color: var(--dsw-alias-label-primary);\n  font-family: inherit;\n  font-size: 14px;\n  line-height: 22px;\n  min-width: 0;\n\n& *, & *::before, & *::after { box-sizing: border-box; }\n& h1, & h2, & h3, & h4, & p, & figure { margin: 0; }\n/* Keyboard focus only: pointer input keeps the native resting appearance. The\n * ring needs no radius of its own — the outline already follows the control's\n * own border-radius, and overriding it here would flatten every control. */\n& :focus-visible { ${officialFocus()}; }\n& [hidden] { display: none !important; }\n\n/* --- Type tiers. The same 14/22 and 13/20 steps the primitives use. --- */\n& .dsh-ui-title { font-size: 16px; line-height: 24px; font-weight: 500; color: var(--dsw-alias-label-primary); }\n& .dsh-ui-heading { font-size: 14px; line-height: 22px; font-weight: 500; color: var(--dsw-alias-label-primary); }\n& .dsh-ui-compact { font-size: 13px; line-height: 20px; color: var(--dsw-alias-label-primary); }\n& .dsh-ui-meta { font-size: 12px; line-height: 18px; color: var(--dsw-alias-label-secondary); }\n& .dsh-ui-hint { font-size: 12px; line-height: 18px; color: var(--dsw-alias-label-tertiary); }\n& .dsh-ui-error { font-size: 12px; line-height: 18px; color: var(--dsw-alias-state-error-primary); }\n& .dsh-ui-warn { color: var(--dsw-alias-state-warn-primary); }\n& .dsh-ui-success { color: var(--dsw-alias-state-success-primary); }\n& .dsh-ui-muted { color: var(--dsw-alias-label-tertiary); }\n& .dsh-ui-truncate { min-width: 0; overflow: hidden; text-overflow: ellipsis; white-space: nowrap; }\n& .dsh-ui-wrap { min-width: 0; overflow-wrap: anywhere; }\n\n/* --- Layout scaffolding. --- */\n& .dsh-ui-stack { display: flex; flex-direction: column; gap: 12px; }\n& .dsh-ui-stack-lg { display: flex; flex-direction: column; gap: 20px; }\n& .dsh-ui-row { display: flex; align-items: center; gap: 8px; min-width: 0; }\n& .dsh-ui-row-wrap { display: flex; align-items: center; flex-wrap: wrap; gap: 8px; }\n& .dsh-ui-spacer { flex: 1; min-width: 0; }\n/* A 0.5px l2 rule is the host's section divider; reserve the same rhythm. */\n& .dsh-ui-divider { height: 0.5px; background: var(--dsw-alias-border-l2); }\n& .dsh-ui-section { display: flex; flex-direction: column; gap: 12px; padding-top: 16px; border-top: 0.5px solid var(--dsw-alias-border-l2); }\n\n/* --- Card: a raised surface whose edge lives in the shadow. --- */\n& .dsh-ui-card {\n  ${officialElevation('stroke')}\n  display: flex;\n  flex-direction: column;\n  gap: 12px;\n  padding: 16px;\n  border-radius: var(--dsw-radius-lg);\n  background: var(--dsw-alias-bg-layer-1);\n  color: var(--dsw-alias-label-primary);\n  min-width: 0;\n}\n& .dsh-ui-card--flat { border: 0.5px solid var(--dsw-alias-border-l3); box-shadow: none; }\n& .dsh-ui-card--nested { background: var(--dsw-alias-bg-layer-2); }\n& .dsh-ui-card--plain { background: none; }\n\n/* --- Field: label, control, help, error. The control itself is an\n * official primitive, so this only owns the vertical rhythm. --- */\n& .dsh-ui-field { display: flex; flex-direction: column; gap: 6px; min-width: 0; }\n& .dsh-ui-field + .dsh-ui-field { border-top: 0.5px solid var(--dsw-alias-border-l2); padding-top: 12px; }\n& .dsh-ui-label { display: flex; align-items: center; gap: 6px; font-size: 13px; line-height: 20px; font-weight: 500; color: var(--dsw-alias-label-primary); }\n& .dsh-ui-label-row { display: flex; align-items: baseline; justify-content: space-between; gap: 8px; }\n& .dsh-ui-help { font-size: 12px; line-height: 1.6; color: var(--dsw-alias-label-secondary); }\n& .dsh-ui-help p { margin: 0; }\n& .dsh-ui-help p + p { margin-top: 8px; }\n& .dsh-ui-required { color: var(--dsw-alias-state-error-primary); }\n& .dsh-ui-control { width: 100%; min-width: 0; }\n/* An invalid control is marked on the control, not only in the message. */\n& .dsh-ui-control[aria-invalid='true'] { border-color: var(--dsw-alias-state-error-primary); }\n& .dsh-ui-readonly { display: flex; flex-direction: column; gap: 4px; min-width: 0; }\n& .dsh-ui-readonly > dt { font-size: 12px; line-height: 18px; color: var(--dsw-alias-label-tertiary); }\n& .dsh-ui-readonly > dd { margin: 0; font-size: 13px; line-height: 20px; overflow-wrap: anywhere; }\n\n/* --- Buttons row. A no-op container: it exists so actions line up on the\n * trailing edge the way every native panel does. --- */\n& .dsh-ui-actions { display: flex; flex-wrap: wrap; align-items: center; gap: 8px; padding-top: 4px; }\n& .dsh-ui-actions-end { justify-content: flex-end; }\n\n/* --- Banners. A banner is a left-rail notice, the shape used for warnings,\n * deprecations and blocking instructions. --- */\n& .dsh-ui-banner {\n  display: flex;\n  flex-direction: column;\n  gap: 8px;\n  padding: 10px 14px;\n  border: 0.5px solid var(--dsw-alias-border-l3);\n  border-left: 3px solid var(--dsw-alias-state-warn-primary);\n  border-radius: var(--dsw-radius-md);\n  background: var(--dsw-alias-bg-layer-1);\n  font-size: 13px;\n  line-height: 20px;\n  color: var(--dsw-alias-label-secondary);\n}\n& .dsh-ui-banner-title { font-weight: 500; color: var(--dsw-alias-state-warn-primary); }\n& .dsh-ui-banner--info { border-left-color: var(--dsw-alias-state-business-primary); }\n& .dsh-ui-banner--danger { border-left-color: var(--dsw-alias-state-error-primary); }\n& .dsh-ui-banner--success { border-left-color: var(--dsw-alias-state-success-primary); }\n& .dsh-ui-banner p { margin: 0; }\n\n/* --- Inline notice: a transient confirmation with no chrome of its own. --- */\n& .dsh-ui-notice { display: flex; align-items: center; gap: 6px; font-size: 12px; line-height: 18px; color: var(--dsw-alias-state-success-primary); }\n& .dsh-ui-notice--error { color: var(--dsw-alias-state-error-primary); }\n\n/* --- Empty and loading states. Both sit in a dashed well so an empty panel\n * reads as \"nothing here yet\" rather than as a broken layout. --- */\n& .dsh-ui-empty {\n  display: flex;\n  flex-direction: column;\n  align-items: flex-start;\n  gap: 6px;\n  padding: 20px 16px;\n  border: 0.5px dashed var(--dsw-alias-border-l3);\n  border-radius: var(--dsw-radius-md);\n  font-size: 13px;\n  line-height: 20px;\n  color: var(--dsw-alias-label-secondary);\n}\n& .dsh-ui-loading { display: flex; align-items: center; gap: 8px; padding: 20px 0; font-size: 13px; line-height: 20px; color: var(--dsw-alias-label-secondary); }\n\n/* --- Selectable list. A row is a button-sized target with a hover fill and\n * a selected fill; the name carries the weight, the description does not. --- */\n& .dsh-ui-list { list-style: none; margin: 0; padding: 0; display: flex; flex-direction: column; gap: 2px; min-width: 0; }\n& .dsh-ui-list-scroll { max-height: min(66vh, 760px); overflow-y: auto; overflow-x: hidden; }\n& .dsh-ui-list-row { border-radius: var(--dsw-radius-md); }\n& .dsh-ui-list-row:hover { background: var(--dsw-alias-interactive-bg-hover); }\n& .dsh-ui-list-row[aria-selected='true'], & .dsh-ui-list-row[data-selected] { background: var(--dsw-alias-interactive-bg-active); }\n& .dsh-ui-list-item {\n  display: flex;\n  flex-direction: column;\n  align-items: flex-start;\n  gap: 4px;\n  width: 100%;\n  min-width: 0;\n  padding: 10px 12px;\n  border: 0;\n  border-radius: var(--dsw-radius-md);\n  background: none;\n  font: inherit;\n  color: inherit;\n  text-align: start;\n  cursor: pointer;\n}\n& .dsh-ui-list-item:disabled { cursor: default; }\n& .dsh-ui-list-item:disabled:hover { background: none; }\n& .dsh-ui-list-name { font-size: 14px; line-height: 22px; font-weight: 500; color: var(--dsw-alias-label-primary); overflow-wrap: anywhere; }\n& .dsh-ui-list-desc { font-size: 12px; line-height: 18px; color: var(--dsw-alias-label-tertiary); }\n\n/* --- Code and structured output. Wraps rather than scrolls, because a\n * feature panel is read rather than scanned. --- */\n& .dsh-ui-code {\n  padding: 10px 12px;\n  border: 0.5px solid var(--dsw-alias-border-l3);\n  border-radius: var(--dsw-radius-md);\n  background: var(--dsw-alias-bg-layer-1);\n  font-family: var(--ds-font-family-code, ui-monospace, 'Cascadia Mono', Consolas, monospace);\n  font-size: 12px;\n  line-height: 20px;\n  color: var(--dsw-alias-label-secondary);\n  overflow-wrap: anywhere;\n  white-space: pre-wrap;\n}\n& .dsh-ui-scroll { max-height: 60vh; overflow: auto; overscroll-behavior: contain; }\n\n/* --- A toggle row: label on the left, switch on the trailing edge. This is\n * layout only; the switch itself is the official primitive. --- */\n& .dsh-ui-toggle-row { display: flex; align-items: center; justify-content: space-between; gap: 16px; min-width: 0; padding: 12px 0; }\n& .dsh-ui-toggle-row + .dsh-ui-toggle-row { border-top: 0.5px solid var(--dsw-alias-border-l2); }\n& .dsh-ui-toggle-text { display: flex; flex-direction: column; gap: 4px; min-width: 0; }\n& .dsh-ui-toggle-label { font-size: 14px; line-height: 22px; font-weight: 500; color: var(--dsw-alias-label-primary); }\n\n/* --- Floating surface: a panel anchored to a trigger. This is the material\n * a menu card is made of — the translucent fill plus its backdrop blur, with\n * the edge riding inside the prominent elevation. A plugin that hand-rolls this\n * is how tokens like --dsw-specific-menu get invented; use this instead. --- */\n& .dsh-ui-surface {\n  --dsw-elevation-stroke-color: var(--dsw-alias-border-l1);\n  --dsh-scrollbar-thumb: var(--dsw-alias-scrollbar-bg-l2);\n  --dsh-scrollbar-thumb-hover: var(--dsw-alias-scrollbar-hover-l2);\n  position: relative;\n  display: flex;\n  flex-direction: column;\n  border: 0;\n  border-radius: var(--dsw-radius-lg);\n  background: var(--dsw-menu-surface-fill);\n  backdrop-filter: var(--dsw-menu-backdrop-filter);\n  box-shadow: var(--dsw-elevation-prominent);\n  color: var(--dsw-alias-label-primary);\n  font-size: 13px;\n  line-height: 20px;\n  min-width: 0;\n}\n& .dsh-ui-surface-body { display: flex; flex-direction: column; gap: 8px; padding: 12px 14px 14px; overflow-y: auto; }\n& .dsh-ui-surface-head { display: flex; align-items: center; gap: 8px; min-width: 0; }\n& .dsh-ui-surface-title { font-size: 14px; line-height: 22px; font-weight: 500; color: var(--dsw-alias-label-primary); }\n\n/* --- Native select. The primitives ship no select, so a plugin that offers a\n * closed list of choices keeps the platform control and matches the official\n * settings field geometry exactly (34px, 0.5px l4, radius-md, layer-3). A\n * SegmentedControl is the primitive to reach for when the choices are few\n * enough to show at once. --- */\n& .dsh-ui-select {\n  box-sizing: border-box;\n  width: 100%;\n  min-width: 0;\n  height: 34px;\n  padding: 0 12px;\n  border: 0.5px solid var(--dsw-alias-border-l4);\n  border-radius: var(--dsw-radius-md);\n  background: var(--dsw-alias-bg-layer-3);\n  font: inherit;\n  font-size: 13px;\n  line-height: 1.5;\n  color: var(--dsw-alias-label-primary);\n  cursor: pointer;\n}\n& .dsh-ui-select:focus-visible { outline: none; border-color: var(--dsw-alias-state-business-primary); }\n& .dsh-ui-select:disabled { color: var(--dsw-alias-label-tertiary); cursor: default; }\n& .dsh-ui-select[aria-invalid='true'] { border-color: var(--dsw-alias-state-error-primary); }\n\n/* Long panels scroll inside themselves instead of growing the host page. */\n& .dsh-ui-panel { display: flex; flex-direction: column; gap: 16px; min-width: 0; }\n& .dsh-ui-panel-wide { max-width: 100%; }\n\n@media (prefers-reduced-motion: reduce) {\n  & *, & *::before, & *::after { transition-duration: 0.01ms !important; animation-duration: 0.01ms !important; }\n}\n}\n`\n  // Widen every recipe from \"a descendant of the root\" to \"the root, or one of\n  // its descendants\". Written as a transform rather than by hand so no recipe\n  // can be added later with only the descendant form. The pattern is narrow on\n  // purpose: a leading `&` followed by one recipe class and no combinator, so\n  // sibling and child rules such as `.dsh-ui-field + .dsh-ui-field` keep their\n  // own meaning and are left alone.\n  return sheet.replace(/^& (\\.dsh-ui-[a-z0-9-]+)(?![+>~])/gm, (_match, className: string) =>\n    `&${className}, & ${className}`)\n}\n","/** Recap-owned records. Shared TaskCheckpoint / RPC / slot names come from @klarkxy/dsh-plugin-kit/contracts. */\nimport type {\n  EvidenceRef,\n  ProducerMessageSource,\n  RpcResult,\n  TaskCheckpoint,\n  TaskContract,\n} from '@klarkxy/dsh-plugin-kit/contracts'\n\nexport type {\n  EvidenceRef,\n  ProducerMessageSource,\n  RpcResult,\n  TaskCheckpoint,\n  TaskContract,\n}\n\nexport { CHAT_EVENTS_SLOT } from '@klarkxy/dsh-plugin-kit/contracts'\n\n/** DSH message source identity for this plugin's own messages. */\nexport const RECAP_PLUGIN = '@klarkxy/dsh-recap'\nexport const RECAP_SOURCE_KIND = 'plugin:@klarkxy/dsh-recap' as const\nexport const RECAP_RPC_CHANNEL = '/dsh-recap'\nexport const RECAP_DISPLAY_PURPOSE = 'recap.display'\nexport const RECAP_CHECKPOINT_PURPOSE = 'recap.checkpoint'\nexport const DEFAULT_IDLE_RETURN_MS = 15 * 60 * 1000\nexport const MAX_LOG_EVENTS = 256\nexport const MAX_EXCERPT_CHARS = 200\nexport const MAX_CARD_BODY_CHARS = 4000\nexport const MAX_CHECKPOINT_CHARS = 2000\nexport const LONG_TASK_MIN_MS = 60_000\nexport const LONG_TASK_MIN_STEPS = 2\nexport const LONG_TASK_MIN_TOOLS = 3\nexport const MEANINGFUL_TOOL_DELTA = 3\n\nexport type RecapSourceStatus = 'completed' | 'failed' | 'cancelled' | 'running'\nexport type RecapTrigger = 'turn-end' | 'idle-return' | 'retry' | 'manual'\nexport type RecapCardKind = 'deterministic' | 'generated' | 'cached'\nexport type RecapGeneration = 'idle' | 'running' | 'failed' | 'cancelled' | 'superseded'\n\n/** Plugin-page model selection. Empty provider/model means \"follow the default\". */\nexport interface RecapModelRoute {\n  readonly provider: string\n  readonly model: string\n  readonly reasoningEffort?: string\n}\n\nexport interface RecapSettings {\n  revision: number\n  cardsEnabled: boolean\n  checkpointsEnabled: boolean\n  semanticCheckpointsEnabled: boolean\n  idleReturnMs: number\n  /** Model for recap cards (display) and semantic checkpoints, chosen on the plugin page. */\n  displayModel: RecapModelRoute\n  checkpointModel: RecapModelRoute\n}\n\nexport const defaultModelRoute = (): RecapModelRoute => ({ provider: '', model: '' })\n\nexport const defaultSettings = (): RecapSettings => ({\n  revision: 0,\n  cardsEnabled: true,\n  checkpointsEnabled: true,\n  semanticCheckpointsEnabled: true,\n  idleReturnMs: DEFAULT_IDLE_RETURN_MS,\n  displayModel: defaultModelRoute(),\n  checkpointModel: defaultModelRoute(),\n})\n\nexport interface RecapCard {\n  id: string\n  sessionId: string\n  sourceVersion: string\n  fromSeq: number\n  toSeq: number\n  trigger: RecapTrigger\n  sourceStatus: Exclude<RecapSourceStatus, 'running'>\n  title: string\n  body: string\n  kind: RecapCardKind\n  generation: RecapGeneration\n  receiptId?: string\n  createdAt: number\n  updatedAt: number\n}\n\nexport interface RecapPersistedState {\n  settings: RecapSettings\n  cards: RecapCard[]\n  checkpoints: TaskCheckpoint[]\n}\n\nexport interface RecapStore {\n  load(): RecapPersistedState\n  save(state: RecapPersistedState): Promise<void>\n}\n\nexport interface RecapStatus {\n  settings: RecapSettings\n  cards: RecapCard[]\n  checkpoints: TaskCheckpoint[]\n  storageFailed: boolean\n}\n\nexport interface RecapLogEvent {\n  seq: number\n  type: string\n  time: number\n  data: unknown\n}\n\nexport interface RecapToolFact {\n  name: string\n  callId?: string\n  proposedChange: boolean\n  error?: boolean\n  seq: number\n  outcome: 'verified' | 'failed' | 'unverified' | 'missing' | 'cancelled' | 'unknown'\n}\n\nexport interface RecapFacts {\n  sessionId: string\n  fromSeq: number\n  toSeq: number\n  sourceVersion: string\n  sourceStatus: RecapSourceStatus\n  turn?: number\n  stepCount: number\n  userTurns: number\n  toolCalls: number\n  toolResults: number\n  proposals: number\n  durationMs: number\n  lastUserExcerpt?: string\n  tools: RecapToolFact[]\n  constraints: string[]\n}\n\nexport type MoodContractApi = {\n  getContract?(sessionId: string): TaskContract | undefined\n}\n\nexport function fail<T = never>(code: string, message: string): RpcResult<T> {\n  return { ok: false, error: { code, message } }\n}\n\nexport function ok<T>(value: T): RpcResult<T> {\n  return { ok: true, value }\n}\n\nexport function recapSourceVersion(sessionId: string, toSeq: number): string {\n  return `${sessionId}#${toSeq}`\n}\n\nexport function parseSessionId(payload: unknown): string | undefined {\n  if (!payload || typeof payload !== 'object' || Array.isArray(payload)) return undefined\n  const sessionId = (payload as { sessionId?: unknown }).sessionId\n  return typeof sessionId === 'string' && sessionId.length > 0 && sessionId.length <= 200 ? sessionId : undefined\n}\n","export const USER_ACTIVITY_KINDS = ['pointer', 'keydown', 'focus', 'visible'] as const\nexport type UserActivityKind = (typeof USER_ACTIVITY_KINDS)[number]\n\nexport function isUserActivity(kind: string): kind is UserActivityKind {\n  return (USER_ACTIVITY_KINDS as readonly string[]).includes(kind)\n}\n\nexport function shouldRequestIdleReturn(input: {\n  now: number\n  lastUserActivityAt: number\n  idleReturnMs: number\n  cardsEnabled: boolean\n  visible: boolean\n  hidden?: boolean\n  focused?: boolean\n  assistantStreaming?: boolean\n}): boolean {\n  if (!input.cardsEnabled || input.hidden || !input.visible) return false\n  if (input.focused === false) return false\n  if (input.assistantStreaming) return false\n  return input.now - input.lastUserActivityAt >= input.idleReturnMs\n}\n\nexport function nextActivityTimestamp(kind: string, previous: number, now: number): number {\n  return isUserActivity(kind) ? now : previous\n}\n\nexport function shouldSkipRecapAutoRefresh(input: {\n  busy: boolean\n  editing?: boolean\n  disposed?: boolean\n}): boolean {\n  return input.busy || input.editing === true || input.disposed === true\n}\n\nexport function createRecapClientWork() {\n  let generation = 0\n  let request = 0\n  let disposed = false\n  return {\n    get disposed() { return disposed },\n    beginLoad() {\n      generation += 1\n      request += 1\n      return generation\n    },\n    beginRequest() {\n      request += 1\n      return { generation, request }\n    },\n    snapshot() {\n      return { generation, request }\n    },\n    isLoad(generationToken: number) {\n      return !disposed && generation === generationToken\n    },\n    isRequest(token: { generation: number; request: number }) {\n      return !disposed && generation === token.generation && request === token.request\n    },\n    dispose() {\n      disposed = true\n      generation += 1\n      request += 1\n    },\n  }\n}\n\nexport type RecapClientWork = ReturnType<typeof createRecapClientWork>\n\nexport function isCurrentRecapRequest(input: {\n  mounted: boolean\n  disposed?: boolean\n  sessionId: string\n  viewSessionId: string\n  requestId: number\n  latestRequestId: number\n  generation?: number\n  viewGeneration?: number\n}): boolean {\n  if (!input.mounted || input.disposed) return false\n  if (input.sessionId !== input.viewSessionId) return false\n  if (input.requestId !== input.latestRequestId) return false\n  if (input.generation !== undefined && input.generation !== input.viewGeneration) return false\n  return true\n}\n","import type { Context } from '@deepseek-ai/cordis'\nimport { CHAT_EVENTS_SLOT } from '@klarkxy/dsh-plugin-kit/contracts'\nimport { useFeatureRefresh, useNativeSeat, type NativeSurfaceClient } from '@klarkxy/dsh-plugin-kit/client-utils'\nimport {\n  modelMenuChoiceKey, modelMenuEffortOptions, parseModelMenuChoiceKey, parseModelMenuChoices, type ModelMenuChoice,\n} from '@klarkxy/dsh-plugin-kit/model-menu'\nimport { useEffect, useId, useRef, useState } from 'react'\nimport { Button, Input, StateDot, Switch } from '@deepseek-ai/dsh-client-ui-primitives'\nimport { officialUiCss } from '@klarkxy/dsh-plugin-kit/official-ui'\nimport {\n  RECAP_PLUGIN, RECAP_RPC_CHANNEL, defaultSettings,\n  type RecapCard, type RecapModelRoute, type RecapSettings, type RecapStatus, type RpcResult,\n} from './contracts.ts'\nimport {\n  createRecapClientWork, shouldRequestIdleReturn, shouldSkipRecapAutoRefresh, type RecapClientWork,\n} from './idle.ts'\n\nexport const name = 'dsh-recap-client'\nexport const inject = ['slots', 'connection', 'remote', 'remote.session', 'sessions', 'locale', 'uiWorkspace', 'uiSession'] as const\nexport {\n  createRecapClientWork, isCurrentRecapRequest, shouldRequestIdleReturn, shouldSkipRecapAutoRefresh,\n  nextActivityTimestamp,\n} from './idle.ts'\nexport { CHAT_EVENTS_SLOT }\n\ntype RpcCaller = { call(channel: string, endpoint: string, payload: unknown): Promise<unknown> }\ntype SlotHandle = {\n  inject(key: string, callback: () => unknown): () => void\n  register(spec: { name: string; id: string; label: string; order: number } | { name: string; key: string }, render: unknown): () => void\n}\ntype RecapClient = Context & NativeSurfaceClient & {\n  connection: { rpc: RpcCaller; generation?: { subscribe(listener: () => void): () => void } }\n  remote?: { session?: { modelCatalog?: () => Promise<unknown> } }\n  slots: SlotHandle\n}\n\nexport function recapHasRunningGeneration(cards: readonly RecapCard[]): boolean {\n  return cards.some(card => card.generation === 'running')\n}\n\nexport function recapSeatProps(props: unknown): { sessionId: string; locale?: string; hidden: boolean } | undefined {\n  if (!props || typeof props !== 'object' || Array.isArray(props)) return undefined\n  const record = props as Record<string, unknown>\n  const nested = record.owner && typeof record.owner === 'object' ? record.owner as Record<string, unknown> : undefined\n  const sessionId = typeof record.sessionId === 'string' ? record.sessionId : typeof nested?.sessionId === 'string' ? nested.sessionId : undefined\n  if (!sessionId) return undefined\n  const locale = typeof record.locale === 'string' ? record.locale : typeof nested?.locale === 'string' ? nested.locale : undefined\n  const hidden = record.hidden === true || nested?.hidden === true\n  return locale ? { sessionId, locale, hidden } : { sessionId, hidden }\n}\n\nexport function recapCardKey(seat: { sessionId: string; locale?: string }): string {\n  return `${seat.sessionId}:${seat.locale ?? ''}`\n}\n\nfunction unwrap<T>(result: RpcResult<T>): T {\n  if (!result.ok) throw new Error(result.error.message)\n  return result.value\n}\n\nexport async function recapCall<T>(rpc: RpcCaller, endpoint: string, payload: unknown = {}): Promise<T> {\n  return unwrap(await rpc.call(RECAP_RPC_CHANNEL, endpoint, payload) as RpcResult<T>)\n}\n\nfunction copy(locale: string | undefined, zh: string, en: string): string {\n  return locale === 'en' ? en : zh\n}\n\nexport async function runRecapStatusLoad(input: {\n  rpc: RpcCaller\n  sessionId?: string\n  isCurrent: () => boolean\n  failedMessage: string\n  onStatus: (status: RecapStatus) => void\n  onError: (message: string) => void\n}): Promise<void> {\n  try {\n    const status = await recapCall<RecapStatus>(input.rpc, 'status', input.sessionId ? { sessionId: input.sessionId } : {})\n    if (!input.isCurrent()) return\n    input.onStatus(status)\n  } catch (cause) {\n    if (!input.isCurrent()) return\n    input.onError(cause instanceof Error && cause.message ? cause.message : input.failedMessage)\n  }\n}\n\n/** Recap's single user-facing name, shared by the chat seat label and copy. */\nexport function recapTitle(locale: string | undefined): string {\n  return copy(locale, '回顾', 'Recap')\n}\n\n/** Maps every generation outcome to a dot state instead of reading anything non-running as done. */\nexport function recapGenerationDot(generation: RecapCard['generation']): 'ongoing' | 'error' | 'warning' | 'idle' | 'done' {\n  switch (generation) {\n    case 'running': return 'ongoing'\n    case 'failed': return 'error'\n    case 'cancelled': return 'warning'\n    case 'superseded': return 'idle'\n    default: return 'done'\n  }\n}\n\nexport function recapGenerationLabel(generation: RecapCard['generation'], locale: string | undefined): string {\n  switch (generation) {\n    case 'running': return copy(locale, '生成中', 'Generating')\n    case 'failed': return copy(locale, '生成失败', 'Failed')\n    case 'cancelled': return copy(locale, '已取消', 'Cancelled')\n    case 'superseded': return copy(locale, '已被新回顾替代', 'Superseded')\n    default: return copy(locale, '已完成', 'Done')\n  }\n}\n\n/**\n * The chat seat stays a quiet lifecycle controller until there is something to\n * show: stored cards or a generation in flight. Only then does it render the card UI.\n */\nexport function recapCardVisible(input: { hidden?: boolean; cards: readonly RecapCard[] }): boolean {\n  // A running generation always belongs to a stored card, so \"has cards\" covers both cases.\n  return !input.hidden && input.cards.length > 0\n}\n\nexport async function runRecapAct(input: {\n  rpc: RpcCaller\n  sessionId: string\n  endpoint: 'cancel' | 'retry' | 'refresh'\n  cardId?: string\n  isCurrent: () => boolean\n  failedMessage: string\n  onBusy: (busy: boolean) => void\n  onStatus: (status: RecapStatus) => void\n  onError: (message: string) => void\n}): Promise<void> {\n  if (!input.isCurrent()) return\n  input.onBusy(true)\n  try {\n    const payload = input.endpoint === 'refresh'\n      ? { sessionId: input.sessionId }\n      : { cardId: input.cardId, sessionId: input.sessionId }\n    await recapCall(input.rpc, input.endpoint, payload)\n    if (!input.isCurrent()) return\n    const status = await recapCall<RecapStatus>(input.rpc, 'status', { sessionId: input.sessionId })\n    if (!input.isCurrent()) return\n    input.onStatus(status)\n  } catch (cause) {\n    if (!input.isCurrent()) return\n    input.onError(cause instanceof Error ? cause.message : input.failedMessage)\n  } finally {\n    if (!input.isCurrent()) return\n    input.onBusy(false)\n  }\n}\n\nexport async function runRecapIdleReturn(input: {\n  rpc: RpcCaller\n  sessionId: string\n  isCurrent: () => boolean\n  failedMessage: string\n  onStatus: (status: RecapStatus) => void\n  onError: (message: string) => void\n  onActivity: () => void\n}): Promise<void> {\n  if (!input.isCurrent()) return\n  try {\n    await recapCall(input.rpc, 'idle.return', { sessionId: input.sessionId })\n    if (!input.isCurrent()) return\n    const status = await recapCall<RecapStatus>(input.rpc, 'status', { sessionId: input.sessionId })\n    if (!input.isCurrent()) return\n    input.onActivity()\n    input.onStatus(status)\n  } catch {\n    if (!input.isCurrent()) return\n    input.onError(input.failedMessage)\n  }\n}\n\nconst css = `${officialUiCss(['dsh-recap-card', 'dsh-recap-settings'])}\n/* The two surfaces take their measure and rhythm from the contract; what stays\n * here is the native <details> header the primitives do not cover, and the\n * generated body, which is prose rather than the monospaced code block the\n * contract's own code well is for. */\n.dsh-recap-card, .dsh-recap-settings { max-width: 760px; }\n.dsh-recap-sr {\n  position: absolute; width: 1px; height: 1px; padding: 0; margin: -1px;\n  overflow: hidden; clip: rect(0 0 0 0); white-space: nowrap; border: 0;\n}\n.dsh-recap-summary { display: flex; align-items: center; gap: 8px; min-width: 0; cursor: pointer; }\n.dsh-recap-body {\n  margin: 0;\n  font: inherit;\n  white-space: pre-wrap;\n  overflow-wrap: anywhere;\n  color: var(--dsw-alias-label-secondary);\n}\n`\n\n/** Retry; when it would overwrite a finished recap, a second click within 3s confirms. */\nfunction RetryButton(props: { locale?: string; disabled?: boolean; confirm: boolean; onRetry(): void }) {\n  const [armed, setArmed] = useState(false)\n  const timer = useRef<ReturnType<typeof setTimeout>>(undefined)\n  useEffect(() => () => clearTimeout(timer.current), [])\n  const disarm = () => { clearTimeout(timer.current); setArmed(false) }\n  const confirmLabel = copy(props.locale, '确认覆盖？', 'Confirm replace?')\n  return <>\n    <Button variant=\"outline\" size=\"sm\" disabled={props.disabled} onBlur={disarm}\n      onClick={() => {\n        if (props.confirm && !armed) {\n          setArmed(true)\n          timer.current = setTimeout(() => setArmed(false), 3000)\n          return\n        }\n        disarm()\n        props.onRetry()\n      }}>{armed ? confirmLabel : copy(props.locale, '重新生成', 'Regenerate')}</Button>\n    <span role=\"status\" className=\"dsh-recap-sr\">{armed ? confirmLabel : ''}</span>\n  </>\n}\n\nexport function RecapEventsCard({\n  client, sessionId, locale, hidden, idle = true, quiet = false,\n}: {\n  client: RecapClient\n  sessionId: string\n  locale?: string\n  hidden?: boolean\n  idle?: boolean\n  quiet?: boolean\n}) {\n  const rpc = client.connection.rpc\n  const [cards, setCards] = useState<RecapCard[]>([])\n  const [error, setError] = useState('')\n  const [cardsOn, setCardsOn] = useState(true)\n  const [busy, setBusy] = useState(false)\n  const lastActivityAt = useRef(Date.now())\n  const idleMs = useRef(defaultSettings().idleReturnMs)\n  const cardsEnabled = useRef(true)\n  const busyRef = useRef(false)\n  const workRef = useRef<RecapClientWork>(undefined)\n  if (!workRef.current) workRef.current = createRecapClientWork()\n  const work = workRef.current\n\n  function markBusy(value: boolean) {\n    busyRef.current = value\n    setBusy(value)\n  }\n\n  function applyStatus(status: RecapStatus) {\n    idleMs.current = status.settings.idleReturnMs\n    cardsEnabled.current = status.settings.cardsEnabled\n    setCardsOn(status.settings.cardsEnabled)\n    setCards(status.cards)\n    setError('')\n  }\n\n  useEffect(() => () => { work.dispose() }, [work])\n\n  useEffect(() => {\n    const generation = work.beginLoad()\n    lastActivityAt.current = Date.now()\n    busyRef.current = false\n    setBusy(false)\n    setError('')\n    setCards([])\n    void runRecapStatusLoad({\n      rpc,\n      sessionId,\n      isCurrent: () => work.isLoad(generation),\n      failedMessage: copy(locale, '无法读取回顾。', 'Could not load recap.'),\n      onStatus: applyStatus,\n      onError: setError,\n    })\n    return () => { if (work.isLoad(generation)) work.beginLoad() }\n  }, [rpc, sessionId, locale, work])\n\n  useEffect(() => {\n    if (hidden || !idle || typeof document === 'undefined') return undefined\n    const requestIdle = () => {\n      const token = work.beginRequest()\n      void runRecapIdleReturn({\n        rpc,\n        sessionId,\n        isCurrent: () => work.isRequest(token),\n        failedMessage: copy(locale, '闲置回顾失败。', 'Idle recap failed.'),\n        onStatus: applyStatus,\n        onError: setError,\n        onActivity: () => { lastActivityAt.current = Date.now() },\n      })\n    }\n    const maybeIdleReturn = () => {\n      if (!shouldRequestIdleReturn({\n        now: Date.now(),\n        lastUserActivityAt: lastActivityAt.current,\n        idleReturnMs: idleMs.current,\n        cardsEnabled: cardsEnabled.current,\n        visible: document.visibilityState === 'visible',\n        hidden: false,\n        focused: document.hasFocus(),\n      })) return\n      requestIdle()\n    }\n    const onPointer = () => { lastActivityAt.current = Date.now() }\n    const onKey = () => { lastActivityAt.current = Date.now() }\n    document.addEventListener('pointerdown', onPointer)\n    document.addEventListener('keydown', onKey)\n    window.addEventListener('focus', maybeIdleReturn)\n    document.addEventListener('visibilitychange', maybeIdleReturn)\n    return () => {\n      document.removeEventListener('pointerdown', onPointer)\n      document.removeEventListener('keydown', onKey)\n      window.removeEventListener('focus', maybeIdleReturn)\n      document.removeEventListener('visibilitychange', maybeIdleReturn)\n    }\n  }, [rpc, sessionId, locale, hidden, idle, work])\n\n  function refreshCards() {\n    if (shouldSkipRecapAutoRefresh({ busy: busyRef.current, disposed: work.disposed })) return\n    const token = work.snapshot()\n    void runRecapStatusLoad({\n      rpc,\n      sessionId,\n      isCurrent: () => work.isRequest(token) && !busyRef.current,\n      failedMessage: copy(locale, '无法读取回顾。', 'Could not load recap.'),\n      onStatus: applyStatus,\n      onError: setError,\n    })\n  }\n\n  useFeatureRefresh(\n    client,\n    sessionId,\n    refreshCards,\n    recapHasRunningGeneration(cards),\n    Boolean(sessionId) && hidden !== true,\n  )\n\n  function act(endpoint: 'cancel' | 'retry' | 'refresh', cardId?: string) {\n    const token = work.beginRequest()\n    void runRecapAct({\n      rpc,\n      sessionId,\n      endpoint,\n      cardId,\n      isCurrent: () => work.isRequest(token),\n      failedMessage: copy(locale, '操作失败。', 'Action failed.'),\n      onBusy: markBusy,\n      onStatus: applyStatus,\n      onError: setError,\n    })\n  }\n\n  // `quiet` keeps the seat a background controller: nothing renders until there is a card to show.\n  if (quiet ? !recapCardVisible({ hidden, cards }) : hidden) return null\n  if (!cardsOn && cards.length === 0 && !error) return null\n  const running = recapHasRunningGeneration(cards)\n  return <section className=\"dsh-recap-card dsh-ui-stack\" data-session={sessionId} aria-label={recapTitle(locale)}>\n    {error ? <p role=\"alert\" className=\"dsh-ui-error\">{error}</p> : null}\n    {cardsOn ? <div className=\"dsh-ui-actions\">\n      <Button variant=\"primary\" size=\"sm\" disabled={busy || running}\n        onClick={() => act('refresh')}>{copy(locale, '生成回顾', 'Generate recap')}</Button>\n      <span role=\"status\" className=\"dsh-ui-hint\">{running ? copy(locale, '正在生成回顾…', 'Generating recap…') : ''}</span>\n    </div> : null}\n    {cards.map(card => (\n      <details className=\"dsh-ui-card dsh-ui-card--flat\" key={card.id}>\n        <summary className=\"dsh-recap-summary\">\n          <StateDot state={recapGenerationDot(card.generation)} />\n          <span className=\"dsh-ui-heading dsh-ui-truncate\">{card.title}</span>\n          <span className=\"dsh-ui-meta\">{recapGenerationLabel(card.generation, locale)}</span>\n        </summary>\n        <pre className=\"dsh-recap-body\">{card.body}</pre>\n        <div className=\"dsh-ui-actions\">\n          {card.generation === 'running'\n            ? <Button variant=\"outline\" size=\"sm\" disabled={busy} onClick={() => act('cancel', card.id)}>{copy(locale, '取消', 'Cancel')}</Button>\n            : <RetryButton locale={locale} disabled={busy}\n              // Retrying a finished recap replaces its text, so that one path asks first.\n              confirm={card.generation === 'idle' && Boolean(card.body.trim())}\n              onRetry={() => act('retry', card.id)} />}\n        </div>\n      </details>\n    ))}\n  </section>\n}\n\nfunction RecapBackgroundSeat({ client, ...props }: { client: RecapClient } & Record<string, unknown>) {\n  const seat = useNativeSeat(client, props)\n  if (!seat.sessionId) return null\n  return <RecapEventsCard key={recapCardKey(seat)} client={client} sessionId={seat.sessionId} locale={seat.locale} hidden={seat.hidden} quiet />\n}\n\n/** One purpose's model select: empty choice keeps the shared role/chat-model default. */\nfunction RecapModelSelect(props: {\n  locale: string\n  label: string\n  route: RecapModelRoute\n  choices: ModelMenuChoice[]\n  busy: boolean\n  onChange: (route: RecapModelRoute) => void\n}) {\n  const optionsId = useId()\n  const selected = props.choices.find(\n    item => item.provider === props.route.provider && item.model === props.route.model,\n  )\n  const efforts = modelMenuEffortOptions(selected, props.route.reasoningEffort)\n  return <>\n    <label className=\"dsh-ui-field\" htmlFor={optionsId}>\n      <span className=\"dsh-ui-label\">{props.label}</span>\n      <select\n        id={optionsId}\n        className=\"dsh-ui-select\"\n        value={modelMenuChoiceKey(props.route.provider, props.route.model)}\n        disabled={props.busy}\n        onChange={event => {\n          const key = event.target.value\n          if (!key) { props.onChange({ provider: '', model: '' }); return }\n          const parsed = parseModelMenuChoiceKey(key)\n          if (parsed) props.onChange(parsed)\n        }}\n      >\n        <option value=\"\">{copy(props.locale, '默认模型', 'Default model')}</option>\n        {props.choices.map(choice => (\n          <option key={modelMenuChoiceKey(choice.provider, choice.model)} value={modelMenuChoiceKey(choice.provider, choice.model)}>\n            {choice.label}\n          </option>\n        ))}\n      </select>\n    </label>\n    {selected && efforts.length > 0 && (\n      <label className=\"dsh-ui-field\" htmlFor={`${optionsId}-effort`}>\n        <span className=\"dsh-ui-label\">{copy(props.locale, '思考强度', 'Reasoning effort')}</span>\n        <select\n          id={`${optionsId}-effort`}\n          className=\"dsh-ui-select\"\n          value={props.route.reasoningEffort ?? ''}\n          disabled={props.busy}\n          onChange={event => props.onChange({ ...props.route, reasoningEffort: event.target.value || undefined })}\n        >\n          <option value=\"\">{copy(props.locale, '默认', 'Default')}</option>\n          {efforts.map(effort => <option key={effort.id} value={effort.id}>{effort.name}</option>)}\n        </select>\n      </label>\n    )}\n  </>\n}\n\nfunction RecapToggle(props: {\n  locale: string; label: string; hint: string; checked: boolean; busy: boolean; onChange(next: boolean): void\n}) {\n  return <div className=\"dsh-ui-toggle-row\">\n    <div className=\"dsh-ui-toggle-text\">\n      <span className=\"dsh-ui-toggle-label\">{props.label}</span>\n      <span className=\"dsh-ui-hint\">{props.hint}</span>\n    </div>\n    <Switch checked={props.checked} label={props.label} disabled={props.busy} onChange={props.onChange} />\n  </div>\n}\n\n/** Minutes bounds mirror the server schema (60_000..180 * 60_000 ms). */\nexport const RECAP_IDLE_MIN_MINUTES = 1\nexport const RECAP_IDLE_MAX_MINUTES = 180\n\n/** Parses the minutes field; undefined when out of range or not a whole number. */\nexport function parseIdleMinutes(text: string): number | undefined {\n  const minutes = Number(text.trim())\n  if (!Number.isInteger(minutes) || minutes < RECAP_IDLE_MIN_MINUTES || minutes > RECAP_IDLE_MAX_MINUTES) return undefined\n  return minutes * 60_000\n}\n\nfunction IdleMinutesField(props: { locale: string; value: number; busy: boolean; onCommit(ms: number): void }) {\n  const id = useId()\n  const [text, setText] = useState(String(Math.round(props.value / 60_000)))\n  useEffect(() => { setText(String(Math.round(props.value / 60_000))) }, [props.value])\n  const parsed = parseIdleMinutes(text)\n  const invalid = parsed === undefined\n  const commit = () => { if (parsed !== undefined && parsed !== props.value) props.onCommit(parsed) }\n  return <div className=\"dsh-ui-field\">\n    <label className=\"dsh-ui-label\" htmlFor={id}>{copy(props.locale, '离开多久后生成回顾（分钟）', 'Recap after being away (minutes)')}</label>\n    <Input id={id} className=\"dsh-ui-control\" inputMode=\"numeric\" value={text} disabled={props.busy}\n      aria-invalid={invalid || undefined} aria-describedby={`${id}-hint`}\n      onChange={event => setText(event.target.value)} onBlur={commit}\n      onKeyDown={event => { if (event.key === 'Enter') commit() }} />\n    <p id={`${id}-hint`} className={invalid ? 'dsh-ui-error' : 'dsh-ui-hint'}>\n      {copy(props.locale, `填写 ${RECAP_IDLE_MIN_MINUTES}–${RECAP_IDLE_MAX_MINUTES} 之间的整数。`, `A whole number from ${RECAP_IDLE_MIN_MINUTES} to ${RECAP_IDLE_MAX_MINUTES}.`)}\n    </p>\n  </div>\n}\n\n/** Plugin-page settings row: recap abilities, idle interval and model picks. */\nexport function RecapSettingsPanel({ client, ...props }: { client: RecapClient } & Record<string, unknown>) {\n  const seat = useNativeSeat(client, props)\n  const locale = seat.locale\n  const [status, setStatus] = useState<RecapStatus>()\n  const [choices, setChoices] = useState<ModelMenuChoice[]>([])\n  const [busy, setBusy] = useState(false)\n  const [error, setError] = useState('')\n  const [note, setNote] = useState('')\n\n  const call = (endpoint: string, payload: unknown) => client.connection.rpc.call(RECAP_RPC_CHANNEL, endpoint, payload)\n\n  useEffect(() => {\n    let live = true\n    void call('status', {}).then(async value => {\n      const result = value as RpcResult<RecapStatus>\n      if (!live) return\n      if (!result || result.ok !== true) {\n        setError(result && result.ok === false && result.error.message ? result.error.message : copy(locale, '无法读取回顾设置。', 'Unable to load recap settings.'))\n        return\n      }\n      setStatus(result.value)\n      setError('')\n      void client.remote?.session?.modelCatalog?.()\n        ?.then(catalog => { if (live) setChoices(parseModelMenuChoices(catalog, result.value.settings.displayModel)) })\n        .catch(() => { if (live) setChoices([]) })\n    }).catch(cause => { if (live) setError(cause instanceof Error && cause.message ? cause.message : copy(locale, '无法读取回顾设置。', 'Unable to load recap settings.')) })\n    return () => { live = false }\n  }, [client, locale])\n\n  async function save(patch: Partial<Omit<RecapSettings, 'revision'>>): Promise<void> {\n    if (!status) return\n    const draft = { ...defaultSettings(), ...status.settings, ...patch }\n    setBusy(true); setError(''); setNote('')\n    try {\n      const value = await call('update', {\n        expectedRevision: status.settings.revision,\n        settings: {\n          cardsEnabled: draft.cardsEnabled,\n          checkpointsEnabled: draft.checkpointsEnabled,\n          semanticCheckpointsEnabled: draft.semanticCheckpointsEnabled,\n          idleReturnMs: draft.idleReturnMs,\n          displayModel: draft.displayModel,\n          checkpointModel: draft.checkpointModel,\n        },\n      })\n      const result = value as RpcResult<RecapStatus>\n      if (!result || result.ok !== true) throw new Error(result && !result.ok ? result.error.message : 'failed')\n      setStatus(result.value)\n      setNote(copy(locale, '已保存。', 'Saved.'))\n    } catch (cause) {\n      setError(cause instanceof Error ? cause.message : copy(locale, '保存失败。', 'Save failed.'))\n    } finally {\n      setBusy(false)\n    }\n  }\n\n  if (!status) {\n    return <section className=\"dsh-recap-settings dsh-ui-panel\" data-testid=\"recap-settings\">\n      {error\n        ? <p role=\"alert\" className=\"dsh-ui-error\">{error}</p>\n        : <p role=\"status\" className=\"dsh-ui-hint\">{copy(locale, '正在读取设置…', 'Loading settings…')}</p>}\n    </section>\n  }\n\n  return <section className=\"dsh-recap-settings dsh-ui-panel\" data-testid=\"recap-settings\">\n    {error && <p role=\"alert\" className=\"dsh-ui-error\">{error}</p>}\n    {note && <p role=\"status\" className=\"dsh-ui-notice\">{note}</p>}\n    <RecapToggle locale={locale} busy={busy}\n      label={copy(locale, '回顾卡片', 'Recap cards')}\n      hint={copy(locale, '长对话结束或离开一段时间后回来时，生成一段回顾。', 'Writes a short recap after long turns or when you come back.')}\n      checked={status.settings.cardsEnabled}\n      onChange={next => void save({ cardsEnabled: next })} />\n    <RecapToggle locale={locale} busy={busy}\n      label={copy(locale, '任务检查点', 'Task checkpoints')}\n      hint={copy(locale, '在关键节点提醒助手当前进度。', 'Reminds the assistant of progress at key points.')}\n      checked={status.settings.checkpointsEnabled}\n      onChange={next => void save({ checkpointsEnabled: next })} />\n    <RecapToggle locale={locale} busy={busy || !status.settings.checkpointsEnabled}\n      label={copy(locale, '语义检查点', 'Semantic checkpoints')}\n      hint={copy(locale, '用模型总结检查点内容，需先开启任务检查点。', 'Uses a model to summarize checkpoints. Needs task checkpoints on.')}\n      checked={status.settings.semanticCheckpointsEnabled}\n      onChange={next => void save({ semanticCheckpointsEnabled: next })} />\n    <IdleMinutesField locale={locale} busy={busy || !status.settings.cardsEnabled}\n      value={status.settings.idleReturnMs}\n      onCommit={ms => void save({ idleReturnMs: ms })} />\n    <RecapModelSelect\n      locale={locale}\n      label={copy(locale, '回顾卡片模型', 'Recap card model')}\n      route={status.settings.displayModel}\n      choices={choices}\n      busy={busy}\n      onChange={route => void save({ displayModel: route })}\n    />\n    <RecapModelSelect\n      locale={locale}\n      label={copy(locale, '语义检查点模型', 'Semantic checkpoint model')}\n      route={status.settings.checkpointModel}\n      choices={choices}\n      busy={busy}\n      onChange={route => void save({ checkpointModel: route })}\n    />\n    <p className=\"dsh-ui-help\">{copy(locale, '留空则用当前会话模型，再回落到宿主默认对话模型。', 'Leave empty to use the current session model, then the host default chat model.')}</p>\n  </section>\n}\n\nexport function apply(ctx: Context): void {\n  const client = ctx as RecapClient\n  ctx.effect(() => {\n    if (typeof document === 'undefined') return () => {}\n    const style = document.createElement('style')\n    style.setAttribute('data-plugin', '@klarkxy/dsh-recap')\n    style.textContent = css\n    document.head.appendChild(style)\n    return () => style.remove()\n  }, 'dsh-recap.styles')\n  ctx.effect(() => client.slots.inject('plugins.bundle.config', () => client.slots.register(\n    { name: 'plugins.bundle.config', key: RECAP_PLUGIN },\n    () => <RecapSettingsPanel client={client} />,\n  )), 'dsh-recap.settings')\n  ctx.effect(() => client.slots.inject(CHAT_EVENTS_SLOT, () => client.slots.register({\n    name: CHAT_EVENTS_SLOT, id: 'recap', order: 40, label: recapTitle(undefined),\n  }, (props: unknown) => <RecapBackgroundSeat client={client} {...(props as object)} />)), 'dsh-recap.background')\n}\n"],"mappings":"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"}